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