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