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