1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Copyright (c) 2010 The FreeBSD Foundation 9 * All rights reserved. 10 * 11 * Portions of this software were developed by Shteryana Sotirova Shopova 12 * under sponsorship from the FreeBSD Foundation. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 36 * 37 * TrapSinkTable 38 */ 39 #include <sys/types.h> 40 #include <sys/queue.h> 41 #include <sys/sysctl.h> 42 #include <sys/un.h> 43 #include <stdint.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <stdarg.h> 47 #include <stdarg.h> 48 #include <string.h> 49 #include <ctype.h> 50 #include <syslog.h> 51 #include <unistd.h> 52 #include <netinet/in.h> 53 #include <arpa/inet.h> 54 55 #include "snmpmod.h" 56 #include "snmpd.h" 57 58 #define SNMPTREE_TYPES 59 #include "tree.h" 60 #include "oid.h" 61 62 struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 63 64 /* List of target addresses */ 65 static struct target_addresslist target_addresslist = 66 SLIST_HEAD_INITIALIZER(target_addresslist); 67 68 /* List of target parameters */ 69 static struct target_paramlist target_paramlist = 70 SLIST_HEAD_INITIALIZER(target_paramlist); 71 72 /* List of notification targets */ 73 static struct target_notifylist target_notifylist = 74 SLIST_HEAD_INITIALIZER(target_notifylist); 75 76 static const struct asn_oid oid_begemotTrapSinkTable = 77 OIDX_begemotTrapSinkTable; 78 static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 79 static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 80 81 struct trapsink_dep { 82 struct snmp_dependency dep; 83 u_int set; 84 u_int status; 85 u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; 86 u_int version; 87 u_int rb; 88 u_int rb_status; 89 u_int rb_version; 90 u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; 91 }; 92 enum { 93 TDEP_STATUS = 0x0001, 94 TDEP_COMM = 0x0002, 95 TDEP_VERSION = 0x0004, 96 97 TDEP_CREATE = 0x0001, 98 TDEP_MODIFY = 0x0002, 99 TDEP_DESTROY = 0x0004, 100 }; 101 102 static int 103 trapsink_create(struct trapsink_dep *tdep) 104 { 105 struct trapsink *t; 106 struct sockaddr_in sa; 107 108 if ((t = malloc(sizeof(*t))) == NULL) 109 return (SNMP_ERR_RES_UNAVAIL); 110 111 t->index = tdep->dep.idx; 112 t->status = TRAPSINK_NOT_READY; 113 t->comm[0] = '\0'; 114 t->version = TRAPSINK_V2; 115 116 if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 117 syslog(LOG_ERR, "socket(UDP): %m"); 118 free(t); 119 return (SNMP_ERR_RES_UNAVAIL); 120 } 121 (void)shutdown(t->socket, SHUT_RD); 122 memset(&sa, 0, sizeof(sa)); 123 sa.sin_len = sizeof(sa); 124 sa.sin_family = AF_INET; 125 sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | 126 (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | 127 (t->index.subs[3] << 0)); 128 sa.sin_port = htons(t->index.subs[4]); 129 130 if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 131 syslog(LOG_ERR, "connect(%s,%u): %m", 132 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 133 (void)close(t->socket); 134 free(t); 135 return (SNMP_ERR_GENERR); 136 } 137 138 if (tdep->set & TDEP_VERSION) 139 t->version = tdep->version; 140 if (tdep->set & TDEP_COMM) 141 strcpy(t->comm, tdep->comm); 142 143 if (t->comm[0] != '\0') 144 t->status = TRAPSINK_NOT_IN_SERVICE; 145 146 /* look whether we should activate */ 147 if (tdep->status == 4) { 148 if (t->status == TRAPSINK_NOT_READY) { 149 if (t->socket != -1) 150 (void)close(t->socket); 151 free(t); 152 return (SNMP_ERR_INCONS_VALUE); 153 } 154 t->status = TRAPSINK_ACTIVE; 155 } 156 157 INSERT_OBJECT_OID(t, &trapsink_list); 158 159 tdep->rb |= TDEP_CREATE; 160 161 return (SNMP_ERR_NOERROR); 162 } 163 164 static void 165 trapsink_free(struct trapsink *t) 166 { 167 TAILQ_REMOVE(&trapsink_list, t, link); 168 if (t->socket != -1) 169 (void)close(t->socket); 170 free(t); 171 } 172 173 static int 174 trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) 175 { 176 tdep->rb_status = t->status; 177 tdep->rb_version = t->version; 178 strcpy(tdep->rb_comm, t->comm); 179 180 if (tdep->set & TDEP_STATUS) { 181 /* if we are active and should move to not_in_service do 182 * this first */ 183 if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { 184 t->status = TRAPSINK_NOT_IN_SERVICE; 185 tdep->rb |= TDEP_MODIFY; 186 } 187 } 188 189 if (tdep->set & TDEP_VERSION) 190 t->version = tdep->version; 191 if (tdep->set & TDEP_COMM) 192 strcpy(t->comm, tdep->comm); 193 194 if (tdep->set & TDEP_STATUS) { 195 /* if we were inactive and should go active - do this now */ 196 if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { 197 if (t->comm[0] == '\0') { 198 t->status = tdep->rb_status; 199 t->version = tdep->rb_version; 200 strcpy(t->comm, tdep->rb_comm); 201 return (SNMP_ERR_INCONS_VALUE); 202 } 203 t->status = TRAPSINK_ACTIVE; 204 tdep->rb |= TDEP_MODIFY; 205 } 206 } 207 return (SNMP_ERR_NOERROR); 208 } 209 210 static int 211 trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) 212 { 213 if (tdep->set & TDEP_STATUS) 214 t->status = tdep->rb_status; 215 if (tdep->set & TDEP_VERSION) 216 t->version = tdep->rb_version; 217 if (tdep->set & TDEP_COMM) 218 strcpy(t->comm, tdep->rb_comm); 219 220 return (SNMP_ERR_NOERROR); 221 } 222 223 static int 224 trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t, 225 struct trapsink_dep *tdep) 226 { 227 t->status = TRAPSINK_DESTROY; 228 tdep->rb_status = t->status; 229 tdep->rb |= TDEP_DESTROY; 230 return (SNMP_ERR_NOERROR); 231 } 232 233 static int 234 trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) 235 { 236 t->status = tdep->rb_status; 237 return (SNMP_ERR_NOERROR); 238 } 239 240 static int 241 trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, 242 enum snmp_depop op) 243 { 244 struct trapsink_dep *tdep = (struct trapsink_dep *)dep; 245 struct trapsink *t; 246 247 t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); 248 249 switch (op) { 250 251 case SNMP_DEPOP_COMMIT: 252 if (tdep->set & TDEP_STATUS) { 253 switch (tdep->status) { 254 255 case 1: 256 case 2: 257 if (t == NULL) 258 return (SNMP_ERR_INCONS_VALUE); 259 return (trapsink_modify(t, tdep)); 260 261 case 4: 262 case 5: 263 if (t != NULL) 264 return (SNMP_ERR_INCONS_VALUE); 265 return (trapsink_create(tdep)); 266 267 case 6: 268 if (t == NULL) 269 return (SNMP_ERR_NOERROR); 270 return (trapsink_destroy(ctx, t, tdep)); 271 } 272 } else if (tdep->set != 0) 273 return (trapsink_modify(t, tdep)); 274 275 return (SNMP_ERR_NOERROR); 276 277 case SNMP_DEPOP_ROLLBACK: 278 if (tdep->rb & TDEP_CREATE) { 279 trapsink_free(t); 280 return (SNMP_ERR_NOERROR); 281 } 282 if (tdep->rb & TDEP_MODIFY) 283 return (trapsink_unmodify(t, tdep)); 284 if(tdep->rb & TDEP_DESTROY) 285 return (trapsink_undestroy(t, tdep)); 286 return (SNMP_ERR_NOERROR); 287 288 case SNMP_DEPOP_FINISH: 289 if ((tdep->rb & TDEP_DESTROY) && t != NULL && 290 ctx->code == SNMP_RET_OK) 291 trapsink_free(t); 292 return (SNMP_ERR_NOERROR); 293 } 294 abort(); 295 } 296 297 int 298 op_trapsink(struct snmp_context *ctx, struct snmp_value *value, 299 u_int sub, u_int iidx, enum snmp_op op) 300 { 301 struct trapsink *t; 302 u_char ipa[4]; 303 int32_t port; 304 struct asn_oid idx; 305 struct trapsink_dep *tdep; 306 u_char *p; 307 308 t = NULL; /* gcc */ 309 310 switch (op) { 311 312 case SNMP_OP_GETNEXT: 313 if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 314 return (SNMP_ERR_NOSUCHNAME); 315 index_append(&value->var, sub, &t->index); 316 break; 317 318 case SNMP_OP_GET: 319 if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 320 return (SNMP_ERR_NOSUCHNAME); 321 break; 322 323 case SNMP_OP_SET: 324 if (index_decode(&value->var, sub, iidx, ipa, &port) || 325 port == 0 || port > 65535) 326 return (SNMP_ERR_NO_CREATION); 327 t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); 328 329 asn_slice_oid(&idx, &value->var, sub, value->var.len); 330 331 tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, 332 &oid_begemotTrapSinkTable, &idx, 333 sizeof(*tdep), trapsink_dep); 334 if (tdep == NULL) 335 return (SNMP_ERR_RES_UNAVAIL); 336 337 switch (value->var.subs[sub - 1]) { 338 339 case LEAF_begemotTrapSinkStatus: 340 if (tdep->set & TDEP_STATUS) 341 return (SNMP_ERR_INCONS_VALUE); 342 switch (value->v.integer) { 343 344 case 1: 345 case 2: 346 if (t == NULL) 347 return (SNMP_ERR_INCONS_VALUE); 348 break; 349 350 case 4: 351 case 5: 352 if (t != NULL) 353 return (SNMP_ERR_INCONS_VALUE); 354 break; 355 356 case 6: 357 break; 358 359 default: 360 return (SNMP_ERR_WRONG_VALUE); 361 } 362 tdep->status = value->v.integer; 363 tdep->set |= TDEP_STATUS; 364 return (SNMP_ERR_NOERROR); 365 366 case LEAF_begemotTrapSinkComm: 367 if (tdep->set & TDEP_COMM) 368 return (SNMP_ERR_INCONS_VALUE); 369 if (value->v.octetstring.len == 0 || 370 value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) 371 return (SNMP_ERR_WRONG_VALUE); 372 for (p = value->v.octetstring.octets; 373 p < value->v.octetstring.octets + value->v.octetstring.len; 374 p++) { 375 if (!isascii(*p) || !isprint(*p)) 376 return (SNMP_ERR_WRONG_VALUE); 377 } 378 tdep->set |= TDEP_COMM; 379 strncpy(tdep->comm, value->v.octetstring.octets, 380 value->v.octetstring.len); 381 tdep->comm[value->v.octetstring.len] = '\0'; 382 return (SNMP_ERR_NOERROR); 383 384 case LEAF_begemotTrapSinkVersion: 385 if (tdep->set & TDEP_VERSION) 386 return (SNMP_ERR_INCONS_VALUE); 387 if (value->v.integer != TRAPSINK_V1 && 388 value->v.integer != TRAPSINK_V2) 389 return (SNMP_ERR_WRONG_VALUE); 390 tdep->version = value->v.integer; 391 tdep->set |= TDEP_VERSION; 392 return (SNMP_ERR_NOERROR); 393 } 394 if (t == NULL) 395 return (SNMP_ERR_INCONS_NAME); 396 else 397 return (SNMP_ERR_NOT_WRITEABLE); 398 399 400 case SNMP_OP_ROLLBACK: 401 case SNMP_OP_COMMIT: 402 return (SNMP_ERR_NOERROR); 403 } 404 405 switch (value->var.subs[sub - 1]) { 406 407 case LEAF_begemotTrapSinkStatus: 408 value->v.integer = t->status; 409 break; 410 411 case LEAF_begemotTrapSinkComm: 412 return (string_get(value, t->comm, -1)); 413 414 case LEAF_begemotTrapSinkVersion: 415 value->v.integer = t->version; 416 break; 417 418 } 419 return (SNMP_ERR_NOERROR); 420 } 421 422 static void 423 snmp_create_v1_trap(struct snmp_pdu *pdu, char *com, 424 const struct asn_oid *trap_oid) 425 { 426 memset(pdu, 0, sizeof(*pdu)); 427 strlcpy(pdu->community, com, sizeof(pdu->community)); 428 429 pdu->version = SNMP_V1; 430 pdu->type = SNMP_PDU_TRAP; 431 pdu->enterprise = systemg.object_id; 432 memcpy(pdu->agent_addr, snmpd.trap1addr, 4); 433 pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 434 pdu->specific_trap = 0; 435 pdu->time_stamp = get_ticks() - start_tick; 436 pdu->nbindings = 0; 437 } 438 439 static void 440 snmp_create_v2_trap(struct snmp_pdu *pdu, char *com, 441 const struct asn_oid *trap_oid) 442 { 443 memset(pdu, 0, sizeof(*pdu)); 444 strlcpy(pdu->community, com, sizeof(pdu->community)); 445 446 pdu->version = SNMP_V2c; 447 pdu->type = SNMP_PDU_TRAP2; 448 pdu->request_id = reqid_next(trap_reqid); 449 pdu->error_index = 0; 450 pdu->error_status = SNMP_ERR_NOERROR; 451 452 pdu->bindings[0].var = oid_sysUpTime; 453 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 454 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 455 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 456 457 pdu->bindings[1].var = oid_snmpTrapOID; 458 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 459 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 460 pdu->bindings[1].v.oid = *trap_oid; 461 462 pdu->nbindings = 2; 463 } 464 465 static void 466 snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, 467 const struct asn_oid *trap_oid) 468 { 469 struct usm_user *usmuser; 470 471 memset(pdu, 0, sizeof(*pdu)); 472 473 pdu->version = SNMP_V3; 474 pdu->type = SNMP_PDU_TRAP2; 475 pdu->request_id = reqid_next(trap_reqid); 476 pdu->error_index = 0; 477 pdu->error_status = SNMP_ERR_NOERROR; 478 479 pdu->bindings[0].var = oid_sysUpTime; 480 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 481 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 482 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 483 484 pdu->bindings[1].var = oid_snmpTrapOID; 485 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 486 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 487 pdu->bindings[1].v.oid = *trap_oid; 488 489 pdu->nbindings = 2; 490 491 update_snmpd_engine_time(); 492 493 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 494 snmpd_engine.engine_len); 495 pdu->engine.engine_len = snmpd_engine.engine_len; 496 pdu->engine.engine_boots = snmpd_engine.engine_boots; 497 pdu->engine.engine_time = snmpd_engine.engine_time; 498 pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 499 strlcpy(pdu->user.sec_name, target->secname, 500 sizeof(pdu->user.sec_name)); 501 pdu->security_model = target->sec_model; 502 503 pdu->context_engine_len = snmpd_engine.engine_len; 504 memcpy(pdu->context_engine, snmpd_engine.engine_id, 505 snmpd_engine.engine_len); 506 507 if (target->sec_model == SNMP_SECMODEL_USM && 508 target->sec_level != SNMP_noAuthNoPriv) { 509 usmuser = usm_find_user(pdu->engine.engine_id, 510 pdu->engine.engine_len, pdu->user.sec_name); 511 if (usmuser != NULL) { 512 pdu->user.auth_proto = usmuser->suser.auth_proto; 513 pdu->user.priv_proto = usmuser->suser.priv_proto; 514 memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 515 sizeof(pdu->user.auth_key)); 516 memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 517 sizeof(pdu->user.priv_key)); 518 } 519 snmp_pdu_init_secparams(pdu); 520 } 521 } 522 523 void 524 snmp_send_trap(const struct asn_oid *trap_oid, ...) 525 { 526 struct snmp_pdu pdu; 527 struct trapsink *t; 528 const struct snmp_value *v; 529 struct target_notify *n; 530 struct target_address *ta; 531 struct target_param *tp; 532 533 va_list ap; 534 u_char *sndbuf; 535 char *tag; 536 size_t sndlen; 537 ssize_t len; 538 int32_t ip; 539 540 TAILQ_FOREACH(t, &trapsink_list, link) { 541 if (t->status != TRAPSINK_ACTIVE) 542 continue; 543 544 if (t->version == TRAPSINK_V1) 545 snmp_create_v1_trap(&pdu, t->comm, trap_oid); 546 else 547 snmp_create_v2_trap(&pdu, t->comm, trap_oid); 548 549 va_start(ap, trap_oid); 550 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 551 pdu.bindings[pdu.nbindings++] = *v; 552 va_end(ap); 553 554 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 555 syslog(LOG_DEBUG, "send trap to %s failed: no access", 556 t->comm); 557 continue; 558 } 559 560 if ((sndbuf = buf_alloc(1)) == NULL) { 561 syslog(LOG_ERR, "trap send buffer: %m"); 562 return; 563 } 564 565 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 566 567 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 568 syslog(LOG_ERR, "send: %m"); 569 else if ((size_t)len != sndlen) 570 syslog(LOG_ERR, "send: short write %zu/%zu", 571 sndlen, (size_t)len); 572 573 free(sndbuf); 574 } 575 576 SLIST_FOREACH(n, &target_notifylist, tn) { 577 if (n->status != RowStatus_active || n->taglist[0] == '\0') 578 continue; 579 580 SLIST_FOREACH(ta, &target_addresslist, ta) 581 if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 582 (tag[strlen(n->taglist)] == ' ' || 583 tag[strlen(n->taglist)] == '\0' || 584 tag[strlen(n->taglist)] == '\t' || 585 tag[strlen(n->taglist)] == '\r' || 586 tag[strlen(n->taglist)] == '\n') && 587 ta->status == RowStatus_active) 588 break; 589 if (ta == NULL) 590 continue; 591 592 SLIST_FOREACH(tp, &target_paramlist, tp) 593 if (strcmp(tp->name, ta->paramname) == 0 && 594 tp->status == 1) 595 break; 596 if (tp == NULL) 597 continue; 598 599 switch (tp->mpmodel) { 600 case SNMP_MPM_SNMP_V1: 601 snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 602 break; 603 604 case SNMP_MPM_SNMP_V2c: 605 snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 606 break; 607 608 case SNMP_MPM_SNMP_V3: 609 snmp_create_v3_trap(&pdu, tp, trap_oid); 610 break; 611 612 default: 613 continue; 614 } 615 616 va_start(ap, trap_oid); 617 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 618 pdu.bindings[pdu.nbindings++] = *v; 619 va_end(ap); 620 621 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 622 syslog(LOG_DEBUG, "send trap to %s failed: no access", 623 t->comm); 624 continue; 625 } 626 627 if ((sndbuf = buf_alloc(1)) == NULL) { 628 syslog(LOG_ERR, "trap send buffer: %m"); 629 return; 630 } 631 632 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 633 634 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 635 syslog(LOG_ERR, "send: %m"); 636 else if ((size_t)len != sndlen) 637 syslog(LOG_ERR, "send: short write %zu/%zu", 638 sndlen, (size_t)len); 639 640 free(sndbuf); 641 } 642 } 643 644 /* 645 * RFC 3413 SNMP Management Target MIB 646 */ 647 struct snmpd_target_stats * 648 bsnmpd_get_target_stats(void) 649 { 650 return (&snmpd_target_stats); 651 } 652 653 struct target_address * 654 target_first_address(void) 655 { 656 return (SLIST_FIRST(&target_addresslist)); 657 } 658 659 struct target_address * 660 target_next_address(struct target_address *addrs) 661 { 662 if (addrs == NULL) 663 return (NULL); 664 665 return (SLIST_NEXT(addrs, ta)); 666 } 667 668 struct target_address * 669 target_new_address(char *aname) 670 { 671 int cmp; 672 struct target_address *addrs, *temp, *prev; 673 674 SLIST_FOREACH(addrs, &target_addresslist, ta) 675 if (strcmp(aname, addrs->name) == 0) 676 return (NULL); 677 678 if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 679 return (NULL); 680 681 memset(addrs, 0, sizeof(*addrs)); 682 strlcpy(addrs->name, aname, sizeof(addrs->name)); 683 addrs->timeout = 150; 684 addrs->retry = 3; /* XXX */ 685 686 if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 687 strcmp(aname, prev->name) < 0) { 688 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 689 return (addrs); 690 } 691 692 SLIST_FOREACH(temp, &target_addresslist, ta) { 693 if ((cmp = strcmp(aname, temp->name)) <= 0) 694 break; 695 prev = temp; 696 } 697 698 if (temp == NULL || cmp < 0) 699 SLIST_INSERT_AFTER(prev, addrs, ta); 700 else if (cmp > 0) 701 SLIST_INSERT_AFTER(temp, addrs, ta); 702 else { 703 syslog(LOG_ERR, "Target address %s exists", addrs->name); 704 free(addrs); 705 return (NULL); 706 } 707 708 return (addrs); 709 } 710 711 int 712 target_activate_address(struct target_address *addrs) 713 { 714 struct sockaddr_in sa; 715 716 if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 717 syslog(LOG_ERR, "socket(UDP): %m"); 718 return (SNMP_ERR_RES_UNAVAIL); 719 } 720 721 (void)shutdown(addrs->socket, SHUT_RD); 722 memset(&sa, 0, sizeof(sa)); 723 sa.sin_len = sizeof(sa); 724 sa.sin_family = AF_INET; 725 726 sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 727 (addrs->address[1] << 16) | (addrs->address[2] << 8) | 728 (addrs->address[3] << 0)); 729 sa.sin_port = htons(addrs->address[4]) << 8 | 730 htons(addrs->address[5]) << 0; 731 732 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 733 syslog(LOG_ERR, "connect(%s,%u): %m", 734 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 735 (void)close(addrs->socket); 736 return (SNMP_ERR_GENERR); 737 } 738 739 addrs->status = RowStatus_active; 740 741 return (SNMP_ERR_NOERROR); 742 } 743 744 int 745 target_delete_address(struct target_address *addrs) 746 { 747 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 748 if (addrs->status == RowStatus_active) 749 close(addrs->socket); 750 free(addrs); 751 752 return (0); 753 } 754 755 struct target_param * 756 target_first_param(void) 757 { 758 return (SLIST_FIRST(&target_paramlist)); 759 } 760 761 struct target_param * 762 target_next_param(struct target_param *param) 763 { 764 if (param == NULL) 765 return (NULL); 766 767 return (SLIST_NEXT(param, tp)); 768 } 769 770 struct target_param * 771 target_new_param(char *pname) 772 { 773 int cmp; 774 struct target_param *param, *temp, *prev; 775 776 SLIST_FOREACH(param, &target_paramlist, tp) 777 if (strcmp(pname, param->name) == 0) 778 return (NULL); 779 780 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 781 return (NULL); 782 783 memset(param, 0, sizeof(*param)); 784 strlcpy(param->name, pname, sizeof(param->name)); 785 786 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 787 strcmp(pname, prev->name) < 0) { 788 SLIST_INSERT_HEAD(&target_paramlist, param, tp); 789 return (param); 790 } 791 792 SLIST_FOREACH(temp, &target_paramlist, tp) { 793 if ((cmp = strcmp(pname, temp->name)) <= 0) 794 break; 795 prev = temp; 796 } 797 798 if (temp == NULL || cmp < 0) 799 SLIST_INSERT_AFTER(prev, param, tp); 800 else if (cmp > 0) 801 SLIST_INSERT_AFTER(temp, param, tp); 802 else { 803 syslog(LOG_ERR, "Target parameter %s exists", param->name); 804 free(param); 805 return (NULL); 806 } 807 808 return (param); 809 } 810 811 int 812 target_delete_param(struct target_param *param) 813 { 814 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 815 free(param); 816 817 return (0); 818 } 819 820 struct target_notify * 821 target_first_notify(void) 822 { 823 return (SLIST_FIRST(&target_notifylist)); 824 } 825 826 struct target_notify * 827 target_next_notify(struct target_notify *notify) 828 { 829 if (notify == NULL) 830 return (NULL); 831 832 return (SLIST_NEXT(notify, tn)); 833 } 834 835 struct target_notify * 836 target_new_notify(char *nname) 837 { 838 int cmp; 839 struct target_notify *notify, *temp, *prev; 840 841 SLIST_FOREACH(notify, &target_notifylist, tn) 842 if (strcmp(nname, notify->name) == 0) 843 return (NULL); 844 845 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 846 return (NULL); 847 848 memset(notify, 0, sizeof(*notify)); 849 strlcpy(notify->name, nname, sizeof(notify->name)); 850 851 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 852 strcmp(nname, prev->name) < 0) { 853 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 854 return (notify); 855 } 856 857 SLIST_FOREACH(temp, &target_notifylist, tn) { 858 if ((cmp = strcmp(nname, temp->name)) <= 0) 859 break; 860 prev = temp; 861 } 862 863 if (temp == NULL || cmp < 0) 864 SLIST_INSERT_AFTER(prev, notify, tn); 865 else if (cmp > 0) 866 SLIST_INSERT_AFTER(temp, notify, tn); 867 else { 868 syslog(LOG_ERR, "Notification target %s exists", notify->name); 869 free(notify); 870 return (NULL); 871 } 872 873 return (notify); 874 } 875 876 int 877 target_delete_notify(struct target_notify *notify) 878 { 879 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 880 free(notify); 881 882 return (0); 883 } 884 885 void 886 target_flush_all(void) 887 { 888 struct target_address *addrs; 889 struct target_param *param; 890 struct target_notify *notify; 891 892 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 893 SLIST_REMOVE_HEAD(&target_addresslist, ta); 894 if (addrs->status == RowStatus_active) 895 close(addrs->socket); 896 free(addrs); 897 } 898 SLIST_INIT(&target_addresslist); 899 900 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 901 SLIST_REMOVE_HEAD(&target_paramlist, tp); 902 free(param); 903 } 904 SLIST_INIT(&target_paramlist); 905 906 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 907 SLIST_REMOVE_HEAD(&target_notifylist, tn); 908 free(notify); 909 } 910 SLIST_INIT(&target_notifylist); 911 } 912