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