main.c revision 128237
1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7122394Sharti * 8122394Sharti * Redistribution of this software and documentation and use in source and 9122394Sharti * binary forms, with or without modification, are permitted provided that 10122394Sharti * the following conditions are met: 11122394Sharti * 12122394Sharti * 1. Redistributions of source code or documentation must retain the above 13122394Sharti * copyright notice, this list of conditions and the following disclaimer. 14122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 15122394Sharti * notice, this list of conditions and the following disclaimer in the 16122394Sharti * documentation and/or other materials provided with the distribution. 17122394Sharti * 3. Neither the name of the Institute nor the names of its contributors 18122394Sharti * may be used to endorse or promote products derived from this software 19122394Sharti * without specific prior written permission. 20122394Sharti * 21122394Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22122394Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23122394Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24122394Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25122394Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26122394Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27122394Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28122394Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29122394Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30122394Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31122394Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32122394Sharti * 33128237Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.85 2004/04/14 15:39:14 novo Exp $ 34122394Sharti * 35122394Sharti * SNMPd main stuff. 36122394Sharti */ 37122394Sharti#include <sys/param.h> 38122394Sharti#include <sys/un.h> 39124861Sharti#include <sys/ucred.h> 40122394Sharti#include <stdio.h> 41122394Sharti#include <stdlib.h> 42122394Sharti#include <stddef.h> 43122394Sharti#include <string.h> 44122394Sharti#include <stdarg.h> 45122394Sharti#include <ctype.h> 46122394Sharti#include <errno.h> 47122394Sharti#include <syslog.h> 48122394Sharti#include <unistd.h> 49122394Sharti#include <signal.h> 50122394Sharti#include <dlfcn.h> 51122394Sharti#include <inttypes.h> 52122394Sharti 53122394Sharti#include "snmpmod.h" 54122394Sharti#include "snmpd.h" 55122394Sharti#include "tree.h" 56122394Sharti#include "oid.h" 57122394Sharti 58122394Sharti#define PATH_PID "/var/run/%s.pid" 59122394Sharti#define PATH_CONFIG "/etc/%s.config" 60122394Sharti 61122394Shartiu_int32_t this_tick; /* start of processing of current packet */ 62122394Shartiu_int32_t start_tick; /* start of processing */ 63122394Sharti 64122394Shartistruct systemg systemg = { 65122394Sharti NULL, 66122394Sharti { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 67122394Sharti NULL, NULL, NULL, 68122394Sharti 64 + 8 + 4, 69122394Sharti 0 70122394Sharti}; 71122394Shartistruct debug debug = { 72122394Sharti 0, /* dump_pdus */ 73122394Sharti LOG_DEBUG, /* log_pri */ 74122394Sharti 0, /* evdebug */ 75122394Sharti}; 76122394Sharti 77122394Shartistruct snmpd snmpd = { 78122394Sharti 2048, /* txbuf */ 79122394Sharti 2048, /* rxbuf */ 80122394Sharti 0, /* comm_dis */ 81122394Sharti 0, /* auth_traps */ 82122394Sharti {0, 0, 0, 0}, /* trap1addr */ 83124861Sharti VERS_ENABLE_ALL,/* version_enable */ 84122394Sharti}; 85122394Shartistruct snmpd_stats snmpd_stats; 86122394Sharti 87122394Sharti/* snmpSerialNo */ 88122394Shartiint32_t snmp_serial_no; 89122394Sharti 90122394Sharti/* search path for config files */ 91122394Sharticonst char *syspath = PATH_SYSCONFIG; 92122394Sharti 93122394Sharti/* list of all loaded modules */ 94122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 95122394Sharti 96122394Sharti/* list of loaded modules during start-up in the order they were loaded */ 97122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 98122394Sharti 99122394Sharti/* list of all known communities */ 100122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 101122394Sharti 102122394Sharti/* list of all installed object resources */ 103122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 104122394Sharti 105122394Sharti/* community value generator */ 106122394Shartistatic u_int next_community_index = 1; 107122394Sharti 108122394Sharti/* list of all known ranges */ 109122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 110122394Sharti 111122394Sharti/* identifier generator */ 112122394Shartiu_int next_idrange = 1; 113122394Sharti 114122394Sharti/* list of all current timers */ 115122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 116122394Sharti 117122394Sharti/* list of file descriptors */ 118122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 119122394Sharti 120122394Sharti/* program arguments */ 121122394Shartistatic char **progargs; 122122394Shartistatic int nprogargs; 123122394Sharti 124122394Sharti/* current community */ 125122394Shartiu_int community; 126122394Shartistatic struct community *comm; 127122394Sharti 128122394Sharti/* file names */ 129122394Shartistatic char config_file[MAXPATHLEN + 1]; 130122394Shartistatic char pid_file[MAXPATHLEN + 1]; 131122394Sharti 132124861Sharti#ifndef USE_LIBBEGEMOT 133122394Sharti/* event context */ 134122394Shartistatic evContext evctx; 135124861Sharti#endif 136122394Sharti 137122394Sharti/* signal mask */ 138122394Shartistatic sigset_t blocked_sigs; 139122394Sharti 140122394Sharti/* signal handling */ 141122394Shartistatic int work; 142122394Sharti#define WORK_DOINFO 0x0001 143122394Sharti#define WORK_RECONFIG 0x0002 144122394Sharti 145122394Sharti/* oids */ 146122394Shartistatic const struct asn_oid 147122394Sharti oid_snmpMIB = OIDX_snmpMIB, 148122394Sharti oid_begemotSnmpd = OIDX_begemotSnmpd, 149122394Sharti oid_coldStart = OIDX_coldStart, 150122394Sharti oid_authenticationFailure = OIDX_authenticationFailure; 151122394Sharti 152122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 153122394Sharti 154122394Sharti/* request id generator for traps */ 155122394Shartiu_int trap_reqid; 156122394Sharti 157122394Sharti/* help text */ 158122394Shartistatic const char usgtxt[] = "\ 159122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 160122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 161122394Shartiusage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 162122394Sharti [-m variable=value] [-p file]\n\ 163122394Shartioptions:\n\ 164122394Sharti -d don't daemonize\n\ 165122394Sharti -h print this info\n\ 166122394Sharti -c file specify configuration file\n\ 167122394Sharti -D options debugging options\n\ 168122394Sharti -I path system include path\n\ 169122394Sharti -l prefix default basename for pid and config file\n\ 170122394Sharti -m var=val define variable\n\ 171122394Sharti -p file specify pid file\n\ 172122394Sharti"; 173122394Sharti 174124861Sharti/* transports */ 175124861Shartiextern const struct transport_def udp_trans; 176124861Shartiextern const struct transport_def lsock_trans; 177124861Sharti 178124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 179124861Sharti 180122394Sharti/* forward declarations */ 181122394Shartistatic void snmp_printf_func(const char *fmt, ...); 182122394Shartistatic void snmp_error_func(const char *err, ...); 183122394Shartistatic void snmp_debug_func(const char *err, ...); 184122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...); 185122394Sharti 186122394Sharti/* 187122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx. 188122394Sharti */ 189122394Shartivoid * 190122394Shartibuf_alloc(int tx) 191122394Sharti{ 192122394Sharti void *buf; 193122394Sharti 194124861Sharti if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 195122394Sharti syslog(LOG_CRIT, "cannot allocate buffer"); 196122394Sharti if (tx) 197122394Sharti snmpd_stats.noTxbuf++; 198122394Sharti else 199122394Sharti snmpd_stats.noRxbuf++; 200122394Sharti return (NULL); 201122394Sharti } 202122394Sharti return (buf); 203122394Sharti} 204122394Sharti 205122394Sharti/* 206124861Sharti * Return the buffer size. 207122394Sharti */ 208122394Shartisize_t 209122394Shartibuf_size(int tx) 210122394Sharti{ 211124861Sharti return (tx ? snmpd.txbuf : snmpd.rxbuf); 212122394Sharti} 213122394Sharti 214122394Sharti/* 215122394Sharti * Prepare a PDU for output 216122394Sharti */ 217122394Shartivoid 218124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 219122394Sharti const char *dest) 220122394Sharti{ 221122394Sharti struct asn_buf resp_b; 222122394Sharti 223122394Sharti resp_b.asn_ptr = sndbuf; 224122394Sharti resp_b.asn_len = snmpd.txbuf; 225122394Sharti 226122394Sharti if (snmp_pdu_encode(pdu, &resp_b) != 0) { 227122394Sharti syslog(LOG_ERR, "cannot encode message"); 228122394Sharti abort(); 229122394Sharti } 230122394Sharti if (debug.dump_pdus) { 231122394Sharti snmp_printf("%s <- ", dest); 232122394Sharti snmp_pdu_dump(pdu); 233122394Sharti } 234122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 235122394Sharti} 236122394Sharti 237122394Sharti/* 238122394Sharti * SNMP input. Start: decode the PDU, find the community. 239122394Sharti */ 240122394Shartienum snmpd_input_err 241122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source, 242124861Sharti struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 243122394Sharti{ 244122394Sharti struct asn_buf b; 245122394Sharti enum snmp_code code; 246122394Sharti enum snmpd_input_err ret; 247124861Sharti int sret; 248122394Sharti 249122394Sharti b.asn_cptr = buf; 250122394Sharti b.asn_len = len; 251124861Sharti 252124861Sharti /* look whether we have enough bytes for the entire PDU. */ 253124861Sharti switch (sret = snmp_pdu_snoop(&b)) { 254124861Sharti 255124861Sharti case 0: 256124861Sharti return (SNMPD_INPUT_TRUNC); 257124861Sharti 258124861Sharti case -1: 259124861Sharti snmpd_stats.inASNParseErrs++; 260124861Sharti return (SNMPD_INPUT_FAILED); 261124861Sharti } 262124861Sharti b.asn_len = *pdulen = (size_t)sret; 263124861Sharti 264122394Sharti code = snmp_pdu_decode(&b, pdu, ip); 265122394Sharti 266124861Sharti snmpd_stats.inPkts++; 267124861Sharti 268122394Sharti ret = SNMPD_INPUT_OK; 269122394Sharti switch (code) { 270122394Sharti 271122394Sharti case SNMP_CODE_FAILED: 272122394Sharti snmpd_stats.inASNParseErrs++; 273122394Sharti return (SNMPD_INPUT_FAILED); 274122394Sharti 275122394Sharti case SNMP_CODE_BADVERS: 276124861Sharti bad_vers: 277122394Sharti snmpd_stats.inBadVersions++; 278122394Sharti return (SNMPD_INPUT_FAILED); 279122394Sharti 280122394Sharti case SNMP_CODE_BADLEN: 281122394Sharti if (pdu->type == SNMP_OP_SET) 282122394Sharti ret = SNMPD_INPUT_VALBADLEN; 283122394Sharti break; 284122394Sharti 285122394Sharti case SNMP_CODE_OORANGE: 286122394Sharti if (pdu->type == SNMP_OP_SET) 287122394Sharti ret = SNMPD_INPUT_VALRANGE; 288122394Sharti break; 289122394Sharti 290122394Sharti case SNMP_CODE_BADENC: 291122394Sharti if (pdu->type == SNMP_OP_SET) 292122394Sharti ret = SNMPD_INPUT_VALBADENC; 293122394Sharti break; 294122394Sharti 295122394Sharti case SNMP_CODE_OK: 296124861Sharti switch (pdu->version) { 297124861Sharti 298124861Sharti case SNMP_V1: 299124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V1)) 300124861Sharti goto bad_vers; 301124861Sharti break; 302124861Sharti 303124861Sharti case SNMP_V2c: 304124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 305124861Sharti goto bad_vers; 306124861Sharti break; 307124861Sharti 308124861Sharti case SNMP_Verr: 309124861Sharti goto bad_vers; 310124861Sharti } 311122394Sharti break; 312122394Sharti } 313122394Sharti 314122394Sharti if (debug.dump_pdus) { 315122394Sharti snmp_printf("%s -> ", source); 316122394Sharti snmp_pdu_dump(pdu); 317122394Sharti } 318122394Sharti 319122394Sharti /* 320122394Sharti * Look, whether we know the community 321122394Sharti */ 322122394Sharti TAILQ_FOREACH(comm, &community_list, link) 323122394Sharti if (comm->string != NULL && 324122394Sharti strcmp(comm->string, pdu->community) == 0) 325122394Sharti break; 326122394Sharti 327122394Sharti if (comm == NULL) { 328122394Sharti snmpd_stats.inBadCommunityNames++; 329122394Sharti snmp_pdu_free(pdu); 330122394Sharti if (snmpd.auth_traps) 331122394Sharti snmp_send_trap(&oid_authenticationFailure, NULL); 332122394Sharti return (SNMPD_INPUT_FAILED); 333122394Sharti } 334122394Sharti community = comm->value; 335122394Sharti 336122394Sharti /* update uptime */ 337122394Sharti this_tick = get_ticks(); 338122394Sharti 339122394Sharti return (ret); 340122394Sharti} 341122394Sharti 342122394Sharti/* 343122394Sharti * Will return only _OK or _FAILED 344122394Sharti */ 345122394Shartienum snmpd_input_err 346122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 347122394Sharti u_char *sndbuf, size_t *sndlen, const char *source, 348122394Sharti enum snmpd_input_err ierr, int32_t ivar, void *data) 349122394Sharti{ 350122394Sharti struct snmp_pdu resp; 351122394Sharti struct asn_buf resp_b, pdu_b; 352122394Sharti enum snmp_ret ret; 353122394Sharti 354122394Sharti resp_b.asn_ptr = sndbuf; 355122394Sharti resp_b.asn_len = snmpd.txbuf; 356122394Sharti 357122394Sharti pdu_b.asn_cptr = rcvbuf; 358122394Sharti pdu_b.asn_len = rcvlen; 359122394Sharti 360122394Sharti if (ierr != SNMPD_INPUT_OK) { 361122394Sharti /* error decoding the input of a SET */ 362122394Sharti if (pdu->version == SNMP_V1) 363122394Sharti pdu->error_status = SNMP_ERR_BADVALUE; 364122394Sharti else if (ierr == SNMPD_INPUT_VALBADLEN) 365122394Sharti pdu->error_status = SNMP_ERR_WRONG_LENGTH; 366122394Sharti else if (ierr == SNMPD_INPUT_VALRANGE) 367122394Sharti pdu->error_status = SNMP_ERR_WRONG_VALUE; 368122394Sharti else 369122394Sharti pdu->error_status = SNMP_ERR_WRONG_ENCODING; 370122394Sharti 371122394Sharti pdu->error_index = ivar; 372122394Sharti 373122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 374122394Sharti syslog(LOG_WARNING, "could not encode error response"); 375122394Sharti snmpd_stats.silentDrops++; 376122394Sharti return (SNMPD_INPUT_FAILED); 377122394Sharti } 378122394Sharti 379122394Sharti if (debug.dump_pdus) { 380122394Sharti snmp_printf("%s <- ", source); 381122394Sharti snmp_pdu_dump(pdu); 382122394Sharti } 383122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 384122394Sharti return (SNMPD_INPUT_OK); 385122394Sharti } 386122394Sharti 387122394Sharti switch (pdu->type) { 388122394Sharti 389122394Sharti case SNMP_PDU_GET: 390122394Sharti ret = snmp_get(pdu, &resp_b, &resp, data); 391122394Sharti break; 392122394Sharti 393122394Sharti case SNMP_PDU_GETNEXT: 394122394Sharti ret = snmp_getnext(pdu, &resp_b, &resp, data); 395122394Sharti break; 396122394Sharti 397122394Sharti case SNMP_PDU_SET: 398122394Sharti ret = snmp_set(pdu, &resp_b, &resp, data); 399122394Sharti break; 400122394Sharti 401122394Sharti case SNMP_PDU_GETBULK: 402122394Sharti ret = snmp_getbulk(pdu, &resp_b, &resp, data); 403122394Sharti break; 404122394Sharti 405122394Sharti default: 406122394Sharti ret = SNMP_RET_IGN; 407122394Sharti break; 408122394Sharti } 409122394Sharti 410122394Sharti switch (ret) { 411122394Sharti 412122394Sharti case SNMP_RET_OK: 413122394Sharti /* normal return - send a response */ 414122394Sharti if (debug.dump_pdus) { 415122394Sharti snmp_printf("%s <- ", source); 416122394Sharti snmp_pdu_dump(&resp); 417122394Sharti } 418122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 419122394Sharti snmp_pdu_free(&resp); 420122394Sharti return (SNMPD_INPUT_OK); 421122394Sharti 422122394Sharti case SNMP_RET_IGN: 423122394Sharti /* error - send nothing */ 424122394Sharti snmpd_stats.silentDrops++; 425122394Sharti return (SNMPD_INPUT_FAILED); 426122394Sharti 427122394Sharti case SNMP_RET_ERR: 428122394Sharti /* error - send error response. The snmp routine has 429122394Sharti * changed the error fields in the original message. */ 430122394Sharti resp_b.asn_ptr = sndbuf; 431122394Sharti resp_b.asn_len = snmpd.txbuf; 432122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 433122394Sharti syslog(LOG_WARNING, "could not encode error response"); 434122394Sharti snmpd_stats.silentDrops++; 435122394Sharti return (SNMPD_INPUT_FAILED); 436122394Sharti } else { 437122394Sharti if (debug.dump_pdus) { 438122394Sharti snmp_printf("%s <- ", source); 439122394Sharti snmp_pdu_dump(pdu); 440122394Sharti } 441122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 442122394Sharti return (SNMPD_INPUT_OK); 443122394Sharti } 444122394Sharti } 445122394Sharti abort(); 446122394Sharti} 447122394Sharti 448124861Sharti/* 449124861Sharti * Insert a port into the right place in the transport's table of ports 450124861Sharti */ 451124861Shartivoid 452124861Shartitrans_insert_port(struct transport *t, struct tport *port) 453124861Sharti{ 454124861Sharti struct tport *p; 455122394Sharti 456124861Sharti TAILQ_FOREACH(p, &t->table, link) { 457124861Sharti if (asn_compare_oid(&p->index, &port->index) > 0) { 458124861Sharti TAILQ_INSERT_BEFORE(p, port, link); 459124861Sharti return; 460124861Sharti } 461124861Sharti } 462124861Sharti port->transport = t; 463124861Sharti TAILQ_INSERT_TAIL(&t->table, port, link); 464124861Sharti} 465122394Sharti 466122394Sharti/* 467124861Sharti * Remove a port from a transport's list 468124861Sharti */ 469124861Shartivoid 470124861Shartitrans_remove_port(struct tport *port) 471124861Sharti{ 472124861Sharti 473124861Sharti TAILQ_REMOVE(&port->transport->table, port, link); 474124861Sharti} 475124861Sharti 476124861Sharti/* 477124861Sharti * Find a port on a transport's list 478124861Sharti */ 479124861Shartistruct tport * 480124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 481124861Sharti{ 482124861Sharti 483124861Sharti return (FIND_OBJECT_OID(&t->table, idx, sub)); 484124861Sharti} 485124861Sharti 486124861Sharti/* 487124861Sharti * Find next port on a transport's list 488124861Sharti */ 489124861Shartistruct tport * 490124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 491124861Sharti{ 492124861Sharti 493124861Sharti return (NEXT_OBJECT_OID(&t->table, idx, sub)); 494124861Sharti} 495124861Sharti 496124861Sharti/* 497124861Sharti * Return first port 498124861Sharti */ 499124861Shartistruct tport * 500124861Shartitrans_first_port(struct transport *t) 501124861Sharti{ 502124861Sharti 503124861Sharti return (TAILQ_FIRST(&t->table)); 504124861Sharti} 505124861Sharti 506124861Sharti/* 507124861Sharti * Iterate through all ports until a function returns a 0. 508124861Sharti */ 509124861Shartistruct tport * 510124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 511124861Sharti intptr_t arg) 512124861Sharti{ 513124861Sharti struct tport *p; 514124861Sharti 515124861Sharti TAILQ_FOREACH(p, &t->table, link) 516124861Sharti if (func(p, arg) == 0) 517124861Sharti return (p); 518124861Sharti return (NULL); 519124861Sharti} 520124861Sharti 521124861Sharti/* 522124861Sharti * Register a transport 523124861Sharti */ 524124861Shartiint 525124861Shartitrans_register(const struct transport_def *def, struct transport **pp) 526124861Sharti{ 527124861Sharti u_int i; 528124861Sharti char or_descr[256]; 529124861Sharti 530124861Sharti if ((*pp = malloc(sizeof(**pp))) == NULL) 531124861Sharti return (SNMP_ERR_GENERR); 532124861Sharti 533124861Sharti /* construct index */ 534124861Sharti (*pp)->index.len = strlen(def->name) + 1; 535124861Sharti (*pp)->index.subs[0] = strlen(def->name); 536124861Sharti for (i = 0; i < (*pp)->index.subs[0]; i++) 537124861Sharti (*pp)->index.subs[i + 1] = def->name[i]; 538124861Sharti 539124861Sharti (*pp)->vtab = def; 540124861Sharti 541124861Sharti if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 542124861Sharti free(*pp); 543124861Sharti return (SNMP_ERR_INCONS_VALUE); 544124861Sharti } 545124861Sharti 546124861Sharti /* register module */ 547124861Sharti snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 548124861Sharti if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 549124861Sharti free(*pp); 550124861Sharti return (SNMP_ERR_GENERR); 551124861Sharti } 552124861Sharti 553124861Sharti INSERT_OBJECT_OID((*pp), &transport_list); 554124861Sharti 555124861Sharti TAILQ_INIT(&(*pp)->table); 556124861Sharti 557124861Sharti return (SNMP_ERR_NOERROR); 558124861Sharti} 559124861Sharti 560124861Sharti/* 561124861Sharti * Unregister transport 562124861Sharti */ 563124861Shartiint 564124861Shartitrans_unregister(struct transport *t) 565124861Sharti{ 566124861Sharti if (!TAILQ_EMPTY(&t->table)) 567124861Sharti return (SNMP_ERR_INCONS_VALUE); 568124861Sharti 569124861Sharti or_unregister(t->or_index); 570124861Sharti TAILQ_REMOVE(&transport_list, t, link); 571124861Sharti 572124861Sharti return (SNMP_ERR_NOERROR); 573124861Sharti} 574124861Sharti 575124861Sharti/* 576122394Sharti * File descriptor support 577122394Sharti */ 578124861Sharti#ifdef USE_LIBBEGEMOT 579122394Shartistatic void 580124861Shartiinput(int fd, int mask __unused, void *uap) 581124861Sharti#else 582124861Shartistatic void 583122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused) 584124861Sharti#endif 585122394Sharti{ 586122394Sharti struct fdesc *f = uap; 587122394Sharti 588122394Sharti (*f->func)(fd, f->udata); 589122394Sharti} 590122394Sharti 591122394Shartivoid 592122394Shartifd_suspend(void *p) 593122394Sharti{ 594122394Sharti struct fdesc *f = p; 595122394Sharti 596124861Sharti#ifdef USE_LIBBEGEMOT 597124861Sharti if (f->id >= 0) { 598124861Sharti poll_unregister(f->id); 599124861Sharti f->id = -1; 600124861Sharti } 601124861Sharti#else 602122394Sharti if (evTestID(f->id)) { 603122394Sharti (void)evDeselectFD(evctx, f->id); 604122394Sharti evInitID(&f->id); 605122394Sharti } 606124861Sharti#endif 607122394Sharti} 608122394Sharti 609122394Shartiint 610122394Shartifd_resume(void *p) 611122394Sharti{ 612122394Sharti struct fdesc *f = p; 613122394Sharti int err; 614122394Sharti 615124861Sharti#ifdef USE_LIBBEGEMOT 616124861Sharti if (f->id >= 0) 617124861Sharti return (0); 618124861Sharti if ((f->fd = poll_register(f->fd, input, f, POLL_IN)) < 0) { 619124861Sharti err = errno; 620124861Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 621124861Sharti errno = err; 622124861Sharti return (-1); 623124861Sharti } 624124861Sharti#else 625122394Sharti if (evTestID(f->id)) 626122394Sharti return (0); 627122394Sharti if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 628122394Sharti err = errno; 629122394Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 630122394Sharti errno = err; 631122394Sharti return (-1); 632122394Sharti } 633124861Sharti#endif 634122394Sharti return (0); 635122394Sharti} 636122394Sharti 637122394Shartivoid * 638122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 639122394Sharti{ 640122394Sharti struct fdesc *f; 641122394Sharti int err; 642122394Sharti 643122394Sharti if ((f = malloc(sizeof(struct fdesc))) == NULL) { 644122394Sharti err = errno; 645122394Sharti syslog(LOG_ERR, "fd_select: %m"); 646122394Sharti errno = err; 647122394Sharti return (NULL); 648122394Sharti } 649122394Sharti f->fd = fd; 650122394Sharti f->func = func; 651122394Sharti f->udata = udata; 652122394Sharti f->owner = mod; 653124861Sharti#ifdef USE_LIBBEGEMOT 654124861Sharti f->id = -1; 655124861Sharti#else 656122394Sharti evInitID(&f->id); 657124861Sharti#endif 658122394Sharti 659122394Sharti if (fd_resume(f)) { 660122394Sharti err = errno; 661122394Sharti free(f); 662122394Sharti errno = err; 663122394Sharti return (NULL); 664122394Sharti } 665122394Sharti 666122394Sharti LIST_INSERT_HEAD(&fdesc_list, f, link); 667122394Sharti 668122394Sharti return (f); 669122394Sharti} 670122394Sharti 671122394Shartivoid 672122394Shartifd_deselect(void *p) 673122394Sharti{ 674122394Sharti struct fdesc *f = p; 675122394Sharti 676122394Sharti LIST_REMOVE(f, link); 677122394Sharti fd_suspend(f); 678122394Sharti free(f); 679122394Sharti} 680122394Sharti 681122394Shartistatic void 682122394Shartifd_flush(struct lmodule *mod) 683122394Sharti{ 684122394Sharti struct fdesc *t, *t1; 685122394Sharti 686122394Sharti t = LIST_FIRST(&fdesc_list); 687122394Sharti while (t != NULL) { 688122394Sharti t1 = LIST_NEXT(t, link); 689122394Sharti if (t->owner == mod) 690122394Sharti fd_deselect(t); 691122394Sharti t = t1; 692122394Sharti } 693122394Sharti} 694122394Sharti 695122394Sharti/* 696124861Sharti * Consume a message from the input buffer 697122394Sharti */ 698122394Shartistatic void 699124861Shartisnmp_input_consume(struct port_input *pi) 700122394Sharti{ 701124861Sharti if (!pi->stream) { 702124861Sharti /* always consume everything */ 703124861Sharti pi->length = 0; 704122394Sharti return; 705122394Sharti } 706124861Sharti if (pi->consumed >= pi->length) { 707124861Sharti /* all bytes consumed */ 708124861Sharti pi->length = 0; 709122394Sharti return; 710122394Sharti } 711124861Sharti memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 712124861Sharti pi->length -= pi->consumed; 713124861Sharti} 714124861Sharti 715124861Shartistruct credmsg { 716124861Sharti struct cmsghdr hdr; 717124861Sharti struct cmsgcred cred; 718124861Sharti}; 719124861Sharti 720124861Shartistatic void 721124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg) 722124861Sharti{ 723124861Sharti struct credmsg *cmsg; 724124861Sharti struct xucred ucred; 725124861Sharti socklen_t ucredlen; 726124861Sharti 727124861Sharti pi->priv = 0; 728124861Sharti 729124861Sharti if (msg->msg_controllen == sizeof(*cmsg)) { 730124861Sharti /* process explicitely sends credentials */ 731124861Sharti 732124861Sharti cmsg = (struct credmsg *)msg->msg_control; 733124861Sharti pi->priv = (cmsg->cred.cmcred_euid == 0); 734122394Sharti return; 735122394Sharti } 736124861Sharti 737124861Sharti /* ok, obtain the accept time credentials */ 738124861Sharti ucredlen = sizeof(ucred); 739124861Sharti 740124861Sharti if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 741124861Sharti ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 742124861Sharti pi->priv = (ucred.cr_uid == 0); 743124861Sharti} 744124861Sharti 745124861Sharti/* 746124861Sharti * Input from a stream socket. 747124861Sharti */ 748124861Shartistatic int 749124861Shartirecv_stream(struct port_input *pi) 750124861Sharti{ 751124861Sharti struct msghdr msg; 752124861Sharti struct iovec iov[1]; 753124861Sharti ssize_t len; 754124861Sharti struct credmsg cmsg; 755124861Sharti 756124861Sharti if (pi->buf == NULL) { 757124861Sharti /* no buffer yet - allocate one */ 758124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 759124861Sharti /* ups - could not get buffer. Return an error 760124861Sharti * the caller must close the transport. */ 761124861Sharti return (-1); 762124861Sharti } 763124861Sharti pi->buflen = buf_size(0); 764124861Sharti pi->consumed = 0; 765124861Sharti pi->length = 0; 766124861Sharti } 767124861Sharti 768124861Sharti /* try to get a message */ 769124861Sharti msg.msg_name = pi->peer; 770124861Sharti msg.msg_namelen = pi->peerlen; 771124861Sharti msg.msg_iov = iov; 772124861Sharti msg.msg_iovlen = 1; 773124861Sharti if (pi->cred) { 774124861Sharti msg.msg_control = &cmsg; 775124861Sharti msg.msg_controllen = sizeof(cmsg); 776124861Sharti 777124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 778124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 779124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 780124861Sharti } else { 781124861Sharti msg.msg_control = NULL; 782124861Sharti msg.msg_controllen = 0; 783124861Sharti } 784124861Sharti msg.msg_flags = 0; 785124861Sharti 786124861Sharti iov[0].iov_base = pi->buf + pi->length; 787124861Sharti iov[0].iov_len = pi->buflen - pi->length; 788124861Sharti 789124861Sharti len = recvmsg(pi->fd, &msg, 0); 790124861Sharti 791124861Sharti if (len == -1 || len == 0) 792124861Sharti /* receive error */ 793124861Sharti return (-1); 794124861Sharti 795124861Sharti pi->length += len; 796124861Sharti 797124861Sharti if (pi->cred) 798124861Sharti check_priv(pi, &msg); 799124861Sharti 800124861Sharti return (0); 801124861Sharti} 802124861Sharti 803124861Sharti/* 804124861Sharti * Input from a datagram socket. 805124861Sharti * Each receive should return one datagram. 806124861Sharti */ 807124861Shartistatic int 808124861Shartirecv_dgram(struct port_input *pi) 809124861Sharti{ 810124861Sharti u_char embuf[1000]; 811124861Sharti struct msghdr msg; 812124861Sharti struct iovec iov[1]; 813124861Sharti ssize_t len; 814124861Sharti struct credmsg cmsg; 815124861Sharti 816124861Sharti if (pi->buf == NULL) { 817124861Sharti /* no buffer yet - allocate one */ 818124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 819124861Sharti /* ups - could not get buffer. Read away input 820124861Sharti * and drop it */ 821124861Sharti (void)recvfrom(pi->fd, embuf, sizeof(embuf), 822124861Sharti 0, NULL, NULL); 823124861Sharti /* return error */ 824124861Sharti return (-1); 825124861Sharti } 826124861Sharti pi->buflen = buf_size(0); 827124861Sharti } 828124861Sharti 829124861Sharti /* try to get a message */ 830124861Sharti msg.msg_name = pi->peer; 831124861Sharti msg.msg_namelen = pi->peerlen; 832124861Sharti msg.msg_iov = iov; 833124861Sharti msg.msg_iovlen = 1; 834124861Sharti if (pi->cred) { 835124861Sharti msg.msg_control = &cmsg; 836124861Sharti msg.msg_controllen = sizeof(cmsg); 837124861Sharti 838124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 839124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 840124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 841124861Sharti } else { 842124861Sharti msg.msg_control = NULL; 843128237Sharti msg.msg_controllen = 0; 844124861Sharti } 845124861Sharti msg.msg_flags = 0; 846124861Sharti 847124861Sharti iov[0].iov_base = pi->buf; 848124861Sharti iov[0].iov_len = pi->buflen; 849124861Sharti 850124861Sharti len = recvmsg(pi->fd, &msg, 0); 851124861Sharti 852124861Sharti if (len == -1 || len == 0) 853124861Sharti /* receive error */ 854124861Sharti return (-1); 855124861Sharti 856124861Sharti if (msg.msg_flags & MSG_TRUNC) { 857124861Sharti /* truncated - drop */ 858122394Sharti snmpd_stats.silentDrops++; 859122394Sharti snmpd_stats.inTooLong++; 860124861Sharti return (-1); 861122394Sharti } 862122394Sharti 863124861Sharti pi->length = (size_t)len; 864124861Sharti 865124861Sharti if (pi->cred) 866124861Sharti check_priv(pi, &msg); 867124861Sharti 868124861Sharti return (0); 869124861Sharti} 870124861Sharti 871124861Sharti/* 872124861Sharti * Input from a socket 873124861Sharti */ 874124861Shartiint 875124861Shartisnmpd_input(struct port_input *pi, struct tport *tport) 876124861Sharti{ 877124861Sharti u_char *sndbuf; 878124861Sharti size_t sndlen; 879124861Sharti struct snmp_pdu pdu; 880124861Sharti enum snmpd_input_err ierr, ferr; 881124861Sharti enum snmpd_proxy_err perr; 882124861Sharti int32_t vi; 883124861Sharti int ret; 884124861Sharti ssize_t slen; 885124861Sharti 886124861Sharti /* get input depending on the transport */ 887124861Sharti if (pi->stream) { 888124861Sharti ret = recv_stream(pi); 889124861Sharti } else { 890124861Sharti ret = recv_dgram(pi); 891124861Sharti } 892124861Sharti 893124861Sharti if (ret == -1) 894124861Sharti return (-1); 895124861Sharti 896122394Sharti /* 897122394Sharti * Handle input 898122394Sharti */ 899124861Sharti ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 900124861Sharti &pi->consumed); 901124861Sharti if (ierr == SNMPD_INPUT_TRUNC) { 902124861Sharti /* need more bytes. This is ok only for streaming transports. 903124861Sharti * but only if we have not reached bufsiz yet. */ 904124861Sharti if (pi->stream) { 905124861Sharti if (pi->length == buf_size(0)) { 906124861Sharti snmpd_stats.silentDrops++; 907124861Sharti return (-1); 908124861Sharti } 909124861Sharti return (0); 910124861Sharti } 911124861Sharti snmpd_stats.silentDrops++; 912124861Sharti return (-1); 913124861Sharti } 914122394Sharti 915122394Sharti /* can't check for bad SET pdus here, because a proxy may have to 916122394Sharti * check the access first. We don't want to return an error response 917122394Sharti * to a proxy PDU with a wrong community */ 918122394Sharti if (ierr == SNMPD_INPUT_FAILED) { 919124861Sharti /* for streaming transports this is fatal */ 920124861Sharti if (pi->stream) 921124861Sharti return (-1); 922124861Sharti snmp_input_consume(pi); 923124861Sharti return (0); 924122394Sharti } 925122394Sharti 926122394Sharti /* 927122394Sharti * If that is a module community and the module has a proxy function, 928122394Sharti * the hand it over to the module. 929122394Sharti */ 930122394Sharti if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 931124861Sharti perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 932124861Sharti &tport->index, pi->peer, pi->peerlen, ierr, vi, pi->priv); 933122394Sharti 934122394Sharti switch (perr) { 935122394Sharti 936122394Sharti case SNMPD_PROXY_OK: 937124861Sharti snmp_input_consume(pi); 938124861Sharti return (0); 939122394Sharti 940122394Sharti case SNMPD_PROXY_REJ: 941122394Sharti break; 942122394Sharti 943122394Sharti case SNMPD_PROXY_DROP: 944124861Sharti snmp_input_consume(pi); 945122394Sharti snmp_pdu_free(&pdu); 946122394Sharti snmpd_stats.proxyDrops++; 947124861Sharti return (0); 948122394Sharti 949122394Sharti case SNMPD_PROXY_BADCOMM: 950124861Sharti snmp_input_consume(pi); 951122394Sharti snmp_pdu_free(&pdu); 952122394Sharti snmpd_stats.inBadCommunityNames++; 953122394Sharti if (snmpd.auth_traps) 954122394Sharti snmp_send_trap(&oid_authenticationFailure, 955122394Sharti NULL); 956124861Sharti return (0); 957122394Sharti 958122394Sharti case SNMPD_PROXY_BADCOMMUSE: 959124861Sharti snmp_input_consume(pi); 960122394Sharti snmp_pdu_free(&pdu); 961122394Sharti snmpd_stats.inBadCommunityUses++; 962122394Sharti if (snmpd.auth_traps) 963122394Sharti snmp_send_trap(&oid_authenticationFailure, 964122394Sharti NULL); 965124861Sharti return (0); 966122394Sharti } 967122394Sharti } 968122394Sharti 969122394Sharti /* 970122394Sharti * Check type 971122394Sharti */ 972122394Sharti if (pdu.type == SNMP_PDU_RESPONSE || 973122394Sharti pdu.type == SNMP_PDU_TRAP || 974122394Sharti pdu.type == SNMP_PDU_TRAP2) { 975122394Sharti snmpd_stats.silentDrops++; 976122394Sharti snmpd_stats.inBadPduTypes++; 977122394Sharti snmp_pdu_free(&pdu); 978124861Sharti snmp_input_consume(pi); 979124861Sharti return (0); 980122394Sharti } 981122394Sharti 982122394Sharti /* 983122394Sharti * Check community 984122394Sharti */ 985124861Sharti if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 986124861Sharti (community != COMM_WRITE && 987124861Sharti (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 988122394Sharti snmpd_stats.inBadCommunityUses++; 989122394Sharti snmp_pdu_free(&pdu); 990124861Sharti snmp_input_consume(pi); 991122394Sharti if (snmpd.auth_traps) 992122394Sharti snmp_send_trap(&oid_authenticationFailure, NULL); 993124861Sharti return (0); 994122394Sharti } 995122394Sharti 996122394Sharti /* 997122394Sharti * Execute it. 998122394Sharti */ 999122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 1000122394Sharti snmpd_stats.silentDrops++; 1001122394Sharti snmp_pdu_free(&pdu); 1002124861Sharti snmp_input_consume(pi); 1003124861Sharti return (0); 1004122394Sharti } 1005124861Sharti ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1006124861Sharti sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1007122394Sharti 1008122394Sharti if (ferr == SNMPD_INPUT_OK) { 1009124861Sharti slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 1010124861Sharti if (slen == -1) 1011122394Sharti syslog(LOG_ERR, "sendto: %m"); 1012124861Sharti else if ((size_t)slen != sndlen) 1013122394Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1014124861Sharti sndlen, (size_t)slen); 1015122394Sharti } 1016122394Sharti snmp_pdu_free(&pdu); 1017122394Sharti free(sndbuf); 1018124861Sharti snmp_input_consume(pi); 1019122394Sharti 1020124861Sharti return (0); 1021122394Sharti} 1022122394Sharti 1023122394Sharti/* 1024124861Sharti * Send a PDU to a given port 1025122394Sharti */ 1026124861Shartivoid 1027124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1028124861Sharti const struct sockaddr *addr, socklen_t addrlen) 1029122394Sharti{ 1030124861Sharti struct transport *trans = targ; 1031124861Sharti struct tport *tp; 1032124861Sharti u_char *sndbuf; 1033124861Sharti size_t sndlen; 1034124861Sharti ssize_t len; 1035122394Sharti 1036124861Sharti TAILQ_FOREACH(tp, &trans->table, link) 1037124861Sharti if (asn_compare_oid(port, &tp->index) == 0) 1038122394Sharti break; 1039124861Sharti if (tp == 0) 1040124861Sharti return; 1041122394Sharti 1042124861Sharti if ((sndbuf = buf_alloc(1)) == NULL) 1043124861Sharti return; 1044122394Sharti 1045124861Sharti snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1046122394Sharti 1047124861Sharti len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1048122394Sharti 1049124861Sharti if (len == -1) 1050124861Sharti syslog(LOG_ERR, "sendto: %m"); 1051124861Sharti else if ((size_t)len != sndlen) 1052124861Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1053124861Sharti sndlen, (size_t)len); 1054122394Sharti 1055124861Sharti free(sndbuf); 1056122394Sharti} 1057122394Sharti 1058122394Sharti 1059122394Sharti/* 1060124861Sharti * Close an input source 1061122394Sharti */ 1062122394Shartivoid 1063124861Shartisnmpd_input_close(struct port_input *pi) 1064122394Sharti{ 1065124861Sharti if (pi->id != NULL) 1066124861Sharti fd_deselect(pi->id); 1067124861Sharti if (pi->fd >= 0) 1068124861Sharti (void)close(pi->fd); 1069124861Sharti if (pi->buf != NULL) 1070124861Sharti free(pi->buf); 1071122394Sharti} 1072122394Sharti 1073122394Sharti/* 1074122394Sharti * Dump internal state. 1075122394Sharti */ 1076124861Sharti#ifdef USE_LIBBEGEMOT 1077122394Shartistatic void 1078124861Shartiinfo_func(void) 1079124861Sharti#else 1080124861Shartistatic void 1081122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1082124861Sharti#endif 1083122394Sharti{ 1084122394Sharti struct lmodule *m; 1085122394Sharti u_int i; 1086122394Sharti char buf[10000]; 1087122394Sharti 1088122394Sharti syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1089122394Sharti for (i = 0; i < tree_size; i++) { 1090122394Sharti switch (tree[i].type) { 1091122394Sharti 1092122394Sharti case SNMP_NODE_LEAF: 1093122394Sharti sprintf(buf, "LEAF: %s %s", tree[i].name, 1094122394Sharti asn_oid2str(&tree[i].oid)); 1095122394Sharti break; 1096122394Sharti 1097122394Sharti case SNMP_NODE_COLUMN: 1098122394Sharti sprintf(buf, "COL: %s %s", tree[i].name, 1099122394Sharti asn_oid2str(&tree[i].oid)); 1100122394Sharti break; 1101122394Sharti } 1102122394Sharti syslog(LOG_DEBUG, "%s", buf); 1103122394Sharti } 1104122394Sharti 1105122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1106122394Sharti if (m->config->dump) 1107122394Sharti (*m->config->dump)(); 1108122394Sharti} 1109122394Sharti 1110122394Sharti/* 1111122394Sharti * Re-read configuration 1112122394Sharti */ 1113124861Sharti#ifdef USE_LIBBEGEMOT 1114122394Shartistatic void 1115124861Sharticonfig_func(void) 1116124861Sharti#else 1117124861Shartistatic void 1118122394Sharticonfig_func(evContext ctx __unused, void *uap __unused, 1119122394Sharti const void *tag __unused) 1120124861Sharti#endif 1121122394Sharti{ 1122122394Sharti struct lmodule *m; 1123122394Sharti 1124122394Sharti if (read_config(config_file, NULL)) { 1125122394Sharti syslog(LOG_ERR, "error reading config file '%s'", config_file); 1126122394Sharti return; 1127122394Sharti } 1128122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1129122394Sharti if (m->config->config) 1130122394Sharti (*m->config->config)(); 1131122394Sharti} 1132122394Sharti 1133122394Sharti/* 1134122394Sharti * On USR1 dump actual configuration. 1135122394Sharti */ 1136122394Shartistatic void 1137122394Shartionusr1(int s __unused) 1138122394Sharti{ 1139124861Sharti 1140122394Sharti work |= WORK_DOINFO; 1141122394Sharti} 1142122394Shartistatic void 1143122394Shartionhup(int s __unused) 1144122394Sharti{ 1145124861Sharti 1146122394Sharti work |= WORK_RECONFIG; 1147122394Sharti} 1148122394Sharti 1149122394Shartistatic void 1150122394Shartionterm(int s __unused) 1151122394Sharti{ 1152122394Sharti 1153124861Sharti /* allow clean-up */ 1154122394Sharti exit(0); 1155122394Sharti} 1156122394Sharti 1157122394Shartistatic void 1158122394Shartiinit_sigs(void) 1159122394Sharti{ 1160122394Sharti struct sigaction sa; 1161122394Sharti 1162122394Sharti sa.sa_handler = onusr1; 1163122394Sharti sa.sa_flags = SA_RESTART; 1164122394Sharti sigemptyset(&sa.sa_mask); 1165122394Sharti if (sigaction(SIGUSR1, &sa, NULL)) { 1166122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1167122394Sharti exit(1); 1168122394Sharti } 1169122394Sharti 1170122394Sharti sa.sa_handler = onhup; 1171122394Sharti if (sigaction(SIGHUP, &sa, NULL)) { 1172122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1173122394Sharti exit(1); 1174122394Sharti } 1175122394Sharti 1176122394Sharti sa.sa_handler = onterm; 1177122394Sharti sa.sa_flags = 0; 1178122394Sharti sigemptyset(&sa.sa_mask); 1179122394Sharti if (sigaction(SIGTERM, &sa, NULL)) { 1180122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1181122394Sharti exit(1); 1182122394Sharti } 1183122394Sharti if (sigaction(SIGINT, &sa, NULL)) { 1184122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1185122394Sharti exit(1); 1186122394Sharti } 1187122394Sharti} 1188122394Sharti 1189122394Shartistatic void 1190122394Shartiblock_sigs(void) 1191122394Sharti{ 1192122394Sharti sigset_t set; 1193122394Sharti 1194122394Sharti sigfillset(&set); 1195122394Sharti if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1196122394Sharti syslog(LOG_ERR, "SIG_BLOCK: %m"); 1197122394Sharti exit(1); 1198122394Sharti } 1199122394Sharti} 1200122394Shartistatic void 1201122394Shartiunblock_sigs(void) 1202122394Sharti{ 1203122394Sharti if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1204122394Sharti syslog(LOG_ERR, "SIG_SETMASK: %m"); 1205122394Sharti exit(1); 1206122394Sharti } 1207122394Sharti} 1208122394Sharti 1209122394Sharti/* 1210122394Sharti * Shut down 1211122394Sharti */ 1212122394Shartistatic void 1213122394Shartiterm(void) 1214122394Sharti{ 1215122394Sharti (void)unlink(pid_file); 1216122394Sharti} 1217122394Sharti 1218124861Shartistatic void 1219124861Shartitrans_stop(void) 1220124861Sharti{ 1221124861Sharti struct transport *t; 1222124861Sharti 1223124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1224124861Sharti (void)t->vtab->stop(1); 1225124861Sharti} 1226124861Sharti 1227122394Sharti/* 1228122394Sharti * Define a macro from the command line 1229122394Sharti */ 1230122394Shartistatic void 1231122394Shartido_macro(char *arg) 1232122394Sharti{ 1233122394Sharti char *eq; 1234122394Sharti int err; 1235122394Sharti 1236122394Sharti if ((eq = strchr(arg, '=')) == NULL) 1237122394Sharti err = define_macro(arg, ""); 1238122394Sharti else { 1239122394Sharti *eq++ = '\0'; 1240122394Sharti err = define_macro(arg, eq); 1241122394Sharti } 1242122394Sharti if (err == -1) { 1243122394Sharti syslog(LOG_ERR, "cannot save macro: %m"); 1244122394Sharti exit(1); 1245122394Sharti } 1246122394Sharti} 1247122394Sharti 1248122394Sharti/* 1249122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken 1250122394Sharti * and will not compile with WARNS=5. 1251122394Sharti */ 1252122394Shartistatic int 1253122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1254122394Sharti{ 1255122394Sharti static const char *const delim = ",\t "; 1256122394Sharti u_int i; 1257122394Sharti char *ptr; 1258122394Sharti 1259122394Sharti *optp = NULL; 1260122394Sharti 1261122394Sharti /* skip leading junk */ 1262122394Sharti for (ptr = *arg; *ptr != '\0'; ptr++) 1263122394Sharti if (strchr(delim, *ptr) == NULL) 1264122394Sharti break; 1265122394Sharti if (*ptr == '\0') { 1266122394Sharti *arg = ptr; 1267122394Sharti return (-1); 1268122394Sharti } 1269122394Sharti *optp = ptr; 1270122394Sharti 1271122394Sharti /* find the end of the option */ 1272122394Sharti while (*++ptr != '\0') 1273122394Sharti if (strchr(delim, *ptr) != NULL || *ptr == '=') 1274122394Sharti break; 1275122394Sharti 1276122394Sharti if (*ptr != '\0') { 1277122394Sharti if (*ptr == '=') { 1278122394Sharti *ptr++ = '\0'; 1279122394Sharti *valp = ptr; 1280122394Sharti while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1281122394Sharti ptr++; 1282122394Sharti if (*ptr != '\0') 1283122394Sharti *ptr++ = '\0'; 1284122394Sharti } else 1285122394Sharti *ptr++ = '\0'; 1286122394Sharti } 1287122394Sharti 1288122394Sharti *arg = ptr; 1289122394Sharti 1290122394Sharti for (i = 0; *options != NULL; options++, i++) 1291124861Sharti if (strcmp(*optp, *options) == 0) 1292122394Sharti return (i); 1293122394Sharti return (-1); 1294122394Sharti} 1295122394Sharti 1296122394Shartiint 1297122394Shartimain(int argc, char *argv[]) 1298122394Sharti{ 1299122394Sharti int opt; 1300122394Sharti FILE *fp; 1301122394Sharti int background = 1; 1302124861Sharti struct tport *p; 1303122394Sharti const char *prefix = "snmpd"; 1304122394Sharti struct lmodule *m; 1305122394Sharti char *value, *option; 1306124861Sharti struct transport *t; 1307122394Sharti 1308122394Sharti#define DBG_DUMP 0 1309122394Sharti#define DBG_EVENTS 1 1310122394Sharti#define DBG_TRACE 2 1311122394Sharti static const char *const debug_opts[] = { 1312122394Sharti "dump", 1313122394Sharti "events", 1314122394Sharti "trace", 1315122394Sharti NULL 1316122394Sharti }; 1317122394Sharti 1318122394Sharti snmp_printf = snmp_printf_func; 1319122394Sharti snmp_error = snmp_error_func; 1320122394Sharti snmp_debug = snmp_debug_func; 1321122394Sharti asn_error = asn_error_func; 1322122394Sharti 1323122394Sharti while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1324122394Sharti switch (opt) { 1325122394Sharti 1326122394Sharti case 'c': 1327122394Sharti strlcpy(config_file, optarg, sizeof(config_file)); 1328122394Sharti break; 1329122394Sharti 1330122394Sharti case 'd': 1331122394Sharti background = 0; 1332122394Sharti break; 1333122394Sharti 1334122394Sharti case 'D': 1335122394Sharti while (*optarg) { 1336122394Sharti switch (getsubopt1(&optarg, debug_opts, 1337122394Sharti &value, &option)) { 1338122394Sharti 1339122394Sharti case DBG_DUMP: 1340122394Sharti debug.dump_pdus = 1; 1341122394Sharti break; 1342122394Sharti 1343122394Sharti case DBG_EVENTS: 1344122394Sharti debug.evdebug++; 1345122394Sharti break; 1346122394Sharti 1347122394Sharti case DBG_TRACE: 1348122394Sharti if (value == NULL) 1349122394Sharti syslog(LOG_ERR, 1350122394Sharti "no value for 'trace'"); 1351122394Sharti snmp_trace = strtoul(value, NULL, 0); 1352122394Sharti break; 1353122394Sharti 1354122394Sharti case -1: 1355122394Sharti if (suboptarg) 1356122394Sharti syslog(LOG_ERR, 1357122394Sharti "unknown debug flag '%s'", 1358122394Sharti option); 1359122394Sharti else 1360122394Sharti syslog(LOG_ERR, 1361122394Sharti "missing debug flag"); 1362122394Sharti break; 1363122394Sharti } 1364122394Sharti } 1365122394Sharti break; 1366122394Sharti 1367122394Sharti case 'h': 1368122394Sharti fprintf(stderr, "%s", usgtxt); 1369122394Sharti exit(0); 1370122394Sharti 1371122394Sharti case 'I': 1372122394Sharti syspath = optarg; 1373122394Sharti break; 1374122394Sharti 1375122394Sharti case 'l': 1376122394Sharti prefix = optarg; 1377122394Sharti break; 1378122394Sharti 1379122394Sharti case 'm': 1380122394Sharti do_macro(optarg); 1381122394Sharti break; 1382122394Sharti 1383122394Sharti case 'p': 1384122394Sharti strlcpy(pid_file, optarg, sizeof(pid_file)); 1385122394Sharti break; 1386122394Sharti } 1387122394Sharti 1388122394Sharti openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1389122394Sharti setlogmask(LOG_UPTO(debug.logpri - 1)); 1390122394Sharti 1391122394Sharti if (background && daemon(0, 0) < 0) { 1392122394Sharti syslog(LOG_ERR, "daemon: %m"); 1393122394Sharti exit(1); 1394122394Sharti } 1395122394Sharti 1396122394Sharti argc -= optind; 1397122394Sharti argv += optind; 1398122394Sharti 1399122394Sharti progargs = argv; 1400122394Sharti nprogargs = argc; 1401122394Sharti 1402122394Sharti srandomdev(); 1403122394Sharti 1404122394Sharti snmp_serial_no = random(); 1405122394Sharti 1406122394Sharti /* 1407122394Sharti * Initialize the tree. 1408122394Sharti */ 1409122394Sharti if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1410122394Sharti syslog(LOG_ERR, "%m"); 1411122394Sharti exit(1); 1412122394Sharti } 1413122394Sharti memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1414122394Sharti tree_size = CTREE_SIZE; 1415122394Sharti 1416122394Sharti /* 1417122394Sharti * Get standard communities 1418122394Sharti */ 1419122394Sharti (void)comm_define(1, "SNMP read", NULL, "public"); 1420122394Sharti (void)comm_define(2, "SNMP write", NULL, "public"); 1421122394Sharti community = COMM_INITIALIZE; 1422122394Sharti 1423122394Sharti trap_reqid = reqid_allocate(512, NULL); 1424122394Sharti 1425122394Sharti if (config_file[0] == '\0') 1426122394Sharti snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1427122394Sharti 1428122394Sharti init_actvals(); 1429124861Sharti 1430124861Sharti start_tick = get_ticks(); 1431124861Sharti this_tick = get_ticks(); 1432124861Sharti 1433124861Sharti /* start transports */ 1434124861Sharti if (atexit(trans_stop) == -1) { 1435124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1436124861Sharti exit(1); 1437124861Sharti } 1438124861Sharti if (udp_trans.start() != SNMP_ERR_NOERROR) 1439124861Sharti syslog(LOG_WARNING, "cannot start UDP transport"); 1440124861Sharti if (lsock_trans.start() != SNMP_ERR_NOERROR) 1441124861Sharti syslog(LOG_WARNING, "cannot start LSOCK transport"); 1442124861Sharti 1443122394Sharti if (read_config(config_file, NULL)) { 1444122394Sharti syslog(LOG_ERR, "error in config file"); 1445122394Sharti exit(1); 1446122394Sharti } 1447122394Sharti 1448124861Sharti#ifdef USE_LIBBEGEMOT 1449124861Sharti if (debug.evdebug > 0) 1450124861Sharti rpoll_trace = 1; 1451124861Sharti#else 1452122394Sharti if (evCreate(&evctx)) { 1453122394Sharti syslog(LOG_ERR, "evCreate: %m"); 1454122394Sharti exit(1); 1455122394Sharti } 1456122394Sharti if (debug.evdebug > 0) 1457122394Sharti evSetDebug(evctx, 10, stderr); 1458124861Sharti#endif 1459122394Sharti 1460124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1461124861Sharti TAILQ_FOREACH(p, &t->table, link) 1462124861Sharti t->vtab->init_port(p); 1463122394Sharti 1464122394Sharti init_sigs(); 1465122394Sharti 1466122394Sharti if (pid_file[0] == '\0') 1467122394Sharti snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1468122394Sharti 1469122394Sharti if ((fp = fopen(pid_file, "w")) != NULL) { 1470122394Sharti fprintf(fp, "%u", getpid()); 1471122394Sharti fclose(fp); 1472124861Sharti if (atexit(term) == -1) { 1473124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1474124861Sharti (void)remove(pid_file); 1475124861Sharti exit(0); 1476124861Sharti } 1477122394Sharti } 1478122394Sharti 1479122394Sharti if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1480122394Sharti NULL) == 0) { 1481122394Sharti syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1482122394Sharti exit(1); 1483122394Sharti } 1484122394Sharti if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1485122394Sharti NULL) == 0) { 1486122394Sharti syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1487122394Sharti exit(1); 1488122394Sharti } 1489122394Sharti 1490122394Sharti snmp_send_trap(&oid_coldStart, NULL); 1491122394Sharti 1492122394Sharti while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1493122394Sharti m->flags &= ~LM_ONSTARTLIST; 1494122394Sharti TAILQ_REMOVE(&modules_start, m, start); 1495122394Sharti lm_start(m); 1496122394Sharti } 1497122394Sharti 1498122394Sharti for (;;) { 1499124861Sharti#ifndef USE_LIBBEGEMOT 1500122394Sharti evEvent event; 1501124861Sharti#endif 1502122394Sharti struct lmodule *mod; 1503122394Sharti 1504122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 1505122394Sharti if (mod->config->idle != NULL) 1506122394Sharti (*mod->config->idle)(); 1507122394Sharti 1508124861Sharti#ifndef USE_LIBBEGEMOT 1509122394Sharti if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1510122394Sharti if (evDispatch(evctx, event)) 1511122394Sharti syslog(LOG_ERR, "evDispatch: %m"); 1512122394Sharti } else if (errno != EINTR) { 1513122394Sharti syslog(LOG_ERR, "evGetNext: %m"); 1514122394Sharti exit(1); 1515122394Sharti } 1516124861Sharti#else 1517124861Sharti poll_dispatch(1); 1518124861Sharti#endif 1519122394Sharti 1520122394Sharti if (work != 0) { 1521122394Sharti block_sigs(); 1522122394Sharti if (work & WORK_DOINFO) { 1523124861Sharti#ifdef USE_LIBBEGEMOT 1524124861Sharti info_func(); 1525124861Sharti#else 1526122394Sharti if (evWaitFor(evctx, &work, info_func, 1527122394Sharti NULL, NULL) == -1) { 1528122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1529122394Sharti exit(1); 1530122394Sharti } 1531124861Sharti#endif 1532122394Sharti } 1533122394Sharti if (work & WORK_RECONFIG) { 1534124861Sharti#ifdef USE_LIBBEGEMOT 1535124861Sharti config_func(); 1536124861Sharti#else 1537122394Sharti if (evWaitFor(evctx, &work, config_func, 1538122394Sharti NULL, NULL) == -1) { 1539122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1540122394Sharti exit(1); 1541122394Sharti } 1542124861Sharti#endif 1543122394Sharti } 1544122394Sharti work = 0; 1545122394Sharti unblock_sigs(); 1546124861Sharti#ifndef USE_LIBBEGEMOT 1547122394Sharti if (evDo(evctx, &work) == -1) { 1548122394Sharti syslog(LOG_ERR, "evDo: %m"); 1549122394Sharti exit(1); 1550122394Sharti } 1551124861Sharti#endif 1552122394Sharti } 1553122394Sharti } 1554122394Sharti 1555122394Sharti return (0); 1556122394Sharti} 1557122394Sharti 1558122394Sharti 1559122394Shartiu_int32_t 1560122394Shartiget_ticks() 1561122394Sharti{ 1562122394Sharti struct timeval tv; 1563122394Sharti u_int32_t ret; 1564122394Sharti 1565122394Sharti if (gettimeofday(&tv, NULL)) 1566122394Sharti abort(); 1567122394Sharti ret = tv.tv_sec * 100 + tv.tv_usec / 10000; 1568122394Sharti return (ret); 1569122394Sharti} 1570122394Sharti/* 1571122394Sharti * Timer support 1572122394Sharti */ 1573124861Sharti#ifdef USE_LIBBEGEMOT 1574122394Shartistatic void 1575124861Shartitfunc(int tid __unused, void *uap) 1576124861Sharti#else 1577124861Shartistatic void 1578122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1579122394Sharti struct timespec inter __unused) 1580124861Sharti#endif 1581122394Sharti{ 1582122394Sharti struct timer *tp = uap; 1583122394Sharti 1584122394Sharti LIST_REMOVE(tp, link); 1585122394Sharti tp->func(tp->udata); 1586122394Sharti free(tp); 1587122394Sharti} 1588122394Sharti 1589122394Sharti/* 1590122394Sharti * Start a timer 1591122394Sharti */ 1592122394Shartivoid * 1593122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1594122394Sharti{ 1595122394Sharti struct timer *tp; 1596124861Sharti#ifdef USE_LIBBEGEMOT 1597124861Sharti struct timeval due; 1598124861Sharti#else 1599122394Sharti struct timespec due; 1600124861Sharti#endif 1601122394Sharti 1602122394Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 1603122394Sharti syslog(LOG_CRIT, "out of memory for timer"); 1604122394Sharti exit(1); 1605122394Sharti } 1606124861Sharti#ifdef USE_LIBBEGEMOT 1607124861Sharti (void)gettimeofday(&due, NULL); 1608124861Sharti due.tv_sec += ticks / 100; 1609124861Sharti due.tv_usec += (ticks % 100) * 10000; 1610124861Sharti if (due.tv_usec >= 1000000) { 1611124861Sharti due.tv_sec++; 1612124861Sharti due.tv_usec -= 1000000; 1613124861Sharti } 1614124861Sharti#else 1615122394Sharti due = evAddTime(evNowTime(), 1616124861Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 1617124861Sharti#endif 1618122394Sharti 1619122394Sharti tp->udata = udata; 1620122394Sharti tp->owner = mod; 1621122394Sharti tp->func = func; 1622122394Sharti 1623122394Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 1624122394Sharti 1625124861Sharti#ifdef USE_LIBBEGEMOT 1626124861Sharti if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000, 1627124861Sharti 0, tfunc, tp)) < 0) { 1628124861Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1629124861Sharti exit(1); 1630124861Sharti } 1631124861Sharti#else 1632122394Sharti if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1633122394Sharti == -1) { 1634122394Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1635122394Sharti exit(1); 1636122394Sharti } 1637124861Sharti#endif 1638122394Sharti return (tp); 1639122394Sharti} 1640122394Sharti 1641122394Shartivoid 1642122394Shartitimer_stop(void *p) 1643122394Sharti{ 1644122394Sharti struct timer *tp = p; 1645122394Sharti 1646122394Sharti LIST_REMOVE(tp, link); 1647124861Sharti#ifdef USE_LIBBEGEMOT 1648124861Sharti poll_stop_timer(tp->id); 1649124861Sharti#else 1650122394Sharti if (evClearTimer(evctx, tp->id) == -1) { 1651122394Sharti syslog(LOG_ERR, "cannot stop timer: %m"); 1652122394Sharti exit(1); 1653122394Sharti } 1654124861Sharti#endif 1655122394Sharti free(p); 1656122394Sharti} 1657122394Sharti 1658122394Shartistatic void 1659122394Shartitimer_flush(struct lmodule *mod) 1660122394Sharti{ 1661122394Sharti struct timer *t, *t1; 1662122394Sharti 1663122394Sharti t = LIST_FIRST(&timer_list); 1664122394Sharti while (t != NULL) { 1665122394Sharti t1 = LIST_NEXT(t, link); 1666122394Sharti if (t->owner == mod) 1667122394Sharti timer_stop(t); 1668122394Sharti t = t1; 1669122394Sharti } 1670122394Sharti} 1671122394Sharti 1672122394Shartistatic void 1673122394Shartisnmp_printf_func(const char *fmt, ...) 1674122394Sharti{ 1675122394Sharti va_list ap; 1676122394Sharti static char *pend = NULL; 1677122394Sharti char *ret, *new; 1678122394Sharti 1679122394Sharti va_start(ap, fmt); 1680122394Sharti vasprintf(&ret, fmt, ap); 1681122394Sharti va_end(ap); 1682122394Sharti 1683122394Sharti if (ret == NULL) 1684122394Sharti return; 1685122394Sharti if (pend != NULL) { 1686122394Sharti if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1687122394Sharti == NULL) { 1688122394Sharti free(ret); 1689122394Sharti return; 1690122394Sharti } 1691122394Sharti pend = new; 1692122394Sharti strcat(pend, ret); 1693122394Sharti free(ret); 1694122394Sharti } else 1695122394Sharti pend = ret; 1696122394Sharti 1697122394Sharti while ((ret = strchr(pend, '\n')) != NULL) { 1698122394Sharti *ret = '\0'; 1699122394Sharti syslog(LOG_DEBUG, "%s", pend); 1700122394Sharti if (strlen(ret + 1) == 0) { 1701122394Sharti free(pend); 1702122394Sharti pend = NULL; 1703122394Sharti break; 1704122394Sharti } 1705122394Sharti strcpy(pend, ret + 1); 1706122394Sharti } 1707122394Sharti} 1708122394Sharti 1709122394Shartistatic void 1710122394Shartisnmp_error_func(const char *err, ...) 1711122394Sharti{ 1712122394Sharti char errbuf[1000]; 1713122394Sharti va_list ap; 1714122394Sharti 1715124861Sharti if (!(snmp_trace & LOG_SNMP_ERRORS)) 1716124861Sharti return; 1717124861Sharti 1718122394Sharti va_start(ap, err); 1719122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1720124861Sharti vsnprintf(errbuf + strlen(errbuf), 1721124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 1722122394Sharti va_end(ap); 1723122394Sharti 1724122394Sharti syslog(LOG_ERR, "%s", errbuf); 1725122394Sharti} 1726122394Sharti 1727122394Shartistatic void 1728122394Shartisnmp_debug_func(const char *err, ...) 1729122394Sharti{ 1730122394Sharti char errbuf[1000]; 1731122394Sharti va_list ap; 1732122394Sharti 1733122394Sharti va_start(ap, err); 1734122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1735122394Sharti vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1736122394Sharti err, ap); 1737122394Sharti va_end(ap); 1738122394Sharti 1739122394Sharti syslog(LOG_DEBUG, "%s", errbuf); 1740122394Sharti} 1741122394Sharti 1742122394Shartistatic void 1743122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...) 1744122394Sharti{ 1745122394Sharti char errbuf[1000]; 1746122394Sharti va_list ap; 1747122394Sharti u_int i; 1748122394Sharti 1749124861Sharti if (!(snmp_trace & LOG_ASN1_ERRORS)) 1750124861Sharti return; 1751124861Sharti 1752122394Sharti va_start(ap, err); 1753122394Sharti snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 1754124861Sharti vsnprintf(errbuf + strlen(errbuf), 1755124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 1756122394Sharti va_end(ap); 1757122394Sharti 1758122394Sharti if (b != NULL) { 1759124861Sharti snprintf(errbuf + strlen(errbuf), 1760124861Sharti sizeof(errbuf) - strlen(errbuf), " at"); 1761122394Sharti for (i = 0; b->asn_len > i; i++) 1762124861Sharti snprintf(errbuf + strlen(errbuf), 1763124861Sharti sizeof(errbuf) - strlen(errbuf), 1764124861Sharti " %02x", b->asn_cptr[i]); 1765122394Sharti } 1766122394Sharti 1767122394Sharti syslog(LOG_ERR, "%s", errbuf); 1768122394Sharti} 1769122394Sharti 1770122394Sharti/* 1771122394Sharti * Create a new community 1772122394Sharti */ 1773122394Shartiu_int 1774122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner, 1775122394Sharti const char *str) 1776122394Sharti{ 1777122394Sharti struct community *c, *p; 1778122394Sharti u_int ncomm; 1779122394Sharti 1780122394Sharti /* generate an identifier */ 1781122394Sharti do { 1782122394Sharti if ((ncomm = next_community_index++) == UINT_MAX) 1783122394Sharti next_community_index = 1; 1784122394Sharti TAILQ_FOREACH(c, &community_list, link) 1785122394Sharti if (c->value == ncomm) 1786122394Sharti break; 1787122394Sharti } while (c != NULL); 1788122394Sharti 1789122394Sharti if ((c = malloc(sizeof(struct community))) == NULL) { 1790122394Sharti syslog(LOG_ERR, "comm_define: %m"); 1791122394Sharti return (0); 1792122394Sharti } 1793122394Sharti c->owner = owner; 1794122394Sharti c->value = ncomm; 1795122394Sharti c->descr = descr; 1796122394Sharti c->string = NULL; 1797122394Sharti c->private = priv; 1798122394Sharti 1799122394Sharti if (str != NULL) { 1800122394Sharti if((c->string = malloc(strlen(str)+1)) == NULL) { 1801122394Sharti free(c); 1802122394Sharti return (0); 1803122394Sharti } 1804122394Sharti strcpy(c->string, str); 1805122394Sharti } 1806122394Sharti 1807122394Sharti /* make index */ 1808122394Sharti if (c->owner == NULL) { 1809122394Sharti c->index.len = 1; 1810122394Sharti c->index.subs[0] = 0; 1811122394Sharti } else { 1812122394Sharti c->index = c->owner->index; 1813122394Sharti } 1814122394Sharti c->index.subs[c->index.len++] = c->private; 1815122394Sharti 1816122394Sharti /* 1817122394Sharti * Insert ordered 1818122394Sharti */ 1819122394Sharti TAILQ_FOREACH(p, &community_list, link) { 1820122394Sharti if (asn_compare_oid(&p->index, &c->index) > 0) { 1821122394Sharti TAILQ_INSERT_BEFORE(p, c, link); 1822122394Sharti break; 1823122394Sharti } 1824122394Sharti } 1825122394Sharti if (p == NULL) 1826122394Sharti TAILQ_INSERT_TAIL(&community_list, c, link); 1827122394Sharti return (c->value); 1828122394Sharti} 1829122394Sharti 1830122394Sharticonst char * 1831122394Sharticomm_string(u_int ncomm) 1832122394Sharti{ 1833122394Sharti struct community *p; 1834122394Sharti 1835122394Sharti TAILQ_FOREACH(p, &community_list, link) 1836122394Sharti if (p->value == ncomm) 1837122394Sharti return (p->string); 1838122394Sharti return (NULL); 1839122394Sharti} 1840122394Sharti 1841122394Sharti/* 1842122394Sharti * Delete all communities allocated by a module 1843122394Sharti */ 1844122394Shartistatic void 1845122394Sharticomm_flush(struct lmodule *mod) 1846122394Sharti{ 1847122394Sharti struct community *p, *p1; 1848122394Sharti 1849122394Sharti p = TAILQ_FIRST(&community_list); 1850122394Sharti while (p != NULL) { 1851122394Sharti p1 = TAILQ_NEXT(p, link); 1852122394Sharti if (p->owner == mod) { 1853122394Sharti free(p->string); 1854122394Sharti TAILQ_REMOVE(&community_list, p, link); 1855122394Sharti free(p); 1856122394Sharti } 1857122394Sharti p = p1; 1858122394Sharti } 1859122394Sharti} 1860122394Sharti 1861122394Sharti/* 1862122394Sharti * Request ID handling. 1863122394Sharti * 1864122394Sharti * Allocate a new range of request ids. Use a first fit algorithm. 1865122394Sharti */ 1866122394Shartiu_int 1867122394Shartireqid_allocate(int size, struct lmodule *mod) 1868122394Sharti{ 1869122394Sharti u_int type; 1870122394Sharti struct idrange *r, *r1; 1871122394Sharti 1872122394Sharti if (size <= 0 || size > INT32_MAX) { 1873122394Sharti syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1874122394Sharti return (0); 1875122394Sharti } 1876122394Sharti /* allocate a type id */ 1877122394Sharti do { 1878122394Sharti if ((type = next_idrange++) == UINT_MAX) 1879122394Sharti next_idrange = 1; 1880122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1881122394Sharti if (r->type == type) 1882122394Sharti break; 1883122394Sharti } while(r != NULL); 1884122394Sharti 1885122394Sharti /* find a range */ 1886122394Sharti if (TAILQ_EMPTY(&idrange_list)) 1887122394Sharti r = NULL; 1888122394Sharti else { 1889122394Sharti r = TAILQ_FIRST(&idrange_list); 1890122394Sharti if (r->base < size) { 1891122394Sharti while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1892122394Sharti if (r1->base - (r->base + r->size) >= size) 1893122394Sharti break; 1894122394Sharti r = r1; 1895122394Sharti } 1896122394Sharti r = r1; 1897122394Sharti } 1898122394Sharti if (r == NULL) { 1899122394Sharti r1 = TAILQ_LAST(&idrange_list, idrange_list); 1900122394Sharti if (INT32_MAX - size + 1 < r1->base + r1->size) { 1901122394Sharti syslog(LOG_ERR, "out of id ranges (%u)", size); 1902122394Sharti return (0); 1903122394Sharti } 1904122394Sharti } 1905122394Sharti } 1906122394Sharti 1907122394Sharti /* allocate structure */ 1908122394Sharti if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 1909122394Sharti syslog(LOG_ERR, "%s: %m", __FUNCTION__); 1910122394Sharti return (0); 1911122394Sharti } 1912122394Sharti 1913122394Sharti r1->type = type; 1914122394Sharti r1->size = size; 1915122394Sharti r1->owner = mod; 1916122394Sharti if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 1917122394Sharti r1->base = 0; 1918122394Sharti TAILQ_INSERT_HEAD(&idrange_list, r1, link); 1919122394Sharti } else if (r == NULL) { 1920122394Sharti r = TAILQ_LAST(&idrange_list, idrange_list); 1921122394Sharti r1->base = r->base + r->size; 1922122394Sharti TAILQ_INSERT_TAIL(&idrange_list, r1, link); 1923122394Sharti } else { 1924122394Sharti r = TAILQ_PREV(r, idrange_list, link); 1925122394Sharti r1->base = r->base + r->size; 1926122394Sharti TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 1927122394Sharti } 1928122394Sharti r1->next = r1->base; 1929122394Sharti 1930122394Sharti return (type); 1931122394Sharti} 1932122394Sharti 1933122394Shartiint32_t 1934122394Shartireqid_next(u_int type) 1935122394Sharti{ 1936122394Sharti struct idrange *r; 1937122394Sharti int32_t id; 1938122394Sharti 1939122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1940122394Sharti if (r->type == type) 1941122394Sharti break; 1942122394Sharti if (r == NULL) { 1943122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 1944122394Sharti abort(); 1945122394Sharti } 1946122394Sharti if ((id = r->next++) == r->base + (r->size - 1)) 1947122394Sharti r->next = r->base; 1948122394Sharti return (id); 1949122394Sharti} 1950122394Sharti 1951122394Shartiint32_t 1952122394Shartireqid_base(u_int type) 1953122394Sharti{ 1954122394Sharti struct idrange *r; 1955122394Sharti 1956122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1957122394Sharti if (r->type == type) 1958122394Sharti return (r->base); 1959122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 1960122394Sharti abort(); 1961122394Sharti} 1962122394Sharti 1963122394Shartiu_int 1964122394Shartireqid_type(int32_t reqid) 1965122394Sharti{ 1966122394Sharti struct idrange *r; 1967122394Sharti 1968122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1969122394Sharti if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 1970122394Sharti return (r->type); 1971122394Sharti return (0); 1972122394Sharti} 1973122394Sharti 1974122394Shartiint 1975122394Shartireqid_istype(int32_t reqid, u_int type) 1976122394Sharti{ 1977122394Sharti return (reqid_type(reqid) == type); 1978122394Sharti} 1979122394Sharti 1980122394Sharti/* 1981122394Sharti * Delete all communities allocated by a module 1982122394Sharti */ 1983122394Shartistatic void 1984122394Shartireqid_flush(struct lmodule *mod) 1985122394Sharti{ 1986122394Sharti struct idrange *p, *p1; 1987122394Sharti 1988122394Sharti p = TAILQ_FIRST(&idrange_list); 1989122394Sharti while (p != NULL) { 1990122394Sharti p1 = TAILQ_NEXT(p, link); 1991122394Sharti if (p->owner == mod) { 1992122394Sharti TAILQ_REMOVE(&idrange_list, p, link); 1993122394Sharti free(p); 1994122394Sharti } 1995122394Sharti p = p1; 1996122394Sharti } 1997122394Sharti} 1998122394Sharti 1999122394Sharti/* 2000122394Sharti * Merge the given tree for the given module into the main tree. 2001122394Sharti */ 2002122394Shartistatic int 2003122394Sharticompare_node(const void *v1, const void *v2) 2004122394Sharti{ 2005122394Sharti const struct snmp_node *n1 = v1; 2006122394Sharti const struct snmp_node *n2 = v2; 2007122394Sharti 2008122394Sharti return (asn_compare_oid(&n1->oid, &n2->oid)); 2009122394Sharti} 2010122394Shartistatic int 2011122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2012122394Sharti{ 2013122394Sharti struct snmp_node *xtree; 2014122394Sharti u_int i; 2015122394Sharti 2016122394Sharti xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2017122394Sharti if (xtree == NULL) { 2018128237Sharti syslog(LOG_ERR, "tree_merge: %m"); 2019122394Sharti return (-1); 2020122394Sharti } 2021122394Sharti tree = xtree; 2022122394Sharti memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2023122394Sharti 2024122394Sharti for (i = 0; i < nsize; i++) 2025128237Sharti tree[tree_size + i].tree_data = mod; 2026122394Sharti 2027122394Sharti tree_size += nsize; 2028122394Sharti 2029122394Sharti qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2030122394Sharti 2031122394Sharti return (0); 2032122394Sharti} 2033122394Sharti 2034122394Sharti/* 2035122394Sharti * Remove all nodes belonging to the loadable module 2036122394Sharti */ 2037122394Shartistatic void 2038122394Shartitree_unmerge(struct lmodule *mod) 2039122394Sharti{ 2040122394Sharti u_int s, d; 2041122394Sharti 2042122394Sharti for(s = d = 0; s < tree_size; s++) 2043128237Sharti if (tree[s].tree_data != mod) { 2044122394Sharti if (s != d) 2045122394Sharti tree[d] = tree[s]; 2046122394Sharti d++; 2047122394Sharti } 2048122394Sharti tree_size = d; 2049122394Sharti} 2050122394Sharti 2051122394Sharti/* 2052122394Sharti * Loadable modules 2053122394Sharti */ 2054122394Shartistruct lmodule * 2055122394Shartilm_load(const char *path, const char *section) 2056122394Sharti{ 2057122394Sharti struct lmodule *m; 2058122394Sharti int err; 2059122394Sharti int i; 2060122394Sharti char *av[MAX_MOD_ARGS + 1]; 2061122394Sharti int ac; 2062122394Sharti u_int u; 2063122394Sharti 2064122394Sharti if ((m = malloc(sizeof(*m))) == NULL) { 2065122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2066122394Sharti return (NULL); 2067122394Sharti } 2068122394Sharti m->handle = NULL; 2069122394Sharti m->flags = 0; 2070122394Sharti strcpy(m->section, section); 2071122394Sharti 2072122394Sharti if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2073122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2074122394Sharti goto err; 2075122394Sharti } 2076122394Sharti strcpy(m->path, path); 2077122394Sharti 2078122394Sharti /* 2079122394Sharti * Make index 2080122394Sharti */ 2081122394Sharti m->index.subs[0] = strlen(section); 2082122394Sharti m->index.len = m->index.subs[0] + 1; 2083122394Sharti for (u = 0; u < m->index.subs[0]; u++) 2084122394Sharti m->index.subs[u + 1] = section[u]; 2085122394Sharti 2086122394Sharti /* 2087122394Sharti * Load the object file and locate the config structure 2088122394Sharti */ 2089122394Sharti if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2090122394Sharti syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2091122394Sharti goto err; 2092122394Sharti } 2093122394Sharti 2094122394Sharti if ((m->config = dlsym(m->handle, "config")) == NULL) { 2095122394Sharti syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2096122394Sharti goto err; 2097122394Sharti } 2098122394Sharti 2099122394Sharti /* 2100122394Sharti * Insert it into the right place 2101122394Sharti */ 2102122394Sharti INSERT_OBJECT_OID(m, &lmodules); 2103122394Sharti 2104122394Sharti /* preserve order */ 2105122394Sharti if (community == COMM_INITIALIZE) { 2106122394Sharti m->flags |= LM_ONSTARTLIST; 2107122394Sharti TAILQ_INSERT_TAIL(&modules_start, m, start); 2108122394Sharti } 2109122394Sharti 2110122394Sharti /* 2111122394Sharti * make the argument vector. 2112122394Sharti */ 2113122394Sharti ac = 0; 2114122394Sharti for (i = 0; i < nprogargs; i++) { 2115122394Sharti if (strlen(progargs[i]) >= strlen(section) + 1 && 2116122394Sharti strncmp(progargs[i], section, strlen(section)) == 0 && 2117122394Sharti progargs[i][strlen(section)] == ':') { 2118122394Sharti if (ac == MAX_MOD_ARGS) { 2119122394Sharti syslog(LOG_WARNING, "too many arguments for " 2120122394Sharti "module '%s", section); 2121122394Sharti break; 2122122394Sharti } 2123122394Sharti av[ac++] = &progargs[i][strlen(section)+1]; 2124122394Sharti } 2125122394Sharti } 2126122394Sharti av[ac] = NULL; 2127122394Sharti 2128122394Sharti /* 2129122394Sharti * Run the initialisation function 2130122394Sharti */ 2131122394Sharti if ((err = (*m->config->init)(m, ac, av)) != 0) { 2132122394Sharti syslog(LOG_ERR, "lm_load: init failed: %d", err); 2133122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2134122394Sharti goto err; 2135122394Sharti } 2136122394Sharti 2137122394Sharti return (m); 2138122394Sharti 2139122394Sharti err: 2140122394Sharti if (m->handle) 2141122394Sharti dlclose(m->handle); 2142122394Sharti free(m->path); 2143122394Sharti free(m); 2144122394Sharti return (NULL); 2145122394Sharti} 2146122394Sharti 2147122394Sharti/* 2148122394Sharti * Start a module 2149122394Sharti */ 2150122394Shartivoid 2151122394Shartilm_start(struct lmodule *mod) 2152122394Sharti{ 2153122394Sharti const struct lmodule *m; 2154122394Sharti 2155122394Sharti /* 2156122394Sharti * Merge tree. If this fails, unload the module. 2157122394Sharti */ 2158122394Sharti if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2159122394Sharti lm_unload(mod); 2160122394Sharti return; 2161122394Sharti } 2162122394Sharti 2163122394Sharti /* 2164122394Sharti * Read configuration 2165122394Sharti */ 2166122394Sharti if (read_config(config_file, mod)) { 2167122394Sharti syslog(LOG_ERR, "error in config file"); 2168122394Sharti lm_unload(mod); 2169122394Sharti return; 2170122394Sharti } 2171122394Sharti if (mod->config->start) 2172122394Sharti (*mod->config->start)(); 2173122394Sharti 2174122394Sharti mod->flags |= LM_STARTED; 2175122394Sharti 2176122394Sharti /* 2177122394Sharti * Inform other modules 2178122394Sharti */ 2179122394Sharti TAILQ_FOREACH(m, &lmodules, link) 2180122394Sharti if (m->config->loading) 2181122394Sharti (*m->config->loading)(mod, 1); 2182122394Sharti} 2183122394Sharti 2184122394Sharti 2185122394Sharti/* 2186122394Sharti * Unload a module. 2187122394Sharti */ 2188122394Shartivoid 2189122394Shartilm_unload(struct lmodule *m) 2190122394Sharti{ 2191122394Sharti int err; 2192122394Sharti const struct lmodule *mod; 2193122394Sharti 2194122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2195122394Sharti if (m->flags & LM_ONSTARTLIST) 2196122394Sharti TAILQ_REMOVE(&modules_start, m, start); 2197122394Sharti tree_unmerge(m); 2198122394Sharti 2199122394Sharti if ((m->flags & LM_STARTED) && m->config->fini && 2200122394Sharti (err = (*m->config->fini)()) != 0) 2201122394Sharti syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2202122394Sharti 2203122394Sharti comm_flush(m); 2204122394Sharti reqid_flush(m); 2205122394Sharti timer_flush(m); 2206122394Sharti fd_flush(m); 2207122394Sharti 2208122394Sharti dlclose(m->handle); 2209122394Sharti free(m->path); 2210122394Sharti 2211122394Sharti /* 2212122394Sharti * Inform other modules 2213122394Sharti */ 2214122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 2215122394Sharti if (mod->config->loading) 2216122394Sharti (*mod->config->loading)(m, 0); 2217122394Sharti 2218122394Sharti free(m); 2219122394Sharti} 2220122394Sharti 2221122394Sharti/* 2222122394Sharti * Register an object resource and return the index (or 0 on failures) 2223122394Sharti */ 2224122394Shartiu_int 2225122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2226122394Sharti{ 2227122394Sharti struct objres *objres, *or1; 2228122394Sharti u_int idx; 2229122394Sharti 2230122394Sharti /* find a free index */ 2231122394Sharti idx = 1; 2232122394Sharti for (objres = TAILQ_FIRST(&objres_list); 2233122394Sharti objres != NULL; 2234122394Sharti objres = TAILQ_NEXT(objres, link)) { 2235122394Sharti if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2236122394Sharti or1->index > objres->index + 1) { 2237122394Sharti idx = objres->index + 1; 2238122394Sharti break; 2239122394Sharti } 2240122394Sharti } 2241122394Sharti 2242122394Sharti if ((objres = malloc(sizeof(*objres))) == NULL) 2243122394Sharti return (0); 2244122394Sharti 2245122394Sharti objres->index = idx; 2246122394Sharti objres->oid = *or; 2247122394Sharti strlcpy(objres->descr, descr, sizeof(objres->descr)); 2248122394Sharti objres->uptime = get_ticks() - start_tick; 2249122394Sharti objres->module = mod; 2250122394Sharti 2251122394Sharti INSERT_OBJECT_INT(objres, &objres_list); 2252122394Sharti 2253122394Sharti systemg.or_last_change = objres->uptime; 2254122394Sharti 2255122394Sharti return (idx); 2256122394Sharti} 2257122394Sharti 2258122394Shartivoid 2259122394Shartior_unregister(u_int idx) 2260122394Sharti{ 2261122394Sharti struct objres *objres; 2262122394Sharti 2263122394Sharti TAILQ_FOREACH(objres, &objres_list, link) 2264122394Sharti if (objres->index == idx) { 2265122394Sharti TAILQ_REMOVE(&objres_list, objres, link); 2266122394Sharti free(objres); 2267122394Sharti return; 2268122394Sharti } 2269122394Sharti} 2270