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