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 struct target_addresslist target_addresslist = 64 SLIST_HEAD_INITIALIZER(target_addresslist); 65 66 /* List of target parameters */ 67 struct target_paramlist target_paramlist = 68 SLIST_HEAD_INITIALIZER(target_paramlist); 69 70 /* List of notification targets */ 71 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 strcpy(pdu->community, com); 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 strcpy(pdu->community, com); 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 uint64_t etime; 468 struct usm_user *usmuser; 469 470 memset(pdu, 0, sizeof(*pdu)); 471 472 pdu->version = SNMP_V3; 473 pdu->type = SNMP_PDU_TRAP2; 474 pdu->request_id = reqid_next(trap_reqid); 475 pdu->error_index = 0; 476 pdu->error_status = SNMP_ERR_NOERROR; 477 478 pdu->bindings[0].var = oid_sysUpTime; 479 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 480 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 481 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 482 483 pdu->bindings[1].var = oid_snmpTrapOID; 484 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 485 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 486 pdu->bindings[1].v.oid = *trap_oid; 487 488 pdu->nbindings = 2; 489 490 etime = (get_ticks() - start_tick) / 100ULL; 491 if (etime < INT32_MAX) 492 snmpd_engine.engine_time = etime; 493 else { 494 start_tick = get_ticks(); 495 set_snmpd_engine(); 496 snmpd_engine.engine_time = start_tick; 497 } 498 499 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 500 snmpd_engine.engine_len); 501 pdu->engine.engine_len = snmpd_engine.engine_len; 502 pdu->engine.engine_boots = snmpd_engine.engine_boots; 503 pdu->engine.engine_time = snmpd_engine.engine_time; 504 pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 505 strlcpy(pdu->user.sec_name, target->secname, 506 sizeof(pdu->user.sec_name)); 507 pdu->security_model = target->sec_model; 508 509 pdu->context_engine_len = snmpd_engine.engine_len; 510 memcpy(pdu->context_engine, snmpd_engine.engine_id, 511 snmpd_engine.engine_len); 512 513 if (target->sec_model == SNMP_SECMODEL_USM && 514 target->sec_level != SNMP_noAuthNoPriv) { 515 usmuser = usm_find_user(pdu->engine.engine_id, 516 pdu->engine.engine_len, pdu->user.sec_name); 517 if (usmuser != NULL) { 518 pdu->user.auth_proto = usmuser->suser.auth_proto; 519 pdu->user.priv_proto = usmuser->suser.priv_proto; 520 memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 521 sizeof(pdu->user.auth_key)); 522 memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 523 sizeof(pdu->user.priv_key)); 524 } 525 snmp_pdu_init_secparams(pdu); 526 } 527 } 528 529 void 530 snmp_send_trap(const struct asn_oid *trap_oid, ...) 531 { 532 struct snmp_pdu pdu; 533 struct trapsink *t; 534 const struct snmp_value *v; 535 struct target_notify *n; 536 struct target_address *ta; 537 struct target_param *tp; 538 539 va_list ap; 540 u_char *sndbuf; 541 char *tag; 542 size_t sndlen; 543 ssize_t len; 544 int32_t ip; 545 546 TAILQ_FOREACH(t, &trapsink_list, link) { 547 if (t->status != TRAPSINK_ACTIVE) 548 continue; 549 550 if (t->version == TRAPSINK_V1) 551 snmp_create_v1_trap(&pdu, t->comm, trap_oid); 552 else 553 snmp_create_v2_trap(&pdu, t->comm, trap_oid); 554 555 va_start(ap, trap_oid); 556 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 557 pdu.bindings[pdu.nbindings++] = *v; 558 va_end(ap); 559 560 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 561 syslog(LOG_DEBUG, "send trap to %s failed: no access", 562 t->comm); 563 continue; 564 } 565 566 if ((sndbuf = buf_alloc(1)) == NULL) { 567 syslog(LOG_ERR, "trap send buffer: %m"); 568 return; 569 } 570 571 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 572 573 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 574 syslog(LOG_ERR, "send: %m"); 575 else if ((size_t)len != sndlen) 576 syslog(LOG_ERR, "send: short write %zu/%zu", 577 sndlen, (size_t)len); 578 579 free(sndbuf); 580 } 581 582 SLIST_FOREACH(n, &target_notifylist, tn) { 583 if (n->status != RowStatus_active || n->taglist[0] == '\0') 584 continue; 585 586 SLIST_FOREACH(ta, &target_addresslist, ta) 587 if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 588 (tag[strlen(n->taglist)] == ' ' || 589 tag[strlen(n->taglist)] == '\0' || 590 tag[strlen(n->taglist)] == '\t' || 591 tag[strlen(n->taglist)] == '\r' || 592 tag[strlen(n->taglist)] == '\n') && 593 ta->status == RowStatus_active) 594 break; 595 if (ta == NULL) 596 continue; 597 598 SLIST_FOREACH(tp, &target_paramlist, tp) 599 if (strcmp(tp->name, ta->paramname) == 0 && 600 tp->status == 1) 601 break; 602 if (tp == NULL) 603 continue; 604 605 switch (tp->mpmodel) { 606 case SNMP_MPM_SNMP_V1: 607 snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 608 break; 609 610 case SNMP_MPM_SNMP_V2c: 611 snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 612 break; 613 614 case SNMP_MPM_SNMP_V3: 615 snmp_create_v3_trap(&pdu, tp, trap_oid); 616 break; 617 618 default: 619 continue; 620 } 621 622 va_start(ap, trap_oid); 623 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 624 pdu.bindings[pdu.nbindings++] = *v; 625 va_end(ap); 626 627 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 628 syslog(LOG_DEBUG, "send trap to %s failed: no access", 629 t->comm); 630 continue; 631 } 632 633 if ((sndbuf = buf_alloc(1)) == NULL) { 634 syslog(LOG_ERR, "trap send buffer: %m"); 635 return; 636 } 637 638 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 639 640 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 641 syslog(LOG_ERR, "send: %m"); 642 else if ((size_t)len != sndlen) 643 syslog(LOG_ERR, "send: short write %zu/%zu", 644 sndlen, (size_t)len); 645 646 free(sndbuf); 647 } 648 } 649 650 /* 651 * RFC 3413 SNMP Management Target MIB 652 */ 653 struct snmpd_target_stats * 654 bsnmpd_get_target_stats(void) 655 { 656 return (&snmpd_target_stats); 657 } 658 659 struct target_address * 660 target_first_address(void) 661 { 662 return (SLIST_FIRST(&target_addresslist)); 663 } 664 665 struct target_address * 666 target_next_address(struct target_address *addrs) 667 { 668 if (addrs == NULL) 669 return (NULL); 670 671 return (SLIST_NEXT(addrs, ta)); 672 } 673 674 struct target_address * 675 target_new_address(char *aname) 676 { 677 int cmp; 678 struct target_address *addrs, *temp, *prev; 679 680 SLIST_FOREACH(addrs, &target_addresslist, ta) 681 if (strcmp(aname, addrs->name) == 0) 682 return (NULL); 683 684 if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 685 return (NULL); 686 687 memset(addrs, 0, sizeof(*addrs)); 688 strlcpy(addrs->name, aname, sizeof(addrs->name)); 689 addrs->timeout = 150; 690 addrs->retry = 3; /* XXX */ 691 692 if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 693 strcmp(aname, prev->name) < 0) { 694 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 695 return (addrs); 696 } 697 698 SLIST_FOREACH(temp, &target_addresslist, ta) { 699 if ((cmp = strcmp(aname, temp->name)) <= 0) 700 break; 701 prev = temp; 702 } 703 704 if (temp == NULL || cmp < 0) 705 SLIST_INSERT_AFTER(prev, addrs, ta); 706 else if (cmp > 0) 707 SLIST_INSERT_AFTER(temp, addrs, ta); 708 else { 709 syslog(LOG_ERR, "Target address %s exists", addrs->name); 710 free(addrs); 711 return (NULL); 712 } 713 714 return (addrs); 715 } 716 717 int 718 target_activate_address(struct target_address *addrs) 719 { 720 struct sockaddr_in sa; 721 722 if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 723 syslog(LOG_ERR, "socket(UDP): %m"); 724 return (SNMP_ERR_RES_UNAVAIL); 725 } 726 727 (void)shutdown(addrs->socket, SHUT_RD); 728 memset(&sa, 0, sizeof(sa)); 729 sa.sin_len = sizeof(sa); 730 sa.sin_family = AF_INET; 731 732 sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 733 (addrs->address[1] << 16) | (addrs->address[2] << 8) | 734 (addrs->address[3] << 0)); 735 sa.sin_port = htons(addrs->address[4]) << 8 | 736 htons(addrs->address[5]) << 0; 737 738 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 739 syslog(LOG_ERR, "connect(%s,%u): %m", 740 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 741 (void)close(addrs->socket); 742 return (SNMP_ERR_GENERR); 743 } 744 745 addrs->status = RowStatus_active; 746 747 return (SNMP_ERR_NOERROR); 748 } 749 750 int 751 target_delete_address(struct target_address *addrs) 752 { 753 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 754 if (addrs->status == RowStatus_active) 755 close(addrs->socket); 756 free(addrs); 757 758 return (0); 759 } 760 761 struct target_param * 762 target_first_param(void) 763 { 764 return (SLIST_FIRST(&target_paramlist)); 765 } 766 767 struct target_param * 768 target_next_param(struct target_param *param) 769 { 770 if (param == NULL) 771 return (NULL); 772 773 return (SLIST_NEXT(param, tp)); 774 } 775 776 struct target_param * 777 target_new_param(char *pname) 778 { 779 int cmp; 780 struct target_param *param, *temp, *prev; 781 782 SLIST_FOREACH(param, &target_paramlist, tp) 783 if (strcmp(pname, param->name) == 0) 784 return (NULL); 785 786 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 787 return (NULL); 788 789 memset(param, 0, sizeof(*param)); 790 strlcpy(param->name, pname, sizeof(param->name)); 791 792 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 793 strcmp(pname, prev->name) < 0) { 794 SLIST_INSERT_HEAD(&target_paramlist, param, tp); 795 return (param); 796 } 797 798 SLIST_FOREACH(temp, &target_paramlist, tp) { 799 if ((cmp = strcmp(pname, temp->name)) <= 0) 800 break; 801 prev = temp; 802 } 803 804 if (temp == NULL || cmp < 0) 805 SLIST_INSERT_AFTER(prev, param, tp); 806 else if (cmp > 0) 807 SLIST_INSERT_AFTER(temp, param, tp); 808 else { 809 syslog(LOG_ERR, "Target parameter %s exists", param->name); 810 free(param); 811 return (NULL); 812 } 813 814 return (param); 815 } 816 817 int 818 target_delete_param(struct target_param *param) 819 { 820 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 821 free(param); 822 823 return (0); 824 } 825 826 struct target_notify * 827 target_first_notify(void) 828 { 829 return (SLIST_FIRST(&target_notifylist)); 830 } 831 832 struct target_notify * 833 target_next_notify(struct target_notify *notify) 834 { 835 if (notify == NULL) 836 return (NULL); 837 838 return (SLIST_NEXT(notify, tn)); 839 } 840 841 struct target_notify * 842 target_new_notify(char *nname) 843 { 844 int cmp; 845 struct target_notify *notify, *temp, *prev; 846 847 SLIST_FOREACH(notify, &target_notifylist, tn) 848 if (strcmp(nname, notify->name) == 0) 849 return (NULL); 850 851 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 852 return (NULL); 853 854 memset(notify, 0, sizeof(*notify)); 855 strlcpy(notify->name, nname, sizeof(notify->name)); 856 857 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 858 strcmp(nname, prev->name) < 0) { 859 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 860 return (notify); 861 } 862 863 SLIST_FOREACH(temp, &target_notifylist, tn) { 864 if ((cmp = strcmp(nname, temp->name)) <= 0) 865 break; 866 prev = temp; 867 } 868 869 if (temp == NULL || cmp < 0) 870 SLIST_INSERT_AFTER(prev, notify, tn); 871 else if (cmp > 0) 872 SLIST_INSERT_AFTER(temp, notify, tn); 873 else { 874 syslog(LOG_ERR, "Notification target %s exists", notify->name); 875 free(notify); 876 return (NULL); 877 } 878 879 return (notify); 880 } 881 882 int 883 target_delete_notify(struct target_notify *notify) 884 { 885 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 886 free(notify); 887 888 return (0); 889 } 890 891 void 892 target_flush_all(void) 893 { 894 struct target_address *addrs; 895 struct target_param *param; 896 struct target_notify *notify; 897 898 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 899 SLIST_REMOVE_HEAD(&target_addresslist, ta); 900 if (addrs->status == RowStatus_active) 901 close(addrs->socket); 902 free(addrs); 903 } 904 SLIST_INIT(&target_addresslist); 905 906 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 907 SLIST_REMOVE_HEAD(&target_paramlist, tp); 908 free(param); 909 } 910 SLIST_INIT(&target_paramlist); 911 912 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 913 SLIST_REMOVE_HEAD(&target_notifylist, tn); 914 free(notify); 915 } 916 SLIST_INIT(&target_notifylist); 917 } 918