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 | addrs->address[5]); 730 731 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 732 syslog(LOG_ERR, "connect(%s,%u): %m", 733 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 734 (void)close(addrs->socket); 735 return (SNMP_ERR_GENERR); 736 } 737 738 addrs->status = RowStatus_active; 739 740 return (SNMP_ERR_NOERROR); 741 } 742 743 int 744 target_delete_address(struct target_address *addrs) 745 { 746 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 747 if (addrs->status == RowStatus_active) 748 close(addrs->socket); 749 free(addrs); 750 751 return (0); 752 } 753 754 struct target_param * 755 target_first_param(void) 756 { 757 return (SLIST_FIRST(&target_paramlist)); 758 } 759 760 struct target_param * 761 target_next_param(struct target_param *param) 762 { 763 if (param == NULL) 764 return (NULL); 765 766 return (SLIST_NEXT(param, tp)); 767 } 768 769 struct target_param * 770 target_new_param(char *pname) 771 { 772 int cmp; 773 struct target_param *param, *temp, *prev; 774 775 SLIST_FOREACH(param, &target_paramlist, tp) 776 if (strcmp(pname, param->name) == 0) 777 return (NULL); 778 779 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 780 return (NULL); 781 782 memset(param, 0, sizeof(*param)); 783 strlcpy(param->name, pname, sizeof(param->name)); 784 785 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 786 strcmp(pname, prev->name) < 0) { 787 SLIST_INSERT_HEAD(&target_paramlist, param, tp); 788 return (param); 789 } 790 791 SLIST_FOREACH(temp, &target_paramlist, tp) { 792 if ((cmp = strcmp(pname, temp->name)) <= 0) 793 break; 794 prev = temp; 795 } 796 797 if (temp == NULL || cmp < 0) 798 SLIST_INSERT_AFTER(prev, param, tp); 799 else if (cmp > 0) 800 SLIST_INSERT_AFTER(temp, param, tp); 801 else { 802 syslog(LOG_ERR, "Target parameter %s exists", param->name); 803 free(param); 804 return (NULL); 805 } 806 807 return (param); 808 } 809 810 int 811 target_delete_param(struct target_param *param) 812 { 813 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 814 free(param); 815 816 return (0); 817 } 818 819 struct target_notify * 820 target_first_notify(void) 821 { 822 return (SLIST_FIRST(&target_notifylist)); 823 } 824 825 struct target_notify * 826 target_next_notify(struct target_notify *notify) 827 { 828 if (notify == NULL) 829 return (NULL); 830 831 return (SLIST_NEXT(notify, tn)); 832 } 833 834 struct target_notify * 835 target_new_notify(char *nname) 836 { 837 int cmp; 838 struct target_notify *notify, *temp, *prev; 839 840 SLIST_FOREACH(notify, &target_notifylist, tn) 841 if (strcmp(nname, notify->name) == 0) 842 return (NULL); 843 844 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 845 return (NULL); 846 847 memset(notify, 0, sizeof(*notify)); 848 strlcpy(notify->name, nname, sizeof(notify->name)); 849 850 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 851 strcmp(nname, prev->name) < 0) { 852 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 853 return (notify); 854 } 855 856 SLIST_FOREACH(temp, &target_notifylist, tn) { 857 if ((cmp = strcmp(nname, temp->name)) <= 0) 858 break; 859 prev = temp; 860 } 861 862 if (temp == NULL || cmp < 0) 863 SLIST_INSERT_AFTER(prev, notify, tn); 864 else if (cmp > 0) 865 SLIST_INSERT_AFTER(temp, notify, tn); 866 else { 867 syslog(LOG_ERR, "Notification target %s exists", notify->name); 868 free(notify); 869 return (NULL); 870 } 871 872 return (notify); 873 } 874 875 int 876 target_delete_notify(struct target_notify *notify) 877 { 878 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 879 free(notify); 880 881 return (0); 882 } 883 884 void 885 target_flush_all(void) 886 { 887 struct target_address *addrs; 888 struct target_param *param; 889 struct target_notify *notify; 890 891 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 892 SLIST_REMOVE_HEAD(&target_addresslist, ta); 893 if (addrs->status == RowStatus_active) 894 close(addrs->socket); 895 free(addrs); 896 } 897 SLIST_INIT(&target_addresslist); 898 899 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 900 SLIST_REMOVE_HEAD(&target_paramlist, tp); 901 free(param); 902 } 903 SLIST_INIT(&target_paramlist); 904 905 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 906 SLIST_REMOVE_HEAD(&target_notifylist, tn); 907 free(notify); 908 } 909 SLIST_INIT(&target_notifylist); 910 } 911