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