main.c revision 145557
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> 7133211Sharti * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 14122394Sharti * notice, this list of conditions and the following disclaimer in the 15122394Sharti * documentation and/or other materials provided with the distribution. 16133211Sharti * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28122394Sharti * 29145557Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.91 2005/04/22 12:18:14 brandt_h Exp $ 30122394Sharti * 31122394Sharti * SNMPd main stuff. 32122394Sharti */ 33122394Sharti#include <sys/param.h> 34122394Sharti#include <sys/un.h> 35124861Sharti#include <sys/ucred.h> 36122394Sharti#include <stdio.h> 37122394Sharti#include <stdlib.h> 38122394Sharti#include <stddef.h> 39122394Sharti#include <string.h> 40122394Sharti#include <stdarg.h> 41122394Sharti#include <ctype.h> 42122394Sharti#include <errno.h> 43122394Sharti#include <syslog.h> 44122394Sharti#include <unistd.h> 45122394Sharti#include <signal.h> 46122394Sharti#include <dlfcn.h> 47122394Sharti#include <inttypes.h> 48122394Sharti 49145557Sharti#ifdef USE_TCPWRAPPERS 50145557Sharti#include <arpa/inet.h> 51145557Sharti#include <tcpd.h> 52145557Sharti#endif 53145557Sharti 54122394Sharti#include "snmpmod.h" 55122394Sharti#include "snmpd.h" 56122394Sharti#include "tree.h" 57122394Sharti#include "oid.h" 58122394Sharti 59122394Sharti#define PATH_PID "/var/run/%s.pid" 60122394Sharti#define PATH_CONFIG "/etc/%s.config" 61122394Sharti 62122394Shartiu_int32_t this_tick; /* start of processing of current packet */ 63122394Shartiu_int32_t start_tick; /* start of processing */ 64122394Sharti 65122394Shartistruct systemg systemg = { 66122394Sharti NULL, 67122394Sharti { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 68122394Sharti NULL, NULL, NULL, 69122394Sharti 64 + 8 + 4, 70122394Sharti 0 71122394Sharti}; 72122394Shartistruct debug debug = { 73122394Sharti 0, /* dump_pdus */ 74122394Sharti LOG_DEBUG, /* log_pri */ 75122394Sharti 0, /* evdebug */ 76122394Sharti}; 77122394Sharti 78122394Shartistruct snmpd snmpd = { 79122394Sharti 2048, /* txbuf */ 80122394Sharti 2048, /* rxbuf */ 81122394Sharti 0, /* comm_dis */ 82122394Sharti 0, /* auth_traps */ 83122394Sharti {0, 0, 0, 0}, /* trap1addr */ 84124861Sharti VERS_ENABLE_ALL,/* version_enable */ 85122394Sharti}; 86122394Shartistruct snmpd_stats snmpd_stats; 87122394Sharti 88122394Sharti/* snmpSerialNo */ 89122394Shartiint32_t snmp_serial_no; 90122394Sharti 91122394Sharti/* search path for config files */ 92122394Sharticonst char *syspath = PATH_SYSCONFIG; 93122394Sharti 94122394Sharti/* list of all loaded modules */ 95122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 96122394Sharti 97122394Sharti/* list of loaded modules during start-up in the order they were loaded */ 98122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 99122394Sharti 100122394Sharti/* list of all known communities */ 101122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 102122394Sharti 103122394Sharti/* list of all installed object resources */ 104122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 105122394Sharti 106122394Sharti/* community value generator */ 107122394Shartistatic u_int next_community_index = 1; 108122394Sharti 109122394Sharti/* list of all known ranges */ 110122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 111122394Sharti 112122394Sharti/* identifier generator */ 113122394Shartiu_int next_idrange = 1; 114122394Sharti 115122394Sharti/* list of all current timers */ 116122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 117122394Sharti 118122394Sharti/* list of file descriptors */ 119122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 120122394Sharti 121122394Sharti/* program arguments */ 122122394Shartistatic char **progargs; 123122394Shartistatic int nprogargs; 124122394Sharti 125122394Sharti/* current community */ 126122394Shartiu_int community; 127122394Shartistatic struct community *comm; 128122394Sharti 129122394Sharti/* file names */ 130122394Shartistatic char config_file[MAXPATHLEN + 1]; 131122394Shartistatic char pid_file[MAXPATHLEN + 1]; 132122394Sharti 133124861Sharti#ifndef USE_LIBBEGEMOT 134122394Sharti/* event context */ 135122394Shartistatic evContext evctx; 136124861Sharti#endif 137122394Sharti 138122394Sharti/* signal mask */ 139122394Shartistatic sigset_t blocked_sigs; 140122394Sharti 141122394Sharti/* signal handling */ 142122394Shartistatic int work; 143122394Sharti#define WORK_DOINFO 0x0001 144122394Sharti#define WORK_RECONFIG 0x0002 145122394Sharti 146122394Sharti/* oids */ 147122394Shartistatic const struct asn_oid 148122394Sharti oid_snmpMIB = OIDX_snmpMIB, 149122394Sharti oid_begemotSnmpd = OIDX_begemotSnmpd, 150122394Sharti oid_coldStart = OIDX_coldStart, 151122394Sharti oid_authenticationFailure = OIDX_authenticationFailure; 152122394Sharti 153122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 154122394Sharti 155122394Sharti/* request id generator for traps */ 156122394Shartiu_int trap_reqid; 157122394Sharti 158122394Sharti/* help text */ 159122394Shartistatic const char usgtxt[] = "\ 160122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 161122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 162122394Shartiusage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 163122394Sharti [-m variable=value] [-p file]\n\ 164122394Shartioptions:\n\ 165122394Sharti -d don't daemonize\n\ 166122394Sharti -h print this info\n\ 167122394Sharti -c file specify configuration file\n\ 168122394Sharti -D options debugging options\n\ 169122394Sharti -I path system include path\n\ 170122394Sharti -l prefix default basename for pid and config file\n\ 171122394Sharti -m var=val define variable\n\ 172122394Sharti -p file specify pid file\n\ 173122394Sharti"; 174122394Sharti 175145557Sharti/* hosts_access(3) request */ 176145557Sharti#ifdef USE_TCPWRAPPERS 177145557Shartistatic struct request_info req; 178145557Sharti#endif 179145557Sharti 180124861Sharti/* transports */ 181124861Shartiextern const struct transport_def udp_trans; 182124861Shartiextern const struct transport_def lsock_trans; 183124861Sharti 184124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 185124861Sharti 186122394Sharti/* forward declarations */ 187122394Shartistatic void snmp_printf_func(const char *fmt, ...); 188122394Shartistatic void snmp_error_func(const char *err, ...); 189122394Shartistatic void snmp_debug_func(const char *err, ...); 190122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...); 191122394Sharti 192122394Sharti/* 193122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx. 194122394Sharti */ 195122394Shartivoid * 196122394Shartibuf_alloc(int tx) 197122394Sharti{ 198122394Sharti void *buf; 199122394Sharti 200124861Sharti if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 201122394Sharti syslog(LOG_CRIT, "cannot allocate buffer"); 202122394Sharti if (tx) 203122394Sharti snmpd_stats.noTxbuf++; 204122394Sharti else 205122394Sharti snmpd_stats.noRxbuf++; 206122394Sharti return (NULL); 207122394Sharti } 208122394Sharti return (buf); 209122394Sharti} 210122394Sharti 211122394Sharti/* 212124861Sharti * Return the buffer size. 213122394Sharti */ 214122394Shartisize_t 215122394Shartibuf_size(int tx) 216122394Sharti{ 217124861Sharti return (tx ? snmpd.txbuf : snmpd.rxbuf); 218122394Sharti} 219122394Sharti 220122394Sharti/* 221122394Sharti * Prepare a PDU for output 222122394Sharti */ 223122394Shartivoid 224124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 225122394Sharti const char *dest) 226122394Sharti{ 227122394Sharti struct asn_buf resp_b; 228122394Sharti 229122394Sharti resp_b.asn_ptr = sndbuf; 230122394Sharti resp_b.asn_len = snmpd.txbuf; 231122394Sharti 232122394Sharti if (snmp_pdu_encode(pdu, &resp_b) != 0) { 233122394Sharti syslog(LOG_ERR, "cannot encode message"); 234122394Sharti abort(); 235122394Sharti } 236122394Sharti if (debug.dump_pdus) { 237122394Sharti snmp_printf("%s <- ", dest); 238122394Sharti snmp_pdu_dump(pdu); 239122394Sharti } 240122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 241122394Sharti} 242122394Sharti 243122394Sharti/* 244122394Sharti * SNMP input. Start: decode the PDU, find the community. 245122394Sharti */ 246122394Shartienum snmpd_input_err 247122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source, 248124861Sharti struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 249122394Sharti{ 250122394Sharti struct asn_buf b; 251122394Sharti enum snmp_code code; 252122394Sharti enum snmpd_input_err ret; 253124861Sharti int sret; 254122394Sharti 255122394Sharti b.asn_cptr = buf; 256122394Sharti b.asn_len = len; 257124861Sharti 258124861Sharti /* look whether we have enough bytes for the entire PDU. */ 259124861Sharti switch (sret = snmp_pdu_snoop(&b)) { 260124861Sharti 261124861Sharti case 0: 262124861Sharti return (SNMPD_INPUT_TRUNC); 263124861Sharti 264124861Sharti case -1: 265124861Sharti snmpd_stats.inASNParseErrs++; 266124861Sharti return (SNMPD_INPUT_FAILED); 267124861Sharti } 268124861Sharti b.asn_len = *pdulen = (size_t)sret; 269124861Sharti 270122394Sharti code = snmp_pdu_decode(&b, pdu, ip); 271122394Sharti 272124861Sharti snmpd_stats.inPkts++; 273124861Sharti 274122394Sharti ret = SNMPD_INPUT_OK; 275122394Sharti switch (code) { 276122394Sharti 277122394Sharti case SNMP_CODE_FAILED: 278122394Sharti snmpd_stats.inASNParseErrs++; 279122394Sharti return (SNMPD_INPUT_FAILED); 280122394Sharti 281122394Sharti case SNMP_CODE_BADVERS: 282124861Sharti bad_vers: 283122394Sharti snmpd_stats.inBadVersions++; 284122394Sharti return (SNMPD_INPUT_FAILED); 285122394Sharti 286122394Sharti case SNMP_CODE_BADLEN: 287122394Sharti if (pdu->type == SNMP_OP_SET) 288122394Sharti ret = SNMPD_INPUT_VALBADLEN; 289122394Sharti break; 290122394Sharti 291122394Sharti case SNMP_CODE_OORANGE: 292122394Sharti if (pdu->type == SNMP_OP_SET) 293122394Sharti ret = SNMPD_INPUT_VALRANGE; 294122394Sharti break; 295122394Sharti 296122394Sharti case SNMP_CODE_BADENC: 297122394Sharti if (pdu->type == SNMP_OP_SET) 298122394Sharti ret = SNMPD_INPUT_VALBADENC; 299122394Sharti break; 300122394Sharti 301122394Sharti case SNMP_CODE_OK: 302124861Sharti switch (pdu->version) { 303124861Sharti 304124861Sharti case SNMP_V1: 305124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V1)) 306124861Sharti goto bad_vers; 307124861Sharti break; 308124861Sharti 309124861Sharti case SNMP_V2c: 310124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 311124861Sharti goto bad_vers; 312124861Sharti break; 313124861Sharti 314124861Sharti case SNMP_Verr: 315124861Sharti goto bad_vers; 316124861Sharti } 317122394Sharti break; 318122394Sharti } 319122394Sharti 320122394Sharti if (debug.dump_pdus) { 321122394Sharti snmp_printf("%s -> ", source); 322122394Sharti snmp_pdu_dump(pdu); 323122394Sharti } 324122394Sharti 325122394Sharti /* 326122394Sharti * Look, whether we know the community 327122394Sharti */ 328122394Sharti TAILQ_FOREACH(comm, &community_list, link) 329122394Sharti if (comm->string != NULL && 330122394Sharti strcmp(comm->string, pdu->community) == 0) 331122394Sharti break; 332122394Sharti 333122394Sharti if (comm == NULL) { 334122394Sharti snmpd_stats.inBadCommunityNames++; 335122394Sharti snmp_pdu_free(pdu); 336122394Sharti if (snmpd.auth_traps) 337133211Sharti snmp_send_trap(&oid_authenticationFailure, 338133211Sharti (struct snmp_value *)NULL); 339133211Sharti ret = SNMPD_INPUT_BAD_COMM; 340133211Sharti } else 341133211Sharti community = comm->value; 342122394Sharti 343122394Sharti /* update uptime */ 344122394Sharti this_tick = get_ticks(); 345122394Sharti 346122394Sharti return (ret); 347122394Sharti} 348122394Sharti 349122394Sharti/* 350122394Sharti * Will return only _OK or _FAILED 351122394Sharti */ 352122394Shartienum snmpd_input_err 353122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 354122394Sharti u_char *sndbuf, size_t *sndlen, const char *source, 355122394Sharti enum snmpd_input_err ierr, int32_t ivar, void *data) 356122394Sharti{ 357122394Sharti struct snmp_pdu resp; 358122394Sharti struct asn_buf resp_b, pdu_b; 359122394Sharti enum snmp_ret ret; 360122394Sharti 361122394Sharti resp_b.asn_ptr = sndbuf; 362122394Sharti resp_b.asn_len = snmpd.txbuf; 363122394Sharti 364122394Sharti pdu_b.asn_cptr = rcvbuf; 365122394Sharti pdu_b.asn_len = rcvlen; 366122394Sharti 367122394Sharti if (ierr != SNMPD_INPUT_OK) { 368122394Sharti /* error decoding the input of a SET */ 369122394Sharti if (pdu->version == SNMP_V1) 370122394Sharti pdu->error_status = SNMP_ERR_BADVALUE; 371122394Sharti else if (ierr == SNMPD_INPUT_VALBADLEN) 372122394Sharti pdu->error_status = SNMP_ERR_WRONG_LENGTH; 373122394Sharti else if (ierr == SNMPD_INPUT_VALRANGE) 374122394Sharti pdu->error_status = SNMP_ERR_WRONG_VALUE; 375122394Sharti else 376122394Sharti pdu->error_status = SNMP_ERR_WRONG_ENCODING; 377122394Sharti 378122394Sharti pdu->error_index = ivar; 379122394Sharti 380122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 381122394Sharti syslog(LOG_WARNING, "could not encode error response"); 382122394Sharti snmpd_stats.silentDrops++; 383122394Sharti return (SNMPD_INPUT_FAILED); 384122394Sharti } 385122394Sharti 386122394Sharti if (debug.dump_pdus) { 387122394Sharti snmp_printf("%s <- ", source); 388122394Sharti snmp_pdu_dump(pdu); 389122394Sharti } 390122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 391122394Sharti return (SNMPD_INPUT_OK); 392122394Sharti } 393122394Sharti 394122394Sharti switch (pdu->type) { 395122394Sharti 396122394Sharti case SNMP_PDU_GET: 397122394Sharti ret = snmp_get(pdu, &resp_b, &resp, data); 398122394Sharti break; 399122394Sharti 400122394Sharti case SNMP_PDU_GETNEXT: 401122394Sharti ret = snmp_getnext(pdu, &resp_b, &resp, data); 402122394Sharti break; 403122394Sharti 404122394Sharti case SNMP_PDU_SET: 405122394Sharti ret = snmp_set(pdu, &resp_b, &resp, data); 406122394Sharti break; 407122394Sharti 408122394Sharti case SNMP_PDU_GETBULK: 409122394Sharti ret = snmp_getbulk(pdu, &resp_b, &resp, data); 410122394Sharti break; 411122394Sharti 412122394Sharti default: 413122394Sharti ret = SNMP_RET_IGN; 414122394Sharti break; 415122394Sharti } 416122394Sharti 417122394Sharti switch (ret) { 418122394Sharti 419122394Sharti case SNMP_RET_OK: 420122394Sharti /* normal return - send a response */ 421122394Sharti if (debug.dump_pdus) { 422122394Sharti snmp_printf("%s <- ", source); 423122394Sharti snmp_pdu_dump(&resp); 424122394Sharti } 425122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 426122394Sharti snmp_pdu_free(&resp); 427122394Sharti return (SNMPD_INPUT_OK); 428122394Sharti 429122394Sharti case SNMP_RET_IGN: 430122394Sharti /* error - send nothing */ 431122394Sharti snmpd_stats.silentDrops++; 432122394Sharti return (SNMPD_INPUT_FAILED); 433122394Sharti 434122394Sharti case SNMP_RET_ERR: 435122394Sharti /* error - send error response. The snmp routine has 436122394Sharti * changed the error fields in the original message. */ 437122394Sharti resp_b.asn_ptr = sndbuf; 438122394Sharti resp_b.asn_len = snmpd.txbuf; 439122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 440122394Sharti syslog(LOG_WARNING, "could not encode error response"); 441122394Sharti snmpd_stats.silentDrops++; 442122394Sharti return (SNMPD_INPUT_FAILED); 443122394Sharti } else { 444122394Sharti if (debug.dump_pdus) { 445122394Sharti snmp_printf("%s <- ", source); 446122394Sharti snmp_pdu_dump(pdu); 447122394Sharti } 448122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 449122394Sharti return (SNMPD_INPUT_OK); 450122394Sharti } 451122394Sharti } 452122394Sharti abort(); 453122394Sharti} 454122394Sharti 455124861Sharti/* 456124861Sharti * Insert a port into the right place in the transport's table of ports 457124861Sharti */ 458124861Shartivoid 459124861Shartitrans_insert_port(struct transport *t, struct tport *port) 460124861Sharti{ 461124861Sharti struct tport *p; 462122394Sharti 463124861Sharti TAILQ_FOREACH(p, &t->table, link) { 464124861Sharti if (asn_compare_oid(&p->index, &port->index) > 0) { 465124861Sharti TAILQ_INSERT_BEFORE(p, port, link); 466124861Sharti return; 467124861Sharti } 468124861Sharti } 469124861Sharti port->transport = t; 470124861Sharti TAILQ_INSERT_TAIL(&t->table, port, link); 471124861Sharti} 472122394Sharti 473122394Sharti/* 474124861Sharti * Remove a port from a transport's list 475124861Sharti */ 476124861Shartivoid 477124861Shartitrans_remove_port(struct tport *port) 478124861Sharti{ 479124861Sharti 480124861Sharti TAILQ_REMOVE(&port->transport->table, port, link); 481124861Sharti} 482124861Sharti 483124861Sharti/* 484124861Sharti * Find a port on a transport's list 485124861Sharti */ 486124861Shartistruct tport * 487124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 488124861Sharti{ 489124861Sharti 490124861Sharti return (FIND_OBJECT_OID(&t->table, idx, sub)); 491124861Sharti} 492124861Sharti 493124861Sharti/* 494124861Sharti * Find next port on a transport's list 495124861Sharti */ 496124861Shartistruct tport * 497124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 498124861Sharti{ 499124861Sharti 500124861Sharti return (NEXT_OBJECT_OID(&t->table, idx, sub)); 501124861Sharti} 502124861Sharti 503124861Sharti/* 504124861Sharti * Return first port 505124861Sharti */ 506124861Shartistruct tport * 507124861Shartitrans_first_port(struct transport *t) 508124861Sharti{ 509124861Sharti 510124861Sharti return (TAILQ_FIRST(&t->table)); 511124861Sharti} 512124861Sharti 513124861Sharti/* 514124861Sharti * Iterate through all ports until a function returns a 0. 515124861Sharti */ 516124861Shartistruct tport * 517124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 518124861Sharti intptr_t arg) 519124861Sharti{ 520124861Sharti struct tport *p; 521124861Sharti 522124861Sharti TAILQ_FOREACH(p, &t->table, link) 523124861Sharti if (func(p, arg) == 0) 524124861Sharti return (p); 525124861Sharti return (NULL); 526124861Sharti} 527124861Sharti 528124861Sharti/* 529124861Sharti * Register a transport 530124861Sharti */ 531124861Shartiint 532124861Shartitrans_register(const struct transport_def *def, struct transport **pp) 533124861Sharti{ 534124861Sharti u_int i; 535124861Sharti char or_descr[256]; 536124861Sharti 537124861Sharti if ((*pp = malloc(sizeof(**pp))) == NULL) 538124861Sharti return (SNMP_ERR_GENERR); 539124861Sharti 540124861Sharti /* construct index */ 541124861Sharti (*pp)->index.len = strlen(def->name) + 1; 542124861Sharti (*pp)->index.subs[0] = strlen(def->name); 543124861Sharti for (i = 0; i < (*pp)->index.subs[0]; i++) 544124861Sharti (*pp)->index.subs[i + 1] = def->name[i]; 545124861Sharti 546124861Sharti (*pp)->vtab = def; 547124861Sharti 548124861Sharti if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 549124861Sharti free(*pp); 550124861Sharti return (SNMP_ERR_INCONS_VALUE); 551124861Sharti } 552124861Sharti 553124861Sharti /* register module */ 554124861Sharti snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 555124861Sharti if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 556124861Sharti free(*pp); 557124861Sharti return (SNMP_ERR_GENERR); 558124861Sharti } 559124861Sharti 560124861Sharti INSERT_OBJECT_OID((*pp), &transport_list); 561124861Sharti 562124861Sharti TAILQ_INIT(&(*pp)->table); 563124861Sharti 564124861Sharti return (SNMP_ERR_NOERROR); 565124861Sharti} 566124861Sharti 567124861Sharti/* 568124861Sharti * Unregister transport 569124861Sharti */ 570124861Shartiint 571124861Shartitrans_unregister(struct transport *t) 572124861Sharti{ 573124861Sharti if (!TAILQ_EMPTY(&t->table)) 574124861Sharti return (SNMP_ERR_INCONS_VALUE); 575124861Sharti 576124861Sharti or_unregister(t->or_index); 577124861Sharti TAILQ_REMOVE(&transport_list, t, link); 578124861Sharti 579124861Sharti return (SNMP_ERR_NOERROR); 580124861Sharti} 581124861Sharti 582124861Sharti/* 583122394Sharti * File descriptor support 584122394Sharti */ 585124861Sharti#ifdef USE_LIBBEGEMOT 586122394Shartistatic void 587124861Shartiinput(int fd, int mask __unused, void *uap) 588124861Sharti#else 589124861Shartistatic void 590122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused) 591124861Sharti#endif 592122394Sharti{ 593122394Sharti struct fdesc *f = uap; 594122394Sharti 595122394Sharti (*f->func)(fd, f->udata); 596122394Sharti} 597122394Sharti 598122394Shartivoid 599122394Shartifd_suspend(void *p) 600122394Sharti{ 601122394Sharti struct fdesc *f = p; 602122394Sharti 603124861Sharti#ifdef USE_LIBBEGEMOT 604124861Sharti if (f->id >= 0) { 605124861Sharti poll_unregister(f->id); 606124861Sharti f->id = -1; 607124861Sharti } 608124861Sharti#else 609122394Sharti if (evTestID(f->id)) { 610122394Sharti (void)evDeselectFD(evctx, f->id); 611122394Sharti evInitID(&f->id); 612122394Sharti } 613124861Sharti#endif 614122394Sharti} 615122394Sharti 616122394Shartiint 617122394Shartifd_resume(void *p) 618122394Sharti{ 619122394Sharti struct fdesc *f = p; 620122394Sharti int err; 621122394Sharti 622124861Sharti#ifdef USE_LIBBEGEMOT 623124861Sharti if (f->id >= 0) 624124861Sharti return (0); 625142810Sharti if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 626124861Sharti err = errno; 627124861Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 628124861Sharti errno = err; 629124861Sharti return (-1); 630124861Sharti } 631124861Sharti#else 632122394Sharti if (evTestID(f->id)) 633122394Sharti return (0); 634122394Sharti if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 635122394Sharti err = errno; 636122394Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 637122394Sharti errno = err; 638122394Sharti return (-1); 639122394Sharti } 640124861Sharti#endif 641122394Sharti return (0); 642122394Sharti} 643122394Sharti 644122394Shartivoid * 645122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 646122394Sharti{ 647122394Sharti struct fdesc *f; 648122394Sharti int err; 649122394Sharti 650122394Sharti if ((f = malloc(sizeof(struct fdesc))) == NULL) { 651122394Sharti err = errno; 652122394Sharti syslog(LOG_ERR, "fd_select: %m"); 653122394Sharti errno = err; 654122394Sharti return (NULL); 655122394Sharti } 656122394Sharti f->fd = fd; 657122394Sharti f->func = func; 658122394Sharti f->udata = udata; 659122394Sharti f->owner = mod; 660124861Sharti#ifdef USE_LIBBEGEMOT 661124861Sharti f->id = -1; 662124861Sharti#else 663122394Sharti evInitID(&f->id); 664124861Sharti#endif 665122394Sharti 666122394Sharti if (fd_resume(f)) { 667122394Sharti err = errno; 668122394Sharti free(f); 669122394Sharti errno = err; 670122394Sharti return (NULL); 671122394Sharti } 672122394Sharti 673122394Sharti LIST_INSERT_HEAD(&fdesc_list, f, link); 674122394Sharti 675122394Sharti return (f); 676122394Sharti} 677122394Sharti 678122394Shartivoid 679122394Shartifd_deselect(void *p) 680122394Sharti{ 681122394Sharti struct fdesc *f = p; 682122394Sharti 683122394Sharti LIST_REMOVE(f, link); 684122394Sharti fd_suspend(f); 685122394Sharti free(f); 686122394Sharti} 687122394Sharti 688122394Shartistatic void 689122394Shartifd_flush(struct lmodule *mod) 690122394Sharti{ 691122394Sharti struct fdesc *t, *t1; 692122394Sharti 693122394Sharti t = LIST_FIRST(&fdesc_list); 694122394Sharti while (t != NULL) { 695122394Sharti t1 = LIST_NEXT(t, link); 696122394Sharti if (t->owner == mod) 697122394Sharti fd_deselect(t); 698122394Sharti t = t1; 699122394Sharti } 700122394Sharti} 701122394Sharti 702122394Sharti/* 703124861Sharti * Consume a message from the input buffer 704122394Sharti */ 705122394Shartistatic void 706124861Shartisnmp_input_consume(struct port_input *pi) 707122394Sharti{ 708124861Sharti if (!pi->stream) { 709124861Sharti /* always consume everything */ 710124861Sharti pi->length = 0; 711122394Sharti return; 712122394Sharti } 713124861Sharti if (pi->consumed >= pi->length) { 714124861Sharti /* all bytes consumed */ 715124861Sharti pi->length = 0; 716122394Sharti return; 717122394Sharti } 718124861Sharti memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 719124861Sharti pi->length -= pi->consumed; 720124861Sharti} 721124861Sharti 722124861Shartistruct credmsg { 723124861Sharti struct cmsghdr hdr; 724124861Sharti struct cmsgcred cred; 725124861Sharti}; 726124861Sharti 727124861Shartistatic void 728124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg) 729124861Sharti{ 730124861Sharti struct credmsg *cmsg; 731124861Sharti struct xucred ucred; 732124861Sharti socklen_t ucredlen; 733124861Sharti 734124861Sharti pi->priv = 0; 735124861Sharti 736124861Sharti if (msg->msg_controllen == sizeof(*cmsg)) { 737124861Sharti /* process explicitely sends credentials */ 738124861Sharti 739124861Sharti cmsg = (struct credmsg *)msg->msg_control; 740124861Sharti pi->priv = (cmsg->cred.cmcred_euid == 0); 741122394Sharti return; 742122394Sharti } 743124861Sharti 744124861Sharti /* ok, obtain the accept time credentials */ 745124861Sharti ucredlen = sizeof(ucred); 746124861Sharti 747124861Sharti if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 748124861Sharti ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 749124861Sharti pi->priv = (ucred.cr_uid == 0); 750124861Sharti} 751124861Sharti 752124861Sharti/* 753124861Sharti * Input from a stream socket. 754124861Sharti */ 755124861Shartistatic int 756124861Shartirecv_stream(struct port_input *pi) 757124861Sharti{ 758124861Sharti struct msghdr msg; 759124861Sharti struct iovec iov[1]; 760124861Sharti ssize_t len; 761124861Sharti struct credmsg cmsg; 762124861Sharti 763124861Sharti if (pi->buf == NULL) { 764124861Sharti /* no buffer yet - allocate one */ 765124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 766124861Sharti /* ups - could not get buffer. Return an error 767124861Sharti * the caller must close the transport. */ 768124861Sharti return (-1); 769124861Sharti } 770124861Sharti pi->buflen = buf_size(0); 771124861Sharti pi->consumed = 0; 772124861Sharti pi->length = 0; 773124861Sharti } 774124861Sharti 775124861Sharti /* try to get a message */ 776124861Sharti msg.msg_name = pi->peer; 777124861Sharti msg.msg_namelen = pi->peerlen; 778124861Sharti msg.msg_iov = iov; 779124861Sharti msg.msg_iovlen = 1; 780124861Sharti if (pi->cred) { 781124861Sharti msg.msg_control = &cmsg; 782124861Sharti msg.msg_controllen = sizeof(cmsg); 783124861Sharti 784124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 785124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 786124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 787124861Sharti } else { 788124861Sharti msg.msg_control = NULL; 789124861Sharti msg.msg_controllen = 0; 790124861Sharti } 791124861Sharti msg.msg_flags = 0; 792124861Sharti 793124861Sharti iov[0].iov_base = pi->buf + pi->length; 794124861Sharti iov[0].iov_len = pi->buflen - pi->length; 795124861Sharti 796124861Sharti len = recvmsg(pi->fd, &msg, 0); 797124861Sharti 798124861Sharti if (len == -1 || len == 0) 799124861Sharti /* receive error */ 800124861Sharti return (-1); 801124861Sharti 802124861Sharti pi->length += len; 803124861Sharti 804124861Sharti if (pi->cred) 805124861Sharti check_priv(pi, &msg); 806124861Sharti 807124861Sharti return (0); 808124861Sharti} 809124861Sharti 810124861Sharti/* 811124861Sharti * Input from a datagram socket. 812124861Sharti * Each receive should return one datagram. 813124861Sharti */ 814124861Shartistatic int 815124861Shartirecv_dgram(struct port_input *pi) 816124861Sharti{ 817124861Sharti u_char embuf[1000]; 818124861Sharti struct msghdr msg; 819124861Sharti struct iovec iov[1]; 820124861Sharti ssize_t len; 821124861Sharti struct credmsg cmsg; 822124861Sharti 823124861Sharti if (pi->buf == NULL) { 824124861Sharti /* no buffer yet - allocate one */ 825124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 826124861Sharti /* ups - could not get buffer. Read away input 827124861Sharti * and drop it */ 828124861Sharti (void)recvfrom(pi->fd, embuf, sizeof(embuf), 829124861Sharti 0, NULL, NULL); 830124861Sharti /* return error */ 831124861Sharti return (-1); 832124861Sharti } 833124861Sharti pi->buflen = buf_size(0); 834124861Sharti } 835124861Sharti 836124861Sharti /* try to get a message */ 837124861Sharti msg.msg_name = pi->peer; 838124861Sharti msg.msg_namelen = pi->peerlen; 839124861Sharti msg.msg_iov = iov; 840124861Sharti msg.msg_iovlen = 1; 841124861Sharti if (pi->cred) { 842124861Sharti msg.msg_control = &cmsg; 843124861Sharti msg.msg_controllen = sizeof(cmsg); 844124861Sharti 845124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 846124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 847124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 848124861Sharti } else { 849124861Sharti msg.msg_control = NULL; 850128237Sharti msg.msg_controllen = 0; 851124861Sharti } 852124861Sharti msg.msg_flags = 0; 853124861Sharti 854124861Sharti iov[0].iov_base = pi->buf; 855124861Sharti iov[0].iov_len = pi->buflen; 856124861Sharti 857124861Sharti len = recvmsg(pi->fd, &msg, 0); 858124861Sharti 859124861Sharti if (len == -1 || len == 0) 860124861Sharti /* receive error */ 861124861Sharti return (-1); 862124861Sharti 863124861Sharti if (msg.msg_flags & MSG_TRUNC) { 864124861Sharti /* truncated - drop */ 865122394Sharti snmpd_stats.silentDrops++; 866122394Sharti snmpd_stats.inTooLong++; 867124861Sharti return (-1); 868122394Sharti } 869122394Sharti 870124861Sharti pi->length = (size_t)len; 871124861Sharti 872124861Sharti if (pi->cred) 873124861Sharti check_priv(pi, &msg); 874124861Sharti 875124861Sharti return (0); 876124861Sharti} 877124861Sharti 878124861Sharti/* 879124861Sharti * Input from a socket 880124861Sharti */ 881124861Shartiint 882124861Shartisnmpd_input(struct port_input *pi, struct tport *tport) 883124861Sharti{ 884124861Sharti u_char *sndbuf; 885124861Sharti size_t sndlen; 886124861Sharti struct snmp_pdu pdu; 887124861Sharti enum snmpd_input_err ierr, ferr; 888124861Sharti enum snmpd_proxy_err perr; 889124861Sharti int32_t vi; 890124861Sharti int ret; 891124861Sharti ssize_t slen; 892145557Sharti#ifdef USE_TCPWRAPPERS 893145557Sharti char client[16]; 894145557Sharti#endif 895124861Sharti 896124861Sharti /* get input depending on the transport */ 897124861Sharti if (pi->stream) { 898124861Sharti ret = recv_stream(pi); 899124861Sharti } else { 900124861Sharti ret = recv_dgram(pi); 901124861Sharti } 902124861Sharti 903124861Sharti if (ret == -1) 904124861Sharti return (-1); 905124861Sharti 906145557Sharti#ifdef USE_TCPWRAPPERS 907122394Sharti /* 908145557Sharti * In case of AF_INET{6} peer, do hosts_access(5) check. 909145557Sharti */ 910145557Sharti if (inet_ntop(pi->peer->sa_family, 911145557Sharti &((struct sockaddr_in *)pi->peer)->sin_addr, client, 912145557Sharti sizeof(client)) != NULL) { 913145557Sharti request_set(&req, RQ_CLIENT_ADDR, client, 0); 914145557Sharti if (hosts_access(&req) == 0) { 915145557Sharti syslog(LOG_ERR, "refused connection from %.500s", 916145557Sharti eval_client(&req)); 917145557Sharti return (-1); 918145557Sharti } 919145557Sharti } else 920145557Sharti syslog(LOG_ERR, "inet_ntop(): %m"); 921145557Sharti#endif 922145557Sharti 923145557Sharti /* 924122394Sharti * Handle input 925122394Sharti */ 926124861Sharti ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 927124861Sharti &pi->consumed); 928124861Sharti if (ierr == SNMPD_INPUT_TRUNC) { 929124861Sharti /* need more bytes. This is ok only for streaming transports. 930124861Sharti * but only if we have not reached bufsiz yet. */ 931124861Sharti if (pi->stream) { 932124861Sharti if (pi->length == buf_size(0)) { 933124861Sharti snmpd_stats.silentDrops++; 934124861Sharti return (-1); 935124861Sharti } 936124861Sharti return (0); 937124861Sharti } 938124861Sharti snmpd_stats.silentDrops++; 939124861Sharti return (-1); 940124861Sharti } 941122394Sharti 942122394Sharti /* can't check for bad SET pdus here, because a proxy may have to 943122394Sharti * check the access first. We don't want to return an error response 944122394Sharti * to a proxy PDU with a wrong community */ 945122394Sharti if (ierr == SNMPD_INPUT_FAILED) { 946124861Sharti /* for streaming transports this is fatal */ 947124861Sharti if (pi->stream) 948124861Sharti return (-1); 949124861Sharti snmp_input_consume(pi); 950124861Sharti return (0); 951122394Sharti } 952133211Sharti if (ierr == SNMPD_INPUT_BAD_COMM) { 953133211Sharti snmp_input_consume(pi); 954133211Sharti return (0); 955133211Sharti } 956122394Sharti 957122394Sharti /* 958122394Sharti * If that is a module community and the module has a proxy function, 959122394Sharti * the hand it over to the module. 960122394Sharti */ 961122394Sharti if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 962124861Sharti perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 963133211Sharti &tport->index, pi->peer, pi->peerlen, ierr, vi, 964133211Sharti !pi->cred || pi->priv); 965122394Sharti 966122394Sharti switch (perr) { 967122394Sharti 968122394Sharti case SNMPD_PROXY_OK: 969124861Sharti snmp_input_consume(pi); 970124861Sharti return (0); 971122394Sharti 972122394Sharti case SNMPD_PROXY_REJ: 973122394Sharti break; 974122394Sharti 975122394Sharti case SNMPD_PROXY_DROP: 976124861Sharti snmp_input_consume(pi); 977122394Sharti snmp_pdu_free(&pdu); 978122394Sharti snmpd_stats.proxyDrops++; 979124861Sharti return (0); 980122394Sharti 981122394Sharti case SNMPD_PROXY_BADCOMM: 982124861Sharti snmp_input_consume(pi); 983122394Sharti snmp_pdu_free(&pdu); 984122394Sharti snmpd_stats.inBadCommunityNames++; 985122394Sharti if (snmpd.auth_traps) 986122394Sharti snmp_send_trap(&oid_authenticationFailure, 987133211Sharti (struct snmp_value *)NULL); 988124861Sharti return (0); 989122394Sharti 990122394Sharti case SNMPD_PROXY_BADCOMMUSE: 991124861Sharti snmp_input_consume(pi); 992122394Sharti snmp_pdu_free(&pdu); 993122394Sharti snmpd_stats.inBadCommunityUses++; 994122394Sharti if (snmpd.auth_traps) 995122394Sharti snmp_send_trap(&oid_authenticationFailure, 996133211Sharti (struct snmp_value *)NULL); 997124861Sharti return (0); 998122394Sharti } 999122394Sharti } 1000122394Sharti 1001122394Sharti /* 1002122394Sharti * Check type 1003122394Sharti */ 1004122394Sharti if (pdu.type == SNMP_PDU_RESPONSE || 1005122394Sharti pdu.type == SNMP_PDU_TRAP || 1006122394Sharti pdu.type == SNMP_PDU_TRAP2) { 1007122394Sharti snmpd_stats.silentDrops++; 1008122394Sharti snmpd_stats.inBadPduTypes++; 1009122394Sharti snmp_pdu_free(&pdu); 1010124861Sharti snmp_input_consume(pi); 1011124861Sharti return (0); 1012122394Sharti } 1013122394Sharti 1014122394Sharti /* 1015122394Sharti * Check community 1016122394Sharti */ 1017124861Sharti if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1018124861Sharti (community != COMM_WRITE && 1019124861Sharti (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 1020122394Sharti snmpd_stats.inBadCommunityUses++; 1021122394Sharti snmp_pdu_free(&pdu); 1022124861Sharti snmp_input_consume(pi); 1023122394Sharti if (snmpd.auth_traps) 1024133211Sharti snmp_send_trap(&oid_authenticationFailure, 1025133211Sharti (struct snmp_value *)NULL); 1026124861Sharti return (0); 1027122394Sharti } 1028122394Sharti 1029122394Sharti /* 1030122394Sharti * Execute it. 1031122394Sharti */ 1032122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 1033122394Sharti snmpd_stats.silentDrops++; 1034122394Sharti snmp_pdu_free(&pdu); 1035124861Sharti snmp_input_consume(pi); 1036124861Sharti return (0); 1037122394Sharti } 1038124861Sharti ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1039124861Sharti sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1040122394Sharti 1041122394Sharti if (ferr == SNMPD_INPUT_OK) { 1042124861Sharti slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 1043124861Sharti if (slen == -1) 1044122394Sharti syslog(LOG_ERR, "sendto: %m"); 1045124861Sharti else if ((size_t)slen != sndlen) 1046122394Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1047124861Sharti sndlen, (size_t)slen); 1048122394Sharti } 1049122394Sharti snmp_pdu_free(&pdu); 1050122394Sharti free(sndbuf); 1051124861Sharti snmp_input_consume(pi); 1052122394Sharti 1053124861Sharti return (0); 1054122394Sharti} 1055122394Sharti 1056122394Sharti/* 1057124861Sharti * Send a PDU to a given port 1058122394Sharti */ 1059124861Shartivoid 1060124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1061124861Sharti const struct sockaddr *addr, socklen_t addrlen) 1062122394Sharti{ 1063124861Sharti struct transport *trans = targ; 1064124861Sharti struct tport *tp; 1065124861Sharti u_char *sndbuf; 1066124861Sharti size_t sndlen; 1067124861Sharti ssize_t len; 1068122394Sharti 1069124861Sharti TAILQ_FOREACH(tp, &trans->table, link) 1070124861Sharti if (asn_compare_oid(port, &tp->index) == 0) 1071122394Sharti break; 1072124861Sharti if (tp == 0) 1073124861Sharti return; 1074122394Sharti 1075124861Sharti if ((sndbuf = buf_alloc(1)) == NULL) 1076124861Sharti return; 1077122394Sharti 1078124861Sharti snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1079122394Sharti 1080124861Sharti len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1081122394Sharti 1082124861Sharti if (len == -1) 1083124861Sharti syslog(LOG_ERR, "sendto: %m"); 1084124861Sharti else if ((size_t)len != sndlen) 1085124861Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1086124861Sharti sndlen, (size_t)len); 1087122394Sharti 1088124861Sharti free(sndbuf); 1089122394Sharti} 1090122394Sharti 1091122394Sharti 1092122394Sharti/* 1093124861Sharti * Close an input source 1094122394Sharti */ 1095122394Shartivoid 1096124861Shartisnmpd_input_close(struct port_input *pi) 1097122394Sharti{ 1098124861Sharti if (pi->id != NULL) 1099124861Sharti fd_deselect(pi->id); 1100124861Sharti if (pi->fd >= 0) 1101124861Sharti (void)close(pi->fd); 1102124861Sharti if (pi->buf != NULL) 1103124861Sharti free(pi->buf); 1104122394Sharti} 1105122394Sharti 1106122394Sharti/* 1107122394Sharti * Dump internal state. 1108122394Sharti */ 1109124861Sharti#ifdef USE_LIBBEGEMOT 1110122394Shartistatic void 1111124861Shartiinfo_func(void) 1112124861Sharti#else 1113124861Shartistatic void 1114122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1115124861Sharti#endif 1116122394Sharti{ 1117122394Sharti struct lmodule *m; 1118122394Sharti u_int i; 1119122394Sharti char buf[10000]; 1120122394Sharti 1121122394Sharti syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1122122394Sharti for (i = 0; i < tree_size; i++) { 1123122394Sharti switch (tree[i].type) { 1124122394Sharti 1125122394Sharti case SNMP_NODE_LEAF: 1126122394Sharti sprintf(buf, "LEAF: %s %s", tree[i].name, 1127122394Sharti asn_oid2str(&tree[i].oid)); 1128122394Sharti break; 1129122394Sharti 1130122394Sharti case SNMP_NODE_COLUMN: 1131122394Sharti sprintf(buf, "COL: %s %s", tree[i].name, 1132122394Sharti asn_oid2str(&tree[i].oid)); 1133122394Sharti break; 1134122394Sharti } 1135122394Sharti syslog(LOG_DEBUG, "%s", buf); 1136122394Sharti } 1137122394Sharti 1138122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1139122394Sharti if (m->config->dump) 1140122394Sharti (*m->config->dump)(); 1141122394Sharti} 1142122394Sharti 1143122394Sharti/* 1144122394Sharti * Re-read configuration 1145122394Sharti */ 1146124861Sharti#ifdef USE_LIBBEGEMOT 1147122394Shartistatic void 1148124861Sharticonfig_func(void) 1149124861Sharti#else 1150124861Shartistatic void 1151122394Sharticonfig_func(evContext ctx __unused, void *uap __unused, 1152122394Sharti const void *tag __unused) 1153124861Sharti#endif 1154122394Sharti{ 1155122394Sharti struct lmodule *m; 1156122394Sharti 1157122394Sharti if (read_config(config_file, NULL)) { 1158122394Sharti syslog(LOG_ERR, "error reading config file '%s'", config_file); 1159122394Sharti return; 1160122394Sharti } 1161122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1162122394Sharti if (m->config->config) 1163122394Sharti (*m->config->config)(); 1164122394Sharti} 1165122394Sharti 1166122394Sharti/* 1167122394Sharti * On USR1 dump actual configuration. 1168122394Sharti */ 1169122394Shartistatic void 1170122394Shartionusr1(int s __unused) 1171122394Sharti{ 1172124861Sharti 1173122394Sharti work |= WORK_DOINFO; 1174122394Sharti} 1175122394Shartistatic void 1176122394Shartionhup(int s __unused) 1177122394Sharti{ 1178124861Sharti 1179122394Sharti work |= WORK_RECONFIG; 1180122394Sharti} 1181122394Sharti 1182122394Shartistatic void 1183122394Shartionterm(int s __unused) 1184122394Sharti{ 1185122394Sharti 1186124861Sharti /* allow clean-up */ 1187122394Sharti exit(0); 1188122394Sharti} 1189122394Sharti 1190122394Shartistatic void 1191122394Shartiinit_sigs(void) 1192122394Sharti{ 1193122394Sharti struct sigaction sa; 1194122394Sharti 1195122394Sharti sa.sa_handler = onusr1; 1196122394Sharti sa.sa_flags = SA_RESTART; 1197122394Sharti sigemptyset(&sa.sa_mask); 1198122394Sharti if (sigaction(SIGUSR1, &sa, NULL)) { 1199122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1200122394Sharti exit(1); 1201122394Sharti } 1202122394Sharti 1203122394Sharti sa.sa_handler = onhup; 1204122394Sharti if (sigaction(SIGHUP, &sa, NULL)) { 1205122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1206122394Sharti exit(1); 1207122394Sharti } 1208122394Sharti 1209122394Sharti sa.sa_handler = onterm; 1210122394Sharti sa.sa_flags = 0; 1211122394Sharti sigemptyset(&sa.sa_mask); 1212122394Sharti if (sigaction(SIGTERM, &sa, NULL)) { 1213122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1214122394Sharti exit(1); 1215122394Sharti } 1216122394Sharti if (sigaction(SIGINT, &sa, NULL)) { 1217122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1218122394Sharti exit(1); 1219122394Sharti } 1220122394Sharti} 1221122394Sharti 1222122394Shartistatic void 1223122394Shartiblock_sigs(void) 1224122394Sharti{ 1225122394Sharti sigset_t set; 1226122394Sharti 1227122394Sharti sigfillset(&set); 1228122394Sharti if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1229122394Sharti syslog(LOG_ERR, "SIG_BLOCK: %m"); 1230122394Sharti exit(1); 1231122394Sharti } 1232122394Sharti} 1233122394Shartistatic void 1234122394Shartiunblock_sigs(void) 1235122394Sharti{ 1236122394Sharti if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1237122394Sharti syslog(LOG_ERR, "SIG_SETMASK: %m"); 1238122394Sharti exit(1); 1239122394Sharti } 1240122394Sharti} 1241122394Sharti 1242122394Sharti/* 1243122394Sharti * Shut down 1244122394Sharti */ 1245122394Shartistatic void 1246122394Shartiterm(void) 1247122394Sharti{ 1248122394Sharti (void)unlink(pid_file); 1249122394Sharti} 1250122394Sharti 1251124861Shartistatic void 1252124861Shartitrans_stop(void) 1253124861Sharti{ 1254124861Sharti struct transport *t; 1255124861Sharti 1256124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1257124861Sharti (void)t->vtab->stop(1); 1258124861Sharti} 1259124861Sharti 1260122394Sharti/* 1261122394Sharti * Define a macro from the command line 1262122394Sharti */ 1263122394Shartistatic void 1264122394Shartido_macro(char *arg) 1265122394Sharti{ 1266122394Sharti char *eq; 1267122394Sharti int err; 1268122394Sharti 1269122394Sharti if ((eq = strchr(arg, '=')) == NULL) 1270122394Sharti err = define_macro(arg, ""); 1271122394Sharti else { 1272122394Sharti *eq++ = '\0'; 1273122394Sharti err = define_macro(arg, eq); 1274122394Sharti } 1275122394Sharti if (err == -1) { 1276122394Sharti syslog(LOG_ERR, "cannot save macro: %m"); 1277122394Sharti exit(1); 1278122394Sharti } 1279122394Sharti} 1280122394Sharti 1281122394Sharti/* 1282122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken 1283122394Sharti * and will not compile with WARNS=5. 1284122394Sharti */ 1285122394Shartistatic int 1286122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1287122394Sharti{ 1288122394Sharti static const char *const delim = ",\t "; 1289122394Sharti u_int i; 1290122394Sharti char *ptr; 1291122394Sharti 1292122394Sharti *optp = NULL; 1293122394Sharti 1294122394Sharti /* skip leading junk */ 1295122394Sharti for (ptr = *arg; *ptr != '\0'; ptr++) 1296122394Sharti if (strchr(delim, *ptr) == NULL) 1297122394Sharti break; 1298122394Sharti if (*ptr == '\0') { 1299122394Sharti *arg = ptr; 1300122394Sharti return (-1); 1301122394Sharti } 1302122394Sharti *optp = ptr; 1303122394Sharti 1304122394Sharti /* find the end of the option */ 1305122394Sharti while (*++ptr != '\0') 1306122394Sharti if (strchr(delim, *ptr) != NULL || *ptr == '=') 1307122394Sharti break; 1308122394Sharti 1309122394Sharti if (*ptr != '\0') { 1310122394Sharti if (*ptr == '=') { 1311122394Sharti *ptr++ = '\0'; 1312122394Sharti *valp = ptr; 1313122394Sharti while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1314122394Sharti ptr++; 1315122394Sharti if (*ptr != '\0') 1316122394Sharti *ptr++ = '\0'; 1317122394Sharti } else 1318122394Sharti *ptr++ = '\0'; 1319122394Sharti } 1320122394Sharti 1321122394Sharti *arg = ptr; 1322122394Sharti 1323122394Sharti for (i = 0; *options != NULL; options++, i++) 1324124861Sharti if (strcmp(*optp, *options) == 0) 1325122394Sharti return (i); 1326122394Sharti return (-1); 1327122394Sharti} 1328122394Sharti 1329122394Shartiint 1330122394Shartimain(int argc, char *argv[]) 1331122394Sharti{ 1332122394Sharti int opt; 1333122394Sharti FILE *fp; 1334122394Sharti int background = 1; 1335124861Sharti struct tport *p; 1336122394Sharti const char *prefix = "snmpd"; 1337122394Sharti struct lmodule *m; 1338122394Sharti char *value, *option; 1339124861Sharti struct transport *t; 1340122394Sharti 1341122394Sharti#define DBG_DUMP 0 1342122394Sharti#define DBG_EVENTS 1 1343122394Sharti#define DBG_TRACE 2 1344122394Sharti static const char *const debug_opts[] = { 1345122394Sharti "dump", 1346122394Sharti "events", 1347122394Sharti "trace", 1348122394Sharti NULL 1349122394Sharti }; 1350122394Sharti 1351122394Sharti snmp_printf = snmp_printf_func; 1352122394Sharti snmp_error = snmp_error_func; 1353122394Sharti snmp_debug = snmp_debug_func; 1354122394Sharti asn_error = asn_error_func; 1355122394Sharti 1356122394Sharti while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1357122394Sharti switch (opt) { 1358122394Sharti 1359122394Sharti case 'c': 1360122394Sharti strlcpy(config_file, optarg, sizeof(config_file)); 1361122394Sharti break; 1362122394Sharti 1363122394Sharti case 'd': 1364122394Sharti background = 0; 1365122394Sharti break; 1366122394Sharti 1367122394Sharti case 'D': 1368122394Sharti while (*optarg) { 1369122394Sharti switch (getsubopt1(&optarg, debug_opts, 1370122394Sharti &value, &option)) { 1371122394Sharti 1372122394Sharti case DBG_DUMP: 1373122394Sharti debug.dump_pdus = 1; 1374122394Sharti break; 1375122394Sharti 1376122394Sharti case DBG_EVENTS: 1377122394Sharti debug.evdebug++; 1378122394Sharti break; 1379122394Sharti 1380122394Sharti case DBG_TRACE: 1381122394Sharti if (value == NULL) 1382122394Sharti syslog(LOG_ERR, 1383122394Sharti "no value for 'trace'"); 1384122394Sharti snmp_trace = strtoul(value, NULL, 0); 1385122394Sharti break; 1386122394Sharti 1387122394Sharti case -1: 1388122394Sharti if (suboptarg) 1389122394Sharti syslog(LOG_ERR, 1390122394Sharti "unknown debug flag '%s'", 1391122394Sharti option); 1392122394Sharti else 1393122394Sharti syslog(LOG_ERR, 1394122394Sharti "missing debug flag"); 1395122394Sharti break; 1396122394Sharti } 1397122394Sharti } 1398122394Sharti break; 1399122394Sharti 1400122394Sharti case 'h': 1401122394Sharti fprintf(stderr, "%s", usgtxt); 1402122394Sharti exit(0); 1403122394Sharti 1404122394Sharti case 'I': 1405122394Sharti syspath = optarg; 1406122394Sharti break; 1407122394Sharti 1408122394Sharti case 'l': 1409122394Sharti prefix = optarg; 1410122394Sharti break; 1411122394Sharti 1412122394Sharti case 'm': 1413122394Sharti do_macro(optarg); 1414122394Sharti break; 1415122394Sharti 1416122394Sharti case 'p': 1417122394Sharti strlcpy(pid_file, optarg, sizeof(pid_file)); 1418122394Sharti break; 1419122394Sharti } 1420122394Sharti 1421122394Sharti openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1422122394Sharti setlogmask(LOG_UPTO(debug.logpri - 1)); 1423122394Sharti 1424122394Sharti if (background && daemon(0, 0) < 0) { 1425122394Sharti syslog(LOG_ERR, "daemon: %m"); 1426122394Sharti exit(1); 1427122394Sharti } 1428122394Sharti 1429122394Sharti argc -= optind; 1430122394Sharti argv += optind; 1431122394Sharti 1432122394Sharti progargs = argv; 1433122394Sharti nprogargs = argc; 1434122394Sharti 1435122394Sharti srandomdev(); 1436122394Sharti 1437122394Sharti snmp_serial_no = random(); 1438122394Sharti 1439145557Sharti#ifdef USE_TCPWRAPPERS 1440122394Sharti /* 1441145557Sharti * Initialize hosts_access(3) handler. 1442145557Sharti */ 1443145557Sharti request_init(&req, RQ_DAEMON, "snmpd", 0); 1444145557Sharti sock_methods(&req); 1445145557Sharti#endif 1446145557Sharti 1447145557Sharti /* 1448122394Sharti * Initialize the tree. 1449122394Sharti */ 1450122394Sharti if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1451122394Sharti syslog(LOG_ERR, "%m"); 1452122394Sharti exit(1); 1453122394Sharti } 1454122394Sharti memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1455122394Sharti tree_size = CTREE_SIZE; 1456122394Sharti 1457122394Sharti /* 1458122394Sharti * Get standard communities 1459122394Sharti */ 1460122394Sharti (void)comm_define(1, "SNMP read", NULL, "public"); 1461122394Sharti (void)comm_define(2, "SNMP write", NULL, "public"); 1462122394Sharti community = COMM_INITIALIZE; 1463122394Sharti 1464122394Sharti trap_reqid = reqid_allocate(512, NULL); 1465122394Sharti 1466122394Sharti if (config_file[0] == '\0') 1467122394Sharti snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1468122394Sharti 1469122394Sharti init_actvals(); 1470124861Sharti 1471124861Sharti start_tick = get_ticks(); 1472124861Sharti this_tick = get_ticks(); 1473124861Sharti 1474124861Sharti /* start transports */ 1475124861Sharti if (atexit(trans_stop) == -1) { 1476124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1477124861Sharti exit(1); 1478124861Sharti } 1479124861Sharti if (udp_trans.start() != SNMP_ERR_NOERROR) 1480124861Sharti syslog(LOG_WARNING, "cannot start UDP transport"); 1481124861Sharti if (lsock_trans.start() != SNMP_ERR_NOERROR) 1482124861Sharti syslog(LOG_WARNING, "cannot start LSOCK transport"); 1483124861Sharti 1484124861Sharti#ifdef USE_LIBBEGEMOT 1485124861Sharti if (debug.evdebug > 0) 1486124861Sharti rpoll_trace = 1; 1487124861Sharti#else 1488122394Sharti if (evCreate(&evctx)) { 1489122394Sharti syslog(LOG_ERR, "evCreate: %m"); 1490122394Sharti exit(1); 1491122394Sharti } 1492122394Sharti if (debug.evdebug > 0) 1493122394Sharti evSetDebug(evctx, 10, stderr); 1494124861Sharti#endif 1495122394Sharti 1496133211Sharti if (read_config(config_file, NULL)) { 1497133211Sharti syslog(LOG_ERR, "error in config file"); 1498133211Sharti exit(1); 1499133211Sharti } 1500133211Sharti 1501124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1502124861Sharti TAILQ_FOREACH(p, &t->table, link) 1503124861Sharti t->vtab->init_port(p); 1504122394Sharti 1505122394Sharti init_sigs(); 1506122394Sharti 1507122394Sharti if (pid_file[0] == '\0') 1508122394Sharti snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1509122394Sharti 1510122394Sharti if ((fp = fopen(pid_file, "w")) != NULL) { 1511122394Sharti fprintf(fp, "%u", getpid()); 1512122394Sharti fclose(fp); 1513124861Sharti if (atexit(term) == -1) { 1514124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1515124861Sharti (void)remove(pid_file); 1516124861Sharti exit(0); 1517124861Sharti } 1518122394Sharti } 1519122394Sharti 1520122394Sharti if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1521122394Sharti NULL) == 0) { 1522122394Sharti syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1523122394Sharti exit(1); 1524122394Sharti } 1525122394Sharti if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1526122394Sharti NULL) == 0) { 1527122394Sharti syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1528122394Sharti exit(1); 1529122394Sharti } 1530122394Sharti 1531133211Sharti snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1532122394Sharti 1533122394Sharti while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1534122394Sharti m->flags &= ~LM_ONSTARTLIST; 1535122394Sharti TAILQ_REMOVE(&modules_start, m, start); 1536122394Sharti lm_start(m); 1537122394Sharti } 1538122394Sharti 1539122394Sharti for (;;) { 1540124861Sharti#ifndef USE_LIBBEGEMOT 1541122394Sharti evEvent event; 1542124861Sharti#endif 1543122394Sharti struct lmodule *mod; 1544122394Sharti 1545122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 1546122394Sharti if (mod->config->idle != NULL) 1547122394Sharti (*mod->config->idle)(); 1548122394Sharti 1549124861Sharti#ifndef USE_LIBBEGEMOT 1550122394Sharti if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1551122394Sharti if (evDispatch(evctx, event)) 1552122394Sharti syslog(LOG_ERR, "evDispatch: %m"); 1553122394Sharti } else if (errno != EINTR) { 1554122394Sharti syslog(LOG_ERR, "evGetNext: %m"); 1555122394Sharti exit(1); 1556122394Sharti } 1557124861Sharti#else 1558124861Sharti poll_dispatch(1); 1559124861Sharti#endif 1560122394Sharti 1561122394Sharti if (work != 0) { 1562122394Sharti block_sigs(); 1563122394Sharti if (work & WORK_DOINFO) { 1564124861Sharti#ifdef USE_LIBBEGEMOT 1565124861Sharti info_func(); 1566124861Sharti#else 1567122394Sharti if (evWaitFor(evctx, &work, info_func, 1568122394Sharti NULL, NULL) == -1) { 1569122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1570122394Sharti exit(1); 1571122394Sharti } 1572124861Sharti#endif 1573122394Sharti } 1574122394Sharti if (work & WORK_RECONFIG) { 1575124861Sharti#ifdef USE_LIBBEGEMOT 1576124861Sharti config_func(); 1577124861Sharti#else 1578122394Sharti if (evWaitFor(evctx, &work, config_func, 1579122394Sharti NULL, NULL) == -1) { 1580122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1581122394Sharti exit(1); 1582122394Sharti } 1583124861Sharti#endif 1584122394Sharti } 1585122394Sharti work = 0; 1586122394Sharti unblock_sigs(); 1587124861Sharti#ifndef USE_LIBBEGEMOT 1588122394Sharti if (evDo(evctx, &work) == -1) { 1589122394Sharti syslog(LOG_ERR, "evDo: %m"); 1590122394Sharti exit(1); 1591122394Sharti } 1592124861Sharti#endif 1593122394Sharti } 1594122394Sharti } 1595122394Sharti 1596122394Sharti return (0); 1597122394Sharti} 1598122394Sharti 1599122394Sharti 1600122394Shartiu_int32_t 1601122394Shartiget_ticks() 1602122394Sharti{ 1603122394Sharti struct timeval tv; 1604122394Sharti u_int32_t ret; 1605122394Sharti 1606122394Sharti if (gettimeofday(&tv, NULL)) 1607122394Sharti abort(); 1608122394Sharti ret = tv.tv_sec * 100 + tv.tv_usec / 10000; 1609122394Sharti return (ret); 1610122394Sharti} 1611122394Sharti/* 1612122394Sharti * Timer support 1613122394Sharti */ 1614124861Sharti#ifdef USE_LIBBEGEMOT 1615122394Shartistatic void 1616124861Shartitfunc(int tid __unused, void *uap) 1617124861Sharti#else 1618124861Shartistatic void 1619122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1620122394Sharti struct timespec inter __unused) 1621124861Sharti#endif 1622122394Sharti{ 1623122394Sharti struct timer *tp = uap; 1624122394Sharti 1625122394Sharti LIST_REMOVE(tp, link); 1626122394Sharti tp->func(tp->udata); 1627122394Sharti free(tp); 1628122394Sharti} 1629122394Sharti 1630122394Sharti/* 1631122394Sharti * Start a timer 1632122394Sharti */ 1633122394Shartivoid * 1634122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1635122394Sharti{ 1636122394Sharti struct timer *tp; 1637124861Sharti#ifdef USE_LIBBEGEMOT 1638124861Sharti struct timeval due; 1639124861Sharti#else 1640122394Sharti struct timespec due; 1641124861Sharti#endif 1642122394Sharti 1643122394Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 1644122394Sharti syslog(LOG_CRIT, "out of memory for timer"); 1645122394Sharti exit(1); 1646122394Sharti } 1647124861Sharti#ifdef USE_LIBBEGEMOT 1648124861Sharti (void)gettimeofday(&due, NULL); 1649124861Sharti due.tv_sec += ticks / 100; 1650124861Sharti due.tv_usec += (ticks % 100) * 10000; 1651124861Sharti if (due.tv_usec >= 1000000) { 1652124861Sharti due.tv_sec++; 1653124861Sharti due.tv_usec -= 1000000; 1654124861Sharti } 1655124861Sharti#else 1656122394Sharti due = evAddTime(evNowTime(), 1657124861Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 1658124861Sharti#endif 1659122394Sharti 1660122394Sharti tp->udata = udata; 1661122394Sharti tp->owner = mod; 1662122394Sharti tp->func = func; 1663122394Sharti 1664122394Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 1665122394Sharti 1666124861Sharti#ifdef USE_LIBBEGEMOT 1667124861Sharti if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000, 1668124861Sharti 0, tfunc, tp)) < 0) { 1669124861Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1670124861Sharti exit(1); 1671124861Sharti } 1672124861Sharti#else 1673122394Sharti if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1674122394Sharti == -1) { 1675122394Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1676122394Sharti exit(1); 1677122394Sharti } 1678124861Sharti#endif 1679122394Sharti return (tp); 1680122394Sharti} 1681122394Sharti 1682122394Shartivoid 1683122394Shartitimer_stop(void *p) 1684122394Sharti{ 1685122394Sharti struct timer *tp = p; 1686122394Sharti 1687122394Sharti LIST_REMOVE(tp, link); 1688124861Sharti#ifdef USE_LIBBEGEMOT 1689124861Sharti poll_stop_timer(tp->id); 1690124861Sharti#else 1691122394Sharti if (evClearTimer(evctx, tp->id) == -1) { 1692122394Sharti syslog(LOG_ERR, "cannot stop timer: %m"); 1693122394Sharti exit(1); 1694122394Sharti } 1695124861Sharti#endif 1696122394Sharti free(p); 1697122394Sharti} 1698122394Sharti 1699122394Shartistatic void 1700122394Shartitimer_flush(struct lmodule *mod) 1701122394Sharti{ 1702122394Sharti struct timer *t, *t1; 1703122394Sharti 1704122394Sharti t = LIST_FIRST(&timer_list); 1705122394Sharti while (t != NULL) { 1706122394Sharti t1 = LIST_NEXT(t, link); 1707122394Sharti if (t->owner == mod) 1708122394Sharti timer_stop(t); 1709122394Sharti t = t1; 1710122394Sharti } 1711122394Sharti} 1712122394Sharti 1713122394Shartistatic void 1714122394Shartisnmp_printf_func(const char *fmt, ...) 1715122394Sharti{ 1716122394Sharti va_list ap; 1717122394Sharti static char *pend = NULL; 1718122394Sharti char *ret, *new; 1719122394Sharti 1720122394Sharti va_start(ap, fmt); 1721122394Sharti vasprintf(&ret, fmt, ap); 1722122394Sharti va_end(ap); 1723122394Sharti 1724122394Sharti if (ret == NULL) 1725122394Sharti return; 1726122394Sharti if (pend != NULL) { 1727122394Sharti if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1728122394Sharti == NULL) { 1729122394Sharti free(ret); 1730122394Sharti return; 1731122394Sharti } 1732122394Sharti pend = new; 1733122394Sharti strcat(pend, ret); 1734122394Sharti free(ret); 1735122394Sharti } else 1736122394Sharti pend = ret; 1737122394Sharti 1738122394Sharti while ((ret = strchr(pend, '\n')) != NULL) { 1739122394Sharti *ret = '\0'; 1740122394Sharti syslog(LOG_DEBUG, "%s", pend); 1741122394Sharti if (strlen(ret + 1) == 0) { 1742122394Sharti free(pend); 1743122394Sharti pend = NULL; 1744122394Sharti break; 1745122394Sharti } 1746122394Sharti strcpy(pend, ret + 1); 1747122394Sharti } 1748122394Sharti} 1749122394Sharti 1750122394Shartistatic void 1751122394Shartisnmp_error_func(const char *err, ...) 1752122394Sharti{ 1753122394Sharti char errbuf[1000]; 1754122394Sharti va_list ap; 1755122394Sharti 1756124861Sharti if (!(snmp_trace & LOG_SNMP_ERRORS)) 1757124861Sharti return; 1758124861Sharti 1759122394Sharti va_start(ap, err); 1760122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1761124861Sharti vsnprintf(errbuf + strlen(errbuf), 1762124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 1763122394Sharti va_end(ap); 1764122394Sharti 1765122394Sharti syslog(LOG_ERR, "%s", errbuf); 1766122394Sharti} 1767122394Sharti 1768122394Shartistatic void 1769122394Shartisnmp_debug_func(const char *err, ...) 1770122394Sharti{ 1771122394Sharti char errbuf[1000]; 1772122394Sharti va_list ap; 1773122394Sharti 1774122394Sharti va_start(ap, err); 1775122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1776122394Sharti vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1777122394Sharti err, ap); 1778122394Sharti va_end(ap); 1779122394Sharti 1780122394Sharti syslog(LOG_DEBUG, "%s", errbuf); 1781122394Sharti} 1782122394Sharti 1783122394Shartistatic void 1784122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...) 1785122394Sharti{ 1786122394Sharti char errbuf[1000]; 1787122394Sharti va_list ap; 1788122394Sharti u_int i; 1789122394Sharti 1790124861Sharti if (!(snmp_trace & LOG_ASN1_ERRORS)) 1791124861Sharti return; 1792124861Sharti 1793122394Sharti va_start(ap, err); 1794122394Sharti snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 1795124861Sharti vsnprintf(errbuf + strlen(errbuf), 1796124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 1797122394Sharti va_end(ap); 1798122394Sharti 1799122394Sharti if (b != NULL) { 1800124861Sharti snprintf(errbuf + strlen(errbuf), 1801124861Sharti sizeof(errbuf) - strlen(errbuf), " at"); 1802122394Sharti for (i = 0; b->asn_len > i; i++) 1803124861Sharti snprintf(errbuf + strlen(errbuf), 1804124861Sharti sizeof(errbuf) - strlen(errbuf), 1805124861Sharti " %02x", b->asn_cptr[i]); 1806122394Sharti } 1807122394Sharti 1808122394Sharti syslog(LOG_ERR, "%s", errbuf); 1809122394Sharti} 1810122394Sharti 1811122394Sharti/* 1812122394Sharti * Create a new community 1813122394Sharti */ 1814122394Shartiu_int 1815122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner, 1816122394Sharti const char *str) 1817122394Sharti{ 1818122394Sharti struct community *c, *p; 1819122394Sharti u_int ncomm; 1820122394Sharti 1821122394Sharti /* generate an identifier */ 1822122394Sharti do { 1823122394Sharti if ((ncomm = next_community_index++) == UINT_MAX) 1824122394Sharti next_community_index = 1; 1825122394Sharti TAILQ_FOREACH(c, &community_list, link) 1826122394Sharti if (c->value == ncomm) 1827122394Sharti break; 1828122394Sharti } while (c != NULL); 1829122394Sharti 1830122394Sharti if ((c = malloc(sizeof(struct community))) == NULL) { 1831122394Sharti syslog(LOG_ERR, "comm_define: %m"); 1832122394Sharti return (0); 1833122394Sharti } 1834122394Sharti c->owner = owner; 1835122394Sharti c->value = ncomm; 1836122394Sharti c->descr = descr; 1837122394Sharti c->string = NULL; 1838122394Sharti c->private = priv; 1839122394Sharti 1840122394Sharti if (str != NULL) { 1841122394Sharti if((c->string = malloc(strlen(str)+1)) == NULL) { 1842122394Sharti free(c); 1843122394Sharti return (0); 1844122394Sharti } 1845122394Sharti strcpy(c->string, str); 1846122394Sharti } 1847122394Sharti 1848122394Sharti /* make index */ 1849122394Sharti if (c->owner == NULL) { 1850122394Sharti c->index.len = 1; 1851122394Sharti c->index.subs[0] = 0; 1852122394Sharti } else { 1853122394Sharti c->index = c->owner->index; 1854122394Sharti } 1855122394Sharti c->index.subs[c->index.len++] = c->private; 1856122394Sharti 1857122394Sharti /* 1858122394Sharti * Insert ordered 1859122394Sharti */ 1860122394Sharti TAILQ_FOREACH(p, &community_list, link) { 1861122394Sharti if (asn_compare_oid(&p->index, &c->index) > 0) { 1862122394Sharti TAILQ_INSERT_BEFORE(p, c, link); 1863122394Sharti break; 1864122394Sharti } 1865122394Sharti } 1866122394Sharti if (p == NULL) 1867122394Sharti TAILQ_INSERT_TAIL(&community_list, c, link); 1868122394Sharti return (c->value); 1869122394Sharti} 1870122394Sharti 1871122394Sharticonst char * 1872122394Sharticomm_string(u_int ncomm) 1873122394Sharti{ 1874122394Sharti struct community *p; 1875122394Sharti 1876122394Sharti TAILQ_FOREACH(p, &community_list, link) 1877122394Sharti if (p->value == ncomm) 1878122394Sharti return (p->string); 1879122394Sharti return (NULL); 1880122394Sharti} 1881122394Sharti 1882122394Sharti/* 1883122394Sharti * Delete all communities allocated by a module 1884122394Sharti */ 1885122394Shartistatic void 1886122394Sharticomm_flush(struct lmodule *mod) 1887122394Sharti{ 1888122394Sharti struct community *p, *p1; 1889122394Sharti 1890122394Sharti p = TAILQ_FIRST(&community_list); 1891122394Sharti while (p != NULL) { 1892122394Sharti p1 = TAILQ_NEXT(p, link); 1893122394Sharti if (p->owner == mod) { 1894122394Sharti free(p->string); 1895122394Sharti TAILQ_REMOVE(&community_list, p, link); 1896122394Sharti free(p); 1897122394Sharti } 1898122394Sharti p = p1; 1899122394Sharti } 1900122394Sharti} 1901122394Sharti 1902122394Sharti/* 1903122394Sharti * Request ID handling. 1904122394Sharti * 1905122394Sharti * Allocate a new range of request ids. Use a first fit algorithm. 1906122394Sharti */ 1907122394Shartiu_int 1908122394Shartireqid_allocate(int size, struct lmodule *mod) 1909122394Sharti{ 1910122394Sharti u_int type; 1911122394Sharti struct idrange *r, *r1; 1912122394Sharti 1913122394Sharti if (size <= 0 || size > INT32_MAX) { 1914122394Sharti syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1915122394Sharti return (0); 1916122394Sharti } 1917122394Sharti /* allocate a type id */ 1918122394Sharti do { 1919122394Sharti if ((type = next_idrange++) == UINT_MAX) 1920122394Sharti next_idrange = 1; 1921122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1922122394Sharti if (r->type == type) 1923122394Sharti break; 1924122394Sharti } while(r != NULL); 1925122394Sharti 1926122394Sharti /* find a range */ 1927122394Sharti if (TAILQ_EMPTY(&idrange_list)) 1928122394Sharti r = NULL; 1929122394Sharti else { 1930122394Sharti r = TAILQ_FIRST(&idrange_list); 1931122394Sharti if (r->base < size) { 1932122394Sharti while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1933122394Sharti if (r1->base - (r->base + r->size) >= size) 1934122394Sharti break; 1935122394Sharti r = r1; 1936122394Sharti } 1937122394Sharti r = r1; 1938122394Sharti } 1939122394Sharti if (r == NULL) { 1940122394Sharti r1 = TAILQ_LAST(&idrange_list, idrange_list); 1941122394Sharti if (INT32_MAX - size + 1 < r1->base + r1->size) { 1942122394Sharti syslog(LOG_ERR, "out of id ranges (%u)", size); 1943122394Sharti return (0); 1944122394Sharti } 1945122394Sharti } 1946122394Sharti } 1947122394Sharti 1948122394Sharti /* allocate structure */ 1949122394Sharti if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 1950122394Sharti syslog(LOG_ERR, "%s: %m", __FUNCTION__); 1951122394Sharti return (0); 1952122394Sharti } 1953122394Sharti 1954122394Sharti r1->type = type; 1955122394Sharti r1->size = size; 1956122394Sharti r1->owner = mod; 1957122394Sharti if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 1958122394Sharti r1->base = 0; 1959122394Sharti TAILQ_INSERT_HEAD(&idrange_list, r1, link); 1960122394Sharti } else if (r == NULL) { 1961122394Sharti r = TAILQ_LAST(&idrange_list, idrange_list); 1962122394Sharti r1->base = r->base + r->size; 1963122394Sharti TAILQ_INSERT_TAIL(&idrange_list, r1, link); 1964122394Sharti } else { 1965122394Sharti r = TAILQ_PREV(r, idrange_list, link); 1966122394Sharti r1->base = r->base + r->size; 1967122394Sharti TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 1968122394Sharti } 1969122394Sharti r1->next = r1->base; 1970122394Sharti 1971122394Sharti return (type); 1972122394Sharti} 1973122394Sharti 1974122394Shartiint32_t 1975122394Shartireqid_next(u_int type) 1976122394Sharti{ 1977122394Sharti struct idrange *r; 1978122394Sharti int32_t id; 1979122394Sharti 1980122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1981122394Sharti if (r->type == type) 1982122394Sharti break; 1983122394Sharti if (r == NULL) { 1984122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 1985122394Sharti abort(); 1986122394Sharti } 1987122394Sharti if ((id = r->next++) == r->base + (r->size - 1)) 1988122394Sharti r->next = r->base; 1989122394Sharti return (id); 1990122394Sharti} 1991122394Sharti 1992122394Shartiint32_t 1993122394Shartireqid_base(u_int type) 1994122394Sharti{ 1995122394Sharti struct idrange *r; 1996122394Sharti 1997122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1998122394Sharti if (r->type == type) 1999122394Sharti return (r->base); 2000122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2001122394Sharti abort(); 2002122394Sharti} 2003122394Sharti 2004122394Shartiu_int 2005122394Shartireqid_type(int32_t reqid) 2006122394Sharti{ 2007122394Sharti struct idrange *r; 2008122394Sharti 2009122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2010122394Sharti if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2011122394Sharti return (r->type); 2012122394Sharti return (0); 2013122394Sharti} 2014122394Sharti 2015122394Shartiint 2016122394Shartireqid_istype(int32_t reqid, u_int type) 2017122394Sharti{ 2018122394Sharti return (reqid_type(reqid) == type); 2019122394Sharti} 2020122394Sharti 2021122394Sharti/* 2022122394Sharti * Delete all communities allocated by a module 2023122394Sharti */ 2024122394Shartistatic void 2025122394Shartireqid_flush(struct lmodule *mod) 2026122394Sharti{ 2027122394Sharti struct idrange *p, *p1; 2028122394Sharti 2029122394Sharti p = TAILQ_FIRST(&idrange_list); 2030122394Sharti while (p != NULL) { 2031122394Sharti p1 = TAILQ_NEXT(p, link); 2032122394Sharti if (p->owner == mod) { 2033122394Sharti TAILQ_REMOVE(&idrange_list, p, link); 2034122394Sharti free(p); 2035122394Sharti } 2036122394Sharti p = p1; 2037122394Sharti } 2038122394Sharti} 2039122394Sharti 2040122394Sharti/* 2041122394Sharti * Merge the given tree for the given module into the main tree. 2042122394Sharti */ 2043122394Shartistatic int 2044122394Sharticompare_node(const void *v1, const void *v2) 2045122394Sharti{ 2046122394Sharti const struct snmp_node *n1 = v1; 2047122394Sharti const struct snmp_node *n2 = v2; 2048122394Sharti 2049122394Sharti return (asn_compare_oid(&n1->oid, &n2->oid)); 2050122394Sharti} 2051122394Shartistatic int 2052122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2053122394Sharti{ 2054122394Sharti struct snmp_node *xtree; 2055122394Sharti u_int i; 2056122394Sharti 2057122394Sharti xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2058122394Sharti if (xtree == NULL) { 2059128237Sharti syslog(LOG_ERR, "tree_merge: %m"); 2060122394Sharti return (-1); 2061122394Sharti } 2062122394Sharti tree = xtree; 2063122394Sharti memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2064122394Sharti 2065122394Sharti for (i = 0; i < nsize; i++) 2066128237Sharti tree[tree_size + i].tree_data = mod; 2067122394Sharti 2068122394Sharti tree_size += nsize; 2069122394Sharti 2070122394Sharti qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2071122394Sharti 2072122394Sharti return (0); 2073122394Sharti} 2074122394Sharti 2075122394Sharti/* 2076122394Sharti * Remove all nodes belonging to the loadable module 2077122394Sharti */ 2078122394Shartistatic void 2079122394Shartitree_unmerge(struct lmodule *mod) 2080122394Sharti{ 2081122394Sharti u_int s, d; 2082122394Sharti 2083122394Sharti for(s = d = 0; s < tree_size; s++) 2084128237Sharti if (tree[s].tree_data != mod) { 2085122394Sharti if (s != d) 2086122394Sharti tree[d] = tree[s]; 2087122394Sharti d++; 2088122394Sharti } 2089122394Sharti tree_size = d; 2090122394Sharti} 2091122394Sharti 2092122394Sharti/* 2093122394Sharti * Loadable modules 2094122394Sharti */ 2095122394Shartistruct lmodule * 2096122394Shartilm_load(const char *path, const char *section) 2097122394Sharti{ 2098122394Sharti struct lmodule *m; 2099122394Sharti int err; 2100122394Sharti int i; 2101122394Sharti char *av[MAX_MOD_ARGS + 1]; 2102122394Sharti int ac; 2103122394Sharti u_int u; 2104122394Sharti 2105122394Sharti if ((m = malloc(sizeof(*m))) == NULL) { 2106122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2107122394Sharti return (NULL); 2108122394Sharti } 2109122394Sharti m->handle = NULL; 2110122394Sharti m->flags = 0; 2111122394Sharti strcpy(m->section, section); 2112122394Sharti 2113122394Sharti if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2114122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2115122394Sharti goto err; 2116122394Sharti } 2117122394Sharti strcpy(m->path, path); 2118122394Sharti 2119122394Sharti /* 2120122394Sharti * Make index 2121122394Sharti */ 2122122394Sharti m->index.subs[0] = strlen(section); 2123122394Sharti m->index.len = m->index.subs[0] + 1; 2124122394Sharti for (u = 0; u < m->index.subs[0]; u++) 2125122394Sharti m->index.subs[u + 1] = section[u]; 2126122394Sharti 2127122394Sharti /* 2128122394Sharti * Load the object file and locate the config structure 2129122394Sharti */ 2130122394Sharti if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2131122394Sharti syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2132122394Sharti goto err; 2133122394Sharti } 2134122394Sharti 2135122394Sharti if ((m->config = dlsym(m->handle, "config")) == NULL) { 2136122394Sharti syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2137122394Sharti goto err; 2138122394Sharti } 2139122394Sharti 2140122394Sharti /* 2141122394Sharti * Insert it into the right place 2142122394Sharti */ 2143122394Sharti INSERT_OBJECT_OID(m, &lmodules); 2144122394Sharti 2145122394Sharti /* preserve order */ 2146122394Sharti if (community == COMM_INITIALIZE) { 2147122394Sharti m->flags |= LM_ONSTARTLIST; 2148122394Sharti TAILQ_INSERT_TAIL(&modules_start, m, start); 2149122394Sharti } 2150122394Sharti 2151122394Sharti /* 2152122394Sharti * make the argument vector. 2153122394Sharti */ 2154122394Sharti ac = 0; 2155122394Sharti for (i = 0; i < nprogargs; i++) { 2156122394Sharti if (strlen(progargs[i]) >= strlen(section) + 1 && 2157122394Sharti strncmp(progargs[i], section, strlen(section)) == 0 && 2158122394Sharti progargs[i][strlen(section)] == ':') { 2159122394Sharti if (ac == MAX_MOD_ARGS) { 2160122394Sharti syslog(LOG_WARNING, "too many arguments for " 2161122394Sharti "module '%s", section); 2162122394Sharti break; 2163122394Sharti } 2164122394Sharti av[ac++] = &progargs[i][strlen(section)+1]; 2165122394Sharti } 2166122394Sharti } 2167122394Sharti av[ac] = NULL; 2168122394Sharti 2169122394Sharti /* 2170122394Sharti * Run the initialisation function 2171122394Sharti */ 2172122394Sharti if ((err = (*m->config->init)(m, ac, av)) != 0) { 2173122394Sharti syslog(LOG_ERR, "lm_load: init failed: %d", err); 2174122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2175122394Sharti goto err; 2176122394Sharti } 2177122394Sharti 2178122394Sharti return (m); 2179122394Sharti 2180122394Sharti err: 2181122394Sharti if (m->handle) 2182122394Sharti dlclose(m->handle); 2183122394Sharti free(m->path); 2184122394Sharti free(m); 2185122394Sharti return (NULL); 2186122394Sharti} 2187122394Sharti 2188122394Sharti/* 2189122394Sharti * Start a module 2190122394Sharti */ 2191122394Shartivoid 2192122394Shartilm_start(struct lmodule *mod) 2193122394Sharti{ 2194122394Sharti const struct lmodule *m; 2195122394Sharti 2196122394Sharti /* 2197122394Sharti * Merge tree. If this fails, unload the module. 2198122394Sharti */ 2199122394Sharti if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2200122394Sharti lm_unload(mod); 2201122394Sharti return; 2202122394Sharti } 2203122394Sharti 2204122394Sharti /* 2205122394Sharti * Read configuration 2206122394Sharti */ 2207122394Sharti if (read_config(config_file, mod)) { 2208122394Sharti syslog(LOG_ERR, "error in config file"); 2209122394Sharti lm_unload(mod); 2210122394Sharti return; 2211122394Sharti } 2212122394Sharti if (mod->config->start) 2213122394Sharti (*mod->config->start)(); 2214122394Sharti 2215122394Sharti mod->flags |= LM_STARTED; 2216122394Sharti 2217122394Sharti /* 2218122394Sharti * Inform other modules 2219122394Sharti */ 2220122394Sharti TAILQ_FOREACH(m, &lmodules, link) 2221122394Sharti if (m->config->loading) 2222122394Sharti (*m->config->loading)(mod, 1); 2223122394Sharti} 2224122394Sharti 2225122394Sharti 2226122394Sharti/* 2227122394Sharti * Unload a module. 2228122394Sharti */ 2229122394Shartivoid 2230122394Shartilm_unload(struct lmodule *m) 2231122394Sharti{ 2232122394Sharti int err; 2233122394Sharti const struct lmodule *mod; 2234122394Sharti 2235122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2236122394Sharti if (m->flags & LM_ONSTARTLIST) 2237122394Sharti TAILQ_REMOVE(&modules_start, m, start); 2238122394Sharti tree_unmerge(m); 2239122394Sharti 2240122394Sharti if ((m->flags & LM_STARTED) && m->config->fini && 2241122394Sharti (err = (*m->config->fini)()) != 0) 2242122394Sharti syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2243122394Sharti 2244122394Sharti comm_flush(m); 2245122394Sharti reqid_flush(m); 2246122394Sharti timer_flush(m); 2247122394Sharti fd_flush(m); 2248122394Sharti 2249122394Sharti dlclose(m->handle); 2250122394Sharti free(m->path); 2251122394Sharti 2252122394Sharti /* 2253122394Sharti * Inform other modules 2254122394Sharti */ 2255122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 2256122394Sharti if (mod->config->loading) 2257122394Sharti (*mod->config->loading)(m, 0); 2258122394Sharti 2259122394Sharti free(m); 2260122394Sharti} 2261122394Sharti 2262122394Sharti/* 2263122394Sharti * Register an object resource and return the index (or 0 on failures) 2264122394Sharti */ 2265122394Shartiu_int 2266122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2267122394Sharti{ 2268122394Sharti struct objres *objres, *or1; 2269122394Sharti u_int idx; 2270122394Sharti 2271122394Sharti /* find a free index */ 2272122394Sharti idx = 1; 2273122394Sharti for (objres = TAILQ_FIRST(&objres_list); 2274122394Sharti objres != NULL; 2275122394Sharti objres = TAILQ_NEXT(objres, link)) { 2276122394Sharti if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2277122394Sharti or1->index > objres->index + 1) { 2278122394Sharti idx = objres->index + 1; 2279122394Sharti break; 2280122394Sharti } 2281122394Sharti } 2282122394Sharti 2283122394Sharti if ((objres = malloc(sizeof(*objres))) == NULL) 2284122394Sharti return (0); 2285122394Sharti 2286122394Sharti objres->index = idx; 2287122394Sharti objres->oid = *or; 2288122394Sharti strlcpy(objres->descr, descr, sizeof(objres->descr)); 2289122394Sharti objres->uptime = get_ticks() - start_tick; 2290122394Sharti objres->module = mod; 2291122394Sharti 2292122394Sharti INSERT_OBJECT_INT(objres, &objres_list); 2293122394Sharti 2294122394Sharti systemg.or_last_change = objres->uptime; 2295122394Sharti 2296122394Sharti return (idx); 2297122394Sharti} 2298122394Sharti 2299122394Shartivoid 2300122394Shartior_unregister(u_int idx) 2301122394Sharti{ 2302122394Sharti struct objres *objres; 2303122394Sharti 2304122394Sharti TAILQ_FOREACH(objres, &objres_list, link) 2305122394Sharti if (objres->index == idx) { 2306122394Sharti TAILQ_REMOVE(&objres_list, objres, link); 2307122394Sharti free(objres); 2308122394Sharti return; 2309122394Sharti } 2310122394Sharti} 2311