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 * 29896052c1SHartmut Brandt * $Begemot: bsnmp/snmpd/main.c,v 1.89 2004/08/06 08:47:11 brandt 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> 36f06ca4afSHartmut Brandt #include <stdio.h> 37f06ca4afSHartmut Brandt #include <stdlib.h> 38f06ca4afSHartmut Brandt #include <stddef.h> 39f06ca4afSHartmut Brandt #include <string.h> 40f06ca4afSHartmut Brandt #include <stdarg.h> 41f06ca4afSHartmut Brandt #include <ctype.h> 42f06ca4afSHartmut Brandt #include <errno.h> 43f06ca4afSHartmut Brandt #include <syslog.h> 44f06ca4afSHartmut Brandt #include <unistd.h> 45f06ca4afSHartmut Brandt #include <signal.h> 46f06ca4afSHartmut Brandt #include <dlfcn.h> 47f06ca4afSHartmut Brandt #include <inttypes.h> 48f06ca4afSHartmut Brandt 49f06ca4afSHartmut Brandt #include "snmpmod.h" 50f06ca4afSHartmut Brandt #include "snmpd.h" 51f06ca4afSHartmut Brandt #include "tree.h" 52f06ca4afSHartmut Brandt #include "oid.h" 53f06ca4afSHartmut Brandt 54f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 55f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 56f06ca4afSHartmut Brandt 57f06ca4afSHartmut Brandt u_int32_t this_tick; /* start of processing of current packet */ 58f06ca4afSHartmut Brandt u_int32_t start_tick; /* start of processing */ 59f06ca4afSHartmut Brandt 60f06ca4afSHartmut Brandt struct systemg systemg = { 61f06ca4afSHartmut Brandt NULL, 62f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 63f06ca4afSHartmut Brandt NULL, NULL, NULL, 64f06ca4afSHartmut Brandt 64 + 8 + 4, 65f06ca4afSHartmut Brandt 0 66f06ca4afSHartmut Brandt }; 67f06ca4afSHartmut Brandt struct debug debug = { 68f06ca4afSHartmut Brandt 0, /* dump_pdus */ 69f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 70f06ca4afSHartmut Brandt 0, /* evdebug */ 71f06ca4afSHartmut Brandt }; 72f06ca4afSHartmut Brandt 73f06ca4afSHartmut Brandt struct snmpd snmpd = { 74f06ca4afSHartmut Brandt 2048, /* txbuf */ 75f06ca4afSHartmut Brandt 2048, /* rxbuf */ 76f06ca4afSHartmut Brandt 0, /* comm_dis */ 77f06ca4afSHartmut Brandt 0, /* auth_traps */ 78f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 7970af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 80f06ca4afSHartmut Brandt }; 81f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 82f06ca4afSHartmut Brandt 83f06ca4afSHartmut Brandt /* snmpSerialNo */ 84f06ca4afSHartmut Brandt int32_t snmp_serial_no; 85f06ca4afSHartmut Brandt 86f06ca4afSHartmut Brandt /* search path for config files */ 87f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 88f06ca4afSHartmut Brandt 89f06ca4afSHartmut Brandt /* list of all loaded modules */ 90f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 91f06ca4afSHartmut Brandt 92f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 93f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 94f06ca4afSHartmut Brandt 95f06ca4afSHartmut Brandt /* list of all known communities */ 96f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 97f06ca4afSHartmut Brandt 98f06ca4afSHartmut Brandt /* list of all installed object resources */ 99f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 100f06ca4afSHartmut Brandt 101f06ca4afSHartmut Brandt /* community value generator */ 102f06ca4afSHartmut Brandt static u_int next_community_index = 1; 103f06ca4afSHartmut Brandt 104f06ca4afSHartmut Brandt /* list of all known ranges */ 105f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 106f06ca4afSHartmut Brandt 107f06ca4afSHartmut Brandt /* identifier generator */ 108f06ca4afSHartmut Brandt u_int next_idrange = 1; 109f06ca4afSHartmut Brandt 110f06ca4afSHartmut Brandt /* list of all current timers */ 111f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 112f06ca4afSHartmut Brandt 113f06ca4afSHartmut Brandt /* list of file descriptors */ 114f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 115f06ca4afSHartmut Brandt 116f06ca4afSHartmut Brandt /* program arguments */ 117f06ca4afSHartmut Brandt static char **progargs; 118f06ca4afSHartmut Brandt static int nprogargs; 119f06ca4afSHartmut Brandt 120f06ca4afSHartmut Brandt /* current community */ 121f06ca4afSHartmut Brandt u_int community; 122f06ca4afSHartmut Brandt static struct community *comm; 123f06ca4afSHartmut Brandt 124f06ca4afSHartmut Brandt /* file names */ 125f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 126f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 127f06ca4afSHartmut Brandt 12870af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 129f06ca4afSHartmut Brandt /* event context */ 130f06ca4afSHartmut Brandt static evContext evctx; 13170af00a1SHartmut Brandt #endif 132f06ca4afSHartmut Brandt 133f06ca4afSHartmut Brandt /* signal mask */ 134f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 135f06ca4afSHartmut Brandt 136f06ca4afSHartmut Brandt /* signal handling */ 137f06ca4afSHartmut Brandt static int work; 138f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 139f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 140f06ca4afSHartmut Brandt 141f06ca4afSHartmut Brandt /* oids */ 142f06ca4afSHartmut Brandt static const struct asn_oid 143f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 144f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 145f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 146f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 147f06ca4afSHartmut Brandt 148f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 149f06ca4afSHartmut Brandt 150f06ca4afSHartmut Brandt /* request id generator for traps */ 151f06ca4afSHartmut Brandt u_int trap_reqid; 152f06ca4afSHartmut Brandt 153f06ca4afSHartmut Brandt /* help text */ 154f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 155f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 156f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 157f06ca4afSHartmut Brandt usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 158f06ca4afSHartmut Brandt [-m variable=value] [-p file]\n\ 159f06ca4afSHartmut Brandt options:\n\ 160f06ca4afSHartmut Brandt -d don't daemonize\n\ 161f06ca4afSHartmut Brandt -h print this info\n\ 162f06ca4afSHartmut Brandt -c file specify configuration file\n\ 163f06ca4afSHartmut Brandt -D options debugging options\n\ 164f06ca4afSHartmut Brandt -I path system include path\n\ 165f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 166f06ca4afSHartmut Brandt -m var=val define variable\n\ 167f06ca4afSHartmut Brandt -p file specify pid file\n\ 168f06ca4afSHartmut Brandt "; 169f06ca4afSHartmut Brandt 17070af00a1SHartmut Brandt /* transports */ 17170af00a1SHartmut Brandt extern const struct transport_def udp_trans; 17270af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 17370af00a1SHartmut Brandt 17470af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 17570af00a1SHartmut Brandt 176f06ca4afSHartmut Brandt /* forward declarations */ 177f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 178f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 179f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 180f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 181f06ca4afSHartmut Brandt 182f06ca4afSHartmut Brandt /* 183f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 184f06ca4afSHartmut Brandt */ 185f06ca4afSHartmut Brandt void * 186f06ca4afSHartmut Brandt buf_alloc(int tx) 187f06ca4afSHartmut Brandt { 188f06ca4afSHartmut Brandt void *buf; 189f06ca4afSHartmut Brandt 19070af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 191f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 192f06ca4afSHartmut Brandt if (tx) 193f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 194f06ca4afSHartmut Brandt else 195f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 196f06ca4afSHartmut Brandt return (NULL); 197f06ca4afSHartmut Brandt } 198f06ca4afSHartmut Brandt return (buf); 199f06ca4afSHartmut Brandt } 200f06ca4afSHartmut Brandt 201f06ca4afSHartmut Brandt /* 20270af00a1SHartmut Brandt * Return the buffer size. 203f06ca4afSHartmut Brandt */ 204f06ca4afSHartmut Brandt size_t 205f06ca4afSHartmut Brandt buf_size(int tx) 206f06ca4afSHartmut Brandt { 20770af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 208f06ca4afSHartmut Brandt } 209f06ca4afSHartmut Brandt 210f06ca4afSHartmut Brandt /* 211f06ca4afSHartmut Brandt * Prepare a PDU for output 212f06ca4afSHartmut Brandt */ 213f06ca4afSHartmut Brandt void 21470af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 215f06ca4afSHartmut Brandt const char *dest) 216f06ca4afSHartmut Brandt { 217f06ca4afSHartmut Brandt struct asn_buf resp_b; 218f06ca4afSHartmut Brandt 219f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 220f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 221f06ca4afSHartmut Brandt 222f06ca4afSHartmut Brandt if (snmp_pdu_encode(pdu, &resp_b) != 0) { 223f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot encode message"); 224f06ca4afSHartmut Brandt abort(); 225f06ca4afSHartmut Brandt } 226f06ca4afSHartmut Brandt if (debug.dump_pdus) { 227f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 228f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 229f06ca4afSHartmut Brandt } 230f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 231f06ca4afSHartmut Brandt } 232f06ca4afSHartmut Brandt 233f06ca4afSHartmut Brandt /* 234f06ca4afSHartmut Brandt * SNMP input. Start: decode the PDU, find the community. 235f06ca4afSHartmut Brandt */ 236f06ca4afSHartmut Brandt enum snmpd_input_err 237f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 23870af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 239f06ca4afSHartmut Brandt { 240f06ca4afSHartmut Brandt struct asn_buf b; 241f06ca4afSHartmut Brandt enum snmp_code code; 242f06ca4afSHartmut Brandt enum snmpd_input_err ret; 24370af00a1SHartmut Brandt int sret; 244f06ca4afSHartmut Brandt 245f06ca4afSHartmut Brandt b.asn_cptr = buf; 246f06ca4afSHartmut Brandt b.asn_len = len; 24770af00a1SHartmut Brandt 24870af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 24970af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 25070af00a1SHartmut Brandt 25170af00a1SHartmut Brandt case 0: 25270af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 25370af00a1SHartmut Brandt 25470af00a1SHartmut Brandt case -1: 25570af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 25670af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 25770af00a1SHartmut Brandt } 25870af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 25970af00a1SHartmut Brandt 260f06ca4afSHartmut Brandt code = snmp_pdu_decode(&b, pdu, ip); 261f06ca4afSHartmut Brandt 26270af00a1SHartmut Brandt snmpd_stats.inPkts++; 26370af00a1SHartmut Brandt 264f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 265f06ca4afSHartmut Brandt switch (code) { 266f06ca4afSHartmut Brandt 267f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 268f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 269f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 270f06ca4afSHartmut Brandt 271f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 27270af00a1SHartmut Brandt bad_vers: 273f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 274f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 275f06ca4afSHartmut Brandt 276f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 277f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 278f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 279f06ca4afSHartmut Brandt break; 280f06ca4afSHartmut Brandt 281f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 282f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 283f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 284f06ca4afSHartmut Brandt break; 285f06ca4afSHartmut Brandt 286f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 287f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 288f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 289f06ca4afSHartmut Brandt break; 290f06ca4afSHartmut Brandt 291f06ca4afSHartmut Brandt case SNMP_CODE_OK: 29270af00a1SHartmut Brandt switch (pdu->version) { 29370af00a1SHartmut Brandt 29470af00a1SHartmut Brandt case SNMP_V1: 29570af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 29670af00a1SHartmut Brandt goto bad_vers; 29770af00a1SHartmut Brandt break; 29870af00a1SHartmut Brandt 29970af00a1SHartmut Brandt case SNMP_V2c: 30070af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 30170af00a1SHartmut Brandt goto bad_vers; 30270af00a1SHartmut Brandt break; 30370af00a1SHartmut Brandt 30470af00a1SHartmut Brandt case SNMP_Verr: 30570af00a1SHartmut Brandt goto bad_vers; 30670af00a1SHartmut Brandt } 307f06ca4afSHartmut Brandt break; 308f06ca4afSHartmut Brandt } 309f06ca4afSHartmut Brandt 310f06ca4afSHartmut Brandt if (debug.dump_pdus) { 311f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 312f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 313f06ca4afSHartmut Brandt } 314f06ca4afSHartmut Brandt 315f06ca4afSHartmut Brandt /* 316f06ca4afSHartmut Brandt * Look, whether we know the community 317f06ca4afSHartmut Brandt */ 318f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 319f06ca4afSHartmut Brandt if (comm->string != NULL && 320f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 321f06ca4afSHartmut Brandt break; 322f06ca4afSHartmut Brandt 323f06ca4afSHartmut Brandt if (comm == NULL) { 324f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 325f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 326f06ca4afSHartmut Brandt if (snmpd.auth_traps) 327896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 328896052c1SHartmut Brandt (struct snmp_value *)NULL); 329896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 330896052c1SHartmut Brandt } else 331f06ca4afSHartmut Brandt community = comm->value; 332f06ca4afSHartmut Brandt 333f06ca4afSHartmut Brandt /* update uptime */ 334f06ca4afSHartmut Brandt this_tick = get_ticks(); 335f06ca4afSHartmut Brandt 336f06ca4afSHartmut Brandt return (ret); 337f06ca4afSHartmut Brandt } 338f06ca4afSHartmut Brandt 339f06ca4afSHartmut Brandt /* 340f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 341f06ca4afSHartmut Brandt */ 342f06ca4afSHartmut Brandt enum snmpd_input_err 343f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 344f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 345f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 346f06ca4afSHartmut Brandt { 347f06ca4afSHartmut Brandt struct snmp_pdu resp; 348f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 349f06ca4afSHartmut Brandt enum snmp_ret ret; 350f06ca4afSHartmut Brandt 351f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 352f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 353f06ca4afSHartmut Brandt 354f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 355f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 356f06ca4afSHartmut Brandt 357f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 358f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 359f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 360f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 361f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 362f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 363f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 364f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 365f06ca4afSHartmut Brandt else 366f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 367f06ca4afSHartmut Brandt 368f06ca4afSHartmut Brandt pdu->error_index = ivar; 369f06ca4afSHartmut Brandt 370f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 371f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 372f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 373f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 374f06ca4afSHartmut Brandt } 375f06ca4afSHartmut Brandt 376f06ca4afSHartmut Brandt if (debug.dump_pdus) { 377f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 378f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 379f06ca4afSHartmut Brandt } 380f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 381f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 382f06ca4afSHartmut Brandt } 383f06ca4afSHartmut Brandt 384f06ca4afSHartmut Brandt switch (pdu->type) { 385f06ca4afSHartmut Brandt 386f06ca4afSHartmut Brandt case SNMP_PDU_GET: 387f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 388f06ca4afSHartmut Brandt break; 389f06ca4afSHartmut Brandt 390f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 391f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 392f06ca4afSHartmut Brandt break; 393f06ca4afSHartmut Brandt 394f06ca4afSHartmut Brandt case SNMP_PDU_SET: 395f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 396f06ca4afSHartmut Brandt break; 397f06ca4afSHartmut Brandt 398f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 399f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 400f06ca4afSHartmut Brandt break; 401f06ca4afSHartmut Brandt 402f06ca4afSHartmut Brandt default: 403f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 404f06ca4afSHartmut Brandt break; 405f06ca4afSHartmut Brandt } 406f06ca4afSHartmut Brandt 407f06ca4afSHartmut Brandt switch (ret) { 408f06ca4afSHartmut Brandt 409f06ca4afSHartmut Brandt case SNMP_RET_OK: 410f06ca4afSHartmut Brandt /* normal return - send a response */ 411f06ca4afSHartmut Brandt if (debug.dump_pdus) { 412f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 413f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 414f06ca4afSHartmut Brandt } 415f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 416f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 417f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 418f06ca4afSHartmut Brandt 419f06ca4afSHartmut Brandt case SNMP_RET_IGN: 420f06ca4afSHartmut Brandt /* error - send nothing */ 421f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 422f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 423f06ca4afSHartmut Brandt 424f06ca4afSHartmut Brandt case SNMP_RET_ERR: 425f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 426f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 427f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 428f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 429f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 430f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 431f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 432f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 433f06ca4afSHartmut Brandt } else { 434f06ca4afSHartmut Brandt if (debug.dump_pdus) { 435f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 436f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 437f06ca4afSHartmut Brandt } 438f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 439f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 440f06ca4afSHartmut Brandt } 441f06ca4afSHartmut Brandt } 442f06ca4afSHartmut Brandt abort(); 443f06ca4afSHartmut Brandt } 444f06ca4afSHartmut Brandt 44570af00a1SHartmut Brandt /* 44670af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 44770af00a1SHartmut Brandt */ 44870af00a1SHartmut Brandt void 44970af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 45070af00a1SHartmut Brandt { 45170af00a1SHartmut Brandt struct tport *p; 452f06ca4afSHartmut Brandt 45370af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 45470af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 45570af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 45670af00a1SHartmut Brandt return; 45770af00a1SHartmut Brandt } 45870af00a1SHartmut Brandt } 45970af00a1SHartmut Brandt port->transport = t; 46070af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 46170af00a1SHartmut Brandt } 46270af00a1SHartmut Brandt 46370af00a1SHartmut Brandt /* 46470af00a1SHartmut Brandt * Remove a port from a transport's list 46570af00a1SHartmut Brandt */ 46670af00a1SHartmut Brandt void 46770af00a1SHartmut Brandt trans_remove_port(struct tport *port) 46870af00a1SHartmut Brandt { 46970af00a1SHartmut Brandt 47070af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 47170af00a1SHartmut Brandt } 47270af00a1SHartmut Brandt 47370af00a1SHartmut Brandt /* 47470af00a1SHartmut Brandt * Find a port on a transport's list 47570af00a1SHartmut Brandt */ 47670af00a1SHartmut Brandt struct tport * 47770af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 47870af00a1SHartmut Brandt { 47970af00a1SHartmut Brandt 48070af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 48170af00a1SHartmut Brandt } 48270af00a1SHartmut Brandt 48370af00a1SHartmut Brandt /* 48470af00a1SHartmut Brandt * Find next port on a transport's list 48570af00a1SHartmut Brandt */ 48670af00a1SHartmut Brandt struct tport * 48770af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 48870af00a1SHartmut Brandt { 48970af00a1SHartmut Brandt 49070af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 49170af00a1SHartmut Brandt } 49270af00a1SHartmut Brandt 49370af00a1SHartmut Brandt /* 49470af00a1SHartmut Brandt * Return first port 49570af00a1SHartmut Brandt */ 49670af00a1SHartmut Brandt struct tport * 49770af00a1SHartmut Brandt trans_first_port(struct transport *t) 49870af00a1SHartmut Brandt { 49970af00a1SHartmut Brandt 50070af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 50170af00a1SHartmut Brandt } 50270af00a1SHartmut Brandt 50370af00a1SHartmut Brandt /* 50470af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 50570af00a1SHartmut Brandt */ 50670af00a1SHartmut Brandt struct tport * 50770af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 50870af00a1SHartmut Brandt intptr_t arg) 50970af00a1SHartmut Brandt { 51070af00a1SHartmut Brandt struct tport *p; 51170af00a1SHartmut Brandt 51270af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 51370af00a1SHartmut Brandt if (func(p, arg) == 0) 51470af00a1SHartmut Brandt return (p); 51570af00a1SHartmut Brandt return (NULL); 51670af00a1SHartmut Brandt } 51770af00a1SHartmut Brandt 51870af00a1SHartmut Brandt /* 51970af00a1SHartmut Brandt * Register a transport 52070af00a1SHartmut Brandt */ 52170af00a1SHartmut Brandt int 52270af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 52370af00a1SHartmut Brandt { 52470af00a1SHartmut Brandt u_int i; 52570af00a1SHartmut Brandt char or_descr[256]; 52670af00a1SHartmut Brandt 52770af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 52870af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 52970af00a1SHartmut Brandt 53070af00a1SHartmut Brandt /* construct index */ 53170af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 53270af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 53370af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 53470af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 53570af00a1SHartmut Brandt 53670af00a1SHartmut Brandt (*pp)->vtab = def; 53770af00a1SHartmut Brandt 53870af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 53970af00a1SHartmut Brandt free(*pp); 54070af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 54170af00a1SHartmut Brandt } 54270af00a1SHartmut Brandt 54370af00a1SHartmut Brandt /* register module */ 54470af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 54570af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 54670af00a1SHartmut Brandt free(*pp); 54770af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 54870af00a1SHartmut Brandt } 54970af00a1SHartmut Brandt 55070af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 55170af00a1SHartmut Brandt 55270af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 55370af00a1SHartmut Brandt 55470af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 55570af00a1SHartmut Brandt } 55670af00a1SHartmut Brandt 55770af00a1SHartmut Brandt /* 55870af00a1SHartmut Brandt * Unregister transport 55970af00a1SHartmut Brandt */ 56070af00a1SHartmut Brandt int 56170af00a1SHartmut Brandt trans_unregister(struct transport *t) 56270af00a1SHartmut Brandt { 56370af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 56470af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 56570af00a1SHartmut Brandt 56670af00a1SHartmut Brandt or_unregister(t->or_index); 56770af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 56870af00a1SHartmut Brandt 56970af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 57070af00a1SHartmut Brandt } 571f06ca4afSHartmut Brandt 572f06ca4afSHartmut Brandt /* 573f06ca4afSHartmut Brandt * File descriptor support 574f06ca4afSHartmut Brandt */ 57570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 57670af00a1SHartmut Brandt static void 57770af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 57870af00a1SHartmut Brandt #else 579f06ca4afSHartmut Brandt static void 580f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 58170af00a1SHartmut Brandt #endif 582f06ca4afSHartmut Brandt { 583f06ca4afSHartmut Brandt struct fdesc *f = uap; 584f06ca4afSHartmut Brandt 585f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 586f06ca4afSHartmut Brandt } 587f06ca4afSHartmut Brandt 588f06ca4afSHartmut Brandt void 589f06ca4afSHartmut Brandt fd_suspend(void *p) 590f06ca4afSHartmut Brandt { 591f06ca4afSHartmut Brandt struct fdesc *f = p; 592f06ca4afSHartmut Brandt 59370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 59470af00a1SHartmut Brandt if (f->id >= 0) { 59570af00a1SHartmut Brandt poll_unregister(f->id); 59670af00a1SHartmut Brandt f->id = -1; 59770af00a1SHartmut Brandt } 59870af00a1SHartmut Brandt #else 599f06ca4afSHartmut Brandt if (evTestID(f->id)) { 600f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 601f06ca4afSHartmut Brandt evInitID(&f->id); 602f06ca4afSHartmut Brandt } 60370af00a1SHartmut Brandt #endif 604f06ca4afSHartmut Brandt } 605f06ca4afSHartmut Brandt 606f06ca4afSHartmut Brandt int 607f06ca4afSHartmut Brandt fd_resume(void *p) 608f06ca4afSHartmut Brandt { 609f06ca4afSHartmut Brandt struct fdesc *f = p; 610f06ca4afSHartmut Brandt int err; 611f06ca4afSHartmut Brandt 61270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 61370af00a1SHartmut Brandt if (f->id >= 0) 61470af00a1SHartmut Brandt return (0); 61570af00a1SHartmut Brandt if ((f->fd = poll_register(f->fd, input, f, POLL_IN)) < 0) { 61670af00a1SHartmut Brandt err = errno; 61770af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 61870af00a1SHartmut Brandt errno = err; 61970af00a1SHartmut Brandt return (-1); 62070af00a1SHartmut Brandt } 62170af00a1SHartmut Brandt #else 622f06ca4afSHartmut Brandt if (evTestID(f->id)) 623f06ca4afSHartmut Brandt return (0); 624f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 625f06ca4afSHartmut Brandt err = errno; 626f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 627f06ca4afSHartmut Brandt errno = err; 628f06ca4afSHartmut Brandt return (-1); 629f06ca4afSHartmut Brandt } 63070af00a1SHartmut Brandt #endif 631f06ca4afSHartmut Brandt return (0); 632f06ca4afSHartmut Brandt } 633f06ca4afSHartmut Brandt 634f06ca4afSHartmut Brandt void * 635f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 636f06ca4afSHartmut Brandt { 637f06ca4afSHartmut Brandt struct fdesc *f; 638f06ca4afSHartmut Brandt int err; 639f06ca4afSHartmut Brandt 640f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 641f06ca4afSHartmut Brandt err = errno; 642f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 643f06ca4afSHartmut Brandt errno = err; 644f06ca4afSHartmut Brandt return (NULL); 645f06ca4afSHartmut Brandt } 646f06ca4afSHartmut Brandt f->fd = fd; 647f06ca4afSHartmut Brandt f->func = func; 648f06ca4afSHartmut Brandt f->udata = udata; 649f06ca4afSHartmut Brandt f->owner = mod; 65070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 65170af00a1SHartmut Brandt f->id = -1; 65270af00a1SHartmut Brandt #else 653f06ca4afSHartmut Brandt evInitID(&f->id); 65470af00a1SHartmut Brandt #endif 655f06ca4afSHartmut Brandt 656f06ca4afSHartmut Brandt if (fd_resume(f)) { 657f06ca4afSHartmut Brandt err = errno; 658f06ca4afSHartmut Brandt free(f); 659f06ca4afSHartmut Brandt errno = err; 660f06ca4afSHartmut Brandt return (NULL); 661f06ca4afSHartmut Brandt } 662f06ca4afSHartmut Brandt 663f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 664f06ca4afSHartmut Brandt 665f06ca4afSHartmut Brandt return (f); 666f06ca4afSHartmut Brandt } 667f06ca4afSHartmut Brandt 668f06ca4afSHartmut Brandt void 669f06ca4afSHartmut Brandt fd_deselect(void *p) 670f06ca4afSHartmut Brandt { 671f06ca4afSHartmut Brandt struct fdesc *f = p; 672f06ca4afSHartmut Brandt 673f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 674f06ca4afSHartmut Brandt fd_suspend(f); 675f06ca4afSHartmut Brandt free(f); 676f06ca4afSHartmut Brandt } 677f06ca4afSHartmut Brandt 678f06ca4afSHartmut Brandt static void 679f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 680f06ca4afSHartmut Brandt { 681f06ca4afSHartmut Brandt struct fdesc *t, *t1; 682f06ca4afSHartmut Brandt 683f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 684f06ca4afSHartmut Brandt while (t != NULL) { 685f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 686f06ca4afSHartmut Brandt if (t->owner == mod) 687f06ca4afSHartmut Brandt fd_deselect(t); 688f06ca4afSHartmut Brandt t = t1; 689f06ca4afSHartmut Brandt } 690f06ca4afSHartmut Brandt } 691f06ca4afSHartmut Brandt 692f06ca4afSHartmut Brandt /* 69370af00a1SHartmut Brandt * Consume a message from the input buffer 694f06ca4afSHartmut Brandt */ 695f06ca4afSHartmut Brandt static void 69670af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 697f06ca4afSHartmut Brandt { 69870af00a1SHartmut Brandt if (!pi->stream) { 69970af00a1SHartmut Brandt /* always consume everything */ 70070af00a1SHartmut Brandt pi->length = 0; 70170af00a1SHartmut Brandt return; 70270af00a1SHartmut Brandt } 70370af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 70470af00a1SHartmut Brandt /* all bytes consumed */ 70570af00a1SHartmut Brandt pi->length = 0; 70670af00a1SHartmut Brandt return; 70770af00a1SHartmut Brandt } 70870af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 70970af00a1SHartmut Brandt pi->length -= pi->consumed; 71070af00a1SHartmut Brandt } 71170af00a1SHartmut Brandt 71270af00a1SHartmut Brandt struct credmsg { 71370af00a1SHartmut Brandt struct cmsghdr hdr; 71470af00a1SHartmut Brandt struct cmsgcred cred; 71570af00a1SHartmut Brandt }; 71670af00a1SHartmut Brandt 71770af00a1SHartmut Brandt static void 71870af00a1SHartmut Brandt check_priv(struct port_input *pi, struct msghdr *msg) 71970af00a1SHartmut Brandt { 72070af00a1SHartmut Brandt struct credmsg *cmsg; 72170af00a1SHartmut Brandt struct xucred ucred; 72270af00a1SHartmut Brandt socklen_t ucredlen; 72370af00a1SHartmut Brandt 72470af00a1SHartmut Brandt pi->priv = 0; 72570af00a1SHartmut Brandt 72670af00a1SHartmut Brandt if (msg->msg_controllen == sizeof(*cmsg)) { 72770af00a1SHartmut Brandt /* process explicitely sends credentials */ 72870af00a1SHartmut Brandt 72970af00a1SHartmut Brandt cmsg = (struct credmsg *)msg->msg_control; 73070af00a1SHartmut Brandt pi->priv = (cmsg->cred.cmcred_euid == 0); 73170af00a1SHartmut Brandt return; 73270af00a1SHartmut Brandt } 73370af00a1SHartmut Brandt 73470af00a1SHartmut Brandt /* ok, obtain the accept time credentials */ 73570af00a1SHartmut Brandt ucredlen = sizeof(ucred); 73670af00a1SHartmut Brandt 73770af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 73870af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 73970af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 74070af00a1SHartmut Brandt } 74170af00a1SHartmut Brandt 74270af00a1SHartmut Brandt /* 74370af00a1SHartmut Brandt * Input from a stream socket. 74470af00a1SHartmut Brandt */ 74570af00a1SHartmut Brandt static int 74670af00a1SHartmut Brandt recv_stream(struct port_input *pi) 74770af00a1SHartmut Brandt { 74870af00a1SHartmut Brandt struct msghdr msg; 74970af00a1SHartmut Brandt struct iovec iov[1]; 75070af00a1SHartmut Brandt ssize_t len; 75170af00a1SHartmut Brandt struct credmsg cmsg; 75270af00a1SHartmut Brandt 75370af00a1SHartmut Brandt if (pi->buf == NULL) { 75470af00a1SHartmut Brandt /* no buffer yet - allocate one */ 75570af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 75670af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 75770af00a1SHartmut Brandt * the caller must close the transport. */ 75870af00a1SHartmut Brandt return (-1); 75970af00a1SHartmut Brandt } 76070af00a1SHartmut Brandt pi->buflen = buf_size(0); 76170af00a1SHartmut Brandt pi->consumed = 0; 76270af00a1SHartmut Brandt pi->length = 0; 76370af00a1SHartmut Brandt } 76470af00a1SHartmut Brandt 76570af00a1SHartmut Brandt /* try to get a message */ 76670af00a1SHartmut Brandt msg.msg_name = pi->peer; 76770af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 76870af00a1SHartmut Brandt msg.msg_iov = iov; 76970af00a1SHartmut Brandt msg.msg_iovlen = 1; 77070af00a1SHartmut Brandt if (pi->cred) { 77170af00a1SHartmut Brandt msg.msg_control = &cmsg; 77270af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 77370af00a1SHartmut Brandt 77470af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 77570af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 77670af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 77770af00a1SHartmut Brandt } else { 77870af00a1SHartmut Brandt msg.msg_control = NULL; 77970af00a1SHartmut Brandt msg.msg_controllen = 0; 78070af00a1SHartmut Brandt } 78170af00a1SHartmut Brandt msg.msg_flags = 0; 78270af00a1SHartmut Brandt 78370af00a1SHartmut Brandt iov[0].iov_base = pi->buf + pi->length; 78470af00a1SHartmut Brandt iov[0].iov_len = pi->buflen - pi->length; 78570af00a1SHartmut Brandt 78670af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 78770af00a1SHartmut Brandt 78870af00a1SHartmut Brandt if (len == -1 || len == 0) 78970af00a1SHartmut Brandt /* receive error */ 79070af00a1SHartmut Brandt return (-1); 79170af00a1SHartmut Brandt 79270af00a1SHartmut Brandt pi->length += len; 79370af00a1SHartmut Brandt 79470af00a1SHartmut Brandt if (pi->cred) 79570af00a1SHartmut Brandt check_priv(pi, &msg); 79670af00a1SHartmut Brandt 79770af00a1SHartmut Brandt return (0); 79870af00a1SHartmut Brandt } 79970af00a1SHartmut Brandt 80070af00a1SHartmut Brandt /* 80170af00a1SHartmut Brandt * Input from a datagram socket. 80270af00a1SHartmut Brandt * Each receive should return one datagram. 80370af00a1SHartmut Brandt */ 80470af00a1SHartmut Brandt static int 80570af00a1SHartmut Brandt recv_dgram(struct port_input *pi) 80670af00a1SHartmut Brandt { 80770af00a1SHartmut Brandt u_char embuf[1000]; 80870af00a1SHartmut Brandt struct msghdr msg; 80970af00a1SHartmut Brandt struct iovec iov[1]; 81070af00a1SHartmut Brandt ssize_t len; 81170af00a1SHartmut Brandt struct credmsg cmsg; 81270af00a1SHartmut Brandt 81370af00a1SHartmut Brandt if (pi->buf == NULL) { 81470af00a1SHartmut Brandt /* no buffer yet - allocate one */ 81570af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 81670af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 81770af00a1SHartmut Brandt * and drop it */ 81870af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 81970af00a1SHartmut Brandt 0, NULL, NULL); 82070af00a1SHartmut Brandt /* return error */ 82170af00a1SHartmut Brandt return (-1); 82270af00a1SHartmut Brandt } 82370af00a1SHartmut Brandt pi->buflen = buf_size(0); 82470af00a1SHartmut Brandt } 82570af00a1SHartmut Brandt 82670af00a1SHartmut Brandt /* try to get a message */ 82770af00a1SHartmut Brandt msg.msg_name = pi->peer; 82870af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 82970af00a1SHartmut Brandt msg.msg_iov = iov; 83070af00a1SHartmut Brandt msg.msg_iovlen = 1; 83170af00a1SHartmut Brandt if (pi->cred) { 83270af00a1SHartmut Brandt msg.msg_control = &cmsg; 83370af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 83470af00a1SHartmut Brandt 83570af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 83670af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 83770af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 83870af00a1SHartmut Brandt } else { 83970af00a1SHartmut Brandt msg.msg_control = NULL; 8408eecd77aSHartmut Brandt msg.msg_controllen = 0; 84170af00a1SHartmut Brandt } 84270af00a1SHartmut Brandt msg.msg_flags = 0; 84370af00a1SHartmut Brandt 84470af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 84570af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 84670af00a1SHartmut Brandt 84770af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 84870af00a1SHartmut Brandt 84970af00a1SHartmut Brandt if (len == -1 || len == 0) 85070af00a1SHartmut Brandt /* receive error */ 85170af00a1SHartmut Brandt return (-1); 85270af00a1SHartmut Brandt 85370af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 85470af00a1SHartmut Brandt /* truncated - drop */ 85570af00a1SHartmut Brandt snmpd_stats.silentDrops++; 85670af00a1SHartmut Brandt snmpd_stats.inTooLong++; 85770af00a1SHartmut Brandt return (-1); 85870af00a1SHartmut Brandt } 85970af00a1SHartmut Brandt 86070af00a1SHartmut Brandt pi->length = (size_t)len; 86170af00a1SHartmut Brandt 86270af00a1SHartmut Brandt if (pi->cred) 86370af00a1SHartmut Brandt check_priv(pi, &msg); 86470af00a1SHartmut Brandt 86570af00a1SHartmut Brandt return (0); 86670af00a1SHartmut Brandt } 86770af00a1SHartmut Brandt 86870af00a1SHartmut Brandt /* 86970af00a1SHartmut Brandt * Input from a socket 87070af00a1SHartmut Brandt */ 87170af00a1SHartmut Brandt int 87270af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 87370af00a1SHartmut Brandt { 874f06ca4afSHartmut Brandt u_char *sndbuf; 875f06ca4afSHartmut Brandt size_t sndlen; 87670af00a1SHartmut Brandt struct snmp_pdu pdu; 877f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 878f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 879f06ca4afSHartmut Brandt int32_t vi; 88070af00a1SHartmut Brandt int ret; 88170af00a1SHartmut Brandt ssize_t slen; 882f06ca4afSHartmut Brandt 88370af00a1SHartmut Brandt /* get input depending on the transport */ 88470af00a1SHartmut Brandt if (pi->stream) { 88570af00a1SHartmut Brandt ret = recv_stream(pi); 88670af00a1SHartmut Brandt } else { 88770af00a1SHartmut Brandt ret = recv_dgram(pi); 888f06ca4afSHartmut Brandt } 88970af00a1SHartmut Brandt 89070af00a1SHartmut Brandt if (ret == -1) 89170af00a1SHartmut Brandt return (-1); 892f06ca4afSHartmut Brandt 893f06ca4afSHartmut Brandt /* 894f06ca4afSHartmut Brandt * Handle input 895f06ca4afSHartmut Brandt */ 89670af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 89770af00a1SHartmut Brandt &pi->consumed); 89870af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 89970af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 90070af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 90170af00a1SHartmut Brandt if (pi->stream) { 90270af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 90370af00a1SHartmut Brandt snmpd_stats.silentDrops++; 90470af00a1SHartmut Brandt return (-1); 90570af00a1SHartmut Brandt } 90670af00a1SHartmut Brandt return (0); 90770af00a1SHartmut Brandt } 90870af00a1SHartmut Brandt snmpd_stats.silentDrops++; 90970af00a1SHartmut Brandt return (-1); 91070af00a1SHartmut Brandt } 911f06ca4afSHartmut Brandt 912f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 913f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 914f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 915f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 91670af00a1SHartmut Brandt /* for streaming transports this is fatal */ 91770af00a1SHartmut Brandt if (pi->stream) 91870af00a1SHartmut Brandt return (-1); 91970af00a1SHartmut Brandt snmp_input_consume(pi); 92070af00a1SHartmut Brandt return (0); 921f06ca4afSHartmut Brandt } 922896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 923896052c1SHartmut Brandt snmp_input_consume(pi); 924896052c1SHartmut Brandt return (0); 925896052c1SHartmut Brandt } 926f06ca4afSHartmut Brandt 927f06ca4afSHartmut Brandt /* 928f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 929f06ca4afSHartmut Brandt * the hand it over to the module. 930f06ca4afSHartmut Brandt */ 931f06ca4afSHartmut Brandt if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 93270af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 933896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 934896052c1SHartmut Brandt !pi->cred || pi->priv); 935f06ca4afSHartmut Brandt 936f06ca4afSHartmut Brandt switch (perr) { 937f06ca4afSHartmut Brandt 938f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 93970af00a1SHartmut Brandt snmp_input_consume(pi); 94070af00a1SHartmut Brandt return (0); 941f06ca4afSHartmut Brandt 942f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 943f06ca4afSHartmut Brandt break; 944f06ca4afSHartmut Brandt 945f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 94670af00a1SHartmut Brandt snmp_input_consume(pi); 947f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 948f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 94970af00a1SHartmut Brandt return (0); 950f06ca4afSHartmut Brandt 951f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 95270af00a1SHartmut Brandt snmp_input_consume(pi); 953f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 954f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 955f06ca4afSHartmut Brandt if (snmpd.auth_traps) 956f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 957896052c1SHartmut Brandt (struct snmp_value *)NULL); 95870af00a1SHartmut Brandt return (0); 959f06ca4afSHartmut Brandt 960f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 96170af00a1SHartmut Brandt snmp_input_consume(pi); 962f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 963f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 964f06ca4afSHartmut Brandt if (snmpd.auth_traps) 965f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 966896052c1SHartmut Brandt (struct snmp_value *)NULL); 96770af00a1SHartmut Brandt return (0); 968f06ca4afSHartmut Brandt } 969f06ca4afSHartmut Brandt } 970f06ca4afSHartmut Brandt 971f06ca4afSHartmut Brandt /* 972f06ca4afSHartmut Brandt * Check type 973f06ca4afSHartmut Brandt */ 974f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 975f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 976f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 977f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 978f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 979f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 98070af00a1SHartmut Brandt snmp_input_consume(pi); 98170af00a1SHartmut Brandt return (0); 982f06ca4afSHartmut Brandt } 983f06ca4afSHartmut Brandt 984f06ca4afSHartmut Brandt /* 985f06ca4afSHartmut Brandt * Check community 986f06ca4afSHartmut Brandt */ 98770af00a1SHartmut Brandt if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 98870af00a1SHartmut Brandt (community != COMM_WRITE && 98970af00a1SHartmut Brandt (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 990f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 991f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 99270af00a1SHartmut Brandt snmp_input_consume(pi); 993f06ca4afSHartmut Brandt if (snmpd.auth_traps) 994896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 995896052c1SHartmut Brandt (struct snmp_value *)NULL); 99670af00a1SHartmut Brandt return (0); 997f06ca4afSHartmut Brandt } 998f06ca4afSHartmut Brandt 999f06ca4afSHartmut Brandt /* 1000f06ca4afSHartmut Brandt * Execute it. 1001f06ca4afSHartmut Brandt */ 1002f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1003f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1004f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 100570af00a1SHartmut Brandt snmp_input_consume(pi); 100670af00a1SHartmut Brandt return (0); 1007f06ca4afSHartmut Brandt } 100870af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 100970af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1010f06ca4afSHartmut Brandt 1011f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 101270af00a1SHartmut Brandt slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 101370af00a1SHartmut Brandt if (slen == -1) 101470af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 101570af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 101670af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 101770af00a1SHartmut Brandt sndlen, (size_t)slen); 101870af00a1SHartmut Brandt } 101970af00a1SHartmut Brandt snmp_pdu_free(&pdu); 102070af00a1SHartmut Brandt free(sndbuf); 102170af00a1SHartmut Brandt snmp_input_consume(pi); 102270af00a1SHartmut Brandt 102370af00a1SHartmut Brandt return (0); 102470af00a1SHartmut Brandt } 102570af00a1SHartmut Brandt 102670af00a1SHartmut Brandt /* 102770af00a1SHartmut Brandt * Send a PDU to a given port 102870af00a1SHartmut Brandt */ 102970af00a1SHartmut Brandt void 103070af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 103170af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 103270af00a1SHartmut Brandt { 103370af00a1SHartmut Brandt struct transport *trans = targ; 103470af00a1SHartmut Brandt struct tport *tp; 103570af00a1SHartmut Brandt u_char *sndbuf; 103670af00a1SHartmut Brandt size_t sndlen; 103770af00a1SHartmut Brandt ssize_t len; 103870af00a1SHartmut Brandt 103970af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 104070af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 104170af00a1SHartmut Brandt break; 104270af00a1SHartmut Brandt if (tp == 0) 104370af00a1SHartmut Brandt return; 104470af00a1SHartmut Brandt 104570af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 104670af00a1SHartmut Brandt return; 104770af00a1SHartmut Brandt 104870af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 104970af00a1SHartmut Brandt 105070af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 105170af00a1SHartmut Brandt 105270af00a1SHartmut Brandt if (len == -1) 1053f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1054f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1055f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1056f06ca4afSHartmut Brandt sndlen, (size_t)len); 105770af00a1SHartmut Brandt 1058f06ca4afSHartmut Brandt free(sndbuf); 1059f06ca4afSHartmut Brandt } 1060f06ca4afSHartmut Brandt 1061f06ca4afSHartmut Brandt 1062f06ca4afSHartmut Brandt /* 106370af00a1SHartmut Brandt * Close an input source 1064f06ca4afSHartmut Brandt */ 1065f06ca4afSHartmut Brandt void 106670af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1067f06ca4afSHartmut Brandt { 106870af00a1SHartmut Brandt if (pi->id != NULL) 106970af00a1SHartmut Brandt fd_deselect(pi->id); 107070af00a1SHartmut Brandt if (pi->fd >= 0) 107170af00a1SHartmut Brandt (void)close(pi->fd); 107270af00a1SHartmut Brandt if (pi->buf != NULL) 107370af00a1SHartmut Brandt free(pi->buf); 1074f06ca4afSHartmut Brandt } 1075f06ca4afSHartmut Brandt 1076f06ca4afSHartmut Brandt /* 1077f06ca4afSHartmut Brandt * Dump internal state. 1078f06ca4afSHartmut Brandt */ 107970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 108070af00a1SHartmut Brandt static void 108170af00a1SHartmut Brandt info_func(void) 108270af00a1SHartmut Brandt #else 1083f06ca4afSHartmut Brandt static void 1084f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 108570af00a1SHartmut Brandt #endif 1086f06ca4afSHartmut Brandt { 1087f06ca4afSHartmut Brandt struct lmodule *m; 1088f06ca4afSHartmut Brandt u_int i; 1089f06ca4afSHartmut Brandt char buf[10000]; 1090f06ca4afSHartmut Brandt 1091f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1092f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1093f06ca4afSHartmut Brandt switch (tree[i].type) { 1094f06ca4afSHartmut Brandt 1095f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1096f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1097f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1098f06ca4afSHartmut Brandt break; 1099f06ca4afSHartmut Brandt 1100f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1101f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1102f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1103f06ca4afSHartmut Brandt break; 1104f06ca4afSHartmut Brandt } 1105f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1106f06ca4afSHartmut Brandt } 1107f06ca4afSHartmut Brandt 1108f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1109f06ca4afSHartmut Brandt if (m->config->dump) 1110f06ca4afSHartmut Brandt (*m->config->dump)(); 1111f06ca4afSHartmut Brandt } 1112f06ca4afSHartmut Brandt 1113f06ca4afSHartmut Brandt /* 1114f06ca4afSHartmut Brandt * Re-read configuration 1115f06ca4afSHartmut Brandt */ 111670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 111770af00a1SHartmut Brandt static void 111870af00a1SHartmut Brandt config_func(void) 111970af00a1SHartmut Brandt #else 1120f06ca4afSHartmut Brandt static void 1121f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1122f06ca4afSHartmut Brandt const void *tag __unused) 112370af00a1SHartmut Brandt #endif 1124f06ca4afSHartmut Brandt { 1125f06ca4afSHartmut Brandt struct lmodule *m; 1126f06ca4afSHartmut Brandt 1127f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1128f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1129f06ca4afSHartmut Brandt return; 1130f06ca4afSHartmut Brandt } 1131f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1132f06ca4afSHartmut Brandt if (m->config->config) 1133f06ca4afSHartmut Brandt (*m->config->config)(); 1134f06ca4afSHartmut Brandt } 1135f06ca4afSHartmut Brandt 1136f06ca4afSHartmut Brandt /* 1137f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1138f06ca4afSHartmut Brandt */ 1139f06ca4afSHartmut Brandt static void 1140f06ca4afSHartmut Brandt onusr1(int s __unused) 1141f06ca4afSHartmut Brandt { 114270af00a1SHartmut Brandt 1143f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1144f06ca4afSHartmut Brandt } 1145f06ca4afSHartmut Brandt static void 1146f06ca4afSHartmut Brandt onhup(int s __unused) 1147f06ca4afSHartmut Brandt { 114870af00a1SHartmut Brandt 1149f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1150f06ca4afSHartmut Brandt } 1151f06ca4afSHartmut Brandt 1152f06ca4afSHartmut Brandt static void 1153f06ca4afSHartmut Brandt onterm(int s __unused) 1154f06ca4afSHartmut Brandt { 1155f06ca4afSHartmut Brandt 115670af00a1SHartmut Brandt /* allow clean-up */ 1157f06ca4afSHartmut Brandt exit(0); 1158f06ca4afSHartmut Brandt } 1159f06ca4afSHartmut Brandt 1160f06ca4afSHartmut Brandt static void 1161f06ca4afSHartmut Brandt init_sigs(void) 1162f06ca4afSHartmut Brandt { 1163f06ca4afSHartmut Brandt struct sigaction sa; 1164f06ca4afSHartmut Brandt 1165f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1166f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1167f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1168f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1169f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1170f06ca4afSHartmut Brandt exit(1); 1171f06ca4afSHartmut Brandt } 1172f06ca4afSHartmut Brandt 1173f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1174f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1175f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1176f06ca4afSHartmut Brandt exit(1); 1177f06ca4afSHartmut Brandt } 1178f06ca4afSHartmut Brandt 1179f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1180f06ca4afSHartmut Brandt sa.sa_flags = 0; 1181f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1182f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1183f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1184f06ca4afSHartmut Brandt exit(1); 1185f06ca4afSHartmut Brandt } 1186f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1187f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1188f06ca4afSHartmut Brandt exit(1); 1189f06ca4afSHartmut Brandt } 1190f06ca4afSHartmut Brandt } 1191f06ca4afSHartmut Brandt 1192f06ca4afSHartmut Brandt static void 1193f06ca4afSHartmut Brandt block_sigs(void) 1194f06ca4afSHartmut Brandt { 1195f06ca4afSHartmut Brandt sigset_t set; 1196f06ca4afSHartmut Brandt 1197f06ca4afSHartmut Brandt sigfillset(&set); 1198f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1199f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1200f06ca4afSHartmut Brandt exit(1); 1201f06ca4afSHartmut Brandt } 1202f06ca4afSHartmut Brandt } 1203f06ca4afSHartmut Brandt static void 1204f06ca4afSHartmut Brandt unblock_sigs(void) 1205f06ca4afSHartmut Brandt { 1206f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1207f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1208f06ca4afSHartmut Brandt exit(1); 1209f06ca4afSHartmut Brandt } 1210f06ca4afSHartmut Brandt } 1211f06ca4afSHartmut Brandt 1212f06ca4afSHartmut Brandt /* 1213f06ca4afSHartmut Brandt * Shut down 1214f06ca4afSHartmut Brandt */ 1215f06ca4afSHartmut Brandt static void 1216f06ca4afSHartmut Brandt term(void) 1217f06ca4afSHartmut Brandt { 1218f06ca4afSHartmut Brandt (void)unlink(pid_file); 1219f06ca4afSHartmut Brandt } 1220f06ca4afSHartmut Brandt 122170af00a1SHartmut Brandt static void 122270af00a1SHartmut Brandt trans_stop(void) 122370af00a1SHartmut Brandt { 122470af00a1SHartmut Brandt struct transport *t; 122570af00a1SHartmut Brandt 122670af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 122770af00a1SHartmut Brandt (void)t->vtab->stop(1); 122870af00a1SHartmut Brandt } 122970af00a1SHartmut Brandt 1230f06ca4afSHartmut Brandt /* 1231f06ca4afSHartmut Brandt * Define a macro from the command line 1232f06ca4afSHartmut Brandt */ 1233f06ca4afSHartmut Brandt static void 1234f06ca4afSHartmut Brandt do_macro(char *arg) 1235f06ca4afSHartmut Brandt { 1236f06ca4afSHartmut Brandt char *eq; 1237f06ca4afSHartmut Brandt int err; 1238f06ca4afSHartmut Brandt 1239f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1240f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1241f06ca4afSHartmut Brandt else { 1242f06ca4afSHartmut Brandt *eq++ = '\0'; 1243f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1244f06ca4afSHartmut Brandt } 1245f06ca4afSHartmut Brandt if (err == -1) { 1246f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1247f06ca4afSHartmut Brandt exit(1); 1248f06ca4afSHartmut Brandt } 1249f06ca4afSHartmut Brandt } 1250f06ca4afSHartmut Brandt 1251f06ca4afSHartmut Brandt /* 1252f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1253f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1254f06ca4afSHartmut Brandt */ 1255f06ca4afSHartmut Brandt static int 1256f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1257f06ca4afSHartmut Brandt { 1258f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1259f06ca4afSHartmut Brandt u_int i; 1260f06ca4afSHartmut Brandt char *ptr; 1261f06ca4afSHartmut Brandt 1262f06ca4afSHartmut Brandt *optp = NULL; 1263f06ca4afSHartmut Brandt 1264f06ca4afSHartmut Brandt /* skip leading junk */ 1265f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1266f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1267f06ca4afSHartmut Brandt break; 1268f06ca4afSHartmut Brandt if (*ptr == '\0') { 1269f06ca4afSHartmut Brandt *arg = ptr; 1270f06ca4afSHartmut Brandt return (-1); 1271f06ca4afSHartmut Brandt } 1272f06ca4afSHartmut Brandt *optp = ptr; 1273f06ca4afSHartmut Brandt 1274f06ca4afSHartmut Brandt /* find the end of the option */ 1275f06ca4afSHartmut Brandt while (*++ptr != '\0') 1276f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1277f06ca4afSHartmut Brandt break; 1278f06ca4afSHartmut Brandt 1279f06ca4afSHartmut Brandt if (*ptr != '\0') { 1280f06ca4afSHartmut Brandt if (*ptr == '=') { 1281f06ca4afSHartmut Brandt *ptr++ = '\0'; 1282f06ca4afSHartmut Brandt *valp = ptr; 1283f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1284f06ca4afSHartmut Brandt ptr++; 1285f06ca4afSHartmut Brandt if (*ptr != '\0') 1286f06ca4afSHartmut Brandt *ptr++ = '\0'; 1287f06ca4afSHartmut Brandt } else 1288f06ca4afSHartmut Brandt *ptr++ = '\0'; 1289f06ca4afSHartmut Brandt } 1290f06ca4afSHartmut Brandt 1291f06ca4afSHartmut Brandt *arg = ptr; 1292f06ca4afSHartmut Brandt 1293f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 129470af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1295f06ca4afSHartmut Brandt return (i); 1296f06ca4afSHartmut Brandt return (-1); 1297f06ca4afSHartmut Brandt } 1298f06ca4afSHartmut Brandt 1299f06ca4afSHartmut Brandt int 1300f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1301f06ca4afSHartmut Brandt { 1302f06ca4afSHartmut Brandt int opt; 1303f06ca4afSHartmut Brandt FILE *fp; 1304f06ca4afSHartmut Brandt int background = 1; 130570af00a1SHartmut Brandt struct tport *p; 1306f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1307f06ca4afSHartmut Brandt struct lmodule *m; 1308f06ca4afSHartmut Brandt char *value, *option; 130970af00a1SHartmut Brandt struct transport *t; 1310f06ca4afSHartmut Brandt 1311f06ca4afSHartmut Brandt #define DBG_DUMP 0 1312f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1313f06ca4afSHartmut Brandt #define DBG_TRACE 2 1314f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1315f06ca4afSHartmut Brandt "dump", 1316f06ca4afSHartmut Brandt "events", 1317f06ca4afSHartmut Brandt "trace", 1318f06ca4afSHartmut Brandt NULL 1319f06ca4afSHartmut Brandt }; 1320f06ca4afSHartmut Brandt 1321f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1322f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1323f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1324f06ca4afSHartmut Brandt asn_error = asn_error_func; 1325f06ca4afSHartmut Brandt 1326f06ca4afSHartmut Brandt while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1327f06ca4afSHartmut Brandt switch (opt) { 1328f06ca4afSHartmut Brandt 1329f06ca4afSHartmut Brandt case 'c': 1330f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1331f06ca4afSHartmut Brandt break; 1332f06ca4afSHartmut Brandt 1333f06ca4afSHartmut Brandt case 'd': 1334f06ca4afSHartmut Brandt background = 0; 1335f06ca4afSHartmut Brandt break; 1336f06ca4afSHartmut Brandt 1337f06ca4afSHartmut Brandt case 'D': 1338f06ca4afSHartmut Brandt while (*optarg) { 1339f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1340f06ca4afSHartmut Brandt &value, &option)) { 1341f06ca4afSHartmut Brandt 1342f06ca4afSHartmut Brandt case DBG_DUMP: 1343f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1344f06ca4afSHartmut Brandt break; 1345f06ca4afSHartmut Brandt 1346f06ca4afSHartmut Brandt case DBG_EVENTS: 1347f06ca4afSHartmut Brandt debug.evdebug++; 1348f06ca4afSHartmut Brandt break; 1349f06ca4afSHartmut Brandt 1350f06ca4afSHartmut Brandt case DBG_TRACE: 1351f06ca4afSHartmut Brandt if (value == NULL) 1352f06ca4afSHartmut Brandt syslog(LOG_ERR, 1353f06ca4afSHartmut Brandt "no value for 'trace'"); 1354f06ca4afSHartmut Brandt snmp_trace = strtoul(value, NULL, 0); 1355f06ca4afSHartmut Brandt break; 1356f06ca4afSHartmut Brandt 1357f06ca4afSHartmut Brandt case -1: 1358f06ca4afSHartmut Brandt if (suboptarg) 1359f06ca4afSHartmut Brandt syslog(LOG_ERR, 1360f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1361f06ca4afSHartmut Brandt option); 1362f06ca4afSHartmut Brandt else 1363f06ca4afSHartmut Brandt syslog(LOG_ERR, 1364f06ca4afSHartmut Brandt "missing debug flag"); 1365f06ca4afSHartmut Brandt break; 1366f06ca4afSHartmut Brandt } 1367f06ca4afSHartmut Brandt } 1368f06ca4afSHartmut Brandt break; 1369f06ca4afSHartmut Brandt 1370f06ca4afSHartmut Brandt case 'h': 1371f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1372f06ca4afSHartmut Brandt exit(0); 1373f06ca4afSHartmut Brandt 1374f06ca4afSHartmut Brandt case 'I': 1375f06ca4afSHartmut Brandt syspath = optarg; 1376f06ca4afSHartmut Brandt break; 1377f06ca4afSHartmut Brandt 1378f06ca4afSHartmut Brandt case 'l': 1379f06ca4afSHartmut Brandt prefix = optarg; 1380f06ca4afSHartmut Brandt break; 1381f06ca4afSHartmut Brandt 1382f06ca4afSHartmut Brandt case 'm': 1383f06ca4afSHartmut Brandt do_macro(optarg); 1384f06ca4afSHartmut Brandt break; 1385f06ca4afSHartmut Brandt 1386f06ca4afSHartmut Brandt case 'p': 1387f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1388f06ca4afSHartmut Brandt break; 1389f06ca4afSHartmut Brandt } 1390f06ca4afSHartmut Brandt 1391f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1392f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1393f06ca4afSHartmut Brandt 1394f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1395f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1396f06ca4afSHartmut Brandt exit(1); 1397f06ca4afSHartmut Brandt } 1398f06ca4afSHartmut Brandt 1399f06ca4afSHartmut Brandt argc -= optind; 1400f06ca4afSHartmut Brandt argv += optind; 1401f06ca4afSHartmut Brandt 1402f06ca4afSHartmut Brandt progargs = argv; 1403f06ca4afSHartmut Brandt nprogargs = argc; 1404f06ca4afSHartmut Brandt 1405f06ca4afSHartmut Brandt srandomdev(); 1406f06ca4afSHartmut Brandt 1407f06ca4afSHartmut Brandt snmp_serial_no = random(); 1408f06ca4afSHartmut Brandt 1409f06ca4afSHartmut Brandt /* 1410f06ca4afSHartmut Brandt * Initialize the tree. 1411f06ca4afSHartmut Brandt */ 1412f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1413f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1414f06ca4afSHartmut Brandt exit(1); 1415f06ca4afSHartmut Brandt } 1416f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1417f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1418f06ca4afSHartmut Brandt 1419f06ca4afSHartmut Brandt /* 1420f06ca4afSHartmut Brandt * Get standard communities 1421f06ca4afSHartmut Brandt */ 1422f06ca4afSHartmut Brandt (void)comm_define(1, "SNMP read", NULL, "public"); 1423f06ca4afSHartmut Brandt (void)comm_define(2, "SNMP write", NULL, "public"); 1424f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1425f06ca4afSHartmut Brandt 1426f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1427f06ca4afSHartmut Brandt 1428f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1429f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1430f06ca4afSHartmut Brandt 1431f06ca4afSHartmut Brandt init_actvals(); 143270af00a1SHartmut Brandt 143370af00a1SHartmut Brandt start_tick = get_ticks(); 143470af00a1SHartmut Brandt this_tick = get_ticks(); 143570af00a1SHartmut Brandt 143670af00a1SHartmut Brandt /* start transports */ 143770af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 143870af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 143970af00a1SHartmut Brandt exit(1); 144070af00a1SHartmut Brandt } 144170af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 144270af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 144370af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 144470af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 144570af00a1SHartmut Brandt 144670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 144770af00a1SHartmut Brandt if (debug.evdebug > 0) 144870af00a1SHartmut Brandt rpoll_trace = 1; 144970af00a1SHartmut Brandt #else 1450f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1451f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1452f06ca4afSHartmut Brandt exit(1); 1453f06ca4afSHartmut Brandt } 1454f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1455f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 145670af00a1SHartmut Brandt #endif 1457f06ca4afSHartmut Brandt 1458896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1459896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1460896052c1SHartmut Brandt exit(1); 1461896052c1SHartmut Brandt } 1462896052c1SHartmut Brandt 146370af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 146470af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 146570af00a1SHartmut Brandt t->vtab->init_port(p); 1466f06ca4afSHartmut Brandt 1467f06ca4afSHartmut Brandt init_sigs(); 1468f06ca4afSHartmut Brandt 1469f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1470f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1471f06ca4afSHartmut Brandt 1472f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1473f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1474f06ca4afSHartmut Brandt fclose(fp); 147570af00a1SHartmut Brandt if (atexit(term) == -1) { 147670af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 147770af00a1SHartmut Brandt (void)remove(pid_file); 147870af00a1SHartmut Brandt exit(0); 1479f06ca4afSHartmut Brandt } 148070af00a1SHartmut Brandt } 1481f06ca4afSHartmut Brandt 1482f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1483f06ca4afSHartmut Brandt NULL) == 0) { 1484f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1485f06ca4afSHartmut Brandt exit(1); 1486f06ca4afSHartmut Brandt } 1487f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1488f06ca4afSHartmut Brandt NULL) == 0) { 1489f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1490f06ca4afSHartmut Brandt exit(1); 1491f06ca4afSHartmut Brandt } 1492f06ca4afSHartmut Brandt 1493896052c1SHartmut Brandt snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1494f06ca4afSHartmut Brandt 1495f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1496f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1497f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1498f06ca4afSHartmut Brandt lm_start(m); 1499f06ca4afSHartmut Brandt } 1500f06ca4afSHartmut Brandt 1501f06ca4afSHartmut Brandt for (;;) { 150270af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1503f06ca4afSHartmut Brandt evEvent event; 150470af00a1SHartmut Brandt #endif 1505f06ca4afSHartmut Brandt struct lmodule *mod; 1506f06ca4afSHartmut Brandt 1507f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1508f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1509f06ca4afSHartmut Brandt (*mod->config->idle)(); 1510f06ca4afSHartmut Brandt 151170af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1512f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1513f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1514f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1515f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1516f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1517f06ca4afSHartmut Brandt exit(1); 1518f06ca4afSHartmut Brandt } 151970af00a1SHartmut Brandt #else 152070af00a1SHartmut Brandt poll_dispatch(1); 152170af00a1SHartmut Brandt #endif 1522f06ca4afSHartmut Brandt 1523f06ca4afSHartmut Brandt if (work != 0) { 1524f06ca4afSHartmut Brandt block_sigs(); 1525f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 152670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 152770af00a1SHartmut Brandt info_func(); 152870af00a1SHartmut Brandt #else 1529f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1530f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1531f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1532f06ca4afSHartmut Brandt exit(1); 1533f06ca4afSHartmut Brandt } 153470af00a1SHartmut Brandt #endif 1535f06ca4afSHartmut Brandt } 1536f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 153770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 153870af00a1SHartmut Brandt config_func(); 153970af00a1SHartmut Brandt #else 1540f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1541f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1542f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1543f06ca4afSHartmut Brandt exit(1); 1544f06ca4afSHartmut Brandt } 154570af00a1SHartmut Brandt #endif 1546f06ca4afSHartmut Brandt } 1547f06ca4afSHartmut Brandt work = 0; 1548f06ca4afSHartmut Brandt unblock_sigs(); 154970af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1550f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1551f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1552f06ca4afSHartmut Brandt exit(1); 1553f06ca4afSHartmut Brandt } 155470af00a1SHartmut Brandt #endif 1555f06ca4afSHartmut Brandt } 1556f06ca4afSHartmut Brandt } 1557f06ca4afSHartmut Brandt 1558f06ca4afSHartmut Brandt return (0); 1559f06ca4afSHartmut Brandt } 1560f06ca4afSHartmut Brandt 1561f06ca4afSHartmut Brandt 1562f06ca4afSHartmut Brandt u_int32_t 1563f06ca4afSHartmut Brandt get_ticks() 1564f06ca4afSHartmut Brandt { 1565f06ca4afSHartmut Brandt struct timeval tv; 1566f06ca4afSHartmut Brandt u_int32_t ret; 1567f06ca4afSHartmut Brandt 1568f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1569f06ca4afSHartmut Brandt abort(); 1570f06ca4afSHartmut Brandt ret = tv.tv_sec * 100 + tv.tv_usec / 10000; 1571f06ca4afSHartmut Brandt return (ret); 1572f06ca4afSHartmut Brandt } 1573f06ca4afSHartmut Brandt /* 1574f06ca4afSHartmut Brandt * Timer support 1575f06ca4afSHartmut Brandt */ 157670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 157770af00a1SHartmut Brandt static void 157870af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 157970af00a1SHartmut Brandt #else 1580f06ca4afSHartmut Brandt static void 1581f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1582f06ca4afSHartmut Brandt struct timespec inter __unused) 158370af00a1SHartmut Brandt #endif 1584f06ca4afSHartmut Brandt { 1585f06ca4afSHartmut Brandt struct timer *tp = uap; 1586f06ca4afSHartmut Brandt 1587f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1588f06ca4afSHartmut Brandt tp->func(tp->udata); 1589f06ca4afSHartmut Brandt free(tp); 1590f06ca4afSHartmut Brandt } 1591f06ca4afSHartmut Brandt 1592f06ca4afSHartmut Brandt /* 1593f06ca4afSHartmut Brandt * Start a timer 1594f06ca4afSHartmut Brandt */ 1595f06ca4afSHartmut Brandt void * 1596f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1597f06ca4afSHartmut Brandt { 1598f06ca4afSHartmut Brandt struct timer *tp; 159970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 160070af00a1SHartmut Brandt struct timeval due; 160170af00a1SHartmut Brandt #else 1602f06ca4afSHartmut Brandt struct timespec due; 160370af00a1SHartmut Brandt #endif 1604f06ca4afSHartmut Brandt 1605f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1606f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1607f06ca4afSHartmut Brandt exit(1); 1608f06ca4afSHartmut Brandt } 160970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 161070af00a1SHartmut Brandt (void)gettimeofday(&due, NULL); 161170af00a1SHartmut Brandt due.tv_sec += ticks / 100; 161270af00a1SHartmut Brandt due.tv_usec += (ticks % 100) * 10000; 161370af00a1SHartmut Brandt if (due.tv_usec >= 1000000) { 161470af00a1SHartmut Brandt due.tv_sec++; 161570af00a1SHartmut Brandt due.tv_usec -= 1000000; 161670af00a1SHartmut Brandt } 161770af00a1SHartmut Brandt #else 1618f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1619f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 162070af00a1SHartmut Brandt #endif 1621f06ca4afSHartmut Brandt 1622f06ca4afSHartmut Brandt tp->udata = udata; 1623f06ca4afSHartmut Brandt tp->owner = mod; 1624f06ca4afSHartmut Brandt tp->func = func; 1625f06ca4afSHartmut Brandt 1626f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1627f06ca4afSHartmut Brandt 162870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 162970af00a1SHartmut Brandt if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000, 163070af00a1SHartmut Brandt 0, tfunc, tp)) < 0) { 163170af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 163270af00a1SHartmut Brandt exit(1); 163370af00a1SHartmut Brandt } 163470af00a1SHartmut Brandt #else 1635f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1636f06ca4afSHartmut Brandt == -1) { 1637f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1638f06ca4afSHartmut Brandt exit(1); 1639f06ca4afSHartmut Brandt } 164070af00a1SHartmut Brandt #endif 1641f06ca4afSHartmut Brandt return (tp); 1642f06ca4afSHartmut Brandt } 1643f06ca4afSHartmut Brandt 1644f06ca4afSHartmut Brandt void 1645f06ca4afSHartmut Brandt timer_stop(void *p) 1646f06ca4afSHartmut Brandt { 1647f06ca4afSHartmut Brandt struct timer *tp = p; 1648f06ca4afSHartmut Brandt 1649f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 165070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 165170af00a1SHartmut Brandt poll_stop_timer(tp->id); 165270af00a1SHartmut Brandt #else 1653f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 1654f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 1655f06ca4afSHartmut Brandt exit(1); 1656f06ca4afSHartmut Brandt } 165770af00a1SHartmut Brandt #endif 1658f06ca4afSHartmut Brandt free(p); 1659f06ca4afSHartmut Brandt } 1660f06ca4afSHartmut Brandt 1661f06ca4afSHartmut Brandt static void 1662f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 1663f06ca4afSHartmut Brandt { 1664f06ca4afSHartmut Brandt struct timer *t, *t1; 1665f06ca4afSHartmut Brandt 1666f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 1667f06ca4afSHartmut Brandt while (t != NULL) { 1668f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1669f06ca4afSHartmut Brandt if (t->owner == mod) 1670f06ca4afSHartmut Brandt timer_stop(t); 1671f06ca4afSHartmut Brandt t = t1; 1672f06ca4afSHartmut Brandt } 1673f06ca4afSHartmut Brandt } 1674f06ca4afSHartmut Brandt 1675f06ca4afSHartmut Brandt static void 1676f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1677f06ca4afSHartmut Brandt { 1678f06ca4afSHartmut Brandt va_list ap; 1679f06ca4afSHartmut Brandt static char *pend = NULL; 1680f06ca4afSHartmut Brandt char *ret, *new; 1681f06ca4afSHartmut Brandt 1682f06ca4afSHartmut Brandt va_start(ap, fmt); 1683f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 1684f06ca4afSHartmut Brandt va_end(ap); 1685f06ca4afSHartmut Brandt 1686f06ca4afSHartmut Brandt if (ret == NULL) 1687f06ca4afSHartmut Brandt return; 1688f06ca4afSHartmut Brandt if (pend != NULL) { 1689f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1690f06ca4afSHartmut Brandt == NULL) { 1691f06ca4afSHartmut Brandt free(ret); 1692f06ca4afSHartmut Brandt return; 1693f06ca4afSHartmut Brandt } 1694f06ca4afSHartmut Brandt pend = new; 1695f06ca4afSHartmut Brandt strcat(pend, ret); 1696f06ca4afSHartmut Brandt free(ret); 1697f06ca4afSHartmut Brandt } else 1698f06ca4afSHartmut Brandt pend = ret; 1699f06ca4afSHartmut Brandt 1700f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 1701f06ca4afSHartmut Brandt *ret = '\0'; 1702f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 1703f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 1704f06ca4afSHartmut Brandt free(pend); 1705f06ca4afSHartmut Brandt pend = NULL; 1706f06ca4afSHartmut Brandt break; 1707f06ca4afSHartmut Brandt } 1708f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 1709f06ca4afSHartmut Brandt } 1710f06ca4afSHartmut Brandt } 1711f06ca4afSHartmut Brandt 1712f06ca4afSHartmut Brandt static void 1713f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 1714f06ca4afSHartmut Brandt { 1715f06ca4afSHartmut Brandt char errbuf[1000]; 1716f06ca4afSHartmut Brandt va_list ap; 1717f06ca4afSHartmut Brandt 171870af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 171970af00a1SHartmut Brandt return; 172070af00a1SHartmut Brandt 1721f06ca4afSHartmut Brandt va_start(ap, err); 1722f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 172370af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 172470af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1725f06ca4afSHartmut Brandt va_end(ap); 1726f06ca4afSHartmut Brandt 1727f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1728f06ca4afSHartmut Brandt } 1729f06ca4afSHartmut Brandt 1730f06ca4afSHartmut Brandt static void 1731f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 1732f06ca4afSHartmut Brandt { 1733f06ca4afSHartmut Brandt char errbuf[1000]; 1734f06ca4afSHartmut Brandt va_list ap; 1735f06ca4afSHartmut Brandt 1736f06ca4afSHartmut Brandt va_start(ap, err); 1737f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1738f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1739f06ca4afSHartmut Brandt err, ap); 1740f06ca4afSHartmut Brandt va_end(ap); 1741f06ca4afSHartmut Brandt 1742f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 1743f06ca4afSHartmut Brandt } 1744f06ca4afSHartmut Brandt 1745f06ca4afSHartmut Brandt static void 1746f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 1747f06ca4afSHartmut Brandt { 1748f06ca4afSHartmut Brandt char errbuf[1000]; 1749f06ca4afSHartmut Brandt va_list ap; 1750f06ca4afSHartmut Brandt u_int i; 1751f06ca4afSHartmut Brandt 175270af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 175370af00a1SHartmut Brandt return; 175470af00a1SHartmut Brandt 1755f06ca4afSHartmut Brandt va_start(ap, err); 1756f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 175770af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 175870af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1759f06ca4afSHartmut Brandt va_end(ap); 1760f06ca4afSHartmut Brandt 1761f06ca4afSHartmut Brandt if (b != NULL) { 176270af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 176370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 1764f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 1765f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 176670af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 176770af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 1768f06ca4afSHartmut Brandt } 1769f06ca4afSHartmut Brandt 1770f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1771f06ca4afSHartmut Brandt } 1772f06ca4afSHartmut Brandt 1773f06ca4afSHartmut Brandt /* 1774f06ca4afSHartmut Brandt * Create a new community 1775f06ca4afSHartmut Brandt */ 1776f06ca4afSHartmut Brandt u_int 1777f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 1778f06ca4afSHartmut Brandt const char *str) 1779f06ca4afSHartmut Brandt { 1780f06ca4afSHartmut Brandt struct community *c, *p; 1781f06ca4afSHartmut Brandt u_int ncomm; 1782f06ca4afSHartmut Brandt 1783f06ca4afSHartmut Brandt /* generate an identifier */ 1784f06ca4afSHartmut Brandt do { 1785f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 1786f06ca4afSHartmut Brandt next_community_index = 1; 1787f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 1788f06ca4afSHartmut Brandt if (c->value == ncomm) 1789f06ca4afSHartmut Brandt break; 1790f06ca4afSHartmut Brandt } while (c != NULL); 1791f06ca4afSHartmut Brandt 1792f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 1793f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 1794f06ca4afSHartmut Brandt return (0); 1795f06ca4afSHartmut Brandt } 1796f06ca4afSHartmut Brandt c->owner = owner; 1797f06ca4afSHartmut Brandt c->value = ncomm; 1798f06ca4afSHartmut Brandt c->descr = descr; 1799f06ca4afSHartmut Brandt c->string = NULL; 1800f06ca4afSHartmut Brandt c->private = priv; 1801f06ca4afSHartmut Brandt 1802f06ca4afSHartmut Brandt if (str != NULL) { 1803f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 1804f06ca4afSHartmut Brandt free(c); 1805f06ca4afSHartmut Brandt return (0); 1806f06ca4afSHartmut Brandt } 1807f06ca4afSHartmut Brandt strcpy(c->string, str); 1808f06ca4afSHartmut Brandt } 1809f06ca4afSHartmut Brandt 1810f06ca4afSHartmut Brandt /* make index */ 1811f06ca4afSHartmut Brandt if (c->owner == NULL) { 1812f06ca4afSHartmut Brandt c->index.len = 1; 1813f06ca4afSHartmut Brandt c->index.subs[0] = 0; 1814f06ca4afSHartmut Brandt } else { 1815f06ca4afSHartmut Brandt c->index = c->owner->index; 1816f06ca4afSHartmut Brandt } 1817f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 1818f06ca4afSHartmut Brandt 1819f06ca4afSHartmut Brandt /* 1820f06ca4afSHartmut Brandt * Insert ordered 1821f06ca4afSHartmut Brandt */ 1822f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 1823f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 1824f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 1825f06ca4afSHartmut Brandt break; 1826f06ca4afSHartmut Brandt } 1827f06ca4afSHartmut Brandt } 1828f06ca4afSHartmut Brandt if (p == NULL) 1829f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 1830f06ca4afSHartmut Brandt return (c->value); 1831f06ca4afSHartmut Brandt } 1832f06ca4afSHartmut Brandt 1833f06ca4afSHartmut Brandt const char * 1834f06ca4afSHartmut Brandt comm_string(u_int ncomm) 1835f06ca4afSHartmut Brandt { 1836f06ca4afSHartmut Brandt struct community *p; 1837f06ca4afSHartmut Brandt 1838f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 1839f06ca4afSHartmut Brandt if (p->value == ncomm) 1840f06ca4afSHartmut Brandt return (p->string); 1841f06ca4afSHartmut Brandt return (NULL); 1842f06ca4afSHartmut Brandt } 1843f06ca4afSHartmut Brandt 1844f06ca4afSHartmut Brandt /* 1845f06ca4afSHartmut Brandt * Delete all communities allocated by a module 1846f06ca4afSHartmut Brandt */ 1847f06ca4afSHartmut Brandt static void 1848f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 1849f06ca4afSHartmut Brandt { 1850f06ca4afSHartmut Brandt struct community *p, *p1; 1851f06ca4afSHartmut Brandt 1852f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 1853f06ca4afSHartmut Brandt while (p != NULL) { 1854f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 1855f06ca4afSHartmut Brandt if (p->owner == mod) { 1856f06ca4afSHartmut Brandt free(p->string); 1857f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 1858f06ca4afSHartmut Brandt free(p); 1859f06ca4afSHartmut Brandt } 1860f06ca4afSHartmut Brandt p = p1; 1861f06ca4afSHartmut Brandt } 1862f06ca4afSHartmut Brandt } 1863f06ca4afSHartmut Brandt 1864f06ca4afSHartmut Brandt /* 1865f06ca4afSHartmut Brandt * Request ID handling. 1866f06ca4afSHartmut Brandt * 1867f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 1868f06ca4afSHartmut Brandt */ 1869f06ca4afSHartmut Brandt u_int 1870f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 1871f06ca4afSHartmut Brandt { 1872f06ca4afSHartmut Brandt u_int type; 1873f06ca4afSHartmut Brandt struct idrange *r, *r1; 1874f06ca4afSHartmut Brandt 1875f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 1876f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1877f06ca4afSHartmut Brandt return (0); 1878f06ca4afSHartmut Brandt } 1879f06ca4afSHartmut Brandt /* allocate a type id */ 1880f06ca4afSHartmut Brandt do { 1881f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 1882f06ca4afSHartmut Brandt next_idrange = 1; 1883f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1884f06ca4afSHartmut Brandt if (r->type == type) 1885f06ca4afSHartmut Brandt break; 1886f06ca4afSHartmut Brandt } while(r != NULL); 1887f06ca4afSHartmut Brandt 1888f06ca4afSHartmut Brandt /* find a range */ 1889f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 1890f06ca4afSHartmut Brandt r = NULL; 1891f06ca4afSHartmut Brandt else { 1892f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 1893f06ca4afSHartmut Brandt if (r->base < size) { 1894f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1895f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 1896f06ca4afSHartmut Brandt break; 1897f06ca4afSHartmut Brandt r = r1; 1898f06ca4afSHartmut Brandt } 1899f06ca4afSHartmut Brandt r = r1; 1900f06ca4afSHartmut Brandt } 1901f06ca4afSHartmut Brandt if (r == NULL) { 1902f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 1903f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 1904f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 1905f06ca4afSHartmut Brandt return (0); 1906f06ca4afSHartmut Brandt } 1907f06ca4afSHartmut Brandt } 1908f06ca4afSHartmut Brandt } 1909f06ca4afSHartmut Brandt 1910f06ca4afSHartmut Brandt /* allocate structure */ 1911f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 1912f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 1913f06ca4afSHartmut Brandt return (0); 1914f06ca4afSHartmut Brandt } 1915f06ca4afSHartmut Brandt 1916f06ca4afSHartmut Brandt r1->type = type; 1917f06ca4afSHartmut Brandt r1->size = size; 1918f06ca4afSHartmut Brandt r1->owner = mod; 1919f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 1920f06ca4afSHartmut Brandt r1->base = 0; 1921f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 1922f06ca4afSHartmut Brandt } else if (r == NULL) { 1923f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 1924f06ca4afSHartmut Brandt r1->base = r->base + r->size; 1925f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 1926f06ca4afSHartmut Brandt } else { 1927f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 1928f06ca4afSHartmut Brandt r1->base = r->base + r->size; 1929f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 1930f06ca4afSHartmut Brandt } 1931f06ca4afSHartmut Brandt r1->next = r1->base; 1932f06ca4afSHartmut Brandt 1933f06ca4afSHartmut Brandt return (type); 1934f06ca4afSHartmut Brandt } 1935f06ca4afSHartmut Brandt 1936f06ca4afSHartmut Brandt int32_t 1937f06ca4afSHartmut Brandt reqid_next(u_int type) 1938f06ca4afSHartmut Brandt { 1939f06ca4afSHartmut Brandt struct idrange *r; 1940f06ca4afSHartmut Brandt int32_t id; 1941f06ca4afSHartmut Brandt 1942f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1943f06ca4afSHartmut Brandt if (r->type == type) 1944f06ca4afSHartmut Brandt break; 1945f06ca4afSHartmut Brandt if (r == NULL) { 1946f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 1947f06ca4afSHartmut Brandt abort(); 1948f06ca4afSHartmut Brandt } 1949f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 1950f06ca4afSHartmut Brandt r->next = r->base; 1951f06ca4afSHartmut Brandt return (id); 1952f06ca4afSHartmut Brandt } 1953f06ca4afSHartmut Brandt 1954f06ca4afSHartmut Brandt int32_t 1955f06ca4afSHartmut Brandt reqid_base(u_int type) 1956f06ca4afSHartmut Brandt { 1957f06ca4afSHartmut Brandt struct idrange *r; 1958f06ca4afSHartmut Brandt 1959f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1960f06ca4afSHartmut Brandt if (r->type == type) 1961f06ca4afSHartmut Brandt return (r->base); 1962f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 1963f06ca4afSHartmut Brandt abort(); 1964f06ca4afSHartmut Brandt } 1965f06ca4afSHartmut Brandt 1966f06ca4afSHartmut Brandt u_int 1967f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 1968f06ca4afSHartmut Brandt { 1969f06ca4afSHartmut Brandt struct idrange *r; 1970f06ca4afSHartmut Brandt 1971f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1972f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 1973f06ca4afSHartmut Brandt return (r->type); 1974f06ca4afSHartmut Brandt return (0); 1975f06ca4afSHartmut Brandt } 1976f06ca4afSHartmut Brandt 1977f06ca4afSHartmut Brandt int 1978f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 1979f06ca4afSHartmut Brandt { 1980f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 1981f06ca4afSHartmut Brandt } 1982f06ca4afSHartmut Brandt 1983f06ca4afSHartmut Brandt /* 1984f06ca4afSHartmut Brandt * Delete all communities allocated by a module 1985f06ca4afSHartmut Brandt */ 1986f06ca4afSHartmut Brandt static void 1987f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 1988f06ca4afSHartmut Brandt { 1989f06ca4afSHartmut Brandt struct idrange *p, *p1; 1990f06ca4afSHartmut Brandt 1991f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 1992f06ca4afSHartmut Brandt while (p != NULL) { 1993f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 1994f06ca4afSHartmut Brandt if (p->owner == mod) { 1995f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 1996f06ca4afSHartmut Brandt free(p); 1997f06ca4afSHartmut Brandt } 1998f06ca4afSHartmut Brandt p = p1; 1999f06ca4afSHartmut Brandt } 2000f06ca4afSHartmut Brandt } 2001f06ca4afSHartmut Brandt 2002f06ca4afSHartmut Brandt /* 2003f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2004f06ca4afSHartmut Brandt */ 2005f06ca4afSHartmut Brandt static int 2006f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2007f06ca4afSHartmut Brandt { 2008f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2009f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2010f06ca4afSHartmut Brandt 2011f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2012f06ca4afSHartmut Brandt } 2013f06ca4afSHartmut Brandt static int 2014f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2015f06ca4afSHartmut Brandt { 2016f06ca4afSHartmut Brandt struct snmp_node *xtree; 2017f06ca4afSHartmut Brandt u_int i; 2018f06ca4afSHartmut Brandt 2019f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2020f06ca4afSHartmut Brandt if (xtree == NULL) { 20218eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2022f06ca4afSHartmut Brandt return (-1); 2023f06ca4afSHartmut Brandt } 2024f06ca4afSHartmut Brandt tree = xtree; 2025f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2026f06ca4afSHartmut Brandt 2027f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 20288eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2029f06ca4afSHartmut Brandt 2030f06ca4afSHartmut Brandt tree_size += nsize; 2031f06ca4afSHartmut Brandt 2032f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2033f06ca4afSHartmut Brandt 2034f06ca4afSHartmut Brandt return (0); 2035f06ca4afSHartmut Brandt } 2036f06ca4afSHartmut Brandt 2037f06ca4afSHartmut Brandt /* 2038f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2039f06ca4afSHartmut Brandt */ 2040f06ca4afSHartmut Brandt static void 2041f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2042f06ca4afSHartmut Brandt { 2043f06ca4afSHartmut Brandt u_int s, d; 2044f06ca4afSHartmut Brandt 2045f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 20468eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2047f06ca4afSHartmut Brandt if (s != d) 2048f06ca4afSHartmut Brandt tree[d] = tree[s]; 2049f06ca4afSHartmut Brandt d++; 2050f06ca4afSHartmut Brandt } 2051f06ca4afSHartmut Brandt tree_size = d; 2052f06ca4afSHartmut Brandt } 2053f06ca4afSHartmut Brandt 2054f06ca4afSHartmut Brandt /* 2055f06ca4afSHartmut Brandt * Loadable modules 2056f06ca4afSHartmut Brandt */ 2057f06ca4afSHartmut Brandt struct lmodule * 2058f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2059f06ca4afSHartmut Brandt { 2060f06ca4afSHartmut Brandt struct lmodule *m; 2061f06ca4afSHartmut Brandt int err; 2062f06ca4afSHartmut Brandt int i; 2063f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2064f06ca4afSHartmut Brandt int ac; 2065f06ca4afSHartmut Brandt u_int u; 2066f06ca4afSHartmut Brandt 2067f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2068f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2069f06ca4afSHartmut Brandt return (NULL); 2070f06ca4afSHartmut Brandt } 2071f06ca4afSHartmut Brandt m->handle = NULL; 2072f06ca4afSHartmut Brandt m->flags = 0; 2073f06ca4afSHartmut Brandt strcpy(m->section, section); 2074f06ca4afSHartmut Brandt 2075f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2076f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2077f06ca4afSHartmut Brandt goto err; 2078f06ca4afSHartmut Brandt } 2079f06ca4afSHartmut Brandt strcpy(m->path, path); 2080f06ca4afSHartmut Brandt 2081f06ca4afSHartmut Brandt /* 2082f06ca4afSHartmut Brandt * Make index 2083f06ca4afSHartmut Brandt */ 2084f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2085f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2086f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2087f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2088f06ca4afSHartmut Brandt 2089f06ca4afSHartmut Brandt /* 2090f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2091f06ca4afSHartmut Brandt */ 2092f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2093f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2094f06ca4afSHartmut Brandt goto err; 2095f06ca4afSHartmut Brandt } 2096f06ca4afSHartmut Brandt 2097f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2098f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2099f06ca4afSHartmut Brandt goto err; 2100f06ca4afSHartmut Brandt } 2101f06ca4afSHartmut Brandt 2102f06ca4afSHartmut Brandt /* 2103f06ca4afSHartmut Brandt * Insert it into the right place 2104f06ca4afSHartmut Brandt */ 2105f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2106f06ca4afSHartmut Brandt 2107f06ca4afSHartmut Brandt /* preserve order */ 2108f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2109f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2110f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2111f06ca4afSHartmut Brandt } 2112f06ca4afSHartmut Brandt 2113f06ca4afSHartmut Brandt /* 2114f06ca4afSHartmut Brandt * make the argument vector. 2115f06ca4afSHartmut Brandt */ 2116f06ca4afSHartmut Brandt ac = 0; 2117f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2118f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2119f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2120f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2121f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2122f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2123f06ca4afSHartmut Brandt "module '%s", section); 2124f06ca4afSHartmut Brandt break; 2125f06ca4afSHartmut Brandt } 2126f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2127f06ca4afSHartmut Brandt } 2128f06ca4afSHartmut Brandt } 2129f06ca4afSHartmut Brandt av[ac] = NULL; 2130f06ca4afSHartmut Brandt 2131f06ca4afSHartmut Brandt /* 2132f06ca4afSHartmut Brandt * Run the initialisation function 2133f06ca4afSHartmut Brandt */ 2134f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2135f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2136f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2137f06ca4afSHartmut Brandt goto err; 2138f06ca4afSHartmut Brandt } 2139f06ca4afSHartmut Brandt 2140f06ca4afSHartmut Brandt return (m); 2141f06ca4afSHartmut Brandt 2142f06ca4afSHartmut Brandt err: 2143f06ca4afSHartmut Brandt if (m->handle) 2144f06ca4afSHartmut Brandt dlclose(m->handle); 2145f06ca4afSHartmut Brandt free(m->path); 2146f06ca4afSHartmut Brandt free(m); 2147f06ca4afSHartmut Brandt return (NULL); 2148f06ca4afSHartmut Brandt } 2149f06ca4afSHartmut Brandt 2150f06ca4afSHartmut Brandt /* 2151f06ca4afSHartmut Brandt * Start a module 2152f06ca4afSHartmut Brandt */ 2153f06ca4afSHartmut Brandt void 2154f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2155f06ca4afSHartmut Brandt { 2156f06ca4afSHartmut Brandt const struct lmodule *m; 2157f06ca4afSHartmut Brandt 2158f06ca4afSHartmut Brandt /* 2159f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2160f06ca4afSHartmut Brandt */ 2161f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2162f06ca4afSHartmut Brandt lm_unload(mod); 2163f06ca4afSHartmut Brandt return; 2164f06ca4afSHartmut Brandt } 2165f06ca4afSHartmut Brandt 2166f06ca4afSHartmut Brandt /* 2167f06ca4afSHartmut Brandt * Read configuration 2168f06ca4afSHartmut Brandt */ 2169f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2170f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2171f06ca4afSHartmut Brandt lm_unload(mod); 2172f06ca4afSHartmut Brandt return; 2173f06ca4afSHartmut Brandt } 2174f06ca4afSHartmut Brandt if (mod->config->start) 2175f06ca4afSHartmut Brandt (*mod->config->start)(); 2176f06ca4afSHartmut Brandt 2177f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2178f06ca4afSHartmut Brandt 2179f06ca4afSHartmut Brandt /* 2180f06ca4afSHartmut Brandt * Inform other modules 2181f06ca4afSHartmut Brandt */ 2182f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2183f06ca4afSHartmut Brandt if (m->config->loading) 2184f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2185f06ca4afSHartmut Brandt } 2186f06ca4afSHartmut Brandt 2187f06ca4afSHartmut Brandt 2188f06ca4afSHartmut Brandt /* 2189f06ca4afSHartmut Brandt * Unload a module. 2190f06ca4afSHartmut Brandt */ 2191f06ca4afSHartmut Brandt void 2192f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2193f06ca4afSHartmut Brandt { 2194f06ca4afSHartmut Brandt int err; 2195f06ca4afSHartmut Brandt const struct lmodule *mod; 2196f06ca4afSHartmut Brandt 2197f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2198f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2199f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2200f06ca4afSHartmut Brandt tree_unmerge(m); 2201f06ca4afSHartmut Brandt 2202f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2203f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2204f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2205f06ca4afSHartmut Brandt 2206f06ca4afSHartmut Brandt comm_flush(m); 2207f06ca4afSHartmut Brandt reqid_flush(m); 2208f06ca4afSHartmut Brandt timer_flush(m); 2209f06ca4afSHartmut Brandt fd_flush(m); 2210f06ca4afSHartmut Brandt 2211f06ca4afSHartmut Brandt dlclose(m->handle); 2212f06ca4afSHartmut Brandt free(m->path); 2213f06ca4afSHartmut Brandt 2214f06ca4afSHartmut Brandt /* 2215f06ca4afSHartmut Brandt * Inform other modules 2216f06ca4afSHartmut Brandt */ 2217f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2218f06ca4afSHartmut Brandt if (mod->config->loading) 2219f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2220f06ca4afSHartmut Brandt 2221f06ca4afSHartmut Brandt free(m); 2222f06ca4afSHartmut Brandt } 2223f06ca4afSHartmut Brandt 2224f06ca4afSHartmut Brandt /* 2225f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2226f06ca4afSHartmut Brandt */ 2227f06ca4afSHartmut Brandt u_int 2228f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2229f06ca4afSHartmut Brandt { 2230f06ca4afSHartmut Brandt struct objres *objres, *or1; 2231f06ca4afSHartmut Brandt u_int idx; 2232f06ca4afSHartmut Brandt 2233f06ca4afSHartmut Brandt /* find a free index */ 2234f06ca4afSHartmut Brandt idx = 1; 2235f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2236f06ca4afSHartmut Brandt objres != NULL; 2237f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2238f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2239f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2240f06ca4afSHartmut Brandt idx = objres->index + 1; 2241f06ca4afSHartmut Brandt break; 2242f06ca4afSHartmut Brandt } 2243f06ca4afSHartmut Brandt } 2244f06ca4afSHartmut Brandt 2245f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2246f06ca4afSHartmut Brandt return (0); 2247f06ca4afSHartmut Brandt 2248f06ca4afSHartmut Brandt objres->index = idx; 2249f06ca4afSHartmut Brandt objres->oid = *or; 2250f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 2251f06ca4afSHartmut Brandt objres->uptime = get_ticks() - start_tick; 2252f06ca4afSHartmut Brandt objres->module = mod; 2253f06ca4afSHartmut Brandt 2254f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2255f06ca4afSHartmut Brandt 2256f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2257f06ca4afSHartmut Brandt 2258f06ca4afSHartmut Brandt return (idx); 2259f06ca4afSHartmut Brandt } 2260f06ca4afSHartmut Brandt 2261f06ca4afSHartmut Brandt void 2262f06ca4afSHartmut Brandt or_unregister(u_int idx) 2263f06ca4afSHartmut Brandt { 2264f06ca4afSHartmut Brandt struct objres *objres; 2265f06ca4afSHartmut Brandt 2266f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2267f06ca4afSHartmut Brandt if (objres->index == idx) { 2268f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2269f06ca4afSHartmut Brandt free(objres); 2270f06ca4afSHartmut Brandt return; 2271f06ca4afSHartmut Brandt } 2272f06ca4afSHartmut Brandt } 2273