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 64 uint64_t this_tick; /* start of processing of current packet (absolute) */ 65 uint64_t start_tick; /* start of processing */ 66 67 struct 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 }; 74 struct debug debug = { 75 0, /* dump_pdus */ 76 LOG_DEBUG, /* log_pri */ 77 0, /* evdebug */ 78 }; 79 80 struct 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 }; 88 struct snmpd_stats snmpd_stats; 89 90 /* snmpSerialNo */ 91 int32_t snmp_serial_no; 92 93 /* search path for config files */ 94 const char *syspath = PATH_SYSCONFIG; 95 96 /* list of all loaded modules */ 97 struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 98 99 /* list of loaded modules during start-up in the order they were loaded */ 100 static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 101 102 /* list of all known communities */ 103 struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 104 105 /* list of all installed object resources */ 106 struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 107 108 /* community value generator */ 109 static u_int next_community_index = 1; 110 111 /* list of all known ranges */ 112 struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 113 114 /* identifier generator */ 115 u_int next_idrange = 1; 116 117 /* list of all current timers */ 118 struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 119 120 /* list of file descriptors */ 121 struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 122 123 /* program arguments */ 124 static char **progargs; 125 static int nprogargs; 126 127 /* current community */ 128 u_int community; 129 static struct community *comm; 130 131 /* file names */ 132 static char config_file[MAXPATHLEN + 1]; 133 static char pid_file[MAXPATHLEN + 1]; 134 135 #ifndef USE_LIBBEGEMOT 136 /* event context */ 137 static evContext evctx; 138 #endif 139 140 /* signal mask */ 141 static sigset_t blocked_sigs; 142 143 /* signal handling */ 144 static int work; 145 #define WORK_DOINFO 0x0001 146 #define WORK_RECONFIG 0x0002 147 148 /* oids */ 149 static 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 155 const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 156 157 /* request id generator for traps */ 158 u_int trap_reqid; 159 160 /* help text */ 161 static const char usgtxt[] = "\ 162 Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 163 Open Communication Systems (FhG Fokus). All rights reserved.\n\ 164 usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 165 [-m variable=value] [-p file]\n\ 166 options:\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 179 static struct request_info req; 180 #endif 181 182 /* transports */ 183 extern const struct transport_def udp_trans; 184 extern const struct transport_def lsock_trans; 185 186 struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 187 188 /* forward declarations */ 189 static void snmp_printf_func(const char *fmt, ...); 190 static void snmp_error_func(const char *err, ...); 191 static void snmp_debug_func(const char *err, ...); 192 static 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 */ 197 void * 198 buf_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 */ 216 size_t 217 buf_size(int tx) 218 { 219 return (tx ? snmpd.txbuf : snmpd.rxbuf); 220 } 221 222 /* 223 * Prepare a PDU for output 224 */ 225 void 226 snmp_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 */ 248 enum snmpd_input_err 249 snmp_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 */ 354 enum snmpd_input_err 355 snmp_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 */ 460 void 461 trans_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 */ 478 void 479 trans_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 */ 488 struct tport * 489 trans_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 */ 498 struct tport * 499 trans_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 */ 508 struct tport * 509 trans_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 */ 518 struct tport * 519 trans_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 */ 533 int 534 trans_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 */ 572 int 573 trans_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 588 static void 589 input(int fd, int mask __unused, void *uap) 590 #else 591 static void 592 input(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 600 void 601 fd_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 618 int 619 fd_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 646 void * 647 fd_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 680 void 681 fd_deselect(void *p) 682 { 683 struct fdesc *f = p; 684 685 LIST_REMOVE(f, link); 686 fd_suspend(f); 687 free(f); 688 } 689 690 static void 691 fd_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 */ 707 static void 708 snmp_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 724 struct credmsg { 725 struct cmsghdr hdr; 726 struct cmsgcred cred; 727 }; 728 729 static void 730 check_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 */ 757 static int 758 recv_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 */ 816 static int 817 recv_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 */ 883 int 884 snmpd_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 */ 1061 void 1062 snmp_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 */ 1097 void 1098 snmpd_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 1112 static void 1113 info_func(void) 1114 #else 1115 static void 1116 info_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 1149 static void 1150 config_func(void) 1151 #else 1152 static void 1153 config_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 */ 1171 static void 1172 onusr1(int s __unused) 1173 { 1174 1175 work |= WORK_DOINFO; 1176 } 1177 static void 1178 onhup(int s __unused) 1179 { 1180 1181 work |= WORK_RECONFIG; 1182 } 1183 1184 static void 1185 onterm(int s __unused) 1186 { 1187 1188 /* allow clean-up */ 1189 exit(0); 1190 } 1191 1192 static void 1193 init_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 1224 static void 1225 block_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 } 1235 static void 1236 unblock_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 */ 1247 static void 1248 term(void) 1249 { 1250 (void)unlink(pid_file); 1251 } 1252 1253 static void 1254 trans_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 */ 1265 static void 1266 do_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 */ 1287 static int 1288 getsubopt1(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 1331 int 1332 main(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 1603 uint64_t 1604 get_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 1623 static void 1624 tfunc(int tid __unused, void *uap) 1625 #else 1626 static void 1627 tfunc(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 1642 static void 1643 trfunc(int tid __unused, void *uap) 1644 #else 1645 static void 1646 trfunc(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 */ 1658 void * 1659 timer_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 */ 1702 void * 1703 timer_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 */ 1746 void 1747 timer_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 1763 static void 1764 timer_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 1777 static void 1778 snmp_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 1814 static void 1815 snmp_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 1832 static void 1833 snmp_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 1847 static void 1848 asn_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 */ 1878 u_int 1879 comm_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 1935 const char * 1936 comm_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 */ 1949 static void 1950 comm_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 */ 1971 u_int 1972 reqid_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 2038 int32_t 2039 reqid_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 2056 int32_t 2057 reqid_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 2068 u_int 2069 reqid_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 2079 int 2080 reqid_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 */ 2088 static void 2089 reqid_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 */ 2107 static int 2108 compare_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 } 2115 static int 2116 tree_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 */ 2142 static void 2143 tree_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 */ 2159 struct lmodule * 2160 lm_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->handle) 2246 dlclose(m->handle); 2247 free(m->path); 2248 free(m); 2249 return (NULL); 2250 } 2251 2252 /* 2253 * Start a module 2254 */ 2255 void 2256 lm_start(struct lmodule *mod) 2257 { 2258 const struct lmodule *m; 2259 2260 /* 2261 * Merge tree. If this fails, unload the module. 2262 */ 2263 if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2264 lm_unload(mod); 2265 return; 2266 } 2267 2268 /* 2269 * Read configuration 2270 */ 2271 if (read_config(config_file, mod)) { 2272 syslog(LOG_ERR, "error in config file"); 2273 lm_unload(mod); 2274 return; 2275 } 2276 if (mod->config->start) 2277 (*mod->config->start)(); 2278 2279 mod->flags |= LM_STARTED; 2280 2281 /* 2282 * Inform other modules 2283 */ 2284 TAILQ_FOREACH(m, &lmodules, link) 2285 if (m->config->loading) 2286 (*m->config->loading)(mod, 1); 2287 } 2288 2289 2290 /* 2291 * Unload a module. 2292 */ 2293 void 2294 lm_unload(struct lmodule *m) 2295 { 2296 int err; 2297 const struct lmodule *mod; 2298 2299 TAILQ_REMOVE(&lmodules, m, link); 2300 if (m->flags & LM_ONSTARTLIST) 2301 TAILQ_REMOVE(&modules_start, m, start); 2302 tree_unmerge(m); 2303 2304 if ((m->flags & LM_STARTED) && m->config->fini && 2305 (err = (*m->config->fini)()) != 0) 2306 syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2307 2308 comm_flush(m); 2309 reqid_flush(m); 2310 timer_flush(m); 2311 fd_flush(m); 2312 2313 dlclose(m->handle); 2314 free(m->path); 2315 2316 /* 2317 * Inform other modules 2318 */ 2319 TAILQ_FOREACH(mod, &lmodules, link) 2320 if (mod->config->loading) 2321 (*mod->config->loading)(m, 0); 2322 2323 free(m); 2324 } 2325 2326 /* 2327 * Register an object resource and return the index (or 0 on failures) 2328 */ 2329 u_int 2330 or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2331 { 2332 struct objres *objres, *or1; 2333 u_int idx; 2334 2335 /* find a free index */ 2336 idx = 1; 2337 for (objres = TAILQ_FIRST(&objres_list); 2338 objres != NULL; 2339 objres = TAILQ_NEXT(objres, link)) { 2340 if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2341 or1->index > objres->index + 1) { 2342 idx = objres->index + 1; 2343 break; 2344 } 2345 } 2346 2347 if ((objres = malloc(sizeof(*objres))) == NULL) 2348 return (0); 2349 2350 objres->index = idx; 2351 objres->oid = *or; 2352 strlcpy(objres->descr, descr, sizeof(objres->descr)); 2353 objres->uptime = (uint32_t)(get_ticks() - start_tick); 2354 objres->module = mod; 2355 2356 INSERT_OBJECT_INT(objres, &objres_list); 2357 2358 systemg.or_last_change = objres->uptime; 2359 2360 return (idx); 2361 } 2362 2363 void 2364 or_unregister(u_int idx) 2365 { 2366 struct objres *objres; 2367 2368 TAILQ_FOREACH(objres, &objres_list, link) 2369 if (objres->index == idx) { 2370 TAILQ_REMOVE(&objres_list, objres, link); 2371 free(objres); 2372 return; 2373 } 2374 } 2375