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 TAILQ_FOREACH(p, &t->table, link) { 769 if (asn_compare_oid(&p->index, &port->index) > 0) { 770 TAILQ_INSERT_BEFORE(p, port, link); 771 return; 772 } 773 } 774 port->transport = t; 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, POLL_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 (community != COMM_WRITE && 1164 (pdu.type == SNMP_PDU_SET || community != 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 (void)comm_define(1, "SNMP read", NULL, NULL); 1613 (void)comm_define(2, "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 u_int 2031 comm_define(u_int priv, const char *descr, struct lmodule *owner, 2032 const char *str) 2033 { 2034 struct community *c, *p; 2035 u_int ncomm; 2036 2037 /* generate an identifier */ 2038 do { 2039 if ((ncomm = next_community_index++) == UINT_MAX) 2040 next_community_index = 1; 2041 TAILQ_FOREACH(c, &community_list, link) 2042 if (c->value == ncomm) 2043 break; 2044 } while (c != NULL); 2045 2046 if ((c = malloc(sizeof(struct community))) == NULL) { 2047 syslog(LOG_ERR, "comm_define: %m"); 2048 return (0); 2049 } 2050 c->owner = owner; 2051 c->value = ncomm; 2052 c->descr = descr; 2053 c->string = NULL; 2054 c->private = priv; 2055 2056 if (str != NULL) { 2057 if((c->string = malloc(strlen(str)+1)) == NULL) { 2058 free(c); 2059 return (0); 2060 } 2061 strcpy(c->string, str); 2062 } 2063 2064 /* make index */ 2065 if (c->owner == NULL) { 2066 c->index.len = 1; 2067 c->index.subs[0] = 0; 2068 } else { 2069 c->index = c->owner->index; 2070 } 2071 c->index.subs[c->index.len++] = c->private; 2072 2073 /* 2074 * Insert ordered 2075 */ 2076 TAILQ_FOREACH(p, &community_list, link) { 2077 if (asn_compare_oid(&p->index, &c->index) > 0) { 2078 TAILQ_INSERT_BEFORE(p, c, link); 2079 break; 2080 } 2081 } 2082 if (p == NULL) 2083 TAILQ_INSERT_TAIL(&community_list, c, link); 2084 return (c->value); 2085 } 2086 2087 const char * 2088 comm_string(u_int ncomm) 2089 { 2090 struct community *p; 2091 2092 TAILQ_FOREACH(p, &community_list, link) 2093 if (p->value == ncomm) 2094 return (p->string); 2095 return (NULL); 2096 } 2097 2098 /* 2099 * Delete all communities allocated by a module 2100 */ 2101 static void 2102 comm_flush(struct lmodule *mod) 2103 { 2104 struct community *p, *p1; 2105 2106 p = TAILQ_FIRST(&community_list); 2107 while (p != NULL) { 2108 p1 = TAILQ_NEXT(p, link); 2109 if (p->owner == mod) { 2110 free(p->string); 2111 TAILQ_REMOVE(&community_list, p, link); 2112 free(p); 2113 } 2114 p = p1; 2115 } 2116 } 2117 2118 /* 2119 * Request ID handling. 2120 * 2121 * Allocate a new range of request ids. Use a first fit algorithm. 2122 */ 2123 u_int 2124 reqid_allocate(int size, struct lmodule *mod) 2125 { 2126 u_int type; 2127 struct idrange *r, *r1; 2128 2129 if (size <= 0 || size > INT32_MAX) { 2130 syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2131 return (0); 2132 } 2133 /* allocate a type id */ 2134 do { 2135 if ((type = next_idrange++) == UINT_MAX) 2136 next_idrange = 1; 2137 TAILQ_FOREACH(r, &idrange_list, link) 2138 if (r->type == type) 2139 break; 2140 } while(r != NULL); 2141 2142 /* find a range */ 2143 if (TAILQ_EMPTY(&idrange_list)) 2144 r = NULL; 2145 else { 2146 r = TAILQ_FIRST(&idrange_list); 2147 if (r->base < size) { 2148 while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2149 if (r1->base - (r->base + r->size) >= size) 2150 break; 2151 r = r1; 2152 } 2153 r = r1; 2154 } 2155 if (r == NULL) { 2156 r1 = TAILQ_LAST(&idrange_list, idrange_list); 2157 if (INT32_MAX - size + 1 < r1->base + r1->size) { 2158 syslog(LOG_ERR, "out of id ranges (%u)", size); 2159 return (0); 2160 } 2161 } 2162 } 2163 2164 /* allocate structure */ 2165 if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2166 syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2167 return (0); 2168 } 2169 2170 r1->type = type; 2171 r1->size = size; 2172 r1->owner = mod; 2173 if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2174 r1->base = 0; 2175 TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2176 } else if (r == NULL) { 2177 r = TAILQ_LAST(&idrange_list, idrange_list); 2178 r1->base = r->base + r->size; 2179 TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2180 } else { 2181 r = TAILQ_PREV(r, idrange_list, link); 2182 r1->base = r->base + r->size; 2183 TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2184 } 2185 r1->next = r1->base; 2186 2187 return (type); 2188 } 2189 2190 int32_t 2191 reqid_next(u_int type) 2192 { 2193 struct idrange *r; 2194 int32_t id; 2195 2196 TAILQ_FOREACH(r, &idrange_list, link) 2197 if (r->type == type) 2198 break; 2199 if (r == NULL) { 2200 syslog(LOG_CRIT, "wrong idrange type"); 2201 abort(); 2202 } 2203 if ((id = r->next++) == r->base + (r->size - 1)) 2204 r->next = r->base; 2205 return (id); 2206 } 2207 2208 int32_t 2209 reqid_base(u_int type) 2210 { 2211 struct idrange *r; 2212 2213 TAILQ_FOREACH(r, &idrange_list, link) 2214 if (r->type == type) 2215 return (r->base); 2216 syslog(LOG_CRIT, "wrong idrange type"); 2217 abort(); 2218 } 2219 2220 u_int 2221 reqid_type(int32_t reqid) 2222 { 2223 struct idrange *r; 2224 2225 TAILQ_FOREACH(r, &idrange_list, link) 2226 if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2227 return (r->type); 2228 return (0); 2229 } 2230 2231 int 2232 reqid_istype(int32_t reqid, u_int type) 2233 { 2234 return (reqid_type(reqid) == type); 2235 } 2236 2237 /* 2238 * Delete all communities allocated by a module 2239 */ 2240 static void 2241 reqid_flush(struct lmodule *mod) 2242 { 2243 struct idrange *p, *p1; 2244 2245 p = TAILQ_FIRST(&idrange_list); 2246 while (p != NULL) { 2247 p1 = TAILQ_NEXT(p, link); 2248 if (p->owner == mod) { 2249 TAILQ_REMOVE(&idrange_list, p, link); 2250 free(p); 2251 } 2252 p = p1; 2253 } 2254 } 2255 2256 /* 2257 * Merge the given tree for the given module into the main tree. 2258 */ 2259 static int 2260 compare_node(const void *v1, const void *v2) 2261 { 2262 const struct snmp_node *n1 = v1; 2263 const struct snmp_node *n2 = v2; 2264 2265 return (asn_compare_oid(&n1->oid, &n2->oid)); 2266 } 2267 static int 2268 tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2269 { 2270 struct snmp_node *xtree; 2271 u_int i; 2272 2273 xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2274 if (xtree == NULL) { 2275 syslog(LOG_ERR, "tree_merge: %m"); 2276 return (-1); 2277 } 2278 tree = xtree; 2279 memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2280 2281 for (i = 0; i < nsize; i++) 2282 tree[tree_size + i].tree_data = mod; 2283 2284 tree_size += nsize; 2285 2286 qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2287 2288 return (0); 2289 } 2290 2291 /* 2292 * Remove all nodes belonging to the loadable module 2293 */ 2294 static void 2295 tree_unmerge(struct lmodule *mod) 2296 { 2297 u_int s, d; 2298 2299 for(s = d = 0; s < tree_size; s++) 2300 if (tree[s].tree_data != mod) { 2301 if (s != d) 2302 tree[d] = tree[s]; 2303 d++; 2304 } 2305 tree_size = d; 2306 } 2307 2308 /* 2309 * Loadable modules 2310 */ 2311 struct lmodule * 2312 lm_load(const char *path, const char *section) 2313 { 2314 struct lmodule *m; 2315 int err; 2316 int i; 2317 char *av[MAX_MOD_ARGS + 1]; 2318 int ac; 2319 u_int u; 2320 2321 if ((m = malloc(sizeof(*m))) == NULL) { 2322 syslog(LOG_ERR, "lm_load: %m"); 2323 return (NULL); 2324 } 2325 m->handle = NULL; 2326 m->flags = 0; 2327 strlcpy(m->section, section, sizeof(m->section)); 2328 2329 if ((m->path = strdup(path)) == NULL) { 2330 syslog(LOG_ERR, "lm_load: %m"); 2331 goto err; 2332 } 2333 2334 /* 2335 * Make index 2336 */ 2337 m->index.subs[0] = strlen(section); 2338 m->index.len = m->index.subs[0] + 1; 2339 for (u = 0; u < m->index.subs[0]; u++) 2340 m->index.subs[u + 1] = section[u]; 2341 2342 /* 2343 * Load the object file and locate the config structure 2344 */ 2345 if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2346 syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2347 goto err; 2348 } 2349 2350 if ((m->config = dlsym(m->handle, "config")) == NULL) { 2351 syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2352 goto err; 2353 } 2354 2355 /* 2356 * Insert it into the right place 2357 */ 2358 INSERT_OBJECT_OID(m, &lmodules); 2359 2360 /* preserve order */ 2361 if (community == COMM_INITIALIZE) { 2362 m->flags |= LM_ONSTARTLIST; 2363 TAILQ_INSERT_TAIL(&modules_start, m, start); 2364 } 2365 2366 /* 2367 * make the argument vector. 2368 */ 2369 ac = 0; 2370 for (i = 0; i < nprogargs; i++) { 2371 if (strlen(progargs[i]) >= strlen(section) + 1 && 2372 strncmp(progargs[i], section, strlen(section)) == 0 && 2373 progargs[i][strlen(section)] == ':') { 2374 if (ac == MAX_MOD_ARGS) { 2375 syslog(LOG_WARNING, "too many arguments for " 2376 "module '%s", section); 2377 break; 2378 } 2379 av[ac++] = &progargs[i][strlen(section)+1]; 2380 } 2381 } 2382 av[ac] = NULL; 2383 2384 /* 2385 * Run the initialization function 2386 */ 2387 if ((err = (*m->config->init)(m, ac, av)) != 0) { 2388 syslog(LOG_ERR, "lm_load: init failed: %d", err); 2389 TAILQ_REMOVE(&lmodules, m, link); 2390 goto err; 2391 } 2392 2393 return (m); 2394 2395 err: 2396 if ((m->flags & LM_ONSTARTLIST) != 0) 2397 TAILQ_REMOVE(&modules_start, m, start); 2398 if (m->handle) 2399 dlclose(m->handle); 2400 free(m->path); 2401 free(m); 2402 return (NULL); 2403 } 2404 2405 /* 2406 * Start a module 2407 */ 2408 void 2409 lm_start(struct lmodule *mod) 2410 { 2411 const struct lmodule *m; 2412 2413 /* 2414 * Merge tree. If this fails, unload the module. 2415 */ 2416 if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2417 lm_unload(mod); 2418 return; 2419 } 2420 2421 /* 2422 * Read configuration 2423 */ 2424 if (read_config(config_file, mod)) { 2425 syslog(LOG_ERR, "error in config file"); 2426 lm_unload(mod); 2427 return; 2428 } 2429 if (mod->config->start) 2430 (*mod->config->start)(); 2431 2432 mod->flags |= LM_STARTED; 2433 2434 /* 2435 * Inform other modules 2436 */ 2437 TAILQ_FOREACH(m, &lmodules, link) 2438 if (m->config->loading) 2439 (*m->config->loading)(mod, 1); 2440 } 2441 2442 2443 /* 2444 * Unload a module. 2445 */ 2446 void 2447 lm_unload(struct lmodule *m) 2448 { 2449 int err; 2450 const struct lmodule *mod; 2451 2452 TAILQ_REMOVE(&lmodules, m, link); 2453 if (m->flags & LM_ONSTARTLIST) 2454 TAILQ_REMOVE(&modules_start, m, start); 2455 tree_unmerge(m); 2456 2457 if ((m->flags & LM_STARTED) && m->config->fini && 2458 (err = (*m->config->fini)()) != 0) 2459 syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2460 2461 comm_flush(m); 2462 reqid_flush(m); 2463 timer_flush(m); 2464 fd_flush(m); 2465 2466 dlclose(m->handle); 2467 free(m->path); 2468 2469 /* 2470 * Inform other modules 2471 */ 2472 TAILQ_FOREACH(mod, &lmodules, link) 2473 if (mod->config->loading) 2474 (*mod->config->loading)(m, 0); 2475 2476 free(m); 2477 } 2478 2479 /* 2480 * Register an object resource and return the index (or 0 on failures) 2481 */ 2482 u_int 2483 or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2484 { 2485 struct objres *objres, *or1; 2486 u_int idx; 2487 2488 /* find a free index */ 2489 idx = 1; 2490 for (objres = TAILQ_FIRST(&objres_list); 2491 objres != NULL; 2492 objres = TAILQ_NEXT(objres, link)) { 2493 if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2494 or1->index > objres->index + 1) { 2495 idx = objres->index + 1; 2496 break; 2497 } 2498 } 2499 2500 if ((objres = malloc(sizeof(*objres))) == NULL) 2501 return (0); 2502 2503 objres->index = idx; 2504 objres->oid = *or; 2505 strlcpy(objres->descr, descr, sizeof(objres->descr)); 2506 objres->uptime = (uint32_t)(get_ticks() - start_tick); 2507 objres->module = mod; 2508 2509 INSERT_OBJECT_INT(objres, &objres_list); 2510 2511 systemg.or_last_change = objres->uptime; 2512 2513 return (idx); 2514 } 2515 2516 void 2517 or_unregister(u_int idx) 2518 { 2519 struct objres *objres; 2520 2521 TAILQ_FOREACH(objres, &objres_list, link) 2522 if (objres->index == idx) { 2523 TAILQ_REMOVE(&objres_list, objres, link); 2524 free(objres); 2525 return; 2526 } 2527 } 2528 2529 /* 2530 * RFC 3414 User-based Security Model support 2531 */ 2532 2533 struct snmpd_usmstat * 2534 bsnmpd_get_usm_stats(void) 2535 { 2536 return (&snmpd_usmstats); 2537 } 2538 2539 void 2540 bsnmpd_reset_usm_stats(void) 2541 { 2542 memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2543 } 2544 2545 struct usm_user * 2546 usm_first_user(void) 2547 { 2548 return (SLIST_FIRST(&usm_userlist)); 2549 } 2550 2551 struct usm_user * 2552 usm_next_user(struct usm_user *uuser) 2553 { 2554 if (uuser == NULL) 2555 return (NULL); 2556 2557 return (SLIST_NEXT(uuser, up)); 2558 } 2559 2560 struct usm_user * 2561 usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2562 { 2563 struct usm_user *uuser; 2564 2565 SLIST_FOREACH(uuser, &usm_userlist, up) 2566 if (uuser->user_engine_len == elen && 2567 memcmp(uuser->user_engine_id, engine, elen) == 0 && 2568 strlen(uuser->suser.sec_name) == strlen(uname) && 2569 strcmp(uuser->suser.sec_name, uname) == 0) 2570 break; 2571 2572 return (uuser); 2573 } 2574 2575 static int 2576 usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2577 { 2578 uint32_t i; 2579 2580 if (u1->user_engine_len < u2->user_engine_len) 2581 return (-1); 2582 if (u1->user_engine_len > u2->user_engine_len) 2583 return (1); 2584 2585 for (i = 0; i < u1->user_engine_len; i++) { 2586 if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2587 return (-1); 2588 if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2589 return (1); 2590 } 2591 2592 if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2593 return (-1); 2594 if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2595 return (1); 2596 2597 for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2598 if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2599 return (-1); 2600 if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2601 return (1); 2602 } 2603 2604 return (0); 2605 } 2606 2607 struct usm_user * 2608 usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2609 { 2610 int cmp; 2611 struct usm_user *uuser, *temp, *prev; 2612 2613 for (uuser = usm_first_user(); uuser != NULL; 2614 (uuser = usm_next_user(uuser))) { 2615 if (uuser->user_engine_len == elen && 2616 strlen(uname) == strlen(uuser->suser.sec_name) && 2617 strcmp(uname, uuser->suser.sec_name) == 0 && 2618 memcmp(eid, uuser->user_engine_id, elen) == 0) 2619 return (NULL); 2620 } 2621 2622 if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2623 return (NULL); 2624 2625 memset(uuser, 0, sizeof(*uuser)); 2626 strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2627 memcpy(uuser->user_engine_id, eid, elen); 2628 uuser->user_engine_len = elen; 2629 2630 if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2631 usm_compare_user(uuser, prev) < 0) { 2632 SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2633 return (uuser); 2634 } 2635 2636 SLIST_FOREACH(temp, &usm_userlist, up) { 2637 if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2638 break; 2639 prev = temp; 2640 } 2641 2642 if (temp == NULL || cmp < 0) 2643 SLIST_INSERT_AFTER(prev, uuser, up); 2644 else if (cmp > 0) 2645 SLIST_INSERT_AFTER(temp, uuser, up); 2646 else { 2647 syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2648 free(uuser); 2649 return (NULL); 2650 } 2651 2652 return (uuser); 2653 } 2654 2655 void 2656 usm_delete_user(struct usm_user *uuser) 2657 { 2658 SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2659 free(uuser); 2660 } 2661 2662 void 2663 usm_flush_users(void) 2664 { 2665 struct usm_user *uuser; 2666 2667 while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2668 SLIST_REMOVE_HEAD(&usm_userlist, up); 2669 free(uuser); 2670 } 2671 2672 SLIST_INIT(&usm_userlist); 2673 } 2674 2675 /* 2676 * RFC 3415 View-based Access Control Model support 2677 */ 2678 struct vacm_user * 2679 vacm_first_user(void) 2680 { 2681 return (SLIST_FIRST(&vacm_userlist)); 2682 } 2683 2684 struct vacm_user * 2685 vacm_next_user(struct vacm_user *vuser) 2686 { 2687 if (vuser == NULL) 2688 return (NULL); 2689 2690 return (SLIST_NEXT(vuser, vvu)); 2691 } 2692 2693 static int 2694 vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2695 { 2696 uint32_t i; 2697 2698 if (v1->sec_model < v2->sec_model) 2699 return (-1); 2700 if (v1->sec_model > v2->sec_model) 2701 return (1); 2702 2703 if (strlen(v1->secname) < strlen(v2->secname)) 2704 return (-1); 2705 if (strlen(v1->secname) > strlen(v2->secname)) 2706 return (1); 2707 2708 for (i = 0; i < strlen(v1->secname); i++) { 2709 if (v1->secname[i] < v2->secname[i]) 2710 return (-1); 2711 if (v1->secname[i] > v2->secname[i]) 2712 return (1); 2713 } 2714 2715 return (0); 2716 } 2717 2718 struct vacm_user * 2719 vacm_new_user(int32_t smodel, char *uname) 2720 { 2721 int cmp; 2722 struct vacm_user *user, *temp, *prev; 2723 2724 SLIST_FOREACH(user, &vacm_userlist, vvu) 2725 if (strcmp(uname, user->secname) == 0 && 2726 smodel == user->sec_model) 2727 return (NULL); 2728 2729 if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2730 return (NULL); 2731 2732 memset(user, 0, sizeof(*user)); 2733 user->group = &vacm_default_group; 2734 SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2735 user->sec_model = smodel; 2736 strlcpy(user->secname, uname, sizeof(user->secname)); 2737 2738 if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2739 vacm_compare_user(user, prev) < 0) { 2740 SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2741 return (user); 2742 } 2743 2744 SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2745 if ((cmp = vacm_compare_user(user, temp)) <= 0) 2746 break; 2747 prev = temp; 2748 } 2749 2750 if (temp == NULL || cmp < 0) 2751 SLIST_INSERT_AFTER(prev, user, vvu); 2752 else if (cmp > 0) 2753 SLIST_INSERT_AFTER(temp, user, vvu); 2754 else { 2755 syslog(LOG_ERR, "User %s exists", user->secname); 2756 free(user); 2757 return (NULL); 2758 } 2759 2760 return (user); 2761 } 2762 2763 int 2764 vacm_delete_user(struct vacm_user *user) 2765 { 2766 if (user->group != NULL && user->group != &vacm_default_group) { 2767 SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2768 if (SLIST_EMPTY(&user->group->group_users)) { 2769 SLIST_REMOVE(&vacm_grouplist, user->group, 2770 vacm_group, vge); 2771 free(user->group); 2772 } 2773 } 2774 2775 SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2776 free(user); 2777 2778 return (0); 2779 } 2780 2781 int 2782 vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2783 { 2784 struct vacm_group *group; 2785 2786 if (len >= SNMP_ADM_STR32_SIZ) 2787 return (-1); 2788 2789 SLIST_FOREACH(group, &vacm_grouplist, vge) 2790 if (strlen(group->groupname) == len && 2791 memcmp(octets, group->groupname, len) == 0) 2792 break; 2793 2794 if (group == NULL) { 2795 if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2796 return (-1); 2797 memset(group, 0, sizeof(*group)); 2798 memcpy(group->groupname, octets, len); 2799 group->groupname[len] = '\0'; 2800 SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2801 } 2802 2803 SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2804 SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2805 user->group = group; 2806 2807 return (0); 2808 } 2809 2810 void 2811 vacm_groups_init(void) 2812 { 2813 SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2814 } 2815 2816 struct vacm_access * 2817 vacm_first_access_rule(void) 2818 { 2819 return (TAILQ_FIRST(&vacm_accesslist)); 2820 } 2821 2822 struct vacm_access * 2823 vacm_next_access_rule(struct vacm_access *acl) 2824 { 2825 if (acl == NULL) 2826 return (NULL); 2827 2828 return (TAILQ_NEXT(acl, vva)); 2829 } 2830 2831 static int 2832 vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2833 { 2834 uint32_t i; 2835 2836 if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 2837 return (-1); 2838 if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 2839 return (1); 2840 2841 for (i = 0; i < strlen(v1->group->groupname); i++) { 2842 if (v1->group->groupname[i] < v2->group->groupname[i]) 2843 return (-1); 2844 if (v1->group->groupname[i] > v2->group->groupname[i]) 2845 return (1); 2846 } 2847 2848 if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 2849 return (-1); 2850 if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 2851 return (1); 2852 2853 for (i = 0; i < strlen(v1->ctx_prefix); i++) { 2854 if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 2855 return (-1); 2856 if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 2857 return (1); 2858 } 2859 2860 if (v1->sec_model < v2->sec_model) 2861 return (-1); 2862 if (v1->sec_model > v2->sec_model) 2863 return (1); 2864 2865 if (v1->sec_level < v2->sec_level) 2866 return (-1); 2867 if (v1->sec_level > v2->sec_level) 2868 return (1); 2869 2870 return (0); 2871 } 2872 2873 struct vacm_access * 2874 vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 2875 { 2876 struct vacm_group *group; 2877 struct vacm_access *acl, *temp; 2878 2879 TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 2880 if (acl->group == NULL) 2881 continue; 2882 if (strcmp(gname, acl->group->groupname) == 0 && 2883 strcmp(cprefix, acl->ctx_prefix) == 0 && 2884 acl->sec_model == smodel && acl->sec_level == slevel) 2885 return (NULL); 2886 } 2887 2888 /* Make sure the group exists */ 2889 SLIST_FOREACH(group, &vacm_grouplist, vge) 2890 if (strcmp(gname, group->groupname) == 0) 2891 break; 2892 2893 if (group == NULL) 2894 return (NULL); 2895 2896 if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 2897 return (NULL); 2898 2899 memset(acl, 0, sizeof(*acl)); 2900 acl->group = group; 2901 strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 2902 acl->sec_model = smodel; 2903 acl->sec_level = slevel; 2904 2905 if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 2906 vacm_compare_access_rule(acl, temp) < 0) { 2907 TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 2908 return (acl); 2909 } 2910 2911 TAILQ_FOREACH(temp, &vacm_accesslist, vva) 2912 if (vacm_compare_access_rule(acl, temp) < 0) { 2913 TAILQ_INSERT_BEFORE(temp, acl, vva); 2914 return (acl); 2915 } 2916 2917 TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 2918 2919 return (acl); 2920 } 2921 2922 int 2923 vacm_delete_access_rule(struct vacm_access *acl) 2924 { 2925 TAILQ_REMOVE(&vacm_accesslist, acl, vva); 2926 free(acl); 2927 2928 return (0); 2929 } 2930 2931 struct vacm_view * 2932 vacm_first_view(void) 2933 { 2934 return (SLIST_FIRST(&vacm_viewlist)); 2935 } 2936 2937 struct vacm_view * 2938 vacm_next_view(struct vacm_view *view) 2939 { 2940 if (view == NULL) 2941 return (NULL); 2942 2943 return (SLIST_NEXT(view, vvl)); 2944 } 2945 2946 static int 2947 vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 2948 { 2949 uint32_t i; 2950 2951 if (strlen(v1->viewname) < strlen(v2->viewname)) 2952 return (-1); 2953 if (strlen(v1->viewname) > strlen(v2->viewname)) 2954 return (1); 2955 2956 for (i = 0; i < strlen(v1->viewname); i++) { 2957 if (v1->viewname[i] < v2->viewname[i]) 2958 return (-1); 2959 if (v1->viewname[i] > v2->viewname[i]) 2960 return (1); 2961 } 2962 2963 return (asn_compare_oid(&v1->subtree, &v2->subtree)); 2964 } 2965 2966 struct vacm_view * 2967 vacm_new_view(char *vname, struct asn_oid *oid) 2968 { 2969 int cmp; 2970 struct vacm_view *view, *temp, *prev; 2971 2972 SLIST_FOREACH(view, &vacm_viewlist, vvl) 2973 if (strcmp(vname, view->viewname) == 0) 2974 return (NULL); 2975 2976 if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 2977 return (NULL); 2978 2979 memset(view, 0, sizeof(*view)); 2980 strlcpy(view->viewname, vname, sizeof(view->viewname)); 2981 asn_append_oid(&view->subtree, oid); 2982 2983 if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 2984 vacm_compare_view(view, prev) < 0) { 2985 SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 2986 return (view); 2987 } 2988 2989 SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 2990 if ((cmp = vacm_compare_view(view, temp)) <= 0) 2991 break; 2992 prev = temp; 2993 } 2994 2995 if (temp == NULL || cmp < 0) 2996 SLIST_INSERT_AFTER(prev, view, vvl); 2997 else if (cmp > 0) 2998 SLIST_INSERT_AFTER(temp, view, vvl); 2999 else { 3000 syslog(LOG_ERR, "View %s exists", view->viewname); 3001 free(view); 3002 return (NULL); 3003 } 3004 3005 return (view); 3006 } 3007 3008 int 3009 vacm_delete_view(struct vacm_view *view) 3010 { 3011 SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3012 free(view); 3013 3014 return (0); 3015 } 3016 3017 struct vacm_context * 3018 vacm_first_context(void) 3019 { 3020 return (SLIST_FIRST(&vacm_contextlist)); 3021 } 3022 3023 struct vacm_context * 3024 vacm_next_context(struct vacm_context *vacmctx) 3025 { 3026 if (vacmctx == NULL) 3027 return (NULL); 3028 3029 return (SLIST_NEXT(vacmctx, vcl)); 3030 } 3031 3032 struct vacm_context * 3033 vacm_add_context(char *ctxname, int regid) 3034 { 3035 int cmp; 3036 struct vacm_context *ctx, *temp, *prev; 3037 3038 SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3039 if (strcmp(ctxname, ctx->ctxname) == 0) { 3040 syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3041 return (NULL); 3042 } 3043 3044 if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3045 return (NULL); 3046 3047 memset(ctx, 0, sizeof(*ctx)); 3048 strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3049 ctx->regid = regid; 3050 3051 if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3052 strlen(ctx->ctxname) < strlen(prev->ctxname) || 3053 strcmp(ctx->ctxname, prev->ctxname) < 0) { 3054 SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3055 return (ctx); 3056 } 3057 3058 SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3059 if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3060 strcmp(ctx->ctxname, temp->ctxname) < 0) { 3061 cmp = -1; 3062 break; 3063 } 3064 prev = temp; 3065 } 3066 3067 if (temp == NULL || cmp < 0) 3068 SLIST_INSERT_AFTER(prev, ctx, vcl); 3069 else if (cmp > 0) 3070 SLIST_INSERT_AFTER(temp, ctx, vcl); 3071 else { 3072 syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3073 free(ctx); 3074 return (NULL); 3075 } 3076 3077 return (ctx); 3078 } 3079 3080 void 3081 vacm_flush_contexts(int regid) 3082 { 3083 struct vacm_context *ctx, *temp; 3084 3085 SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3086 if (ctx->regid == regid) { 3087 SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3088 free(ctx); 3089 } 3090 } 3091