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