1f06ca4afSHartmut Brandt /* 2f06ca4afSHartmut Brandt * Copyright (c) 2001-2003 3f06ca4afSHartmut Brandt * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4f06ca4afSHartmut Brandt * All rights reserved. 5f06ca4afSHartmut Brandt * 6f06ca4afSHartmut Brandt * Author: Harti Brandt <harti@freebsd.org> 7f06ca4afSHartmut Brandt * 8896052c1SHartmut Brandt * Redistribution and use in source and binary forms, with or without 9896052c1SHartmut Brandt * modification, are permitted provided that the following conditions 10896052c1SHartmut Brandt * are met: 11896052c1SHartmut Brandt * 1. Redistributions of source code must retain the above copyright 12896052c1SHartmut Brandt * notice, this list of conditions and the following disclaimer. 13f06ca4afSHartmut Brandt * 2. Redistributions in binary form must reproduce the above copyright 14f06ca4afSHartmut Brandt * notice, this list of conditions and the following disclaimer in the 15f06ca4afSHartmut Brandt * documentation and/or other materials provided with the distribution. 16f06ca4afSHartmut Brandt * 17896052c1SHartmut Brandt * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18896052c1SHartmut Brandt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19896052c1SHartmut Brandt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20896052c1SHartmut Brandt * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21896052c1SHartmut Brandt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22896052c1SHartmut Brandt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23896052c1SHartmut Brandt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24896052c1SHartmut Brandt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25896052c1SHartmut Brandt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26896052c1SHartmut Brandt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27896052c1SHartmut Brandt * SUCH DAMAGE. 28f06ca4afSHartmut Brandt * 29165c5d31SHartmut Brandt * $Begemot: bsnmp/snmpd/main.c,v 1.97 2005/10/04 14:32:45 brandt_h Exp $ 30f06ca4afSHartmut Brandt * 31f06ca4afSHartmut Brandt * SNMPd main stuff. 32f06ca4afSHartmut Brandt */ 33f06ca4afSHartmut Brandt #include <sys/param.h> 34f06ca4afSHartmut Brandt #include <sys/un.h> 3570af00a1SHartmut Brandt #include <sys/ucred.h> 36165c5d31SHartmut Brandt #include <sys/uio.h> 37f06ca4afSHartmut Brandt #include <stdio.h> 38f06ca4afSHartmut Brandt #include <stdlib.h> 39f06ca4afSHartmut Brandt #include <stddef.h> 40f06ca4afSHartmut Brandt #include <string.h> 41f06ca4afSHartmut Brandt #include <stdarg.h> 42f06ca4afSHartmut Brandt #include <ctype.h> 43f06ca4afSHartmut Brandt #include <errno.h> 44f06ca4afSHartmut Brandt #include <syslog.h> 45f06ca4afSHartmut Brandt #include <unistd.h> 46f06ca4afSHartmut Brandt #include <signal.h> 47f06ca4afSHartmut Brandt #include <dlfcn.h> 48f06ca4afSHartmut Brandt #include <inttypes.h> 49f06ca4afSHartmut Brandt 50d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 51d7eb6b47SHartmut Brandt #include <arpa/inet.h> 52d7eb6b47SHartmut Brandt #include <tcpd.h> 53d7eb6b47SHartmut Brandt #endif 54d7eb6b47SHartmut Brandt 55f06ca4afSHartmut Brandt #include "snmpmod.h" 56f06ca4afSHartmut Brandt #include "snmpd.h" 57f06ca4afSHartmut Brandt #include "tree.h" 58f06ca4afSHartmut Brandt #include "oid.h" 59f06ca4afSHartmut Brandt 60f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 61f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 62f06ca4afSHartmut Brandt 6369292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 6469292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 65f06ca4afSHartmut Brandt 66f06ca4afSHartmut Brandt struct systemg systemg = { 67f06ca4afSHartmut Brandt NULL, 68f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 69f06ca4afSHartmut Brandt NULL, NULL, NULL, 70f06ca4afSHartmut Brandt 64 + 8 + 4, 71f06ca4afSHartmut Brandt 0 72f06ca4afSHartmut Brandt }; 73f06ca4afSHartmut Brandt struct debug debug = { 74f06ca4afSHartmut Brandt 0, /* dump_pdus */ 75f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 76f06ca4afSHartmut Brandt 0, /* evdebug */ 77f06ca4afSHartmut Brandt }; 78f06ca4afSHartmut Brandt 79f06ca4afSHartmut Brandt struct snmpd snmpd = { 80f06ca4afSHartmut Brandt 2048, /* txbuf */ 81f06ca4afSHartmut Brandt 2048, /* rxbuf */ 82f06ca4afSHartmut Brandt 0, /* comm_dis */ 83f06ca4afSHartmut Brandt 0, /* auth_traps */ 84f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 8570af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 86f06ca4afSHartmut Brandt }; 87f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 88f06ca4afSHartmut Brandt 89f06ca4afSHartmut Brandt /* snmpSerialNo */ 90f06ca4afSHartmut Brandt int32_t snmp_serial_no; 91f06ca4afSHartmut Brandt 92f06ca4afSHartmut Brandt /* search path for config files */ 93f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 94f06ca4afSHartmut Brandt 95f06ca4afSHartmut Brandt /* list of all loaded modules */ 96f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 97f06ca4afSHartmut Brandt 98f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 99f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 100f06ca4afSHartmut Brandt 101f06ca4afSHartmut Brandt /* list of all known communities */ 102f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 103f06ca4afSHartmut Brandt 104f06ca4afSHartmut Brandt /* list of all installed object resources */ 105f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 106f06ca4afSHartmut Brandt 107f06ca4afSHartmut Brandt /* community value generator */ 108f06ca4afSHartmut Brandt static u_int next_community_index = 1; 109f06ca4afSHartmut Brandt 110f06ca4afSHartmut Brandt /* list of all known ranges */ 111f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 112f06ca4afSHartmut Brandt 113f06ca4afSHartmut Brandt /* identifier generator */ 114f06ca4afSHartmut Brandt u_int next_idrange = 1; 115f06ca4afSHartmut Brandt 116f06ca4afSHartmut Brandt /* list of all current timers */ 117f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 118f06ca4afSHartmut Brandt 119f06ca4afSHartmut Brandt /* list of file descriptors */ 120f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 121f06ca4afSHartmut Brandt 122f06ca4afSHartmut Brandt /* program arguments */ 123f06ca4afSHartmut Brandt static char **progargs; 124f06ca4afSHartmut Brandt static int nprogargs; 125f06ca4afSHartmut Brandt 126f06ca4afSHartmut Brandt /* current community */ 127f06ca4afSHartmut Brandt u_int community; 128f06ca4afSHartmut Brandt static struct community *comm; 129f06ca4afSHartmut Brandt 130f06ca4afSHartmut Brandt /* file names */ 131f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 132f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 133f06ca4afSHartmut Brandt 13470af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 135f06ca4afSHartmut Brandt /* event context */ 136f06ca4afSHartmut Brandt static evContext evctx; 13770af00a1SHartmut Brandt #endif 138f06ca4afSHartmut Brandt 139f06ca4afSHartmut Brandt /* signal mask */ 140f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 141f06ca4afSHartmut Brandt 142f06ca4afSHartmut Brandt /* signal handling */ 143f06ca4afSHartmut Brandt static int work; 144f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 145f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 146f06ca4afSHartmut Brandt 147f06ca4afSHartmut Brandt /* oids */ 148f06ca4afSHartmut Brandt static const struct asn_oid 149f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 150f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 151f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 152f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 153f06ca4afSHartmut Brandt 154f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 155f06ca4afSHartmut Brandt 156f06ca4afSHartmut Brandt /* request id generator for traps */ 157f06ca4afSHartmut Brandt u_int trap_reqid; 158f06ca4afSHartmut Brandt 159f06ca4afSHartmut Brandt /* help text */ 160f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 161f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 162f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 163f06ca4afSHartmut Brandt usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 164f06ca4afSHartmut Brandt [-m variable=value] [-p file]\n\ 165f06ca4afSHartmut Brandt options:\n\ 166f06ca4afSHartmut Brandt -d don't daemonize\n\ 167f06ca4afSHartmut Brandt -h print this info\n\ 168f06ca4afSHartmut Brandt -c file specify configuration file\n\ 169f06ca4afSHartmut Brandt -D options debugging options\n\ 170f06ca4afSHartmut Brandt -I path system include path\n\ 171f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 172f06ca4afSHartmut Brandt -m var=val define variable\n\ 173f06ca4afSHartmut Brandt -p file specify pid file\n\ 174f06ca4afSHartmut Brandt "; 175f06ca4afSHartmut Brandt 176d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 177d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 178d7eb6b47SHartmut Brandt static struct request_info req; 179d7eb6b47SHartmut Brandt #endif 180d7eb6b47SHartmut Brandt 18170af00a1SHartmut Brandt /* transports */ 18270af00a1SHartmut Brandt extern const struct transport_def udp_trans; 18370af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 18470af00a1SHartmut Brandt 18570af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 18670af00a1SHartmut Brandt 187f06ca4afSHartmut Brandt /* forward declarations */ 188f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 189f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 190f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 191f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 192f06ca4afSHartmut Brandt 193f06ca4afSHartmut Brandt /* 194f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 195f06ca4afSHartmut Brandt */ 196f06ca4afSHartmut Brandt void * 197f06ca4afSHartmut Brandt buf_alloc(int tx) 198f06ca4afSHartmut Brandt { 199f06ca4afSHartmut Brandt void *buf; 200f06ca4afSHartmut Brandt 20170af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 202f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 203f06ca4afSHartmut Brandt if (tx) 204f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 205f06ca4afSHartmut Brandt else 206f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 207f06ca4afSHartmut Brandt return (NULL); 208f06ca4afSHartmut Brandt } 209f06ca4afSHartmut Brandt return (buf); 210f06ca4afSHartmut Brandt } 211f06ca4afSHartmut Brandt 212f06ca4afSHartmut Brandt /* 21370af00a1SHartmut Brandt * Return the buffer size. 214f06ca4afSHartmut Brandt */ 215f06ca4afSHartmut Brandt size_t 216f06ca4afSHartmut Brandt buf_size(int tx) 217f06ca4afSHartmut Brandt { 21870af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 219f06ca4afSHartmut Brandt } 220f06ca4afSHartmut Brandt 221f06ca4afSHartmut Brandt /* 222f06ca4afSHartmut Brandt * Prepare a PDU for output 223f06ca4afSHartmut Brandt */ 224f06ca4afSHartmut Brandt void 22570af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 226f06ca4afSHartmut Brandt const char *dest) 227f06ca4afSHartmut Brandt { 228f06ca4afSHartmut Brandt struct asn_buf resp_b; 229f06ca4afSHartmut Brandt 230f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 231f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 232f06ca4afSHartmut Brandt 233f06ca4afSHartmut Brandt if (snmp_pdu_encode(pdu, &resp_b) != 0) { 234f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot encode message"); 235f06ca4afSHartmut Brandt abort(); 236f06ca4afSHartmut Brandt } 237f06ca4afSHartmut Brandt if (debug.dump_pdus) { 238f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 239f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 240f06ca4afSHartmut Brandt } 241f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 242f06ca4afSHartmut Brandt } 243f06ca4afSHartmut Brandt 244f06ca4afSHartmut Brandt /* 245f06ca4afSHartmut Brandt * SNMP input. Start: decode the PDU, find the community. 246f06ca4afSHartmut Brandt */ 247f06ca4afSHartmut Brandt enum snmpd_input_err 248f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 24970af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 250f06ca4afSHartmut Brandt { 251f06ca4afSHartmut Brandt struct asn_buf b; 252f06ca4afSHartmut Brandt enum snmp_code code; 253f06ca4afSHartmut Brandt enum snmpd_input_err ret; 25470af00a1SHartmut Brandt int sret; 255f06ca4afSHartmut Brandt 256f06ca4afSHartmut Brandt b.asn_cptr = buf; 257f06ca4afSHartmut Brandt b.asn_len = len; 25870af00a1SHartmut Brandt 25970af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 26070af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 26170af00a1SHartmut Brandt 26270af00a1SHartmut Brandt case 0: 26370af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 26470af00a1SHartmut Brandt 26570af00a1SHartmut Brandt case -1: 26670af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 26770af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 26870af00a1SHartmut Brandt } 26970af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 27070af00a1SHartmut Brandt 271f06ca4afSHartmut Brandt code = snmp_pdu_decode(&b, pdu, ip); 272f06ca4afSHartmut Brandt 27370af00a1SHartmut Brandt snmpd_stats.inPkts++; 27470af00a1SHartmut Brandt 275f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 276f06ca4afSHartmut Brandt switch (code) { 277f06ca4afSHartmut Brandt 278f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 279f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 280f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 281f06ca4afSHartmut Brandt 282f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 28370af00a1SHartmut Brandt bad_vers: 284f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 285f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 286f06ca4afSHartmut Brandt 287f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 288f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 289f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 290f06ca4afSHartmut Brandt break; 291f06ca4afSHartmut Brandt 292f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 293f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 294f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 295f06ca4afSHartmut Brandt break; 296f06ca4afSHartmut Brandt 297f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 298f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 299f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 300f06ca4afSHartmut Brandt break; 301f06ca4afSHartmut Brandt 302f06ca4afSHartmut Brandt case SNMP_CODE_OK: 30370af00a1SHartmut Brandt switch (pdu->version) { 30470af00a1SHartmut Brandt 30570af00a1SHartmut Brandt case SNMP_V1: 30670af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 30770af00a1SHartmut Brandt goto bad_vers; 30870af00a1SHartmut Brandt break; 30970af00a1SHartmut Brandt 31070af00a1SHartmut Brandt case SNMP_V2c: 31170af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 31270af00a1SHartmut Brandt goto bad_vers; 31370af00a1SHartmut Brandt break; 31470af00a1SHartmut Brandt 31570af00a1SHartmut Brandt case SNMP_Verr: 31670af00a1SHartmut Brandt goto bad_vers; 31770af00a1SHartmut Brandt } 318f06ca4afSHartmut Brandt break; 319f06ca4afSHartmut Brandt } 320f06ca4afSHartmut Brandt 321f06ca4afSHartmut Brandt if (debug.dump_pdus) { 322f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 323f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 324f06ca4afSHartmut Brandt } 325f06ca4afSHartmut Brandt 326f06ca4afSHartmut Brandt /* 327f06ca4afSHartmut Brandt * Look, whether we know the community 328f06ca4afSHartmut Brandt */ 329f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 330f06ca4afSHartmut Brandt if (comm->string != NULL && 331f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 332f06ca4afSHartmut Brandt break; 333f06ca4afSHartmut Brandt 334f06ca4afSHartmut Brandt if (comm == NULL) { 335f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 336f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 337f06ca4afSHartmut Brandt if (snmpd.auth_traps) 338896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 339896052c1SHartmut Brandt (struct snmp_value *)NULL); 340896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 341896052c1SHartmut Brandt } else 342f06ca4afSHartmut Brandt community = comm->value; 343f06ca4afSHartmut Brandt 344f06ca4afSHartmut Brandt /* update uptime */ 345f06ca4afSHartmut Brandt this_tick = get_ticks(); 346f06ca4afSHartmut Brandt 347f06ca4afSHartmut Brandt return (ret); 348f06ca4afSHartmut Brandt } 349f06ca4afSHartmut Brandt 350f06ca4afSHartmut Brandt /* 351f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 352f06ca4afSHartmut Brandt */ 353f06ca4afSHartmut Brandt enum snmpd_input_err 354f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 355f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 356f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 357f06ca4afSHartmut Brandt { 358f06ca4afSHartmut Brandt struct snmp_pdu resp; 359f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 360f06ca4afSHartmut Brandt enum snmp_ret ret; 361f06ca4afSHartmut Brandt 362f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 363f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 364f06ca4afSHartmut Brandt 365f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 366f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 367f06ca4afSHartmut Brandt 368f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 369f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 370f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 371f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 372f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 373f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 374f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 375f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 376f06ca4afSHartmut Brandt else 377f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 378f06ca4afSHartmut Brandt 379f06ca4afSHartmut Brandt pdu->error_index = ivar; 380f06ca4afSHartmut Brandt 381f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 382f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 383f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 384f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 385f06ca4afSHartmut Brandt } 386f06ca4afSHartmut Brandt 387f06ca4afSHartmut Brandt if (debug.dump_pdus) { 388f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 389f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 390f06ca4afSHartmut Brandt } 391f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 392f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 393f06ca4afSHartmut Brandt } 394f06ca4afSHartmut Brandt 395f06ca4afSHartmut Brandt switch (pdu->type) { 396f06ca4afSHartmut Brandt 397f06ca4afSHartmut Brandt case SNMP_PDU_GET: 398f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 399f06ca4afSHartmut Brandt break; 400f06ca4afSHartmut Brandt 401f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 402f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 403f06ca4afSHartmut Brandt break; 404f06ca4afSHartmut Brandt 405f06ca4afSHartmut Brandt case SNMP_PDU_SET: 406f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 407f06ca4afSHartmut Brandt break; 408f06ca4afSHartmut Brandt 409f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 410f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 411f06ca4afSHartmut Brandt break; 412f06ca4afSHartmut Brandt 413f06ca4afSHartmut Brandt default: 414f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 415f06ca4afSHartmut Brandt break; 416f06ca4afSHartmut Brandt } 417f06ca4afSHartmut Brandt 418f06ca4afSHartmut Brandt switch (ret) { 419f06ca4afSHartmut Brandt 420f06ca4afSHartmut Brandt case SNMP_RET_OK: 421f06ca4afSHartmut Brandt /* normal return - send a response */ 422f06ca4afSHartmut Brandt if (debug.dump_pdus) { 423f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 424f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 425f06ca4afSHartmut Brandt } 426f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 427f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 428f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 429f06ca4afSHartmut Brandt 430f06ca4afSHartmut Brandt case SNMP_RET_IGN: 431f06ca4afSHartmut Brandt /* error - send nothing */ 432f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 433f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 434f06ca4afSHartmut Brandt 435f06ca4afSHartmut Brandt case SNMP_RET_ERR: 436f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 437f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 438f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 439f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 440f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 441f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 442f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 443f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 444f06ca4afSHartmut Brandt } else { 445f06ca4afSHartmut Brandt if (debug.dump_pdus) { 446f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 447f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 448f06ca4afSHartmut Brandt } 449f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 450f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 451f06ca4afSHartmut Brandt } 452f06ca4afSHartmut Brandt } 453f06ca4afSHartmut Brandt abort(); 454f06ca4afSHartmut Brandt } 455f06ca4afSHartmut Brandt 45670af00a1SHartmut Brandt /* 45770af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 45870af00a1SHartmut Brandt */ 45970af00a1SHartmut Brandt void 46070af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 46170af00a1SHartmut Brandt { 46270af00a1SHartmut Brandt struct tport *p; 463f06ca4afSHartmut Brandt 46470af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 46570af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 46670af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 46770af00a1SHartmut Brandt return; 46870af00a1SHartmut Brandt } 46970af00a1SHartmut Brandt } 47070af00a1SHartmut Brandt port->transport = t; 47170af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 47270af00a1SHartmut Brandt } 47370af00a1SHartmut Brandt 47470af00a1SHartmut Brandt /* 47570af00a1SHartmut Brandt * Remove a port from a transport's list 47670af00a1SHartmut Brandt */ 47770af00a1SHartmut Brandt void 47870af00a1SHartmut Brandt trans_remove_port(struct tport *port) 47970af00a1SHartmut Brandt { 48070af00a1SHartmut Brandt 48170af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 48270af00a1SHartmut Brandt } 48370af00a1SHartmut Brandt 48470af00a1SHartmut Brandt /* 48570af00a1SHartmut Brandt * Find a port on a transport's list 48670af00a1SHartmut Brandt */ 48770af00a1SHartmut Brandt struct tport * 48870af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 48970af00a1SHartmut Brandt { 49070af00a1SHartmut Brandt 49170af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 49270af00a1SHartmut Brandt } 49370af00a1SHartmut Brandt 49470af00a1SHartmut Brandt /* 49570af00a1SHartmut Brandt * Find next port on a transport's list 49670af00a1SHartmut Brandt */ 49770af00a1SHartmut Brandt struct tport * 49870af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 49970af00a1SHartmut Brandt { 50070af00a1SHartmut Brandt 50170af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 50270af00a1SHartmut Brandt } 50370af00a1SHartmut Brandt 50470af00a1SHartmut Brandt /* 50570af00a1SHartmut Brandt * Return first port 50670af00a1SHartmut Brandt */ 50770af00a1SHartmut Brandt struct tport * 50870af00a1SHartmut Brandt trans_first_port(struct transport *t) 50970af00a1SHartmut Brandt { 51070af00a1SHartmut Brandt 51170af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 51270af00a1SHartmut Brandt } 51370af00a1SHartmut Brandt 51470af00a1SHartmut Brandt /* 51570af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 51670af00a1SHartmut Brandt */ 51770af00a1SHartmut Brandt struct tport * 51870af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 51970af00a1SHartmut Brandt intptr_t arg) 52070af00a1SHartmut Brandt { 52170af00a1SHartmut Brandt struct tport *p; 52270af00a1SHartmut Brandt 52370af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 52470af00a1SHartmut Brandt if (func(p, arg) == 0) 52570af00a1SHartmut Brandt return (p); 52670af00a1SHartmut Brandt return (NULL); 52770af00a1SHartmut Brandt } 52870af00a1SHartmut Brandt 52970af00a1SHartmut Brandt /* 53070af00a1SHartmut Brandt * Register a transport 53170af00a1SHartmut Brandt */ 53270af00a1SHartmut Brandt int 53370af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 53470af00a1SHartmut Brandt { 53570af00a1SHartmut Brandt u_int i; 53670af00a1SHartmut Brandt char or_descr[256]; 53770af00a1SHartmut Brandt 53870af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 53970af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 54070af00a1SHartmut Brandt 54170af00a1SHartmut Brandt /* construct index */ 54270af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 54370af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 54470af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 54570af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 54670af00a1SHartmut Brandt 54770af00a1SHartmut Brandt (*pp)->vtab = def; 54870af00a1SHartmut Brandt 54970af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 55070af00a1SHartmut Brandt free(*pp); 55170af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 55270af00a1SHartmut Brandt } 55370af00a1SHartmut Brandt 55470af00a1SHartmut Brandt /* register module */ 55570af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 55670af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 55770af00a1SHartmut Brandt free(*pp); 55870af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 55970af00a1SHartmut Brandt } 56070af00a1SHartmut Brandt 56170af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 56270af00a1SHartmut Brandt 56370af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 56470af00a1SHartmut Brandt 56570af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 56670af00a1SHartmut Brandt } 56770af00a1SHartmut Brandt 56870af00a1SHartmut Brandt /* 56970af00a1SHartmut Brandt * Unregister transport 57070af00a1SHartmut Brandt */ 57170af00a1SHartmut Brandt int 57270af00a1SHartmut Brandt trans_unregister(struct transport *t) 57370af00a1SHartmut Brandt { 57470af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 57570af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 57670af00a1SHartmut Brandt 57770af00a1SHartmut Brandt or_unregister(t->or_index); 57870af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 57970af00a1SHartmut Brandt 58070af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 58170af00a1SHartmut Brandt } 582f06ca4afSHartmut Brandt 583f06ca4afSHartmut Brandt /* 584f06ca4afSHartmut Brandt * File descriptor support 585f06ca4afSHartmut Brandt */ 58670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 58770af00a1SHartmut Brandt static void 58870af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 58970af00a1SHartmut Brandt #else 590f06ca4afSHartmut Brandt static void 591f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 59270af00a1SHartmut Brandt #endif 593f06ca4afSHartmut Brandt { 594f06ca4afSHartmut Brandt struct fdesc *f = uap; 595f06ca4afSHartmut Brandt 596f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 597f06ca4afSHartmut Brandt } 598f06ca4afSHartmut Brandt 599f06ca4afSHartmut Brandt void 600f06ca4afSHartmut Brandt fd_suspend(void *p) 601f06ca4afSHartmut Brandt { 602f06ca4afSHartmut Brandt struct fdesc *f = p; 603f06ca4afSHartmut Brandt 60470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 60570af00a1SHartmut Brandt if (f->id >= 0) { 60670af00a1SHartmut Brandt poll_unregister(f->id); 60770af00a1SHartmut Brandt f->id = -1; 60870af00a1SHartmut Brandt } 60970af00a1SHartmut Brandt #else 610f06ca4afSHartmut Brandt if (evTestID(f->id)) { 611f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 612f06ca4afSHartmut Brandt evInitID(&f->id); 613f06ca4afSHartmut Brandt } 61470af00a1SHartmut Brandt #endif 615f06ca4afSHartmut Brandt } 616f06ca4afSHartmut Brandt 617f06ca4afSHartmut Brandt int 618f06ca4afSHartmut Brandt fd_resume(void *p) 619f06ca4afSHartmut Brandt { 620f06ca4afSHartmut Brandt struct fdesc *f = p; 621f06ca4afSHartmut Brandt int err; 622f06ca4afSHartmut Brandt 62370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 62470af00a1SHartmut Brandt if (f->id >= 0) 62570af00a1SHartmut Brandt return (0); 62694caccb3SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 62770af00a1SHartmut Brandt err = errno; 62870af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 62970af00a1SHartmut Brandt errno = err; 63070af00a1SHartmut Brandt return (-1); 63170af00a1SHartmut Brandt } 63270af00a1SHartmut Brandt #else 633f06ca4afSHartmut Brandt if (evTestID(f->id)) 634f06ca4afSHartmut Brandt return (0); 635f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 636f06ca4afSHartmut Brandt err = errno; 637f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 638f06ca4afSHartmut Brandt errno = err; 639f06ca4afSHartmut Brandt return (-1); 640f06ca4afSHartmut Brandt } 64170af00a1SHartmut Brandt #endif 642f06ca4afSHartmut Brandt return (0); 643f06ca4afSHartmut Brandt } 644f06ca4afSHartmut Brandt 645f06ca4afSHartmut Brandt void * 646f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 647f06ca4afSHartmut Brandt { 648f06ca4afSHartmut Brandt struct fdesc *f; 649f06ca4afSHartmut Brandt int err; 650f06ca4afSHartmut Brandt 651f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 652f06ca4afSHartmut Brandt err = errno; 653f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 654f06ca4afSHartmut Brandt errno = err; 655f06ca4afSHartmut Brandt return (NULL); 656f06ca4afSHartmut Brandt } 657f06ca4afSHartmut Brandt f->fd = fd; 658f06ca4afSHartmut Brandt f->func = func; 659f06ca4afSHartmut Brandt f->udata = udata; 660f06ca4afSHartmut Brandt f->owner = mod; 66170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 66270af00a1SHartmut Brandt f->id = -1; 66370af00a1SHartmut Brandt #else 664f06ca4afSHartmut Brandt evInitID(&f->id); 66570af00a1SHartmut Brandt #endif 666f06ca4afSHartmut Brandt 667f06ca4afSHartmut Brandt if (fd_resume(f)) { 668f06ca4afSHartmut Brandt err = errno; 669f06ca4afSHartmut Brandt free(f); 670f06ca4afSHartmut Brandt errno = err; 671f06ca4afSHartmut Brandt return (NULL); 672f06ca4afSHartmut Brandt } 673f06ca4afSHartmut Brandt 674f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 675f06ca4afSHartmut Brandt 676f06ca4afSHartmut Brandt return (f); 677f06ca4afSHartmut Brandt } 678f06ca4afSHartmut Brandt 679f06ca4afSHartmut Brandt void 680f06ca4afSHartmut Brandt fd_deselect(void *p) 681f06ca4afSHartmut Brandt { 682f06ca4afSHartmut Brandt struct fdesc *f = p; 683f06ca4afSHartmut Brandt 684f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 685f06ca4afSHartmut Brandt fd_suspend(f); 686f06ca4afSHartmut Brandt free(f); 687f06ca4afSHartmut Brandt } 688f06ca4afSHartmut Brandt 689f06ca4afSHartmut Brandt static void 690f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 691f06ca4afSHartmut Brandt { 692f06ca4afSHartmut Brandt struct fdesc *t, *t1; 693f06ca4afSHartmut Brandt 694f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 695f06ca4afSHartmut Brandt while (t != NULL) { 696f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 697f06ca4afSHartmut Brandt if (t->owner == mod) 698f06ca4afSHartmut Brandt fd_deselect(t); 699f06ca4afSHartmut Brandt t = t1; 700f06ca4afSHartmut Brandt } 701f06ca4afSHartmut Brandt } 702f06ca4afSHartmut Brandt 703f06ca4afSHartmut Brandt /* 70470af00a1SHartmut Brandt * Consume a message from the input buffer 705f06ca4afSHartmut Brandt */ 706f06ca4afSHartmut Brandt static void 70770af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 708f06ca4afSHartmut Brandt { 70970af00a1SHartmut Brandt if (!pi->stream) { 71070af00a1SHartmut Brandt /* always consume everything */ 71170af00a1SHartmut Brandt pi->length = 0; 71270af00a1SHartmut Brandt return; 71370af00a1SHartmut Brandt } 71470af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 71570af00a1SHartmut Brandt /* all bytes consumed */ 71670af00a1SHartmut Brandt pi->length = 0; 71770af00a1SHartmut Brandt return; 71870af00a1SHartmut Brandt } 71970af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 72070af00a1SHartmut Brandt pi->length -= pi->consumed; 72170af00a1SHartmut Brandt } 72270af00a1SHartmut Brandt 72370af00a1SHartmut Brandt struct credmsg { 72470af00a1SHartmut Brandt struct cmsghdr hdr; 72570af00a1SHartmut Brandt struct cmsgcred cred; 72670af00a1SHartmut Brandt }; 72770af00a1SHartmut Brandt 72870af00a1SHartmut Brandt static void 72970af00a1SHartmut Brandt check_priv(struct port_input *pi, struct msghdr *msg) 73070af00a1SHartmut Brandt { 73170af00a1SHartmut Brandt struct credmsg *cmsg; 73270af00a1SHartmut Brandt struct xucred ucred; 73370af00a1SHartmut Brandt socklen_t ucredlen; 73470af00a1SHartmut Brandt 73570af00a1SHartmut Brandt pi->priv = 0; 73670af00a1SHartmut Brandt 73770af00a1SHartmut Brandt if (msg->msg_controllen == sizeof(*cmsg)) { 738165c5d31SHartmut Brandt /* process explicitly sends credentials */ 73970af00a1SHartmut Brandt 74070af00a1SHartmut Brandt cmsg = (struct credmsg *)msg->msg_control; 74170af00a1SHartmut Brandt pi->priv = (cmsg->cred.cmcred_euid == 0); 74270af00a1SHartmut Brandt return; 74370af00a1SHartmut Brandt } 74470af00a1SHartmut Brandt 74570af00a1SHartmut Brandt /* ok, obtain the accept time credentials */ 74670af00a1SHartmut Brandt ucredlen = sizeof(ucred); 74770af00a1SHartmut Brandt 74870af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 74970af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 75070af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 75170af00a1SHartmut Brandt } 75270af00a1SHartmut Brandt 75370af00a1SHartmut Brandt /* 75470af00a1SHartmut Brandt * Input from a stream socket. 75570af00a1SHartmut Brandt */ 75670af00a1SHartmut Brandt static int 75770af00a1SHartmut Brandt recv_stream(struct port_input *pi) 75870af00a1SHartmut Brandt { 75970af00a1SHartmut Brandt struct msghdr msg; 76070af00a1SHartmut Brandt struct iovec iov[1]; 76170af00a1SHartmut Brandt ssize_t len; 76270af00a1SHartmut Brandt struct credmsg cmsg; 76370af00a1SHartmut Brandt 76470af00a1SHartmut Brandt if (pi->buf == NULL) { 76570af00a1SHartmut Brandt /* no buffer yet - allocate one */ 76670af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 76770af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 76870af00a1SHartmut Brandt * the caller must close the transport. */ 76970af00a1SHartmut Brandt return (-1); 77070af00a1SHartmut Brandt } 77170af00a1SHartmut Brandt pi->buflen = buf_size(0); 77270af00a1SHartmut Brandt pi->consumed = 0; 77370af00a1SHartmut Brandt pi->length = 0; 77470af00a1SHartmut Brandt } 77570af00a1SHartmut Brandt 77670af00a1SHartmut Brandt /* try to get a message */ 77770af00a1SHartmut Brandt msg.msg_name = pi->peer; 77870af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 77970af00a1SHartmut Brandt msg.msg_iov = iov; 78070af00a1SHartmut Brandt msg.msg_iovlen = 1; 78170af00a1SHartmut Brandt if (pi->cred) { 78270af00a1SHartmut Brandt msg.msg_control = &cmsg; 78370af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 78470af00a1SHartmut Brandt 78570af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 78670af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 78770af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 78870af00a1SHartmut Brandt } else { 78970af00a1SHartmut Brandt msg.msg_control = NULL; 79070af00a1SHartmut Brandt msg.msg_controllen = 0; 79170af00a1SHartmut Brandt } 79270af00a1SHartmut Brandt msg.msg_flags = 0; 79370af00a1SHartmut Brandt 79470af00a1SHartmut Brandt iov[0].iov_base = pi->buf + pi->length; 79570af00a1SHartmut Brandt iov[0].iov_len = pi->buflen - pi->length; 79670af00a1SHartmut Brandt 79770af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 79870af00a1SHartmut Brandt 79970af00a1SHartmut Brandt if (len == -1 || len == 0) 80070af00a1SHartmut Brandt /* receive error */ 80170af00a1SHartmut Brandt return (-1); 80270af00a1SHartmut Brandt 80370af00a1SHartmut Brandt pi->length += len; 80470af00a1SHartmut Brandt 80570af00a1SHartmut Brandt if (pi->cred) 80670af00a1SHartmut Brandt check_priv(pi, &msg); 80770af00a1SHartmut Brandt 80870af00a1SHartmut Brandt return (0); 80970af00a1SHartmut Brandt } 81070af00a1SHartmut Brandt 81170af00a1SHartmut Brandt /* 81270af00a1SHartmut Brandt * Input from a datagram socket. 81370af00a1SHartmut Brandt * Each receive should return one datagram. 81470af00a1SHartmut Brandt */ 81570af00a1SHartmut Brandt static int 81670af00a1SHartmut Brandt recv_dgram(struct port_input *pi) 81770af00a1SHartmut Brandt { 81870af00a1SHartmut Brandt u_char embuf[1000]; 81970af00a1SHartmut Brandt struct msghdr msg; 82070af00a1SHartmut Brandt struct iovec iov[1]; 82170af00a1SHartmut Brandt ssize_t len; 82270af00a1SHartmut Brandt struct credmsg cmsg; 82370af00a1SHartmut Brandt 82470af00a1SHartmut Brandt if (pi->buf == NULL) { 82570af00a1SHartmut Brandt /* no buffer yet - allocate one */ 82670af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 82770af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 82870af00a1SHartmut Brandt * and drop it */ 82970af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 83070af00a1SHartmut Brandt 0, NULL, NULL); 83170af00a1SHartmut Brandt /* return error */ 83270af00a1SHartmut Brandt return (-1); 83370af00a1SHartmut Brandt } 83470af00a1SHartmut Brandt pi->buflen = buf_size(0); 83570af00a1SHartmut Brandt } 83670af00a1SHartmut Brandt 83770af00a1SHartmut Brandt /* try to get a message */ 83870af00a1SHartmut Brandt msg.msg_name = pi->peer; 83970af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 84070af00a1SHartmut Brandt msg.msg_iov = iov; 84170af00a1SHartmut Brandt msg.msg_iovlen = 1; 84270af00a1SHartmut Brandt if (pi->cred) { 84370af00a1SHartmut Brandt msg.msg_control = &cmsg; 84470af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 84570af00a1SHartmut Brandt 84670af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 84770af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 84870af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 84970af00a1SHartmut Brandt } else { 85070af00a1SHartmut Brandt msg.msg_control = NULL; 8518eecd77aSHartmut Brandt msg.msg_controllen = 0; 85270af00a1SHartmut Brandt } 85370af00a1SHartmut Brandt msg.msg_flags = 0; 85470af00a1SHartmut Brandt 85570af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 85670af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 85770af00a1SHartmut Brandt 85870af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 85970af00a1SHartmut Brandt 86070af00a1SHartmut Brandt if (len == -1 || len == 0) 86170af00a1SHartmut Brandt /* receive error */ 86270af00a1SHartmut Brandt return (-1); 86370af00a1SHartmut Brandt 86470af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 86570af00a1SHartmut Brandt /* truncated - drop */ 86670af00a1SHartmut Brandt snmpd_stats.silentDrops++; 86770af00a1SHartmut Brandt snmpd_stats.inTooLong++; 86870af00a1SHartmut Brandt return (-1); 86970af00a1SHartmut Brandt } 87070af00a1SHartmut Brandt 87170af00a1SHartmut Brandt pi->length = (size_t)len; 87270af00a1SHartmut Brandt 87370af00a1SHartmut Brandt if (pi->cred) 87470af00a1SHartmut Brandt check_priv(pi, &msg); 87570af00a1SHartmut Brandt 87670af00a1SHartmut Brandt return (0); 87770af00a1SHartmut Brandt } 87870af00a1SHartmut Brandt 87970af00a1SHartmut Brandt /* 88070af00a1SHartmut Brandt * Input from a socket 88170af00a1SHartmut Brandt */ 88270af00a1SHartmut Brandt int 88370af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 88470af00a1SHartmut Brandt { 885f06ca4afSHartmut Brandt u_char *sndbuf; 886f06ca4afSHartmut Brandt size_t sndlen; 88770af00a1SHartmut Brandt struct snmp_pdu pdu; 888f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 889f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 890f06ca4afSHartmut Brandt int32_t vi; 89170af00a1SHartmut Brandt int ret; 89270af00a1SHartmut Brandt ssize_t slen; 893d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 894d7eb6b47SHartmut Brandt char client[16]; 895d7eb6b47SHartmut Brandt #endif 896f06ca4afSHartmut Brandt 89770af00a1SHartmut Brandt /* get input depending on the transport */ 89870af00a1SHartmut Brandt if (pi->stream) { 89970af00a1SHartmut Brandt ret = recv_stream(pi); 90070af00a1SHartmut Brandt } else { 90170af00a1SHartmut Brandt ret = recv_dgram(pi); 902f06ca4afSHartmut Brandt } 90370af00a1SHartmut Brandt 90470af00a1SHartmut Brandt if (ret == -1) 90570af00a1SHartmut Brandt return (-1); 906f06ca4afSHartmut Brandt 907d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 908d7eb6b47SHartmut Brandt /* 909d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 910d7eb6b47SHartmut Brandt */ 911d7eb6b47SHartmut Brandt if (inet_ntop(pi->peer->sa_family, 91269292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 91369292cedSHartmut Brandt client, sizeof(client)) != NULL) { 914d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 915d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 916d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 917d7eb6b47SHartmut Brandt eval_client(&req)); 918d7eb6b47SHartmut Brandt return (-1); 919d7eb6b47SHartmut Brandt } 920d7eb6b47SHartmut Brandt } else 921d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 922d7eb6b47SHartmut Brandt #endif 923d7eb6b47SHartmut Brandt 924f06ca4afSHartmut Brandt /* 925f06ca4afSHartmut Brandt * Handle input 926f06ca4afSHartmut Brandt */ 92770af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 92870af00a1SHartmut Brandt &pi->consumed); 92970af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 93070af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 93170af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 93270af00a1SHartmut Brandt if (pi->stream) { 93370af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 93470af00a1SHartmut Brandt snmpd_stats.silentDrops++; 93570af00a1SHartmut Brandt return (-1); 93670af00a1SHartmut Brandt } 93770af00a1SHartmut Brandt return (0); 93870af00a1SHartmut Brandt } 93970af00a1SHartmut Brandt snmpd_stats.silentDrops++; 94070af00a1SHartmut Brandt return (-1); 94170af00a1SHartmut Brandt } 942f06ca4afSHartmut Brandt 943f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 944f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 945f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 946f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 94770af00a1SHartmut Brandt /* for streaming transports this is fatal */ 94870af00a1SHartmut Brandt if (pi->stream) 94970af00a1SHartmut Brandt return (-1); 95070af00a1SHartmut Brandt snmp_input_consume(pi); 95170af00a1SHartmut Brandt return (0); 952f06ca4afSHartmut Brandt } 953896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 954896052c1SHartmut Brandt snmp_input_consume(pi); 955896052c1SHartmut Brandt return (0); 956896052c1SHartmut Brandt } 957f06ca4afSHartmut Brandt 958f06ca4afSHartmut Brandt /* 959f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 960f06ca4afSHartmut Brandt * the hand it over to the module. 961f06ca4afSHartmut Brandt */ 962f06ca4afSHartmut Brandt if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 96370af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 964896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 965896052c1SHartmut Brandt !pi->cred || pi->priv); 966f06ca4afSHartmut Brandt 967f06ca4afSHartmut Brandt switch (perr) { 968f06ca4afSHartmut Brandt 969f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 97070af00a1SHartmut Brandt snmp_input_consume(pi); 97170af00a1SHartmut Brandt return (0); 972f06ca4afSHartmut Brandt 973f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 974f06ca4afSHartmut Brandt break; 975f06ca4afSHartmut Brandt 976f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 97770af00a1SHartmut Brandt snmp_input_consume(pi); 978f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 979f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 98070af00a1SHartmut Brandt return (0); 981f06ca4afSHartmut Brandt 982f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 98370af00a1SHartmut Brandt snmp_input_consume(pi); 984f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 985f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 986f06ca4afSHartmut Brandt if (snmpd.auth_traps) 987f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 988896052c1SHartmut Brandt (struct snmp_value *)NULL); 98970af00a1SHartmut Brandt return (0); 990f06ca4afSHartmut Brandt 991f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 99270af00a1SHartmut Brandt snmp_input_consume(pi); 993f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 994f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 995f06ca4afSHartmut Brandt if (snmpd.auth_traps) 996f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 997896052c1SHartmut Brandt (struct snmp_value *)NULL); 99870af00a1SHartmut Brandt return (0); 999f06ca4afSHartmut Brandt } 1000f06ca4afSHartmut Brandt } 1001f06ca4afSHartmut Brandt 1002f06ca4afSHartmut Brandt /* 1003f06ca4afSHartmut Brandt * Check type 1004f06ca4afSHartmut Brandt */ 1005f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1006f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1007f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1008f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1009f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1010f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 101170af00a1SHartmut Brandt snmp_input_consume(pi); 101270af00a1SHartmut Brandt return (0); 1013f06ca4afSHartmut Brandt } 1014f06ca4afSHartmut Brandt 1015f06ca4afSHartmut Brandt /* 1016f06ca4afSHartmut Brandt * Check community 1017f06ca4afSHartmut Brandt */ 101870af00a1SHartmut Brandt if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 101970af00a1SHartmut Brandt (community != COMM_WRITE && 102070af00a1SHartmut Brandt (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 1021f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1022f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 102370af00a1SHartmut Brandt snmp_input_consume(pi); 1024f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1025896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1026896052c1SHartmut Brandt (struct snmp_value *)NULL); 102770af00a1SHartmut Brandt return (0); 1028f06ca4afSHartmut Brandt } 1029f06ca4afSHartmut Brandt 1030f06ca4afSHartmut Brandt /* 1031f06ca4afSHartmut Brandt * Execute it. 1032f06ca4afSHartmut Brandt */ 1033f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1034f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1035f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 103670af00a1SHartmut Brandt snmp_input_consume(pi); 103770af00a1SHartmut Brandt return (0); 1038f06ca4afSHartmut Brandt } 103970af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 104070af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1041f06ca4afSHartmut Brandt 1042f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 104370af00a1SHartmut Brandt slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 104470af00a1SHartmut Brandt if (slen == -1) 104570af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 104670af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 104770af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 104870af00a1SHartmut Brandt sndlen, (size_t)slen); 104970af00a1SHartmut Brandt } 105070af00a1SHartmut Brandt snmp_pdu_free(&pdu); 105170af00a1SHartmut Brandt free(sndbuf); 105270af00a1SHartmut Brandt snmp_input_consume(pi); 105370af00a1SHartmut Brandt 105470af00a1SHartmut Brandt return (0); 105570af00a1SHartmut Brandt } 105670af00a1SHartmut Brandt 105770af00a1SHartmut Brandt /* 105870af00a1SHartmut Brandt * Send a PDU to a given port 105970af00a1SHartmut Brandt */ 106070af00a1SHartmut Brandt void 106170af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 106270af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 106370af00a1SHartmut Brandt { 106470af00a1SHartmut Brandt struct transport *trans = targ; 106570af00a1SHartmut Brandt struct tport *tp; 106670af00a1SHartmut Brandt u_char *sndbuf; 106770af00a1SHartmut Brandt size_t sndlen; 106870af00a1SHartmut Brandt ssize_t len; 106970af00a1SHartmut Brandt 107070af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 107170af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 107270af00a1SHartmut Brandt break; 107370af00a1SHartmut Brandt if (tp == 0) 107470af00a1SHartmut Brandt return; 107570af00a1SHartmut Brandt 107670af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 107770af00a1SHartmut Brandt return; 107870af00a1SHartmut Brandt 107970af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 108070af00a1SHartmut Brandt 108170af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 108270af00a1SHartmut Brandt 108370af00a1SHartmut Brandt if (len == -1) 1084f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1085f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1086f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1087f06ca4afSHartmut Brandt sndlen, (size_t)len); 108870af00a1SHartmut Brandt 1089f06ca4afSHartmut Brandt free(sndbuf); 1090f06ca4afSHartmut Brandt } 1091f06ca4afSHartmut Brandt 1092f06ca4afSHartmut Brandt 1093f06ca4afSHartmut Brandt /* 109470af00a1SHartmut Brandt * Close an input source 1095f06ca4afSHartmut Brandt */ 1096f06ca4afSHartmut Brandt void 109770af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1098f06ca4afSHartmut Brandt { 109970af00a1SHartmut Brandt if (pi->id != NULL) 110070af00a1SHartmut Brandt fd_deselect(pi->id); 110170af00a1SHartmut Brandt if (pi->fd >= 0) 110270af00a1SHartmut Brandt (void)close(pi->fd); 110370af00a1SHartmut Brandt if (pi->buf != NULL) 110470af00a1SHartmut Brandt free(pi->buf); 1105f06ca4afSHartmut Brandt } 1106f06ca4afSHartmut Brandt 1107f06ca4afSHartmut Brandt /* 1108f06ca4afSHartmut Brandt * Dump internal state. 1109f06ca4afSHartmut Brandt */ 111070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 111170af00a1SHartmut Brandt static void 111270af00a1SHartmut Brandt info_func(void) 111370af00a1SHartmut Brandt #else 1114f06ca4afSHartmut Brandt static void 1115f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 111670af00a1SHartmut Brandt #endif 1117f06ca4afSHartmut Brandt { 1118f06ca4afSHartmut Brandt struct lmodule *m; 1119f06ca4afSHartmut Brandt u_int i; 1120f06ca4afSHartmut Brandt char buf[10000]; 1121f06ca4afSHartmut Brandt 1122f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1123f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1124f06ca4afSHartmut Brandt switch (tree[i].type) { 1125f06ca4afSHartmut Brandt 1126f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1127f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1128f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1129f06ca4afSHartmut Brandt break; 1130f06ca4afSHartmut Brandt 1131f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1132f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1133f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1134f06ca4afSHartmut Brandt break; 1135f06ca4afSHartmut Brandt } 1136f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1137f06ca4afSHartmut Brandt } 1138f06ca4afSHartmut Brandt 1139f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1140f06ca4afSHartmut Brandt if (m->config->dump) 1141f06ca4afSHartmut Brandt (*m->config->dump)(); 1142f06ca4afSHartmut Brandt } 1143f06ca4afSHartmut Brandt 1144f06ca4afSHartmut Brandt /* 1145f06ca4afSHartmut Brandt * Re-read configuration 1146f06ca4afSHartmut Brandt */ 114770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 114870af00a1SHartmut Brandt static void 114970af00a1SHartmut Brandt config_func(void) 115070af00a1SHartmut Brandt #else 1151f06ca4afSHartmut Brandt static void 1152f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1153f06ca4afSHartmut Brandt const void *tag __unused) 115470af00a1SHartmut Brandt #endif 1155f06ca4afSHartmut Brandt { 1156f06ca4afSHartmut Brandt struct lmodule *m; 1157f06ca4afSHartmut Brandt 1158f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1159f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1160f06ca4afSHartmut Brandt return; 1161f06ca4afSHartmut Brandt } 1162f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1163f06ca4afSHartmut Brandt if (m->config->config) 1164f06ca4afSHartmut Brandt (*m->config->config)(); 1165f06ca4afSHartmut Brandt } 1166f06ca4afSHartmut Brandt 1167f06ca4afSHartmut Brandt /* 1168f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1169f06ca4afSHartmut Brandt */ 1170f06ca4afSHartmut Brandt static void 1171f06ca4afSHartmut Brandt onusr1(int s __unused) 1172f06ca4afSHartmut Brandt { 117370af00a1SHartmut Brandt 1174f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1175f06ca4afSHartmut Brandt } 1176f06ca4afSHartmut Brandt static void 1177f06ca4afSHartmut Brandt onhup(int s __unused) 1178f06ca4afSHartmut Brandt { 117970af00a1SHartmut Brandt 1180f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1181f06ca4afSHartmut Brandt } 1182f06ca4afSHartmut Brandt 1183f06ca4afSHartmut Brandt static void 1184f06ca4afSHartmut Brandt onterm(int s __unused) 1185f06ca4afSHartmut Brandt { 1186f06ca4afSHartmut Brandt 118770af00a1SHartmut Brandt /* allow clean-up */ 1188f06ca4afSHartmut Brandt exit(0); 1189f06ca4afSHartmut Brandt } 1190f06ca4afSHartmut Brandt 1191f06ca4afSHartmut Brandt static void 1192f06ca4afSHartmut Brandt init_sigs(void) 1193f06ca4afSHartmut Brandt { 1194f06ca4afSHartmut Brandt struct sigaction sa; 1195f06ca4afSHartmut Brandt 1196f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1197f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1198f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1199f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1200f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1201f06ca4afSHartmut Brandt exit(1); 1202f06ca4afSHartmut Brandt } 1203f06ca4afSHartmut Brandt 1204f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1205f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1206f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1207f06ca4afSHartmut Brandt exit(1); 1208f06ca4afSHartmut Brandt } 1209f06ca4afSHartmut Brandt 1210f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1211f06ca4afSHartmut Brandt sa.sa_flags = 0; 1212f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1213f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1214f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1215f06ca4afSHartmut Brandt exit(1); 1216f06ca4afSHartmut Brandt } 1217f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1218f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1219f06ca4afSHartmut Brandt exit(1); 1220f06ca4afSHartmut Brandt } 1221f06ca4afSHartmut Brandt } 1222f06ca4afSHartmut Brandt 1223f06ca4afSHartmut Brandt static void 1224f06ca4afSHartmut Brandt block_sigs(void) 1225f06ca4afSHartmut Brandt { 1226f06ca4afSHartmut Brandt sigset_t set; 1227f06ca4afSHartmut Brandt 1228f06ca4afSHartmut Brandt sigfillset(&set); 1229f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1230f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1231f06ca4afSHartmut Brandt exit(1); 1232f06ca4afSHartmut Brandt } 1233f06ca4afSHartmut Brandt } 1234f06ca4afSHartmut Brandt static void 1235f06ca4afSHartmut Brandt unblock_sigs(void) 1236f06ca4afSHartmut Brandt { 1237f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1238f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1239f06ca4afSHartmut Brandt exit(1); 1240f06ca4afSHartmut Brandt } 1241f06ca4afSHartmut Brandt } 1242f06ca4afSHartmut Brandt 1243f06ca4afSHartmut Brandt /* 1244f06ca4afSHartmut Brandt * Shut down 1245f06ca4afSHartmut Brandt */ 1246f06ca4afSHartmut Brandt static void 1247f06ca4afSHartmut Brandt term(void) 1248f06ca4afSHartmut Brandt { 1249f06ca4afSHartmut Brandt (void)unlink(pid_file); 1250f06ca4afSHartmut Brandt } 1251f06ca4afSHartmut Brandt 125270af00a1SHartmut Brandt static void 125370af00a1SHartmut Brandt trans_stop(void) 125470af00a1SHartmut Brandt { 125570af00a1SHartmut Brandt struct transport *t; 125670af00a1SHartmut Brandt 125770af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 125870af00a1SHartmut Brandt (void)t->vtab->stop(1); 125970af00a1SHartmut Brandt } 126070af00a1SHartmut Brandt 1261f06ca4afSHartmut Brandt /* 1262f06ca4afSHartmut Brandt * Define a macro from the command line 1263f06ca4afSHartmut Brandt */ 1264f06ca4afSHartmut Brandt static void 1265f06ca4afSHartmut Brandt do_macro(char *arg) 1266f06ca4afSHartmut Brandt { 1267f06ca4afSHartmut Brandt char *eq; 1268f06ca4afSHartmut Brandt int err; 1269f06ca4afSHartmut Brandt 1270f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1271f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1272f06ca4afSHartmut Brandt else { 1273f06ca4afSHartmut Brandt *eq++ = '\0'; 1274f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1275f06ca4afSHartmut Brandt } 1276f06ca4afSHartmut Brandt if (err == -1) { 1277f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1278f06ca4afSHartmut Brandt exit(1); 1279f06ca4afSHartmut Brandt } 1280f06ca4afSHartmut Brandt } 1281f06ca4afSHartmut Brandt 1282f06ca4afSHartmut Brandt /* 1283f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1284f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1285f06ca4afSHartmut Brandt */ 1286f06ca4afSHartmut Brandt static int 1287f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1288f06ca4afSHartmut Brandt { 1289f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1290f06ca4afSHartmut Brandt u_int i; 1291f06ca4afSHartmut Brandt char *ptr; 1292f06ca4afSHartmut Brandt 1293f06ca4afSHartmut Brandt *optp = NULL; 1294f06ca4afSHartmut Brandt 1295f06ca4afSHartmut Brandt /* skip leading junk */ 1296f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1297f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1298f06ca4afSHartmut Brandt break; 1299f06ca4afSHartmut Brandt if (*ptr == '\0') { 1300f06ca4afSHartmut Brandt *arg = ptr; 1301f06ca4afSHartmut Brandt return (-1); 1302f06ca4afSHartmut Brandt } 1303f06ca4afSHartmut Brandt *optp = ptr; 1304f06ca4afSHartmut Brandt 1305f06ca4afSHartmut Brandt /* find the end of the option */ 1306f06ca4afSHartmut Brandt while (*++ptr != '\0') 1307f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1308f06ca4afSHartmut Brandt break; 1309f06ca4afSHartmut Brandt 1310f06ca4afSHartmut Brandt if (*ptr != '\0') { 1311f06ca4afSHartmut Brandt if (*ptr == '=') { 1312f06ca4afSHartmut Brandt *ptr++ = '\0'; 1313f06ca4afSHartmut Brandt *valp = ptr; 1314f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1315f06ca4afSHartmut Brandt ptr++; 1316f06ca4afSHartmut Brandt if (*ptr != '\0') 1317f06ca4afSHartmut Brandt *ptr++ = '\0'; 1318f06ca4afSHartmut Brandt } else 1319f06ca4afSHartmut Brandt *ptr++ = '\0'; 1320f06ca4afSHartmut Brandt } 1321f06ca4afSHartmut Brandt 1322f06ca4afSHartmut Brandt *arg = ptr; 1323f06ca4afSHartmut Brandt 1324f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 132570af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1326f06ca4afSHartmut Brandt return (i); 1327f06ca4afSHartmut Brandt return (-1); 1328f06ca4afSHartmut Brandt } 1329f06ca4afSHartmut Brandt 1330f06ca4afSHartmut Brandt int 1331f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1332f06ca4afSHartmut Brandt { 1333f06ca4afSHartmut Brandt int opt; 1334f06ca4afSHartmut Brandt FILE *fp; 1335f06ca4afSHartmut Brandt int background = 1; 133670af00a1SHartmut Brandt struct tport *p; 1337f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1338f06ca4afSHartmut Brandt struct lmodule *m; 1339f06ca4afSHartmut Brandt char *value, *option; 134070af00a1SHartmut Brandt struct transport *t; 1341f06ca4afSHartmut Brandt 1342f06ca4afSHartmut Brandt #define DBG_DUMP 0 1343f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1344f06ca4afSHartmut Brandt #define DBG_TRACE 2 1345f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1346f06ca4afSHartmut Brandt "dump", 1347f06ca4afSHartmut Brandt "events", 1348f06ca4afSHartmut Brandt "trace", 1349f06ca4afSHartmut Brandt NULL 1350f06ca4afSHartmut Brandt }; 1351f06ca4afSHartmut Brandt 1352f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1353f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1354f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1355f06ca4afSHartmut Brandt asn_error = asn_error_func; 1356f06ca4afSHartmut Brandt 1357f06ca4afSHartmut Brandt while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1358f06ca4afSHartmut Brandt switch (opt) { 1359f06ca4afSHartmut Brandt 1360f06ca4afSHartmut Brandt case 'c': 1361f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1362f06ca4afSHartmut Brandt break; 1363f06ca4afSHartmut Brandt 1364f06ca4afSHartmut Brandt case 'd': 1365f06ca4afSHartmut Brandt background = 0; 1366f06ca4afSHartmut Brandt break; 1367f06ca4afSHartmut Brandt 1368f06ca4afSHartmut Brandt case 'D': 1369f06ca4afSHartmut Brandt while (*optarg) { 1370f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1371f06ca4afSHartmut Brandt &value, &option)) { 1372f06ca4afSHartmut Brandt 1373f06ca4afSHartmut Brandt case DBG_DUMP: 1374f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1375f06ca4afSHartmut Brandt break; 1376f06ca4afSHartmut Brandt 1377f06ca4afSHartmut Brandt case DBG_EVENTS: 1378f06ca4afSHartmut Brandt debug.evdebug++; 1379f06ca4afSHartmut Brandt break; 1380f06ca4afSHartmut Brandt 1381f06ca4afSHartmut Brandt case DBG_TRACE: 1382f06ca4afSHartmut Brandt if (value == NULL) 1383f06ca4afSHartmut Brandt syslog(LOG_ERR, 1384f06ca4afSHartmut Brandt "no value for 'trace'"); 1385f06ca4afSHartmut Brandt snmp_trace = strtoul(value, NULL, 0); 1386f06ca4afSHartmut Brandt break; 1387f06ca4afSHartmut Brandt 1388f06ca4afSHartmut Brandt case -1: 1389f06ca4afSHartmut Brandt if (suboptarg) 1390f06ca4afSHartmut Brandt syslog(LOG_ERR, 1391f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1392f06ca4afSHartmut Brandt option); 1393f06ca4afSHartmut Brandt else 1394f06ca4afSHartmut Brandt syslog(LOG_ERR, 1395f06ca4afSHartmut Brandt "missing debug flag"); 1396f06ca4afSHartmut Brandt break; 1397f06ca4afSHartmut Brandt } 1398f06ca4afSHartmut Brandt } 1399f06ca4afSHartmut Brandt break; 1400f06ca4afSHartmut Brandt 1401f06ca4afSHartmut Brandt case 'h': 1402f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1403f06ca4afSHartmut Brandt exit(0); 1404f06ca4afSHartmut Brandt 1405f06ca4afSHartmut Brandt case 'I': 1406f06ca4afSHartmut Brandt syspath = optarg; 1407f06ca4afSHartmut Brandt break; 1408f06ca4afSHartmut Brandt 1409f06ca4afSHartmut Brandt case 'l': 1410f06ca4afSHartmut Brandt prefix = optarg; 1411f06ca4afSHartmut Brandt break; 1412f06ca4afSHartmut Brandt 1413f06ca4afSHartmut Brandt case 'm': 1414f06ca4afSHartmut Brandt do_macro(optarg); 1415f06ca4afSHartmut Brandt break; 1416f06ca4afSHartmut Brandt 1417f06ca4afSHartmut Brandt case 'p': 1418f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1419f06ca4afSHartmut Brandt break; 1420f06ca4afSHartmut Brandt } 1421f06ca4afSHartmut Brandt 1422f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1423f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1424f06ca4afSHartmut Brandt 1425f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1426f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1427f06ca4afSHartmut Brandt exit(1); 1428f06ca4afSHartmut Brandt } 1429f06ca4afSHartmut Brandt 1430f06ca4afSHartmut Brandt argc -= optind; 1431f06ca4afSHartmut Brandt argv += optind; 1432f06ca4afSHartmut Brandt 1433f06ca4afSHartmut Brandt progargs = argv; 1434f06ca4afSHartmut Brandt nprogargs = argc; 1435f06ca4afSHartmut Brandt 1436f06ca4afSHartmut Brandt srandomdev(); 1437f06ca4afSHartmut Brandt 1438f06ca4afSHartmut Brandt snmp_serial_no = random(); 1439f06ca4afSHartmut Brandt 1440d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1441d7eb6b47SHartmut Brandt /* 1442d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1443d7eb6b47SHartmut Brandt */ 1444d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1445d7eb6b47SHartmut Brandt sock_methods(&req); 1446d7eb6b47SHartmut Brandt #endif 1447d7eb6b47SHartmut Brandt 1448f06ca4afSHartmut Brandt /* 1449f06ca4afSHartmut Brandt * Initialize the tree. 1450f06ca4afSHartmut Brandt */ 1451f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1452f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1453f06ca4afSHartmut Brandt exit(1); 1454f06ca4afSHartmut Brandt } 1455f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1456f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1457f06ca4afSHartmut Brandt 1458f06ca4afSHartmut Brandt /* 1459f06ca4afSHartmut Brandt * Get standard communities 1460f06ca4afSHartmut Brandt */ 1461f06ca4afSHartmut Brandt (void)comm_define(1, "SNMP read", NULL, "public"); 1462f06ca4afSHartmut Brandt (void)comm_define(2, "SNMP write", NULL, "public"); 1463f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1464f06ca4afSHartmut Brandt 1465f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1466f06ca4afSHartmut Brandt 1467f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1468f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1469f06ca4afSHartmut Brandt 1470f06ca4afSHartmut Brandt init_actvals(); 147170af00a1SHartmut Brandt 147270af00a1SHartmut Brandt this_tick = get_ticks(); 147369292cedSHartmut Brandt start_tick = this_tick; 147470af00a1SHartmut Brandt 147570af00a1SHartmut Brandt /* start transports */ 147670af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 147770af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 147870af00a1SHartmut Brandt exit(1); 147970af00a1SHartmut Brandt } 148070af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 148170af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 148270af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 148370af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 148470af00a1SHartmut Brandt 148570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 148670af00a1SHartmut Brandt if (debug.evdebug > 0) 148770af00a1SHartmut Brandt rpoll_trace = 1; 148870af00a1SHartmut Brandt #else 1489f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1490f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1491f06ca4afSHartmut Brandt exit(1); 1492f06ca4afSHartmut Brandt } 1493f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1494f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 149570af00a1SHartmut Brandt #endif 1496f06ca4afSHartmut Brandt 1497896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1498896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1499896052c1SHartmut Brandt exit(1); 1500896052c1SHartmut Brandt } 1501896052c1SHartmut Brandt 150270af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 150370af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 150470af00a1SHartmut Brandt t->vtab->init_port(p); 1505f06ca4afSHartmut Brandt 1506f06ca4afSHartmut Brandt init_sigs(); 1507f06ca4afSHartmut Brandt 1508f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1509f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1510f06ca4afSHartmut Brandt 1511f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1512f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1513f06ca4afSHartmut Brandt fclose(fp); 151470af00a1SHartmut Brandt if (atexit(term) == -1) { 151570af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 151670af00a1SHartmut Brandt (void)remove(pid_file); 151770af00a1SHartmut Brandt exit(0); 1518f06ca4afSHartmut Brandt } 151970af00a1SHartmut Brandt } 1520f06ca4afSHartmut Brandt 1521f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1522f06ca4afSHartmut Brandt NULL) == 0) { 1523f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1524f06ca4afSHartmut Brandt exit(1); 1525f06ca4afSHartmut Brandt } 1526f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1527f06ca4afSHartmut Brandt NULL) == 0) { 1528f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1529f06ca4afSHartmut Brandt exit(1); 1530f06ca4afSHartmut Brandt } 1531f06ca4afSHartmut Brandt 1532896052c1SHartmut Brandt snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1533f06ca4afSHartmut Brandt 1534f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1535f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1536f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1537f06ca4afSHartmut Brandt lm_start(m); 1538f06ca4afSHartmut Brandt } 1539f06ca4afSHartmut Brandt 1540f06ca4afSHartmut Brandt for (;;) { 154170af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1542f06ca4afSHartmut Brandt evEvent event; 154370af00a1SHartmut Brandt #endif 1544f06ca4afSHartmut Brandt struct lmodule *mod; 1545f06ca4afSHartmut Brandt 1546f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1547f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1548f06ca4afSHartmut Brandt (*mod->config->idle)(); 1549f06ca4afSHartmut Brandt 155070af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1551f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1552f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1553f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1554f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1555f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1556f06ca4afSHartmut Brandt exit(1); 1557f06ca4afSHartmut Brandt } 155870af00a1SHartmut Brandt #else 155970af00a1SHartmut Brandt poll_dispatch(1); 156070af00a1SHartmut Brandt #endif 1561f06ca4afSHartmut Brandt 1562f06ca4afSHartmut Brandt if (work != 0) { 1563f06ca4afSHartmut Brandt block_sigs(); 1564f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 156570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 156670af00a1SHartmut Brandt info_func(); 156770af00a1SHartmut Brandt #else 1568f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1569f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1570f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1571f06ca4afSHartmut Brandt exit(1); 1572f06ca4afSHartmut Brandt } 157370af00a1SHartmut Brandt #endif 1574f06ca4afSHartmut Brandt } 1575f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 157670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 157770af00a1SHartmut Brandt config_func(); 157870af00a1SHartmut Brandt #else 1579f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1580f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1581f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1582f06ca4afSHartmut Brandt exit(1); 1583f06ca4afSHartmut Brandt } 158470af00a1SHartmut Brandt #endif 1585f06ca4afSHartmut Brandt } 1586f06ca4afSHartmut Brandt work = 0; 1587f06ca4afSHartmut Brandt unblock_sigs(); 158870af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1589f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1590f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1591f06ca4afSHartmut Brandt exit(1); 1592f06ca4afSHartmut Brandt } 159370af00a1SHartmut Brandt #endif 1594f06ca4afSHartmut Brandt } 1595f06ca4afSHartmut Brandt } 1596f06ca4afSHartmut Brandt 1597f06ca4afSHartmut Brandt return (0); 1598f06ca4afSHartmut Brandt } 1599f06ca4afSHartmut Brandt 160069292cedSHartmut Brandt uint64_t 1601f06ca4afSHartmut Brandt get_ticks() 1602f06ca4afSHartmut Brandt { 1603f06ca4afSHartmut Brandt struct timeval tv; 160469292cedSHartmut Brandt uint64_t ret; 1605f06ca4afSHartmut Brandt 1606f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1607f06ca4afSHartmut Brandt abort(); 160869292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1609f06ca4afSHartmut Brandt return (ret); 1610f06ca4afSHartmut Brandt } 161169292cedSHartmut Brandt 1612f06ca4afSHartmut Brandt /* 1613f06ca4afSHartmut Brandt * Timer support 1614f06ca4afSHartmut Brandt */ 1615165c5d31SHartmut Brandt 1616165c5d31SHartmut Brandt /* 1617165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1618165c5d31SHartmut Brandt */ 161970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 162070af00a1SHartmut Brandt static void 162170af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 162270af00a1SHartmut Brandt #else 1623f06ca4afSHartmut Brandt static void 1624f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1625f06ca4afSHartmut Brandt struct timespec inter __unused) 162670af00a1SHartmut Brandt #endif 1627f06ca4afSHartmut Brandt { 1628f06ca4afSHartmut Brandt struct timer *tp = uap; 1629f06ca4afSHartmut Brandt 1630f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1631f06ca4afSHartmut Brandt tp->func(tp->udata); 1632f06ca4afSHartmut Brandt free(tp); 1633f06ca4afSHartmut Brandt } 1634f06ca4afSHartmut Brandt 1635f06ca4afSHartmut Brandt /* 1636165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1637165c5d31SHartmut Brandt */ 1638165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1639165c5d31SHartmut Brandt static void 1640165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1641165c5d31SHartmut Brandt #else 1642165c5d31SHartmut Brandt static void 1643165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1644165c5d31SHartmut Brandt struct timespec inter __unused) 1645165c5d31SHartmut Brandt #endif 1646165c5d31SHartmut Brandt { 1647165c5d31SHartmut Brandt struct timer *tp = uap; 1648165c5d31SHartmut Brandt 1649165c5d31SHartmut Brandt tp->func(tp->udata); 1650165c5d31SHartmut Brandt } 1651165c5d31SHartmut Brandt 1652165c5d31SHartmut Brandt /* 1653165c5d31SHartmut Brandt * Start a one-shot timer 1654f06ca4afSHartmut Brandt */ 1655f06ca4afSHartmut Brandt void * 1656f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1657f06ca4afSHartmut Brandt { 1658f06ca4afSHartmut Brandt struct timer *tp; 1659a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1660f06ca4afSHartmut Brandt struct timespec due; 166170af00a1SHartmut Brandt #endif 1662f06ca4afSHartmut Brandt 1663f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1664f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1665f06ca4afSHartmut Brandt exit(1); 1666f06ca4afSHartmut Brandt } 1667a9bfedb7SHartmut Brandt 1668a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1669f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1670f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 167170af00a1SHartmut Brandt #endif 1672f06ca4afSHartmut Brandt 1673f06ca4afSHartmut Brandt tp->udata = udata; 1674f06ca4afSHartmut Brandt tp->owner = mod; 1675f06ca4afSHartmut Brandt tp->func = func; 1676f06ca4afSHartmut Brandt 1677f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1678f06ca4afSHartmut Brandt 167970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 1680a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 168170af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 168270af00a1SHartmut Brandt exit(1); 168370af00a1SHartmut Brandt } 168470af00a1SHartmut Brandt #else 1685f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1686f06ca4afSHartmut Brandt == -1) { 1687f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1688f06ca4afSHartmut Brandt exit(1); 1689f06ca4afSHartmut Brandt } 169070af00a1SHartmut Brandt #endif 1691f06ca4afSHartmut Brandt return (tp); 1692f06ca4afSHartmut Brandt } 1693f06ca4afSHartmut Brandt 1694165c5d31SHartmut Brandt /* 1695165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 1696165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 1697165c5d31SHartmut Brandt * repeat number of ticks. 1698165c5d31SHartmut Brandt */ 1699165c5d31SHartmut Brandt void * 1700165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 1701165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 1702165c5d31SHartmut Brandt { 1703165c5d31SHartmut Brandt struct timer *tp; 1704165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1705165c5d31SHartmut Brandt struct timespec due; 1706165c5d31SHartmut Brandt struct timespec inter; 1707165c5d31SHartmut Brandt #endif 1708165c5d31SHartmut Brandt 1709165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1710165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1711165c5d31SHartmut Brandt exit(1); 1712165c5d31SHartmut Brandt } 1713165c5d31SHartmut Brandt 1714165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1715165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 1716165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 1717165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 1718165c5d31SHartmut Brandt #endif 1719165c5d31SHartmut Brandt 1720165c5d31SHartmut Brandt tp->udata = udata; 1721165c5d31SHartmut Brandt tp->owner = mod; 1722165c5d31SHartmut Brandt tp->func = func; 1723165c5d31SHartmut Brandt 1724165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1725165c5d31SHartmut Brandt 1726165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1727165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 1728165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1729165c5d31SHartmut Brandt exit(1); 1730165c5d31SHartmut Brandt } 1731165c5d31SHartmut Brandt #else 1732165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 1733165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1734165c5d31SHartmut Brandt exit(1); 1735165c5d31SHartmut Brandt } 1736165c5d31SHartmut Brandt #endif 1737165c5d31SHartmut Brandt return (tp); 1738165c5d31SHartmut Brandt } 1739165c5d31SHartmut Brandt 1740165c5d31SHartmut Brandt /* 1741165c5d31SHartmut Brandt * Stop a timer. 1742165c5d31SHartmut Brandt */ 1743f06ca4afSHartmut Brandt void 1744f06ca4afSHartmut Brandt timer_stop(void *p) 1745f06ca4afSHartmut Brandt { 1746f06ca4afSHartmut Brandt struct timer *tp = p; 1747f06ca4afSHartmut Brandt 1748f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 174970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 175070af00a1SHartmut Brandt poll_stop_timer(tp->id); 175170af00a1SHartmut Brandt #else 1752f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 1753f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 1754f06ca4afSHartmut Brandt exit(1); 1755f06ca4afSHartmut Brandt } 175670af00a1SHartmut Brandt #endif 1757f06ca4afSHartmut Brandt free(p); 1758f06ca4afSHartmut Brandt } 1759f06ca4afSHartmut Brandt 1760f06ca4afSHartmut Brandt static void 1761f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 1762f06ca4afSHartmut Brandt { 1763f06ca4afSHartmut Brandt struct timer *t, *t1; 1764f06ca4afSHartmut Brandt 1765f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 1766f06ca4afSHartmut Brandt while (t != NULL) { 1767f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1768f06ca4afSHartmut Brandt if (t->owner == mod) 1769f06ca4afSHartmut Brandt timer_stop(t); 1770f06ca4afSHartmut Brandt t = t1; 1771f06ca4afSHartmut Brandt } 1772f06ca4afSHartmut Brandt } 1773f06ca4afSHartmut Brandt 1774f06ca4afSHartmut Brandt static void 1775f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1776f06ca4afSHartmut Brandt { 1777f06ca4afSHartmut Brandt va_list ap; 1778f06ca4afSHartmut Brandt static char *pend = NULL; 1779f06ca4afSHartmut Brandt char *ret, *new; 1780f06ca4afSHartmut Brandt 1781f06ca4afSHartmut Brandt va_start(ap, fmt); 1782f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 1783f06ca4afSHartmut Brandt va_end(ap); 1784f06ca4afSHartmut Brandt 1785f06ca4afSHartmut Brandt if (ret == NULL) 1786f06ca4afSHartmut Brandt return; 1787f06ca4afSHartmut Brandt if (pend != NULL) { 1788f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1789f06ca4afSHartmut Brandt == NULL) { 1790f06ca4afSHartmut Brandt free(ret); 1791f06ca4afSHartmut Brandt return; 1792f06ca4afSHartmut Brandt } 1793f06ca4afSHartmut Brandt pend = new; 1794f06ca4afSHartmut Brandt strcat(pend, ret); 1795f06ca4afSHartmut Brandt free(ret); 1796f06ca4afSHartmut Brandt } else 1797f06ca4afSHartmut Brandt pend = ret; 1798f06ca4afSHartmut Brandt 1799f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 1800f06ca4afSHartmut Brandt *ret = '\0'; 1801f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 1802f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 1803f06ca4afSHartmut Brandt free(pend); 1804f06ca4afSHartmut Brandt pend = NULL; 1805f06ca4afSHartmut Brandt break; 1806f06ca4afSHartmut Brandt } 1807f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 1808f06ca4afSHartmut Brandt } 1809f06ca4afSHartmut Brandt } 1810f06ca4afSHartmut Brandt 1811f06ca4afSHartmut Brandt static void 1812f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 1813f06ca4afSHartmut Brandt { 1814f06ca4afSHartmut Brandt char errbuf[1000]; 1815f06ca4afSHartmut Brandt va_list ap; 1816f06ca4afSHartmut Brandt 181770af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 181870af00a1SHartmut Brandt return; 181970af00a1SHartmut Brandt 1820f06ca4afSHartmut Brandt va_start(ap, err); 1821f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 182270af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 182370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1824f06ca4afSHartmut Brandt va_end(ap); 1825f06ca4afSHartmut Brandt 1826f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1827f06ca4afSHartmut Brandt } 1828f06ca4afSHartmut Brandt 1829f06ca4afSHartmut Brandt static void 1830f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 1831f06ca4afSHartmut Brandt { 1832f06ca4afSHartmut Brandt char errbuf[1000]; 1833f06ca4afSHartmut Brandt va_list ap; 1834f06ca4afSHartmut Brandt 1835f06ca4afSHartmut Brandt va_start(ap, err); 1836f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1837f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1838f06ca4afSHartmut Brandt err, ap); 1839f06ca4afSHartmut Brandt va_end(ap); 1840f06ca4afSHartmut Brandt 1841f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 1842f06ca4afSHartmut Brandt } 1843f06ca4afSHartmut Brandt 1844f06ca4afSHartmut Brandt static void 1845f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 1846f06ca4afSHartmut Brandt { 1847f06ca4afSHartmut Brandt char errbuf[1000]; 1848f06ca4afSHartmut Brandt va_list ap; 1849f06ca4afSHartmut Brandt u_int i; 1850f06ca4afSHartmut Brandt 185170af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 185270af00a1SHartmut Brandt return; 185370af00a1SHartmut Brandt 1854f06ca4afSHartmut Brandt va_start(ap, err); 1855f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 185670af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 185770af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1858f06ca4afSHartmut Brandt va_end(ap); 1859f06ca4afSHartmut Brandt 1860f06ca4afSHartmut Brandt if (b != NULL) { 186170af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 186270af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 1863f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 1864f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 186570af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 186670af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 1867f06ca4afSHartmut Brandt } 1868f06ca4afSHartmut Brandt 1869f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1870f06ca4afSHartmut Brandt } 1871f06ca4afSHartmut Brandt 1872f06ca4afSHartmut Brandt /* 1873f06ca4afSHartmut Brandt * Create a new community 1874f06ca4afSHartmut Brandt */ 1875f06ca4afSHartmut Brandt u_int 1876f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 1877f06ca4afSHartmut Brandt const char *str) 1878f06ca4afSHartmut Brandt { 1879f06ca4afSHartmut Brandt struct community *c, *p; 1880f06ca4afSHartmut Brandt u_int ncomm; 1881f06ca4afSHartmut Brandt 1882f06ca4afSHartmut Brandt /* generate an identifier */ 1883f06ca4afSHartmut Brandt do { 1884f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 1885f06ca4afSHartmut Brandt next_community_index = 1; 1886f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 1887f06ca4afSHartmut Brandt if (c->value == ncomm) 1888f06ca4afSHartmut Brandt break; 1889f06ca4afSHartmut Brandt } while (c != NULL); 1890f06ca4afSHartmut Brandt 1891f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 1892f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 1893f06ca4afSHartmut Brandt return (0); 1894f06ca4afSHartmut Brandt } 1895f06ca4afSHartmut Brandt c->owner = owner; 1896f06ca4afSHartmut Brandt c->value = ncomm; 1897f06ca4afSHartmut Brandt c->descr = descr; 1898f06ca4afSHartmut Brandt c->string = NULL; 1899f06ca4afSHartmut Brandt c->private = priv; 1900f06ca4afSHartmut Brandt 1901f06ca4afSHartmut Brandt if (str != NULL) { 1902f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 1903f06ca4afSHartmut Brandt free(c); 1904f06ca4afSHartmut Brandt return (0); 1905f06ca4afSHartmut Brandt } 1906f06ca4afSHartmut Brandt strcpy(c->string, str); 1907f06ca4afSHartmut Brandt } 1908f06ca4afSHartmut Brandt 1909f06ca4afSHartmut Brandt /* make index */ 1910f06ca4afSHartmut Brandt if (c->owner == NULL) { 1911f06ca4afSHartmut Brandt c->index.len = 1; 1912f06ca4afSHartmut Brandt c->index.subs[0] = 0; 1913f06ca4afSHartmut Brandt } else { 1914f06ca4afSHartmut Brandt c->index = c->owner->index; 1915f06ca4afSHartmut Brandt } 1916f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 1917f06ca4afSHartmut Brandt 1918f06ca4afSHartmut Brandt /* 1919f06ca4afSHartmut Brandt * Insert ordered 1920f06ca4afSHartmut Brandt */ 1921f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 1922f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 1923f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 1924f06ca4afSHartmut Brandt break; 1925f06ca4afSHartmut Brandt } 1926f06ca4afSHartmut Brandt } 1927f06ca4afSHartmut Brandt if (p == NULL) 1928f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 1929f06ca4afSHartmut Brandt return (c->value); 1930f06ca4afSHartmut Brandt } 1931f06ca4afSHartmut Brandt 1932f06ca4afSHartmut Brandt const char * 1933f06ca4afSHartmut Brandt comm_string(u_int ncomm) 1934f06ca4afSHartmut Brandt { 1935f06ca4afSHartmut Brandt struct community *p; 1936f06ca4afSHartmut Brandt 1937f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 1938f06ca4afSHartmut Brandt if (p->value == ncomm) 1939f06ca4afSHartmut Brandt return (p->string); 1940f06ca4afSHartmut Brandt return (NULL); 1941f06ca4afSHartmut Brandt } 1942f06ca4afSHartmut Brandt 1943f06ca4afSHartmut Brandt /* 1944f06ca4afSHartmut Brandt * Delete all communities allocated by a module 1945f06ca4afSHartmut Brandt */ 1946f06ca4afSHartmut Brandt static void 1947f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 1948f06ca4afSHartmut Brandt { 1949f06ca4afSHartmut Brandt struct community *p, *p1; 1950f06ca4afSHartmut Brandt 1951f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 1952f06ca4afSHartmut Brandt while (p != NULL) { 1953f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 1954f06ca4afSHartmut Brandt if (p->owner == mod) { 1955f06ca4afSHartmut Brandt free(p->string); 1956f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 1957f06ca4afSHartmut Brandt free(p); 1958f06ca4afSHartmut Brandt } 1959f06ca4afSHartmut Brandt p = p1; 1960f06ca4afSHartmut Brandt } 1961f06ca4afSHartmut Brandt } 1962f06ca4afSHartmut Brandt 1963f06ca4afSHartmut Brandt /* 1964f06ca4afSHartmut Brandt * Request ID handling. 1965f06ca4afSHartmut Brandt * 1966f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 1967f06ca4afSHartmut Brandt */ 1968f06ca4afSHartmut Brandt u_int 1969f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 1970f06ca4afSHartmut Brandt { 1971f06ca4afSHartmut Brandt u_int type; 1972f06ca4afSHartmut Brandt struct idrange *r, *r1; 1973f06ca4afSHartmut Brandt 1974f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 1975f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1976f06ca4afSHartmut Brandt return (0); 1977f06ca4afSHartmut Brandt } 1978f06ca4afSHartmut Brandt /* allocate a type id */ 1979f06ca4afSHartmut Brandt do { 1980f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 1981f06ca4afSHartmut Brandt next_idrange = 1; 1982f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1983f06ca4afSHartmut Brandt if (r->type == type) 1984f06ca4afSHartmut Brandt break; 1985f06ca4afSHartmut Brandt } while(r != NULL); 1986f06ca4afSHartmut Brandt 1987f06ca4afSHartmut Brandt /* find a range */ 1988f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 1989f06ca4afSHartmut Brandt r = NULL; 1990f06ca4afSHartmut Brandt else { 1991f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 1992f06ca4afSHartmut Brandt if (r->base < size) { 1993f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1994f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 1995f06ca4afSHartmut Brandt break; 1996f06ca4afSHartmut Brandt r = r1; 1997f06ca4afSHartmut Brandt } 1998f06ca4afSHartmut Brandt r = r1; 1999f06ca4afSHartmut Brandt } 2000f06ca4afSHartmut Brandt if (r == NULL) { 2001f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2002f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2003f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2004f06ca4afSHartmut Brandt return (0); 2005f06ca4afSHartmut Brandt } 2006f06ca4afSHartmut Brandt } 2007f06ca4afSHartmut Brandt } 2008f06ca4afSHartmut Brandt 2009f06ca4afSHartmut Brandt /* allocate structure */ 2010f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2011f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2012f06ca4afSHartmut Brandt return (0); 2013f06ca4afSHartmut Brandt } 2014f06ca4afSHartmut Brandt 2015f06ca4afSHartmut Brandt r1->type = type; 2016f06ca4afSHartmut Brandt r1->size = size; 2017f06ca4afSHartmut Brandt r1->owner = mod; 2018f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2019f06ca4afSHartmut Brandt r1->base = 0; 2020f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2021f06ca4afSHartmut Brandt } else if (r == NULL) { 2022f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2023f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2024f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2025f06ca4afSHartmut Brandt } else { 2026f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2027f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2028f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2029f06ca4afSHartmut Brandt } 2030f06ca4afSHartmut Brandt r1->next = r1->base; 2031f06ca4afSHartmut Brandt 2032f06ca4afSHartmut Brandt return (type); 2033f06ca4afSHartmut Brandt } 2034f06ca4afSHartmut Brandt 2035f06ca4afSHartmut Brandt int32_t 2036f06ca4afSHartmut Brandt reqid_next(u_int type) 2037f06ca4afSHartmut Brandt { 2038f06ca4afSHartmut Brandt struct idrange *r; 2039f06ca4afSHartmut Brandt int32_t id; 2040f06ca4afSHartmut Brandt 2041f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2042f06ca4afSHartmut Brandt if (r->type == type) 2043f06ca4afSHartmut Brandt break; 2044f06ca4afSHartmut Brandt if (r == NULL) { 2045f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2046f06ca4afSHartmut Brandt abort(); 2047f06ca4afSHartmut Brandt } 2048f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2049f06ca4afSHartmut Brandt r->next = r->base; 2050f06ca4afSHartmut Brandt return (id); 2051f06ca4afSHartmut Brandt } 2052f06ca4afSHartmut Brandt 2053f06ca4afSHartmut Brandt int32_t 2054f06ca4afSHartmut Brandt reqid_base(u_int type) 2055f06ca4afSHartmut Brandt { 2056f06ca4afSHartmut Brandt struct idrange *r; 2057f06ca4afSHartmut Brandt 2058f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2059f06ca4afSHartmut Brandt if (r->type == type) 2060f06ca4afSHartmut Brandt return (r->base); 2061f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2062f06ca4afSHartmut Brandt abort(); 2063f06ca4afSHartmut Brandt } 2064f06ca4afSHartmut Brandt 2065f06ca4afSHartmut Brandt u_int 2066f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2067f06ca4afSHartmut Brandt { 2068f06ca4afSHartmut Brandt struct idrange *r; 2069f06ca4afSHartmut Brandt 2070f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2071f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2072f06ca4afSHartmut Brandt return (r->type); 2073f06ca4afSHartmut Brandt return (0); 2074f06ca4afSHartmut Brandt } 2075f06ca4afSHartmut Brandt 2076f06ca4afSHartmut Brandt int 2077f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2078f06ca4afSHartmut Brandt { 2079f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2080f06ca4afSHartmut Brandt } 2081f06ca4afSHartmut Brandt 2082f06ca4afSHartmut Brandt /* 2083f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2084f06ca4afSHartmut Brandt */ 2085f06ca4afSHartmut Brandt static void 2086f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2087f06ca4afSHartmut Brandt { 2088f06ca4afSHartmut Brandt struct idrange *p, *p1; 2089f06ca4afSHartmut Brandt 2090f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2091f06ca4afSHartmut Brandt while (p != NULL) { 2092f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2093f06ca4afSHartmut Brandt if (p->owner == mod) { 2094f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2095f06ca4afSHartmut Brandt free(p); 2096f06ca4afSHartmut Brandt } 2097f06ca4afSHartmut Brandt p = p1; 2098f06ca4afSHartmut Brandt } 2099f06ca4afSHartmut Brandt } 2100f06ca4afSHartmut Brandt 2101f06ca4afSHartmut Brandt /* 2102f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2103f06ca4afSHartmut Brandt */ 2104f06ca4afSHartmut Brandt static int 2105f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2106f06ca4afSHartmut Brandt { 2107f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2108f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2109f06ca4afSHartmut Brandt 2110f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2111f06ca4afSHartmut Brandt } 2112f06ca4afSHartmut Brandt static int 2113f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2114f06ca4afSHartmut Brandt { 2115f06ca4afSHartmut Brandt struct snmp_node *xtree; 2116f06ca4afSHartmut Brandt u_int i; 2117f06ca4afSHartmut Brandt 2118f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2119f06ca4afSHartmut Brandt if (xtree == NULL) { 21208eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2121f06ca4afSHartmut Brandt return (-1); 2122f06ca4afSHartmut Brandt } 2123f06ca4afSHartmut Brandt tree = xtree; 2124f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2125f06ca4afSHartmut Brandt 2126f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 21278eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2128f06ca4afSHartmut Brandt 2129f06ca4afSHartmut Brandt tree_size += nsize; 2130f06ca4afSHartmut Brandt 2131f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2132f06ca4afSHartmut Brandt 2133f06ca4afSHartmut Brandt return (0); 2134f06ca4afSHartmut Brandt } 2135f06ca4afSHartmut Brandt 2136f06ca4afSHartmut Brandt /* 2137f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2138f06ca4afSHartmut Brandt */ 2139f06ca4afSHartmut Brandt static void 2140f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2141f06ca4afSHartmut Brandt { 2142f06ca4afSHartmut Brandt u_int s, d; 2143f06ca4afSHartmut Brandt 2144f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 21458eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2146f06ca4afSHartmut Brandt if (s != d) 2147f06ca4afSHartmut Brandt tree[d] = tree[s]; 2148f06ca4afSHartmut Brandt d++; 2149f06ca4afSHartmut Brandt } 2150f06ca4afSHartmut Brandt tree_size = d; 2151f06ca4afSHartmut Brandt } 2152f06ca4afSHartmut Brandt 2153f06ca4afSHartmut Brandt /* 2154f06ca4afSHartmut Brandt * Loadable modules 2155f06ca4afSHartmut Brandt */ 2156f06ca4afSHartmut Brandt struct lmodule * 2157f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2158f06ca4afSHartmut Brandt { 2159f06ca4afSHartmut Brandt struct lmodule *m; 2160f06ca4afSHartmut Brandt int err; 2161f06ca4afSHartmut Brandt int i; 2162f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2163f06ca4afSHartmut Brandt int ac; 2164f06ca4afSHartmut Brandt u_int u; 2165f06ca4afSHartmut Brandt 2166f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2167f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2168f06ca4afSHartmut Brandt return (NULL); 2169f06ca4afSHartmut Brandt } 2170f06ca4afSHartmut Brandt m->handle = NULL; 2171f06ca4afSHartmut Brandt m->flags = 0; 2172f06ca4afSHartmut Brandt strcpy(m->section, section); 2173f06ca4afSHartmut Brandt 2174f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2175f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2176f06ca4afSHartmut Brandt goto err; 2177f06ca4afSHartmut Brandt } 2178f06ca4afSHartmut Brandt strcpy(m->path, path); 2179f06ca4afSHartmut Brandt 2180f06ca4afSHartmut Brandt /* 2181f06ca4afSHartmut Brandt * Make index 2182f06ca4afSHartmut Brandt */ 2183f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2184f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2185f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2186f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2187f06ca4afSHartmut Brandt 2188f06ca4afSHartmut Brandt /* 2189f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2190f06ca4afSHartmut Brandt */ 2191f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2192f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2193f06ca4afSHartmut Brandt goto err; 2194f06ca4afSHartmut Brandt } 2195f06ca4afSHartmut Brandt 2196f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2197f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2198f06ca4afSHartmut Brandt goto err; 2199f06ca4afSHartmut Brandt } 2200f06ca4afSHartmut Brandt 2201f06ca4afSHartmut Brandt /* 2202f06ca4afSHartmut Brandt * Insert it into the right place 2203f06ca4afSHartmut Brandt */ 2204f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2205f06ca4afSHartmut Brandt 2206f06ca4afSHartmut Brandt /* preserve order */ 2207f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2208f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2209f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2210f06ca4afSHartmut Brandt } 2211f06ca4afSHartmut Brandt 2212f06ca4afSHartmut Brandt /* 2213f06ca4afSHartmut Brandt * make the argument vector. 2214f06ca4afSHartmut Brandt */ 2215f06ca4afSHartmut Brandt ac = 0; 2216f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2217f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2218f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2219f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2220f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2221f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2222f06ca4afSHartmut Brandt "module '%s", section); 2223f06ca4afSHartmut Brandt break; 2224f06ca4afSHartmut Brandt } 2225f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2226f06ca4afSHartmut Brandt } 2227f06ca4afSHartmut Brandt } 2228f06ca4afSHartmut Brandt av[ac] = NULL; 2229f06ca4afSHartmut Brandt 2230f06ca4afSHartmut Brandt /* 2231165c5d31SHartmut Brandt * Run the initialization function 2232f06ca4afSHartmut Brandt */ 2233f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2234f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2235f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2236f06ca4afSHartmut Brandt goto err; 2237f06ca4afSHartmut Brandt } 2238f06ca4afSHartmut Brandt 2239f06ca4afSHartmut Brandt return (m); 2240f06ca4afSHartmut Brandt 2241f06ca4afSHartmut Brandt err: 2242f06ca4afSHartmut Brandt if (m->handle) 2243f06ca4afSHartmut Brandt dlclose(m->handle); 2244f06ca4afSHartmut Brandt free(m->path); 2245f06ca4afSHartmut Brandt free(m); 2246f06ca4afSHartmut Brandt return (NULL); 2247f06ca4afSHartmut Brandt } 2248f06ca4afSHartmut Brandt 2249f06ca4afSHartmut Brandt /* 2250f06ca4afSHartmut Brandt * Start a module 2251f06ca4afSHartmut Brandt */ 2252f06ca4afSHartmut Brandt void 2253f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2254f06ca4afSHartmut Brandt { 2255f06ca4afSHartmut Brandt const struct lmodule *m; 2256f06ca4afSHartmut Brandt 2257f06ca4afSHartmut Brandt /* 2258f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2259f06ca4afSHartmut Brandt */ 2260f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2261f06ca4afSHartmut Brandt lm_unload(mod); 2262f06ca4afSHartmut Brandt return; 2263f06ca4afSHartmut Brandt } 2264f06ca4afSHartmut Brandt 2265f06ca4afSHartmut Brandt /* 2266f06ca4afSHartmut Brandt * Read configuration 2267f06ca4afSHartmut Brandt */ 2268f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2269f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2270f06ca4afSHartmut Brandt lm_unload(mod); 2271f06ca4afSHartmut Brandt return; 2272f06ca4afSHartmut Brandt } 2273f06ca4afSHartmut Brandt if (mod->config->start) 2274f06ca4afSHartmut Brandt (*mod->config->start)(); 2275f06ca4afSHartmut Brandt 2276f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2277f06ca4afSHartmut Brandt 2278f06ca4afSHartmut Brandt /* 2279f06ca4afSHartmut Brandt * Inform other modules 2280f06ca4afSHartmut Brandt */ 2281f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2282f06ca4afSHartmut Brandt if (m->config->loading) 2283f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2284f06ca4afSHartmut Brandt } 2285f06ca4afSHartmut Brandt 2286f06ca4afSHartmut Brandt 2287f06ca4afSHartmut Brandt /* 2288f06ca4afSHartmut Brandt * Unload a module. 2289f06ca4afSHartmut Brandt */ 2290f06ca4afSHartmut Brandt void 2291f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2292f06ca4afSHartmut Brandt { 2293f06ca4afSHartmut Brandt int err; 2294f06ca4afSHartmut Brandt const struct lmodule *mod; 2295f06ca4afSHartmut Brandt 2296f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2297f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2298f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2299f06ca4afSHartmut Brandt tree_unmerge(m); 2300f06ca4afSHartmut Brandt 2301f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2302f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2303f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2304f06ca4afSHartmut Brandt 2305f06ca4afSHartmut Brandt comm_flush(m); 2306f06ca4afSHartmut Brandt reqid_flush(m); 2307f06ca4afSHartmut Brandt timer_flush(m); 2308f06ca4afSHartmut Brandt fd_flush(m); 2309f06ca4afSHartmut Brandt 2310f06ca4afSHartmut Brandt dlclose(m->handle); 2311f06ca4afSHartmut Brandt free(m->path); 2312f06ca4afSHartmut Brandt 2313f06ca4afSHartmut Brandt /* 2314f06ca4afSHartmut Brandt * Inform other modules 2315f06ca4afSHartmut Brandt */ 2316f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2317f06ca4afSHartmut Brandt if (mod->config->loading) 2318f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2319f06ca4afSHartmut Brandt 2320f06ca4afSHartmut Brandt free(m); 2321f06ca4afSHartmut Brandt } 2322f06ca4afSHartmut Brandt 2323f06ca4afSHartmut Brandt /* 2324f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2325f06ca4afSHartmut Brandt */ 2326f06ca4afSHartmut Brandt u_int 2327f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2328f06ca4afSHartmut Brandt { 2329f06ca4afSHartmut Brandt struct objres *objres, *or1; 2330f06ca4afSHartmut Brandt u_int idx; 2331f06ca4afSHartmut Brandt 2332f06ca4afSHartmut Brandt /* find a free index */ 2333f06ca4afSHartmut Brandt idx = 1; 2334f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2335f06ca4afSHartmut Brandt objres != NULL; 2336f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2337f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2338f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2339f06ca4afSHartmut Brandt idx = objres->index + 1; 2340f06ca4afSHartmut Brandt break; 2341f06ca4afSHartmut Brandt } 2342f06ca4afSHartmut Brandt } 2343f06ca4afSHartmut Brandt 2344f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2345f06ca4afSHartmut Brandt return (0); 2346f06ca4afSHartmut Brandt 2347f06ca4afSHartmut Brandt objres->index = idx; 2348f06ca4afSHartmut Brandt objres->oid = *or; 2349f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 235069292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2351f06ca4afSHartmut Brandt objres->module = mod; 2352f06ca4afSHartmut Brandt 2353f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2354f06ca4afSHartmut Brandt 2355f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2356f06ca4afSHartmut Brandt 2357f06ca4afSHartmut Brandt return (idx); 2358f06ca4afSHartmut Brandt } 2359f06ca4afSHartmut Brandt 2360f06ca4afSHartmut Brandt void 2361f06ca4afSHartmut Brandt or_unregister(u_int idx) 2362f06ca4afSHartmut Brandt { 2363f06ca4afSHartmut Brandt struct objres *objres; 2364f06ca4afSHartmut Brandt 2365f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2366f06ca4afSHartmut Brandt if (objres->index == idx) { 2367f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2368f06ca4afSHartmut Brandt free(objres); 2369f06ca4afSHartmut Brandt return; 2370f06ca4afSHartmut Brandt } 2371f06ca4afSHartmut Brandt } 2372