main.c revision 122394
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 * Redistribution of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Begemot: bsnmp/snmpd/main.c,v 1.76 2003/01/28 13:44:35 hbb Exp $ 34 * 35 * SNMPd main stuff. 36 */ 37#include <sys/param.h> 38#include <sys/un.h> 39#include <sys/stat.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <stddef.h> 43#include <string.h> 44#include <stdarg.h> 45#include <ctype.h> 46#include <errno.h> 47#include <syslog.h> 48#include <unistd.h> 49#include <signal.h> 50#include <dlfcn.h> 51#include <inttypes.h> 52#include <netinet/in.h> 53#include <arpa/inet.h> 54 55#include "snmpmod.h" 56#include "snmpd.h" 57#include "tree.h" 58#include "oid.h" 59 60#define PATH_PID "/var/run/%s.pid" 61#define PATH_CONFIG "/etc/%s.config" 62 63u_int32_t this_tick; /* start of processing of current packet */ 64u_int32_t start_tick; /* start of processing */ 65 66struct systemg systemg = { 67 NULL, 68 { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 69 NULL, NULL, NULL, 70 64 + 8 + 4, 71 0 72}; 73struct debug debug = { 74 0, /* dump_pdus */ 75 LOG_DEBUG, /* log_pri */ 76 0, /* evdebug */ 77}; 78 79struct snmpd snmpd = { 80 2048, /* txbuf */ 81 2048, /* rxbuf */ 82 0, /* comm_dis */ 83 0, /* auth_traps */ 84 {0, 0, 0, 0}, /* trap1addr */ 85}; 86struct snmpd_stats snmpd_stats; 87 88/* snmpSerialNo */ 89int32_t snmp_serial_no; 90 91/* search path for config files */ 92const char *syspath = PATH_SYSCONFIG; 93 94/* list of all loaded modules */ 95struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 96 97/* list of loaded modules during start-up in the order they were loaded */ 98static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 99 100/* list of all known communities */ 101struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 102 103/* list of all installed object resources */ 104struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 105 106/* community value generator */ 107static u_int next_community_index = 1; 108 109/* list of all known ranges */ 110struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 111 112/* identifier generator */ 113u_int next_idrange = 1; 114 115/* list of all current timers */ 116struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 117 118/* list of file descriptors */ 119struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 120 121/* program arguments */ 122static char **progargs; 123static int nprogargs; 124 125/* current community */ 126u_int community; 127static struct community *comm; 128 129/* list of all IP ports we are listening on */ 130struct snmp_port_list snmp_port_list = 131 TAILQ_HEAD_INITIALIZER(snmp_port_list); 132 133/* list of all local ports we are listening on */ 134struct local_port_list local_port_list = 135 TAILQ_HEAD_INITIALIZER(local_port_list); 136 137/* file names */ 138static char config_file[MAXPATHLEN + 1]; 139static char pid_file[MAXPATHLEN + 1]; 140 141/* event context */ 142static evContext evctx; 143 144/* signal mask */ 145static sigset_t blocked_sigs; 146 147/* signal handling */ 148static int work; 149#define WORK_DOINFO 0x0001 150#define WORK_RECONFIG 0x0002 151 152/* oids */ 153static const struct asn_oid 154 oid_snmpMIB = OIDX_snmpMIB, 155 oid_begemotSnmpd = OIDX_begemotSnmpd, 156 oid_coldStart = OIDX_coldStart, 157 oid_authenticationFailure = OIDX_authenticationFailure; 158 159const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 160 161/* request id generator for traps */ 162u_int trap_reqid; 163 164/* help text */ 165static const char usgtxt[] = "\ 166Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 167Open Communication Systems (FhG Fokus). All rights reserved.\n\ 168usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 169 [-m variable=value] [-p file]\n\ 170options:\n\ 171 -d don't daemonize\n\ 172 -h print this info\n\ 173 -c file specify configuration file\n\ 174 -D options debugging options\n\ 175 -I path system include path\n\ 176 -l prefix default basename for pid and config file\n\ 177 -m var=val define variable\n\ 178 -p file specify pid file\n\ 179"; 180 181/* forward declarations */ 182static void snmp_printf_func(const char *fmt, ...); 183static void snmp_error_func(const char *err, ...); 184static void snmp_debug_func(const char *err, ...); 185static void asn_error_func(const struct asn_buf *b, const char *err, ...); 186 187/* 188 * Allocate rx/tx buffer. We allocate one byte more for rx. 189 */ 190void * 191buf_alloc(int tx) 192{ 193 void *buf; 194 195 if ((buf = malloc(tx ? snmpd.txbuf : (snmpd.rxbuf + 1))) == NULL) { 196 syslog(LOG_CRIT, "cannot allocate buffer"); 197 if (tx) 198 snmpd_stats.noTxbuf++; 199 else 200 snmpd_stats.noRxbuf++; 201 return (NULL); 202 } 203 return (buf); 204} 205 206/* 207 * Return the buffer size. (one more for RX). 208 */ 209size_t 210buf_size(int tx) 211{ 212 return (tx ? snmpd.txbuf : (snmpd.rxbuf + 1)); 213} 214 215/* 216 * Prepare a PDU for output 217 */ 218void 219snmp_output(struct snmp_v1_pdu *pdu, u_char *sndbuf, size_t *sndlen, 220 const char *dest) 221{ 222 struct asn_buf resp_b; 223 224 resp_b.asn_ptr = sndbuf; 225 resp_b.asn_len = snmpd.txbuf; 226 227 if (snmp_pdu_encode(pdu, &resp_b) != 0) { 228 syslog(LOG_ERR, "cannot encode message"); 229 abort(); 230 } 231 if (debug.dump_pdus) { 232 snmp_printf("%s <- ", dest); 233 snmp_pdu_dump(pdu); 234 } 235 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 236} 237 238/* 239 * Send a PDU to a given port 240 */ 241void 242snmp_send_port(const struct asn_oid *port, struct snmp_v1_pdu *pdu, 243 const struct sockaddr *addr, socklen_t addrlen) 244{ 245 struct snmp_port *p; 246 u_char *sndbuf; 247 size_t sndlen; 248 ssize_t len; 249 250 TAILQ_FOREACH(p, &snmp_port_list, link) 251 if (asn_compare_oid(port, &p->index) == 0) 252 break; 253 254 if (p == 0) 255 return; 256 257 if ((sndbuf = buf_alloc(1)) == NULL) 258 return; 259 260 snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 261 262 if ((len = sendto(p->sock, sndbuf, sndlen, 0, addr, addrlen)) == -1) 263 syslog(LOG_ERR, "sendto: %m"); 264 else if ((size_t)len != sndlen) 265 syslog(LOG_ERR, "sendto: short write %zu/%zu", 266 sndlen, (size_t)len); 267 268 free(sndbuf); 269} 270 271/* 272 * SNMP input. Start: decode the PDU, find the community. 273 */ 274enum snmpd_input_err 275snmp_input_start(const u_char *buf, size_t len, const char *source, 276 struct snmp_v1_pdu *pdu, int32_t *ip) 277{ 278 struct asn_buf b; 279 enum snmp_code code; 280 enum snmpd_input_err ret; 281 282 snmpd_stats.inPkts++; 283 284 b.asn_cptr = buf; 285 b.asn_len = len; 286 code = snmp_pdu_decode(&b, pdu, ip); 287 288 ret = SNMPD_INPUT_OK; 289 switch (code) { 290 291 case SNMP_CODE_FAILED: 292 snmpd_stats.inASNParseErrs++; 293 return (SNMPD_INPUT_FAILED); 294 295 case SNMP_CODE_BADVERS: 296 snmpd_stats.inBadVersions++; 297 return (SNMPD_INPUT_FAILED); 298 299 case SNMP_CODE_BADLEN: 300 if (pdu->type == SNMP_OP_SET) 301 ret = SNMPD_INPUT_VALBADLEN; 302 break; 303 304 case SNMP_CODE_OORANGE: 305 if (pdu->type == SNMP_OP_SET) 306 ret = SNMPD_INPUT_VALRANGE; 307 break; 308 309 case SNMP_CODE_BADENC: 310 if (pdu->type == SNMP_OP_SET) 311 ret = SNMPD_INPUT_VALBADENC; 312 break; 313 314 case SNMP_CODE_OK: 315 break; 316 } 317 318 if (debug.dump_pdus) { 319 snmp_printf("%s -> ", source); 320 snmp_pdu_dump(pdu); 321 } 322 323 /* 324 * Look, whether we know the community 325 */ 326 TAILQ_FOREACH(comm, &community_list, link) 327 if (comm->string != NULL && 328 strcmp(comm->string, pdu->community) == 0) 329 break; 330 331 if (comm == NULL) { 332 snmpd_stats.inBadCommunityNames++; 333 snmp_pdu_free(pdu); 334 if (snmpd.auth_traps) 335 snmp_send_trap(&oid_authenticationFailure, NULL); 336 return (SNMPD_INPUT_FAILED); 337 } 338 community = comm->value; 339 340 /* update uptime */ 341 this_tick = get_ticks(); 342 343 return (ret); 344} 345 346/* 347 * Will return only _OK or _FAILED 348 */ 349enum snmpd_input_err 350snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 351 u_char *sndbuf, size_t *sndlen, const char *source, 352 enum snmpd_input_err ierr, int32_t ivar, void *data) 353{ 354 struct snmp_pdu resp; 355 struct asn_buf resp_b, pdu_b; 356 enum snmp_ret ret; 357 358 resp_b.asn_ptr = sndbuf; 359 resp_b.asn_len = snmpd.txbuf; 360 361 pdu_b.asn_cptr = rcvbuf; 362 pdu_b.asn_len = rcvlen; 363 364 if (ierr != SNMPD_INPUT_OK) { 365 /* error decoding the input of a SET */ 366 if (pdu->version == SNMP_V1) 367 pdu->error_status = SNMP_ERR_BADVALUE; 368 else if (ierr == SNMPD_INPUT_VALBADLEN) 369 pdu->error_status = SNMP_ERR_WRONG_LENGTH; 370 else if (ierr == SNMPD_INPUT_VALRANGE) 371 pdu->error_status = SNMP_ERR_WRONG_VALUE; 372 else 373 pdu->error_status = SNMP_ERR_WRONG_ENCODING; 374 375 pdu->error_index = ivar; 376 377 if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 378 syslog(LOG_WARNING, "could not encode error response"); 379 snmpd_stats.silentDrops++; 380 return (SNMPD_INPUT_FAILED); 381 } 382 383 if (debug.dump_pdus) { 384 snmp_printf("%s <- ", source); 385 snmp_pdu_dump(pdu); 386 } 387 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 388 return (SNMPD_INPUT_OK); 389 } 390 391 switch (pdu->type) { 392 393 case SNMP_PDU_GET: 394 ret = snmp_get(pdu, &resp_b, &resp, data); 395 break; 396 397 case SNMP_PDU_GETNEXT: 398 ret = snmp_getnext(pdu, &resp_b, &resp, data); 399 break; 400 401 case SNMP_PDU_SET: 402 ret = snmp_set(pdu, &resp_b, &resp, data); 403 break; 404 405 case SNMP_PDU_GETBULK: 406 ret = snmp_getbulk(pdu, &resp_b, &resp, data); 407 break; 408 409 default: 410 ret = SNMP_RET_IGN; 411 break; 412 } 413 414 switch (ret) { 415 416 case SNMP_RET_OK: 417 /* normal return - send a response */ 418 if (debug.dump_pdus) { 419 snmp_printf("%s <- ", source); 420 snmp_pdu_dump(&resp); 421 } 422 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 423 snmp_pdu_free(&resp); 424 return (SNMPD_INPUT_OK); 425 426 case SNMP_RET_IGN: 427 /* error - send nothing */ 428 snmpd_stats.silentDrops++; 429 return (SNMPD_INPUT_FAILED); 430 431 case SNMP_RET_ERR: 432 /* error - send error response. The snmp routine has 433 * changed the error fields in the original message. */ 434 resp_b.asn_ptr = sndbuf; 435 resp_b.asn_len = snmpd.txbuf; 436 if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 437 syslog(LOG_WARNING, "could not encode error response"); 438 snmpd_stats.silentDrops++; 439 return (SNMPD_INPUT_FAILED); 440 } else { 441 if (debug.dump_pdus) { 442 snmp_printf("%s <- ", source); 443 snmp_pdu_dump(pdu); 444 } 445 *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 446 return (SNMPD_INPUT_OK); 447 } 448 } 449 abort(); 450} 451 452 453 454/* 455 * File descriptor support 456 */ 457static void 458input(evContext ctx __unused, void *uap, int fd, int mask __unused) 459{ 460 struct fdesc *f = uap; 461 462 (*f->func)(fd, f->udata); 463} 464 465void 466fd_suspend(void *p) 467{ 468 struct fdesc *f = p; 469 470 if (evTestID(f->id)) { 471 (void)evDeselectFD(evctx, f->id); 472 evInitID(&f->id); 473 } 474} 475 476int 477fd_resume(void *p) 478{ 479 struct fdesc *f = p; 480 int err; 481 482 if (evTestID(f->id)) 483 return (0); 484 if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 485 err = errno; 486 syslog(LOG_ERR, "select fd %d: %m", f->fd); 487 errno = err; 488 return (-1); 489 } 490 return (0); 491} 492 493void * 494fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 495{ 496 struct fdesc *f; 497 int err; 498 499 if ((f = malloc(sizeof(struct fdesc))) == NULL) { 500 err = errno; 501 syslog(LOG_ERR, "fd_select: %m"); 502 errno = err; 503 return (NULL); 504 } 505 f->fd = fd; 506 f->func = func; 507 f->udata = udata; 508 f->owner = mod; 509 evInitID(&f->id); 510 511 if (fd_resume(f)) { 512 err = errno; 513 free(f); 514 errno = err; 515 return (NULL); 516 } 517 518 LIST_INSERT_HEAD(&fdesc_list, f, link); 519 520 return (f); 521} 522 523void 524fd_deselect(void *p) 525{ 526 struct fdesc *f = p; 527 528 LIST_REMOVE(f, link); 529 fd_suspend(f); 530 free(f); 531} 532 533static void 534fd_flush(struct lmodule *mod) 535{ 536 struct fdesc *t, *t1; 537 538 t = LIST_FIRST(&fdesc_list); 539 while (t != NULL) { 540 t1 = LIST_NEXT(t, link); 541 if (t->owner == mod) 542 fd_deselect(t); 543 t = t1; 544 } 545 546} 547 548 549/* 550 * Input from UDP socket 551 */ 552static void 553do_input(int fd, const struct asn_oid *port_index, 554 struct sockaddr *ret, socklen_t *retlen) 555{ 556 u_char *resbuf, embuf[100]; 557 u_char *sndbuf; 558 size_t sndlen; 559 ssize_t len; 560 struct snmp_v1_pdu pdu; 561 enum snmpd_input_err ierr, ferr; 562 enum snmpd_proxy_err perr; 563 int32_t vi; 564 565 if ((resbuf = buf_alloc(0)) == NULL) { 566 (void)recvfrom(fd, embuf, sizeof(embuf), 0, ret, retlen); 567 return; 568 } 569 if ((len = recvfrom(fd, resbuf, buf_size(0), 0, ret, retlen)) == -1) { 570 free(resbuf); 571 return; 572 } 573 if (len == 0) { 574 free(resbuf); 575 return; 576 } 577 if ((size_t)len == buf_size(0)) { 578 free(resbuf); 579 snmpd_stats.silentDrops++; 580 snmpd_stats.inTooLong++; 581 return; 582 } 583 584 /* 585 * Handle input 586 */ 587 ierr = snmp_input_start(resbuf, (size_t)len, "SNMP", &pdu, &vi); 588 589 /* can't check for bad SET pdus here, because a proxy may have to 590 * check the access first. We don't want to return an error response 591 * to a proxy PDU with a wrong community */ 592 if (ierr == SNMPD_INPUT_FAILED) { 593 free(resbuf); 594 return; 595 } 596 597 /* 598 * If that is a module community and the module has a proxy function, 599 * the hand it over to the module. 600 */ 601 if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 602 perr = (*comm->owner->config->proxy)(&pdu, port_index, 603 ret, *retlen, ierr, vi); 604 605 switch (perr) { 606 607 case SNMPD_PROXY_OK: 608 free(resbuf); 609 return; 610 611 case SNMPD_PROXY_REJ: 612 break; 613 614 case SNMPD_PROXY_DROP: 615 free(resbuf); 616 snmp_pdu_free(&pdu); 617 snmpd_stats.proxyDrops++; 618 return; 619 620 case SNMPD_PROXY_BADCOMM: 621 free(resbuf); 622 snmp_pdu_free(&pdu); 623 snmpd_stats.inBadCommunityNames++; 624 if (snmpd.auth_traps) 625 snmp_send_trap(&oid_authenticationFailure, 626 NULL); 627 return; 628 629 case SNMPD_PROXY_BADCOMMUSE: 630 free(resbuf); 631 snmp_pdu_free(&pdu); 632 snmpd_stats.inBadCommunityUses++; 633 if (snmpd.auth_traps) 634 snmp_send_trap(&oid_authenticationFailure, 635 NULL); 636 return; 637 } 638 } 639 640 /* 641 * Check type 642 */ 643 if (pdu.type == SNMP_PDU_RESPONSE || 644 pdu.type == SNMP_PDU_TRAP || 645 pdu.type == SNMP_PDU_TRAP2) { 646 snmpd_stats.silentDrops++; 647 snmpd_stats.inBadPduTypes++; 648 snmp_pdu_free(&pdu); 649 free(resbuf); 650 return; 651 } 652 653 /* 654 * Check community 655 */ 656 if (community != COMM_WRITE && 657 (pdu.type == SNMP_PDU_SET || community != COMM_READ)) { 658 snmpd_stats.inBadCommunityUses++; 659 snmp_pdu_free(&pdu); 660 free(resbuf); 661 if (snmpd.auth_traps) 662 snmp_send_trap(&oid_authenticationFailure, NULL); 663 return; 664 } 665 666 /* 667 * Execute it. 668 */ 669 if ((sndbuf = buf_alloc(1)) == NULL) { 670 snmpd_stats.silentDrops++; 671 snmp_pdu_free(&pdu); 672 free(resbuf); 673 return; 674 } 675 ferr = snmp_input_finish(&pdu, resbuf, len, sndbuf, &sndlen, "SNMP", 676 ierr, vi, NULL); 677 678 if (ferr == SNMPD_INPUT_OK) { 679 if ((len = sendto(fd, sndbuf, sndlen, 0, ret, *retlen)) == -1) 680 syslog(LOG_ERR, "sendto: %m"); 681 else if ((size_t)len != sndlen) 682 syslog(LOG_ERR, "sendto: short write %zu/%zu", 683 sndlen, (size_t)len); 684 } 685 snmp_pdu_free(&pdu); 686 free(sndbuf); 687 free(resbuf); 688} 689 690static void 691ssock_input(int fd, void *udata) 692{ 693 struct snmp_port *p = udata; 694 695 p->retlen = sizeof(p->ret); 696 do_input(fd, &p->index, (struct sockaddr *)&p->ret, &p->retlen); 697} 698 699static void 700lsock_input(int fd, void *udata) 701{ 702 struct local_port *p = udata; 703 704 p->retlen = sizeof(p->ret); 705 do_input(fd, &p->index, (struct sockaddr *)&p->ret, &p->retlen); 706} 707 708 709/* 710 * Create a UDP socket and bind it to the given port 711 */ 712static int 713init_snmp(struct snmp_port *p) 714{ 715 struct sockaddr_in addr; 716 u_int32_t ip; 717 718 if ((p->sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 719 syslog(LOG_ERR, "creating UDP socket: %m"); 720 return (SNMP_ERR_RES_UNAVAIL); 721 } 722 ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) | 723 p->addr[3]; 724 memset(&addr, 0, sizeof(addr)); 725 addr.sin_addr.s_addr = htonl(ip); 726 addr.sin_port = htons(p->port); 727 addr.sin_family = AF_INET; 728 addr.sin_len = sizeof(addr); 729 if (bind(p->sock, (struct sockaddr *)&addr, sizeof(addr))) { 730 if (errno == EADDRNOTAVAIL) { 731 close(p->sock); 732 p->sock = -1; 733 return (SNMP_ERR_INCONS_NAME); 734 } 735 syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr), 736 p->port); 737 close(p->sock); 738 p->sock = -1; 739 return (SNMP_ERR_GENERR); 740 } 741 if ((p->id = fd_select(p->sock, ssock_input, p, NULL)) == NULL) { 742 close(p->sock); 743 p->sock = -1; 744 return (SNMP_ERR_GENERR); 745 } 746 return (SNMP_ERR_NOERROR); 747} 748 749 750/* 751 * Create a new SNMP Port object and start it, if we are not 752 * in initialisation mode. The arguments are in host byte order. 753 */ 754int 755open_snmp_port(u_int8_t *addr, u_int32_t port, struct snmp_port **pp) 756{ 757 struct snmp_port *snmp, *p; 758 int err; 759 760 if (port > 0xffff) 761 return (SNMP_ERR_NO_CREATION); 762 if ((snmp = malloc(sizeof(*snmp))) == NULL) 763 return (SNMP_ERR_GENERR); 764 snmp->addr[0] = addr[0]; 765 snmp->addr[1] = addr[1]; 766 snmp->addr[2] = addr[2]; 767 snmp->addr[3] = addr[3]; 768 snmp->port = port; 769 snmp->sock = -1; 770 snmp->id = NULL; 771 snmp->index.len = 5; 772 snmp->index.subs[0] = addr[0]; 773 snmp->index.subs[1] = addr[1]; 774 snmp->index.subs[2] = addr[2]; 775 snmp->index.subs[3] = addr[3]; 776 snmp->index.subs[4] = port; 777 778 /* 779 * Insert it into the right place 780 */ 781 TAILQ_FOREACH(p, &snmp_port_list, link) { 782 if (asn_compare_oid(&p->index, &snmp->index) > 0) { 783 TAILQ_INSERT_BEFORE(p, snmp, link); 784 break; 785 } 786 } 787 if (p == NULL) 788 TAILQ_INSERT_TAIL(&snmp_port_list, snmp, link); 789 790 if (community != COMM_INITIALIZE && 791 (err = init_snmp(snmp)) != SNMP_ERR_NOERROR) { 792 TAILQ_REMOVE(&snmp_port_list, snmp, link); 793 free(snmp); 794 return (err); 795 } 796 *pp = snmp; 797 return (SNMP_ERR_NOERROR); 798} 799 800/* 801 * Close an SNMP port 802 */ 803void 804close_snmp_port(struct snmp_port *snmp) 805{ 806 if (snmp->id != NULL) 807 fd_deselect(snmp->id); 808 if (snmp->sock >= 0) 809 (void)close(snmp->sock); 810 811 TAILQ_REMOVE(&snmp_port_list, snmp, link); 812 free(snmp); 813} 814 815/* 816 * Create a local socket 817 */ 818static int 819init_local(struct local_port *p) 820{ 821 struct sockaddr_un sa; 822 823 if ((p->sock = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) { 824 syslog(LOG_ERR, "creating local socket: %m"); 825 return (SNMP_ERR_RES_UNAVAIL); 826 } 827 strcpy(sa.sun_path, p->name); 828 sa.sun_family = AF_LOCAL; 829 sa.sun_len = strlen(p->name) + offsetof(struct sockaddr_un, sun_path); 830 831 (void)remove(p->name); 832 833 if (bind(p->sock, (struct sockaddr *)&sa, sizeof(sa))) { 834 if (errno == EADDRNOTAVAIL) { 835 close(p->sock); 836 p->sock = -1; 837 return (SNMP_ERR_INCONS_NAME); 838 } 839 syslog(LOG_ERR, "bind: %s %m", p->name); 840 close(p->sock); 841 p->sock = -1; 842 return (SNMP_ERR_GENERR); 843 } 844 if (chmod(p->name, 0666) == -1) 845 syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name); 846 if ((p->id = fd_select(p->sock, lsock_input, p, NULL)) == NULL) { 847 (void)remove(p->name); 848 close(p->sock); 849 p->sock = -1; 850 return (SNMP_ERR_GENERR); 851 } 852 return (SNMP_ERR_NOERROR); 853} 854 855 856/* 857 * Open a local port 858 */ 859int 860open_local_port(u_char *name, size_t namelen, struct local_port **pp) 861{ 862 struct local_port *port, *p; 863 size_t u; 864 int err; 865 struct sockaddr_un sa; 866 867 if (namelen == 0 || namelen + 1 > sizeof(sa.sun_path)) { 868 free(name); 869 return (SNMP_ERR_BADVALUE); 870 } 871 if ((port = malloc(sizeof(*port))) == NULL) { 872 free(name); 873 return (SNMP_ERR_GENERR); 874 } 875 if ((port->name = malloc(namelen + 1)) == NULL) { 876 free(name); 877 free(port); 878 return (SNMP_ERR_GENERR); 879 } 880 strncpy(port->name, name, namelen); 881 port->name[namelen] = '\0'; 882 883 port->sock = -1; 884 port->id = NULL; 885 port->index.len = namelen + 1; 886 port->index.subs[0] = namelen; 887 for (u = 0; u < namelen; u++) 888 port->index.subs[u + 1] = name[u]; 889 890 /* 891 * Insert it into the right place 892 */ 893 TAILQ_FOREACH(p, &local_port_list, link) { 894 if (asn_compare_oid(&p->index, &port->index) > 0) { 895 TAILQ_INSERT_BEFORE(p, port, link); 896 break; 897 } 898 } 899 if (p == NULL) 900 TAILQ_INSERT_TAIL(&local_port_list, port, link); 901 902 if (community != COMM_INITIALIZE && 903 (err = init_local(port)) != SNMP_ERR_NOERROR) { 904 TAILQ_REMOVE(&local_port_list, port, link); 905 free(port->name); 906 free(port); 907 return (err); 908 } 909 910 *pp = p; 911 912 return (SNMP_ERR_NOERROR); 913} 914 915/* 916 * Close a local port 917 */ 918void 919close_local_port(struct local_port *port) 920{ 921 if (port->id != NULL) 922 fd_deselect(port->id); 923 if (port->sock >= 0) 924 (void)close(port->sock); 925 (void)remove(port->name); 926 927 TAILQ_REMOVE(&local_port_list, port, link); 928 free(port->name); 929 free(port); 930} 931 932/* 933 * Dump internal state. 934 */ 935static void 936info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 937{ 938 struct lmodule *m; 939 u_int i; 940 char buf[10000]; 941 942 syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 943 for (i = 0; i < tree_size; i++) { 944 switch (tree[i].type) { 945 946 case SNMP_NODE_LEAF: 947 sprintf(buf, "LEAF: %s %s", tree[i].name, 948 asn_oid2str(&tree[i].oid)); 949 break; 950 951 case SNMP_NODE_COLUMN: 952 sprintf(buf, "COL: %s %s", tree[i].name, 953 asn_oid2str(&tree[i].oid)); 954 break; 955 } 956 syslog(LOG_DEBUG, "%s", buf); 957 } 958 959 TAILQ_FOREACH(m, &lmodules, link) 960 if (m->config->dump) 961 (*m->config->dump)(); 962} 963 964/* 965 * Re-read configuration 966 */ 967static void 968config_func(evContext ctx __unused, void *uap __unused, 969 const void *tag __unused) 970{ 971 struct lmodule *m; 972 973 if (read_config(config_file, NULL)) { 974 syslog(LOG_ERR, "error reading config file '%s'", config_file); 975 return; 976 } 977 TAILQ_FOREACH(m, &lmodules, link) 978 if (m->config->config) 979 (*m->config->config)(); 980} 981 982/* 983 * On USR1 dump actual configuration. 984 */ 985static void 986onusr1(int s __unused) 987{ 988 work |= WORK_DOINFO; 989} 990static void 991onhup(int s __unused) 992{ 993 work |= WORK_RECONFIG; 994} 995 996static void 997onterm(int s __unused) 998{ 999 struct local_port *p; 1000 1001 TAILQ_FOREACH(p, &local_port_list, link) 1002 (void)remove(p->name); 1003 1004 exit(0); 1005} 1006 1007 1008static void 1009init_sigs(void) 1010{ 1011 struct sigaction sa; 1012 1013 sa.sa_handler = onusr1; 1014 sa.sa_flags = SA_RESTART; 1015 sigemptyset(&sa.sa_mask); 1016 if (sigaction(SIGUSR1, &sa, NULL)) { 1017 syslog(LOG_ERR, "sigaction: %m"); 1018 exit(1); 1019 } 1020 1021 sa.sa_handler = onhup; 1022 if (sigaction(SIGHUP, &sa, NULL)) { 1023 syslog(LOG_ERR, "sigaction: %m"); 1024 exit(1); 1025 } 1026 1027 sa.sa_handler = onterm; 1028 sa.sa_flags = 0; 1029 sigemptyset(&sa.sa_mask); 1030 if (sigaction(SIGTERM, &sa, NULL)) { 1031 syslog(LOG_ERR, "sigaction: %m"); 1032 exit(1); 1033 } 1034 if (sigaction(SIGINT, &sa, NULL)) { 1035 syslog(LOG_ERR, "sigaction: %m"); 1036 exit(1); 1037 } 1038} 1039 1040static void 1041block_sigs(void) 1042{ 1043 sigset_t set; 1044 1045 sigfillset(&set); 1046 if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1047 syslog(LOG_ERR, "SIG_BLOCK: %m"); 1048 exit(1); 1049 } 1050} 1051static void 1052unblock_sigs(void) 1053{ 1054 if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1055 syslog(LOG_ERR, "SIG_SETMASK: %m"); 1056 exit(1); 1057 } 1058} 1059 1060/* 1061 * Shut down 1062 */ 1063static void 1064term(void) 1065{ 1066 (void)unlink(pid_file); 1067} 1068 1069/* 1070 * Define a macro from the command line 1071 */ 1072static void 1073do_macro(char *arg) 1074{ 1075 char *eq; 1076 int err; 1077 1078 if ((eq = strchr(arg, '=')) == NULL) 1079 err = define_macro(arg, ""); 1080 else { 1081 *eq++ = '\0'; 1082 err = define_macro(arg, eq); 1083 } 1084 if (err == -1) { 1085 syslog(LOG_ERR, "cannot save macro: %m"); 1086 exit(1); 1087 } 1088} 1089 1090/* 1091 * Re-implement getsubopt from scratch, because the second argument is broken 1092 * and will not compile with WARNS=5. 1093 */ 1094static int 1095getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1096{ 1097 static const char *const delim = ",\t "; 1098 u_int i; 1099 char *ptr; 1100 1101 *optp = NULL; 1102 1103 /* skip leading junk */ 1104 for (ptr = *arg; *ptr != '\0'; ptr++) 1105 if (strchr(delim, *ptr) == NULL) 1106 break; 1107 if (*ptr == '\0') { 1108 *arg = ptr; 1109 return (-1); 1110 } 1111 *optp = ptr; 1112 1113 /* find the end of the option */ 1114 while (*++ptr != '\0') 1115 if (strchr(delim, *ptr) != NULL || *ptr == '=') 1116 break; 1117 1118 if (*ptr != '\0') { 1119 if (*ptr == '=') { 1120 *ptr++ = '\0'; 1121 *valp = ptr; 1122 while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1123 ptr++; 1124 if (*ptr != '\0') 1125 *ptr++ = '\0'; 1126 } else 1127 *ptr++ = '\0'; 1128 } 1129 1130 *arg = ptr; 1131 1132 for (i = 0; *options != NULL; options++, i++) 1133 if (strcmp(suboptarg, *options) == 0) 1134 return (i); 1135 return (-1); 1136} 1137 1138int 1139main(int argc, char *argv[]) 1140{ 1141 int opt; 1142 FILE *fp; 1143 int background = 1; 1144 struct snmp_port *p; 1145 struct local_port *pl; 1146 const char *prefix = "snmpd"; 1147 struct lmodule *m; 1148 char *value, *option; 1149 1150#define DBG_DUMP 0 1151#define DBG_EVENTS 1 1152#define DBG_TRACE 2 1153 static const char *const debug_opts[] = { 1154 "dump", 1155 "events", 1156 "trace", 1157 NULL 1158 }; 1159 1160 snmp_printf = snmp_printf_func; 1161 snmp_error = snmp_error_func; 1162 snmp_debug = snmp_debug_func; 1163 asn_error = asn_error_func; 1164 1165 while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1166 switch (opt) { 1167 1168 case 'c': 1169 strlcpy(config_file, optarg, sizeof(config_file)); 1170 break; 1171 1172 case 'd': 1173 background = 0; 1174 break; 1175 1176 case 'D': 1177 while (*optarg) { 1178 switch (getsubopt1(&optarg, debug_opts, 1179 &value, &option)) { 1180 1181 case DBG_DUMP: 1182 debug.dump_pdus = 1; 1183 break; 1184 1185 case DBG_EVENTS: 1186 debug.evdebug++; 1187 break; 1188 1189 case DBG_TRACE: 1190 if (value == NULL) 1191 syslog(LOG_ERR, 1192 "no value for 'trace'"); 1193 snmp_trace = strtoul(value, NULL, 0); 1194 break; 1195 1196 case -1: 1197 if (suboptarg) 1198 syslog(LOG_ERR, 1199 "unknown debug flag '%s'", 1200 option); 1201 else 1202 syslog(LOG_ERR, 1203 "missing debug flag"); 1204 break; 1205 } 1206 } 1207 break; 1208 1209 case 'h': 1210 fprintf(stderr, "%s", usgtxt); 1211 exit(0); 1212 1213 case 'I': 1214 syspath = optarg; 1215 break; 1216 1217 case 'l': 1218 prefix = optarg; 1219 break; 1220 1221 case 'm': 1222 do_macro(optarg); 1223 break; 1224 1225 case 'p': 1226 strlcpy(pid_file, optarg, sizeof(pid_file)); 1227 break; 1228 } 1229 1230 openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1231 setlogmask(LOG_UPTO(debug.logpri - 1)); 1232 1233 if (background && daemon(0, 0) < 0) { 1234 syslog(LOG_ERR, "daemon: %m"); 1235 exit(1); 1236 } 1237 1238 argc -= optind; 1239 argv += optind; 1240 1241 progargs = argv; 1242 nprogargs = argc; 1243 1244 srandomdev(); 1245 1246 snmp_serial_no = random(); 1247 1248 /* 1249 * Initialize the tree. 1250 */ 1251 if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1252 syslog(LOG_ERR, "%m"); 1253 exit(1); 1254 } 1255 memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1256 tree_size = CTREE_SIZE; 1257 1258 /* 1259 * Get standard communities 1260 */ 1261 (void)comm_define(1, "SNMP read", NULL, "public"); 1262 (void)comm_define(2, "SNMP write", NULL, "public"); 1263 community = COMM_INITIALIZE; 1264 1265 trap_reqid = reqid_allocate(512, NULL); 1266 1267 if (config_file[0] == '\0') 1268 snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1269 1270 init_actvals(); 1271 if (read_config(config_file, NULL)) { 1272 syslog(LOG_ERR, "error in config file"); 1273 exit(1); 1274 } 1275 1276 if (evCreate(&evctx)) { 1277 syslog(LOG_ERR, "evCreate: %m"); 1278 exit(1); 1279 } 1280 if (debug.evdebug > 0) 1281 evSetDebug(evctx, 10, stderr); 1282 1283 TAILQ_FOREACH(p, &snmp_port_list, link) 1284 (void)init_snmp(p); 1285 TAILQ_FOREACH(pl, &local_port_list, link) 1286 (void)init_local(pl); 1287 1288 init_sigs(); 1289 1290 if (pid_file[0] == '\0') 1291 snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1292 1293 if ((fp = fopen(pid_file, "w")) != NULL) { 1294 fprintf(fp, "%u", getpid()); 1295 fclose(fp); 1296 atexit(term); 1297 } 1298 1299 start_tick = get_ticks(); 1300 this_tick = get_ticks(); 1301 1302 if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1303 NULL) == 0) { 1304 syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1305 exit(1); 1306 } 1307 if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1308 NULL) == 0) { 1309 syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1310 exit(1); 1311 } 1312 1313 snmp_send_trap(&oid_coldStart, NULL); 1314 1315 while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1316 m->flags &= ~LM_ONSTARTLIST; 1317 TAILQ_REMOVE(&modules_start, m, start); 1318 lm_start(m); 1319 } 1320 1321 for (;;) { 1322 evEvent event; 1323 struct lmodule *mod; 1324 1325 TAILQ_FOREACH(mod, &lmodules, link) 1326 if (mod->config->idle != NULL) 1327 (*mod->config->idle)(); 1328 1329 if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1330 if (evDispatch(evctx, event)) 1331 syslog(LOG_ERR, "evDispatch: %m"); 1332 } else if (errno != EINTR) { 1333 syslog(LOG_ERR, "evGetNext: %m"); 1334 exit(1); 1335 } 1336 1337 if (work != 0) { 1338 block_sigs(); 1339 if (work & WORK_DOINFO) { 1340 if (evWaitFor(evctx, &work, info_func, 1341 NULL, NULL) == -1) { 1342 syslog(LOG_ERR, "evWaitFor: %m"); 1343 exit(1); 1344 } 1345 } 1346 if (work & WORK_RECONFIG) { 1347 if (evWaitFor(evctx, &work, config_func, 1348 NULL, NULL) == -1) { 1349 syslog(LOG_ERR, "evWaitFor: %m"); 1350 exit(1); 1351 } 1352 } 1353 work = 0; 1354 unblock_sigs(); 1355 if (evDo(evctx, &work) == -1) { 1356 syslog(LOG_ERR, "evDo: %m"); 1357 exit(1); 1358 } 1359 } 1360 } 1361 1362 return (0); 1363} 1364 1365 1366u_int32_t 1367get_ticks() 1368{ 1369 struct timeval tv; 1370 u_int32_t ret; 1371 1372 if (gettimeofday(&tv, NULL)) 1373 abort(); 1374 ret = tv.tv_sec * 100 + tv.tv_usec / 10000; 1375 return (ret); 1376} 1377/* 1378 * Timer support 1379 */ 1380static void 1381tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1382 struct timespec inter __unused) 1383{ 1384 struct timer *tp = uap; 1385 1386 LIST_REMOVE(tp, link); 1387 tp->func(tp->udata); 1388 free(tp); 1389} 1390 1391/* 1392 * Start a timer 1393 */ 1394void * 1395timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1396{ 1397 struct timer *tp; 1398 struct timespec due; 1399 1400 if ((tp = malloc(sizeof(struct timer))) == NULL) { 1401 syslog(LOG_CRIT, "out of memory for timer"); 1402 exit(1); 1403 } 1404 due = evAddTime(evNowTime(), 1405 evConsTime(ticks / 100, (ticks % 100) * 10000)); 1406 1407 tp->udata = udata; 1408 tp->owner = mod; 1409 tp->func = func; 1410 1411 LIST_INSERT_HEAD(&timer_list, tp, link); 1412 1413 if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1414 == -1) { 1415 syslog(LOG_ERR, "cannot set timer: %m"); 1416 exit(1); 1417 } 1418 return (tp); 1419} 1420 1421void 1422timer_stop(void *p) 1423{ 1424 struct timer *tp = p; 1425 1426 LIST_REMOVE(tp, link); 1427 if (evClearTimer(evctx, tp->id) == -1) { 1428 syslog(LOG_ERR, "cannot stop timer: %m"); 1429 exit(1); 1430 } 1431 free(p); 1432} 1433 1434static void 1435timer_flush(struct lmodule *mod) 1436{ 1437 struct timer *t, *t1; 1438 1439 t = LIST_FIRST(&timer_list); 1440 while (t != NULL) { 1441 t1 = LIST_NEXT(t, link); 1442 if (t->owner == mod) 1443 timer_stop(t); 1444 t = t1; 1445 } 1446} 1447 1448static void 1449snmp_printf_func(const char *fmt, ...) 1450{ 1451 va_list ap; 1452 static char *pend = NULL; 1453 char *ret, *new; 1454 1455 va_start(ap, fmt); 1456 vasprintf(&ret, fmt, ap); 1457 va_end(ap); 1458 1459 if (ret == NULL) 1460 return; 1461 if (pend != NULL) { 1462 if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1463 == NULL) { 1464 free(ret); 1465 return; 1466 } 1467 pend = new; 1468 strcat(pend, ret); 1469 free(ret); 1470 } else 1471 pend = ret; 1472 1473 while ((ret = strchr(pend, '\n')) != NULL) { 1474 *ret = '\0'; 1475 syslog(LOG_DEBUG, "%s", pend); 1476 if (strlen(ret + 1) == 0) { 1477 free(pend); 1478 pend = NULL; 1479 break; 1480 } 1481 strcpy(pend, ret + 1); 1482 } 1483} 1484 1485static void 1486snmp_error_func(const char *err, ...) 1487{ 1488 char errbuf[1000]; 1489 va_list ap; 1490 1491 va_start(ap, err); 1492 snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1493 vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1494 err, ap); 1495 va_end(ap); 1496 1497 syslog(LOG_ERR, "%s", errbuf); 1498} 1499 1500static void 1501snmp_debug_func(const char *err, ...) 1502{ 1503 char errbuf[1000]; 1504 va_list ap; 1505 1506 va_start(ap, err); 1507 snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1508 vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1509 err, ap); 1510 va_end(ap); 1511 1512 syslog(LOG_DEBUG, "%s", errbuf); 1513} 1514 1515static void 1516asn_error_func(const struct asn_buf *b, const char *err, ...) 1517{ 1518 char errbuf[1000]; 1519 va_list ap; 1520 u_int i; 1521 1522 va_start(ap, err); 1523 snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 1524 vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1525 err, ap); 1526 va_end(ap); 1527 1528 if (b != NULL) { 1529 snprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1530 " at"); 1531 for (i = 0; b->asn_len > i; i++) 1532 snprintf(errbuf+strlen(errbuf), 1533 sizeof(errbuf)-strlen(errbuf), " %02x", b->asn_cptr[i]); 1534 } 1535 1536 syslog(LOG_ERR, "%s", errbuf); 1537} 1538 1539/* 1540 * Create a new community 1541 */ 1542u_int 1543comm_define(u_int priv, const char *descr, struct lmodule *owner, 1544 const char *str) 1545{ 1546 struct community *c, *p; 1547 u_int ncomm; 1548 1549 /* generate an identifier */ 1550 do { 1551 if ((ncomm = next_community_index++) == UINT_MAX) 1552 next_community_index = 1; 1553 TAILQ_FOREACH(c, &community_list, link) 1554 if (c->value == ncomm) 1555 break; 1556 } while (c != NULL); 1557 1558 if ((c = malloc(sizeof(struct community))) == NULL) { 1559 syslog(LOG_ERR, "comm_define: %m"); 1560 return (0); 1561 } 1562 c->owner = owner; 1563 c->value = ncomm; 1564 c->descr = descr; 1565 c->string = NULL; 1566 c->private = priv; 1567 1568 if (str != NULL) { 1569 if((c->string = malloc(strlen(str)+1)) == NULL) { 1570 free(c); 1571 return (0); 1572 } 1573 strcpy(c->string, str); 1574 } 1575 1576 /* make index */ 1577 if (c->owner == NULL) { 1578 c->index.len = 1; 1579 c->index.subs[0] = 0; 1580 } else { 1581 c->index = c->owner->index; 1582 } 1583 c->index.subs[c->index.len++] = c->private; 1584 1585 /* 1586 * Insert ordered 1587 */ 1588 TAILQ_FOREACH(p, &community_list, link) { 1589 if (asn_compare_oid(&p->index, &c->index) > 0) { 1590 TAILQ_INSERT_BEFORE(p, c, link); 1591 break; 1592 } 1593 } 1594 if (p == NULL) 1595 TAILQ_INSERT_TAIL(&community_list, c, link); 1596 return (c->value); 1597} 1598 1599const char * 1600comm_string(u_int ncomm) 1601{ 1602 struct community *p; 1603 1604 TAILQ_FOREACH(p, &community_list, link) 1605 if (p->value == ncomm) 1606 return (p->string); 1607 return (NULL); 1608} 1609 1610/* 1611 * Delete all communities allocated by a module 1612 */ 1613static void 1614comm_flush(struct lmodule *mod) 1615{ 1616 struct community *p, *p1; 1617 1618 p = TAILQ_FIRST(&community_list); 1619 while (p != NULL) { 1620 p1 = TAILQ_NEXT(p, link); 1621 if (p->owner == mod) { 1622 free(p->string); 1623 TAILQ_REMOVE(&community_list, p, link); 1624 free(p); 1625 } 1626 p = p1; 1627 } 1628} 1629 1630/* 1631 * Request ID handling. 1632 * 1633 * Allocate a new range of request ids. Use a first fit algorithm. 1634 */ 1635u_int 1636reqid_allocate(int size, struct lmodule *mod) 1637{ 1638 u_int type; 1639 struct idrange *r, *r1; 1640 1641 if (size <= 0 || size > INT32_MAX) { 1642 syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1643 return (0); 1644 } 1645 /* allocate a type id */ 1646 do { 1647 if ((type = next_idrange++) == UINT_MAX) 1648 next_idrange = 1; 1649 TAILQ_FOREACH(r, &idrange_list, link) 1650 if (r->type == type) 1651 break; 1652 } while(r != NULL); 1653 1654 /* find a range */ 1655 if (TAILQ_EMPTY(&idrange_list)) 1656 r = NULL; 1657 else { 1658 r = TAILQ_FIRST(&idrange_list); 1659 if (r->base < size) { 1660 while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1661 if (r1->base - (r->base + r->size) >= size) 1662 break; 1663 r = r1; 1664 } 1665 r = r1; 1666 } 1667 if (r == NULL) { 1668 r1 = TAILQ_LAST(&idrange_list, idrange_list); 1669 if (INT32_MAX - size + 1 < r1->base + r1->size) { 1670 syslog(LOG_ERR, "out of id ranges (%u)", size); 1671 return (0); 1672 } 1673 } 1674 } 1675 1676 /* allocate structure */ 1677 if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 1678 syslog(LOG_ERR, "%s: %m", __FUNCTION__); 1679 return (0); 1680 } 1681 1682 r1->type = type; 1683 r1->size = size; 1684 r1->owner = mod; 1685 if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 1686 r1->base = 0; 1687 TAILQ_INSERT_HEAD(&idrange_list, r1, link); 1688 } else if (r == NULL) { 1689 r = TAILQ_LAST(&idrange_list, idrange_list); 1690 r1->base = r->base + r->size; 1691 TAILQ_INSERT_TAIL(&idrange_list, r1, link); 1692 } else { 1693 r = TAILQ_PREV(r, idrange_list, link); 1694 r1->base = r->base + r->size; 1695 TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 1696 } 1697 r1->next = r1->base; 1698 1699 return (type); 1700} 1701 1702int32_t 1703reqid_next(u_int type) 1704{ 1705 struct idrange *r; 1706 int32_t id; 1707 1708 TAILQ_FOREACH(r, &idrange_list, link) 1709 if (r->type == type) 1710 break; 1711 if (r == NULL) { 1712 syslog(LOG_CRIT, "wrong idrange type"); 1713 abort(); 1714 } 1715 if ((id = r->next++) == r->base + (r->size - 1)) 1716 r->next = r->base; 1717 return (id); 1718} 1719 1720int32_t 1721reqid_base(u_int type) 1722{ 1723 struct idrange *r; 1724 1725 TAILQ_FOREACH(r, &idrange_list, link) 1726 if (r->type == type) 1727 return (r->base); 1728 syslog(LOG_CRIT, "wrong idrange type"); 1729 abort(); 1730} 1731 1732u_int 1733reqid_type(int32_t reqid) 1734{ 1735 struct idrange *r; 1736 1737 TAILQ_FOREACH(r, &idrange_list, link) 1738 if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 1739 return (r->type); 1740 return (0); 1741} 1742 1743int 1744reqid_istype(int32_t reqid, u_int type) 1745{ 1746 return (reqid_type(reqid) == type); 1747} 1748 1749/* 1750 * Delete all communities allocated by a module 1751 */ 1752static void 1753reqid_flush(struct lmodule *mod) 1754{ 1755 struct idrange *p, *p1; 1756 1757 p = TAILQ_FIRST(&idrange_list); 1758 while (p != NULL) { 1759 p1 = TAILQ_NEXT(p, link); 1760 if (p->owner == mod) { 1761 TAILQ_REMOVE(&idrange_list, p, link); 1762 free(p); 1763 } 1764 p = p1; 1765 } 1766} 1767 1768/* 1769 * Merge the given tree for the given module into the main tree. 1770 */ 1771static int 1772compare_node(const void *v1, const void *v2) 1773{ 1774 const struct snmp_node *n1 = v1; 1775 const struct snmp_node *n2 = v2; 1776 1777 return (asn_compare_oid(&n1->oid, &n2->oid)); 1778} 1779static int 1780tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 1781{ 1782 struct snmp_node *xtree; 1783 u_int i; 1784 1785 xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 1786 if (xtree == NULL) { 1787 syslog(LOG_ERR, "lm_load: %m"); 1788 return (-1); 1789 } 1790 tree = xtree; 1791 memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 1792 1793 for (i = 0; i < nsize; i++) 1794 tree[tree_size + i].data = mod; 1795 1796 tree_size += nsize; 1797 1798 qsort(tree, tree_size, sizeof(tree[0]), compare_node); 1799 1800 return (0); 1801} 1802 1803/* 1804 * Remove all nodes belonging to the loadable module 1805 */ 1806static void 1807tree_unmerge(struct lmodule *mod) 1808{ 1809 u_int s, d; 1810 1811 for(s = d = 0; s < tree_size; s++) 1812 if (tree[s].data != mod) { 1813 if (s != d) 1814 tree[d] = tree[s]; 1815 d++; 1816 } 1817 tree_size = d; 1818} 1819 1820/* 1821 * Loadable modules 1822 */ 1823struct lmodule * 1824lm_load(const char *path, const char *section) 1825{ 1826 struct lmodule *m; 1827 int err; 1828 int i; 1829 char *av[MAX_MOD_ARGS + 1]; 1830 int ac; 1831 u_int u; 1832 1833 if ((m = malloc(sizeof(*m))) == NULL) { 1834 syslog(LOG_ERR, "lm_load: %m"); 1835 return (NULL); 1836 } 1837 m->handle = NULL; 1838 m->flags = 0; 1839 strcpy(m->section, section); 1840 1841 if ((m->path = malloc(strlen(path) + 1)) == NULL) { 1842 syslog(LOG_ERR, "lm_load: %m"); 1843 goto err; 1844 } 1845 strcpy(m->path, path); 1846 1847 /* 1848 * Make index 1849 */ 1850 m->index.subs[0] = strlen(section); 1851 m->index.len = m->index.subs[0] + 1; 1852 for (u = 0; u < m->index.subs[0]; u++) 1853 m->index.subs[u + 1] = section[u]; 1854 1855 /* 1856 * Load the object file and locate the config structure 1857 */ 1858 if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 1859 syslog(LOG_ERR, "lm_load: open %s", dlerror()); 1860 goto err; 1861 } 1862 1863 if ((m->config = dlsym(m->handle, "config")) == NULL) { 1864 syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 1865 goto err; 1866 } 1867 1868 /* 1869 * Insert it into the right place 1870 */ 1871 INSERT_OBJECT_OID(m, &lmodules); 1872 1873 /* preserve order */ 1874 if (community == COMM_INITIALIZE) { 1875 m->flags |= LM_ONSTARTLIST; 1876 TAILQ_INSERT_TAIL(&modules_start, m, start); 1877 } 1878 1879 /* 1880 * make the argument vector. 1881 */ 1882 ac = 0; 1883 for (i = 0; i < nprogargs; i++) { 1884 if (strlen(progargs[i]) >= strlen(section) + 1 && 1885 strncmp(progargs[i], section, strlen(section)) == 0 && 1886 progargs[i][strlen(section)] == ':') { 1887 if (ac == MAX_MOD_ARGS) { 1888 syslog(LOG_WARNING, "too many arguments for " 1889 "module '%s", section); 1890 break; 1891 } 1892 av[ac++] = &progargs[i][strlen(section)+1]; 1893 } 1894 } 1895 av[ac] = NULL; 1896 1897 /* 1898 * Run the initialisation function 1899 */ 1900 if ((err = (*m->config->init)(m, ac, av)) != 0) { 1901 syslog(LOG_ERR, "lm_load: init failed: %d", err); 1902 TAILQ_REMOVE(&lmodules, m, link); 1903 goto err; 1904 } 1905 1906 return (m); 1907 1908 err: 1909 if (m->handle) 1910 dlclose(m->handle); 1911 free(m->path); 1912 free(m); 1913 return (NULL); 1914} 1915 1916/* 1917 * Start a module 1918 */ 1919void 1920lm_start(struct lmodule *mod) 1921{ 1922 const struct lmodule *m; 1923 1924 /* 1925 * Merge tree. If this fails, unload the module. 1926 */ 1927 if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 1928 lm_unload(mod); 1929 return; 1930 } 1931 1932 /* 1933 * Read configuration 1934 */ 1935 if (read_config(config_file, mod)) { 1936 syslog(LOG_ERR, "error in config file"); 1937 lm_unload(mod); 1938 return; 1939 } 1940 if (mod->config->start) 1941 (*mod->config->start)(); 1942 1943 mod->flags |= LM_STARTED; 1944 1945 /* 1946 * Inform other modules 1947 */ 1948 TAILQ_FOREACH(m, &lmodules, link) 1949 if (m->config->loading) 1950 (*m->config->loading)(mod, 1); 1951} 1952 1953 1954/* 1955 * Unload a module. 1956 */ 1957void 1958lm_unload(struct lmodule *m) 1959{ 1960 int err; 1961 const struct lmodule *mod; 1962 1963 TAILQ_REMOVE(&lmodules, m, link); 1964 if (m->flags & LM_ONSTARTLIST) 1965 TAILQ_REMOVE(&modules_start, m, start); 1966 tree_unmerge(m); 1967 1968 if ((m->flags & LM_STARTED) && m->config->fini && 1969 (err = (*m->config->fini)()) != 0) 1970 syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 1971 1972 comm_flush(m); 1973 reqid_flush(m); 1974 timer_flush(m); 1975 fd_flush(m); 1976 1977 dlclose(m->handle); 1978 free(m->path); 1979 1980 /* 1981 * Inform other modules 1982 */ 1983 TAILQ_FOREACH(mod, &lmodules, link) 1984 if (mod->config->loading) 1985 (*mod->config->loading)(m, 0); 1986 1987 free(m); 1988} 1989 1990/* 1991 * Register an object resource and return the index (or 0 on failures) 1992 */ 1993u_int 1994or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 1995{ 1996 struct objres *objres, *or1; 1997 u_int idx; 1998 1999 /* find a free index */ 2000 idx = 1; 2001 for (objres = TAILQ_FIRST(&objres_list); 2002 objres != NULL; 2003 objres = TAILQ_NEXT(objres, link)) { 2004 if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2005 or1->index > objres->index + 1) { 2006 idx = objres->index + 1; 2007 break; 2008 } 2009 } 2010 2011 if ((objres = malloc(sizeof(*objres))) == NULL) 2012 return (0); 2013 2014 objres->index = idx; 2015 objres->oid = *or; 2016 strlcpy(objres->descr, descr, sizeof(objres->descr)); 2017 objres->uptime = get_ticks() - start_tick; 2018 objres->module = mod; 2019 2020 INSERT_OBJECT_INT(objres, &objres_list); 2021 2022 systemg.or_last_change = objres->uptime; 2023 2024 return (idx); 2025} 2026 2027void 2028or_unregister(u_int idx) 2029{ 2030 struct objres *objres; 2031 2032 TAILQ_FOREACH(objres, &objres_list, link) 2033 if (objres->index == idx) { 2034 TAILQ_REMOVE(&objres_list, objres, link); 2035 free(objres); 2036 return; 2037 } 2038} 2039