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/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 36 * 37 * SNMPd main stuff. 38 */ 39 40 #include <sys/queue.h> 41 #include <sys/param.h> 42 #include <sys/un.h> 43 #include <sys/ucred.h> 44 #include <sys/uio.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <stddef.h> 48 #include <string.h> 49 #include <stdarg.h> 50 #include <ctype.h> 51 #include <errno.h> 52 #include <syslog.h> 53 #include <unistd.h> 54 #include <signal.h> 55 #include <dlfcn.h> 56 57 #ifdef USE_TCPWRAPPERS 58 #include <arpa/inet.h> 59 #include <tcpd.h> 60 #endif 61 62 #include "support.h" 63 #include "snmpmod.h" 64 #include "snmpd.h" 65 #include "tree.h" 66 #include "oid.h" 67 68 #define PATH_PID "/var/run/%s.pid" 69 #define PATH_CONFIG "/etc/%s.config" 70 #define PATH_ENGINE "/var/%s.engine" 71 72 uint64_t this_tick; /* start of processing of current packet (absolute) */ 73 uint64_t start_tick; /* start of processing */ 74 75 struct systemg systemg = { 76 NULL, 77 { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 78 NULL, NULL, NULL, 79 64 + 8 + 4, 80 0 81 }; 82 struct debug debug = { 83 0, /* dump_pdus */ 84 LOG_DEBUG, /* log_pri */ 85 0, /* evdebug */ 86 }; 87 88 struct snmpd snmpd = { 89 2048, /* txbuf */ 90 2048, /* rxbuf */ 91 0, /* comm_dis */ 92 0, /* auth_traps */ 93 {0, 0, 0, 0}, /* trap1addr */ 94 VERS_ENABLE_ALL,/* version_enable */ 95 }; 96 struct snmpd_stats snmpd_stats; 97 98 struct snmpd_usmstat snmpd_usmstats; 99 100 /* snmpEngine */ 101 struct snmp_engine snmpd_engine; 102 103 /* snmpSerialNo */ 104 int32_t snmp_serial_no; 105 106 struct snmpd_target_stats snmpd_target_stats; 107 108 /* search path for config files */ 109 const char *syspath = PATH_SYSCONFIG; 110 111 /* list of all loaded modules */ 112 struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 113 114 /* list of loaded modules during start-up in the order they were loaded */ 115 static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 116 117 /* list of all known communities */ 118 struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 119 120 /* list of all known USM users */ 121 static struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 122 123 /* A list of all VACM users configured, including v1, v2c and v3 */ 124 static struct vacm_userlist vacm_userlist = 125 SLIST_HEAD_INITIALIZER(vacm_userlist); 126 127 /* A list of all VACM groups */ 128 static struct vacm_grouplist vacm_grouplist = 129 SLIST_HEAD_INITIALIZER(vacm_grouplist); 130 131 static struct vacm_group vacm_default_group = { 132 .groupname = "", 133 }; 134 135 /* The list of configured access entries */ 136 static struct vacm_accesslist vacm_accesslist = 137 TAILQ_HEAD_INITIALIZER(vacm_accesslist); 138 139 /* The list of configured views */ 140 static struct vacm_viewlist vacm_viewlist = 141 SLIST_HEAD_INITIALIZER(vacm_viewlist); 142 143 /* The list of configured contexts */ 144 static struct vacm_contextlist vacm_contextlist = 145 SLIST_HEAD_INITIALIZER(vacm_contextlist); 146 147 /* list of all installed object resources */ 148 struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 149 150 /* community value generator */ 151 static u_int next_community_index = 1; 152 153 /* list of all known ranges */ 154 struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 155 156 /* identifier generator */ 157 u_int next_idrange = 1; 158 159 /* list of all current timers */ 160 struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 161 162 /* list of file descriptors */ 163 struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 164 165 /* program arguments */ 166 static char **progargs; 167 static int nprogargs; 168 169 /* current community */ 170 u_int community; 171 static struct community *comm; 172 173 /* current USM user */ 174 struct usm_user *usm_user; 175 176 /* file names */ 177 static char config_file[MAXPATHLEN + 1]; 178 static char pid_file[MAXPATHLEN + 1]; 179 char engine_file[MAXPATHLEN + 1]; 180 181 #ifndef USE_LIBBEGEMOT 182 /* event context */ 183 static evContext evctx; 184 #endif 185 186 /* signal mask */ 187 static sigset_t blocked_sigs; 188 189 /* signal handling */ 190 static int work; 191 #define WORK_DOINFO 0x0001 192 #define WORK_RECONFIG 0x0002 193 194 /* oids */ 195 static const struct asn_oid 196 oid_snmpMIB = OIDX_snmpMIB, 197 oid_begemotSnmpd = OIDX_begemotSnmpd, 198 oid_coldStart = OIDX_coldStart, 199 oid_authenticationFailure = OIDX_authenticationFailure; 200 201 const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 202 203 const struct asn_oid oid_usmUnknownEngineIDs = 204 { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 205 206 const struct asn_oid oid_usmNotInTimeWindows = 207 { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 208 209 /* request id generator for traps */ 210 u_int trap_reqid; 211 212 /* help text */ 213 static const char usgtxt[] = "\ 214 Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 215 Open Communication Systems (FhG Fokus). All rights reserved.\n\ 216 Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 217 usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 218 [-l prefix] [-m variable=value] [-p file]\n\ 219 options:\n\ 220 -d don't daemonize\n\ 221 -h print this info\n\ 222 -c file specify configuration file\n\ 223 -D options debugging options\n\ 224 -e file specify engine id file\n\ 225 -I path system include path\n\ 226 -l prefix default basename for pid and config file\n\ 227 -m var=val define variable\n\ 228 -p file specify pid file\n\ 229 "; 230 231 /* hosts_access(3) request */ 232 #ifdef USE_TCPWRAPPERS 233 static struct request_info req; 234 #endif 235 236 /* transports */ 237 extern const struct transport_def udp_trans; 238 extern const struct transport_def lsock_trans; 239 240 struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 241 242 /* forward declarations */ 243 static void snmp_printf_func(const char *fmt, ...); 244 static void snmp_error_func(const char *err, ...); 245 static void snmp_debug_func(const char *err, ...); 246 static void asn_error_func(const struct asn_buf *b, const char *err, ...); 247 248 /* 249 * Allocate rx/tx buffer. We allocate one byte more for rx. 250 */ 251 void * 252 buf_alloc(int tx) 253 { 254 void *buf; 255 256 if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 257 syslog(LOG_CRIT, "cannot allocate buffer"); 258 if (tx) 259 snmpd_stats.noTxbuf++; 260 else 261 snmpd_stats.noRxbuf++; 262 return (NULL); 263 } 264 return (buf); 265 } 266 267 /* 268 * Return the buffer size. 269 */ 270 size_t 271 buf_size(int tx) 272 { 273 return (tx ? snmpd.txbuf : snmpd.rxbuf); 274 } 275 276 /* 277 * Prepare a PDU for output 278 */ 279 void 280 snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 281 const char *dest) 282 { 283 struct asn_buf resp_b; 284 enum snmp_code code; 285 286 resp_b.asn_ptr = sndbuf; 287 resp_b.asn_len = snmpd.txbuf; 288 289 if ((code = snmp_pdu_encode(pdu, &resp_b)) != SNMP_CODE_OK) { 290 syslog(LOG_ERR, "cannot encode message (code=%d)", code); 291 abort(); 292 } 293 if (debug.dump_pdus) { 294 snmp_printf("%s <- ", dest); 295 snmp_pdu_dump(pdu); 296 } 297 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 298 } 299 300 /* 301 * Check USM PDU header credentials against local SNMP Engine & users. 302 */ 303 static enum snmp_code 304 snmp_pdu_auth_user(struct snmp_pdu *pdu) 305 { 306 usm_user = NULL; 307 308 /* un-authenticated snmpEngineId discovery */ 309 if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 310 pdu->engine.engine_len = snmpd_engine.engine_len; 311 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 312 snmpd_engine.engine_len); 313 update_snmpd_engine_time(); 314 pdu->engine.engine_boots = snmpd_engine.engine_boots; 315 pdu->engine.engine_time = snmpd_engine.engine_time; 316 pdu->flags |= SNMP_MSG_AUTODISCOVER; 317 return (SNMP_CODE_OK); 318 } 319 320 if ((usm_user = usm_find_user(pdu->engine.engine_id, 321 pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 322 usm_user->status != 1 /* active */) 323 return (SNMP_CODE_BADUSER); 324 325 if (usm_user->user_engine_len != snmpd_engine.engine_len || 326 memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 327 snmpd_engine.engine_len) != 0) 328 return (SNMP_CODE_BADENGINE); 329 330 pdu->user.priv_proto = usm_user->suser.priv_proto; 331 memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 332 sizeof(pdu->user.priv_key)); 333 334 /* authenticated snmpEngineId discovery */ 335 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 336 update_snmpd_engine_time(); 337 pdu->user.auth_proto = usm_user->suser.auth_proto; 338 memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 339 sizeof(pdu->user.auth_key)); 340 341 if (pdu->engine.engine_boots == 0 && 342 pdu->engine.engine_time == 0) { 343 update_snmpd_engine_time(); 344 pdu->flags |= SNMP_MSG_AUTODISCOVER; 345 return (SNMP_CODE_OK); 346 } 347 348 if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 349 abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 350 SNMP_TIME_WINDOW) 351 return (SNMP_CODE_NOTINTIME); 352 } 353 354 if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 355 (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 356 ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 357 usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 358 ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 359 usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 360 return (SNMP_CODE_BADSECLEVEL); 361 362 return (SNMP_CODE_OK); 363 } 364 365 /* 366 * Check whether access to each of var bindings in the PDU is allowed based 367 * on the user credentials against the configured User groups & VACM views. 368 */ 369 enum snmp_code 370 snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 371 { 372 const char *uname; 373 int32_t suboid, smodel; 374 uint32_t i; 375 struct vacm_user *vuser; 376 struct vacm_access *acl; 377 struct vacm_context *vacmctx; 378 struct vacm_view *view; 379 380 /* 381 * At least a default context exists if the snmpd_vacm(3) module is 382 * running. 383 */ 384 if (SLIST_EMPTY(&vacm_contextlist) || 385 (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 386 return (SNMP_CODE_OK); 387 388 switch (pdu->version) { 389 case SNMP_V1: 390 if ((uname = comm_string(community)) == NULL) 391 return (SNMP_CODE_FAILED); 392 smodel = SNMP_SECMODEL_SNMPv1; 393 break; 394 395 case SNMP_V2c: 396 if ((uname = comm_string(community)) == NULL) 397 return (SNMP_CODE_FAILED); 398 smodel = SNMP_SECMODEL_SNMPv2c; 399 break; 400 401 case SNMP_V3: 402 uname = pdu->user.sec_name; 403 if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 404 return (SNMP_CODE_FAILED); 405 /* Compare the PDU context engine id against the agent's */ 406 if (pdu->context_engine_len != snmpd_engine.engine_len || 407 memcmp(pdu->context_engine, snmpd_engine.engine_id, 408 snmpd_engine.engine_len) != 0) 409 return (SNMP_CODE_FAILED); 410 break; 411 412 default: 413 abort(); 414 } 415 416 SLIST_FOREACH(vuser, &vacm_userlist, vvu) 417 if (strcmp(uname, vuser->secname) == 0 && 418 vuser->sec_model == smodel) 419 break; 420 421 if (vuser == NULL || vuser->group == NULL) 422 return (SNMP_CODE_FAILED); 423 424 /* XXX: shteryana - recheck */ 425 TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 426 if (acl->group != vuser->group) 427 continue; 428 SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 429 if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 430 acl->ctx_match) == 0) 431 goto match; 432 } 433 434 return (SNMP_CODE_FAILED); 435 436 match: 437 438 switch (pdu->type) { 439 case SNMP_PDU_GET: 440 case SNMP_PDU_GETNEXT: 441 case SNMP_PDU_GETBULK: 442 if ((view = acl->read_view) == NULL) 443 return (SNMP_CODE_FAILED); 444 break; 445 446 case SNMP_PDU_SET: 447 if ((view = acl->write_view) == NULL) 448 return (SNMP_CODE_FAILED); 449 break; 450 451 case SNMP_PDU_TRAP: 452 case SNMP_PDU_INFORM: 453 case SNMP_PDU_TRAP2: 454 case SNMP_PDU_REPORT: 455 if ((view = acl->notify_view) == NULL) 456 return (SNMP_CODE_FAILED); 457 break; 458 case SNMP_PDU_RESPONSE: 459 /* NOTREACHED */ 460 return (SNMP_CODE_FAILED); 461 default: 462 abort(); 463 } 464 465 for (i = 0; i < pdu->nbindings; i++) { 466 /* XXX - view->mask*/ 467 suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 468 if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 469 *ip = i + 1; 470 return (SNMP_CODE_FAILED); 471 } 472 } 473 474 return (SNMP_CODE_OK); 475 } 476 477 /* 478 * SNMP input. Start: decode the PDU, find the user or community. 479 */ 480 enum snmpd_input_err 481 snmp_input_start(const u_char *buf, size_t len, const char *source, 482 struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 483 { 484 struct asn_buf b; 485 enum snmp_code code; 486 enum snmpd_input_err ret; 487 int sret; 488 489 /* update uptime */ 490 this_tick = get_ticks(); 491 492 b.asn_cptr = buf; 493 b.asn_len = len; 494 495 ret = SNMPD_INPUT_OK; 496 497 /* look whether we have enough bytes for the entire PDU. */ 498 switch (sret = snmp_pdu_snoop(&b)) { 499 500 case 0: 501 return (SNMPD_INPUT_TRUNC); 502 503 case -1: 504 snmpd_stats.inASNParseErrs++; 505 return (SNMPD_INPUT_FAILED); 506 } 507 b.asn_len = *pdulen = (size_t)sret; 508 509 memset(pdu, 0, sizeof(*pdu)); 510 if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 511 goto decoded; 512 513 if (pdu->version == SNMP_V3) { 514 if (pdu->security_model != SNMP_SECMODEL_USM) { 515 code = SNMP_CODE_FAILED; 516 goto decoded; 517 } 518 if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 519 goto decoded; 520 if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 521 goto decoded; 522 } 523 code = snmp_pdu_decode_scoped(&b, pdu, ip); 524 525 decoded: 526 snmpd_stats.inPkts++; 527 528 switch (code) { 529 530 case SNMP_CODE_FAILED: 531 snmpd_stats.inASNParseErrs++; 532 return (SNMPD_INPUT_FAILED); 533 534 case SNMP_CODE_BADVERS: 535 bad_vers: 536 snmpd_stats.inBadVersions++; 537 return (SNMPD_INPUT_FAILED); 538 539 case SNMP_CODE_BADLEN: 540 if (pdu->type == SNMP_OP_SET) 541 ret = SNMPD_INPUT_VALBADLEN; 542 break; 543 544 case SNMP_CODE_OORANGE: 545 if (pdu->type == SNMP_OP_SET) 546 ret = SNMPD_INPUT_VALRANGE; 547 break; 548 549 case SNMP_CODE_BADENC: 550 if (pdu->type == SNMP_OP_SET) 551 ret = SNMPD_INPUT_VALBADENC; 552 break; 553 554 case SNMP_CODE_BADSECLEVEL: 555 snmpd_usmstats.unsupported_seclevels++; 556 return (SNMPD_INPUT_FAILED); 557 558 case SNMP_CODE_NOTINTIME: 559 snmpd_usmstats.not_in_time_windows++; 560 return (SNMPD_INPUT_FAILED); 561 562 case SNMP_CODE_BADUSER: 563 snmpd_usmstats.unknown_users++; 564 return (SNMPD_INPUT_FAILED); 565 566 case SNMP_CODE_BADENGINE: 567 snmpd_usmstats.unknown_engine_ids++; 568 return (SNMPD_INPUT_FAILED); 569 570 case SNMP_CODE_BADDIGEST: 571 snmpd_usmstats.wrong_digests++; 572 return (SNMPD_INPUT_FAILED); 573 574 case SNMP_CODE_EDECRYPT: 575 snmpd_usmstats.decrypt_errors++; 576 return (SNMPD_INPUT_FAILED); 577 578 case SNMP_CODE_OK: 579 switch (pdu->version) { 580 581 case SNMP_V1: 582 if (!(snmpd.version_enable & VERS_ENABLE_V1)) 583 goto bad_vers; 584 break; 585 586 case SNMP_V2c: 587 if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 588 goto bad_vers; 589 break; 590 591 case SNMP_V3: 592 if (!(snmpd.version_enable & VERS_ENABLE_V3)) 593 goto bad_vers; 594 break; 595 596 case SNMP_Verr: 597 goto bad_vers; 598 } 599 break; 600 } 601 602 if (debug.dump_pdus) { 603 snmp_printf("%s -> ", source); 604 snmp_pdu_dump(pdu); 605 } 606 607 /* 608 * Look, whether we know the community or user 609 */ 610 611 if (pdu->version != SNMP_V3) { 612 TAILQ_FOREACH(comm, &community_list, link) 613 if (comm->string != NULL && 614 strcmp(comm->string, pdu->community) == 0) 615 break; 616 617 if (comm == NULL) { 618 snmpd_stats.inBadCommunityNames++; 619 snmp_pdu_free(pdu); 620 if (snmpd.auth_traps) 621 snmp_send_trap(&oid_authenticationFailure, 622 (struct snmp_value *)NULL); 623 ret = SNMPD_INPUT_BAD_COMM; 624 } else 625 community = comm->value; 626 } else if (pdu->nbindings == 0) { 627 /* RFC 3414 - snmpEngineID Discovery */ 628 if (strlen(pdu->user.sec_name) == 0) { 629 asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 630 &oid_usmUnknownEngineIDs); 631 pdu->context_engine_len = snmpd_engine.engine_len; 632 memcpy(pdu->context_engine, snmpd_engine.engine_id, 633 snmpd_engine.engine_len); 634 } else if (pdu->engine.engine_boots == 0 && 635 pdu->engine.engine_time == 0) { 636 asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 637 &oid_usmNotInTimeWindows); 638 update_snmpd_engine_time(); 639 pdu->engine.engine_boots = snmpd_engine.engine_boots; 640 pdu->engine.engine_time = snmpd_engine.engine_time; 641 } 642 } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 643 (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 644 snmpd_usmstats.not_in_time_windows++; 645 ret = SNMPD_INPUT_FAILED; 646 } 647 648 if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 649 ret = SNMPD_INPUT_FAILED; 650 651 return (ret); 652 } 653 654 /* 655 * Will return only _OK or _FAILED 656 */ 657 enum snmpd_input_err 658 snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 659 u_char *sndbuf, size_t *sndlen, const char *source, 660 enum snmpd_input_err ierr, int32_t ivar, void *data) 661 { 662 struct snmp_pdu resp; 663 struct asn_buf resp_b, pdu_b; 664 enum snmp_ret ret; 665 666 resp_b.asn_ptr = sndbuf; 667 resp_b.asn_len = snmpd.txbuf; 668 669 pdu_b.asn_cptr = rcvbuf; 670 pdu_b.asn_len = rcvlen; 671 672 if (ierr != SNMPD_INPUT_OK) { 673 /* error decoding the input of a SET */ 674 if (pdu->version == SNMP_V1) 675 pdu->error_status = SNMP_ERR_BADVALUE; 676 else if (ierr == SNMPD_INPUT_VALBADLEN) 677 pdu->error_status = SNMP_ERR_WRONG_LENGTH; 678 else if (ierr == SNMPD_INPUT_VALRANGE) 679 pdu->error_status = SNMP_ERR_WRONG_VALUE; 680 else 681 pdu->error_status = SNMP_ERR_WRONG_ENCODING; 682 683 pdu->error_index = ivar; 684 685 if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 686 syslog(LOG_WARNING, "could not encode error response"); 687 snmpd_stats.silentDrops++; 688 return (SNMPD_INPUT_FAILED); 689 } 690 691 if (debug.dump_pdus) { 692 snmp_printf("%s <- ", source); 693 snmp_pdu_dump(pdu); 694 } 695 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 696 return (SNMPD_INPUT_OK); 697 } 698 699 switch (pdu->type) { 700 701 case SNMP_PDU_GET: 702 ret = snmp_get(pdu, &resp_b, &resp, data); 703 break; 704 705 case SNMP_PDU_GETNEXT: 706 ret = snmp_getnext(pdu, &resp_b, &resp, data); 707 break; 708 709 case SNMP_PDU_SET: 710 ret = snmp_set(pdu, &resp_b, &resp, data); 711 break; 712 713 case SNMP_PDU_GETBULK: 714 ret = snmp_getbulk(pdu, &resp_b, &resp, data); 715 break; 716 717 default: 718 ret = SNMP_RET_IGN; 719 break; 720 } 721 722 switch (ret) { 723 724 case SNMP_RET_OK: 725 /* normal return - send a response */ 726 if (debug.dump_pdus) { 727 snmp_printf("%s <- ", source); 728 snmp_pdu_dump(&resp); 729 } 730 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 731 snmp_pdu_free(&resp); 732 return (SNMPD_INPUT_OK); 733 734 case SNMP_RET_IGN: 735 /* error - send nothing */ 736 snmpd_stats.silentDrops++; 737 return (SNMPD_INPUT_FAILED); 738 739 case SNMP_RET_ERR: 740 /* error - send error response. The snmp routine has 741 * changed the error fields in the original message. */ 742 resp_b.asn_ptr = sndbuf; 743 resp_b.asn_len = snmpd.txbuf; 744 if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 745 syslog(LOG_WARNING, "could not encode error response"); 746 snmpd_stats.silentDrops++; 747 return (SNMPD_INPUT_FAILED); 748 } else { 749 if (debug.dump_pdus) { 750 snmp_printf("%s <- ", source); 751 snmp_pdu_dump(pdu); 752 } 753 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 754 return (SNMPD_INPUT_OK); 755 } 756 } 757 abort(); 758 } 759 760 /* 761 * Insert a port into the right place in the transport's table of ports 762 */ 763 void 764 trans_insert_port(struct transport *t, struct tport *port) 765 { 766 struct tport *p; 767 768 port->transport = t; 769 TAILQ_FOREACH(p, &t->table, link) { 770 if (asn_compare_oid(&p->index, &port->index) > 0) { 771 TAILQ_INSERT_BEFORE(p, port, link); 772 return; 773 } 774 } 775 TAILQ_INSERT_TAIL(&t->table, port, link); 776 } 777 778 /* 779 * Remove a port from a transport's list 780 */ 781 void 782 trans_remove_port(struct tport *port) 783 { 784 785 TAILQ_REMOVE(&port->transport->table, port, link); 786 } 787 788 /* 789 * Find a port on a transport's list 790 */ 791 struct tport * 792 trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 793 { 794 795 return (FIND_OBJECT_OID(&t->table, idx, sub)); 796 } 797 798 /* 799 * Find next port on a transport's list 800 */ 801 struct tport * 802 trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 803 { 804 805 return (NEXT_OBJECT_OID(&t->table, idx, sub)); 806 } 807 808 /* 809 * Return first port 810 */ 811 struct tport * 812 trans_first_port(struct transport *t) 813 { 814 815 return (TAILQ_FIRST(&t->table)); 816 } 817 818 /* 819 * Iterate through all ports until a function returns a 0. 820 */ 821 struct tport * 822 trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 823 intptr_t arg) 824 { 825 struct tport *p; 826 827 TAILQ_FOREACH(p, &t->table, link) 828 if (func(p, arg) == 0) 829 return (p); 830 return (NULL); 831 } 832 833 /* 834 * Register a transport 835 */ 836 int 837 trans_register(const struct transport_def *def, struct transport **pp) 838 { 839 u_int i; 840 char or_descr[256]; 841 842 if ((*pp = malloc(sizeof(**pp))) == NULL) 843 return (SNMP_ERR_GENERR); 844 845 /* construct index */ 846 (*pp)->index.len = strlen(def->name) + 1; 847 (*pp)->index.subs[0] = strlen(def->name); 848 for (i = 0; i < (*pp)->index.subs[0]; i++) 849 (*pp)->index.subs[i + 1] = def->name[i]; 850 851 (*pp)->vtab = def; 852 853 if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 854 free(*pp); 855 return (SNMP_ERR_INCONS_VALUE); 856 } 857 858 /* register module */ 859 snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 860 if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 861 free(*pp); 862 return (SNMP_ERR_GENERR); 863 } 864 865 INSERT_OBJECT_OID((*pp), &transport_list); 866 867 TAILQ_INIT(&(*pp)->table); 868 869 return (SNMP_ERR_NOERROR); 870 } 871 872 /* 873 * Unregister transport 874 */ 875 int 876 trans_unregister(struct transport *t) 877 { 878 if (!TAILQ_EMPTY(&t->table)) 879 return (SNMP_ERR_INCONS_VALUE); 880 881 or_unregister(t->or_index); 882 TAILQ_REMOVE(&transport_list, t, link); 883 884 return (SNMP_ERR_NOERROR); 885 } 886 887 /* 888 * File descriptor support 889 */ 890 #ifdef USE_LIBBEGEMOT 891 static void 892 input(int fd, int mask __unused, void *uap) 893 #else 894 static void 895 input(evContext ctx __unused, void *uap, int fd, int mask __unused) 896 #endif 897 { 898 struct fdesc *f = uap; 899 900 (*f->func)(fd, f->udata); 901 } 902 903 void 904 fd_suspend(void *p) 905 { 906 struct fdesc *f = p; 907 908 #ifdef USE_LIBBEGEMOT 909 if (f->id >= 0) { 910 poll_unregister(f->id); 911 f->id = -1; 912 } 913 #else 914 if (evTestID(f->id)) { 915 (void)evDeselectFD(evctx, f->id); 916 evInitID(&f->id); 917 } 918 #endif 919 } 920 921 int 922 fd_resume(void *p) 923 { 924 struct fdesc *f = p; 925 int err; 926 927 #ifdef USE_LIBBEGEMOT 928 if (f->id >= 0) 929 return (0); 930 if ((f->id = poll_register(f->fd, input, f, RPOLL_IN)) < 0) { 931 err = errno; 932 syslog(LOG_ERR, "select fd %d: %m", f->fd); 933 errno = err; 934 return (-1); 935 } 936 #else 937 if (evTestID(f->id)) 938 return (0); 939 if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 940 err = errno; 941 syslog(LOG_ERR, "select fd %d: %m", f->fd); 942 errno = err; 943 return (-1); 944 } 945 #endif 946 return (0); 947 } 948 949 void * 950 fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 951 { 952 struct fdesc *f; 953 int err; 954 955 if ((f = malloc(sizeof(struct fdesc))) == NULL) { 956 err = errno; 957 syslog(LOG_ERR, "fd_select: %m"); 958 errno = err; 959 return (NULL); 960 } 961 f->fd = fd; 962 f->func = func; 963 f->udata = udata; 964 f->owner = mod; 965 #ifdef USE_LIBBEGEMOT 966 f->id = -1; 967 #else 968 evInitID(&f->id); 969 #endif 970 971 if (fd_resume(f)) { 972 err = errno; 973 free(f); 974 errno = err; 975 return (NULL); 976 } 977 978 LIST_INSERT_HEAD(&fdesc_list, f, link); 979 980 return (f); 981 } 982 983 void 984 fd_deselect(void *p) 985 { 986 struct fdesc *f = p; 987 988 LIST_REMOVE(f, link); 989 fd_suspend(f); 990 free(f); 991 } 992 993 static void 994 fd_flush(struct lmodule *mod) 995 { 996 struct fdesc *t, *t1; 997 998 t = LIST_FIRST(&fdesc_list); 999 while (t != NULL) { 1000 t1 = LIST_NEXT(t, link); 1001 if (t->owner == mod) 1002 fd_deselect(t); 1003 t = t1; 1004 } 1005 } 1006 1007 /* 1008 * Consume a message from the input buffer 1009 */ 1010 static void 1011 snmp_input_consume(struct port_input *pi) 1012 { 1013 if (!pi->stream) { 1014 /* always consume everything */ 1015 pi->length = 0; 1016 return; 1017 } 1018 if (pi->consumed >= pi->length) { 1019 /* all bytes consumed */ 1020 pi->length = 0; 1021 return; 1022 } 1023 memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 1024 pi->length -= pi->consumed; 1025 } 1026 1027 /* 1028 * Input from a socket 1029 */ 1030 int 1031 snmpd_input(struct port_input *pi, struct tport *tport) 1032 { 1033 u_char *sndbuf; 1034 size_t sndlen; 1035 struct snmp_pdu pdu; 1036 enum snmpd_input_err ierr, ferr; 1037 enum snmpd_proxy_err perr; 1038 ssize_t ret, slen; 1039 int32_t vi; 1040 #ifdef USE_TCPWRAPPERS 1041 char client[16]; 1042 #endif 1043 1044 ret = tport->transport->vtab->recv(tport, pi); 1045 if (ret == -1) 1046 return (-1); 1047 1048 #ifdef USE_TCPWRAPPERS 1049 /* 1050 * In case of AF_INET{6} peer, do hosts_access(5) check. 1051 */ 1052 if (pi->peer->sa_family != AF_LOCAL && 1053 inet_ntop(pi->peer->sa_family, 1054 &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 1055 client, sizeof(client)) != NULL) { 1056 request_set(&req, RQ_CLIENT_ADDR, client, 0); 1057 if (hosts_access(&req) == 0) { 1058 syslog(LOG_ERR, "refused connection from %.500s", 1059 eval_client(&req)); 1060 return (-1); 1061 } 1062 } else if (pi->peer->sa_family != AF_LOCAL) 1063 syslog(LOG_ERR, "inet_ntop(): %m"); 1064 #endif 1065 1066 /* 1067 * Handle input 1068 */ 1069 ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 1070 &pi->consumed); 1071 if (ierr == SNMPD_INPUT_TRUNC) { 1072 /* need more bytes. This is ok only for streaming transports. 1073 * but only if we have not reached bufsiz yet. */ 1074 if (pi->stream) { 1075 if (pi->length == buf_size(0)) { 1076 snmpd_stats.silentDrops++; 1077 return (-1); 1078 } 1079 return (0); 1080 } 1081 snmpd_stats.silentDrops++; 1082 return (-1); 1083 } 1084 1085 /* can't check for bad SET pdus here, because a proxy may have to 1086 * check the access first. We don't want to return an error response 1087 * to a proxy PDU with a wrong community */ 1088 if (ierr == SNMPD_INPUT_FAILED) { 1089 /* for streaming transports this is fatal */ 1090 if (pi->stream) 1091 return (-1); 1092 snmp_input_consume(pi); 1093 return (0); 1094 } 1095 if (ierr == SNMPD_INPUT_BAD_COMM) { 1096 snmp_input_consume(pi); 1097 return (0); 1098 } 1099 1100 /* 1101 * If that is a module community and the module has a proxy function, 1102 * the hand it over to the module. 1103 */ 1104 if (comm != NULL && comm->owner != NULL && 1105 comm->owner->config->proxy != NULL) { 1106 perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1107 &tport->index, pi->peer, pi->peerlen, ierr, vi, 1108 !pi->cred || pi->priv); 1109 1110 switch (perr) { 1111 1112 case SNMPD_PROXY_OK: 1113 snmp_input_consume(pi); 1114 return (0); 1115 1116 case SNMPD_PROXY_REJ: 1117 break; 1118 1119 case SNMPD_PROXY_DROP: 1120 snmp_input_consume(pi); 1121 snmp_pdu_free(&pdu); 1122 snmpd_stats.proxyDrops++; 1123 return (0); 1124 1125 case SNMPD_PROXY_BADCOMM: 1126 snmp_input_consume(pi); 1127 snmp_pdu_free(&pdu); 1128 snmpd_stats.inBadCommunityNames++; 1129 if (snmpd.auth_traps) 1130 snmp_send_trap(&oid_authenticationFailure, 1131 (struct snmp_value *)NULL); 1132 return (0); 1133 1134 case SNMPD_PROXY_BADCOMMUSE: 1135 snmp_input_consume(pi); 1136 snmp_pdu_free(&pdu); 1137 snmpd_stats.inBadCommunityUses++; 1138 if (snmpd.auth_traps) 1139 snmp_send_trap(&oid_authenticationFailure, 1140 (struct snmp_value *)NULL); 1141 return (0); 1142 } 1143 } 1144 1145 /* 1146 * Check type 1147 */ 1148 if (pdu.type == SNMP_PDU_RESPONSE || 1149 pdu.type == SNMP_PDU_TRAP || 1150 pdu.type == SNMP_PDU_TRAP2) { 1151 snmpd_stats.silentDrops++; 1152 snmpd_stats.inBadPduTypes++; 1153 snmp_pdu_free(&pdu); 1154 snmp_input_consume(pi); 1155 return (0); 1156 } 1157 1158 /* 1159 * Check community 1160 */ 1161 if (pdu.version < SNMP_V3 && 1162 ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1163 (comm != NULL && comm->private != COMM_WRITE && 1164 (pdu.type == SNMP_PDU_SET || comm->private != COMM_READ)))) { 1165 snmpd_stats.inBadCommunityUses++; 1166 snmp_pdu_free(&pdu); 1167 snmp_input_consume(pi); 1168 if (snmpd.auth_traps) 1169 snmp_send_trap(&oid_authenticationFailure, 1170 (struct snmp_value *)NULL); 1171 return (0); 1172 } 1173 1174 /* 1175 * Execute it. 1176 */ 1177 if ((sndbuf = buf_alloc(1)) == NULL) { 1178 snmpd_stats.silentDrops++; 1179 snmp_pdu_free(&pdu); 1180 snmp_input_consume(pi); 1181 return (0); 1182 } 1183 ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1184 sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1185 1186 if (ferr == SNMPD_INPUT_OK) { 1187 slen = tport->transport->vtab->send(tport, sndbuf, sndlen, 1188 pi->peer, pi->peerlen); 1189 if (slen == -1) 1190 syslog(LOG_ERR, "send*: %m"); 1191 else if ((size_t)slen != sndlen) 1192 syslog(LOG_ERR, "send*: short write %zu/%zu", sndlen, 1193 (size_t)slen); 1194 } 1195 1196 snmp_pdu_free(&pdu); 1197 free(sndbuf); 1198 snmp_input_consume(pi); 1199 1200 return (0); 1201 } 1202 1203 /* 1204 * Send a PDU to a given port 1205 */ 1206 void 1207 snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1208 const struct sockaddr *addr, socklen_t addrlen) 1209 { 1210 struct transport *trans = targ; 1211 struct tport *tp; 1212 u_char *sndbuf; 1213 size_t sndlen; 1214 ssize_t len; 1215 1216 TAILQ_FOREACH(tp, &trans->table, link) 1217 if (asn_compare_oid(port, &tp->index) == 0) 1218 break; 1219 if (tp == 0) 1220 return; 1221 1222 if ((sndbuf = buf_alloc(1)) == NULL) 1223 return; 1224 1225 snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1226 1227 len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1228 1229 if (len == -1) 1230 syslog(LOG_ERR, "sendto: %m"); 1231 else if ((size_t)len != sndlen) 1232 syslog(LOG_ERR, "sendto: short write %zu/%zu", 1233 sndlen, (size_t)len); 1234 1235 free(sndbuf); 1236 } 1237 1238 1239 /* 1240 * Close an input source 1241 */ 1242 void 1243 snmpd_input_close(struct port_input *pi) 1244 { 1245 if (pi->id != NULL) 1246 fd_deselect(pi->id); 1247 if (pi->fd >= 0) 1248 (void)close(pi->fd); 1249 if (pi->buf != NULL) 1250 free(pi->buf); 1251 } 1252 1253 /* 1254 * Dump internal state. 1255 */ 1256 #ifdef USE_LIBBEGEMOT 1257 static void 1258 info_func(void) 1259 #else 1260 static void 1261 info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1262 #endif 1263 { 1264 struct lmodule *m; 1265 u_int i; 1266 char buf[10000]; 1267 1268 syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1269 for (i = 0; i < tree_size; i++) { 1270 switch (tree[i].type) { 1271 1272 case SNMP_NODE_LEAF: 1273 sprintf(buf, "LEAF: %s %s", tree[i].name, 1274 asn_oid2str(&tree[i].oid)); 1275 break; 1276 1277 case SNMP_NODE_COLUMN: 1278 sprintf(buf, "COL: %s %s", tree[i].name, 1279 asn_oid2str(&tree[i].oid)); 1280 break; 1281 } 1282 syslog(LOG_DEBUG, "%s", buf); 1283 } 1284 1285 TAILQ_FOREACH(m, &lmodules, link) 1286 if (m->config->dump) 1287 (*m->config->dump)(); 1288 } 1289 1290 /* 1291 * Re-read configuration 1292 */ 1293 #ifdef USE_LIBBEGEMOT 1294 static void 1295 config_func(void) 1296 #else 1297 static void 1298 config_func(evContext ctx __unused, void *uap __unused, 1299 const void *tag __unused) 1300 #endif 1301 { 1302 struct lmodule *m; 1303 1304 if (read_config(config_file, NULL)) { 1305 syslog(LOG_ERR, "error reading config file '%s'", config_file); 1306 return; 1307 } 1308 TAILQ_FOREACH(m, &lmodules, link) 1309 if (m->config->config) 1310 (*m->config->config)(); 1311 } 1312 1313 /* 1314 * On USR1 dump actual configuration. 1315 */ 1316 static void 1317 onusr1(int s __unused) 1318 { 1319 1320 work |= WORK_DOINFO; 1321 } 1322 static void 1323 onhup(int s __unused) 1324 { 1325 1326 work |= WORK_RECONFIG; 1327 } 1328 1329 static void 1330 onterm(int s __unused) 1331 { 1332 1333 /* allow clean-up */ 1334 exit(0); 1335 } 1336 1337 static void 1338 init_sigs(void) 1339 { 1340 struct sigaction sa; 1341 1342 sa.sa_handler = onusr1; 1343 sa.sa_flags = SA_RESTART; 1344 sigemptyset(&sa.sa_mask); 1345 if (sigaction(SIGUSR1, &sa, NULL)) { 1346 syslog(LOG_ERR, "sigaction: %m"); 1347 exit(1); 1348 } 1349 1350 sa.sa_handler = onhup; 1351 if (sigaction(SIGHUP, &sa, NULL)) { 1352 syslog(LOG_ERR, "sigaction: %m"); 1353 exit(1); 1354 } 1355 1356 sa.sa_handler = onterm; 1357 sa.sa_flags = 0; 1358 sigemptyset(&sa.sa_mask); 1359 if (sigaction(SIGTERM, &sa, NULL)) { 1360 syslog(LOG_ERR, "sigaction: %m"); 1361 exit(1); 1362 } 1363 if (sigaction(SIGINT, &sa, NULL)) { 1364 syslog(LOG_ERR, "sigaction: %m"); 1365 exit(1); 1366 } 1367 } 1368 1369 static void 1370 block_sigs(void) 1371 { 1372 sigset_t set; 1373 1374 sigfillset(&set); 1375 if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1376 syslog(LOG_ERR, "SIG_BLOCK: %m"); 1377 exit(1); 1378 } 1379 } 1380 static void 1381 unblock_sigs(void) 1382 { 1383 if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1384 syslog(LOG_ERR, "SIG_SETMASK: %m"); 1385 exit(1); 1386 } 1387 } 1388 1389 /* 1390 * Shut down 1391 */ 1392 static void 1393 term(void) 1394 { 1395 (void)unlink(pid_file); 1396 } 1397 1398 static void 1399 trans_stop(void) 1400 { 1401 struct transport *t; 1402 1403 TAILQ_FOREACH(t, &transport_list, link) 1404 (void)t->vtab->stop(1); 1405 } 1406 1407 /* 1408 * Define a macro from the command line 1409 */ 1410 static void 1411 do_macro(char *arg) 1412 { 1413 char *eq; 1414 int err; 1415 1416 if ((eq = strchr(arg, '=')) == NULL) 1417 err = define_macro(arg, ""); 1418 else { 1419 *eq++ = '\0'; 1420 err = define_macro(arg, eq); 1421 } 1422 if (err == -1) { 1423 syslog(LOG_ERR, "cannot save macro: %m"); 1424 exit(1); 1425 } 1426 } 1427 1428 /* 1429 * Re-implement getsubopt from scratch, because the second argument is broken 1430 * and will not compile with WARNS=5. 1431 */ 1432 static int 1433 getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1434 { 1435 static const char *const delim = ",\t "; 1436 u_int i; 1437 char *ptr; 1438 1439 *optp = NULL; 1440 1441 /* skip leading junk */ 1442 for (ptr = *arg; *ptr != '\0'; ptr++) 1443 if (strchr(delim, *ptr) == NULL) 1444 break; 1445 if (*ptr == '\0') { 1446 *arg = ptr; 1447 return (-1); 1448 } 1449 *optp = ptr; 1450 1451 /* find the end of the option */ 1452 while (*++ptr != '\0') 1453 if (strchr(delim, *ptr) != NULL || *ptr == '=') 1454 break; 1455 1456 if (*ptr != '\0') { 1457 if (*ptr == '=') { 1458 *ptr++ = '\0'; 1459 *valp = ptr; 1460 while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1461 ptr++; 1462 if (*ptr != '\0') 1463 *ptr++ = '\0'; 1464 } else 1465 *ptr++ = '\0'; 1466 } 1467 1468 *arg = ptr; 1469 1470 for (i = 0; *options != NULL; options++, i++) 1471 if (strcmp(*optp, *options) == 0) 1472 return (i); 1473 return (-1); 1474 } 1475 1476 int 1477 main(int argc, char *argv[]) 1478 { 1479 int opt; 1480 FILE *fp; 1481 int background = 1; 1482 struct tport *p; 1483 const char *prefix = "snmpd"; 1484 struct lmodule *m; 1485 char *value = NULL, *option; /* XXX */ 1486 struct transport *t; 1487 1488 #define DBG_DUMP 0 1489 #define DBG_EVENTS 1 1490 #define DBG_TRACE 2 1491 static const char *const debug_opts[] = { 1492 "dump", 1493 "events", 1494 "trace", 1495 NULL 1496 }; 1497 1498 snmp_printf = snmp_printf_func; 1499 snmp_error = snmp_error_func; 1500 snmp_debug = snmp_debug_func; 1501 asn_error = asn_error_func; 1502 1503 while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1504 switch (opt) { 1505 1506 case 'c': 1507 strlcpy(config_file, optarg, sizeof(config_file)); 1508 break; 1509 1510 case 'd': 1511 background = 0; 1512 break; 1513 1514 case 'D': 1515 while (*optarg) { 1516 switch (getsubopt1(&optarg, debug_opts, 1517 &value, &option)) { 1518 1519 case DBG_DUMP: 1520 debug.dump_pdus = 1; 1521 break; 1522 1523 case DBG_EVENTS: 1524 debug.evdebug++; 1525 break; 1526 1527 case DBG_TRACE: 1528 if (value == NULL) 1529 syslog(LOG_ERR, 1530 "no value for 'trace'"); 1531 else 1532 snmp_trace = strtoul(value, 1533 NULL, 0); 1534 break; 1535 1536 case -1: 1537 if (suboptarg) 1538 syslog(LOG_ERR, 1539 "unknown debug flag '%s'", 1540 option); 1541 else 1542 syslog(LOG_ERR, 1543 "missing debug flag"); 1544 break; 1545 } 1546 } 1547 break; 1548 1549 case 'e': 1550 strlcpy(engine_file, optarg, sizeof(engine_file)); 1551 break; 1552 case 'h': 1553 fprintf(stderr, "%s", usgtxt); 1554 exit(0); 1555 1556 case 'I': 1557 syspath = optarg; 1558 break; 1559 1560 case 'l': 1561 prefix = optarg; 1562 break; 1563 1564 case 'm': 1565 do_macro(optarg); 1566 break; 1567 1568 case 'p': 1569 strlcpy(pid_file, optarg, sizeof(pid_file)); 1570 break; 1571 } 1572 1573 openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1574 setlogmask(LOG_UPTO(debug.logpri - 1)); 1575 1576 if (background && daemon(0, 0) < 0) { 1577 syslog(LOG_ERR, "daemon: %m"); 1578 exit(1); 1579 } 1580 1581 argc -= optind; 1582 argv += optind; 1583 1584 progargs = argv; 1585 nprogargs = argc; 1586 1587 srandomdev(); 1588 1589 snmp_serial_no = random(); 1590 1591 #ifdef USE_TCPWRAPPERS 1592 /* 1593 * Initialize hosts_access(3) handler. 1594 */ 1595 request_init(&req, RQ_DAEMON, "snmpd", 0); 1596 sock_methods(&req); 1597 #endif 1598 1599 /* 1600 * Initialize the tree. 1601 */ 1602 if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1603 syslog(LOG_ERR, "%m"); 1604 exit(1); 1605 } 1606 memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1607 tree_size = CTREE_SIZE; 1608 1609 /* 1610 * Get standard communities 1611 */ 1612 comm_define(COMM_READ, "SNMP read", NULL, NULL); 1613 comm_define(COMM_WRITE, "SNMP write", NULL, NULL); 1614 community = COMM_INITIALIZE; 1615 1616 trap_reqid = reqid_allocate(512, NULL); 1617 1618 if (config_file[0] == '\0') 1619 snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1620 1621 init_actvals(); 1622 init_snmpd_engine(); 1623 1624 this_tick = get_ticks(); 1625 start_tick = this_tick; 1626 1627 /* start transports */ 1628 if (atexit(trans_stop) == -1) { 1629 syslog(LOG_ERR, "atexit failed: %m"); 1630 exit(1); 1631 } 1632 if (udp_trans.start() != SNMP_ERR_NOERROR) 1633 syslog(LOG_WARNING, "cannot start UDP transport"); 1634 if (lsock_trans.start() != SNMP_ERR_NOERROR) 1635 syslog(LOG_WARNING, "cannot start LSOCK transport"); 1636 1637 #ifdef USE_LIBBEGEMOT 1638 if (debug.evdebug > 0) 1639 rpoll_trace = 1; 1640 #else 1641 if (evCreate(&evctx)) { 1642 syslog(LOG_ERR, "evCreate: %m"); 1643 exit(1); 1644 } 1645 if (debug.evdebug > 0) 1646 evSetDebug(evctx, 10, stderr); 1647 #endif 1648 1649 if (engine_file[0] == '\0') 1650 snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1651 1652 if (read_config(config_file, NULL)) { 1653 syslog(LOG_ERR, "error in config file"); 1654 exit(1); 1655 } 1656 1657 TAILQ_FOREACH(t, &transport_list, link) 1658 TAILQ_FOREACH(p, &t->table, link) 1659 t->vtab->init_port(p); 1660 1661 init_sigs(); 1662 1663 if (pid_file[0] == '\0') 1664 snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1665 1666 if ((fp = fopen(pid_file, "w")) != NULL) { 1667 fprintf(fp, "%u", getpid()); 1668 fclose(fp); 1669 if (atexit(term) == -1) { 1670 syslog(LOG_ERR, "atexit failed: %m"); 1671 (void)remove(pid_file); 1672 exit(0); 1673 } 1674 } 1675 1676 if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1677 NULL) == 0) { 1678 syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1679 exit(1); 1680 } 1681 if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1682 NULL) == 0) { 1683 syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1684 exit(1); 1685 } 1686 1687 while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1688 m->flags &= ~LM_ONSTARTLIST; 1689 TAILQ_REMOVE(&modules_start, m, start); 1690 lm_start(m); 1691 } 1692 1693 snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1694 1695 for (;;) { 1696 #ifndef USE_LIBBEGEMOT 1697 evEvent event; 1698 #endif 1699 struct lmodule *mod; 1700 1701 TAILQ_FOREACH(mod, &lmodules, link) 1702 if (mod->config->idle != NULL) 1703 (*mod->config->idle)(); 1704 1705 #ifndef USE_LIBBEGEMOT 1706 if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1707 if (evDispatch(evctx, event)) 1708 syslog(LOG_ERR, "evDispatch: %m"); 1709 } else if (errno != EINTR) { 1710 syslog(LOG_ERR, "evGetNext: %m"); 1711 exit(1); 1712 } 1713 #else 1714 poll_dispatch(1); 1715 #endif 1716 1717 if (work != 0) { 1718 block_sigs(); 1719 if (work & WORK_DOINFO) { 1720 #ifdef USE_LIBBEGEMOT 1721 info_func(); 1722 #else 1723 if (evWaitFor(evctx, &work, info_func, 1724 NULL, NULL) == -1) { 1725 syslog(LOG_ERR, "evWaitFor: %m"); 1726 exit(1); 1727 } 1728 #endif 1729 } 1730 if (work & WORK_RECONFIG) { 1731 #ifdef USE_LIBBEGEMOT 1732 config_func(); 1733 #else 1734 if (evWaitFor(evctx, &work, config_func, 1735 NULL, NULL) == -1) { 1736 syslog(LOG_ERR, "evWaitFor: %m"); 1737 exit(1); 1738 } 1739 #endif 1740 } 1741 work = 0; 1742 unblock_sigs(); 1743 #ifndef USE_LIBBEGEMOT 1744 if (evDo(evctx, &work) == -1) { 1745 syslog(LOG_ERR, "evDo: %m"); 1746 exit(1); 1747 } 1748 #endif 1749 } 1750 } 1751 1752 return (0); 1753 } 1754 1755 uint64_t 1756 get_ticks(void) 1757 { 1758 struct timeval tv; 1759 uint64_t ret; 1760 1761 if (gettimeofday(&tv, NULL)) 1762 abort(); 1763 ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1764 return (ret); 1765 } 1766 1767 /* 1768 * Timer support 1769 */ 1770 1771 /* 1772 * Trampoline for the non-repeatable timers. 1773 */ 1774 #ifdef USE_LIBBEGEMOT 1775 static void 1776 tfunc(int tid __unused, void *uap) 1777 #else 1778 static void 1779 tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1780 struct timespec inter __unused) 1781 #endif 1782 { 1783 struct timer *tp = uap; 1784 1785 LIST_REMOVE(tp, link); 1786 tp->func(tp->udata); 1787 free(tp); 1788 } 1789 1790 /* 1791 * Trampoline for the repeatable timers. 1792 */ 1793 #ifdef USE_LIBBEGEMOT 1794 static void 1795 trfunc(int tid __unused, void *uap) 1796 #else 1797 static void 1798 trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1799 struct timespec inter __unused) 1800 #endif 1801 { 1802 struct timer *tp = uap; 1803 1804 tp->func(tp->udata); 1805 } 1806 1807 /* 1808 * Start a one-shot timer 1809 */ 1810 void * 1811 timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1812 { 1813 struct timer *tp; 1814 #ifndef USE_LIBBEGEMOT 1815 struct timespec due; 1816 #endif 1817 1818 if ((tp = malloc(sizeof(struct timer))) == NULL) { 1819 syslog(LOG_CRIT, "out of memory for timer"); 1820 exit(1); 1821 } 1822 1823 #ifndef USE_LIBBEGEMOT 1824 due = evAddTime(evNowTime(), 1825 evConsTime(ticks / 100, (ticks % 100) * 10000)); 1826 #endif 1827 1828 tp->udata = udata; 1829 tp->owner = mod; 1830 tp->func = func; 1831 1832 LIST_INSERT_HEAD(&timer_list, tp, link); 1833 1834 #ifdef USE_LIBBEGEMOT 1835 if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 1836 syslog(LOG_ERR, "cannot set timer: %m"); 1837 exit(1); 1838 } 1839 #else 1840 if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1841 == -1) { 1842 syslog(LOG_ERR, "cannot set timer: %m"); 1843 exit(1); 1844 } 1845 #endif 1846 return (tp); 1847 } 1848 1849 /* 1850 * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 1851 * is currently ignored and the initial number of ticks is set to the 1852 * repeat number of ticks. 1853 */ 1854 void * 1855 timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 1856 void (*func)(void *), void *udata, struct lmodule *mod) 1857 { 1858 struct timer *tp; 1859 #ifndef USE_LIBBEGEMOT 1860 struct timespec due; 1861 struct timespec inter; 1862 #endif 1863 1864 if ((tp = malloc(sizeof(struct timer))) == NULL) { 1865 syslog(LOG_CRIT, "out of memory for timer"); 1866 exit(1); 1867 } 1868 1869 #ifndef USE_LIBBEGEMOT 1870 due = evAddTime(evNowTime(), 1871 evConsTime(ticks / 100, (ticks % 100) * 10000)); 1872 inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 1873 #endif 1874 1875 tp->udata = udata; 1876 tp->owner = mod; 1877 tp->func = func; 1878 1879 LIST_INSERT_HEAD(&timer_list, tp, link); 1880 1881 #ifdef USE_LIBBEGEMOT 1882 if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 1883 syslog(LOG_ERR, "cannot set timer: %m"); 1884 exit(1); 1885 } 1886 #else 1887 if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 1888 syslog(LOG_ERR, "cannot set timer: %m"); 1889 exit(1); 1890 } 1891 #endif 1892 return (tp); 1893 } 1894 1895 /* 1896 * Stop a timer. 1897 */ 1898 void 1899 timer_stop(void *p) 1900 { 1901 struct timer *tp = p; 1902 1903 LIST_REMOVE(tp, link); 1904 #ifdef USE_LIBBEGEMOT 1905 poll_stop_timer(tp->id); 1906 #else 1907 if (evClearTimer(evctx, tp->id) == -1) { 1908 syslog(LOG_ERR, "cannot stop timer: %m"); 1909 exit(1); 1910 } 1911 #endif 1912 free(p); 1913 } 1914 1915 static void 1916 timer_flush(struct lmodule *mod) 1917 { 1918 struct timer *t, *t1; 1919 1920 t = LIST_FIRST(&timer_list); 1921 while (t != NULL) { 1922 t1 = LIST_NEXT(t, link); 1923 if (t->owner == mod) 1924 timer_stop(t); 1925 t = t1; 1926 } 1927 } 1928 1929 static void 1930 snmp_printf_func(const char *fmt, ...) 1931 { 1932 va_list ap; 1933 static char *pend = NULL; 1934 char *ret, *new; 1935 1936 va_start(ap, fmt); 1937 vasprintf(&ret, fmt, ap); 1938 va_end(ap); 1939 1940 if (ret == NULL) 1941 return; 1942 if (pend != NULL) { 1943 if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1944 == NULL) { 1945 free(ret); 1946 return; 1947 } 1948 pend = new; 1949 strcat(pend, ret); 1950 free(ret); 1951 } else 1952 pend = ret; 1953 1954 while ((ret = strchr(pend, '\n')) != NULL) { 1955 *ret = '\0'; 1956 syslog(LOG_DEBUG, "%s", pend); 1957 if (strlen(ret + 1) == 0) { 1958 free(pend); 1959 pend = NULL; 1960 break; 1961 } 1962 strcpy(pend, ret + 1); 1963 } 1964 } 1965 1966 static void 1967 snmp_error_func(const char *err, ...) 1968 { 1969 char errbuf[1000]; 1970 va_list ap; 1971 1972 if (!(snmp_trace & LOG_SNMP_ERRORS)) 1973 return; 1974 1975 va_start(ap, err); 1976 snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1977 vsnprintf(errbuf + strlen(errbuf), 1978 sizeof(errbuf) - strlen(errbuf), err, ap); 1979 va_end(ap); 1980 1981 syslog(LOG_ERR, "%s", errbuf); 1982 } 1983 1984 static void 1985 snmp_debug_func(const char *err, ...) 1986 { 1987 char errbuf[1000]; 1988 va_list ap; 1989 1990 va_start(ap, err); 1991 snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1992 vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1993 err, ap); 1994 va_end(ap); 1995 1996 syslog(LOG_DEBUG, "%s", errbuf); 1997 } 1998 1999 static void 2000 asn_error_func(const struct asn_buf *b, const char *err, ...) 2001 { 2002 char errbuf[1000]; 2003 va_list ap; 2004 u_int i; 2005 2006 if (!(snmp_trace & LOG_ASN1_ERRORS)) 2007 return; 2008 2009 va_start(ap, err); 2010 snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 2011 vsnprintf(errbuf + strlen(errbuf), 2012 sizeof(errbuf) - strlen(errbuf), err, ap); 2013 va_end(ap); 2014 2015 if (b != NULL) { 2016 snprintf(errbuf + strlen(errbuf), 2017 sizeof(errbuf) - strlen(errbuf), " at"); 2018 for (i = 0; b->asn_len > i; i++) 2019 snprintf(errbuf + strlen(errbuf), 2020 sizeof(errbuf) - strlen(errbuf), 2021 " %02x", b->asn_cptr[i]); 2022 } 2023 2024 syslog(LOG_ERR, "%s", errbuf); 2025 } 2026 2027 /* 2028 * Create a new community 2029 */ 2030 struct community* 2031 comm_define_ordered(u_int priv, const char *descr, struct asn_oid *idx, 2032 struct lmodule *owner, const char *str) 2033 { 2034 struct community *c, *p; 2035 u_int ncomm; 2036 2037 ncomm = idx->subs[idx->len - 1]; 2038 2039 /* check that community doesn't already exist */ 2040 TAILQ_FOREACH(c, &community_list, link) 2041 if (c->value == ncomm) 2042 return (c); 2043 2044 if ((c = malloc(sizeof(struct community))) == NULL) { 2045 syslog(LOG_ERR, "%s: %m", __func__); 2046 return (NULL); 2047 } 2048 c->owner = owner; 2049 c->value = ncomm; 2050 c->descr = descr; 2051 c->string = NULL; 2052 c->private = priv; 2053 2054 if (str != NULL) { 2055 if((c->string = malloc(strlen(str)+1)) == NULL) { 2056 free(c); 2057 return (NULL); 2058 } 2059 strcpy(c->string, str); 2060 } 2061 /* 2062 * Insert ordered 2063 */ 2064 c->index = *idx; 2065 TAILQ_FOREACH(p, &community_list, link) { 2066 if (asn_compare_oid(&p->index, &c->index) > 0) { 2067 TAILQ_INSERT_BEFORE(p, c, link); 2068 break; 2069 } 2070 } 2071 if (p == NULL) 2072 TAILQ_INSERT_TAIL(&community_list, c, link); 2073 return (c); 2074 } 2075 2076 u_int 2077 comm_define(u_int priv, const char *descr, struct lmodule *owner, 2078 const char *str) 2079 { 2080 struct asn_oid idx, *p; 2081 struct community *c; 2082 u_int ncomm; 2083 2084 /* generate an identifier */ 2085 do { 2086 if ((ncomm = next_community_index++) == UINT_MAX) 2087 next_community_index = 1; 2088 TAILQ_FOREACH(c, &community_list, link) 2089 if (c->value == ncomm) 2090 break; 2091 } while (c != NULL); 2092 2093 /* make index */ 2094 if (owner != NULL) 2095 p = &owner->index; 2096 else { 2097 p = &idx; 2098 p->len = 1; 2099 p->subs[0] = 0; 2100 } 2101 p->subs[p->len++] = ncomm; 2102 c = comm_define_ordered(priv, descr, p, owner, str); 2103 if (c == NULL) 2104 return (0); 2105 return (c->value); 2106 } 2107 2108 const char * 2109 comm_string(u_int ncomm) 2110 { 2111 struct community *p; 2112 2113 TAILQ_FOREACH(p, &community_list, link) 2114 if (p->value == ncomm) 2115 return (p->string); 2116 return (NULL); 2117 } 2118 2119 /* 2120 * Delete all communities allocated by a module 2121 */ 2122 static void 2123 comm_flush(struct lmodule *mod) 2124 { 2125 struct community *p, *p1; 2126 2127 p = TAILQ_FIRST(&community_list); 2128 while (p != NULL) { 2129 p1 = TAILQ_NEXT(p, link); 2130 if (p->owner == mod) { 2131 free(p->string); 2132 TAILQ_REMOVE(&community_list, p, link); 2133 free(p); 2134 } 2135 p = p1; 2136 } 2137 } 2138 2139 /* 2140 * Request ID handling. 2141 * 2142 * Allocate a new range of request ids. Use a first fit algorithm. 2143 */ 2144 u_int 2145 reqid_allocate(int size, struct lmodule *mod) 2146 { 2147 u_int type; 2148 struct idrange *r, *r1; 2149 2150 if (size <= 0 || size > INT32_MAX) { 2151 syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2152 return (0); 2153 } 2154 /* allocate a type id */ 2155 do { 2156 if ((type = next_idrange++) == UINT_MAX) 2157 next_idrange = 1; 2158 TAILQ_FOREACH(r, &idrange_list, link) 2159 if (r->type == type) 2160 break; 2161 } while(r != NULL); 2162 2163 /* find a range */ 2164 if (TAILQ_EMPTY(&idrange_list)) 2165 r = NULL; 2166 else { 2167 r = TAILQ_FIRST(&idrange_list); 2168 if (r->base < size) { 2169 while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2170 if (r1->base - (r->base + r->size) >= size) 2171 break; 2172 r = r1; 2173 } 2174 r = r1; 2175 } 2176 if (r == NULL) { 2177 r1 = TAILQ_LAST(&idrange_list, idrange_list); 2178 if (INT32_MAX - size + 1 < r1->base + r1->size) { 2179 syslog(LOG_ERR, "out of id ranges (%u)", size); 2180 return (0); 2181 } 2182 } 2183 } 2184 2185 /* allocate structure */ 2186 if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2187 syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2188 return (0); 2189 } 2190 2191 r1->type = type; 2192 r1->size = size; 2193 r1->owner = mod; 2194 if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2195 r1->base = 0; 2196 TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2197 } else if (r == NULL) { 2198 r = TAILQ_LAST(&idrange_list, idrange_list); 2199 r1->base = r->base + r->size; 2200 TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2201 } else { 2202 r = TAILQ_PREV(r, idrange_list, link); 2203 r1->base = r->base + r->size; 2204 TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2205 } 2206 r1->next = r1->base; 2207 2208 return (type); 2209 } 2210 2211 int32_t 2212 reqid_next(u_int type) 2213 { 2214 struct idrange *r; 2215 int32_t id; 2216 2217 TAILQ_FOREACH(r, &idrange_list, link) 2218 if (r->type == type) 2219 break; 2220 if (r == NULL) { 2221 syslog(LOG_CRIT, "wrong idrange type"); 2222 abort(); 2223 } 2224 if ((id = r->next++) == r->base + (r->size - 1)) 2225 r->next = r->base; 2226 return (id); 2227 } 2228 2229 int32_t 2230 reqid_base(u_int type) 2231 { 2232 struct idrange *r; 2233 2234 TAILQ_FOREACH(r, &idrange_list, link) 2235 if (r->type == type) 2236 return (r->base); 2237 syslog(LOG_CRIT, "wrong idrange type"); 2238 abort(); 2239 } 2240 2241 u_int 2242 reqid_type(int32_t reqid) 2243 { 2244 struct idrange *r; 2245 2246 TAILQ_FOREACH(r, &idrange_list, link) 2247 if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2248 return (r->type); 2249 return (0); 2250 } 2251 2252 int 2253 reqid_istype(int32_t reqid, u_int type) 2254 { 2255 return (reqid_type(reqid) == type); 2256 } 2257 2258 /* 2259 * Delete all communities allocated by a module 2260 */ 2261 static void 2262 reqid_flush(struct lmodule *mod) 2263 { 2264 struct idrange *p, *p1; 2265 2266 p = TAILQ_FIRST(&idrange_list); 2267 while (p != NULL) { 2268 p1 = TAILQ_NEXT(p, link); 2269 if (p->owner == mod) { 2270 TAILQ_REMOVE(&idrange_list, p, link); 2271 free(p); 2272 } 2273 p = p1; 2274 } 2275 } 2276 2277 /* 2278 * Merge the given tree for the given module into the main tree. 2279 */ 2280 static int 2281 compare_node(const void *v1, const void *v2) 2282 { 2283 const struct snmp_node *n1 = v1; 2284 const struct snmp_node *n2 = v2; 2285 2286 return (asn_compare_oid(&n1->oid, &n2->oid)); 2287 } 2288 static int 2289 tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2290 { 2291 struct snmp_node *xtree; 2292 u_int i; 2293 2294 xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2295 if (xtree == NULL) { 2296 syslog(LOG_ERR, "tree_merge: %m"); 2297 return (-1); 2298 } 2299 tree = xtree; 2300 memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2301 2302 for (i = 0; i < nsize; i++) 2303 tree[tree_size + i].tree_data = mod; 2304 2305 tree_size += nsize; 2306 2307 qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2308 2309 return (0); 2310 } 2311 2312 /* 2313 * Remove all nodes belonging to the loadable module 2314 */ 2315 static void 2316 tree_unmerge(struct lmodule *mod) 2317 { 2318 u_int s, d; 2319 2320 for(s = d = 0; s < tree_size; s++) 2321 if (tree[s].tree_data != mod) { 2322 if (s != d) 2323 tree[d] = tree[s]; 2324 d++; 2325 } 2326 tree_size = d; 2327 } 2328 2329 /* 2330 * Loadable modules 2331 */ 2332 struct lmodule * 2333 lm_load(const char *path, const char *section) 2334 { 2335 struct lmodule *m; 2336 int err; 2337 int i; 2338 char *av[MAX_MOD_ARGS + 1]; 2339 int ac; 2340 u_int u; 2341 2342 if ((m = malloc(sizeof(*m))) == NULL) { 2343 syslog(LOG_ERR, "lm_load: %m"); 2344 return (NULL); 2345 } 2346 m->handle = NULL; 2347 m->flags = 0; 2348 strlcpy(m->section, section, sizeof(m->section)); 2349 2350 if ((m->path = strdup(path)) == NULL) { 2351 syslog(LOG_ERR, "lm_load: %m"); 2352 goto err; 2353 } 2354 2355 /* 2356 * Make index 2357 */ 2358 m->index.subs[0] = strlen(section); 2359 m->index.len = m->index.subs[0] + 1; 2360 for (u = 0; u < m->index.subs[0]; u++) 2361 m->index.subs[u + 1] = section[u]; 2362 2363 /* 2364 * Load the object file and locate the config structure 2365 */ 2366 if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2367 syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2368 goto err; 2369 } 2370 2371 if ((m->config = dlsym(m->handle, "config")) == NULL) { 2372 syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2373 goto err; 2374 } 2375 2376 /* 2377 * Insert it into the right place 2378 */ 2379 INSERT_OBJECT_OID(m, &lmodules); 2380 2381 /* preserve order */ 2382 if (community == COMM_INITIALIZE) { 2383 m->flags |= LM_ONSTARTLIST; 2384 TAILQ_INSERT_TAIL(&modules_start, m, start); 2385 } 2386 2387 /* 2388 * make the argument vector. 2389 */ 2390 ac = 0; 2391 for (i = 0; i < nprogargs; i++) { 2392 if (strlen(progargs[i]) >= strlen(section) + 1 && 2393 strncmp(progargs[i], section, strlen(section)) == 0 && 2394 progargs[i][strlen(section)] == ':') { 2395 if (ac == MAX_MOD_ARGS) { 2396 syslog(LOG_WARNING, "too many arguments for " 2397 "module '%s", section); 2398 break; 2399 } 2400 av[ac++] = &progargs[i][strlen(section)+1]; 2401 } 2402 } 2403 av[ac] = NULL; 2404 2405 /* 2406 * Run the initialization function 2407 */ 2408 if ((err = (*m->config->init)(m, ac, av)) != 0) { 2409 syslog(LOG_ERR, "lm_load: init failed: %d", err); 2410 TAILQ_REMOVE(&lmodules, m, link); 2411 goto err; 2412 } 2413 2414 return (m); 2415 2416 err: 2417 if ((m->flags & LM_ONSTARTLIST) != 0) 2418 TAILQ_REMOVE(&modules_start, m, start); 2419 if (m->handle) 2420 dlclose(m->handle); 2421 free(m->path); 2422 free(m); 2423 return (NULL); 2424 } 2425 2426 /* 2427 * Start a module 2428 */ 2429 void 2430 lm_start(struct lmodule *mod) 2431 { 2432 const struct lmodule *m; 2433 2434 /* 2435 * Merge tree. If this fails, unload the module. 2436 */ 2437 if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2438 lm_unload(mod); 2439 return; 2440 } 2441 2442 /* 2443 * Read configuration 2444 */ 2445 if (read_config(config_file, mod)) { 2446 syslog(LOG_ERR, "error in config file"); 2447 lm_unload(mod); 2448 return; 2449 } 2450 if (mod->config->start) 2451 (*mod->config->start)(); 2452 2453 mod->flags |= LM_STARTED; 2454 2455 /* 2456 * Inform other modules 2457 */ 2458 TAILQ_FOREACH(m, &lmodules, link) 2459 if (m->config->loading) 2460 (*m->config->loading)(mod, 1); 2461 } 2462 2463 2464 /* 2465 * Unload a module. 2466 */ 2467 void 2468 lm_unload(struct lmodule *m) 2469 { 2470 int err; 2471 const struct lmodule *mod; 2472 2473 TAILQ_REMOVE(&lmodules, m, link); 2474 if (m->flags & LM_ONSTARTLIST) 2475 TAILQ_REMOVE(&modules_start, m, start); 2476 tree_unmerge(m); 2477 2478 if ((m->flags & LM_STARTED) && m->config->fini && 2479 (err = (*m->config->fini)()) != 0) 2480 syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2481 2482 comm_flush(m); 2483 reqid_flush(m); 2484 timer_flush(m); 2485 fd_flush(m); 2486 2487 dlclose(m->handle); 2488 free(m->path); 2489 2490 /* 2491 * Inform other modules 2492 */ 2493 TAILQ_FOREACH(mod, &lmodules, link) 2494 if (mod->config->loading) 2495 (*mod->config->loading)(m, 0); 2496 2497 free(m); 2498 } 2499 2500 /* 2501 * Register an object resource and return the index (or 0 on failures) 2502 */ 2503 u_int 2504 or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2505 { 2506 struct objres *objres, *or1; 2507 u_int idx; 2508 2509 /* find a free index */ 2510 idx = 1; 2511 for (objres = TAILQ_FIRST(&objres_list); 2512 objres != NULL; 2513 objres = TAILQ_NEXT(objres, link)) { 2514 if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2515 or1->index > objres->index + 1) { 2516 idx = objres->index + 1; 2517 break; 2518 } 2519 } 2520 2521 if ((objres = malloc(sizeof(*objres))) == NULL) 2522 return (0); 2523 2524 objres->index = idx; 2525 objres->oid = *or; 2526 strlcpy(objres->descr, descr, sizeof(objres->descr)); 2527 objres->uptime = (uint32_t)(get_ticks() - start_tick); 2528 objres->module = mod; 2529 2530 INSERT_OBJECT_INT(objres, &objres_list); 2531 2532 systemg.or_last_change = objres->uptime; 2533 2534 return (idx); 2535 } 2536 2537 void 2538 or_unregister(u_int idx) 2539 { 2540 struct objres *objres; 2541 2542 TAILQ_FOREACH(objres, &objres_list, link) 2543 if (objres->index == idx) { 2544 TAILQ_REMOVE(&objres_list, objres, link); 2545 free(objres); 2546 return; 2547 } 2548 } 2549 2550 /* 2551 * RFC 3414 User-based Security Model support 2552 */ 2553 2554 struct snmpd_usmstat * 2555 bsnmpd_get_usm_stats(void) 2556 { 2557 return (&snmpd_usmstats); 2558 } 2559 2560 void 2561 bsnmpd_reset_usm_stats(void) 2562 { 2563 memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2564 } 2565 2566 struct usm_user * 2567 usm_first_user(void) 2568 { 2569 return (SLIST_FIRST(&usm_userlist)); 2570 } 2571 2572 struct usm_user * 2573 usm_next_user(struct usm_user *uuser) 2574 { 2575 if (uuser == NULL) 2576 return (NULL); 2577 2578 return (SLIST_NEXT(uuser, up)); 2579 } 2580 2581 struct usm_user * 2582 usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2583 { 2584 struct usm_user *uuser; 2585 2586 SLIST_FOREACH(uuser, &usm_userlist, up) 2587 if (uuser->user_engine_len == elen && 2588 memcmp(uuser->user_engine_id, engine, elen) == 0 && 2589 strlen(uuser->suser.sec_name) == strlen(uname) && 2590 strcmp(uuser->suser.sec_name, uname) == 0) 2591 break; 2592 2593 return (uuser); 2594 } 2595 2596 static int 2597 usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2598 { 2599 uint32_t i; 2600 2601 if (u1->user_engine_len < u2->user_engine_len) 2602 return (-1); 2603 if (u1->user_engine_len > u2->user_engine_len) 2604 return (1); 2605 2606 for (i = 0; i < u1->user_engine_len; i++) { 2607 if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2608 return (-1); 2609 if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2610 return (1); 2611 } 2612 2613 if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2614 return (-1); 2615 if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2616 return (1); 2617 2618 for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2619 if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2620 return (-1); 2621 if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2622 return (1); 2623 } 2624 2625 return (0); 2626 } 2627 2628 struct usm_user * 2629 usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2630 { 2631 int cmp; 2632 struct usm_user *uuser, *temp, *prev; 2633 2634 for (uuser = usm_first_user(); uuser != NULL; 2635 (uuser = usm_next_user(uuser))) { 2636 if (uuser->user_engine_len == elen && 2637 strlen(uname) == strlen(uuser->suser.sec_name) && 2638 strcmp(uname, uuser->suser.sec_name) == 0 && 2639 memcmp(eid, uuser->user_engine_id, elen) == 0) 2640 return (NULL); 2641 } 2642 2643 if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2644 return (NULL); 2645 2646 memset(uuser, 0, sizeof(*uuser)); 2647 strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2648 memcpy(uuser->user_engine_id, eid, elen); 2649 uuser->user_engine_len = elen; 2650 2651 if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2652 usm_compare_user(uuser, prev) < 0) { 2653 SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2654 return (uuser); 2655 } 2656 2657 SLIST_FOREACH(temp, &usm_userlist, up) { 2658 if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2659 break; 2660 prev = temp; 2661 } 2662 2663 if (temp == NULL || cmp < 0) 2664 SLIST_INSERT_AFTER(prev, uuser, up); 2665 else if (cmp > 0) 2666 SLIST_INSERT_AFTER(temp, uuser, up); 2667 else { 2668 syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2669 free(uuser); 2670 return (NULL); 2671 } 2672 2673 return (uuser); 2674 } 2675 2676 void 2677 usm_delete_user(struct usm_user *uuser) 2678 { 2679 SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2680 free(uuser); 2681 } 2682 2683 void 2684 usm_flush_users(void) 2685 { 2686 struct usm_user *uuser; 2687 2688 while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2689 SLIST_REMOVE_HEAD(&usm_userlist, up); 2690 free(uuser); 2691 } 2692 2693 SLIST_INIT(&usm_userlist); 2694 } 2695 2696 /* 2697 * RFC 3415 View-based Access Control Model support 2698 */ 2699 struct vacm_user * 2700 vacm_first_user(void) 2701 { 2702 return (SLIST_FIRST(&vacm_userlist)); 2703 } 2704 2705 struct vacm_user * 2706 vacm_next_user(struct vacm_user *vuser) 2707 { 2708 if (vuser == NULL) 2709 return (NULL); 2710 2711 return (SLIST_NEXT(vuser, vvu)); 2712 } 2713 2714 static int 2715 vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2716 { 2717 uint32_t i; 2718 2719 if (v1->sec_model < v2->sec_model) 2720 return (-1); 2721 if (v1->sec_model > v2->sec_model) 2722 return (1); 2723 2724 if (strlen(v1->secname) < strlen(v2->secname)) 2725 return (-1); 2726 if (strlen(v1->secname) > strlen(v2->secname)) 2727 return (1); 2728 2729 for (i = 0; i < strlen(v1->secname); i++) { 2730 if (v1->secname[i] < v2->secname[i]) 2731 return (-1); 2732 if (v1->secname[i] > v2->secname[i]) 2733 return (1); 2734 } 2735 2736 return (0); 2737 } 2738 2739 struct vacm_user * 2740 vacm_new_user(int32_t smodel, char *uname) 2741 { 2742 int cmp; 2743 struct vacm_user *user, *temp, *prev; 2744 2745 SLIST_FOREACH(user, &vacm_userlist, vvu) 2746 if (strcmp(uname, user->secname) == 0 && 2747 smodel == user->sec_model) 2748 return (NULL); 2749 2750 if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2751 return (NULL); 2752 2753 memset(user, 0, sizeof(*user)); 2754 user->group = &vacm_default_group; 2755 SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2756 user->sec_model = smodel; 2757 strlcpy(user->secname, uname, sizeof(user->secname)); 2758 2759 if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2760 vacm_compare_user(user, prev) < 0) { 2761 SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2762 return (user); 2763 } 2764 2765 SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2766 if ((cmp = vacm_compare_user(user, temp)) <= 0) 2767 break; 2768 prev = temp; 2769 } 2770 2771 if (temp == NULL || cmp < 0) 2772 SLIST_INSERT_AFTER(prev, user, vvu); 2773 else if (cmp > 0) 2774 SLIST_INSERT_AFTER(temp, user, vvu); 2775 else { 2776 syslog(LOG_ERR, "User %s exists", user->secname); 2777 free(user); 2778 return (NULL); 2779 } 2780 2781 return (user); 2782 } 2783 2784 int 2785 vacm_delete_user(struct vacm_user *user) 2786 { 2787 if (user->group != NULL && user->group != &vacm_default_group) { 2788 SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2789 if (SLIST_EMPTY(&user->group->group_users)) { 2790 SLIST_REMOVE(&vacm_grouplist, user->group, 2791 vacm_group, vge); 2792 free(user->group); 2793 } 2794 } 2795 2796 SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2797 free(user); 2798 2799 return (0); 2800 } 2801 2802 int 2803 vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2804 { 2805 struct vacm_group *group; 2806 2807 if (len >= SNMP_ADM_STR32_SIZ) 2808 return (-1); 2809 2810 SLIST_FOREACH(group, &vacm_grouplist, vge) 2811 if (strlen(group->groupname) == len && 2812 memcmp(octets, group->groupname, len) == 0) 2813 break; 2814 2815 if (group == NULL) { 2816 if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2817 return (-1); 2818 memset(group, 0, sizeof(*group)); 2819 memcpy(group->groupname, octets, len); 2820 group->groupname[len] = '\0'; 2821 SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2822 } 2823 2824 SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2825 SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2826 user->group = group; 2827 2828 return (0); 2829 } 2830 2831 void 2832 vacm_groups_init(void) 2833 { 2834 SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2835 } 2836 2837 struct vacm_access * 2838 vacm_first_access_rule(void) 2839 { 2840 return (TAILQ_FIRST(&vacm_accesslist)); 2841 } 2842 2843 struct vacm_access * 2844 vacm_next_access_rule(struct vacm_access *acl) 2845 { 2846 if (acl == NULL) 2847 return (NULL); 2848 2849 return (TAILQ_NEXT(acl, vva)); 2850 } 2851 2852 static int 2853 vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2854 { 2855 uint32_t i; 2856 2857 if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 2858 return (-1); 2859 if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 2860 return (1); 2861 2862 for (i = 0; i < strlen(v1->group->groupname); i++) { 2863 if (v1->group->groupname[i] < v2->group->groupname[i]) 2864 return (-1); 2865 if (v1->group->groupname[i] > v2->group->groupname[i]) 2866 return (1); 2867 } 2868 2869 if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 2870 return (-1); 2871 if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 2872 return (1); 2873 2874 for (i = 0; i < strlen(v1->ctx_prefix); i++) { 2875 if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 2876 return (-1); 2877 if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 2878 return (1); 2879 } 2880 2881 if (v1->sec_model < v2->sec_model) 2882 return (-1); 2883 if (v1->sec_model > v2->sec_model) 2884 return (1); 2885 2886 if (v1->sec_level < v2->sec_level) 2887 return (-1); 2888 if (v1->sec_level > v2->sec_level) 2889 return (1); 2890 2891 return (0); 2892 } 2893 2894 struct vacm_access * 2895 vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 2896 { 2897 struct vacm_group *group; 2898 struct vacm_access *acl, *temp; 2899 2900 TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 2901 if (acl->group == NULL) 2902 continue; 2903 if (strcmp(gname, acl->group->groupname) == 0 && 2904 strcmp(cprefix, acl->ctx_prefix) == 0 && 2905 acl->sec_model == smodel && acl->sec_level == slevel) 2906 return (NULL); 2907 } 2908 2909 /* Make sure the group exists */ 2910 SLIST_FOREACH(group, &vacm_grouplist, vge) 2911 if (strcmp(gname, group->groupname) == 0) 2912 break; 2913 2914 if (group == NULL) 2915 return (NULL); 2916 2917 if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 2918 return (NULL); 2919 2920 memset(acl, 0, sizeof(*acl)); 2921 acl->group = group; 2922 strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 2923 acl->sec_model = smodel; 2924 acl->sec_level = slevel; 2925 2926 if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 2927 vacm_compare_access_rule(acl, temp) < 0) { 2928 TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 2929 return (acl); 2930 } 2931 2932 TAILQ_FOREACH(temp, &vacm_accesslist, vva) 2933 if (vacm_compare_access_rule(acl, temp) < 0) { 2934 TAILQ_INSERT_BEFORE(temp, acl, vva); 2935 return (acl); 2936 } 2937 2938 TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 2939 2940 return (acl); 2941 } 2942 2943 int 2944 vacm_delete_access_rule(struct vacm_access *acl) 2945 { 2946 TAILQ_REMOVE(&vacm_accesslist, acl, vva); 2947 free(acl); 2948 2949 return (0); 2950 } 2951 2952 struct vacm_view * 2953 vacm_first_view(void) 2954 { 2955 return (SLIST_FIRST(&vacm_viewlist)); 2956 } 2957 2958 struct vacm_view * 2959 vacm_next_view(struct vacm_view *view) 2960 { 2961 if (view == NULL) 2962 return (NULL); 2963 2964 return (SLIST_NEXT(view, vvl)); 2965 } 2966 2967 static int 2968 vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 2969 { 2970 uint32_t i; 2971 2972 if (strlen(v1->viewname) < strlen(v2->viewname)) 2973 return (-1); 2974 if (strlen(v1->viewname) > strlen(v2->viewname)) 2975 return (1); 2976 2977 for (i = 0; i < strlen(v1->viewname); i++) { 2978 if (v1->viewname[i] < v2->viewname[i]) 2979 return (-1); 2980 if (v1->viewname[i] > v2->viewname[i]) 2981 return (1); 2982 } 2983 2984 return (asn_compare_oid(&v1->subtree, &v2->subtree)); 2985 } 2986 2987 struct vacm_view * 2988 vacm_new_view(char *vname, struct asn_oid *oid) 2989 { 2990 int cmp; 2991 struct vacm_view *view, *temp, *prev; 2992 2993 SLIST_FOREACH(view, &vacm_viewlist, vvl) 2994 if (strcmp(vname, view->viewname) == 0) 2995 return (NULL); 2996 2997 if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 2998 return (NULL); 2999 3000 memset(view, 0, sizeof(*view)); 3001 strlcpy(view->viewname, vname, sizeof(view->viewname)); 3002 asn_append_oid(&view->subtree, oid); 3003 3004 if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3005 vacm_compare_view(view, prev) < 0) { 3006 SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3007 return (view); 3008 } 3009 3010 SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3011 if ((cmp = vacm_compare_view(view, temp)) <= 0) 3012 break; 3013 prev = temp; 3014 } 3015 3016 if (temp == NULL || cmp < 0) 3017 SLIST_INSERT_AFTER(prev, view, vvl); 3018 else if (cmp > 0) 3019 SLIST_INSERT_AFTER(temp, view, vvl); 3020 else { 3021 syslog(LOG_ERR, "View %s exists", view->viewname); 3022 free(view); 3023 return (NULL); 3024 } 3025 3026 return (view); 3027 } 3028 3029 int 3030 vacm_delete_view(struct vacm_view *view) 3031 { 3032 SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3033 free(view); 3034 3035 return (0); 3036 } 3037 3038 struct vacm_context * 3039 vacm_first_context(void) 3040 { 3041 return (SLIST_FIRST(&vacm_contextlist)); 3042 } 3043 3044 struct vacm_context * 3045 vacm_next_context(struct vacm_context *vacmctx) 3046 { 3047 if (vacmctx == NULL) 3048 return (NULL); 3049 3050 return (SLIST_NEXT(vacmctx, vcl)); 3051 } 3052 3053 struct vacm_context * 3054 vacm_add_context(char *ctxname, int regid) 3055 { 3056 int cmp; 3057 struct vacm_context *ctx, *temp, *prev; 3058 3059 SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3060 if (strcmp(ctxname, ctx->ctxname) == 0) { 3061 syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3062 return (NULL); 3063 } 3064 3065 if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3066 return (NULL); 3067 3068 memset(ctx, 0, sizeof(*ctx)); 3069 strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3070 ctx->regid = regid; 3071 3072 if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3073 strlen(ctx->ctxname) < strlen(prev->ctxname) || 3074 strcmp(ctx->ctxname, prev->ctxname) < 0) { 3075 SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3076 return (ctx); 3077 } 3078 3079 SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3080 if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3081 strcmp(ctx->ctxname, temp->ctxname) < 0) { 3082 cmp = -1; 3083 break; 3084 } 3085 prev = temp; 3086 } 3087 3088 if (temp == NULL || cmp < 0) 3089 SLIST_INSERT_AFTER(prev, ctx, vcl); 3090 else if (cmp > 0) 3091 SLIST_INSERT_AFTER(temp, ctx, vcl); 3092 else { 3093 syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3094 free(ctx); 3095 return (NULL); 3096 } 3097 3098 return (ctx); 3099 } 3100 3101 void 3102 vacm_flush_contexts(int regid) 3103 { 3104 struct vacm_context *ctx, *temp; 3105 3106 SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3107 if (ctx->regid == regid) { 3108 SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3109 free(ctx); 3110 } 3111 } 3112