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