main.c revision 156066
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 * 29156066Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 30122394Sharti * 31122394Sharti * SNMPd main stuff. 32122394Sharti */ 33122394Sharti#include <sys/param.h> 34122394Sharti#include <sys/un.h> 35124861Sharti#include <sys/ucred.h> 36150920Sharti#include <sys/uio.h> 37122394Sharti#include <stdio.h> 38122394Sharti#include <stdlib.h> 39122394Sharti#include <stddef.h> 40122394Sharti#include <string.h> 41122394Sharti#include <stdarg.h> 42122394Sharti#include <ctype.h> 43122394Sharti#include <errno.h> 44122394Sharti#include <syslog.h> 45122394Sharti#include <unistd.h> 46122394Sharti#include <signal.h> 47122394Sharti#include <dlfcn.h> 48122394Sharti#include <inttypes.h> 49122394Sharti 50145557Sharti#ifdef USE_TCPWRAPPERS 51145557Sharti#include <arpa/inet.h> 52145557Sharti#include <tcpd.h> 53145557Sharti#endif 54145557Sharti 55156066Sharti#include "support.h" 56122394Sharti#include "snmpmod.h" 57122394Sharti#include "snmpd.h" 58122394Sharti#include "tree.h" 59122394Sharti#include "oid.h" 60122394Sharti 61122394Sharti#define PATH_PID "/var/run/%s.pid" 62122394Sharti#define PATH_CONFIG "/etc/%s.config" 63122394Sharti 64146525Shartiuint64_t this_tick; /* start of processing of current packet (absolute) */ 65146525Shartiuint64_t start_tick; /* start of processing */ 66122394Sharti 67122394Shartistruct systemg systemg = { 68122394Sharti NULL, 69122394Sharti { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 70122394Sharti NULL, NULL, NULL, 71122394Sharti 64 + 8 + 4, 72122394Sharti 0 73122394Sharti}; 74122394Shartistruct debug debug = { 75122394Sharti 0, /* dump_pdus */ 76122394Sharti LOG_DEBUG, /* log_pri */ 77122394Sharti 0, /* evdebug */ 78122394Sharti}; 79122394Sharti 80122394Shartistruct snmpd snmpd = { 81122394Sharti 2048, /* txbuf */ 82122394Sharti 2048, /* rxbuf */ 83122394Sharti 0, /* comm_dis */ 84122394Sharti 0, /* auth_traps */ 85122394Sharti {0, 0, 0, 0}, /* trap1addr */ 86124861Sharti VERS_ENABLE_ALL,/* version_enable */ 87122394Sharti}; 88122394Shartistruct snmpd_stats snmpd_stats; 89122394Sharti 90122394Sharti/* snmpSerialNo */ 91122394Shartiint32_t snmp_serial_no; 92122394Sharti 93122394Sharti/* search path for config files */ 94122394Sharticonst char *syspath = PATH_SYSCONFIG; 95122394Sharti 96122394Sharti/* list of all loaded modules */ 97122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 98122394Sharti 99122394Sharti/* list of loaded modules during start-up in the order they were loaded */ 100122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 101122394Sharti 102122394Sharti/* list of all known communities */ 103122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 104122394Sharti 105122394Sharti/* list of all installed object resources */ 106122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 107122394Sharti 108122394Sharti/* community value generator */ 109122394Shartistatic u_int next_community_index = 1; 110122394Sharti 111122394Sharti/* list of all known ranges */ 112122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 113122394Sharti 114122394Sharti/* identifier generator */ 115122394Shartiu_int next_idrange = 1; 116122394Sharti 117122394Sharti/* list of all current timers */ 118122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 119122394Sharti 120122394Sharti/* list of file descriptors */ 121122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 122122394Sharti 123122394Sharti/* program arguments */ 124122394Shartistatic char **progargs; 125122394Shartistatic int nprogargs; 126122394Sharti 127122394Sharti/* current community */ 128122394Shartiu_int community; 129122394Shartistatic struct community *comm; 130122394Sharti 131122394Sharti/* file names */ 132122394Shartistatic char config_file[MAXPATHLEN + 1]; 133122394Shartistatic char pid_file[MAXPATHLEN + 1]; 134122394Sharti 135124861Sharti#ifndef USE_LIBBEGEMOT 136122394Sharti/* event context */ 137122394Shartistatic evContext evctx; 138124861Sharti#endif 139122394Sharti 140122394Sharti/* signal mask */ 141122394Shartistatic sigset_t blocked_sigs; 142122394Sharti 143122394Sharti/* signal handling */ 144122394Shartistatic int work; 145122394Sharti#define WORK_DOINFO 0x0001 146122394Sharti#define WORK_RECONFIG 0x0002 147122394Sharti 148122394Sharti/* oids */ 149122394Shartistatic const struct asn_oid 150122394Sharti oid_snmpMIB = OIDX_snmpMIB, 151122394Sharti oid_begemotSnmpd = OIDX_begemotSnmpd, 152122394Sharti oid_coldStart = OIDX_coldStart, 153122394Sharti oid_authenticationFailure = OIDX_authenticationFailure; 154122394Sharti 155122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 156122394Sharti 157122394Sharti/* request id generator for traps */ 158122394Shartiu_int trap_reqid; 159122394Sharti 160122394Sharti/* help text */ 161122394Shartistatic const char usgtxt[] = "\ 162122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 163122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 164122394Shartiusage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 165122394Sharti [-m variable=value] [-p file]\n\ 166122394Shartioptions:\n\ 167122394Sharti -d don't daemonize\n\ 168122394Sharti -h print this info\n\ 169122394Sharti -c file specify configuration file\n\ 170122394Sharti -D options debugging options\n\ 171122394Sharti -I path system include path\n\ 172122394Sharti -l prefix default basename for pid and config file\n\ 173122394Sharti -m var=val define variable\n\ 174122394Sharti -p file specify pid file\n\ 175122394Sharti"; 176122394Sharti 177145557Sharti/* hosts_access(3) request */ 178145557Sharti#ifdef USE_TCPWRAPPERS 179145557Shartistatic struct request_info req; 180145557Sharti#endif 181145557Sharti 182124861Sharti/* transports */ 183124861Shartiextern const struct transport_def udp_trans; 184124861Shartiextern const struct transport_def lsock_trans; 185124861Sharti 186124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 187124861Sharti 188122394Sharti/* forward declarations */ 189122394Shartistatic void snmp_printf_func(const char *fmt, ...); 190122394Shartistatic void snmp_error_func(const char *err, ...); 191122394Shartistatic void snmp_debug_func(const char *err, ...); 192122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...); 193122394Sharti 194122394Sharti/* 195122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx. 196122394Sharti */ 197122394Shartivoid * 198122394Shartibuf_alloc(int tx) 199122394Sharti{ 200122394Sharti void *buf; 201122394Sharti 202124861Sharti if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 203122394Sharti syslog(LOG_CRIT, "cannot allocate buffer"); 204122394Sharti if (tx) 205122394Sharti snmpd_stats.noTxbuf++; 206122394Sharti else 207122394Sharti snmpd_stats.noRxbuf++; 208122394Sharti return (NULL); 209122394Sharti } 210122394Sharti return (buf); 211122394Sharti} 212122394Sharti 213122394Sharti/* 214124861Sharti * Return the buffer size. 215122394Sharti */ 216122394Shartisize_t 217122394Shartibuf_size(int tx) 218122394Sharti{ 219124861Sharti return (tx ? snmpd.txbuf : snmpd.rxbuf); 220122394Sharti} 221122394Sharti 222122394Sharti/* 223122394Sharti * Prepare a PDU for output 224122394Sharti */ 225122394Shartivoid 226124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 227122394Sharti const char *dest) 228122394Sharti{ 229122394Sharti struct asn_buf resp_b; 230122394Sharti 231122394Sharti resp_b.asn_ptr = sndbuf; 232122394Sharti resp_b.asn_len = snmpd.txbuf; 233122394Sharti 234122394Sharti if (snmp_pdu_encode(pdu, &resp_b) != 0) { 235122394Sharti syslog(LOG_ERR, "cannot encode message"); 236122394Sharti abort(); 237122394Sharti } 238122394Sharti if (debug.dump_pdus) { 239122394Sharti snmp_printf("%s <- ", dest); 240122394Sharti snmp_pdu_dump(pdu); 241122394Sharti } 242122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 243122394Sharti} 244122394Sharti 245122394Sharti/* 246122394Sharti * SNMP input. Start: decode the PDU, find the community. 247122394Sharti */ 248122394Shartienum snmpd_input_err 249122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source, 250124861Sharti struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 251122394Sharti{ 252122394Sharti struct asn_buf b; 253122394Sharti enum snmp_code code; 254122394Sharti enum snmpd_input_err ret; 255124861Sharti int sret; 256122394Sharti 257122394Sharti b.asn_cptr = buf; 258122394Sharti b.asn_len = len; 259124861Sharti 260124861Sharti /* look whether we have enough bytes for the entire PDU. */ 261124861Sharti switch (sret = snmp_pdu_snoop(&b)) { 262124861Sharti 263124861Sharti case 0: 264124861Sharti return (SNMPD_INPUT_TRUNC); 265124861Sharti 266124861Sharti case -1: 267124861Sharti snmpd_stats.inASNParseErrs++; 268124861Sharti return (SNMPD_INPUT_FAILED); 269124861Sharti } 270124861Sharti b.asn_len = *pdulen = (size_t)sret; 271124861Sharti 272122394Sharti code = snmp_pdu_decode(&b, pdu, ip); 273122394Sharti 274124861Sharti snmpd_stats.inPkts++; 275124861Sharti 276122394Sharti ret = SNMPD_INPUT_OK; 277122394Sharti switch (code) { 278122394Sharti 279122394Sharti case SNMP_CODE_FAILED: 280122394Sharti snmpd_stats.inASNParseErrs++; 281122394Sharti return (SNMPD_INPUT_FAILED); 282122394Sharti 283122394Sharti case SNMP_CODE_BADVERS: 284124861Sharti bad_vers: 285122394Sharti snmpd_stats.inBadVersions++; 286122394Sharti return (SNMPD_INPUT_FAILED); 287122394Sharti 288122394Sharti case SNMP_CODE_BADLEN: 289122394Sharti if (pdu->type == SNMP_OP_SET) 290122394Sharti ret = SNMPD_INPUT_VALBADLEN; 291122394Sharti break; 292122394Sharti 293122394Sharti case SNMP_CODE_OORANGE: 294122394Sharti if (pdu->type == SNMP_OP_SET) 295122394Sharti ret = SNMPD_INPUT_VALRANGE; 296122394Sharti break; 297122394Sharti 298122394Sharti case SNMP_CODE_BADENC: 299122394Sharti if (pdu->type == SNMP_OP_SET) 300122394Sharti ret = SNMPD_INPUT_VALBADENC; 301122394Sharti break; 302122394Sharti 303122394Sharti case SNMP_CODE_OK: 304124861Sharti switch (pdu->version) { 305124861Sharti 306124861Sharti case SNMP_V1: 307124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V1)) 308124861Sharti goto bad_vers; 309124861Sharti break; 310124861Sharti 311124861Sharti case SNMP_V2c: 312124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 313124861Sharti goto bad_vers; 314124861Sharti break; 315124861Sharti 316124861Sharti case SNMP_Verr: 317124861Sharti goto bad_vers; 318124861Sharti } 319122394Sharti break; 320122394Sharti } 321122394Sharti 322122394Sharti if (debug.dump_pdus) { 323122394Sharti snmp_printf("%s -> ", source); 324122394Sharti snmp_pdu_dump(pdu); 325122394Sharti } 326122394Sharti 327122394Sharti /* 328122394Sharti * Look, whether we know the community 329122394Sharti */ 330122394Sharti TAILQ_FOREACH(comm, &community_list, link) 331122394Sharti if (comm->string != NULL && 332122394Sharti strcmp(comm->string, pdu->community) == 0) 333122394Sharti break; 334122394Sharti 335122394Sharti if (comm == NULL) { 336122394Sharti snmpd_stats.inBadCommunityNames++; 337122394Sharti snmp_pdu_free(pdu); 338122394Sharti if (snmpd.auth_traps) 339133211Sharti snmp_send_trap(&oid_authenticationFailure, 340133211Sharti (struct snmp_value *)NULL); 341133211Sharti ret = SNMPD_INPUT_BAD_COMM; 342133211Sharti } else 343133211Sharti community = comm->value; 344122394Sharti 345122394Sharti /* update uptime */ 346122394Sharti this_tick = get_ticks(); 347122394Sharti 348122394Sharti return (ret); 349122394Sharti} 350122394Sharti 351122394Sharti/* 352122394Sharti * Will return only _OK or _FAILED 353122394Sharti */ 354122394Shartienum snmpd_input_err 355122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 356122394Sharti u_char *sndbuf, size_t *sndlen, const char *source, 357122394Sharti enum snmpd_input_err ierr, int32_t ivar, void *data) 358122394Sharti{ 359122394Sharti struct snmp_pdu resp; 360122394Sharti struct asn_buf resp_b, pdu_b; 361122394Sharti enum snmp_ret ret; 362122394Sharti 363122394Sharti resp_b.asn_ptr = sndbuf; 364122394Sharti resp_b.asn_len = snmpd.txbuf; 365122394Sharti 366122394Sharti pdu_b.asn_cptr = rcvbuf; 367122394Sharti pdu_b.asn_len = rcvlen; 368122394Sharti 369122394Sharti if (ierr != SNMPD_INPUT_OK) { 370122394Sharti /* error decoding the input of a SET */ 371122394Sharti if (pdu->version == SNMP_V1) 372122394Sharti pdu->error_status = SNMP_ERR_BADVALUE; 373122394Sharti else if (ierr == SNMPD_INPUT_VALBADLEN) 374122394Sharti pdu->error_status = SNMP_ERR_WRONG_LENGTH; 375122394Sharti else if (ierr == SNMPD_INPUT_VALRANGE) 376122394Sharti pdu->error_status = SNMP_ERR_WRONG_VALUE; 377122394Sharti else 378122394Sharti pdu->error_status = SNMP_ERR_WRONG_ENCODING; 379122394Sharti 380122394Sharti pdu->error_index = ivar; 381122394Sharti 382122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 383122394Sharti syslog(LOG_WARNING, "could not encode error response"); 384122394Sharti snmpd_stats.silentDrops++; 385122394Sharti return (SNMPD_INPUT_FAILED); 386122394Sharti } 387122394Sharti 388122394Sharti if (debug.dump_pdus) { 389122394Sharti snmp_printf("%s <- ", source); 390122394Sharti snmp_pdu_dump(pdu); 391122394Sharti } 392122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 393122394Sharti return (SNMPD_INPUT_OK); 394122394Sharti } 395122394Sharti 396122394Sharti switch (pdu->type) { 397122394Sharti 398122394Sharti case SNMP_PDU_GET: 399122394Sharti ret = snmp_get(pdu, &resp_b, &resp, data); 400122394Sharti break; 401122394Sharti 402122394Sharti case SNMP_PDU_GETNEXT: 403122394Sharti ret = snmp_getnext(pdu, &resp_b, &resp, data); 404122394Sharti break; 405122394Sharti 406122394Sharti case SNMP_PDU_SET: 407122394Sharti ret = snmp_set(pdu, &resp_b, &resp, data); 408122394Sharti break; 409122394Sharti 410122394Sharti case SNMP_PDU_GETBULK: 411122394Sharti ret = snmp_getbulk(pdu, &resp_b, &resp, data); 412122394Sharti break; 413122394Sharti 414122394Sharti default: 415122394Sharti ret = SNMP_RET_IGN; 416122394Sharti break; 417122394Sharti } 418122394Sharti 419122394Sharti switch (ret) { 420122394Sharti 421122394Sharti case SNMP_RET_OK: 422122394Sharti /* normal return - send a response */ 423122394Sharti if (debug.dump_pdus) { 424122394Sharti snmp_printf("%s <- ", source); 425122394Sharti snmp_pdu_dump(&resp); 426122394Sharti } 427122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 428122394Sharti snmp_pdu_free(&resp); 429122394Sharti return (SNMPD_INPUT_OK); 430122394Sharti 431122394Sharti case SNMP_RET_IGN: 432122394Sharti /* error - send nothing */ 433122394Sharti snmpd_stats.silentDrops++; 434122394Sharti return (SNMPD_INPUT_FAILED); 435122394Sharti 436122394Sharti case SNMP_RET_ERR: 437122394Sharti /* error - send error response. The snmp routine has 438122394Sharti * changed the error fields in the original message. */ 439122394Sharti resp_b.asn_ptr = sndbuf; 440122394Sharti resp_b.asn_len = snmpd.txbuf; 441122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 442122394Sharti syslog(LOG_WARNING, "could not encode error response"); 443122394Sharti snmpd_stats.silentDrops++; 444122394Sharti return (SNMPD_INPUT_FAILED); 445122394Sharti } else { 446122394Sharti if (debug.dump_pdus) { 447122394Sharti snmp_printf("%s <- ", source); 448122394Sharti snmp_pdu_dump(pdu); 449122394Sharti } 450122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 451122394Sharti return (SNMPD_INPUT_OK); 452122394Sharti } 453122394Sharti } 454122394Sharti abort(); 455122394Sharti} 456122394Sharti 457124861Sharti/* 458124861Sharti * Insert a port into the right place in the transport's table of ports 459124861Sharti */ 460124861Shartivoid 461124861Shartitrans_insert_port(struct transport *t, struct tport *port) 462124861Sharti{ 463124861Sharti struct tport *p; 464122394Sharti 465124861Sharti TAILQ_FOREACH(p, &t->table, link) { 466124861Sharti if (asn_compare_oid(&p->index, &port->index) > 0) { 467124861Sharti TAILQ_INSERT_BEFORE(p, port, link); 468124861Sharti return; 469124861Sharti } 470124861Sharti } 471124861Sharti port->transport = t; 472124861Sharti TAILQ_INSERT_TAIL(&t->table, port, link); 473124861Sharti} 474122394Sharti 475122394Sharti/* 476124861Sharti * Remove a port from a transport's list 477124861Sharti */ 478124861Shartivoid 479124861Shartitrans_remove_port(struct tport *port) 480124861Sharti{ 481124861Sharti 482124861Sharti TAILQ_REMOVE(&port->transport->table, port, link); 483124861Sharti} 484124861Sharti 485124861Sharti/* 486124861Sharti * Find a port on a transport's list 487124861Sharti */ 488124861Shartistruct tport * 489124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 490124861Sharti{ 491124861Sharti 492124861Sharti return (FIND_OBJECT_OID(&t->table, idx, sub)); 493124861Sharti} 494124861Sharti 495124861Sharti/* 496124861Sharti * Find next port on a transport's list 497124861Sharti */ 498124861Shartistruct tport * 499124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 500124861Sharti{ 501124861Sharti 502124861Sharti return (NEXT_OBJECT_OID(&t->table, idx, sub)); 503124861Sharti} 504124861Sharti 505124861Sharti/* 506124861Sharti * Return first port 507124861Sharti */ 508124861Shartistruct tport * 509124861Shartitrans_first_port(struct transport *t) 510124861Sharti{ 511124861Sharti 512124861Sharti return (TAILQ_FIRST(&t->table)); 513124861Sharti} 514124861Sharti 515124861Sharti/* 516124861Sharti * Iterate through all ports until a function returns a 0. 517124861Sharti */ 518124861Shartistruct tport * 519124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 520124861Sharti intptr_t arg) 521124861Sharti{ 522124861Sharti struct tport *p; 523124861Sharti 524124861Sharti TAILQ_FOREACH(p, &t->table, link) 525124861Sharti if (func(p, arg) == 0) 526124861Sharti return (p); 527124861Sharti return (NULL); 528124861Sharti} 529124861Sharti 530124861Sharti/* 531124861Sharti * Register a transport 532124861Sharti */ 533124861Shartiint 534124861Shartitrans_register(const struct transport_def *def, struct transport **pp) 535124861Sharti{ 536124861Sharti u_int i; 537124861Sharti char or_descr[256]; 538124861Sharti 539124861Sharti if ((*pp = malloc(sizeof(**pp))) == NULL) 540124861Sharti return (SNMP_ERR_GENERR); 541124861Sharti 542124861Sharti /* construct index */ 543124861Sharti (*pp)->index.len = strlen(def->name) + 1; 544124861Sharti (*pp)->index.subs[0] = strlen(def->name); 545124861Sharti for (i = 0; i < (*pp)->index.subs[0]; i++) 546124861Sharti (*pp)->index.subs[i + 1] = def->name[i]; 547124861Sharti 548124861Sharti (*pp)->vtab = def; 549124861Sharti 550124861Sharti if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 551124861Sharti free(*pp); 552124861Sharti return (SNMP_ERR_INCONS_VALUE); 553124861Sharti } 554124861Sharti 555124861Sharti /* register module */ 556124861Sharti snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 557124861Sharti if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 558124861Sharti free(*pp); 559124861Sharti return (SNMP_ERR_GENERR); 560124861Sharti } 561124861Sharti 562124861Sharti INSERT_OBJECT_OID((*pp), &transport_list); 563124861Sharti 564124861Sharti TAILQ_INIT(&(*pp)->table); 565124861Sharti 566124861Sharti return (SNMP_ERR_NOERROR); 567124861Sharti} 568124861Sharti 569124861Sharti/* 570124861Sharti * Unregister transport 571124861Sharti */ 572124861Shartiint 573124861Shartitrans_unregister(struct transport *t) 574124861Sharti{ 575124861Sharti if (!TAILQ_EMPTY(&t->table)) 576124861Sharti return (SNMP_ERR_INCONS_VALUE); 577124861Sharti 578124861Sharti or_unregister(t->or_index); 579124861Sharti TAILQ_REMOVE(&transport_list, t, link); 580124861Sharti 581124861Sharti return (SNMP_ERR_NOERROR); 582124861Sharti} 583124861Sharti 584124861Sharti/* 585122394Sharti * File descriptor support 586122394Sharti */ 587124861Sharti#ifdef USE_LIBBEGEMOT 588122394Shartistatic void 589124861Shartiinput(int fd, int mask __unused, void *uap) 590124861Sharti#else 591124861Shartistatic void 592122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused) 593124861Sharti#endif 594122394Sharti{ 595122394Sharti struct fdesc *f = uap; 596122394Sharti 597122394Sharti (*f->func)(fd, f->udata); 598122394Sharti} 599122394Sharti 600122394Shartivoid 601122394Shartifd_suspend(void *p) 602122394Sharti{ 603122394Sharti struct fdesc *f = p; 604122394Sharti 605124861Sharti#ifdef USE_LIBBEGEMOT 606124861Sharti if (f->id >= 0) { 607124861Sharti poll_unregister(f->id); 608124861Sharti f->id = -1; 609124861Sharti } 610124861Sharti#else 611122394Sharti if (evTestID(f->id)) { 612122394Sharti (void)evDeselectFD(evctx, f->id); 613122394Sharti evInitID(&f->id); 614122394Sharti } 615124861Sharti#endif 616122394Sharti} 617122394Sharti 618122394Shartiint 619122394Shartifd_resume(void *p) 620122394Sharti{ 621122394Sharti struct fdesc *f = p; 622122394Sharti int err; 623122394Sharti 624124861Sharti#ifdef USE_LIBBEGEMOT 625124861Sharti if (f->id >= 0) 626124861Sharti return (0); 627142810Sharti if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 628124861Sharti err = errno; 629124861Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 630124861Sharti errno = err; 631124861Sharti return (-1); 632124861Sharti } 633124861Sharti#else 634122394Sharti if (evTestID(f->id)) 635122394Sharti return (0); 636122394Sharti if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 637122394Sharti err = errno; 638122394Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 639122394Sharti errno = err; 640122394Sharti return (-1); 641122394Sharti } 642124861Sharti#endif 643122394Sharti return (0); 644122394Sharti} 645122394Sharti 646122394Shartivoid * 647122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 648122394Sharti{ 649122394Sharti struct fdesc *f; 650122394Sharti int err; 651122394Sharti 652122394Sharti if ((f = malloc(sizeof(struct fdesc))) == NULL) { 653122394Sharti err = errno; 654122394Sharti syslog(LOG_ERR, "fd_select: %m"); 655122394Sharti errno = err; 656122394Sharti return (NULL); 657122394Sharti } 658122394Sharti f->fd = fd; 659122394Sharti f->func = func; 660122394Sharti f->udata = udata; 661122394Sharti f->owner = mod; 662124861Sharti#ifdef USE_LIBBEGEMOT 663124861Sharti f->id = -1; 664124861Sharti#else 665122394Sharti evInitID(&f->id); 666124861Sharti#endif 667122394Sharti 668122394Sharti if (fd_resume(f)) { 669122394Sharti err = errno; 670122394Sharti free(f); 671122394Sharti errno = err; 672122394Sharti return (NULL); 673122394Sharti } 674122394Sharti 675122394Sharti LIST_INSERT_HEAD(&fdesc_list, f, link); 676122394Sharti 677122394Sharti return (f); 678122394Sharti} 679122394Sharti 680122394Shartivoid 681122394Shartifd_deselect(void *p) 682122394Sharti{ 683122394Sharti struct fdesc *f = p; 684122394Sharti 685122394Sharti LIST_REMOVE(f, link); 686122394Sharti fd_suspend(f); 687122394Sharti free(f); 688122394Sharti} 689122394Sharti 690122394Shartistatic void 691122394Shartifd_flush(struct lmodule *mod) 692122394Sharti{ 693122394Sharti struct fdesc *t, *t1; 694122394Sharti 695122394Sharti t = LIST_FIRST(&fdesc_list); 696122394Sharti while (t != NULL) { 697122394Sharti t1 = LIST_NEXT(t, link); 698122394Sharti if (t->owner == mod) 699122394Sharti fd_deselect(t); 700122394Sharti t = t1; 701122394Sharti } 702122394Sharti} 703122394Sharti 704122394Sharti/* 705124861Sharti * Consume a message from the input buffer 706122394Sharti */ 707122394Shartistatic void 708124861Shartisnmp_input_consume(struct port_input *pi) 709122394Sharti{ 710124861Sharti if (!pi->stream) { 711124861Sharti /* always consume everything */ 712124861Sharti pi->length = 0; 713122394Sharti return; 714122394Sharti } 715124861Sharti if (pi->consumed >= pi->length) { 716124861Sharti /* all bytes consumed */ 717124861Sharti pi->length = 0; 718122394Sharti return; 719122394Sharti } 720124861Sharti memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 721124861Sharti pi->length -= pi->consumed; 722124861Sharti} 723124861Sharti 724124861Shartistruct credmsg { 725124861Sharti struct cmsghdr hdr; 726124861Sharti struct cmsgcred cred; 727124861Sharti}; 728124861Sharti 729124861Shartistatic void 730124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg) 731124861Sharti{ 732124861Sharti struct credmsg *cmsg; 733124861Sharti struct xucred ucred; 734124861Sharti socklen_t ucredlen; 735124861Sharti 736124861Sharti pi->priv = 0; 737124861Sharti 738124861Sharti if (msg->msg_controllen == sizeof(*cmsg)) { 739150920Sharti /* process explicitly sends credentials */ 740124861Sharti 741124861Sharti cmsg = (struct credmsg *)msg->msg_control; 742124861Sharti pi->priv = (cmsg->cred.cmcred_euid == 0); 743122394Sharti return; 744122394Sharti } 745124861Sharti 746124861Sharti /* ok, obtain the accept time credentials */ 747124861Sharti ucredlen = sizeof(ucred); 748124861Sharti 749124861Sharti if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 750124861Sharti ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 751124861Sharti pi->priv = (ucred.cr_uid == 0); 752124861Sharti} 753124861Sharti 754124861Sharti/* 755124861Sharti * Input from a stream socket. 756124861Sharti */ 757124861Shartistatic int 758124861Shartirecv_stream(struct port_input *pi) 759124861Sharti{ 760124861Sharti struct msghdr msg; 761124861Sharti struct iovec iov[1]; 762124861Sharti ssize_t len; 763124861Sharti struct credmsg cmsg; 764124861Sharti 765124861Sharti if (pi->buf == NULL) { 766124861Sharti /* no buffer yet - allocate one */ 767124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 768124861Sharti /* ups - could not get buffer. Return an error 769124861Sharti * the caller must close the transport. */ 770124861Sharti return (-1); 771124861Sharti } 772124861Sharti pi->buflen = buf_size(0); 773124861Sharti pi->consumed = 0; 774124861Sharti pi->length = 0; 775124861Sharti } 776124861Sharti 777124861Sharti /* try to get a message */ 778124861Sharti msg.msg_name = pi->peer; 779124861Sharti msg.msg_namelen = pi->peerlen; 780124861Sharti msg.msg_iov = iov; 781124861Sharti msg.msg_iovlen = 1; 782124861Sharti if (pi->cred) { 783124861Sharti msg.msg_control = &cmsg; 784124861Sharti msg.msg_controllen = sizeof(cmsg); 785124861Sharti 786124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 787124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 788124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 789124861Sharti } else { 790124861Sharti msg.msg_control = NULL; 791124861Sharti msg.msg_controllen = 0; 792124861Sharti } 793124861Sharti msg.msg_flags = 0; 794124861Sharti 795124861Sharti iov[0].iov_base = pi->buf + pi->length; 796124861Sharti iov[0].iov_len = pi->buflen - pi->length; 797124861Sharti 798124861Sharti len = recvmsg(pi->fd, &msg, 0); 799124861Sharti 800124861Sharti if (len == -1 || len == 0) 801124861Sharti /* receive error */ 802124861Sharti return (-1); 803124861Sharti 804124861Sharti pi->length += len; 805124861Sharti 806124861Sharti if (pi->cred) 807124861Sharti check_priv(pi, &msg); 808124861Sharti 809124861Sharti return (0); 810124861Sharti} 811124861Sharti 812124861Sharti/* 813124861Sharti * Input from a datagram socket. 814124861Sharti * Each receive should return one datagram. 815124861Sharti */ 816124861Shartistatic int 817124861Shartirecv_dgram(struct port_input *pi) 818124861Sharti{ 819124861Sharti u_char embuf[1000]; 820124861Sharti struct msghdr msg; 821124861Sharti struct iovec iov[1]; 822124861Sharti ssize_t len; 823124861Sharti struct credmsg cmsg; 824124861Sharti 825124861Sharti if (pi->buf == NULL) { 826124861Sharti /* no buffer yet - allocate one */ 827124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 828124861Sharti /* ups - could not get buffer. Read away input 829124861Sharti * and drop it */ 830124861Sharti (void)recvfrom(pi->fd, embuf, sizeof(embuf), 831124861Sharti 0, NULL, NULL); 832124861Sharti /* return error */ 833124861Sharti return (-1); 834124861Sharti } 835124861Sharti pi->buflen = buf_size(0); 836124861Sharti } 837124861Sharti 838124861Sharti /* try to get a message */ 839124861Sharti msg.msg_name = pi->peer; 840124861Sharti msg.msg_namelen = pi->peerlen; 841124861Sharti msg.msg_iov = iov; 842124861Sharti msg.msg_iovlen = 1; 843124861Sharti if (pi->cred) { 844124861Sharti msg.msg_control = &cmsg; 845124861Sharti msg.msg_controllen = sizeof(cmsg); 846124861Sharti 847124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 848124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 849124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 850124861Sharti } else { 851124861Sharti msg.msg_control = NULL; 852128237Sharti msg.msg_controllen = 0; 853124861Sharti } 854124861Sharti msg.msg_flags = 0; 855124861Sharti 856124861Sharti iov[0].iov_base = pi->buf; 857124861Sharti iov[0].iov_len = pi->buflen; 858124861Sharti 859124861Sharti len = recvmsg(pi->fd, &msg, 0); 860124861Sharti 861124861Sharti if (len == -1 || len == 0) 862124861Sharti /* receive error */ 863124861Sharti return (-1); 864124861Sharti 865124861Sharti if (msg.msg_flags & MSG_TRUNC) { 866124861Sharti /* truncated - drop */ 867122394Sharti snmpd_stats.silentDrops++; 868122394Sharti snmpd_stats.inTooLong++; 869124861Sharti return (-1); 870122394Sharti } 871122394Sharti 872124861Sharti pi->length = (size_t)len; 873124861Sharti 874124861Sharti if (pi->cred) 875124861Sharti check_priv(pi, &msg); 876124861Sharti 877124861Sharti return (0); 878124861Sharti} 879124861Sharti 880124861Sharti/* 881124861Sharti * Input from a socket 882124861Sharti */ 883124861Shartiint 884124861Shartisnmpd_input(struct port_input *pi, struct tport *tport) 885124861Sharti{ 886124861Sharti u_char *sndbuf; 887124861Sharti size_t sndlen; 888124861Sharti struct snmp_pdu pdu; 889124861Sharti enum snmpd_input_err ierr, ferr; 890124861Sharti enum snmpd_proxy_err perr; 891124861Sharti int32_t vi; 892124861Sharti int ret; 893124861Sharti ssize_t slen; 894145557Sharti#ifdef USE_TCPWRAPPERS 895145557Sharti char client[16]; 896145557Sharti#endif 897124861Sharti 898124861Sharti /* get input depending on the transport */ 899124861Sharti if (pi->stream) { 900124861Sharti ret = recv_stream(pi); 901124861Sharti } else { 902124861Sharti ret = recv_dgram(pi); 903124861Sharti } 904124861Sharti 905124861Sharti if (ret == -1) 906124861Sharti return (-1); 907124861Sharti 908145557Sharti#ifdef USE_TCPWRAPPERS 909122394Sharti /* 910145557Sharti * In case of AF_INET{6} peer, do hosts_access(5) check. 911145557Sharti */ 912145557Sharti if (inet_ntop(pi->peer->sa_family, 913146525Sharti &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 914146525Sharti client, sizeof(client)) != NULL) { 915145557Sharti request_set(&req, RQ_CLIENT_ADDR, client, 0); 916145557Sharti if (hosts_access(&req) == 0) { 917145557Sharti syslog(LOG_ERR, "refused connection from %.500s", 918145557Sharti eval_client(&req)); 919145557Sharti return (-1); 920145557Sharti } 921145557Sharti } else 922145557Sharti syslog(LOG_ERR, "inet_ntop(): %m"); 923145557Sharti#endif 924145557Sharti 925145557Sharti /* 926122394Sharti * Handle input 927122394Sharti */ 928124861Sharti ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 929124861Sharti &pi->consumed); 930124861Sharti if (ierr == SNMPD_INPUT_TRUNC) { 931124861Sharti /* need more bytes. This is ok only for streaming transports. 932124861Sharti * but only if we have not reached bufsiz yet. */ 933124861Sharti if (pi->stream) { 934124861Sharti if (pi->length == buf_size(0)) { 935124861Sharti snmpd_stats.silentDrops++; 936124861Sharti return (-1); 937124861Sharti } 938124861Sharti return (0); 939124861Sharti } 940124861Sharti snmpd_stats.silentDrops++; 941124861Sharti return (-1); 942124861Sharti } 943122394Sharti 944122394Sharti /* can't check for bad SET pdus here, because a proxy may have to 945122394Sharti * check the access first. We don't want to return an error response 946122394Sharti * to a proxy PDU with a wrong community */ 947122394Sharti if (ierr == SNMPD_INPUT_FAILED) { 948124861Sharti /* for streaming transports this is fatal */ 949124861Sharti if (pi->stream) 950124861Sharti return (-1); 951124861Sharti snmp_input_consume(pi); 952124861Sharti return (0); 953122394Sharti } 954133211Sharti if (ierr == SNMPD_INPUT_BAD_COMM) { 955133211Sharti snmp_input_consume(pi); 956133211Sharti return (0); 957133211Sharti } 958122394Sharti 959122394Sharti /* 960122394Sharti * If that is a module community and the module has a proxy function, 961122394Sharti * the hand it over to the module. 962122394Sharti */ 963122394Sharti if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 964124861Sharti perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 965133211Sharti &tport->index, pi->peer, pi->peerlen, ierr, vi, 966133211Sharti !pi->cred || pi->priv); 967122394Sharti 968122394Sharti switch (perr) { 969122394Sharti 970122394Sharti case SNMPD_PROXY_OK: 971124861Sharti snmp_input_consume(pi); 972124861Sharti return (0); 973122394Sharti 974122394Sharti case SNMPD_PROXY_REJ: 975122394Sharti break; 976122394Sharti 977122394Sharti case SNMPD_PROXY_DROP: 978124861Sharti snmp_input_consume(pi); 979122394Sharti snmp_pdu_free(&pdu); 980122394Sharti snmpd_stats.proxyDrops++; 981124861Sharti return (0); 982122394Sharti 983122394Sharti case SNMPD_PROXY_BADCOMM: 984124861Sharti snmp_input_consume(pi); 985122394Sharti snmp_pdu_free(&pdu); 986122394Sharti snmpd_stats.inBadCommunityNames++; 987122394Sharti if (snmpd.auth_traps) 988122394Sharti snmp_send_trap(&oid_authenticationFailure, 989133211Sharti (struct snmp_value *)NULL); 990124861Sharti return (0); 991122394Sharti 992122394Sharti case SNMPD_PROXY_BADCOMMUSE: 993124861Sharti snmp_input_consume(pi); 994122394Sharti snmp_pdu_free(&pdu); 995122394Sharti snmpd_stats.inBadCommunityUses++; 996122394Sharti if (snmpd.auth_traps) 997122394Sharti snmp_send_trap(&oid_authenticationFailure, 998133211Sharti (struct snmp_value *)NULL); 999124861Sharti return (0); 1000122394Sharti } 1001122394Sharti } 1002122394Sharti 1003122394Sharti /* 1004122394Sharti * Check type 1005122394Sharti */ 1006122394Sharti if (pdu.type == SNMP_PDU_RESPONSE || 1007122394Sharti pdu.type == SNMP_PDU_TRAP || 1008122394Sharti pdu.type == SNMP_PDU_TRAP2) { 1009122394Sharti snmpd_stats.silentDrops++; 1010122394Sharti snmpd_stats.inBadPduTypes++; 1011122394Sharti snmp_pdu_free(&pdu); 1012124861Sharti snmp_input_consume(pi); 1013124861Sharti return (0); 1014122394Sharti } 1015122394Sharti 1016122394Sharti /* 1017122394Sharti * Check community 1018122394Sharti */ 1019124861Sharti if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1020124861Sharti (community != COMM_WRITE && 1021124861Sharti (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 1022122394Sharti snmpd_stats.inBadCommunityUses++; 1023122394Sharti snmp_pdu_free(&pdu); 1024124861Sharti snmp_input_consume(pi); 1025122394Sharti if (snmpd.auth_traps) 1026133211Sharti snmp_send_trap(&oid_authenticationFailure, 1027133211Sharti (struct snmp_value *)NULL); 1028124861Sharti return (0); 1029122394Sharti } 1030122394Sharti 1031122394Sharti /* 1032122394Sharti * Execute it. 1033122394Sharti */ 1034122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 1035122394Sharti snmpd_stats.silentDrops++; 1036122394Sharti snmp_pdu_free(&pdu); 1037124861Sharti snmp_input_consume(pi); 1038124861Sharti return (0); 1039122394Sharti } 1040124861Sharti ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1041124861Sharti sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1042122394Sharti 1043122394Sharti if (ferr == SNMPD_INPUT_OK) { 1044124861Sharti slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 1045124861Sharti if (slen == -1) 1046122394Sharti syslog(LOG_ERR, "sendto: %m"); 1047124861Sharti else if ((size_t)slen != sndlen) 1048122394Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1049124861Sharti sndlen, (size_t)slen); 1050122394Sharti } 1051122394Sharti snmp_pdu_free(&pdu); 1052122394Sharti free(sndbuf); 1053124861Sharti snmp_input_consume(pi); 1054122394Sharti 1055124861Sharti return (0); 1056122394Sharti} 1057122394Sharti 1058122394Sharti/* 1059124861Sharti * Send a PDU to a given port 1060122394Sharti */ 1061124861Shartivoid 1062124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1063124861Sharti const struct sockaddr *addr, socklen_t addrlen) 1064122394Sharti{ 1065124861Sharti struct transport *trans = targ; 1066124861Sharti struct tport *tp; 1067124861Sharti u_char *sndbuf; 1068124861Sharti size_t sndlen; 1069124861Sharti ssize_t len; 1070122394Sharti 1071124861Sharti TAILQ_FOREACH(tp, &trans->table, link) 1072124861Sharti if (asn_compare_oid(port, &tp->index) == 0) 1073122394Sharti break; 1074124861Sharti if (tp == 0) 1075124861Sharti return; 1076122394Sharti 1077124861Sharti if ((sndbuf = buf_alloc(1)) == NULL) 1078124861Sharti return; 1079122394Sharti 1080124861Sharti snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1081122394Sharti 1082124861Sharti len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1083122394Sharti 1084124861Sharti if (len == -1) 1085124861Sharti syslog(LOG_ERR, "sendto: %m"); 1086124861Sharti else if ((size_t)len != sndlen) 1087124861Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1088124861Sharti sndlen, (size_t)len); 1089122394Sharti 1090124861Sharti free(sndbuf); 1091122394Sharti} 1092122394Sharti 1093122394Sharti 1094122394Sharti/* 1095124861Sharti * Close an input source 1096122394Sharti */ 1097122394Shartivoid 1098124861Shartisnmpd_input_close(struct port_input *pi) 1099122394Sharti{ 1100124861Sharti if (pi->id != NULL) 1101124861Sharti fd_deselect(pi->id); 1102124861Sharti if (pi->fd >= 0) 1103124861Sharti (void)close(pi->fd); 1104124861Sharti if (pi->buf != NULL) 1105124861Sharti free(pi->buf); 1106122394Sharti} 1107122394Sharti 1108122394Sharti/* 1109122394Sharti * Dump internal state. 1110122394Sharti */ 1111124861Sharti#ifdef USE_LIBBEGEMOT 1112122394Shartistatic void 1113124861Shartiinfo_func(void) 1114124861Sharti#else 1115124861Shartistatic void 1116122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1117124861Sharti#endif 1118122394Sharti{ 1119122394Sharti struct lmodule *m; 1120122394Sharti u_int i; 1121122394Sharti char buf[10000]; 1122122394Sharti 1123122394Sharti syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1124122394Sharti for (i = 0; i < tree_size; i++) { 1125122394Sharti switch (tree[i].type) { 1126122394Sharti 1127122394Sharti case SNMP_NODE_LEAF: 1128122394Sharti sprintf(buf, "LEAF: %s %s", tree[i].name, 1129122394Sharti asn_oid2str(&tree[i].oid)); 1130122394Sharti break; 1131122394Sharti 1132122394Sharti case SNMP_NODE_COLUMN: 1133122394Sharti sprintf(buf, "COL: %s %s", tree[i].name, 1134122394Sharti asn_oid2str(&tree[i].oid)); 1135122394Sharti break; 1136122394Sharti } 1137122394Sharti syslog(LOG_DEBUG, "%s", buf); 1138122394Sharti } 1139122394Sharti 1140122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1141122394Sharti if (m->config->dump) 1142122394Sharti (*m->config->dump)(); 1143122394Sharti} 1144122394Sharti 1145122394Sharti/* 1146122394Sharti * Re-read configuration 1147122394Sharti */ 1148124861Sharti#ifdef USE_LIBBEGEMOT 1149122394Shartistatic void 1150124861Sharticonfig_func(void) 1151124861Sharti#else 1152124861Shartistatic void 1153122394Sharticonfig_func(evContext ctx __unused, void *uap __unused, 1154122394Sharti const void *tag __unused) 1155124861Sharti#endif 1156122394Sharti{ 1157122394Sharti struct lmodule *m; 1158122394Sharti 1159122394Sharti if (read_config(config_file, NULL)) { 1160122394Sharti syslog(LOG_ERR, "error reading config file '%s'", config_file); 1161122394Sharti return; 1162122394Sharti } 1163122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1164122394Sharti if (m->config->config) 1165122394Sharti (*m->config->config)(); 1166122394Sharti} 1167122394Sharti 1168122394Sharti/* 1169122394Sharti * On USR1 dump actual configuration. 1170122394Sharti */ 1171122394Shartistatic void 1172122394Shartionusr1(int s __unused) 1173122394Sharti{ 1174124861Sharti 1175122394Sharti work |= WORK_DOINFO; 1176122394Sharti} 1177122394Shartistatic void 1178122394Shartionhup(int s __unused) 1179122394Sharti{ 1180124861Sharti 1181122394Sharti work |= WORK_RECONFIG; 1182122394Sharti} 1183122394Sharti 1184122394Shartistatic void 1185122394Shartionterm(int s __unused) 1186122394Sharti{ 1187122394Sharti 1188124861Sharti /* allow clean-up */ 1189122394Sharti exit(0); 1190122394Sharti} 1191122394Sharti 1192122394Shartistatic void 1193122394Shartiinit_sigs(void) 1194122394Sharti{ 1195122394Sharti struct sigaction sa; 1196122394Sharti 1197122394Sharti sa.sa_handler = onusr1; 1198122394Sharti sa.sa_flags = SA_RESTART; 1199122394Sharti sigemptyset(&sa.sa_mask); 1200122394Sharti if (sigaction(SIGUSR1, &sa, NULL)) { 1201122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1202122394Sharti exit(1); 1203122394Sharti } 1204122394Sharti 1205122394Sharti sa.sa_handler = onhup; 1206122394Sharti if (sigaction(SIGHUP, &sa, NULL)) { 1207122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1208122394Sharti exit(1); 1209122394Sharti } 1210122394Sharti 1211122394Sharti sa.sa_handler = onterm; 1212122394Sharti sa.sa_flags = 0; 1213122394Sharti sigemptyset(&sa.sa_mask); 1214122394Sharti if (sigaction(SIGTERM, &sa, NULL)) { 1215122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1216122394Sharti exit(1); 1217122394Sharti } 1218122394Sharti if (sigaction(SIGINT, &sa, NULL)) { 1219122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1220122394Sharti exit(1); 1221122394Sharti } 1222122394Sharti} 1223122394Sharti 1224122394Shartistatic void 1225122394Shartiblock_sigs(void) 1226122394Sharti{ 1227122394Sharti sigset_t set; 1228122394Sharti 1229122394Sharti sigfillset(&set); 1230122394Sharti if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1231122394Sharti syslog(LOG_ERR, "SIG_BLOCK: %m"); 1232122394Sharti exit(1); 1233122394Sharti } 1234122394Sharti} 1235122394Shartistatic void 1236122394Shartiunblock_sigs(void) 1237122394Sharti{ 1238122394Sharti if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1239122394Sharti syslog(LOG_ERR, "SIG_SETMASK: %m"); 1240122394Sharti exit(1); 1241122394Sharti } 1242122394Sharti} 1243122394Sharti 1244122394Sharti/* 1245122394Sharti * Shut down 1246122394Sharti */ 1247122394Shartistatic void 1248122394Shartiterm(void) 1249122394Sharti{ 1250122394Sharti (void)unlink(pid_file); 1251122394Sharti} 1252122394Sharti 1253124861Shartistatic void 1254124861Shartitrans_stop(void) 1255124861Sharti{ 1256124861Sharti struct transport *t; 1257124861Sharti 1258124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1259124861Sharti (void)t->vtab->stop(1); 1260124861Sharti} 1261124861Sharti 1262122394Sharti/* 1263122394Sharti * Define a macro from the command line 1264122394Sharti */ 1265122394Shartistatic void 1266122394Shartido_macro(char *arg) 1267122394Sharti{ 1268122394Sharti char *eq; 1269122394Sharti int err; 1270122394Sharti 1271122394Sharti if ((eq = strchr(arg, '=')) == NULL) 1272122394Sharti err = define_macro(arg, ""); 1273122394Sharti else { 1274122394Sharti *eq++ = '\0'; 1275122394Sharti err = define_macro(arg, eq); 1276122394Sharti } 1277122394Sharti if (err == -1) { 1278122394Sharti syslog(LOG_ERR, "cannot save macro: %m"); 1279122394Sharti exit(1); 1280122394Sharti } 1281122394Sharti} 1282122394Sharti 1283122394Sharti/* 1284122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken 1285122394Sharti * and will not compile with WARNS=5. 1286122394Sharti */ 1287122394Shartistatic int 1288122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1289122394Sharti{ 1290122394Sharti static const char *const delim = ",\t "; 1291122394Sharti u_int i; 1292122394Sharti char *ptr; 1293122394Sharti 1294122394Sharti *optp = NULL; 1295122394Sharti 1296122394Sharti /* skip leading junk */ 1297122394Sharti for (ptr = *arg; *ptr != '\0'; ptr++) 1298122394Sharti if (strchr(delim, *ptr) == NULL) 1299122394Sharti break; 1300122394Sharti if (*ptr == '\0') { 1301122394Sharti *arg = ptr; 1302122394Sharti return (-1); 1303122394Sharti } 1304122394Sharti *optp = ptr; 1305122394Sharti 1306122394Sharti /* find the end of the option */ 1307122394Sharti while (*++ptr != '\0') 1308122394Sharti if (strchr(delim, *ptr) != NULL || *ptr == '=') 1309122394Sharti break; 1310122394Sharti 1311122394Sharti if (*ptr != '\0') { 1312122394Sharti if (*ptr == '=') { 1313122394Sharti *ptr++ = '\0'; 1314122394Sharti *valp = ptr; 1315122394Sharti while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1316122394Sharti ptr++; 1317122394Sharti if (*ptr != '\0') 1318122394Sharti *ptr++ = '\0'; 1319122394Sharti } else 1320122394Sharti *ptr++ = '\0'; 1321122394Sharti } 1322122394Sharti 1323122394Sharti *arg = ptr; 1324122394Sharti 1325122394Sharti for (i = 0; *options != NULL; options++, i++) 1326124861Sharti if (strcmp(*optp, *options) == 0) 1327122394Sharti return (i); 1328122394Sharti return (-1); 1329122394Sharti} 1330122394Sharti 1331122394Shartiint 1332122394Shartimain(int argc, char *argv[]) 1333122394Sharti{ 1334122394Sharti int opt; 1335122394Sharti FILE *fp; 1336122394Sharti int background = 1; 1337124861Sharti struct tport *p; 1338122394Sharti const char *prefix = "snmpd"; 1339122394Sharti struct lmodule *m; 1340122394Sharti char *value, *option; 1341124861Sharti struct transport *t; 1342122394Sharti 1343122394Sharti#define DBG_DUMP 0 1344122394Sharti#define DBG_EVENTS 1 1345122394Sharti#define DBG_TRACE 2 1346122394Sharti static const char *const debug_opts[] = { 1347122394Sharti "dump", 1348122394Sharti "events", 1349122394Sharti "trace", 1350122394Sharti NULL 1351122394Sharti }; 1352122394Sharti 1353122394Sharti snmp_printf = snmp_printf_func; 1354122394Sharti snmp_error = snmp_error_func; 1355122394Sharti snmp_debug = snmp_debug_func; 1356122394Sharti asn_error = asn_error_func; 1357122394Sharti 1358122394Sharti while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1359122394Sharti switch (opt) { 1360122394Sharti 1361122394Sharti case 'c': 1362122394Sharti strlcpy(config_file, optarg, sizeof(config_file)); 1363122394Sharti break; 1364122394Sharti 1365122394Sharti case 'd': 1366122394Sharti background = 0; 1367122394Sharti break; 1368122394Sharti 1369122394Sharti case 'D': 1370122394Sharti while (*optarg) { 1371122394Sharti switch (getsubopt1(&optarg, debug_opts, 1372122394Sharti &value, &option)) { 1373122394Sharti 1374122394Sharti case DBG_DUMP: 1375122394Sharti debug.dump_pdus = 1; 1376122394Sharti break; 1377122394Sharti 1378122394Sharti case DBG_EVENTS: 1379122394Sharti debug.evdebug++; 1380122394Sharti break; 1381122394Sharti 1382122394Sharti case DBG_TRACE: 1383122394Sharti if (value == NULL) 1384122394Sharti syslog(LOG_ERR, 1385122394Sharti "no value for 'trace'"); 1386155094Sharti else 1387156066Sharti snmp_trace = strtoul(value, 1388156066Sharti NULL, 0); 1389122394Sharti break; 1390122394Sharti 1391122394Sharti case -1: 1392122394Sharti if (suboptarg) 1393122394Sharti syslog(LOG_ERR, 1394122394Sharti "unknown debug flag '%s'", 1395122394Sharti option); 1396122394Sharti else 1397122394Sharti syslog(LOG_ERR, 1398122394Sharti "missing debug flag"); 1399122394Sharti break; 1400122394Sharti } 1401122394Sharti } 1402122394Sharti break; 1403122394Sharti 1404122394Sharti case 'h': 1405122394Sharti fprintf(stderr, "%s", usgtxt); 1406122394Sharti exit(0); 1407122394Sharti 1408122394Sharti case 'I': 1409122394Sharti syspath = optarg; 1410122394Sharti break; 1411122394Sharti 1412122394Sharti case 'l': 1413122394Sharti prefix = optarg; 1414122394Sharti break; 1415122394Sharti 1416122394Sharti case 'm': 1417122394Sharti do_macro(optarg); 1418122394Sharti break; 1419122394Sharti 1420122394Sharti case 'p': 1421122394Sharti strlcpy(pid_file, optarg, sizeof(pid_file)); 1422122394Sharti break; 1423122394Sharti } 1424122394Sharti 1425122394Sharti openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1426122394Sharti setlogmask(LOG_UPTO(debug.logpri - 1)); 1427122394Sharti 1428122394Sharti if (background && daemon(0, 0) < 0) { 1429122394Sharti syslog(LOG_ERR, "daemon: %m"); 1430122394Sharti exit(1); 1431122394Sharti } 1432122394Sharti 1433122394Sharti argc -= optind; 1434122394Sharti argv += optind; 1435122394Sharti 1436122394Sharti progargs = argv; 1437122394Sharti nprogargs = argc; 1438122394Sharti 1439122394Sharti srandomdev(); 1440122394Sharti 1441122394Sharti snmp_serial_no = random(); 1442122394Sharti 1443145557Sharti#ifdef USE_TCPWRAPPERS 1444122394Sharti /* 1445145557Sharti * Initialize hosts_access(3) handler. 1446145557Sharti */ 1447145557Sharti request_init(&req, RQ_DAEMON, "snmpd", 0); 1448145557Sharti sock_methods(&req); 1449145557Sharti#endif 1450145557Sharti 1451145557Sharti /* 1452122394Sharti * Initialize the tree. 1453122394Sharti */ 1454122394Sharti if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1455122394Sharti syslog(LOG_ERR, "%m"); 1456122394Sharti exit(1); 1457122394Sharti } 1458122394Sharti memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1459122394Sharti tree_size = CTREE_SIZE; 1460122394Sharti 1461122394Sharti /* 1462122394Sharti * Get standard communities 1463122394Sharti */ 1464154180Sharti (void)comm_define(1, "SNMP read", NULL, NULL); 1465154180Sharti (void)comm_define(2, "SNMP write", NULL, NULL); 1466122394Sharti community = COMM_INITIALIZE; 1467122394Sharti 1468122394Sharti trap_reqid = reqid_allocate(512, NULL); 1469122394Sharti 1470122394Sharti if (config_file[0] == '\0') 1471122394Sharti snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1472122394Sharti 1473122394Sharti init_actvals(); 1474124861Sharti 1475124861Sharti this_tick = get_ticks(); 1476146525Sharti start_tick = this_tick; 1477124861Sharti 1478124861Sharti /* start transports */ 1479124861Sharti if (atexit(trans_stop) == -1) { 1480124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1481124861Sharti exit(1); 1482124861Sharti } 1483124861Sharti if (udp_trans.start() != SNMP_ERR_NOERROR) 1484124861Sharti syslog(LOG_WARNING, "cannot start UDP transport"); 1485124861Sharti if (lsock_trans.start() != SNMP_ERR_NOERROR) 1486124861Sharti syslog(LOG_WARNING, "cannot start LSOCK transport"); 1487124861Sharti 1488124861Sharti#ifdef USE_LIBBEGEMOT 1489124861Sharti if (debug.evdebug > 0) 1490124861Sharti rpoll_trace = 1; 1491124861Sharti#else 1492122394Sharti if (evCreate(&evctx)) { 1493122394Sharti syslog(LOG_ERR, "evCreate: %m"); 1494122394Sharti exit(1); 1495122394Sharti } 1496122394Sharti if (debug.evdebug > 0) 1497122394Sharti evSetDebug(evctx, 10, stderr); 1498124861Sharti#endif 1499122394Sharti 1500133211Sharti if (read_config(config_file, NULL)) { 1501133211Sharti syslog(LOG_ERR, "error in config file"); 1502133211Sharti exit(1); 1503133211Sharti } 1504133211Sharti 1505124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1506124861Sharti TAILQ_FOREACH(p, &t->table, link) 1507124861Sharti t->vtab->init_port(p); 1508122394Sharti 1509122394Sharti init_sigs(); 1510122394Sharti 1511122394Sharti if (pid_file[0] == '\0') 1512122394Sharti snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1513122394Sharti 1514122394Sharti if ((fp = fopen(pid_file, "w")) != NULL) { 1515122394Sharti fprintf(fp, "%u", getpid()); 1516122394Sharti fclose(fp); 1517124861Sharti if (atexit(term) == -1) { 1518124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1519124861Sharti (void)remove(pid_file); 1520124861Sharti exit(0); 1521124861Sharti } 1522122394Sharti } 1523122394Sharti 1524122394Sharti if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1525122394Sharti NULL) == 0) { 1526122394Sharti syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1527122394Sharti exit(1); 1528122394Sharti } 1529122394Sharti if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1530122394Sharti NULL) == 0) { 1531122394Sharti syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1532122394Sharti exit(1); 1533122394Sharti } 1534122394Sharti 1535133211Sharti snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1536122394Sharti 1537122394Sharti while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1538122394Sharti m->flags &= ~LM_ONSTARTLIST; 1539122394Sharti TAILQ_REMOVE(&modules_start, m, start); 1540122394Sharti lm_start(m); 1541122394Sharti } 1542122394Sharti 1543122394Sharti for (;;) { 1544124861Sharti#ifndef USE_LIBBEGEMOT 1545122394Sharti evEvent event; 1546124861Sharti#endif 1547122394Sharti struct lmodule *mod; 1548122394Sharti 1549122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 1550122394Sharti if (mod->config->idle != NULL) 1551122394Sharti (*mod->config->idle)(); 1552122394Sharti 1553124861Sharti#ifndef USE_LIBBEGEMOT 1554122394Sharti if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1555122394Sharti if (evDispatch(evctx, event)) 1556122394Sharti syslog(LOG_ERR, "evDispatch: %m"); 1557122394Sharti } else if (errno != EINTR) { 1558122394Sharti syslog(LOG_ERR, "evGetNext: %m"); 1559122394Sharti exit(1); 1560122394Sharti } 1561124861Sharti#else 1562124861Sharti poll_dispatch(1); 1563124861Sharti#endif 1564122394Sharti 1565122394Sharti if (work != 0) { 1566122394Sharti block_sigs(); 1567122394Sharti if (work & WORK_DOINFO) { 1568124861Sharti#ifdef USE_LIBBEGEMOT 1569124861Sharti info_func(); 1570124861Sharti#else 1571122394Sharti if (evWaitFor(evctx, &work, info_func, 1572122394Sharti NULL, NULL) == -1) { 1573122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1574122394Sharti exit(1); 1575122394Sharti } 1576124861Sharti#endif 1577122394Sharti } 1578122394Sharti if (work & WORK_RECONFIG) { 1579124861Sharti#ifdef USE_LIBBEGEMOT 1580124861Sharti config_func(); 1581124861Sharti#else 1582122394Sharti if (evWaitFor(evctx, &work, config_func, 1583122394Sharti NULL, NULL) == -1) { 1584122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1585122394Sharti exit(1); 1586122394Sharti } 1587124861Sharti#endif 1588122394Sharti } 1589122394Sharti work = 0; 1590122394Sharti unblock_sigs(); 1591124861Sharti#ifndef USE_LIBBEGEMOT 1592122394Sharti if (evDo(evctx, &work) == -1) { 1593122394Sharti syslog(LOG_ERR, "evDo: %m"); 1594122394Sharti exit(1); 1595122394Sharti } 1596124861Sharti#endif 1597122394Sharti } 1598122394Sharti } 1599122394Sharti 1600122394Sharti return (0); 1601122394Sharti} 1602122394Sharti 1603146525Shartiuint64_t 1604122394Shartiget_ticks() 1605122394Sharti{ 1606122394Sharti struct timeval tv; 1607146525Sharti uint64_t ret; 1608122394Sharti 1609122394Sharti if (gettimeofday(&tv, NULL)) 1610122394Sharti abort(); 1611146525Sharti ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1612122394Sharti return (ret); 1613122394Sharti} 1614146525Sharti 1615122394Sharti/* 1616122394Sharti * Timer support 1617122394Sharti */ 1618150920Sharti 1619150920Sharti/* 1620150920Sharti * Trampoline for the non-repeatable timers. 1621150920Sharti */ 1622124861Sharti#ifdef USE_LIBBEGEMOT 1623122394Shartistatic void 1624124861Shartitfunc(int tid __unused, void *uap) 1625124861Sharti#else 1626124861Shartistatic void 1627122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1628122394Sharti struct timespec inter __unused) 1629124861Sharti#endif 1630122394Sharti{ 1631122394Sharti struct timer *tp = uap; 1632122394Sharti 1633122394Sharti LIST_REMOVE(tp, link); 1634122394Sharti tp->func(tp->udata); 1635122394Sharti free(tp); 1636122394Sharti} 1637122394Sharti 1638122394Sharti/* 1639150920Sharti * Trampoline for the repeatable timers. 1640122394Sharti */ 1641150920Sharti#ifdef USE_LIBBEGEMOT 1642150920Shartistatic void 1643150920Shartitrfunc(int tid __unused, void *uap) 1644150920Sharti#else 1645150920Shartistatic void 1646150920Shartitrfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1647150920Sharti struct timespec inter __unused) 1648150920Sharti#endif 1649150920Sharti{ 1650150920Sharti struct timer *tp = uap; 1651150920Sharti 1652150920Sharti tp->func(tp->udata); 1653150920Sharti} 1654150920Sharti 1655150920Sharti/* 1656150920Sharti * Start a one-shot timer 1657150920Sharti */ 1658122394Shartivoid * 1659122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1660122394Sharti{ 1661122394Sharti struct timer *tp; 1662145673Sharti#ifndef USE_LIBBEGEMOT 1663122394Sharti struct timespec due; 1664124861Sharti#endif 1665122394Sharti 1666122394Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 1667122394Sharti syslog(LOG_CRIT, "out of memory for timer"); 1668122394Sharti exit(1); 1669122394Sharti } 1670145673Sharti 1671145673Sharti#ifndef USE_LIBBEGEMOT 1672122394Sharti due = evAddTime(evNowTime(), 1673124861Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 1674124861Sharti#endif 1675122394Sharti 1676122394Sharti tp->udata = udata; 1677122394Sharti tp->owner = mod; 1678122394Sharti tp->func = func; 1679122394Sharti 1680122394Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 1681122394Sharti 1682124861Sharti#ifdef USE_LIBBEGEMOT 1683145673Sharti if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 1684124861Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1685124861Sharti exit(1); 1686124861Sharti } 1687124861Sharti#else 1688122394Sharti if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1689122394Sharti == -1) { 1690122394Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1691122394Sharti exit(1); 1692122394Sharti } 1693124861Sharti#endif 1694122394Sharti return (tp); 1695122394Sharti} 1696122394Sharti 1697150920Sharti/* 1698150920Sharti * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 1699150920Sharti * is currently ignored and the initial number of ticks is set to the 1700150920Sharti * repeat number of ticks. 1701150920Sharti */ 1702150920Shartivoid * 1703150920Shartitimer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 1704150920Sharti void (*func)(void *), void *udata, struct lmodule *mod) 1705150920Sharti{ 1706150920Sharti struct timer *tp; 1707150920Sharti#ifndef USE_LIBBEGEMOT 1708150920Sharti struct timespec due; 1709150920Sharti struct timespec inter; 1710150920Sharti#endif 1711150920Sharti 1712150920Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 1713150920Sharti syslog(LOG_CRIT, "out of memory for timer"); 1714150920Sharti exit(1); 1715150920Sharti } 1716150920Sharti 1717150920Sharti#ifndef USE_LIBBEGEMOT 1718150920Sharti due = evAddTime(evNowTime(), 1719150920Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 1720150920Sharti inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 1721150920Sharti#endif 1722150920Sharti 1723150920Sharti tp->udata = udata; 1724150920Sharti tp->owner = mod; 1725150920Sharti tp->func = func; 1726150920Sharti 1727150920Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 1728150920Sharti 1729150920Sharti#ifdef USE_LIBBEGEMOT 1730150920Sharti if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 1731150920Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1732150920Sharti exit(1); 1733150920Sharti } 1734150920Sharti#else 1735150920Sharti if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 1736150920Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1737150920Sharti exit(1); 1738150920Sharti } 1739150920Sharti#endif 1740150920Sharti return (tp); 1741150920Sharti} 1742150920Sharti 1743150920Sharti/* 1744150920Sharti * Stop a timer. 1745150920Sharti */ 1746122394Shartivoid 1747122394Shartitimer_stop(void *p) 1748122394Sharti{ 1749122394Sharti struct timer *tp = p; 1750122394Sharti 1751122394Sharti LIST_REMOVE(tp, link); 1752124861Sharti#ifdef USE_LIBBEGEMOT 1753124861Sharti poll_stop_timer(tp->id); 1754124861Sharti#else 1755122394Sharti if (evClearTimer(evctx, tp->id) == -1) { 1756122394Sharti syslog(LOG_ERR, "cannot stop timer: %m"); 1757122394Sharti exit(1); 1758122394Sharti } 1759124861Sharti#endif 1760122394Sharti free(p); 1761122394Sharti} 1762122394Sharti 1763122394Shartistatic void 1764122394Shartitimer_flush(struct lmodule *mod) 1765122394Sharti{ 1766122394Sharti struct timer *t, *t1; 1767122394Sharti 1768122394Sharti t = LIST_FIRST(&timer_list); 1769122394Sharti while (t != NULL) { 1770122394Sharti t1 = LIST_NEXT(t, link); 1771122394Sharti if (t->owner == mod) 1772122394Sharti timer_stop(t); 1773122394Sharti t = t1; 1774122394Sharti } 1775122394Sharti} 1776122394Sharti 1777122394Shartistatic void 1778122394Shartisnmp_printf_func(const char *fmt, ...) 1779122394Sharti{ 1780122394Sharti va_list ap; 1781122394Sharti static char *pend = NULL; 1782122394Sharti char *ret, *new; 1783122394Sharti 1784122394Sharti va_start(ap, fmt); 1785122394Sharti vasprintf(&ret, fmt, ap); 1786122394Sharti va_end(ap); 1787122394Sharti 1788122394Sharti if (ret == NULL) 1789122394Sharti return; 1790122394Sharti if (pend != NULL) { 1791122394Sharti if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1792122394Sharti == NULL) { 1793122394Sharti free(ret); 1794122394Sharti return; 1795122394Sharti } 1796122394Sharti pend = new; 1797122394Sharti strcat(pend, ret); 1798122394Sharti free(ret); 1799122394Sharti } else 1800122394Sharti pend = ret; 1801122394Sharti 1802122394Sharti while ((ret = strchr(pend, '\n')) != NULL) { 1803122394Sharti *ret = '\0'; 1804122394Sharti syslog(LOG_DEBUG, "%s", pend); 1805122394Sharti if (strlen(ret + 1) == 0) { 1806122394Sharti free(pend); 1807122394Sharti pend = NULL; 1808122394Sharti break; 1809122394Sharti } 1810122394Sharti strcpy(pend, ret + 1); 1811122394Sharti } 1812122394Sharti} 1813122394Sharti 1814122394Shartistatic void 1815122394Shartisnmp_error_func(const char *err, ...) 1816122394Sharti{ 1817122394Sharti char errbuf[1000]; 1818122394Sharti va_list ap; 1819122394Sharti 1820124861Sharti if (!(snmp_trace & LOG_SNMP_ERRORS)) 1821124861Sharti return; 1822124861Sharti 1823122394Sharti va_start(ap, err); 1824122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1825124861Sharti vsnprintf(errbuf + strlen(errbuf), 1826124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 1827122394Sharti va_end(ap); 1828122394Sharti 1829122394Sharti syslog(LOG_ERR, "%s", errbuf); 1830122394Sharti} 1831122394Sharti 1832122394Shartistatic void 1833122394Shartisnmp_debug_func(const char *err, ...) 1834122394Sharti{ 1835122394Sharti char errbuf[1000]; 1836122394Sharti va_list ap; 1837122394Sharti 1838122394Sharti va_start(ap, err); 1839122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1840122394Sharti vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1841122394Sharti err, ap); 1842122394Sharti va_end(ap); 1843122394Sharti 1844122394Sharti syslog(LOG_DEBUG, "%s", errbuf); 1845122394Sharti} 1846122394Sharti 1847122394Shartistatic void 1848122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...) 1849122394Sharti{ 1850122394Sharti char errbuf[1000]; 1851122394Sharti va_list ap; 1852122394Sharti u_int i; 1853122394Sharti 1854124861Sharti if (!(snmp_trace & LOG_ASN1_ERRORS)) 1855124861Sharti return; 1856124861Sharti 1857122394Sharti va_start(ap, err); 1858122394Sharti snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 1859124861Sharti vsnprintf(errbuf + strlen(errbuf), 1860124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 1861122394Sharti va_end(ap); 1862122394Sharti 1863122394Sharti if (b != NULL) { 1864124861Sharti snprintf(errbuf + strlen(errbuf), 1865124861Sharti sizeof(errbuf) - strlen(errbuf), " at"); 1866122394Sharti for (i = 0; b->asn_len > i; i++) 1867124861Sharti snprintf(errbuf + strlen(errbuf), 1868124861Sharti sizeof(errbuf) - strlen(errbuf), 1869124861Sharti " %02x", b->asn_cptr[i]); 1870122394Sharti } 1871122394Sharti 1872122394Sharti syslog(LOG_ERR, "%s", errbuf); 1873122394Sharti} 1874122394Sharti 1875122394Sharti/* 1876122394Sharti * Create a new community 1877122394Sharti */ 1878122394Shartiu_int 1879122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner, 1880122394Sharti const char *str) 1881122394Sharti{ 1882122394Sharti struct community *c, *p; 1883122394Sharti u_int ncomm; 1884122394Sharti 1885122394Sharti /* generate an identifier */ 1886122394Sharti do { 1887122394Sharti if ((ncomm = next_community_index++) == UINT_MAX) 1888122394Sharti next_community_index = 1; 1889122394Sharti TAILQ_FOREACH(c, &community_list, link) 1890122394Sharti if (c->value == ncomm) 1891122394Sharti break; 1892122394Sharti } while (c != NULL); 1893122394Sharti 1894122394Sharti if ((c = malloc(sizeof(struct community))) == NULL) { 1895122394Sharti syslog(LOG_ERR, "comm_define: %m"); 1896122394Sharti return (0); 1897122394Sharti } 1898122394Sharti c->owner = owner; 1899122394Sharti c->value = ncomm; 1900122394Sharti c->descr = descr; 1901122394Sharti c->string = NULL; 1902122394Sharti c->private = priv; 1903122394Sharti 1904122394Sharti if (str != NULL) { 1905122394Sharti if((c->string = malloc(strlen(str)+1)) == NULL) { 1906122394Sharti free(c); 1907122394Sharti return (0); 1908122394Sharti } 1909122394Sharti strcpy(c->string, str); 1910122394Sharti } 1911122394Sharti 1912122394Sharti /* make index */ 1913122394Sharti if (c->owner == NULL) { 1914122394Sharti c->index.len = 1; 1915122394Sharti c->index.subs[0] = 0; 1916122394Sharti } else { 1917122394Sharti c->index = c->owner->index; 1918122394Sharti } 1919122394Sharti c->index.subs[c->index.len++] = c->private; 1920122394Sharti 1921122394Sharti /* 1922122394Sharti * Insert ordered 1923122394Sharti */ 1924122394Sharti TAILQ_FOREACH(p, &community_list, link) { 1925122394Sharti if (asn_compare_oid(&p->index, &c->index) > 0) { 1926122394Sharti TAILQ_INSERT_BEFORE(p, c, link); 1927122394Sharti break; 1928122394Sharti } 1929122394Sharti } 1930122394Sharti if (p == NULL) 1931122394Sharti TAILQ_INSERT_TAIL(&community_list, c, link); 1932122394Sharti return (c->value); 1933122394Sharti} 1934122394Sharti 1935122394Sharticonst char * 1936122394Sharticomm_string(u_int ncomm) 1937122394Sharti{ 1938122394Sharti struct community *p; 1939122394Sharti 1940122394Sharti TAILQ_FOREACH(p, &community_list, link) 1941122394Sharti if (p->value == ncomm) 1942122394Sharti return (p->string); 1943122394Sharti return (NULL); 1944122394Sharti} 1945122394Sharti 1946122394Sharti/* 1947122394Sharti * Delete all communities allocated by a module 1948122394Sharti */ 1949122394Shartistatic void 1950122394Sharticomm_flush(struct lmodule *mod) 1951122394Sharti{ 1952122394Sharti struct community *p, *p1; 1953122394Sharti 1954122394Sharti p = TAILQ_FIRST(&community_list); 1955122394Sharti while (p != NULL) { 1956122394Sharti p1 = TAILQ_NEXT(p, link); 1957122394Sharti if (p->owner == mod) { 1958122394Sharti free(p->string); 1959122394Sharti TAILQ_REMOVE(&community_list, p, link); 1960122394Sharti free(p); 1961122394Sharti } 1962122394Sharti p = p1; 1963122394Sharti } 1964122394Sharti} 1965122394Sharti 1966122394Sharti/* 1967122394Sharti * Request ID handling. 1968122394Sharti * 1969122394Sharti * Allocate a new range of request ids. Use a first fit algorithm. 1970122394Sharti */ 1971122394Shartiu_int 1972122394Shartireqid_allocate(int size, struct lmodule *mod) 1973122394Sharti{ 1974122394Sharti u_int type; 1975122394Sharti struct idrange *r, *r1; 1976122394Sharti 1977122394Sharti if (size <= 0 || size > INT32_MAX) { 1978122394Sharti syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1979122394Sharti return (0); 1980122394Sharti } 1981122394Sharti /* allocate a type id */ 1982122394Sharti do { 1983122394Sharti if ((type = next_idrange++) == UINT_MAX) 1984122394Sharti next_idrange = 1; 1985122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 1986122394Sharti if (r->type == type) 1987122394Sharti break; 1988122394Sharti } while(r != NULL); 1989122394Sharti 1990122394Sharti /* find a range */ 1991122394Sharti if (TAILQ_EMPTY(&idrange_list)) 1992122394Sharti r = NULL; 1993122394Sharti else { 1994122394Sharti r = TAILQ_FIRST(&idrange_list); 1995122394Sharti if (r->base < size) { 1996122394Sharti while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1997122394Sharti if (r1->base - (r->base + r->size) >= size) 1998122394Sharti break; 1999122394Sharti r = r1; 2000122394Sharti } 2001122394Sharti r = r1; 2002122394Sharti } 2003122394Sharti if (r == NULL) { 2004122394Sharti r1 = TAILQ_LAST(&idrange_list, idrange_list); 2005122394Sharti if (INT32_MAX - size + 1 < r1->base + r1->size) { 2006122394Sharti syslog(LOG_ERR, "out of id ranges (%u)", size); 2007122394Sharti return (0); 2008122394Sharti } 2009122394Sharti } 2010122394Sharti } 2011122394Sharti 2012122394Sharti /* allocate structure */ 2013122394Sharti if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2014122394Sharti syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2015122394Sharti return (0); 2016122394Sharti } 2017122394Sharti 2018122394Sharti r1->type = type; 2019122394Sharti r1->size = size; 2020122394Sharti r1->owner = mod; 2021122394Sharti if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2022122394Sharti r1->base = 0; 2023122394Sharti TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2024122394Sharti } else if (r == NULL) { 2025122394Sharti r = TAILQ_LAST(&idrange_list, idrange_list); 2026122394Sharti r1->base = r->base + r->size; 2027122394Sharti TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2028122394Sharti } else { 2029122394Sharti r = TAILQ_PREV(r, idrange_list, link); 2030122394Sharti r1->base = r->base + r->size; 2031122394Sharti TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2032122394Sharti } 2033122394Sharti r1->next = r1->base; 2034122394Sharti 2035122394Sharti return (type); 2036122394Sharti} 2037122394Sharti 2038122394Shartiint32_t 2039122394Shartireqid_next(u_int type) 2040122394Sharti{ 2041122394Sharti struct idrange *r; 2042122394Sharti int32_t id; 2043122394Sharti 2044122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2045122394Sharti if (r->type == type) 2046122394Sharti break; 2047122394Sharti if (r == NULL) { 2048122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2049122394Sharti abort(); 2050122394Sharti } 2051122394Sharti if ((id = r->next++) == r->base + (r->size - 1)) 2052122394Sharti r->next = r->base; 2053122394Sharti return (id); 2054122394Sharti} 2055122394Sharti 2056122394Shartiint32_t 2057122394Shartireqid_base(u_int type) 2058122394Sharti{ 2059122394Sharti struct idrange *r; 2060122394Sharti 2061122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2062122394Sharti if (r->type == type) 2063122394Sharti return (r->base); 2064122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2065122394Sharti abort(); 2066122394Sharti} 2067122394Sharti 2068122394Shartiu_int 2069122394Shartireqid_type(int32_t reqid) 2070122394Sharti{ 2071122394Sharti struct idrange *r; 2072122394Sharti 2073122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2074122394Sharti if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2075122394Sharti return (r->type); 2076122394Sharti return (0); 2077122394Sharti} 2078122394Sharti 2079122394Shartiint 2080122394Shartireqid_istype(int32_t reqid, u_int type) 2081122394Sharti{ 2082122394Sharti return (reqid_type(reqid) == type); 2083122394Sharti} 2084122394Sharti 2085122394Sharti/* 2086122394Sharti * Delete all communities allocated by a module 2087122394Sharti */ 2088122394Shartistatic void 2089122394Shartireqid_flush(struct lmodule *mod) 2090122394Sharti{ 2091122394Sharti struct idrange *p, *p1; 2092122394Sharti 2093122394Sharti p = TAILQ_FIRST(&idrange_list); 2094122394Sharti while (p != NULL) { 2095122394Sharti p1 = TAILQ_NEXT(p, link); 2096122394Sharti if (p->owner == mod) { 2097122394Sharti TAILQ_REMOVE(&idrange_list, p, link); 2098122394Sharti free(p); 2099122394Sharti } 2100122394Sharti p = p1; 2101122394Sharti } 2102122394Sharti} 2103122394Sharti 2104122394Sharti/* 2105122394Sharti * Merge the given tree for the given module into the main tree. 2106122394Sharti */ 2107122394Shartistatic int 2108122394Sharticompare_node(const void *v1, const void *v2) 2109122394Sharti{ 2110122394Sharti const struct snmp_node *n1 = v1; 2111122394Sharti const struct snmp_node *n2 = v2; 2112122394Sharti 2113122394Sharti return (asn_compare_oid(&n1->oid, &n2->oid)); 2114122394Sharti} 2115122394Shartistatic int 2116122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2117122394Sharti{ 2118122394Sharti struct snmp_node *xtree; 2119122394Sharti u_int i; 2120122394Sharti 2121122394Sharti xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2122122394Sharti if (xtree == NULL) { 2123128237Sharti syslog(LOG_ERR, "tree_merge: %m"); 2124122394Sharti return (-1); 2125122394Sharti } 2126122394Sharti tree = xtree; 2127122394Sharti memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2128122394Sharti 2129122394Sharti for (i = 0; i < nsize; i++) 2130128237Sharti tree[tree_size + i].tree_data = mod; 2131122394Sharti 2132122394Sharti tree_size += nsize; 2133122394Sharti 2134122394Sharti qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2135122394Sharti 2136122394Sharti return (0); 2137122394Sharti} 2138122394Sharti 2139122394Sharti/* 2140122394Sharti * Remove all nodes belonging to the loadable module 2141122394Sharti */ 2142122394Shartistatic void 2143122394Shartitree_unmerge(struct lmodule *mod) 2144122394Sharti{ 2145122394Sharti u_int s, d; 2146122394Sharti 2147122394Sharti for(s = d = 0; s < tree_size; s++) 2148128237Sharti if (tree[s].tree_data != mod) { 2149122394Sharti if (s != d) 2150122394Sharti tree[d] = tree[s]; 2151122394Sharti d++; 2152122394Sharti } 2153122394Sharti tree_size = d; 2154122394Sharti} 2155122394Sharti 2156122394Sharti/* 2157122394Sharti * Loadable modules 2158122394Sharti */ 2159122394Shartistruct lmodule * 2160122394Shartilm_load(const char *path, const char *section) 2161122394Sharti{ 2162122394Sharti struct lmodule *m; 2163122394Sharti int err; 2164122394Sharti int i; 2165122394Sharti char *av[MAX_MOD_ARGS + 1]; 2166122394Sharti int ac; 2167122394Sharti u_int u; 2168122394Sharti 2169122394Sharti if ((m = malloc(sizeof(*m))) == NULL) { 2170122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2171122394Sharti return (NULL); 2172122394Sharti } 2173122394Sharti m->handle = NULL; 2174122394Sharti m->flags = 0; 2175122394Sharti strcpy(m->section, section); 2176122394Sharti 2177122394Sharti if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2178122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2179122394Sharti goto err; 2180122394Sharti } 2181122394Sharti strcpy(m->path, path); 2182122394Sharti 2183122394Sharti /* 2184122394Sharti * Make index 2185122394Sharti */ 2186122394Sharti m->index.subs[0] = strlen(section); 2187122394Sharti m->index.len = m->index.subs[0] + 1; 2188122394Sharti for (u = 0; u < m->index.subs[0]; u++) 2189122394Sharti m->index.subs[u + 1] = section[u]; 2190122394Sharti 2191122394Sharti /* 2192122394Sharti * Load the object file and locate the config structure 2193122394Sharti */ 2194122394Sharti if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2195122394Sharti syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2196122394Sharti goto err; 2197122394Sharti } 2198122394Sharti 2199122394Sharti if ((m->config = dlsym(m->handle, "config")) == NULL) { 2200122394Sharti syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2201122394Sharti goto err; 2202122394Sharti } 2203122394Sharti 2204122394Sharti /* 2205122394Sharti * Insert it into the right place 2206122394Sharti */ 2207122394Sharti INSERT_OBJECT_OID(m, &lmodules); 2208122394Sharti 2209122394Sharti /* preserve order */ 2210122394Sharti if (community == COMM_INITIALIZE) { 2211122394Sharti m->flags |= LM_ONSTARTLIST; 2212122394Sharti TAILQ_INSERT_TAIL(&modules_start, m, start); 2213122394Sharti } 2214122394Sharti 2215122394Sharti /* 2216122394Sharti * make the argument vector. 2217122394Sharti */ 2218122394Sharti ac = 0; 2219122394Sharti for (i = 0; i < nprogargs; i++) { 2220122394Sharti if (strlen(progargs[i]) >= strlen(section) + 1 && 2221122394Sharti strncmp(progargs[i], section, strlen(section)) == 0 && 2222122394Sharti progargs[i][strlen(section)] == ':') { 2223122394Sharti if (ac == MAX_MOD_ARGS) { 2224122394Sharti syslog(LOG_WARNING, "too many arguments for " 2225122394Sharti "module '%s", section); 2226122394Sharti break; 2227122394Sharti } 2228122394Sharti av[ac++] = &progargs[i][strlen(section)+1]; 2229122394Sharti } 2230122394Sharti } 2231122394Sharti av[ac] = NULL; 2232122394Sharti 2233122394Sharti /* 2234150920Sharti * Run the initialization function 2235122394Sharti */ 2236122394Sharti if ((err = (*m->config->init)(m, ac, av)) != 0) { 2237122394Sharti syslog(LOG_ERR, "lm_load: init failed: %d", err); 2238122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2239122394Sharti goto err; 2240122394Sharti } 2241122394Sharti 2242122394Sharti return (m); 2243122394Sharti 2244122394Sharti err: 2245122394Sharti if (m->handle) 2246122394Sharti dlclose(m->handle); 2247122394Sharti free(m->path); 2248122394Sharti free(m); 2249122394Sharti return (NULL); 2250122394Sharti} 2251122394Sharti 2252122394Sharti/* 2253122394Sharti * Start a module 2254122394Sharti */ 2255122394Shartivoid 2256122394Shartilm_start(struct lmodule *mod) 2257122394Sharti{ 2258122394Sharti const struct lmodule *m; 2259122394Sharti 2260122394Sharti /* 2261122394Sharti * Merge tree. If this fails, unload the module. 2262122394Sharti */ 2263122394Sharti if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2264122394Sharti lm_unload(mod); 2265122394Sharti return; 2266122394Sharti } 2267122394Sharti 2268122394Sharti /* 2269122394Sharti * Read configuration 2270122394Sharti */ 2271122394Sharti if (read_config(config_file, mod)) { 2272122394Sharti syslog(LOG_ERR, "error in config file"); 2273122394Sharti lm_unload(mod); 2274122394Sharti return; 2275122394Sharti } 2276122394Sharti if (mod->config->start) 2277122394Sharti (*mod->config->start)(); 2278122394Sharti 2279122394Sharti mod->flags |= LM_STARTED; 2280122394Sharti 2281122394Sharti /* 2282122394Sharti * Inform other modules 2283122394Sharti */ 2284122394Sharti TAILQ_FOREACH(m, &lmodules, link) 2285122394Sharti if (m->config->loading) 2286122394Sharti (*m->config->loading)(mod, 1); 2287122394Sharti} 2288122394Sharti 2289122394Sharti 2290122394Sharti/* 2291122394Sharti * Unload a module. 2292122394Sharti */ 2293122394Shartivoid 2294122394Shartilm_unload(struct lmodule *m) 2295122394Sharti{ 2296122394Sharti int err; 2297122394Sharti const struct lmodule *mod; 2298122394Sharti 2299122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2300122394Sharti if (m->flags & LM_ONSTARTLIST) 2301122394Sharti TAILQ_REMOVE(&modules_start, m, start); 2302122394Sharti tree_unmerge(m); 2303122394Sharti 2304122394Sharti if ((m->flags & LM_STARTED) && m->config->fini && 2305122394Sharti (err = (*m->config->fini)()) != 0) 2306122394Sharti syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2307122394Sharti 2308122394Sharti comm_flush(m); 2309122394Sharti reqid_flush(m); 2310122394Sharti timer_flush(m); 2311122394Sharti fd_flush(m); 2312122394Sharti 2313122394Sharti dlclose(m->handle); 2314122394Sharti free(m->path); 2315122394Sharti 2316122394Sharti /* 2317122394Sharti * Inform other modules 2318122394Sharti */ 2319122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 2320122394Sharti if (mod->config->loading) 2321122394Sharti (*mod->config->loading)(m, 0); 2322122394Sharti 2323122394Sharti free(m); 2324122394Sharti} 2325122394Sharti 2326122394Sharti/* 2327122394Sharti * Register an object resource and return the index (or 0 on failures) 2328122394Sharti */ 2329122394Shartiu_int 2330122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2331122394Sharti{ 2332122394Sharti struct objres *objres, *or1; 2333122394Sharti u_int idx; 2334122394Sharti 2335122394Sharti /* find a free index */ 2336122394Sharti idx = 1; 2337122394Sharti for (objres = TAILQ_FIRST(&objres_list); 2338122394Sharti objres != NULL; 2339122394Sharti objres = TAILQ_NEXT(objres, link)) { 2340122394Sharti if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2341122394Sharti or1->index > objres->index + 1) { 2342122394Sharti idx = objres->index + 1; 2343122394Sharti break; 2344122394Sharti } 2345122394Sharti } 2346122394Sharti 2347122394Sharti if ((objres = malloc(sizeof(*objres))) == NULL) 2348122394Sharti return (0); 2349122394Sharti 2350122394Sharti objres->index = idx; 2351122394Sharti objres->oid = *or; 2352122394Sharti strlcpy(objres->descr, descr, sizeof(objres->descr)); 2353146525Sharti objres->uptime = (uint32_t)(get_ticks() - start_tick); 2354122394Sharti objres->module = mod; 2355122394Sharti 2356122394Sharti INSERT_OBJECT_INT(objres, &objres_list); 2357122394Sharti 2358122394Sharti systemg.or_last_change = objres->uptime; 2359122394Sharti 2360122394Sharti return (idx); 2361122394Sharti} 2362122394Sharti 2363122394Shartivoid 2364122394Shartior_unregister(u_int idx) 2365122394Sharti{ 2366122394Sharti struct objres *objres; 2367122394Sharti 2368122394Sharti TAILQ_FOREACH(objres, &objres_list, link) 2369122394Sharti if (objres->index == idx) { 2370122394Sharti TAILQ_REMOVE(&objres_list, objres, link); 2371122394Sharti free(objres); 2372122394Sharti return; 2373122394Sharti } 2374122394Sharti} 2375