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 604c0a7af9SHartmut Brandt #if !defined(INT32_MAX) 614c0a7af9SHartmut Brandt #define INT32_MAX (0x7fffffff) 624c0a7af9SHartmut Brandt #endif 634c0a7af9SHartmut Brandt 64f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 65f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 66f06ca4afSHartmut Brandt 6769292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 6869292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 69f06ca4afSHartmut Brandt 70f06ca4afSHartmut Brandt struct systemg systemg = { 71f06ca4afSHartmut Brandt NULL, 72f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 73f06ca4afSHartmut Brandt NULL, NULL, NULL, 74f06ca4afSHartmut Brandt 64 + 8 + 4, 75f06ca4afSHartmut Brandt 0 76f06ca4afSHartmut Brandt }; 77f06ca4afSHartmut Brandt struct debug debug = { 78f06ca4afSHartmut Brandt 0, /* dump_pdus */ 79f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 80f06ca4afSHartmut Brandt 0, /* evdebug */ 81f06ca4afSHartmut Brandt }; 82f06ca4afSHartmut Brandt 83f06ca4afSHartmut Brandt struct snmpd snmpd = { 84f06ca4afSHartmut Brandt 2048, /* txbuf */ 85f06ca4afSHartmut Brandt 2048, /* rxbuf */ 86f06ca4afSHartmut Brandt 0, /* comm_dis */ 87f06ca4afSHartmut Brandt 0, /* auth_traps */ 88f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 8970af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 90f06ca4afSHartmut Brandt }; 91f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 92f06ca4afSHartmut Brandt 93f06ca4afSHartmut Brandt /* snmpSerialNo */ 94f06ca4afSHartmut Brandt int32_t snmp_serial_no; 95f06ca4afSHartmut Brandt 96f06ca4afSHartmut Brandt /* search path for config files */ 97f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 98f06ca4afSHartmut Brandt 99f06ca4afSHartmut Brandt /* list of all loaded modules */ 100f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 101f06ca4afSHartmut Brandt 102f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 103f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 104f06ca4afSHartmut Brandt 105f06ca4afSHartmut Brandt /* list of all known communities */ 106f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 107f06ca4afSHartmut Brandt 108f06ca4afSHartmut Brandt /* list of all installed object resources */ 109f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 110f06ca4afSHartmut Brandt 111f06ca4afSHartmut Brandt /* community value generator */ 112f06ca4afSHartmut Brandt static u_int next_community_index = 1; 113f06ca4afSHartmut Brandt 114f06ca4afSHartmut Brandt /* list of all known ranges */ 115f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 116f06ca4afSHartmut Brandt 117f06ca4afSHartmut Brandt /* identifier generator */ 118f06ca4afSHartmut Brandt u_int next_idrange = 1; 119f06ca4afSHartmut Brandt 120f06ca4afSHartmut Brandt /* list of all current timers */ 121f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 122f06ca4afSHartmut Brandt 123f06ca4afSHartmut Brandt /* list of file descriptors */ 124f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 125f06ca4afSHartmut Brandt 126f06ca4afSHartmut Brandt /* program arguments */ 127f06ca4afSHartmut Brandt static char **progargs; 128f06ca4afSHartmut Brandt static int nprogargs; 129f06ca4afSHartmut Brandt 130f06ca4afSHartmut Brandt /* current community */ 131f06ca4afSHartmut Brandt u_int community; 132f06ca4afSHartmut Brandt static struct community *comm; 133f06ca4afSHartmut Brandt 134f06ca4afSHartmut Brandt /* file names */ 135f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 136f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 137f06ca4afSHartmut Brandt 13870af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 139f06ca4afSHartmut Brandt /* event context */ 140f06ca4afSHartmut Brandt static evContext evctx; 14170af00a1SHartmut Brandt #endif 142f06ca4afSHartmut Brandt 143f06ca4afSHartmut Brandt /* signal mask */ 144f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 145f06ca4afSHartmut Brandt 146f06ca4afSHartmut Brandt /* signal handling */ 147f06ca4afSHartmut Brandt static int work; 148f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 149f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 150f06ca4afSHartmut Brandt 151f06ca4afSHartmut Brandt /* oids */ 152f06ca4afSHartmut Brandt static const struct asn_oid 153f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 154f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 155f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 156f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 157f06ca4afSHartmut Brandt 158f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 159f06ca4afSHartmut Brandt 160f06ca4afSHartmut Brandt /* request id generator for traps */ 161f06ca4afSHartmut Brandt u_int trap_reqid; 162f06ca4afSHartmut Brandt 163f06ca4afSHartmut Brandt /* help text */ 164f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 165f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 166f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 167f06ca4afSHartmut Brandt usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 168f06ca4afSHartmut Brandt [-m variable=value] [-p file]\n\ 169f06ca4afSHartmut Brandt options:\n\ 170f06ca4afSHartmut Brandt -d don't daemonize\n\ 171f06ca4afSHartmut Brandt -h print this info\n\ 172f06ca4afSHartmut Brandt -c file specify configuration file\n\ 173f06ca4afSHartmut Brandt -D options debugging options\n\ 174f06ca4afSHartmut Brandt -I path system include path\n\ 175f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 176f06ca4afSHartmut Brandt -m var=val define variable\n\ 177f06ca4afSHartmut Brandt -p file specify pid file\n\ 178f06ca4afSHartmut Brandt "; 179f06ca4afSHartmut Brandt 180d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 181d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 182d7eb6b47SHartmut Brandt static struct request_info req; 183d7eb6b47SHartmut Brandt #endif 184d7eb6b47SHartmut Brandt 18570af00a1SHartmut Brandt /* transports */ 18670af00a1SHartmut Brandt extern const struct transport_def udp_trans; 18770af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 18870af00a1SHartmut Brandt 18970af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 19070af00a1SHartmut Brandt 191f06ca4afSHartmut Brandt /* forward declarations */ 192f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 193f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 194f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 195f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 196f06ca4afSHartmut Brandt 197f06ca4afSHartmut Brandt /* 198f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 199f06ca4afSHartmut Brandt */ 200f06ca4afSHartmut Brandt void * 201f06ca4afSHartmut Brandt buf_alloc(int tx) 202f06ca4afSHartmut Brandt { 203f06ca4afSHartmut Brandt void *buf; 204f06ca4afSHartmut Brandt 20570af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 206f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 207f06ca4afSHartmut Brandt if (tx) 208f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 209f06ca4afSHartmut Brandt else 210f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 211f06ca4afSHartmut Brandt return (NULL); 212f06ca4afSHartmut Brandt } 213f06ca4afSHartmut Brandt return (buf); 214f06ca4afSHartmut Brandt } 215f06ca4afSHartmut Brandt 216f06ca4afSHartmut Brandt /* 21770af00a1SHartmut Brandt * Return the buffer size. 218f06ca4afSHartmut Brandt */ 219f06ca4afSHartmut Brandt size_t 220f06ca4afSHartmut Brandt buf_size(int tx) 221f06ca4afSHartmut Brandt { 22270af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 223f06ca4afSHartmut Brandt } 224f06ca4afSHartmut Brandt 225f06ca4afSHartmut Brandt /* 226f06ca4afSHartmut Brandt * Prepare a PDU for output 227f06ca4afSHartmut Brandt */ 228f06ca4afSHartmut Brandt void 22970af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 230f06ca4afSHartmut Brandt const char *dest) 231f06ca4afSHartmut Brandt { 232f06ca4afSHartmut Brandt struct asn_buf resp_b; 233f06ca4afSHartmut Brandt 234f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 235f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 236f06ca4afSHartmut Brandt 237f06ca4afSHartmut Brandt if (snmp_pdu_encode(pdu, &resp_b) != 0) { 238f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot encode message"); 239f06ca4afSHartmut Brandt abort(); 240f06ca4afSHartmut Brandt } 241f06ca4afSHartmut Brandt if (debug.dump_pdus) { 242f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 243f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 244f06ca4afSHartmut Brandt } 245f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 246f06ca4afSHartmut Brandt } 247f06ca4afSHartmut Brandt 248f06ca4afSHartmut Brandt /* 249f06ca4afSHartmut Brandt * SNMP input. Start: decode the PDU, find the community. 250f06ca4afSHartmut Brandt */ 251f06ca4afSHartmut Brandt enum snmpd_input_err 252f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 25370af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 254f06ca4afSHartmut Brandt { 255f06ca4afSHartmut Brandt struct asn_buf b; 256f06ca4afSHartmut Brandt enum snmp_code code; 257f06ca4afSHartmut Brandt enum snmpd_input_err ret; 25870af00a1SHartmut Brandt int sret; 259f06ca4afSHartmut Brandt 260f06ca4afSHartmut Brandt b.asn_cptr = buf; 261f06ca4afSHartmut Brandt b.asn_len = len; 26270af00a1SHartmut Brandt 26370af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 26470af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 26570af00a1SHartmut Brandt 26670af00a1SHartmut Brandt case 0: 26770af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 26870af00a1SHartmut Brandt 26970af00a1SHartmut Brandt case -1: 27070af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 27170af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 27270af00a1SHartmut Brandt } 27370af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 27470af00a1SHartmut Brandt 275f06ca4afSHartmut Brandt code = snmp_pdu_decode(&b, pdu, ip); 276f06ca4afSHartmut Brandt 27770af00a1SHartmut Brandt snmpd_stats.inPkts++; 27870af00a1SHartmut Brandt 279f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 280f06ca4afSHartmut Brandt switch (code) { 281f06ca4afSHartmut Brandt 282f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 283f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 284f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 285f06ca4afSHartmut Brandt 286f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 28770af00a1SHartmut Brandt bad_vers: 288f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 289f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 290f06ca4afSHartmut Brandt 291f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 292f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 293f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 294f06ca4afSHartmut Brandt break; 295f06ca4afSHartmut Brandt 296f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 297f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 298f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 299f06ca4afSHartmut Brandt break; 300f06ca4afSHartmut Brandt 301f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 302f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 303f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 304f06ca4afSHartmut Brandt break; 305f06ca4afSHartmut Brandt 306f06ca4afSHartmut Brandt case SNMP_CODE_OK: 30770af00a1SHartmut Brandt switch (pdu->version) { 30870af00a1SHartmut Brandt 30970af00a1SHartmut Brandt case SNMP_V1: 31070af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 31170af00a1SHartmut Brandt goto bad_vers; 31270af00a1SHartmut Brandt break; 31370af00a1SHartmut Brandt 31470af00a1SHartmut Brandt case SNMP_V2c: 31570af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 31670af00a1SHartmut Brandt goto bad_vers; 31770af00a1SHartmut Brandt break; 31870af00a1SHartmut Brandt 31970af00a1SHartmut Brandt case SNMP_Verr: 32070af00a1SHartmut Brandt goto bad_vers; 32170af00a1SHartmut Brandt } 322f06ca4afSHartmut Brandt break; 323f06ca4afSHartmut Brandt } 324f06ca4afSHartmut Brandt 325f06ca4afSHartmut Brandt if (debug.dump_pdus) { 326f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 327f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 328f06ca4afSHartmut Brandt } 329f06ca4afSHartmut Brandt 330f06ca4afSHartmut Brandt /* 331f06ca4afSHartmut Brandt * Look, whether we know the community 332f06ca4afSHartmut Brandt */ 333f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 334f06ca4afSHartmut Brandt if (comm->string != NULL && 335f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 336f06ca4afSHartmut Brandt break; 337f06ca4afSHartmut Brandt 338f06ca4afSHartmut Brandt if (comm == NULL) { 339f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 340f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 341f06ca4afSHartmut Brandt if (snmpd.auth_traps) 342896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 343896052c1SHartmut Brandt (struct snmp_value *)NULL); 344896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 345896052c1SHartmut Brandt } else 346f06ca4afSHartmut Brandt community = comm->value; 347f06ca4afSHartmut Brandt 348f06ca4afSHartmut Brandt /* update uptime */ 349f06ca4afSHartmut Brandt this_tick = get_ticks(); 350f06ca4afSHartmut Brandt 351f06ca4afSHartmut Brandt return (ret); 352f06ca4afSHartmut Brandt } 353f06ca4afSHartmut Brandt 354f06ca4afSHartmut Brandt /* 355f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 356f06ca4afSHartmut Brandt */ 357f06ca4afSHartmut Brandt enum snmpd_input_err 358f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 359f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 360f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 361f06ca4afSHartmut Brandt { 362f06ca4afSHartmut Brandt struct snmp_pdu resp; 363f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 364f06ca4afSHartmut Brandt enum snmp_ret ret; 365f06ca4afSHartmut Brandt 366f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 367f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 368f06ca4afSHartmut Brandt 369f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 370f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 371f06ca4afSHartmut Brandt 372f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 373f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 374f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 375f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 376f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 377f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 378f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 379f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 380f06ca4afSHartmut Brandt else 381f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 382f06ca4afSHartmut Brandt 383f06ca4afSHartmut Brandt pdu->error_index = ivar; 384f06ca4afSHartmut Brandt 385f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 386f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 387f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 388f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 389f06ca4afSHartmut Brandt } 390f06ca4afSHartmut Brandt 391f06ca4afSHartmut Brandt if (debug.dump_pdus) { 392f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 393f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 394f06ca4afSHartmut Brandt } 395f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 396f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 397f06ca4afSHartmut Brandt } 398f06ca4afSHartmut Brandt 399f06ca4afSHartmut Brandt switch (pdu->type) { 400f06ca4afSHartmut Brandt 401f06ca4afSHartmut Brandt case SNMP_PDU_GET: 402f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 403f06ca4afSHartmut Brandt break; 404f06ca4afSHartmut Brandt 405f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 406f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 407f06ca4afSHartmut Brandt break; 408f06ca4afSHartmut Brandt 409f06ca4afSHartmut Brandt case SNMP_PDU_SET: 410f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 411f06ca4afSHartmut Brandt break; 412f06ca4afSHartmut Brandt 413f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 414f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 415f06ca4afSHartmut Brandt break; 416f06ca4afSHartmut Brandt 417f06ca4afSHartmut Brandt default: 418f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 419f06ca4afSHartmut Brandt break; 420f06ca4afSHartmut Brandt } 421f06ca4afSHartmut Brandt 422f06ca4afSHartmut Brandt switch (ret) { 423f06ca4afSHartmut Brandt 424f06ca4afSHartmut Brandt case SNMP_RET_OK: 425f06ca4afSHartmut Brandt /* normal return - send a response */ 426f06ca4afSHartmut Brandt if (debug.dump_pdus) { 427f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 428f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 429f06ca4afSHartmut Brandt } 430f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 431f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 432f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 433f06ca4afSHartmut Brandt 434f06ca4afSHartmut Brandt case SNMP_RET_IGN: 435f06ca4afSHartmut Brandt /* error - send nothing */ 436f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 437f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 438f06ca4afSHartmut Brandt 439f06ca4afSHartmut Brandt case SNMP_RET_ERR: 440f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 441f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 442f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 443f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 444f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 445f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 446f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 447f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 448f06ca4afSHartmut Brandt } else { 449f06ca4afSHartmut Brandt if (debug.dump_pdus) { 450f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 451f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 452f06ca4afSHartmut Brandt } 453f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 454f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 455f06ca4afSHartmut Brandt } 456f06ca4afSHartmut Brandt } 457f06ca4afSHartmut Brandt abort(); 458f06ca4afSHartmut Brandt } 459f06ca4afSHartmut Brandt 46070af00a1SHartmut Brandt /* 46170af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 46270af00a1SHartmut Brandt */ 46370af00a1SHartmut Brandt void 46470af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 46570af00a1SHartmut Brandt { 46670af00a1SHartmut Brandt struct tport *p; 467f06ca4afSHartmut Brandt 46870af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 46970af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 47070af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 47170af00a1SHartmut Brandt return; 47270af00a1SHartmut Brandt } 47370af00a1SHartmut Brandt } 47470af00a1SHartmut Brandt port->transport = t; 47570af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 47670af00a1SHartmut Brandt } 47770af00a1SHartmut Brandt 47870af00a1SHartmut Brandt /* 47970af00a1SHartmut Brandt * Remove a port from a transport's list 48070af00a1SHartmut Brandt */ 48170af00a1SHartmut Brandt void 48270af00a1SHartmut Brandt trans_remove_port(struct tport *port) 48370af00a1SHartmut Brandt { 48470af00a1SHartmut Brandt 48570af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 48670af00a1SHartmut Brandt } 48770af00a1SHartmut Brandt 48870af00a1SHartmut Brandt /* 48970af00a1SHartmut Brandt * Find a port on a transport's list 49070af00a1SHartmut Brandt */ 49170af00a1SHartmut Brandt struct tport * 49270af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 49370af00a1SHartmut Brandt { 49470af00a1SHartmut Brandt 49570af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 49670af00a1SHartmut Brandt } 49770af00a1SHartmut Brandt 49870af00a1SHartmut Brandt /* 49970af00a1SHartmut Brandt * Find next port on a transport's list 50070af00a1SHartmut Brandt */ 50170af00a1SHartmut Brandt struct tport * 50270af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 50370af00a1SHartmut Brandt { 50470af00a1SHartmut Brandt 50570af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 50670af00a1SHartmut Brandt } 50770af00a1SHartmut Brandt 50870af00a1SHartmut Brandt /* 50970af00a1SHartmut Brandt * Return first port 51070af00a1SHartmut Brandt */ 51170af00a1SHartmut Brandt struct tport * 51270af00a1SHartmut Brandt trans_first_port(struct transport *t) 51370af00a1SHartmut Brandt { 51470af00a1SHartmut Brandt 51570af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 51670af00a1SHartmut Brandt } 51770af00a1SHartmut Brandt 51870af00a1SHartmut Brandt /* 51970af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 52070af00a1SHartmut Brandt */ 52170af00a1SHartmut Brandt struct tport * 52270af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 52370af00a1SHartmut Brandt intptr_t arg) 52470af00a1SHartmut Brandt { 52570af00a1SHartmut Brandt struct tport *p; 52670af00a1SHartmut Brandt 52770af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 52870af00a1SHartmut Brandt if (func(p, arg) == 0) 52970af00a1SHartmut Brandt return (p); 53070af00a1SHartmut Brandt return (NULL); 53170af00a1SHartmut Brandt } 53270af00a1SHartmut Brandt 53370af00a1SHartmut Brandt /* 53470af00a1SHartmut Brandt * Register a transport 53570af00a1SHartmut Brandt */ 53670af00a1SHartmut Brandt int 53770af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 53870af00a1SHartmut Brandt { 53970af00a1SHartmut Brandt u_int i; 54070af00a1SHartmut Brandt char or_descr[256]; 54170af00a1SHartmut Brandt 54270af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 54370af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 54470af00a1SHartmut Brandt 54570af00a1SHartmut Brandt /* construct index */ 54670af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 54770af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 54870af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 54970af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 55070af00a1SHartmut Brandt 55170af00a1SHartmut Brandt (*pp)->vtab = def; 55270af00a1SHartmut Brandt 55370af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 55470af00a1SHartmut Brandt free(*pp); 55570af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 55670af00a1SHartmut Brandt } 55770af00a1SHartmut Brandt 55870af00a1SHartmut Brandt /* register module */ 55970af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 56070af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 56170af00a1SHartmut Brandt free(*pp); 56270af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 56370af00a1SHartmut Brandt } 56470af00a1SHartmut Brandt 56570af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 56670af00a1SHartmut Brandt 56770af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 56870af00a1SHartmut Brandt 56970af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 57070af00a1SHartmut Brandt } 57170af00a1SHartmut Brandt 57270af00a1SHartmut Brandt /* 57370af00a1SHartmut Brandt * Unregister transport 57470af00a1SHartmut Brandt */ 57570af00a1SHartmut Brandt int 57670af00a1SHartmut Brandt trans_unregister(struct transport *t) 57770af00a1SHartmut Brandt { 57870af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 57970af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 58070af00a1SHartmut Brandt 58170af00a1SHartmut Brandt or_unregister(t->or_index); 58270af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 58370af00a1SHartmut Brandt 58470af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 58570af00a1SHartmut Brandt } 586f06ca4afSHartmut Brandt 587f06ca4afSHartmut Brandt /* 588f06ca4afSHartmut Brandt * File descriptor support 589f06ca4afSHartmut Brandt */ 59070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 59170af00a1SHartmut Brandt static void 59270af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 59370af00a1SHartmut Brandt #else 594f06ca4afSHartmut Brandt static void 595f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 59670af00a1SHartmut Brandt #endif 597f06ca4afSHartmut Brandt { 598f06ca4afSHartmut Brandt struct fdesc *f = uap; 599f06ca4afSHartmut Brandt 600f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 601f06ca4afSHartmut Brandt } 602f06ca4afSHartmut Brandt 603f06ca4afSHartmut Brandt void 604f06ca4afSHartmut Brandt fd_suspend(void *p) 605f06ca4afSHartmut Brandt { 606f06ca4afSHartmut Brandt struct fdesc *f = p; 607f06ca4afSHartmut Brandt 60870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 60970af00a1SHartmut Brandt if (f->id >= 0) { 61070af00a1SHartmut Brandt poll_unregister(f->id); 61170af00a1SHartmut Brandt f->id = -1; 61270af00a1SHartmut Brandt } 61370af00a1SHartmut Brandt #else 614f06ca4afSHartmut Brandt if (evTestID(f->id)) { 615f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 616f06ca4afSHartmut Brandt evInitID(&f->id); 617f06ca4afSHartmut Brandt } 61870af00a1SHartmut Brandt #endif 619f06ca4afSHartmut Brandt } 620f06ca4afSHartmut Brandt 621f06ca4afSHartmut Brandt int 622f06ca4afSHartmut Brandt fd_resume(void *p) 623f06ca4afSHartmut Brandt { 624f06ca4afSHartmut Brandt struct fdesc *f = p; 625f06ca4afSHartmut Brandt int err; 626f06ca4afSHartmut Brandt 62770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 62870af00a1SHartmut Brandt if (f->id >= 0) 62970af00a1SHartmut Brandt return (0); 63094caccb3SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 63170af00a1SHartmut Brandt err = errno; 63270af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 63370af00a1SHartmut Brandt errno = err; 63470af00a1SHartmut Brandt return (-1); 63570af00a1SHartmut Brandt } 63670af00a1SHartmut Brandt #else 637f06ca4afSHartmut Brandt if (evTestID(f->id)) 638f06ca4afSHartmut Brandt return (0); 639f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 640f06ca4afSHartmut Brandt err = errno; 641f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 642f06ca4afSHartmut Brandt errno = err; 643f06ca4afSHartmut Brandt return (-1); 644f06ca4afSHartmut Brandt } 64570af00a1SHartmut Brandt #endif 646f06ca4afSHartmut Brandt return (0); 647f06ca4afSHartmut Brandt } 648f06ca4afSHartmut Brandt 649f06ca4afSHartmut Brandt void * 650f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 651f06ca4afSHartmut Brandt { 652f06ca4afSHartmut Brandt struct fdesc *f; 653f06ca4afSHartmut Brandt int err; 654f06ca4afSHartmut Brandt 655f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 656f06ca4afSHartmut Brandt err = errno; 657f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 658f06ca4afSHartmut Brandt errno = err; 659f06ca4afSHartmut Brandt return (NULL); 660f06ca4afSHartmut Brandt } 661f06ca4afSHartmut Brandt f->fd = fd; 662f06ca4afSHartmut Brandt f->func = func; 663f06ca4afSHartmut Brandt f->udata = udata; 664f06ca4afSHartmut Brandt f->owner = mod; 66570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 66670af00a1SHartmut Brandt f->id = -1; 66770af00a1SHartmut Brandt #else 668f06ca4afSHartmut Brandt evInitID(&f->id); 66970af00a1SHartmut Brandt #endif 670f06ca4afSHartmut Brandt 671f06ca4afSHartmut Brandt if (fd_resume(f)) { 672f06ca4afSHartmut Brandt err = errno; 673f06ca4afSHartmut Brandt free(f); 674f06ca4afSHartmut Brandt errno = err; 675f06ca4afSHartmut Brandt return (NULL); 676f06ca4afSHartmut Brandt } 677f06ca4afSHartmut Brandt 678f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 679f06ca4afSHartmut Brandt 680f06ca4afSHartmut Brandt return (f); 681f06ca4afSHartmut Brandt } 682f06ca4afSHartmut Brandt 683f06ca4afSHartmut Brandt void 684f06ca4afSHartmut Brandt fd_deselect(void *p) 685f06ca4afSHartmut Brandt { 686f06ca4afSHartmut Brandt struct fdesc *f = p; 687f06ca4afSHartmut Brandt 688f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 689f06ca4afSHartmut Brandt fd_suspend(f); 690f06ca4afSHartmut Brandt free(f); 691f06ca4afSHartmut Brandt } 692f06ca4afSHartmut Brandt 693f06ca4afSHartmut Brandt static void 694f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 695f06ca4afSHartmut Brandt { 696f06ca4afSHartmut Brandt struct fdesc *t, *t1; 697f06ca4afSHartmut Brandt 698f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 699f06ca4afSHartmut Brandt while (t != NULL) { 700f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 701f06ca4afSHartmut Brandt if (t->owner == mod) 702f06ca4afSHartmut Brandt fd_deselect(t); 703f06ca4afSHartmut Brandt t = t1; 704f06ca4afSHartmut Brandt } 705f06ca4afSHartmut Brandt } 706f06ca4afSHartmut Brandt 707f06ca4afSHartmut Brandt /* 70870af00a1SHartmut Brandt * Consume a message from the input buffer 709f06ca4afSHartmut Brandt */ 710f06ca4afSHartmut Brandt static void 71170af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 712f06ca4afSHartmut Brandt { 71370af00a1SHartmut Brandt if (!pi->stream) { 71470af00a1SHartmut Brandt /* always consume everything */ 71570af00a1SHartmut Brandt pi->length = 0; 71670af00a1SHartmut Brandt return; 71770af00a1SHartmut Brandt } 71870af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 71970af00a1SHartmut Brandt /* all bytes consumed */ 72070af00a1SHartmut Brandt pi->length = 0; 72170af00a1SHartmut Brandt return; 72270af00a1SHartmut Brandt } 72370af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 72470af00a1SHartmut Brandt pi->length -= pi->consumed; 72570af00a1SHartmut Brandt } 72670af00a1SHartmut Brandt 72770af00a1SHartmut Brandt struct credmsg { 72870af00a1SHartmut Brandt struct cmsghdr hdr; 72970af00a1SHartmut Brandt struct cmsgcred cred; 73070af00a1SHartmut Brandt }; 73170af00a1SHartmut Brandt 73270af00a1SHartmut Brandt static void 73370af00a1SHartmut Brandt check_priv(struct port_input *pi, struct msghdr *msg) 73470af00a1SHartmut Brandt { 73570af00a1SHartmut Brandt struct credmsg *cmsg; 73670af00a1SHartmut Brandt struct xucred ucred; 73770af00a1SHartmut Brandt socklen_t ucredlen; 73870af00a1SHartmut Brandt 73970af00a1SHartmut Brandt pi->priv = 0; 74070af00a1SHartmut Brandt 74170af00a1SHartmut Brandt if (msg->msg_controllen == sizeof(*cmsg)) { 742165c5d31SHartmut Brandt /* process explicitly sends credentials */ 74370af00a1SHartmut Brandt 74470af00a1SHartmut Brandt cmsg = (struct credmsg *)msg->msg_control; 74570af00a1SHartmut Brandt pi->priv = (cmsg->cred.cmcred_euid == 0); 74670af00a1SHartmut Brandt return; 74770af00a1SHartmut Brandt } 74870af00a1SHartmut Brandt 74970af00a1SHartmut Brandt /* ok, obtain the accept time credentials */ 75070af00a1SHartmut Brandt ucredlen = sizeof(ucred); 75170af00a1SHartmut Brandt 75270af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 75370af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 75470af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 75570af00a1SHartmut Brandt } 75670af00a1SHartmut Brandt 75770af00a1SHartmut Brandt /* 75870af00a1SHartmut Brandt * Input from a stream socket. 75970af00a1SHartmut Brandt */ 76070af00a1SHartmut Brandt static int 76170af00a1SHartmut Brandt recv_stream(struct port_input *pi) 76270af00a1SHartmut Brandt { 76370af00a1SHartmut Brandt struct msghdr msg; 76470af00a1SHartmut Brandt struct iovec iov[1]; 76570af00a1SHartmut Brandt ssize_t len; 76670af00a1SHartmut Brandt struct credmsg cmsg; 76770af00a1SHartmut Brandt 76870af00a1SHartmut Brandt if (pi->buf == NULL) { 76970af00a1SHartmut Brandt /* no buffer yet - allocate one */ 77070af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 77170af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 77270af00a1SHartmut Brandt * the caller must close the transport. */ 77370af00a1SHartmut Brandt return (-1); 77470af00a1SHartmut Brandt } 77570af00a1SHartmut Brandt pi->buflen = buf_size(0); 77670af00a1SHartmut Brandt pi->consumed = 0; 77770af00a1SHartmut Brandt pi->length = 0; 77870af00a1SHartmut Brandt } 77970af00a1SHartmut Brandt 78070af00a1SHartmut Brandt /* try to get a message */ 78170af00a1SHartmut Brandt msg.msg_name = pi->peer; 78270af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 78370af00a1SHartmut Brandt msg.msg_iov = iov; 78470af00a1SHartmut Brandt msg.msg_iovlen = 1; 78570af00a1SHartmut Brandt if (pi->cred) { 78670af00a1SHartmut Brandt msg.msg_control = &cmsg; 78770af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 78870af00a1SHartmut Brandt 78970af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 79070af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 79170af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 79270af00a1SHartmut Brandt } else { 79370af00a1SHartmut Brandt msg.msg_control = NULL; 79470af00a1SHartmut Brandt msg.msg_controllen = 0; 79570af00a1SHartmut Brandt } 79670af00a1SHartmut Brandt msg.msg_flags = 0; 79770af00a1SHartmut Brandt 79870af00a1SHartmut Brandt iov[0].iov_base = pi->buf + pi->length; 79970af00a1SHartmut Brandt iov[0].iov_len = pi->buflen - pi->length; 80070af00a1SHartmut Brandt 80170af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 80270af00a1SHartmut Brandt 80370af00a1SHartmut Brandt if (len == -1 || len == 0) 80470af00a1SHartmut Brandt /* receive error */ 80570af00a1SHartmut Brandt return (-1); 80670af00a1SHartmut Brandt 80770af00a1SHartmut Brandt pi->length += len; 80870af00a1SHartmut Brandt 80970af00a1SHartmut Brandt if (pi->cred) 81070af00a1SHartmut Brandt check_priv(pi, &msg); 81170af00a1SHartmut Brandt 81270af00a1SHartmut Brandt return (0); 81370af00a1SHartmut Brandt } 81470af00a1SHartmut Brandt 81570af00a1SHartmut Brandt /* 81670af00a1SHartmut Brandt * Input from a datagram socket. 81770af00a1SHartmut Brandt * Each receive should return one datagram. 81870af00a1SHartmut Brandt */ 81970af00a1SHartmut Brandt static int 82070af00a1SHartmut Brandt recv_dgram(struct port_input *pi) 82170af00a1SHartmut Brandt { 82270af00a1SHartmut Brandt u_char embuf[1000]; 82370af00a1SHartmut Brandt struct msghdr msg; 82470af00a1SHartmut Brandt struct iovec iov[1]; 82570af00a1SHartmut Brandt ssize_t len; 82670af00a1SHartmut Brandt struct credmsg cmsg; 82770af00a1SHartmut Brandt 82870af00a1SHartmut Brandt if (pi->buf == NULL) { 82970af00a1SHartmut Brandt /* no buffer yet - allocate one */ 83070af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 83170af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 83270af00a1SHartmut Brandt * and drop it */ 83370af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 83470af00a1SHartmut Brandt 0, NULL, NULL); 83570af00a1SHartmut Brandt /* return error */ 83670af00a1SHartmut Brandt return (-1); 83770af00a1SHartmut Brandt } 83870af00a1SHartmut Brandt pi->buflen = buf_size(0); 83970af00a1SHartmut Brandt } 84070af00a1SHartmut Brandt 84170af00a1SHartmut Brandt /* try to get a message */ 84270af00a1SHartmut Brandt msg.msg_name = pi->peer; 84370af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 84470af00a1SHartmut Brandt msg.msg_iov = iov; 84570af00a1SHartmut Brandt msg.msg_iovlen = 1; 84670af00a1SHartmut Brandt if (pi->cred) { 84770af00a1SHartmut Brandt msg.msg_control = &cmsg; 84870af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 84970af00a1SHartmut Brandt 85070af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 85170af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 85270af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 85370af00a1SHartmut Brandt } else { 85470af00a1SHartmut Brandt msg.msg_control = NULL; 8558eecd77aSHartmut Brandt msg.msg_controllen = 0; 85670af00a1SHartmut Brandt } 85770af00a1SHartmut Brandt msg.msg_flags = 0; 85870af00a1SHartmut Brandt 85970af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 86070af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 86170af00a1SHartmut Brandt 86270af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 86370af00a1SHartmut Brandt 86470af00a1SHartmut Brandt if (len == -1 || len == 0) 86570af00a1SHartmut Brandt /* receive error */ 86670af00a1SHartmut Brandt return (-1); 86770af00a1SHartmut Brandt 86870af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 86970af00a1SHartmut Brandt /* truncated - drop */ 87070af00a1SHartmut Brandt snmpd_stats.silentDrops++; 87170af00a1SHartmut Brandt snmpd_stats.inTooLong++; 87270af00a1SHartmut Brandt return (-1); 87370af00a1SHartmut Brandt } 87470af00a1SHartmut Brandt 87570af00a1SHartmut Brandt pi->length = (size_t)len; 87670af00a1SHartmut Brandt 87770af00a1SHartmut Brandt if (pi->cred) 87870af00a1SHartmut Brandt check_priv(pi, &msg); 87970af00a1SHartmut Brandt 88070af00a1SHartmut Brandt return (0); 88170af00a1SHartmut Brandt } 88270af00a1SHartmut Brandt 88370af00a1SHartmut Brandt /* 88470af00a1SHartmut Brandt * Input from a socket 88570af00a1SHartmut Brandt */ 88670af00a1SHartmut Brandt int 88770af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 88870af00a1SHartmut Brandt { 889f06ca4afSHartmut Brandt u_char *sndbuf; 890f06ca4afSHartmut Brandt size_t sndlen; 89170af00a1SHartmut Brandt struct snmp_pdu pdu; 892f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 893f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 894f06ca4afSHartmut Brandt int32_t vi; 89570af00a1SHartmut Brandt int ret; 89670af00a1SHartmut Brandt ssize_t slen; 897d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 898d7eb6b47SHartmut Brandt char client[16]; 899d7eb6b47SHartmut Brandt #endif 900f06ca4afSHartmut Brandt 90170af00a1SHartmut Brandt /* get input depending on the transport */ 90270af00a1SHartmut Brandt if (pi->stream) { 90370af00a1SHartmut Brandt ret = recv_stream(pi); 90470af00a1SHartmut Brandt } else { 90570af00a1SHartmut Brandt ret = recv_dgram(pi); 906f06ca4afSHartmut Brandt } 90770af00a1SHartmut Brandt 90870af00a1SHartmut Brandt if (ret == -1) 90970af00a1SHartmut Brandt return (-1); 910f06ca4afSHartmut Brandt 911d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 912d7eb6b47SHartmut Brandt /* 913d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 914d7eb6b47SHartmut Brandt */ 915d7eb6b47SHartmut Brandt if (inet_ntop(pi->peer->sa_family, 91669292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 91769292cedSHartmut Brandt client, sizeof(client)) != NULL) { 918d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 919d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 920d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 921d7eb6b47SHartmut Brandt eval_client(&req)); 922d7eb6b47SHartmut Brandt return (-1); 923d7eb6b47SHartmut Brandt } 924d7eb6b47SHartmut Brandt } else 925d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 926d7eb6b47SHartmut Brandt #endif 927d7eb6b47SHartmut Brandt 928f06ca4afSHartmut Brandt /* 929f06ca4afSHartmut Brandt * Handle input 930f06ca4afSHartmut Brandt */ 93170af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 93270af00a1SHartmut Brandt &pi->consumed); 93370af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 93470af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 93570af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 93670af00a1SHartmut Brandt if (pi->stream) { 93770af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 93870af00a1SHartmut Brandt snmpd_stats.silentDrops++; 93970af00a1SHartmut Brandt return (-1); 94070af00a1SHartmut Brandt } 94170af00a1SHartmut Brandt return (0); 94270af00a1SHartmut Brandt } 94370af00a1SHartmut Brandt snmpd_stats.silentDrops++; 94470af00a1SHartmut Brandt return (-1); 94570af00a1SHartmut Brandt } 946f06ca4afSHartmut Brandt 947f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 948f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 949f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 950f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 95170af00a1SHartmut Brandt /* for streaming transports this is fatal */ 95270af00a1SHartmut Brandt if (pi->stream) 95370af00a1SHartmut Brandt return (-1); 95470af00a1SHartmut Brandt snmp_input_consume(pi); 95570af00a1SHartmut Brandt return (0); 956f06ca4afSHartmut Brandt } 957896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 958896052c1SHartmut Brandt snmp_input_consume(pi); 959896052c1SHartmut Brandt return (0); 960896052c1SHartmut Brandt } 961f06ca4afSHartmut Brandt 962f06ca4afSHartmut Brandt /* 963f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 964f06ca4afSHartmut Brandt * the hand it over to the module. 965f06ca4afSHartmut Brandt */ 966f06ca4afSHartmut Brandt if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 96770af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 968896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 969896052c1SHartmut Brandt !pi->cred || pi->priv); 970f06ca4afSHartmut Brandt 971f06ca4afSHartmut Brandt switch (perr) { 972f06ca4afSHartmut Brandt 973f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 97470af00a1SHartmut Brandt snmp_input_consume(pi); 97570af00a1SHartmut Brandt return (0); 976f06ca4afSHartmut Brandt 977f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 978f06ca4afSHartmut Brandt break; 979f06ca4afSHartmut Brandt 980f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 98170af00a1SHartmut Brandt snmp_input_consume(pi); 982f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 983f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 98470af00a1SHartmut Brandt return (0); 985f06ca4afSHartmut Brandt 986f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 98770af00a1SHartmut Brandt snmp_input_consume(pi); 988f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 989f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 990f06ca4afSHartmut Brandt if (snmpd.auth_traps) 991f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 992896052c1SHartmut Brandt (struct snmp_value *)NULL); 99370af00a1SHartmut Brandt return (0); 994f06ca4afSHartmut Brandt 995f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 99670af00a1SHartmut Brandt snmp_input_consume(pi); 997f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 998f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 999f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1000f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1001896052c1SHartmut Brandt (struct snmp_value *)NULL); 100270af00a1SHartmut Brandt return (0); 1003f06ca4afSHartmut Brandt } 1004f06ca4afSHartmut Brandt } 1005f06ca4afSHartmut Brandt 1006f06ca4afSHartmut Brandt /* 1007f06ca4afSHartmut Brandt * Check type 1008f06ca4afSHartmut Brandt */ 1009f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1010f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1011f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1012f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1013f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1014f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 101570af00a1SHartmut Brandt snmp_input_consume(pi); 101670af00a1SHartmut Brandt return (0); 1017f06ca4afSHartmut Brandt } 1018f06ca4afSHartmut Brandt 1019f06ca4afSHartmut Brandt /* 1020f06ca4afSHartmut Brandt * Check community 1021f06ca4afSHartmut Brandt */ 102270af00a1SHartmut Brandt if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 102370af00a1SHartmut Brandt (community != COMM_WRITE && 102470af00a1SHartmut Brandt (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 1025f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1026f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 102770af00a1SHartmut Brandt snmp_input_consume(pi); 1028f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1029896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1030896052c1SHartmut Brandt (struct snmp_value *)NULL); 103170af00a1SHartmut Brandt return (0); 1032f06ca4afSHartmut Brandt } 1033f06ca4afSHartmut Brandt 1034f06ca4afSHartmut Brandt /* 1035f06ca4afSHartmut Brandt * Execute it. 1036f06ca4afSHartmut Brandt */ 1037f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1038f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1039f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 104070af00a1SHartmut Brandt snmp_input_consume(pi); 104170af00a1SHartmut Brandt return (0); 1042f06ca4afSHartmut Brandt } 104370af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 104470af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1045f06ca4afSHartmut Brandt 1046f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 104770af00a1SHartmut Brandt slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 104870af00a1SHartmut Brandt if (slen == -1) 104970af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 105070af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 105170af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 105270af00a1SHartmut Brandt sndlen, (size_t)slen); 105370af00a1SHartmut Brandt } 105470af00a1SHartmut Brandt snmp_pdu_free(&pdu); 105570af00a1SHartmut Brandt free(sndbuf); 105670af00a1SHartmut Brandt snmp_input_consume(pi); 105770af00a1SHartmut Brandt 105870af00a1SHartmut Brandt return (0); 105970af00a1SHartmut Brandt } 106070af00a1SHartmut Brandt 106170af00a1SHartmut Brandt /* 106270af00a1SHartmut Brandt * Send a PDU to a given port 106370af00a1SHartmut Brandt */ 106470af00a1SHartmut Brandt void 106570af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 106670af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 106770af00a1SHartmut Brandt { 106870af00a1SHartmut Brandt struct transport *trans = targ; 106970af00a1SHartmut Brandt struct tport *tp; 107070af00a1SHartmut Brandt u_char *sndbuf; 107170af00a1SHartmut Brandt size_t sndlen; 107270af00a1SHartmut Brandt ssize_t len; 107370af00a1SHartmut Brandt 107470af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 107570af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 107670af00a1SHartmut Brandt break; 107770af00a1SHartmut Brandt if (tp == 0) 107870af00a1SHartmut Brandt return; 107970af00a1SHartmut Brandt 108070af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 108170af00a1SHartmut Brandt return; 108270af00a1SHartmut Brandt 108370af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 108470af00a1SHartmut Brandt 108570af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 108670af00a1SHartmut Brandt 108770af00a1SHartmut Brandt if (len == -1) 1088f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1089f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1090f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1091f06ca4afSHartmut Brandt sndlen, (size_t)len); 109270af00a1SHartmut Brandt 1093f06ca4afSHartmut Brandt free(sndbuf); 1094f06ca4afSHartmut Brandt } 1095f06ca4afSHartmut Brandt 1096f06ca4afSHartmut Brandt 1097f06ca4afSHartmut Brandt /* 109870af00a1SHartmut Brandt * Close an input source 1099f06ca4afSHartmut Brandt */ 1100f06ca4afSHartmut Brandt void 110170af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1102f06ca4afSHartmut Brandt { 110370af00a1SHartmut Brandt if (pi->id != NULL) 110470af00a1SHartmut Brandt fd_deselect(pi->id); 110570af00a1SHartmut Brandt if (pi->fd >= 0) 110670af00a1SHartmut Brandt (void)close(pi->fd); 110770af00a1SHartmut Brandt if (pi->buf != NULL) 110870af00a1SHartmut Brandt free(pi->buf); 1109f06ca4afSHartmut Brandt } 1110f06ca4afSHartmut Brandt 1111f06ca4afSHartmut Brandt /* 1112f06ca4afSHartmut Brandt * Dump internal state. 1113f06ca4afSHartmut Brandt */ 111470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 111570af00a1SHartmut Brandt static void 111670af00a1SHartmut Brandt info_func(void) 111770af00a1SHartmut Brandt #else 1118f06ca4afSHartmut Brandt static void 1119f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 112070af00a1SHartmut Brandt #endif 1121f06ca4afSHartmut Brandt { 1122f06ca4afSHartmut Brandt struct lmodule *m; 1123f06ca4afSHartmut Brandt u_int i; 1124f06ca4afSHartmut Brandt char buf[10000]; 1125f06ca4afSHartmut Brandt 1126f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1127f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1128f06ca4afSHartmut Brandt switch (tree[i].type) { 1129f06ca4afSHartmut Brandt 1130f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1131f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1132f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1133f06ca4afSHartmut Brandt break; 1134f06ca4afSHartmut Brandt 1135f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1136f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1137f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1138f06ca4afSHartmut Brandt break; 1139f06ca4afSHartmut Brandt } 1140f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1141f06ca4afSHartmut Brandt } 1142f06ca4afSHartmut Brandt 1143f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1144f06ca4afSHartmut Brandt if (m->config->dump) 1145f06ca4afSHartmut Brandt (*m->config->dump)(); 1146f06ca4afSHartmut Brandt } 1147f06ca4afSHartmut Brandt 1148f06ca4afSHartmut Brandt /* 1149f06ca4afSHartmut Brandt * Re-read configuration 1150f06ca4afSHartmut Brandt */ 115170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 115270af00a1SHartmut Brandt static void 115370af00a1SHartmut Brandt config_func(void) 115470af00a1SHartmut Brandt #else 1155f06ca4afSHartmut Brandt static void 1156f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1157f06ca4afSHartmut Brandt const void *tag __unused) 115870af00a1SHartmut Brandt #endif 1159f06ca4afSHartmut Brandt { 1160f06ca4afSHartmut Brandt struct lmodule *m; 1161f06ca4afSHartmut Brandt 1162f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1163f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1164f06ca4afSHartmut Brandt return; 1165f06ca4afSHartmut Brandt } 1166f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1167f06ca4afSHartmut Brandt if (m->config->config) 1168f06ca4afSHartmut Brandt (*m->config->config)(); 1169f06ca4afSHartmut Brandt } 1170f06ca4afSHartmut Brandt 1171f06ca4afSHartmut Brandt /* 1172f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1173f06ca4afSHartmut Brandt */ 1174f06ca4afSHartmut Brandt static void 1175f06ca4afSHartmut Brandt onusr1(int s __unused) 1176f06ca4afSHartmut Brandt { 117770af00a1SHartmut Brandt 1178f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1179f06ca4afSHartmut Brandt } 1180f06ca4afSHartmut Brandt static void 1181f06ca4afSHartmut Brandt onhup(int s __unused) 1182f06ca4afSHartmut Brandt { 118370af00a1SHartmut Brandt 1184f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1185f06ca4afSHartmut Brandt } 1186f06ca4afSHartmut Brandt 1187f06ca4afSHartmut Brandt static void 1188f06ca4afSHartmut Brandt onterm(int s __unused) 1189f06ca4afSHartmut Brandt { 1190f06ca4afSHartmut Brandt 119170af00a1SHartmut Brandt /* allow clean-up */ 1192f06ca4afSHartmut Brandt exit(0); 1193f06ca4afSHartmut Brandt } 1194f06ca4afSHartmut Brandt 1195f06ca4afSHartmut Brandt static void 1196f06ca4afSHartmut Brandt init_sigs(void) 1197f06ca4afSHartmut Brandt { 1198f06ca4afSHartmut Brandt struct sigaction sa; 1199f06ca4afSHartmut Brandt 1200f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1201f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1202f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1203f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1204f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1205f06ca4afSHartmut Brandt exit(1); 1206f06ca4afSHartmut Brandt } 1207f06ca4afSHartmut Brandt 1208f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1209f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1210f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1211f06ca4afSHartmut Brandt exit(1); 1212f06ca4afSHartmut Brandt } 1213f06ca4afSHartmut Brandt 1214f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1215f06ca4afSHartmut Brandt sa.sa_flags = 0; 1216f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1217f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1218f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1219f06ca4afSHartmut Brandt exit(1); 1220f06ca4afSHartmut Brandt } 1221f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1222f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1223f06ca4afSHartmut Brandt exit(1); 1224f06ca4afSHartmut Brandt } 1225f06ca4afSHartmut Brandt } 1226f06ca4afSHartmut Brandt 1227f06ca4afSHartmut Brandt static void 1228f06ca4afSHartmut Brandt block_sigs(void) 1229f06ca4afSHartmut Brandt { 1230f06ca4afSHartmut Brandt sigset_t set; 1231f06ca4afSHartmut Brandt 1232f06ca4afSHartmut Brandt sigfillset(&set); 1233f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1234f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1235f06ca4afSHartmut Brandt exit(1); 1236f06ca4afSHartmut Brandt } 1237f06ca4afSHartmut Brandt } 1238f06ca4afSHartmut Brandt static void 1239f06ca4afSHartmut Brandt unblock_sigs(void) 1240f06ca4afSHartmut Brandt { 1241f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1242f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1243f06ca4afSHartmut Brandt exit(1); 1244f06ca4afSHartmut Brandt } 1245f06ca4afSHartmut Brandt } 1246f06ca4afSHartmut Brandt 1247f06ca4afSHartmut Brandt /* 1248f06ca4afSHartmut Brandt * Shut down 1249f06ca4afSHartmut Brandt */ 1250f06ca4afSHartmut Brandt static void 1251f06ca4afSHartmut Brandt term(void) 1252f06ca4afSHartmut Brandt { 1253f06ca4afSHartmut Brandt (void)unlink(pid_file); 1254f06ca4afSHartmut Brandt } 1255f06ca4afSHartmut Brandt 125670af00a1SHartmut Brandt static void 125770af00a1SHartmut Brandt trans_stop(void) 125870af00a1SHartmut Brandt { 125970af00a1SHartmut Brandt struct transport *t; 126070af00a1SHartmut Brandt 126170af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 126270af00a1SHartmut Brandt (void)t->vtab->stop(1); 126370af00a1SHartmut Brandt } 126470af00a1SHartmut Brandt 1265f06ca4afSHartmut Brandt /* 1266f06ca4afSHartmut Brandt * Define a macro from the command line 1267f06ca4afSHartmut Brandt */ 1268f06ca4afSHartmut Brandt static void 1269f06ca4afSHartmut Brandt do_macro(char *arg) 1270f06ca4afSHartmut Brandt { 1271f06ca4afSHartmut Brandt char *eq; 1272f06ca4afSHartmut Brandt int err; 1273f06ca4afSHartmut Brandt 1274f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1275f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1276f06ca4afSHartmut Brandt else { 1277f06ca4afSHartmut Brandt *eq++ = '\0'; 1278f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1279f06ca4afSHartmut Brandt } 1280f06ca4afSHartmut Brandt if (err == -1) { 1281f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1282f06ca4afSHartmut Brandt exit(1); 1283f06ca4afSHartmut Brandt } 1284f06ca4afSHartmut Brandt } 1285f06ca4afSHartmut Brandt 1286f06ca4afSHartmut Brandt /* 1287f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1288f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1289f06ca4afSHartmut Brandt */ 1290f06ca4afSHartmut Brandt static int 1291f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1292f06ca4afSHartmut Brandt { 1293f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1294f06ca4afSHartmut Brandt u_int i; 1295f06ca4afSHartmut Brandt char *ptr; 1296f06ca4afSHartmut Brandt 1297f06ca4afSHartmut Brandt *optp = NULL; 1298f06ca4afSHartmut Brandt 1299f06ca4afSHartmut Brandt /* skip leading junk */ 1300f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1301f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1302f06ca4afSHartmut Brandt break; 1303f06ca4afSHartmut Brandt if (*ptr == '\0') { 1304f06ca4afSHartmut Brandt *arg = ptr; 1305f06ca4afSHartmut Brandt return (-1); 1306f06ca4afSHartmut Brandt } 1307f06ca4afSHartmut Brandt *optp = ptr; 1308f06ca4afSHartmut Brandt 1309f06ca4afSHartmut Brandt /* find the end of the option */ 1310f06ca4afSHartmut Brandt while (*++ptr != '\0') 1311f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1312f06ca4afSHartmut Brandt break; 1313f06ca4afSHartmut Brandt 1314f06ca4afSHartmut Brandt if (*ptr != '\0') { 1315f06ca4afSHartmut Brandt if (*ptr == '=') { 1316f06ca4afSHartmut Brandt *ptr++ = '\0'; 1317f06ca4afSHartmut Brandt *valp = ptr; 1318f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1319f06ca4afSHartmut Brandt ptr++; 1320f06ca4afSHartmut Brandt if (*ptr != '\0') 1321f06ca4afSHartmut Brandt *ptr++ = '\0'; 1322f06ca4afSHartmut Brandt } else 1323f06ca4afSHartmut Brandt *ptr++ = '\0'; 1324f06ca4afSHartmut Brandt } 1325f06ca4afSHartmut Brandt 1326f06ca4afSHartmut Brandt *arg = ptr; 1327f06ca4afSHartmut Brandt 1328f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 132970af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1330f06ca4afSHartmut Brandt return (i); 1331f06ca4afSHartmut Brandt return (-1); 1332f06ca4afSHartmut Brandt } 1333f06ca4afSHartmut Brandt 1334f06ca4afSHartmut Brandt int 1335f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1336f06ca4afSHartmut Brandt { 1337f06ca4afSHartmut Brandt int opt; 1338f06ca4afSHartmut Brandt FILE *fp; 1339f06ca4afSHartmut Brandt int background = 1; 134070af00a1SHartmut Brandt struct tport *p; 1341f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1342f06ca4afSHartmut Brandt struct lmodule *m; 1343f06ca4afSHartmut Brandt char *value, *option; 134470af00a1SHartmut Brandt struct transport *t; 1345f06ca4afSHartmut Brandt 1346f06ca4afSHartmut Brandt #define DBG_DUMP 0 1347f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1348f06ca4afSHartmut Brandt #define DBG_TRACE 2 1349f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1350f06ca4afSHartmut Brandt "dump", 1351f06ca4afSHartmut Brandt "events", 1352f06ca4afSHartmut Brandt "trace", 1353f06ca4afSHartmut Brandt NULL 1354f06ca4afSHartmut Brandt }; 1355f06ca4afSHartmut Brandt 1356f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1357f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1358f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1359f06ca4afSHartmut Brandt asn_error = asn_error_func; 1360f06ca4afSHartmut Brandt 1361f06ca4afSHartmut Brandt while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1362f06ca4afSHartmut Brandt switch (opt) { 1363f06ca4afSHartmut Brandt 1364f06ca4afSHartmut Brandt case 'c': 1365f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1366f06ca4afSHartmut Brandt break; 1367f06ca4afSHartmut Brandt 1368f06ca4afSHartmut Brandt case 'd': 1369f06ca4afSHartmut Brandt background = 0; 1370f06ca4afSHartmut Brandt break; 1371f06ca4afSHartmut Brandt 1372f06ca4afSHartmut Brandt case 'D': 1373f06ca4afSHartmut Brandt while (*optarg) { 1374f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1375f06ca4afSHartmut Brandt &value, &option)) { 1376f06ca4afSHartmut Brandt 1377f06ca4afSHartmut Brandt case DBG_DUMP: 1378f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1379f06ca4afSHartmut Brandt break; 1380f06ca4afSHartmut Brandt 1381f06ca4afSHartmut Brandt case DBG_EVENTS: 1382f06ca4afSHartmut Brandt debug.evdebug++; 1383f06ca4afSHartmut Brandt break; 1384f06ca4afSHartmut Brandt 1385f06ca4afSHartmut Brandt case DBG_TRACE: 1386f06ca4afSHartmut Brandt if (value == NULL) 1387f06ca4afSHartmut Brandt syslog(LOG_ERR, 1388f06ca4afSHartmut Brandt "no value for 'trace'"); 138951054003SHartmut Brandt else 139051054003SHartmut Brandt snmp_trace = 139151054003SHartmut Brandt strtoul(value, NULL, 0); 1392f06ca4afSHartmut Brandt break; 1393f06ca4afSHartmut Brandt 1394f06ca4afSHartmut Brandt case -1: 1395f06ca4afSHartmut Brandt if (suboptarg) 1396f06ca4afSHartmut Brandt syslog(LOG_ERR, 1397f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1398f06ca4afSHartmut Brandt option); 1399f06ca4afSHartmut Brandt else 1400f06ca4afSHartmut Brandt syslog(LOG_ERR, 1401f06ca4afSHartmut Brandt "missing debug flag"); 1402f06ca4afSHartmut Brandt break; 1403f06ca4afSHartmut Brandt } 1404f06ca4afSHartmut Brandt } 1405f06ca4afSHartmut Brandt break; 1406f06ca4afSHartmut Brandt 1407f06ca4afSHartmut Brandt case 'h': 1408f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1409f06ca4afSHartmut Brandt exit(0); 1410f06ca4afSHartmut Brandt 1411f06ca4afSHartmut Brandt case 'I': 1412f06ca4afSHartmut Brandt syspath = optarg; 1413f06ca4afSHartmut Brandt break; 1414f06ca4afSHartmut Brandt 1415f06ca4afSHartmut Brandt case 'l': 1416f06ca4afSHartmut Brandt prefix = optarg; 1417f06ca4afSHartmut Brandt break; 1418f06ca4afSHartmut Brandt 1419f06ca4afSHartmut Brandt case 'm': 1420f06ca4afSHartmut Brandt do_macro(optarg); 1421f06ca4afSHartmut Brandt break; 1422f06ca4afSHartmut Brandt 1423f06ca4afSHartmut Brandt case 'p': 1424f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1425f06ca4afSHartmut Brandt break; 1426f06ca4afSHartmut Brandt } 1427f06ca4afSHartmut Brandt 1428f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1429f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1430f06ca4afSHartmut Brandt 1431f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1432f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1433f06ca4afSHartmut Brandt exit(1); 1434f06ca4afSHartmut Brandt } 1435f06ca4afSHartmut Brandt 1436f06ca4afSHartmut Brandt argc -= optind; 1437f06ca4afSHartmut Brandt argv += optind; 1438f06ca4afSHartmut Brandt 1439f06ca4afSHartmut Brandt progargs = argv; 1440f06ca4afSHartmut Brandt nprogargs = argc; 1441f06ca4afSHartmut Brandt 1442f06ca4afSHartmut Brandt srandomdev(); 1443f06ca4afSHartmut Brandt 1444f06ca4afSHartmut Brandt snmp_serial_no = random(); 1445f06ca4afSHartmut Brandt 1446d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1447d7eb6b47SHartmut Brandt /* 1448d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1449d7eb6b47SHartmut Brandt */ 1450d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1451d7eb6b47SHartmut Brandt sock_methods(&req); 1452d7eb6b47SHartmut Brandt #endif 1453d7eb6b47SHartmut Brandt 1454f06ca4afSHartmut Brandt /* 1455f06ca4afSHartmut Brandt * Initialize the tree. 1456f06ca4afSHartmut Brandt */ 1457f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1458f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1459f06ca4afSHartmut Brandt exit(1); 1460f06ca4afSHartmut Brandt } 1461f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1462f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1463f06ca4afSHartmut Brandt 1464f06ca4afSHartmut Brandt /* 1465f06ca4afSHartmut Brandt * Get standard communities 1466f06ca4afSHartmut Brandt */ 1467d4199d75SHartmut Brandt (void)comm_define(1, "SNMP read", NULL, NULL); 1468d4199d75SHartmut Brandt (void)comm_define(2, "SNMP write", NULL, NULL); 1469f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1470f06ca4afSHartmut Brandt 1471f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1472f06ca4afSHartmut Brandt 1473f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1474f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1475f06ca4afSHartmut Brandt 1476f06ca4afSHartmut Brandt init_actvals(); 147770af00a1SHartmut Brandt 147870af00a1SHartmut Brandt this_tick = get_ticks(); 147969292cedSHartmut Brandt start_tick = this_tick; 148070af00a1SHartmut Brandt 148170af00a1SHartmut Brandt /* start transports */ 148270af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 148370af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 148470af00a1SHartmut Brandt exit(1); 148570af00a1SHartmut Brandt } 148670af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 148770af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 148870af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 148970af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 149070af00a1SHartmut Brandt 149170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 149270af00a1SHartmut Brandt if (debug.evdebug > 0) 149370af00a1SHartmut Brandt rpoll_trace = 1; 149470af00a1SHartmut Brandt #else 1495f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1496f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1497f06ca4afSHartmut Brandt exit(1); 1498f06ca4afSHartmut Brandt } 1499f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1500f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 150170af00a1SHartmut Brandt #endif 1502f06ca4afSHartmut Brandt 1503896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1504896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1505896052c1SHartmut Brandt exit(1); 1506896052c1SHartmut Brandt } 1507896052c1SHartmut Brandt 150870af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 150970af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 151070af00a1SHartmut Brandt t->vtab->init_port(p); 1511f06ca4afSHartmut Brandt 1512f06ca4afSHartmut Brandt init_sigs(); 1513f06ca4afSHartmut Brandt 1514f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1515f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1516f06ca4afSHartmut Brandt 1517f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1518f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1519f06ca4afSHartmut Brandt fclose(fp); 152070af00a1SHartmut Brandt if (atexit(term) == -1) { 152170af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 152270af00a1SHartmut Brandt (void)remove(pid_file); 152370af00a1SHartmut Brandt exit(0); 1524f06ca4afSHartmut Brandt } 152570af00a1SHartmut Brandt } 1526f06ca4afSHartmut Brandt 1527f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1528f06ca4afSHartmut Brandt NULL) == 0) { 1529f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1530f06ca4afSHartmut Brandt exit(1); 1531f06ca4afSHartmut Brandt } 1532f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1533f06ca4afSHartmut Brandt NULL) == 0) { 1534f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1535f06ca4afSHartmut Brandt exit(1); 1536f06ca4afSHartmut Brandt } 1537f06ca4afSHartmut Brandt 1538896052c1SHartmut Brandt snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1539f06ca4afSHartmut Brandt 1540f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1541f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1542f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1543f06ca4afSHartmut Brandt lm_start(m); 1544f06ca4afSHartmut Brandt } 1545f06ca4afSHartmut Brandt 1546f06ca4afSHartmut Brandt for (;;) { 154770af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1548f06ca4afSHartmut Brandt evEvent event; 154970af00a1SHartmut Brandt #endif 1550f06ca4afSHartmut Brandt struct lmodule *mod; 1551f06ca4afSHartmut Brandt 1552f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1553f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1554f06ca4afSHartmut Brandt (*mod->config->idle)(); 1555f06ca4afSHartmut Brandt 155670af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1557f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1558f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1559f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1560f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1561f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1562f06ca4afSHartmut Brandt exit(1); 1563f06ca4afSHartmut Brandt } 156470af00a1SHartmut Brandt #else 156570af00a1SHartmut Brandt poll_dispatch(1); 156670af00a1SHartmut Brandt #endif 1567f06ca4afSHartmut Brandt 1568f06ca4afSHartmut Brandt if (work != 0) { 1569f06ca4afSHartmut Brandt block_sigs(); 1570f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 157170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 157270af00a1SHartmut Brandt info_func(); 157370af00a1SHartmut Brandt #else 1574f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1575f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1576f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1577f06ca4afSHartmut Brandt exit(1); 1578f06ca4afSHartmut Brandt } 157970af00a1SHartmut Brandt #endif 1580f06ca4afSHartmut Brandt } 1581f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 158270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 158370af00a1SHartmut Brandt config_func(); 158470af00a1SHartmut Brandt #else 1585f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1586f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1587f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1588f06ca4afSHartmut Brandt exit(1); 1589f06ca4afSHartmut Brandt } 159070af00a1SHartmut Brandt #endif 1591f06ca4afSHartmut Brandt } 1592f06ca4afSHartmut Brandt work = 0; 1593f06ca4afSHartmut Brandt unblock_sigs(); 159470af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1595f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1596f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1597f06ca4afSHartmut Brandt exit(1); 1598f06ca4afSHartmut Brandt } 159970af00a1SHartmut Brandt #endif 1600f06ca4afSHartmut Brandt } 1601f06ca4afSHartmut Brandt } 1602f06ca4afSHartmut Brandt 1603f06ca4afSHartmut Brandt return (0); 1604f06ca4afSHartmut Brandt } 1605f06ca4afSHartmut Brandt 160669292cedSHartmut Brandt uint64_t 1607f06ca4afSHartmut Brandt get_ticks() 1608f06ca4afSHartmut Brandt { 1609f06ca4afSHartmut Brandt struct timeval tv; 161069292cedSHartmut Brandt uint64_t ret; 1611f06ca4afSHartmut Brandt 1612f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1613f06ca4afSHartmut Brandt abort(); 161469292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1615f06ca4afSHartmut Brandt return (ret); 1616f06ca4afSHartmut Brandt } 161769292cedSHartmut Brandt 1618f06ca4afSHartmut Brandt /* 1619f06ca4afSHartmut Brandt * Timer support 1620f06ca4afSHartmut Brandt */ 1621165c5d31SHartmut Brandt 1622165c5d31SHartmut Brandt /* 1623165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1624165c5d31SHartmut Brandt */ 162570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 162670af00a1SHartmut Brandt static void 162770af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 162870af00a1SHartmut Brandt #else 1629f06ca4afSHartmut Brandt static void 1630f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1631f06ca4afSHartmut Brandt struct timespec inter __unused) 163270af00a1SHartmut Brandt #endif 1633f06ca4afSHartmut Brandt { 1634f06ca4afSHartmut Brandt struct timer *tp = uap; 1635f06ca4afSHartmut Brandt 1636f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1637f06ca4afSHartmut Brandt tp->func(tp->udata); 1638f06ca4afSHartmut Brandt free(tp); 1639f06ca4afSHartmut Brandt } 1640f06ca4afSHartmut Brandt 1641f06ca4afSHartmut Brandt /* 1642165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1643165c5d31SHartmut Brandt */ 1644165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1645165c5d31SHartmut Brandt static void 1646165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1647165c5d31SHartmut Brandt #else 1648165c5d31SHartmut Brandt static void 1649165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1650165c5d31SHartmut Brandt struct timespec inter __unused) 1651165c5d31SHartmut Brandt #endif 1652165c5d31SHartmut Brandt { 1653165c5d31SHartmut Brandt struct timer *tp = uap; 1654165c5d31SHartmut Brandt 1655165c5d31SHartmut Brandt tp->func(tp->udata); 1656165c5d31SHartmut Brandt } 1657165c5d31SHartmut Brandt 1658165c5d31SHartmut Brandt /* 1659165c5d31SHartmut Brandt * Start a one-shot timer 1660f06ca4afSHartmut Brandt */ 1661f06ca4afSHartmut Brandt void * 1662f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1663f06ca4afSHartmut Brandt { 1664f06ca4afSHartmut Brandt struct timer *tp; 1665a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1666f06ca4afSHartmut Brandt struct timespec due; 166770af00a1SHartmut Brandt #endif 1668f06ca4afSHartmut Brandt 1669f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1670f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1671f06ca4afSHartmut Brandt exit(1); 1672f06ca4afSHartmut Brandt } 1673a9bfedb7SHartmut Brandt 1674a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1675f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1676f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 167770af00a1SHartmut Brandt #endif 1678f06ca4afSHartmut Brandt 1679f06ca4afSHartmut Brandt tp->udata = udata; 1680f06ca4afSHartmut Brandt tp->owner = mod; 1681f06ca4afSHartmut Brandt tp->func = func; 1682f06ca4afSHartmut Brandt 1683f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1684f06ca4afSHartmut Brandt 168570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 1686a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 168770af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 168870af00a1SHartmut Brandt exit(1); 168970af00a1SHartmut Brandt } 169070af00a1SHartmut Brandt #else 1691f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1692f06ca4afSHartmut Brandt == -1) { 1693f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1694f06ca4afSHartmut Brandt exit(1); 1695f06ca4afSHartmut Brandt } 169670af00a1SHartmut Brandt #endif 1697f06ca4afSHartmut Brandt return (tp); 1698f06ca4afSHartmut Brandt } 1699f06ca4afSHartmut Brandt 1700165c5d31SHartmut Brandt /* 1701165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 1702165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 1703165c5d31SHartmut Brandt * repeat number of ticks. 1704165c5d31SHartmut Brandt */ 1705165c5d31SHartmut Brandt void * 1706165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 1707165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 1708165c5d31SHartmut Brandt { 1709165c5d31SHartmut Brandt struct timer *tp; 1710165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1711165c5d31SHartmut Brandt struct timespec due; 1712165c5d31SHartmut Brandt struct timespec inter; 1713165c5d31SHartmut Brandt #endif 1714165c5d31SHartmut Brandt 1715165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1716165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1717165c5d31SHartmut Brandt exit(1); 1718165c5d31SHartmut Brandt } 1719165c5d31SHartmut Brandt 1720165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1721165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 1722165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 1723165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 1724165c5d31SHartmut Brandt #endif 1725165c5d31SHartmut Brandt 1726165c5d31SHartmut Brandt tp->udata = udata; 1727165c5d31SHartmut Brandt tp->owner = mod; 1728165c5d31SHartmut Brandt tp->func = func; 1729165c5d31SHartmut Brandt 1730165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1731165c5d31SHartmut Brandt 1732165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1733165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 1734165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1735165c5d31SHartmut Brandt exit(1); 1736165c5d31SHartmut Brandt } 1737165c5d31SHartmut Brandt #else 1738165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 1739165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1740165c5d31SHartmut Brandt exit(1); 1741165c5d31SHartmut Brandt } 1742165c5d31SHartmut Brandt #endif 1743165c5d31SHartmut Brandt return (tp); 1744165c5d31SHartmut Brandt } 1745165c5d31SHartmut Brandt 1746165c5d31SHartmut Brandt /* 1747165c5d31SHartmut Brandt * Stop a timer. 1748165c5d31SHartmut Brandt */ 1749f06ca4afSHartmut Brandt void 1750f06ca4afSHartmut Brandt timer_stop(void *p) 1751f06ca4afSHartmut Brandt { 1752f06ca4afSHartmut Brandt struct timer *tp = p; 1753f06ca4afSHartmut Brandt 1754f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 175570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 175670af00a1SHartmut Brandt poll_stop_timer(tp->id); 175770af00a1SHartmut Brandt #else 1758f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 1759f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 1760f06ca4afSHartmut Brandt exit(1); 1761f06ca4afSHartmut Brandt } 176270af00a1SHartmut Brandt #endif 1763f06ca4afSHartmut Brandt free(p); 1764f06ca4afSHartmut Brandt } 1765f06ca4afSHartmut Brandt 1766f06ca4afSHartmut Brandt static void 1767f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 1768f06ca4afSHartmut Brandt { 1769f06ca4afSHartmut Brandt struct timer *t, *t1; 1770f06ca4afSHartmut Brandt 1771f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 1772f06ca4afSHartmut Brandt while (t != NULL) { 1773f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1774f06ca4afSHartmut Brandt if (t->owner == mod) 1775f06ca4afSHartmut Brandt timer_stop(t); 1776f06ca4afSHartmut Brandt t = t1; 1777f06ca4afSHartmut Brandt } 1778f06ca4afSHartmut Brandt } 1779f06ca4afSHartmut Brandt 1780f06ca4afSHartmut Brandt static void 1781f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1782f06ca4afSHartmut Brandt { 1783f06ca4afSHartmut Brandt va_list ap; 1784f06ca4afSHartmut Brandt static char *pend = NULL; 1785f06ca4afSHartmut Brandt char *ret, *new; 1786f06ca4afSHartmut Brandt 1787f06ca4afSHartmut Brandt va_start(ap, fmt); 1788f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 1789f06ca4afSHartmut Brandt va_end(ap); 1790f06ca4afSHartmut Brandt 1791f06ca4afSHartmut Brandt if (ret == NULL) 1792f06ca4afSHartmut Brandt return; 1793f06ca4afSHartmut Brandt if (pend != NULL) { 1794f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1795f06ca4afSHartmut Brandt == NULL) { 1796f06ca4afSHartmut Brandt free(ret); 1797f06ca4afSHartmut Brandt return; 1798f06ca4afSHartmut Brandt } 1799f06ca4afSHartmut Brandt pend = new; 1800f06ca4afSHartmut Brandt strcat(pend, ret); 1801f06ca4afSHartmut Brandt free(ret); 1802f06ca4afSHartmut Brandt } else 1803f06ca4afSHartmut Brandt pend = ret; 1804f06ca4afSHartmut Brandt 1805f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 1806f06ca4afSHartmut Brandt *ret = '\0'; 1807f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 1808f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 1809f06ca4afSHartmut Brandt free(pend); 1810f06ca4afSHartmut Brandt pend = NULL; 1811f06ca4afSHartmut Brandt break; 1812f06ca4afSHartmut Brandt } 1813f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 1814f06ca4afSHartmut Brandt } 1815f06ca4afSHartmut Brandt } 1816f06ca4afSHartmut Brandt 1817f06ca4afSHartmut Brandt static void 1818f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 1819f06ca4afSHartmut Brandt { 1820f06ca4afSHartmut Brandt char errbuf[1000]; 1821f06ca4afSHartmut Brandt va_list ap; 1822f06ca4afSHartmut Brandt 182370af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 182470af00a1SHartmut Brandt return; 182570af00a1SHartmut Brandt 1826f06ca4afSHartmut Brandt va_start(ap, err); 1827f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 182870af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 182970af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1830f06ca4afSHartmut Brandt va_end(ap); 1831f06ca4afSHartmut Brandt 1832f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1833f06ca4afSHartmut Brandt } 1834f06ca4afSHartmut Brandt 1835f06ca4afSHartmut Brandt static void 1836f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 1837f06ca4afSHartmut Brandt { 1838f06ca4afSHartmut Brandt char errbuf[1000]; 1839f06ca4afSHartmut Brandt va_list ap; 1840f06ca4afSHartmut Brandt 1841f06ca4afSHartmut Brandt va_start(ap, err); 1842f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1843f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1844f06ca4afSHartmut Brandt err, ap); 1845f06ca4afSHartmut Brandt va_end(ap); 1846f06ca4afSHartmut Brandt 1847f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 1848f06ca4afSHartmut Brandt } 1849f06ca4afSHartmut Brandt 1850f06ca4afSHartmut Brandt static void 1851f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 1852f06ca4afSHartmut Brandt { 1853f06ca4afSHartmut Brandt char errbuf[1000]; 1854f06ca4afSHartmut Brandt va_list ap; 1855f06ca4afSHartmut Brandt u_int i; 1856f06ca4afSHartmut Brandt 185770af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 185870af00a1SHartmut Brandt return; 185970af00a1SHartmut Brandt 1860f06ca4afSHartmut Brandt va_start(ap, err); 1861f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 186270af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 186370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1864f06ca4afSHartmut Brandt va_end(ap); 1865f06ca4afSHartmut Brandt 1866f06ca4afSHartmut Brandt if (b != NULL) { 186770af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 186870af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 1869f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 1870f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 187170af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 187270af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 1873f06ca4afSHartmut Brandt } 1874f06ca4afSHartmut Brandt 1875f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1876f06ca4afSHartmut Brandt } 1877f06ca4afSHartmut Brandt 1878f06ca4afSHartmut Brandt /* 1879f06ca4afSHartmut Brandt * Create a new community 1880f06ca4afSHartmut Brandt */ 1881f06ca4afSHartmut Brandt u_int 1882f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 1883f06ca4afSHartmut Brandt const char *str) 1884f06ca4afSHartmut Brandt { 1885f06ca4afSHartmut Brandt struct community *c, *p; 1886f06ca4afSHartmut Brandt u_int ncomm; 1887f06ca4afSHartmut Brandt 1888f06ca4afSHartmut Brandt /* generate an identifier */ 1889f06ca4afSHartmut Brandt do { 1890f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 1891f06ca4afSHartmut Brandt next_community_index = 1; 1892f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 1893f06ca4afSHartmut Brandt if (c->value == ncomm) 1894f06ca4afSHartmut Brandt break; 1895f06ca4afSHartmut Brandt } while (c != NULL); 1896f06ca4afSHartmut Brandt 1897f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 1898f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 1899f06ca4afSHartmut Brandt return (0); 1900f06ca4afSHartmut Brandt } 1901f06ca4afSHartmut Brandt c->owner = owner; 1902f06ca4afSHartmut Brandt c->value = ncomm; 1903f06ca4afSHartmut Brandt c->descr = descr; 1904f06ca4afSHartmut Brandt c->string = NULL; 1905f06ca4afSHartmut Brandt c->private = priv; 1906f06ca4afSHartmut Brandt 1907f06ca4afSHartmut Brandt if (str != NULL) { 1908f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 1909f06ca4afSHartmut Brandt free(c); 1910f06ca4afSHartmut Brandt return (0); 1911f06ca4afSHartmut Brandt } 1912f06ca4afSHartmut Brandt strcpy(c->string, str); 1913f06ca4afSHartmut Brandt } 1914f06ca4afSHartmut Brandt 1915f06ca4afSHartmut Brandt /* make index */ 1916f06ca4afSHartmut Brandt if (c->owner == NULL) { 1917f06ca4afSHartmut Brandt c->index.len = 1; 1918f06ca4afSHartmut Brandt c->index.subs[0] = 0; 1919f06ca4afSHartmut Brandt } else { 1920f06ca4afSHartmut Brandt c->index = c->owner->index; 1921f06ca4afSHartmut Brandt } 1922f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 1923f06ca4afSHartmut Brandt 1924f06ca4afSHartmut Brandt /* 1925f06ca4afSHartmut Brandt * Insert ordered 1926f06ca4afSHartmut Brandt */ 1927f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 1928f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 1929f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 1930f06ca4afSHartmut Brandt break; 1931f06ca4afSHartmut Brandt } 1932f06ca4afSHartmut Brandt } 1933f06ca4afSHartmut Brandt if (p == NULL) 1934f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 1935f06ca4afSHartmut Brandt return (c->value); 1936f06ca4afSHartmut Brandt } 1937f06ca4afSHartmut Brandt 1938f06ca4afSHartmut Brandt const char * 1939f06ca4afSHartmut Brandt comm_string(u_int ncomm) 1940f06ca4afSHartmut Brandt { 1941f06ca4afSHartmut Brandt struct community *p; 1942f06ca4afSHartmut Brandt 1943f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 1944f06ca4afSHartmut Brandt if (p->value == ncomm) 1945f06ca4afSHartmut Brandt return (p->string); 1946f06ca4afSHartmut Brandt return (NULL); 1947f06ca4afSHartmut Brandt } 1948f06ca4afSHartmut Brandt 1949f06ca4afSHartmut Brandt /* 1950f06ca4afSHartmut Brandt * Delete all communities allocated by a module 1951f06ca4afSHartmut Brandt */ 1952f06ca4afSHartmut Brandt static void 1953f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 1954f06ca4afSHartmut Brandt { 1955f06ca4afSHartmut Brandt struct community *p, *p1; 1956f06ca4afSHartmut Brandt 1957f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 1958f06ca4afSHartmut Brandt while (p != NULL) { 1959f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 1960f06ca4afSHartmut Brandt if (p->owner == mod) { 1961f06ca4afSHartmut Brandt free(p->string); 1962f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 1963f06ca4afSHartmut Brandt free(p); 1964f06ca4afSHartmut Brandt } 1965f06ca4afSHartmut Brandt p = p1; 1966f06ca4afSHartmut Brandt } 1967f06ca4afSHartmut Brandt } 1968f06ca4afSHartmut Brandt 1969f06ca4afSHartmut Brandt /* 1970f06ca4afSHartmut Brandt * Request ID handling. 1971f06ca4afSHartmut Brandt * 1972f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 1973f06ca4afSHartmut Brandt */ 1974f06ca4afSHartmut Brandt u_int 1975f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 1976f06ca4afSHartmut Brandt { 1977f06ca4afSHartmut Brandt u_int type; 1978f06ca4afSHartmut Brandt struct idrange *r, *r1; 1979f06ca4afSHartmut Brandt 1980f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 1981f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1982f06ca4afSHartmut Brandt return (0); 1983f06ca4afSHartmut Brandt } 1984f06ca4afSHartmut Brandt /* allocate a type id */ 1985f06ca4afSHartmut Brandt do { 1986f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 1987f06ca4afSHartmut Brandt next_idrange = 1; 1988f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1989f06ca4afSHartmut Brandt if (r->type == type) 1990f06ca4afSHartmut Brandt break; 1991f06ca4afSHartmut Brandt } while(r != NULL); 1992f06ca4afSHartmut Brandt 1993f06ca4afSHartmut Brandt /* find a range */ 1994f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 1995f06ca4afSHartmut Brandt r = NULL; 1996f06ca4afSHartmut Brandt else { 1997f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 1998f06ca4afSHartmut Brandt if (r->base < size) { 1999f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2000f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 2001f06ca4afSHartmut Brandt break; 2002f06ca4afSHartmut Brandt r = r1; 2003f06ca4afSHartmut Brandt } 2004f06ca4afSHartmut Brandt r = r1; 2005f06ca4afSHartmut Brandt } 2006f06ca4afSHartmut Brandt if (r == NULL) { 2007f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2008f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2009f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2010f06ca4afSHartmut Brandt return (0); 2011f06ca4afSHartmut Brandt } 2012f06ca4afSHartmut Brandt } 2013f06ca4afSHartmut Brandt } 2014f06ca4afSHartmut Brandt 2015f06ca4afSHartmut Brandt /* allocate structure */ 2016f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2017f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2018f06ca4afSHartmut Brandt return (0); 2019f06ca4afSHartmut Brandt } 2020f06ca4afSHartmut Brandt 2021f06ca4afSHartmut Brandt r1->type = type; 2022f06ca4afSHartmut Brandt r1->size = size; 2023f06ca4afSHartmut Brandt r1->owner = mod; 2024f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2025f06ca4afSHartmut Brandt r1->base = 0; 2026f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2027f06ca4afSHartmut Brandt } else if (r == NULL) { 2028f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2029f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2030f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2031f06ca4afSHartmut Brandt } else { 2032f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2033f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2034f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2035f06ca4afSHartmut Brandt } 2036f06ca4afSHartmut Brandt r1->next = r1->base; 2037f06ca4afSHartmut Brandt 2038f06ca4afSHartmut Brandt return (type); 2039f06ca4afSHartmut Brandt } 2040f06ca4afSHartmut Brandt 2041f06ca4afSHartmut Brandt int32_t 2042f06ca4afSHartmut Brandt reqid_next(u_int type) 2043f06ca4afSHartmut Brandt { 2044f06ca4afSHartmut Brandt struct idrange *r; 2045f06ca4afSHartmut Brandt int32_t id; 2046f06ca4afSHartmut Brandt 2047f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2048f06ca4afSHartmut Brandt if (r->type == type) 2049f06ca4afSHartmut Brandt break; 2050f06ca4afSHartmut Brandt if (r == NULL) { 2051f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2052f06ca4afSHartmut Brandt abort(); 2053f06ca4afSHartmut Brandt } 2054f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2055f06ca4afSHartmut Brandt r->next = r->base; 2056f06ca4afSHartmut Brandt return (id); 2057f06ca4afSHartmut Brandt } 2058f06ca4afSHartmut Brandt 2059f06ca4afSHartmut Brandt int32_t 2060f06ca4afSHartmut Brandt reqid_base(u_int type) 2061f06ca4afSHartmut Brandt { 2062f06ca4afSHartmut Brandt struct idrange *r; 2063f06ca4afSHartmut Brandt 2064f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2065f06ca4afSHartmut Brandt if (r->type == type) 2066f06ca4afSHartmut Brandt return (r->base); 2067f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2068f06ca4afSHartmut Brandt abort(); 2069f06ca4afSHartmut Brandt } 2070f06ca4afSHartmut Brandt 2071f06ca4afSHartmut Brandt u_int 2072f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2073f06ca4afSHartmut Brandt { 2074f06ca4afSHartmut Brandt struct idrange *r; 2075f06ca4afSHartmut Brandt 2076f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2077f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2078f06ca4afSHartmut Brandt return (r->type); 2079f06ca4afSHartmut Brandt return (0); 2080f06ca4afSHartmut Brandt } 2081f06ca4afSHartmut Brandt 2082f06ca4afSHartmut Brandt int 2083f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2084f06ca4afSHartmut Brandt { 2085f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2086f06ca4afSHartmut Brandt } 2087f06ca4afSHartmut Brandt 2088f06ca4afSHartmut Brandt /* 2089f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2090f06ca4afSHartmut Brandt */ 2091f06ca4afSHartmut Brandt static void 2092f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2093f06ca4afSHartmut Brandt { 2094f06ca4afSHartmut Brandt struct idrange *p, *p1; 2095f06ca4afSHartmut Brandt 2096f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2097f06ca4afSHartmut Brandt while (p != NULL) { 2098f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2099f06ca4afSHartmut Brandt if (p->owner == mod) { 2100f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2101f06ca4afSHartmut Brandt free(p); 2102f06ca4afSHartmut Brandt } 2103f06ca4afSHartmut Brandt p = p1; 2104f06ca4afSHartmut Brandt } 2105f06ca4afSHartmut Brandt } 2106f06ca4afSHartmut Brandt 2107f06ca4afSHartmut Brandt /* 2108f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2109f06ca4afSHartmut Brandt */ 2110f06ca4afSHartmut Brandt static int 2111f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2112f06ca4afSHartmut Brandt { 2113f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2114f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2115f06ca4afSHartmut Brandt 2116f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2117f06ca4afSHartmut Brandt } 2118f06ca4afSHartmut Brandt static int 2119f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2120f06ca4afSHartmut Brandt { 2121f06ca4afSHartmut Brandt struct snmp_node *xtree; 2122f06ca4afSHartmut Brandt u_int i; 2123f06ca4afSHartmut Brandt 2124f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2125f06ca4afSHartmut Brandt if (xtree == NULL) { 21268eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2127f06ca4afSHartmut Brandt return (-1); 2128f06ca4afSHartmut Brandt } 2129f06ca4afSHartmut Brandt tree = xtree; 2130f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2131f06ca4afSHartmut Brandt 2132f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 21338eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2134f06ca4afSHartmut Brandt 2135f06ca4afSHartmut Brandt tree_size += nsize; 2136f06ca4afSHartmut Brandt 2137f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2138f06ca4afSHartmut Brandt 2139f06ca4afSHartmut Brandt return (0); 2140f06ca4afSHartmut Brandt } 2141f06ca4afSHartmut Brandt 2142f06ca4afSHartmut Brandt /* 2143f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2144f06ca4afSHartmut Brandt */ 2145f06ca4afSHartmut Brandt static void 2146f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2147f06ca4afSHartmut Brandt { 2148f06ca4afSHartmut Brandt u_int s, d; 2149f06ca4afSHartmut Brandt 2150f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 21518eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2152f06ca4afSHartmut Brandt if (s != d) 2153f06ca4afSHartmut Brandt tree[d] = tree[s]; 2154f06ca4afSHartmut Brandt d++; 2155f06ca4afSHartmut Brandt } 2156f06ca4afSHartmut Brandt tree_size = d; 2157f06ca4afSHartmut Brandt } 2158f06ca4afSHartmut Brandt 2159f06ca4afSHartmut Brandt /* 2160f06ca4afSHartmut Brandt * Loadable modules 2161f06ca4afSHartmut Brandt */ 2162f06ca4afSHartmut Brandt struct lmodule * 2163f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2164f06ca4afSHartmut Brandt { 2165f06ca4afSHartmut Brandt struct lmodule *m; 2166f06ca4afSHartmut Brandt int err; 2167f06ca4afSHartmut Brandt int i; 2168f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2169f06ca4afSHartmut Brandt int ac; 2170f06ca4afSHartmut Brandt u_int u; 2171f06ca4afSHartmut Brandt 2172f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2173f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2174f06ca4afSHartmut Brandt return (NULL); 2175f06ca4afSHartmut Brandt } 2176f06ca4afSHartmut Brandt m->handle = NULL; 2177f06ca4afSHartmut Brandt m->flags = 0; 2178f06ca4afSHartmut Brandt strcpy(m->section, section); 2179f06ca4afSHartmut Brandt 2180f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2181f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2182f06ca4afSHartmut Brandt goto err; 2183f06ca4afSHartmut Brandt } 2184f06ca4afSHartmut Brandt strcpy(m->path, path); 2185f06ca4afSHartmut Brandt 2186f06ca4afSHartmut Brandt /* 2187f06ca4afSHartmut Brandt * Make index 2188f06ca4afSHartmut Brandt */ 2189f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2190f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2191f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2192f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2193f06ca4afSHartmut Brandt 2194f06ca4afSHartmut Brandt /* 2195f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2196f06ca4afSHartmut Brandt */ 2197f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2198f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2199f06ca4afSHartmut Brandt goto err; 2200f06ca4afSHartmut Brandt } 2201f06ca4afSHartmut Brandt 2202f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2203f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2204f06ca4afSHartmut Brandt goto err; 2205f06ca4afSHartmut Brandt } 2206f06ca4afSHartmut Brandt 2207f06ca4afSHartmut Brandt /* 2208f06ca4afSHartmut Brandt * Insert it into the right place 2209f06ca4afSHartmut Brandt */ 2210f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2211f06ca4afSHartmut Brandt 2212f06ca4afSHartmut Brandt /* preserve order */ 2213f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2214f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2215f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2216f06ca4afSHartmut Brandt } 2217f06ca4afSHartmut Brandt 2218f06ca4afSHartmut Brandt /* 2219f06ca4afSHartmut Brandt * make the argument vector. 2220f06ca4afSHartmut Brandt */ 2221f06ca4afSHartmut Brandt ac = 0; 2222f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2223f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2224f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2225f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2226f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2227f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2228f06ca4afSHartmut Brandt "module '%s", section); 2229f06ca4afSHartmut Brandt break; 2230f06ca4afSHartmut Brandt } 2231f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2232f06ca4afSHartmut Brandt } 2233f06ca4afSHartmut Brandt } 2234f06ca4afSHartmut Brandt av[ac] = NULL; 2235f06ca4afSHartmut Brandt 2236f06ca4afSHartmut Brandt /* 2237165c5d31SHartmut Brandt * Run the initialization function 2238f06ca4afSHartmut Brandt */ 2239f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2240f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2241f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2242f06ca4afSHartmut Brandt goto err; 2243f06ca4afSHartmut Brandt } 2244f06ca4afSHartmut Brandt 2245f06ca4afSHartmut Brandt return (m); 2246f06ca4afSHartmut Brandt 2247f06ca4afSHartmut Brandt err: 2248f06ca4afSHartmut Brandt if (m->handle) 2249f06ca4afSHartmut Brandt dlclose(m->handle); 2250f06ca4afSHartmut Brandt free(m->path); 2251f06ca4afSHartmut Brandt free(m); 2252f06ca4afSHartmut Brandt return (NULL); 2253f06ca4afSHartmut Brandt } 2254f06ca4afSHartmut Brandt 2255f06ca4afSHartmut Brandt /* 2256f06ca4afSHartmut Brandt * Start a module 2257f06ca4afSHartmut Brandt */ 2258f06ca4afSHartmut Brandt void 2259f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2260f06ca4afSHartmut Brandt { 2261f06ca4afSHartmut Brandt const struct lmodule *m; 2262f06ca4afSHartmut Brandt 2263f06ca4afSHartmut Brandt /* 2264f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2265f06ca4afSHartmut Brandt */ 2266f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2267f06ca4afSHartmut Brandt lm_unload(mod); 2268f06ca4afSHartmut Brandt return; 2269f06ca4afSHartmut Brandt } 2270f06ca4afSHartmut Brandt 2271f06ca4afSHartmut Brandt /* 2272f06ca4afSHartmut Brandt * Read configuration 2273f06ca4afSHartmut Brandt */ 2274f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2275f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2276f06ca4afSHartmut Brandt lm_unload(mod); 2277f06ca4afSHartmut Brandt return; 2278f06ca4afSHartmut Brandt } 2279f06ca4afSHartmut Brandt if (mod->config->start) 2280f06ca4afSHartmut Brandt (*mod->config->start)(); 2281f06ca4afSHartmut Brandt 2282f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2283f06ca4afSHartmut Brandt 2284f06ca4afSHartmut Brandt /* 2285f06ca4afSHartmut Brandt * Inform other modules 2286f06ca4afSHartmut Brandt */ 2287f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2288f06ca4afSHartmut Brandt if (m->config->loading) 2289f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2290f06ca4afSHartmut Brandt } 2291f06ca4afSHartmut Brandt 2292f06ca4afSHartmut Brandt 2293f06ca4afSHartmut Brandt /* 2294f06ca4afSHartmut Brandt * Unload a module. 2295f06ca4afSHartmut Brandt */ 2296f06ca4afSHartmut Brandt void 2297f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2298f06ca4afSHartmut Brandt { 2299f06ca4afSHartmut Brandt int err; 2300f06ca4afSHartmut Brandt const struct lmodule *mod; 2301f06ca4afSHartmut Brandt 2302f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2303f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2304f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2305f06ca4afSHartmut Brandt tree_unmerge(m); 2306f06ca4afSHartmut Brandt 2307f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2308f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2309f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2310f06ca4afSHartmut Brandt 2311f06ca4afSHartmut Brandt comm_flush(m); 2312f06ca4afSHartmut Brandt reqid_flush(m); 2313f06ca4afSHartmut Brandt timer_flush(m); 2314f06ca4afSHartmut Brandt fd_flush(m); 2315f06ca4afSHartmut Brandt 2316f06ca4afSHartmut Brandt dlclose(m->handle); 2317f06ca4afSHartmut Brandt free(m->path); 2318f06ca4afSHartmut Brandt 2319f06ca4afSHartmut Brandt /* 2320f06ca4afSHartmut Brandt * Inform other modules 2321f06ca4afSHartmut Brandt */ 2322f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2323f06ca4afSHartmut Brandt if (mod->config->loading) 2324f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2325f06ca4afSHartmut Brandt 2326f06ca4afSHartmut Brandt free(m); 2327f06ca4afSHartmut Brandt } 2328f06ca4afSHartmut Brandt 2329f06ca4afSHartmut Brandt /* 2330f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2331f06ca4afSHartmut Brandt */ 2332f06ca4afSHartmut Brandt u_int 2333f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2334f06ca4afSHartmut Brandt { 2335f06ca4afSHartmut Brandt struct objres *objres, *or1; 2336f06ca4afSHartmut Brandt u_int idx; 2337f06ca4afSHartmut Brandt 2338f06ca4afSHartmut Brandt /* find a free index */ 2339f06ca4afSHartmut Brandt idx = 1; 2340f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2341f06ca4afSHartmut Brandt objres != NULL; 2342f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2343f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2344f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2345f06ca4afSHartmut Brandt idx = objres->index + 1; 2346f06ca4afSHartmut Brandt break; 2347f06ca4afSHartmut Brandt } 2348f06ca4afSHartmut Brandt } 2349f06ca4afSHartmut Brandt 2350f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2351f06ca4afSHartmut Brandt return (0); 2352f06ca4afSHartmut Brandt 2353f06ca4afSHartmut Brandt objres->index = idx; 2354f06ca4afSHartmut Brandt objres->oid = *or; 2355f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 235669292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2357f06ca4afSHartmut Brandt objres->module = mod; 2358f06ca4afSHartmut Brandt 2359f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2360f06ca4afSHartmut Brandt 2361f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2362f06ca4afSHartmut Brandt 2363f06ca4afSHartmut Brandt return (idx); 2364f06ca4afSHartmut Brandt } 2365f06ca4afSHartmut Brandt 2366f06ca4afSHartmut Brandt void 2367f06ca4afSHartmut Brandt or_unregister(u_int idx) 2368f06ca4afSHartmut Brandt { 2369f06ca4afSHartmut Brandt struct objres *objres; 2370f06ca4afSHartmut Brandt 2371f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2372f06ca4afSHartmut Brandt if (objres->index == idx) { 2373f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2374f06ca4afSHartmut Brandt free(objres); 2375f06ca4afSHartmut Brandt return; 2376f06ca4afSHartmut Brandt } 2377f06ca4afSHartmut Brandt } 2378