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 static void 1030 check_priv_dgram(struct port_input *pi, struct sockcred *cred) 1031 { 1032 1033 /* process explicitly sends credentials */ 1034 if (cred) 1035 pi->priv = (cred->sc_euid == 0); 1036 else 1037 pi->priv = 0; 1038 } 1039 1040 static void 1041 check_priv_stream(struct port_input *pi) 1042 { 1043 struct xucred ucred; 1044 socklen_t ucredlen; 1045 1046 /* obtain the accept time credentials */ 1047 ucredlen = sizeof(ucred); 1048 1049 if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 1050 ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 1051 pi->priv = (ucred.cr_uid == 0); 1052 else 1053 pi->priv = 0; 1054 } 1055 1056 /* 1057 * Input from a stream socket. 1058 */ 1059 static int 1060 recv_stream(struct port_input *pi) 1061 { 1062 struct msghdr msg; 1063 struct iovec iov[1]; 1064 ssize_t len; 1065 1066 if (pi->buf == NULL) { 1067 /* no buffer yet - allocate one */ 1068 if ((pi->buf = buf_alloc(0)) == NULL) { 1069 /* ups - could not get buffer. Return an error 1070 * the caller must close the transport. */ 1071 return (-1); 1072 } 1073 pi->buflen = buf_size(0); 1074 pi->consumed = 0; 1075 pi->length = 0; 1076 } 1077 1078 /* try to get a message */ 1079 msg.msg_name = pi->peer; 1080 msg.msg_namelen = pi->peerlen; 1081 msg.msg_iov = iov; 1082 msg.msg_iovlen = 1; 1083 msg.msg_control = NULL; 1084 msg.msg_controllen = 0; 1085 msg.msg_flags = 0; 1086 1087 iov[0].iov_base = pi->buf + pi->length; 1088 iov[0].iov_len = pi->buflen - pi->length; 1089 1090 len = recvmsg(pi->fd, &msg, 0); 1091 1092 if (len == -1 || len == 0) 1093 /* receive error */ 1094 return (-1); 1095 1096 pi->length += len; 1097 1098 if (pi->cred) 1099 check_priv_stream(pi); 1100 1101 return (0); 1102 } 1103 1104 /* 1105 * Input from a datagram socket. 1106 * Each receive should return one datagram. 1107 */ 1108 static int 1109 recv_dgram(struct port_input *pi, struct in_addr *laddr) 1110 { 1111 u_char embuf[1000]; 1112 char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + 1113 CMSG_SPACE(sizeof(struct in_addr))]; 1114 struct msghdr msg; 1115 struct iovec iov[1]; 1116 ssize_t len; 1117 struct cmsghdr *cmsg; 1118 struct sockcred *cred = NULL; 1119 1120 if (pi->buf == NULL) { 1121 /* no buffer yet - allocate one */ 1122 if ((pi->buf = buf_alloc(0)) == NULL) { 1123 /* ups - could not get buffer. Read away input 1124 * and drop it */ 1125 (void)recvfrom(pi->fd, embuf, sizeof(embuf), 1126 0, NULL, NULL); 1127 /* return error */ 1128 return (-1); 1129 } 1130 pi->buflen = buf_size(0); 1131 } 1132 1133 /* try to get a message */ 1134 msg.msg_name = pi->peer; 1135 msg.msg_namelen = pi->peerlen; 1136 msg.msg_iov = iov; 1137 msg.msg_iovlen = 1; 1138 memset(cbuf, 0, sizeof(cbuf)); 1139 msg.msg_control = cbuf; 1140 msg.msg_controllen = sizeof(cbuf); 1141 msg.msg_flags = 0; 1142 1143 iov[0].iov_base = pi->buf; 1144 iov[0].iov_len = pi->buflen; 1145 1146 len = recvmsg(pi->fd, &msg, 0); 1147 1148 if (len == -1 || len == 0) 1149 /* receive error */ 1150 return (-1); 1151 1152 if (msg.msg_flags & MSG_TRUNC) { 1153 /* truncated - drop */ 1154 snmpd_stats.silentDrops++; 1155 snmpd_stats.inTooLong++; 1156 return (-1); 1157 } 1158 1159 pi->length = (size_t)len; 1160 1161 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 1162 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 1163 if (cmsg->cmsg_level == IPPROTO_IP && 1164 cmsg->cmsg_type == IP_RECVDSTADDR) 1165 memcpy(laddr, CMSG_DATA(cmsg), sizeof(struct in_addr)); 1166 if (cmsg->cmsg_level == SOL_SOCKET && 1167 cmsg->cmsg_type == SCM_CREDS) 1168 cred = (struct sockcred *)CMSG_DATA(cmsg); 1169 } 1170 1171 if (pi->cred) 1172 check_priv_dgram(pi, cred); 1173 1174 return (0); 1175 } 1176 1177 /* 1178 * Input from a socket 1179 */ 1180 int 1181 snmpd_input(struct port_input *pi, struct tport *tport) 1182 { 1183 u_char *sndbuf; 1184 size_t sndlen; 1185 struct snmp_pdu pdu; 1186 enum snmpd_input_err ierr, ferr; 1187 enum snmpd_proxy_err perr; 1188 int32_t vi; 1189 int ret; 1190 ssize_t slen; 1191 #ifdef USE_TCPWRAPPERS 1192 char client[16]; 1193 #endif 1194 struct msghdr msg; 1195 struct iovec iov[1]; 1196 char cbuf[CMSG_SPACE(sizeof(struct in_addr))]; 1197 struct cmsghdr *cmsgp; 1198 1199 /* get input depending on the transport */ 1200 if (pi->stream) { 1201 msg.msg_control = NULL; 1202 msg.msg_controllen = 0; 1203 1204 ret = recv_stream(pi); 1205 } else { 1206 struct in_addr *laddr; 1207 1208 memset(cbuf, 0, CMSG_SPACE(sizeof(struct in_addr))); 1209 msg.msg_control = cbuf; 1210 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 1211 cmsgp = CMSG_FIRSTHDR(&msg); 1212 cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1213 cmsgp->cmsg_level = IPPROTO_IP; 1214 cmsgp->cmsg_type = IP_SENDSRCADDR; 1215 laddr = (struct in_addr *)CMSG_DATA(cmsgp); 1216 1217 ret = recv_dgram(pi, laddr); 1218 1219 if (laddr->s_addr == 0) { 1220 msg.msg_control = NULL; 1221 msg.msg_controllen = 0; 1222 } 1223 } 1224 1225 if (ret == -1) 1226 return (-1); 1227 1228 #ifdef USE_TCPWRAPPERS 1229 /* 1230 * In case of AF_INET{6} peer, do hosts_access(5) check. 1231 */ 1232 if (pi->peer->sa_family != AF_LOCAL && 1233 inet_ntop(pi->peer->sa_family, 1234 &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 1235 client, sizeof(client)) != NULL) { 1236 request_set(&req, RQ_CLIENT_ADDR, client, 0); 1237 if (hosts_access(&req) == 0) { 1238 syslog(LOG_ERR, "refused connection from %.500s", 1239 eval_client(&req)); 1240 return (-1); 1241 } 1242 } else if (pi->peer->sa_family != AF_LOCAL) 1243 syslog(LOG_ERR, "inet_ntop(): %m"); 1244 #endif 1245 1246 /* 1247 * Handle input 1248 */ 1249 ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 1250 &pi->consumed); 1251 if (ierr == SNMPD_INPUT_TRUNC) { 1252 /* need more bytes. This is ok only for streaming transports. 1253 * but only if we have not reached bufsiz yet. */ 1254 if (pi->stream) { 1255 if (pi->length == buf_size(0)) { 1256 snmpd_stats.silentDrops++; 1257 return (-1); 1258 } 1259 return (0); 1260 } 1261 snmpd_stats.silentDrops++; 1262 return (-1); 1263 } 1264 1265 /* can't check for bad SET pdus here, because a proxy may have to 1266 * check the access first. We don't want to return an error response 1267 * to a proxy PDU with a wrong community */ 1268 if (ierr == SNMPD_INPUT_FAILED) { 1269 /* for streaming transports this is fatal */ 1270 if (pi->stream) 1271 return (-1); 1272 snmp_input_consume(pi); 1273 return (0); 1274 } 1275 if (ierr == SNMPD_INPUT_BAD_COMM) { 1276 snmp_input_consume(pi); 1277 return (0); 1278 } 1279 1280 /* 1281 * If that is a module community and the module has a proxy function, 1282 * the hand it over to the module. 1283 */ 1284 if (comm != NULL && comm->owner != NULL && 1285 comm->owner->config->proxy != NULL) { 1286 perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1287 &tport->index, pi->peer, pi->peerlen, ierr, vi, 1288 !pi->cred || pi->priv); 1289 1290 switch (perr) { 1291 1292 case SNMPD_PROXY_OK: 1293 snmp_input_consume(pi); 1294 return (0); 1295 1296 case SNMPD_PROXY_REJ: 1297 break; 1298 1299 case SNMPD_PROXY_DROP: 1300 snmp_input_consume(pi); 1301 snmp_pdu_free(&pdu); 1302 snmpd_stats.proxyDrops++; 1303 return (0); 1304 1305 case SNMPD_PROXY_BADCOMM: 1306 snmp_input_consume(pi); 1307 snmp_pdu_free(&pdu); 1308 snmpd_stats.inBadCommunityNames++; 1309 if (snmpd.auth_traps) 1310 snmp_send_trap(&oid_authenticationFailure, 1311 (struct snmp_value *)NULL); 1312 return (0); 1313 1314 case SNMPD_PROXY_BADCOMMUSE: 1315 snmp_input_consume(pi); 1316 snmp_pdu_free(&pdu); 1317 snmpd_stats.inBadCommunityUses++; 1318 if (snmpd.auth_traps) 1319 snmp_send_trap(&oid_authenticationFailure, 1320 (struct snmp_value *)NULL); 1321 return (0); 1322 } 1323 } 1324 1325 /* 1326 * Check type 1327 */ 1328 if (pdu.type == SNMP_PDU_RESPONSE || 1329 pdu.type == SNMP_PDU_TRAP || 1330 pdu.type == SNMP_PDU_TRAP2) { 1331 snmpd_stats.silentDrops++; 1332 snmpd_stats.inBadPduTypes++; 1333 snmp_pdu_free(&pdu); 1334 snmp_input_consume(pi); 1335 return (0); 1336 } 1337 1338 /* 1339 * Check community 1340 */ 1341 if (pdu.version < SNMP_V3 && 1342 ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1343 (community != COMM_WRITE && 1344 (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1345 snmpd_stats.inBadCommunityUses++; 1346 snmp_pdu_free(&pdu); 1347 snmp_input_consume(pi); 1348 if (snmpd.auth_traps) 1349 snmp_send_trap(&oid_authenticationFailure, 1350 (struct snmp_value *)NULL); 1351 return (0); 1352 } 1353 1354 /* 1355 * Execute it. 1356 */ 1357 if ((sndbuf = buf_alloc(1)) == NULL) { 1358 snmpd_stats.silentDrops++; 1359 snmp_pdu_free(&pdu); 1360 snmp_input_consume(pi); 1361 return (0); 1362 } 1363 ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1364 sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1365 1366 if (ferr == SNMPD_INPUT_OK) { 1367 msg.msg_name = pi->peer; 1368 msg.msg_namelen = pi->peerlen; 1369 msg.msg_iov = iov; 1370 msg.msg_iovlen = 1; 1371 msg.msg_flags = 0; 1372 iov[0].iov_base = sndbuf; 1373 iov[0].iov_len = sndlen; 1374 1375 slen = sendmsg(pi->fd, &msg, 0); 1376 if (slen == -1) 1377 syslog(LOG_ERR, "sendmsg: %m"); 1378 else if ((size_t)slen != sndlen) 1379 syslog(LOG_ERR, "sendmsg: short write %zu/%zu", 1380 sndlen, (size_t)slen); 1381 } 1382 snmp_pdu_free(&pdu); 1383 free(sndbuf); 1384 snmp_input_consume(pi); 1385 1386 return (0); 1387 } 1388 1389 /* 1390 * Send a PDU to a given port 1391 */ 1392 void 1393 snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1394 const struct sockaddr *addr, socklen_t addrlen) 1395 { 1396 struct transport *trans = targ; 1397 struct tport *tp; 1398 u_char *sndbuf; 1399 size_t sndlen; 1400 ssize_t len; 1401 1402 TAILQ_FOREACH(tp, &trans->table, link) 1403 if (asn_compare_oid(port, &tp->index) == 0) 1404 break; 1405 if (tp == 0) 1406 return; 1407 1408 if ((sndbuf = buf_alloc(1)) == NULL) 1409 return; 1410 1411 snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1412 1413 len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1414 1415 if (len == -1) 1416 syslog(LOG_ERR, "sendto: %m"); 1417 else if ((size_t)len != sndlen) 1418 syslog(LOG_ERR, "sendto: short write %zu/%zu", 1419 sndlen, (size_t)len); 1420 1421 free(sndbuf); 1422 } 1423 1424 1425 /* 1426 * Close an input source 1427 */ 1428 void 1429 snmpd_input_close(struct port_input *pi) 1430 { 1431 if (pi->id != NULL) 1432 fd_deselect(pi->id); 1433 if (pi->fd >= 0) 1434 (void)close(pi->fd); 1435 if (pi->buf != NULL) 1436 free(pi->buf); 1437 } 1438 1439 /* 1440 * Dump internal state. 1441 */ 1442 #ifdef USE_LIBBEGEMOT 1443 static void 1444 info_func(void) 1445 #else 1446 static void 1447 info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1448 #endif 1449 { 1450 struct lmodule *m; 1451 u_int i; 1452 char buf[10000]; 1453 1454 syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1455 for (i = 0; i < tree_size; i++) { 1456 switch (tree[i].type) { 1457 1458 case SNMP_NODE_LEAF: 1459 sprintf(buf, "LEAF: %s %s", tree[i].name, 1460 asn_oid2str(&tree[i].oid)); 1461 break; 1462 1463 case SNMP_NODE_COLUMN: 1464 sprintf(buf, "COL: %s %s", tree[i].name, 1465 asn_oid2str(&tree[i].oid)); 1466 break; 1467 } 1468 syslog(LOG_DEBUG, "%s", buf); 1469 } 1470 1471 TAILQ_FOREACH(m, &lmodules, link) 1472 if (m->config->dump) 1473 (*m->config->dump)(); 1474 } 1475 1476 /* 1477 * Re-read configuration 1478 */ 1479 #ifdef USE_LIBBEGEMOT 1480 static void 1481 config_func(void) 1482 #else 1483 static void 1484 config_func(evContext ctx __unused, void *uap __unused, 1485 const void *tag __unused) 1486 #endif 1487 { 1488 struct lmodule *m; 1489 1490 if (read_config(config_file, NULL)) { 1491 syslog(LOG_ERR, "error reading config file '%s'", config_file); 1492 return; 1493 } 1494 TAILQ_FOREACH(m, &lmodules, link) 1495 if (m->config->config) 1496 (*m->config->config)(); 1497 } 1498 1499 /* 1500 * On USR1 dump actual configuration. 1501 */ 1502 static void 1503 onusr1(int s __unused) 1504 { 1505 1506 work |= WORK_DOINFO; 1507 } 1508 static void 1509 onhup(int s __unused) 1510 { 1511 1512 work |= WORK_RECONFIG; 1513 } 1514 1515 static void 1516 onterm(int s __unused) 1517 { 1518 1519 /* allow clean-up */ 1520 exit(0); 1521 } 1522 1523 static void 1524 init_sigs(void) 1525 { 1526 struct sigaction sa; 1527 1528 sa.sa_handler = onusr1; 1529 sa.sa_flags = SA_RESTART; 1530 sigemptyset(&sa.sa_mask); 1531 if (sigaction(SIGUSR1, &sa, NULL)) { 1532 syslog(LOG_ERR, "sigaction: %m"); 1533 exit(1); 1534 } 1535 1536 sa.sa_handler = onhup; 1537 if (sigaction(SIGHUP, &sa, NULL)) { 1538 syslog(LOG_ERR, "sigaction: %m"); 1539 exit(1); 1540 } 1541 1542 sa.sa_handler = onterm; 1543 sa.sa_flags = 0; 1544 sigemptyset(&sa.sa_mask); 1545 if (sigaction(SIGTERM, &sa, NULL)) { 1546 syslog(LOG_ERR, "sigaction: %m"); 1547 exit(1); 1548 } 1549 if (sigaction(SIGINT, &sa, NULL)) { 1550 syslog(LOG_ERR, "sigaction: %m"); 1551 exit(1); 1552 } 1553 } 1554 1555 static void 1556 block_sigs(void) 1557 { 1558 sigset_t set; 1559 1560 sigfillset(&set); 1561 if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1562 syslog(LOG_ERR, "SIG_BLOCK: %m"); 1563 exit(1); 1564 } 1565 } 1566 static void 1567 unblock_sigs(void) 1568 { 1569 if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1570 syslog(LOG_ERR, "SIG_SETMASK: %m"); 1571 exit(1); 1572 } 1573 } 1574 1575 /* 1576 * Shut down 1577 */ 1578 static void 1579 term(void) 1580 { 1581 (void)unlink(pid_file); 1582 } 1583 1584 static void 1585 trans_stop(void) 1586 { 1587 struct transport *t; 1588 1589 TAILQ_FOREACH(t, &transport_list, link) 1590 (void)t->vtab->stop(1); 1591 } 1592 1593 /* 1594 * Define a macro from the command line 1595 */ 1596 static void 1597 do_macro(char *arg) 1598 { 1599 char *eq; 1600 int err; 1601 1602 if ((eq = strchr(arg, '=')) == NULL) 1603 err = define_macro(arg, ""); 1604 else { 1605 *eq++ = '\0'; 1606 err = define_macro(arg, eq); 1607 } 1608 if (err == -1) { 1609 syslog(LOG_ERR, "cannot save macro: %m"); 1610 exit(1); 1611 } 1612 } 1613 1614 /* 1615 * Re-implement getsubopt from scratch, because the second argument is broken 1616 * and will not compile with WARNS=5. 1617 */ 1618 static int 1619 getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1620 { 1621 static const char *const delim = ",\t "; 1622 u_int i; 1623 char *ptr; 1624 1625 *optp = NULL; 1626 1627 /* skip leading junk */ 1628 for (ptr = *arg; *ptr != '\0'; ptr++) 1629 if (strchr(delim, *ptr) == NULL) 1630 break; 1631 if (*ptr == '\0') { 1632 *arg = ptr; 1633 return (-1); 1634 } 1635 *optp = ptr; 1636 1637 /* find the end of the option */ 1638 while (*++ptr != '\0') 1639 if (strchr(delim, *ptr) != NULL || *ptr == '=') 1640 break; 1641 1642 if (*ptr != '\0') { 1643 if (*ptr == '=') { 1644 *ptr++ = '\0'; 1645 *valp = ptr; 1646 while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1647 ptr++; 1648 if (*ptr != '\0') 1649 *ptr++ = '\0'; 1650 } else 1651 *ptr++ = '\0'; 1652 } 1653 1654 *arg = ptr; 1655 1656 for (i = 0; *options != NULL; options++, i++) 1657 if (strcmp(*optp, *options) == 0) 1658 return (i); 1659 return (-1); 1660 } 1661 1662 int 1663 main(int argc, char *argv[]) 1664 { 1665 int opt; 1666 FILE *fp; 1667 int background = 1; 1668 struct tport *p; 1669 const char *prefix = "snmpd"; 1670 struct lmodule *m; 1671 char *value = NULL, *option; /* XXX */ 1672 struct transport *t; 1673 1674 #define DBG_DUMP 0 1675 #define DBG_EVENTS 1 1676 #define DBG_TRACE 2 1677 static const char *const debug_opts[] = { 1678 "dump", 1679 "events", 1680 "trace", 1681 NULL 1682 }; 1683 1684 snmp_printf = snmp_printf_func; 1685 snmp_error = snmp_error_func; 1686 snmp_debug = snmp_debug_func; 1687 asn_error = asn_error_func; 1688 1689 while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1690 switch (opt) { 1691 1692 case 'c': 1693 strlcpy(config_file, optarg, sizeof(config_file)); 1694 break; 1695 1696 case 'd': 1697 background = 0; 1698 break; 1699 1700 case 'D': 1701 while (*optarg) { 1702 switch (getsubopt1(&optarg, debug_opts, 1703 &value, &option)) { 1704 1705 case DBG_DUMP: 1706 debug.dump_pdus = 1; 1707 break; 1708 1709 case DBG_EVENTS: 1710 debug.evdebug++; 1711 break; 1712 1713 case DBG_TRACE: 1714 if (value == NULL) 1715 syslog(LOG_ERR, 1716 "no value for 'trace'"); 1717 else 1718 snmp_trace = strtoul(value, 1719 NULL, 0); 1720 break; 1721 1722 case -1: 1723 if (suboptarg) 1724 syslog(LOG_ERR, 1725 "unknown debug flag '%s'", 1726 option); 1727 else 1728 syslog(LOG_ERR, 1729 "missing debug flag"); 1730 break; 1731 } 1732 } 1733 break; 1734 1735 case 'e': 1736 strlcpy(engine_file, optarg, sizeof(engine_file)); 1737 break; 1738 case 'h': 1739 fprintf(stderr, "%s", usgtxt); 1740 exit(0); 1741 1742 case 'I': 1743 syspath = optarg; 1744 break; 1745 1746 case 'l': 1747 prefix = optarg; 1748 break; 1749 1750 case 'm': 1751 do_macro(optarg); 1752 break; 1753 1754 case 'p': 1755 strlcpy(pid_file, optarg, sizeof(pid_file)); 1756 break; 1757 } 1758 1759 openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1760 setlogmask(LOG_UPTO(debug.logpri - 1)); 1761 1762 if (background && daemon(0, 0) < 0) { 1763 syslog(LOG_ERR, "daemon: %m"); 1764 exit(1); 1765 } 1766 1767 argc -= optind; 1768 argv += optind; 1769 1770 progargs = argv; 1771 nprogargs = argc; 1772 1773 srandomdev(); 1774 1775 snmp_serial_no = random(); 1776 1777 #ifdef USE_TCPWRAPPERS 1778 /* 1779 * Initialize hosts_access(3) handler. 1780 */ 1781 request_init(&req, RQ_DAEMON, "snmpd", 0); 1782 sock_methods(&req); 1783 #endif 1784 1785 /* 1786 * Initialize the tree. 1787 */ 1788 if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1789 syslog(LOG_ERR, "%m"); 1790 exit(1); 1791 } 1792 memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1793 tree_size = CTREE_SIZE; 1794 1795 /* 1796 * Get standard communities 1797 */ 1798 (void)comm_define(1, "SNMP read", NULL, NULL); 1799 (void)comm_define(2, "SNMP write", NULL, NULL); 1800 community = COMM_INITIALIZE; 1801 1802 trap_reqid = reqid_allocate(512, NULL); 1803 1804 if (config_file[0] == '\0') 1805 snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1806 1807 init_actvals(); 1808 init_snmpd_engine(); 1809 1810 this_tick = get_ticks(); 1811 start_tick = this_tick; 1812 1813 /* start transports */ 1814 if (atexit(trans_stop) == -1) { 1815 syslog(LOG_ERR, "atexit failed: %m"); 1816 exit(1); 1817 } 1818 if (udp_trans.start() != SNMP_ERR_NOERROR) 1819 syslog(LOG_WARNING, "cannot start UDP transport"); 1820 if (lsock_trans.start() != SNMP_ERR_NOERROR) 1821 syslog(LOG_WARNING, "cannot start LSOCK transport"); 1822 1823 #ifdef USE_LIBBEGEMOT 1824 if (debug.evdebug > 0) 1825 rpoll_trace = 1; 1826 #else 1827 if (evCreate(&evctx)) { 1828 syslog(LOG_ERR, "evCreate: %m"); 1829 exit(1); 1830 } 1831 if (debug.evdebug > 0) 1832 evSetDebug(evctx, 10, stderr); 1833 #endif 1834 1835 if (engine_file[0] == '\0') 1836 snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1837 1838 if (read_config(config_file, NULL)) { 1839 syslog(LOG_ERR, "error in config file"); 1840 exit(1); 1841 } 1842 1843 TAILQ_FOREACH(t, &transport_list, link) 1844 TAILQ_FOREACH(p, &t->table, link) 1845 t->vtab->init_port(p); 1846 1847 init_sigs(); 1848 1849 if (pid_file[0] == '\0') 1850 snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1851 1852 if ((fp = fopen(pid_file, "w")) != NULL) { 1853 fprintf(fp, "%u", getpid()); 1854 fclose(fp); 1855 if (atexit(term) == -1) { 1856 syslog(LOG_ERR, "atexit failed: %m"); 1857 (void)remove(pid_file); 1858 exit(0); 1859 } 1860 } 1861 1862 if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1863 NULL) == 0) { 1864 syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1865 exit(1); 1866 } 1867 if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1868 NULL) == 0) { 1869 syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1870 exit(1); 1871 } 1872 1873 while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1874 m->flags &= ~LM_ONSTARTLIST; 1875 TAILQ_REMOVE(&modules_start, m, start); 1876 lm_start(m); 1877 } 1878 1879 snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1880 1881 for (;;) { 1882 #ifndef USE_LIBBEGEMOT 1883 evEvent event; 1884 #endif 1885 struct lmodule *mod; 1886 1887 TAILQ_FOREACH(mod, &lmodules, link) 1888 if (mod->config->idle != NULL) 1889 (*mod->config->idle)(); 1890 1891 #ifndef USE_LIBBEGEMOT 1892 if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1893 if (evDispatch(evctx, event)) 1894 syslog(LOG_ERR, "evDispatch: %m"); 1895 } else if (errno != EINTR) { 1896 syslog(LOG_ERR, "evGetNext: %m"); 1897 exit(1); 1898 } 1899 #else 1900 poll_dispatch(1); 1901 #endif 1902 1903 if (work != 0) { 1904 block_sigs(); 1905 if (work & WORK_DOINFO) { 1906 #ifdef USE_LIBBEGEMOT 1907 info_func(); 1908 #else 1909 if (evWaitFor(evctx, &work, info_func, 1910 NULL, NULL) == -1) { 1911 syslog(LOG_ERR, "evWaitFor: %m"); 1912 exit(1); 1913 } 1914 #endif 1915 } 1916 if (work & WORK_RECONFIG) { 1917 #ifdef USE_LIBBEGEMOT 1918 config_func(); 1919 #else 1920 if (evWaitFor(evctx, &work, config_func, 1921 NULL, NULL) == -1) { 1922 syslog(LOG_ERR, "evWaitFor: %m"); 1923 exit(1); 1924 } 1925 #endif 1926 } 1927 work = 0; 1928 unblock_sigs(); 1929 #ifndef USE_LIBBEGEMOT 1930 if (evDo(evctx, &work) == -1) { 1931 syslog(LOG_ERR, "evDo: %m"); 1932 exit(1); 1933 } 1934 #endif 1935 } 1936 } 1937 1938 return (0); 1939 } 1940 1941 uint64_t 1942 get_ticks(void) 1943 { 1944 struct timeval tv; 1945 uint64_t ret; 1946 1947 if (gettimeofday(&tv, NULL)) 1948 abort(); 1949 ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1950 return (ret); 1951 } 1952 1953 /* 1954 * Timer support 1955 */ 1956 1957 /* 1958 * Trampoline for the non-repeatable timers. 1959 */ 1960 #ifdef USE_LIBBEGEMOT 1961 static void 1962 tfunc(int tid __unused, void *uap) 1963 #else 1964 static void 1965 tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1966 struct timespec inter __unused) 1967 #endif 1968 { 1969 struct timer *tp = uap; 1970 1971 LIST_REMOVE(tp, link); 1972 tp->func(tp->udata); 1973 free(tp); 1974 } 1975 1976 /* 1977 * Trampoline for the repeatable timers. 1978 */ 1979 #ifdef USE_LIBBEGEMOT 1980 static void 1981 trfunc(int tid __unused, void *uap) 1982 #else 1983 static void 1984 trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1985 struct timespec inter __unused) 1986 #endif 1987 { 1988 struct timer *tp = uap; 1989 1990 tp->func(tp->udata); 1991 } 1992 1993 /* 1994 * Start a one-shot timer 1995 */ 1996 void * 1997 timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1998 { 1999 struct timer *tp; 2000 #ifndef USE_LIBBEGEMOT 2001 struct timespec due; 2002 #endif 2003 2004 if ((tp = malloc(sizeof(struct timer))) == NULL) { 2005 syslog(LOG_CRIT, "out of memory for timer"); 2006 exit(1); 2007 } 2008 2009 #ifndef USE_LIBBEGEMOT 2010 due = evAddTime(evNowTime(), 2011 evConsTime(ticks / 100, (ticks % 100) * 10000)); 2012 #endif 2013 2014 tp->udata = udata; 2015 tp->owner = mod; 2016 tp->func = func; 2017 2018 LIST_INSERT_HEAD(&timer_list, tp, link); 2019 2020 #ifdef USE_LIBBEGEMOT 2021 if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 2022 syslog(LOG_ERR, "cannot set timer: %m"); 2023 exit(1); 2024 } 2025 #else 2026 if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 2027 == -1) { 2028 syslog(LOG_ERR, "cannot set timer: %m"); 2029 exit(1); 2030 } 2031 #endif 2032 return (tp); 2033 } 2034 2035 /* 2036 * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 2037 * is currently ignored and the initial number of ticks is set to the 2038 * repeat number of ticks. 2039 */ 2040 void * 2041 timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 2042 void (*func)(void *), void *udata, struct lmodule *mod) 2043 { 2044 struct timer *tp; 2045 #ifndef USE_LIBBEGEMOT 2046 struct timespec due; 2047 struct timespec inter; 2048 #endif 2049 2050 if ((tp = malloc(sizeof(struct timer))) == NULL) { 2051 syslog(LOG_CRIT, "out of memory for timer"); 2052 exit(1); 2053 } 2054 2055 #ifndef USE_LIBBEGEMOT 2056 due = evAddTime(evNowTime(), 2057 evConsTime(ticks / 100, (ticks % 100) * 10000)); 2058 inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 2059 #endif 2060 2061 tp->udata = udata; 2062 tp->owner = mod; 2063 tp->func = func; 2064 2065 LIST_INSERT_HEAD(&timer_list, tp, link); 2066 2067 #ifdef USE_LIBBEGEMOT 2068 if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 2069 syslog(LOG_ERR, "cannot set timer: %m"); 2070 exit(1); 2071 } 2072 #else 2073 if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 2074 syslog(LOG_ERR, "cannot set timer: %m"); 2075 exit(1); 2076 } 2077 #endif 2078 return (tp); 2079 } 2080 2081 /* 2082 * Stop a timer. 2083 */ 2084 void 2085 timer_stop(void *p) 2086 { 2087 struct timer *tp = p; 2088 2089 LIST_REMOVE(tp, link); 2090 #ifdef USE_LIBBEGEMOT 2091 poll_stop_timer(tp->id); 2092 #else 2093 if (evClearTimer(evctx, tp->id) == -1) { 2094 syslog(LOG_ERR, "cannot stop timer: %m"); 2095 exit(1); 2096 } 2097 #endif 2098 free(p); 2099 } 2100 2101 static void 2102 timer_flush(struct lmodule *mod) 2103 { 2104 struct timer *t, *t1; 2105 2106 t = LIST_FIRST(&timer_list); 2107 while (t != NULL) { 2108 t1 = LIST_NEXT(t, link); 2109 if (t->owner == mod) 2110 timer_stop(t); 2111 t = t1; 2112 } 2113 } 2114 2115 static void 2116 snmp_printf_func(const char *fmt, ...) 2117 { 2118 va_list ap; 2119 static char *pend = NULL; 2120 char *ret, *new; 2121 2122 va_start(ap, fmt); 2123 vasprintf(&ret, fmt, ap); 2124 va_end(ap); 2125 2126 if (ret == NULL) 2127 return; 2128 if (pend != NULL) { 2129 if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 2130 == NULL) { 2131 free(ret); 2132 return; 2133 } 2134 pend = new; 2135 strcat(pend, ret); 2136 free(ret); 2137 } else 2138 pend = ret; 2139 2140 while ((ret = strchr(pend, '\n')) != NULL) { 2141 *ret = '\0'; 2142 syslog(LOG_DEBUG, "%s", pend); 2143 if (strlen(ret + 1) == 0) { 2144 free(pend); 2145 pend = NULL; 2146 break; 2147 } 2148 strcpy(pend, ret + 1); 2149 } 2150 } 2151 2152 static void 2153 snmp_error_func(const char *err, ...) 2154 { 2155 char errbuf[1000]; 2156 va_list ap; 2157 2158 if (!(snmp_trace & LOG_SNMP_ERRORS)) 2159 return; 2160 2161 va_start(ap, err); 2162 snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2163 vsnprintf(errbuf + strlen(errbuf), 2164 sizeof(errbuf) - strlen(errbuf), err, ap); 2165 va_end(ap); 2166 2167 syslog(LOG_ERR, "%s", errbuf); 2168 } 2169 2170 static void 2171 snmp_debug_func(const char *err, ...) 2172 { 2173 char errbuf[1000]; 2174 va_list ap; 2175 2176 va_start(ap, err); 2177 snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2178 vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2179 err, ap); 2180 va_end(ap); 2181 2182 syslog(LOG_DEBUG, "%s", errbuf); 2183 } 2184 2185 static void 2186 asn_error_func(const struct asn_buf *b, const char *err, ...) 2187 { 2188 char errbuf[1000]; 2189 va_list ap; 2190 u_int i; 2191 2192 if (!(snmp_trace & LOG_ASN1_ERRORS)) 2193 return; 2194 2195 va_start(ap, err); 2196 snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 2197 vsnprintf(errbuf + strlen(errbuf), 2198 sizeof(errbuf) - strlen(errbuf), err, ap); 2199 va_end(ap); 2200 2201 if (b != NULL) { 2202 snprintf(errbuf + strlen(errbuf), 2203 sizeof(errbuf) - strlen(errbuf), " at"); 2204 for (i = 0; b->asn_len > i; i++) 2205 snprintf(errbuf + strlen(errbuf), 2206 sizeof(errbuf) - strlen(errbuf), 2207 " %02x", b->asn_cptr[i]); 2208 } 2209 2210 syslog(LOG_ERR, "%s", errbuf); 2211 } 2212 2213 /* 2214 * Create a new community 2215 */ 2216 u_int 2217 comm_define(u_int priv, const char *descr, struct lmodule *owner, 2218 const char *str) 2219 { 2220 struct community *c, *p; 2221 u_int ncomm; 2222 2223 /* generate an identifier */ 2224 do { 2225 if ((ncomm = next_community_index++) == UINT_MAX) 2226 next_community_index = 1; 2227 TAILQ_FOREACH(c, &community_list, link) 2228 if (c->value == ncomm) 2229 break; 2230 } while (c != NULL); 2231 2232 if ((c = malloc(sizeof(struct community))) == NULL) { 2233 syslog(LOG_ERR, "comm_define: %m"); 2234 return (0); 2235 } 2236 c->owner = owner; 2237 c->value = ncomm; 2238 c->descr = descr; 2239 c->string = NULL; 2240 c->private = priv; 2241 2242 if (str != NULL) { 2243 if((c->string = malloc(strlen(str)+1)) == NULL) { 2244 free(c); 2245 return (0); 2246 } 2247 strcpy(c->string, str); 2248 } 2249 2250 /* make index */ 2251 if (c->owner == NULL) { 2252 c->index.len = 1; 2253 c->index.subs[0] = 0; 2254 } else { 2255 c->index = c->owner->index; 2256 } 2257 c->index.subs[c->index.len++] = c->private; 2258 2259 /* 2260 * Insert ordered 2261 */ 2262 TAILQ_FOREACH(p, &community_list, link) { 2263 if (asn_compare_oid(&p->index, &c->index) > 0) { 2264 TAILQ_INSERT_BEFORE(p, c, link); 2265 break; 2266 } 2267 } 2268 if (p == NULL) 2269 TAILQ_INSERT_TAIL(&community_list, c, link); 2270 return (c->value); 2271 } 2272 2273 const char * 2274 comm_string(u_int ncomm) 2275 { 2276 struct community *p; 2277 2278 TAILQ_FOREACH(p, &community_list, link) 2279 if (p->value == ncomm) 2280 return (p->string); 2281 return (NULL); 2282 } 2283 2284 /* 2285 * Delete all communities allocated by a module 2286 */ 2287 static void 2288 comm_flush(struct lmodule *mod) 2289 { 2290 struct community *p, *p1; 2291 2292 p = TAILQ_FIRST(&community_list); 2293 while (p != NULL) { 2294 p1 = TAILQ_NEXT(p, link); 2295 if (p->owner == mod) { 2296 free(p->string); 2297 TAILQ_REMOVE(&community_list, p, link); 2298 free(p); 2299 } 2300 p = p1; 2301 } 2302 } 2303 2304 /* 2305 * Request ID handling. 2306 * 2307 * Allocate a new range of request ids. Use a first fit algorithm. 2308 */ 2309 u_int 2310 reqid_allocate(int size, struct lmodule *mod) 2311 { 2312 u_int type; 2313 struct idrange *r, *r1; 2314 2315 if (size <= 0 || size > INT32_MAX) { 2316 syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2317 return (0); 2318 } 2319 /* allocate a type id */ 2320 do { 2321 if ((type = next_idrange++) == UINT_MAX) 2322 next_idrange = 1; 2323 TAILQ_FOREACH(r, &idrange_list, link) 2324 if (r->type == type) 2325 break; 2326 } while(r != NULL); 2327 2328 /* find a range */ 2329 if (TAILQ_EMPTY(&idrange_list)) 2330 r = NULL; 2331 else { 2332 r = TAILQ_FIRST(&idrange_list); 2333 if (r->base < size) { 2334 while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2335 if (r1->base - (r->base + r->size) >= size) 2336 break; 2337 r = r1; 2338 } 2339 r = r1; 2340 } 2341 if (r == NULL) { 2342 r1 = TAILQ_LAST(&idrange_list, idrange_list); 2343 if (INT32_MAX - size + 1 < r1->base + r1->size) { 2344 syslog(LOG_ERR, "out of id ranges (%u)", size); 2345 return (0); 2346 } 2347 } 2348 } 2349 2350 /* allocate structure */ 2351 if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2352 syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2353 return (0); 2354 } 2355 2356 r1->type = type; 2357 r1->size = size; 2358 r1->owner = mod; 2359 if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2360 r1->base = 0; 2361 TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2362 } else if (r == NULL) { 2363 r = TAILQ_LAST(&idrange_list, idrange_list); 2364 r1->base = r->base + r->size; 2365 TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2366 } else { 2367 r = TAILQ_PREV(r, idrange_list, link); 2368 r1->base = r->base + r->size; 2369 TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2370 } 2371 r1->next = r1->base; 2372 2373 return (type); 2374 } 2375 2376 int32_t 2377 reqid_next(u_int type) 2378 { 2379 struct idrange *r; 2380 int32_t id; 2381 2382 TAILQ_FOREACH(r, &idrange_list, link) 2383 if (r->type == type) 2384 break; 2385 if (r == NULL) { 2386 syslog(LOG_CRIT, "wrong idrange type"); 2387 abort(); 2388 } 2389 if ((id = r->next++) == r->base + (r->size - 1)) 2390 r->next = r->base; 2391 return (id); 2392 } 2393 2394 int32_t 2395 reqid_base(u_int type) 2396 { 2397 struct idrange *r; 2398 2399 TAILQ_FOREACH(r, &idrange_list, link) 2400 if (r->type == type) 2401 return (r->base); 2402 syslog(LOG_CRIT, "wrong idrange type"); 2403 abort(); 2404 } 2405 2406 u_int 2407 reqid_type(int32_t reqid) 2408 { 2409 struct idrange *r; 2410 2411 TAILQ_FOREACH(r, &idrange_list, link) 2412 if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2413 return (r->type); 2414 return (0); 2415 } 2416 2417 int 2418 reqid_istype(int32_t reqid, u_int type) 2419 { 2420 return (reqid_type(reqid) == type); 2421 } 2422 2423 /* 2424 * Delete all communities allocated by a module 2425 */ 2426 static void 2427 reqid_flush(struct lmodule *mod) 2428 { 2429 struct idrange *p, *p1; 2430 2431 p = TAILQ_FIRST(&idrange_list); 2432 while (p != NULL) { 2433 p1 = TAILQ_NEXT(p, link); 2434 if (p->owner == mod) { 2435 TAILQ_REMOVE(&idrange_list, p, link); 2436 free(p); 2437 } 2438 p = p1; 2439 } 2440 } 2441 2442 /* 2443 * Merge the given tree for the given module into the main tree. 2444 */ 2445 static int 2446 compare_node(const void *v1, const void *v2) 2447 { 2448 const struct snmp_node *n1 = v1; 2449 const struct snmp_node *n2 = v2; 2450 2451 return (asn_compare_oid(&n1->oid, &n2->oid)); 2452 } 2453 static int 2454 tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2455 { 2456 struct snmp_node *xtree; 2457 u_int i; 2458 2459 xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2460 if (xtree == NULL) { 2461 syslog(LOG_ERR, "tree_merge: %m"); 2462 return (-1); 2463 } 2464 tree = xtree; 2465 memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2466 2467 for (i = 0; i < nsize; i++) 2468 tree[tree_size + i].tree_data = mod; 2469 2470 tree_size += nsize; 2471 2472 qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2473 2474 return (0); 2475 } 2476 2477 /* 2478 * Remove all nodes belonging to the loadable module 2479 */ 2480 static void 2481 tree_unmerge(struct lmodule *mod) 2482 { 2483 u_int s, d; 2484 2485 for(s = d = 0; s < tree_size; s++) 2486 if (tree[s].tree_data != mod) { 2487 if (s != d) 2488 tree[d] = tree[s]; 2489 d++; 2490 } 2491 tree_size = d; 2492 } 2493 2494 /* 2495 * Loadable modules 2496 */ 2497 struct lmodule * 2498 lm_load(const char *path, const char *section) 2499 { 2500 struct lmodule *m; 2501 int err; 2502 int i; 2503 char *av[MAX_MOD_ARGS + 1]; 2504 int ac; 2505 u_int u; 2506 2507 if ((m = malloc(sizeof(*m))) == NULL) { 2508 syslog(LOG_ERR, "lm_load: %m"); 2509 return (NULL); 2510 } 2511 m->handle = NULL; 2512 m->flags = 0; 2513 strcpy(m->section, section); 2514 2515 if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2516 syslog(LOG_ERR, "lm_load: %m"); 2517 goto err; 2518 } 2519 strcpy(m->path, path); 2520 2521 /* 2522 * Make index 2523 */ 2524 m->index.subs[0] = strlen(section); 2525 m->index.len = m->index.subs[0] + 1; 2526 for (u = 0; u < m->index.subs[0]; u++) 2527 m->index.subs[u + 1] = section[u]; 2528 2529 /* 2530 * Load the object file and locate the config structure 2531 */ 2532 if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2533 syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2534 goto err; 2535 } 2536 2537 if ((m->config = dlsym(m->handle, "config")) == NULL) { 2538 syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2539 goto err; 2540 } 2541 2542 /* 2543 * Insert it into the right place 2544 */ 2545 INSERT_OBJECT_OID(m, &lmodules); 2546 2547 /* preserve order */ 2548 if (community == COMM_INITIALIZE) { 2549 m->flags |= LM_ONSTARTLIST; 2550 TAILQ_INSERT_TAIL(&modules_start, m, start); 2551 } 2552 2553 /* 2554 * make the argument vector. 2555 */ 2556 ac = 0; 2557 for (i = 0; i < nprogargs; i++) { 2558 if (strlen(progargs[i]) >= strlen(section) + 1 && 2559 strncmp(progargs[i], section, strlen(section)) == 0 && 2560 progargs[i][strlen(section)] == ':') { 2561 if (ac == MAX_MOD_ARGS) { 2562 syslog(LOG_WARNING, "too many arguments for " 2563 "module '%s", section); 2564 break; 2565 } 2566 av[ac++] = &progargs[i][strlen(section)+1]; 2567 } 2568 } 2569 av[ac] = NULL; 2570 2571 /* 2572 * Run the initialization function 2573 */ 2574 if ((err = (*m->config->init)(m, ac, av)) != 0) { 2575 syslog(LOG_ERR, "lm_load: init failed: %d", err); 2576 TAILQ_REMOVE(&lmodules, m, link); 2577 goto err; 2578 } 2579 2580 return (m); 2581 2582 err: 2583 if ((m->flags & LM_ONSTARTLIST) != 0) 2584 TAILQ_REMOVE(&modules_start, m, start); 2585 if (m->handle) 2586 dlclose(m->handle); 2587 free(m->path); 2588 free(m); 2589 return (NULL); 2590 } 2591 2592 /* 2593 * Start a module 2594 */ 2595 void 2596 lm_start(struct lmodule *mod) 2597 { 2598 const struct lmodule *m; 2599 2600 /* 2601 * Merge tree. If this fails, unload the module. 2602 */ 2603 if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2604 lm_unload(mod); 2605 return; 2606 } 2607 2608 /* 2609 * Read configuration 2610 */ 2611 if (read_config(config_file, mod)) { 2612 syslog(LOG_ERR, "error in config file"); 2613 lm_unload(mod); 2614 return; 2615 } 2616 if (mod->config->start) 2617 (*mod->config->start)(); 2618 2619 mod->flags |= LM_STARTED; 2620 2621 /* 2622 * Inform other modules 2623 */ 2624 TAILQ_FOREACH(m, &lmodules, link) 2625 if (m->config->loading) 2626 (*m->config->loading)(mod, 1); 2627 } 2628 2629 2630 /* 2631 * Unload a module. 2632 */ 2633 void 2634 lm_unload(struct lmodule *m) 2635 { 2636 int err; 2637 const struct lmodule *mod; 2638 2639 TAILQ_REMOVE(&lmodules, m, link); 2640 if (m->flags & LM_ONSTARTLIST) 2641 TAILQ_REMOVE(&modules_start, m, start); 2642 tree_unmerge(m); 2643 2644 if ((m->flags & LM_STARTED) && m->config->fini && 2645 (err = (*m->config->fini)()) != 0) 2646 syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2647 2648 comm_flush(m); 2649 reqid_flush(m); 2650 timer_flush(m); 2651 fd_flush(m); 2652 2653 dlclose(m->handle); 2654 free(m->path); 2655 2656 /* 2657 * Inform other modules 2658 */ 2659 TAILQ_FOREACH(mod, &lmodules, link) 2660 if (mod->config->loading) 2661 (*mod->config->loading)(m, 0); 2662 2663 free(m); 2664 } 2665 2666 /* 2667 * Register an object resource and return the index (or 0 on failures) 2668 */ 2669 u_int 2670 or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2671 { 2672 struct objres *objres, *or1; 2673 u_int idx; 2674 2675 /* find a free index */ 2676 idx = 1; 2677 for (objres = TAILQ_FIRST(&objres_list); 2678 objres != NULL; 2679 objres = TAILQ_NEXT(objres, link)) { 2680 if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2681 or1->index > objres->index + 1) { 2682 idx = objres->index + 1; 2683 break; 2684 } 2685 } 2686 2687 if ((objres = malloc(sizeof(*objres))) == NULL) 2688 return (0); 2689 2690 objres->index = idx; 2691 objres->oid = *or; 2692 strlcpy(objres->descr, descr, sizeof(objres->descr)); 2693 objres->uptime = (uint32_t)(get_ticks() - start_tick); 2694 objres->module = mod; 2695 2696 INSERT_OBJECT_INT(objres, &objres_list); 2697 2698 systemg.or_last_change = objres->uptime; 2699 2700 return (idx); 2701 } 2702 2703 void 2704 or_unregister(u_int idx) 2705 { 2706 struct objres *objres; 2707 2708 TAILQ_FOREACH(objres, &objres_list, link) 2709 if (objres->index == idx) { 2710 TAILQ_REMOVE(&objres_list, objres, link); 2711 free(objres); 2712 return; 2713 } 2714 } 2715 2716 /* 2717 * RFC 3414 User-based Security Model support 2718 */ 2719 2720 struct snmpd_usmstat * 2721 bsnmpd_get_usm_stats(void) 2722 { 2723 return (&snmpd_usmstats); 2724 } 2725 2726 void 2727 bsnmpd_reset_usm_stats(void) 2728 { 2729 memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2730 } 2731 2732 struct usm_user * 2733 usm_first_user(void) 2734 { 2735 return (SLIST_FIRST(&usm_userlist)); 2736 } 2737 2738 struct usm_user * 2739 usm_next_user(struct usm_user *uuser) 2740 { 2741 if (uuser == NULL) 2742 return (NULL); 2743 2744 return (SLIST_NEXT(uuser, up)); 2745 } 2746 2747 struct usm_user * 2748 usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2749 { 2750 struct usm_user *uuser; 2751 2752 SLIST_FOREACH(uuser, &usm_userlist, up) 2753 if (uuser->user_engine_len == elen && 2754 memcmp(uuser->user_engine_id, engine, elen) == 0 && 2755 strlen(uuser->suser.sec_name) == strlen(uname) && 2756 strcmp(uuser->suser.sec_name, uname) == 0) 2757 break; 2758 2759 return (uuser); 2760 } 2761 2762 static int 2763 usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2764 { 2765 uint32_t i; 2766 2767 if (u1->user_engine_len < u2->user_engine_len) 2768 return (-1); 2769 if (u1->user_engine_len > u2->user_engine_len) 2770 return (1); 2771 2772 for (i = 0; i < u1->user_engine_len; i++) { 2773 if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2774 return (-1); 2775 if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2776 return (1); 2777 } 2778 2779 if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2780 return (-1); 2781 if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2782 return (1); 2783 2784 for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2785 if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2786 return (-1); 2787 if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2788 return (1); 2789 } 2790 2791 return (0); 2792 } 2793 2794 struct usm_user * 2795 usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2796 { 2797 int cmp; 2798 struct usm_user *uuser, *temp, *prev; 2799 2800 for (uuser = usm_first_user(); uuser != NULL; 2801 (uuser = usm_next_user(uuser))) { 2802 if (uuser->user_engine_len == elen && 2803 strlen(uname) == strlen(uuser->suser.sec_name) && 2804 strcmp(uname, uuser->suser.sec_name) == 0 && 2805 memcmp(eid, uuser->user_engine_id, elen) == 0) 2806 return (NULL); 2807 } 2808 2809 if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2810 return (NULL); 2811 2812 memset(uuser, 0, sizeof(struct usm_user)); 2813 strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2814 memcpy(uuser->user_engine_id, eid, elen); 2815 uuser->user_engine_len = elen; 2816 2817 if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2818 usm_compare_user(uuser, prev) < 0) { 2819 SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2820 return (uuser); 2821 } 2822 2823 SLIST_FOREACH(temp, &usm_userlist, up) { 2824 if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2825 break; 2826 prev = temp; 2827 } 2828 2829 if (temp == NULL || cmp < 0) 2830 SLIST_INSERT_AFTER(prev, uuser, up); 2831 else if (cmp > 0) 2832 SLIST_INSERT_AFTER(temp, uuser, up); 2833 else { 2834 syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2835 free(uuser); 2836 return (NULL); 2837 } 2838 2839 return (uuser); 2840 } 2841 2842 void 2843 usm_delete_user(struct usm_user *uuser) 2844 { 2845 SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2846 free(uuser); 2847 } 2848 2849 void 2850 usm_flush_users(void) 2851 { 2852 struct usm_user *uuser; 2853 2854 while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2855 SLIST_REMOVE_HEAD(&usm_userlist, up); 2856 free(uuser); 2857 } 2858 2859 SLIST_INIT(&usm_userlist); 2860 } 2861 2862 /* 2863 * RFC 3415 View-based Access Control Model support 2864 */ 2865 struct vacm_user * 2866 vacm_first_user(void) 2867 { 2868 return (SLIST_FIRST(&vacm_userlist)); 2869 } 2870 2871 struct vacm_user * 2872 vacm_next_user(struct vacm_user *vuser) 2873 { 2874 if (vuser == NULL) 2875 return (NULL); 2876 2877 return (SLIST_NEXT(vuser, vvu)); 2878 } 2879 2880 static int 2881 vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2882 { 2883 uint32_t i; 2884 2885 if (v1->sec_model < v2->sec_model) 2886 return (-1); 2887 if (v1->sec_model > v2->sec_model) 2888 return (1); 2889 2890 if (strlen(v1->secname) < strlen(v2->secname)) 2891 return (-1); 2892 if (strlen(v1->secname) > strlen(v2->secname)) 2893 return (1); 2894 2895 for (i = 0; i < strlen(v1->secname); i++) { 2896 if (v1->secname[i] < v2->secname[i]) 2897 return (-1); 2898 if (v1->secname[i] > v2->secname[i]) 2899 return (1); 2900 } 2901 2902 return (0); 2903 } 2904 2905 struct vacm_user * 2906 vacm_new_user(int32_t smodel, char *uname) 2907 { 2908 int cmp; 2909 struct vacm_user *user, *temp, *prev; 2910 2911 SLIST_FOREACH(user, &vacm_userlist, vvu) 2912 if (strcmp(uname, user->secname) == 0 && 2913 smodel == user->sec_model) 2914 return (NULL); 2915 2916 if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2917 return (NULL); 2918 2919 memset(user, 0, sizeof(*user)); 2920 user->group = &vacm_default_group; 2921 SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2922 user->sec_model = smodel; 2923 strlcpy(user->secname, uname, sizeof(user->secname)); 2924 2925 if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2926 vacm_compare_user(user, prev) < 0) { 2927 SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2928 return (user); 2929 } 2930 2931 SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2932 if ((cmp = vacm_compare_user(user, temp)) <= 0) 2933 break; 2934 prev = temp; 2935 } 2936 2937 if (temp == NULL || cmp < 0) 2938 SLIST_INSERT_AFTER(prev, user, vvu); 2939 else if (cmp > 0) 2940 SLIST_INSERT_AFTER(temp, user, vvu); 2941 else { 2942 syslog(LOG_ERR, "User %s exists", user->secname); 2943 free(user); 2944 return (NULL); 2945 } 2946 2947 return (user); 2948 } 2949 2950 int 2951 vacm_delete_user(struct vacm_user *user) 2952 { 2953 if (user->group != NULL && user->group != &vacm_default_group) { 2954 SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2955 if (SLIST_EMPTY(&user->group->group_users)) { 2956 SLIST_REMOVE(&vacm_grouplist, user->group, 2957 vacm_group, vge); 2958 free(user->group); 2959 } 2960 } 2961 2962 SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2963 free(user); 2964 2965 return (0); 2966 } 2967 2968 int 2969 vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2970 { 2971 struct vacm_group *group; 2972 2973 if (len >= SNMP_ADM_STR32_SIZ) 2974 return (-1); 2975 2976 SLIST_FOREACH(group, &vacm_grouplist, vge) 2977 if (strlen(group->groupname) == len && 2978 memcmp(octets, group->groupname, len) == 0) 2979 break; 2980 2981 if (group == NULL) { 2982 if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2983 return (-1); 2984 memset(group, 0, sizeof(*group)); 2985 memcpy(group->groupname, octets, len); 2986 group->groupname[len] = '\0'; 2987 SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2988 } 2989 2990 SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2991 SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2992 user->group = group; 2993 2994 return (0); 2995 } 2996 2997 void 2998 vacm_groups_init(void) 2999 { 3000 SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 3001 } 3002 3003 struct vacm_access * 3004 vacm_first_access_rule(void) 3005 { 3006 return (TAILQ_FIRST(&vacm_accesslist)); 3007 } 3008 3009 struct vacm_access * 3010 vacm_next_access_rule(struct vacm_access *acl) 3011 { 3012 if (acl == NULL) 3013 return (NULL); 3014 3015 return (TAILQ_NEXT(acl, vva)); 3016 } 3017 3018 static int 3019 vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 3020 { 3021 uint32_t i; 3022 3023 if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 3024 return (-1); 3025 if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 3026 return (1); 3027 3028 for (i = 0; i < strlen(v1->group->groupname); i++) { 3029 if (v1->group->groupname[i] < v2->group->groupname[i]) 3030 return (-1); 3031 if (v1->group->groupname[i] > v2->group->groupname[i]) 3032 return (1); 3033 } 3034 3035 if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 3036 return (-1); 3037 if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 3038 return (1); 3039 3040 for (i = 0; i < strlen(v1->ctx_prefix); i++) { 3041 if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 3042 return (-1); 3043 if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 3044 return (1); 3045 } 3046 3047 if (v1->sec_model < v2->sec_model) 3048 return (-1); 3049 if (v1->sec_model > v2->sec_model) 3050 return (1); 3051 3052 if (v1->sec_level < v2->sec_level) 3053 return (-1); 3054 if (v1->sec_level > v2->sec_level) 3055 return (1); 3056 3057 return (0); 3058 } 3059 3060 struct vacm_access * 3061 vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 3062 { 3063 struct vacm_group *group; 3064 struct vacm_access *acl, *temp; 3065 3066 TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 3067 if (acl->group == NULL) 3068 continue; 3069 if (strcmp(gname, acl->group->groupname) == 0 && 3070 strcmp(cprefix, acl->ctx_prefix) == 0 && 3071 acl->sec_model == smodel && acl->sec_level == slevel) 3072 return (NULL); 3073 } 3074 3075 /* Make sure the group exists */ 3076 SLIST_FOREACH(group, &vacm_grouplist, vge) 3077 if (strcmp(gname, group->groupname) == 0) 3078 break; 3079 3080 if (group == NULL) 3081 return (NULL); 3082 3083 if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 3084 return (NULL); 3085 3086 memset(acl, 0, sizeof(*acl)); 3087 acl->group = group; 3088 strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 3089 acl->sec_model = smodel; 3090 acl->sec_level = slevel; 3091 3092 if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 3093 vacm_compare_access_rule(acl, temp) < 0) { 3094 TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 3095 return (acl); 3096 } 3097 3098 TAILQ_FOREACH(temp, &vacm_accesslist, vva) 3099 if (vacm_compare_access_rule(acl, temp) < 0) { 3100 TAILQ_INSERT_BEFORE(temp, acl, vva); 3101 return (acl); 3102 } 3103 3104 TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 3105 3106 return (acl); 3107 } 3108 3109 int 3110 vacm_delete_access_rule(struct vacm_access *acl) 3111 { 3112 TAILQ_REMOVE(&vacm_accesslist, acl, vva); 3113 free(acl); 3114 3115 return (0); 3116 } 3117 3118 struct vacm_view * 3119 vacm_first_view(void) 3120 { 3121 return (SLIST_FIRST(&vacm_viewlist)); 3122 } 3123 3124 struct vacm_view * 3125 vacm_next_view(struct vacm_view *view) 3126 { 3127 if (view == NULL) 3128 return (NULL); 3129 3130 return (SLIST_NEXT(view, vvl)); 3131 } 3132 3133 static int 3134 vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3135 { 3136 uint32_t i; 3137 3138 if (strlen(v1->viewname) < strlen(v2->viewname)) 3139 return (-1); 3140 if (strlen(v1->viewname) > strlen(v2->viewname)) 3141 return (1); 3142 3143 for (i = 0; i < strlen(v1->viewname); i++) { 3144 if (v1->viewname[i] < v2->viewname[i]) 3145 return (-1); 3146 if (v1->viewname[i] > v2->viewname[i]) 3147 return (1); 3148 } 3149 3150 return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3151 } 3152 3153 struct vacm_view * 3154 vacm_new_view(char *vname, struct asn_oid *oid) 3155 { 3156 int cmp; 3157 struct vacm_view *view, *temp, *prev; 3158 3159 SLIST_FOREACH(view, &vacm_viewlist, vvl) 3160 if (strcmp(vname, view->viewname) == 0) 3161 return (NULL); 3162 3163 if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3164 return (NULL); 3165 3166 memset(view, 0, sizeof(*view)); 3167 strlcpy(view->viewname, vname, sizeof(view->viewname)); 3168 asn_append_oid(&view->subtree, oid); 3169 3170 if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3171 vacm_compare_view(view, prev) < 0) { 3172 SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3173 return (view); 3174 } 3175 3176 SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3177 if ((cmp = vacm_compare_view(view, temp)) <= 0) 3178 break; 3179 prev = temp; 3180 } 3181 3182 if (temp == NULL || cmp < 0) 3183 SLIST_INSERT_AFTER(prev, view, vvl); 3184 else if (cmp > 0) 3185 SLIST_INSERT_AFTER(temp, view, vvl); 3186 else { 3187 syslog(LOG_ERR, "View %s exists", view->viewname); 3188 free(view); 3189 return (NULL); 3190 } 3191 3192 return (view); 3193 } 3194 3195 int 3196 vacm_delete_view(struct vacm_view *view) 3197 { 3198 SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3199 free(view); 3200 3201 return (0); 3202 } 3203 3204 struct vacm_context * 3205 vacm_first_context(void) 3206 { 3207 return (SLIST_FIRST(&vacm_contextlist)); 3208 } 3209 3210 struct vacm_context * 3211 vacm_next_context(struct vacm_context *vacmctx) 3212 { 3213 if (vacmctx == NULL) 3214 return (NULL); 3215 3216 return (SLIST_NEXT(vacmctx, vcl)); 3217 } 3218 3219 struct vacm_context * 3220 vacm_add_context(char *ctxname, int regid) 3221 { 3222 int cmp; 3223 struct vacm_context *ctx, *temp, *prev; 3224 3225 SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3226 if (strcmp(ctxname, ctx->ctxname) == 0) { 3227 syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3228 return (NULL); 3229 } 3230 3231 if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3232 return (NULL); 3233 3234 memset(ctx, 0, sizeof(*ctx)); 3235 strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3236 ctx->regid = regid; 3237 3238 if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3239 strlen(ctx->ctxname) < strlen(prev->ctxname) || 3240 strcmp(ctx->ctxname, prev->ctxname) < 0) { 3241 SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3242 return (ctx); 3243 } 3244 3245 SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3246 if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3247 strcmp(ctx->ctxname, temp->ctxname) < 0) { 3248 cmp = -1; 3249 break; 3250 } 3251 prev = temp; 3252 } 3253 3254 if (temp == NULL || cmp < 0) 3255 SLIST_INSERT_AFTER(prev, ctx, vcl); 3256 else if (cmp > 0) 3257 SLIST_INSERT_AFTER(temp, ctx, vcl); 3258 else { 3259 syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3260 free(ctx); 3261 return (NULL); 3262 } 3263 3264 return (ctx); 3265 } 3266 3267 void 3268 vacm_flush_contexts(int regid) 3269 { 3270 struct vacm_context *ctx, *temp; 3271 3272 SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3273 if (ctx->regid == regid) { 3274 SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3275 free(ctx); 3276 } 3277 } 3278