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 * 8f06ca4afSHartmut Brandt * Redistribution of this software and documentation and use in source and 9f06ca4afSHartmut Brandt * binary forms, with or without modification, are permitted provided that 10f06ca4afSHartmut Brandt * the following conditions are met: 11f06ca4afSHartmut Brandt * 12f06ca4afSHartmut Brandt * 1. Redistributions of source code or documentation must retain the above 13f06ca4afSHartmut Brandt * copyright notice, this list of conditions and the following disclaimer. 14f06ca4afSHartmut Brandt * 2. Redistributions in binary form must reproduce the above copyright 15f06ca4afSHartmut Brandt * notice, this list of conditions and the following disclaimer in the 16f06ca4afSHartmut Brandt * documentation and/or other materials provided with the distribution. 17f06ca4afSHartmut Brandt * 3. Neither the name of the Institute nor the names of its contributors 18f06ca4afSHartmut Brandt * may be used to endorse or promote products derived from this software 19f06ca4afSHartmut Brandt * without specific prior written permission. 20f06ca4afSHartmut Brandt * 21f06ca4afSHartmut Brandt * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22f06ca4afSHartmut Brandt * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23f06ca4afSHartmut Brandt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24f06ca4afSHartmut Brandt * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25f06ca4afSHartmut Brandt * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26f06ca4afSHartmut Brandt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27f06ca4afSHartmut Brandt * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28f06ca4afSHartmut Brandt * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29f06ca4afSHartmut Brandt * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30f06ca4afSHartmut Brandt * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31f06ca4afSHartmut Brandt * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32f06ca4afSHartmut Brandt * 338eecd77aSHartmut Brandt * $Begemot: bsnmp/snmpd/main.c,v 1.85 2004/04/14 15:39:14 novo Exp $ 34f06ca4afSHartmut Brandt * 35f06ca4afSHartmut Brandt * SNMPd main stuff. 36f06ca4afSHartmut Brandt */ 37f06ca4afSHartmut Brandt #include <sys/param.h> 38f06ca4afSHartmut Brandt #include <sys/un.h> 3970af00a1SHartmut Brandt #include <sys/ucred.h> 40f06ca4afSHartmut Brandt #include <stdio.h> 41f06ca4afSHartmut Brandt #include <stdlib.h> 42f06ca4afSHartmut Brandt #include <stddef.h> 43f06ca4afSHartmut Brandt #include <string.h> 44f06ca4afSHartmut Brandt #include <stdarg.h> 45f06ca4afSHartmut Brandt #include <ctype.h> 46f06ca4afSHartmut Brandt #include <errno.h> 47f06ca4afSHartmut Brandt #include <syslog.h> 48f06ca4afSHartmut Brandt #include <unistd.h> 49f06ca4afSHartmut Brandt #include <signal.h> 50f06ca4afSHartmut Brandt #include <dlfcn.h> 51f06ca4afSHartmut Brandt #include <inttypes.h> 52f06ca4afSHartmut Brandt 53f06ca4afSHartmut Brandt #include "snmpmod.h" 54f06ca4afSHartmut Brandt #include "snmpd.h" 55f06ca4afSHartmut Brandt #include "tree.h" 56f06ca4afSHartmut Brandt #include "oid.h" 57f06ca4afSHartmut Brandt 58f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 59f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 60f06ca4afSHartmut Brandt 61f06ca4afSHartmut Brandt u_int32_t this_tick; /* start of processing of current packet */ 62f06ca4afSHartmut Brandt u_int32_t start_tick; /* start of processing */ 63f06ca4afSHartmut Brandt 64f06ca4afSHartmut Brandt struct systemg systemg = { 65f06ca4afSHartmut Brandt NULL, 66f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 67f06ca4afSHartmut Brandt NULL, NULL, NULL, 68f06ca4afSHartmut Brandt 64 + 8 + 4, 69f06ca4afSHartmut Brandt 0 70f06ca4afSHartmut Brandt }; 71f06ca4afSHartmut Brandt struct debug debug = { 72f06ca4afSHartmut Brandt 0, /* dump_pdus */ 73f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 74f06ca4afSHartmut Brandt 0, /* evdebug */ 75f06ca4afSHartmut Brandt }; 76f06ca4afSHartmut Brandt 77f06ca4afSHartmut Brandt struct snmpd snmpd = { 78f06ca4afSHartmut Brandt 2048, /* txbuf */ 79f06ca4afSHartmut Brandt 2048, /* rxbuf */ 80f06ca4afSHartmut Brandt 0, /* comm_dis */ 81f06ca4afSHartmut Brandt 0, /* auth_traps */ 82f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 8370af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 84f06ca4afSHartmut Brandt }; 85f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 86f06ca4afSHartmut Brandt 87f06ca4afSHartmut Brandt /* snmpSerialNo */ 88f06ca4afSHartmut Brandt int32_t snmp_serial_no; 89f06ca4afSHartmut Brandt 90f06ca4afSHartmut Brandt /* search path for config files */ 91f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 92f06ca4afSHartmut Brandt 93f06ca4afSHartmut Brandt /* list of all loaded modules */ 94f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 95f06ca4afSHartmut Brandt 96f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 97f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 98f06ca4afSHartmut Brandt 99f06ca4afSHartmut Brandt /* list of all known communities */ 100f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 101f06ca4afSHartmut Brandt 102f06ca4afSHartmut Brandt /* list of all installed object resources */ 103f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 104f06ca4afSHartmut Brandt 105f06ca4afSHartmut Brandt /* community value generator */ 106f06ca4afSHartmut Brandt static u_int next_community_index = 1; 107f06ca4afSHartmut Brandt 108f06ca4afSHartmut Brandt /* list of all known ranges */ 109f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 110f06ca4afSHartmut Brandt 111f06ca4afSHartmut Brandt /* identifier generator */ 112f06ca4afSHartmut Brandt u_int next_idrange = 1; 113f06ca4afSHartmut Brandt 114f06ca4afSHartmut Brandt /* list of all current timers */ 115f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 116f06ca4afSHartmut Brandt 117f06ca4afSHartmut Brandt /* list of file descriptors */ 118f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 119f06ca4afSHartmut Brandt 120f06ca4afSHartmut Brandt /* program arguments */ 121f06ca4afSHartmut Brandt static char **progargs; 122f06ca4afSHartmut Brandt static int nprogargs; 123f06ca4afSHartmut Brandt 124f06ca4afSHartmut Brandt /* current community */ 125f06ca4afSHartmut Brandt u_int community; 126f06ca4afSHartmut Brandt static struct community *comm; 127f06ca4afSHartmut Brandt 128f06ca4afSHartmut Brandt /* file names */ 129f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 130f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 131f06ca4afSHartmut Brandt 13270af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 133f06ca4afSHartmut Brandt /* event context */ 134f06ca4afSHartmut Brandt static evContext evctx; 13570af00a1SHartmut Brandt #endif 136f06ca4afSHartmut Brandt 137f06ca4afSHartmut Brandt /* signal mask */ 138f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 139f06ca4afSHartmut Brandt 140f06ca4afSHartmut Brandt /* signal handling */ 141f06ca4afSHartmut Brandt static int work; 142f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 143f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 144f06ca4afSHartmut Brandt 145f06ca4afSHartmut Brandt /* oids */ 146f06ca4afSHartmut Brandt static const struct asn_oid 147f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 148f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 149f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 150f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 151f06ca4afSHartmut Brandt 152f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 153f06ca4afSHartmut Brandt 154f06ca4afSHartmut Brandt /* request id generator for traps */ 155f06ca4afSHartmut Brandt u_int trap_reqid; 156f06ca4afSHartmut Brandt 157f06ca4afSHartmut Brandt /* help text */ 158f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 159f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 160f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 161f06ca4afSHartmut Brandt usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\ 162f06ca4afSHartmut Brandt [-m variable=value] [-p file]\n\ 163f06ca4afSHartmut Brandt options:\n\ 164f06ca4afSHartmut Brandt -d don't daemonize\n\ 165f06ca4afSHartmut Brandt -h print this info\n\ 166f06ca4afSHartmut Brandt -c file specify configuration file\n\ 167f06ca4afSHartmut Brandt -D options debugging options\n\ 168f06ca4afSHartmut Brandt -I path system include path\n\ 169f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 170f06ca4afSHartmut Brandt -m var=val define variable\n\ 171f06ca4afSHartmut Brandt -p file specify pid file\n\ 172f06ca4afSHartmut Brandt "; 173f06ca4afSHartmut Brandt 17470af00a1SHartmut Brandt /* transports */ 17570af00a1SHartmut Brandt extern const struct transport_def udp_trans; 17670af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 17770af00a1SHartmut Brandt 17870af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 17970af00a1SHartmut Brandt 180f06ca4afSHartmut Brandt /* forward declarations */ 181f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 182f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 183f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 184f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 185f06ca4afSHartmut Brandt 186f06ca4afSHartmut Brandt /* 187f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 188f06ca4afSHartmut Brandt */ 189f06ca4afSHartmut Brandt void * 190f06ca4afSHartmut Brandt buf_alloc(int tx) 191f06ca4afSHartmut Brandt { 192f06ca4afSHartmut Brandt void *buf; 193f06ca4afSHartmut Brandt 19470af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 195f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 196f06ca4afSHartmut Brandt if (tx) 197f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 198f06ca4afSHartmut Brandt else 199f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 200f06ca4afSHartmut Brandt return (NULL); 201f06ca4afSHartmut Brandt } 202f06ca4afSHartmut Brandt return (buf); 203f06ca4afSHartmut Brandt } 204f06ca4afSHartmut Brandt 205f06ca4afSHartmut Brandt /* 20670af00a1SHartmut Brandt * Return the buffer size. 207f06ca4afSHartmut Brandt */ 208f06ca4afSHartmut Brandt size_t 209f06ca4afSHartmut Brandt buf_size(int tx) 210f06ca4afSHartmut Brandt { 21170af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 212f06ca4afSHartmut Brandt } 213f06ca4afSHartmut Brandt 214f06ca4afSHartmut Brandt /* 215f06ca4afSHartmut Brandt * Prepare a PDU for output 216f06ca4afSHartmut Brandt */ 217f06ca4afSHartmut Brandt void 21870af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 219f06ca4afSHartmut Brandt const char *dest) 220f06ca4afSHartmut Brandt { 221f06ca4afSHartmut Brandt struct asn_buf resp_b; 222f06ca4afSHartmut Brandt 223f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 224f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 225f06ca4afSHartmut Brandt 226f06ca4afSHartmut Brandt if (snmp_pdu_encode(pdu, &resp_b) != 0) { 227f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot encode message"); 228f06ca4afSHartmut Brandt abort(); 229f06ca4afSHartmut Brandt } 230f06ca4afSHartmut Brandt if (debug.dump_pdus) { 231f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 232f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 233f06ca4afSHartmut Brandt } 234f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 235f06ca4afSHartmut Brandt } 236f06ca4afSHartmut Brandt 237f06ca4afSHartmut Brandt /* 238f06ca4afSHartmut Brandt * SNMP input. Start: decode the PDU, find the community. 239f06ca4afSHartmut Brandt */ 240f06ca4afSHartmut Brandt enum snmpd_input_err 241f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 24270af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 243f06ca4afSHartmut Brandt { 244f06ca4afSHartmut Brandt struct asn_buf b; 245f06ca4afSHartmut Brandt enum snmp_code code; 246f06ca4afSHartmut Brandt enum snmpd_input_err ret; 24770af00a1SHartmut Brandt int sret; 248f06ca4afSHartmut Brandt 249f06ca4afSHartmut Brandt b.asn_cptr = buf; 250f06ca4afSHartmut Brandt b.asn_len = len; 25170af00a1SHartmut Brandt 25270af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 25370af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 25470af00a1SHartmut Brandt 25570af00a1SHartmut Brandt case 0: 25670af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 25770af00a1SHartmut Brandt 25870af00a1SHartmut Brandt case -1: 25970af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 26070af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 26170af00a1SHartmut Brandt } 26270af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 26370af00a1SHartmut Brandt 264f06ca4afSHartmut Brandt code = snmp_pdu_decode(&b, pdu, ip); 265f06ca4afSHartmut Brandt 26670af00a1SHartmut Brandt snmpd_stats.inPkts++; 26770af00a1SHartmut Brandt 268f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 269f06ca4afSHartmut Brandt switch (code) { 270f06ca4afSHartmut Brandt 271f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 272f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 273f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 274f06ca4afSHartmut Brandt 275f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 27670af00a1SHartmut Brandt bad_vers: 277f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 278f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 279f06ca4afSHartmut Brandt 280f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 281f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 282f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 283f06ca4afSHartmut Brandt break; 284f06ca4afSHartmut Brandt 285f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 286f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 287f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 288f06ca4afSHartmut Brandt break; 289f06ca4afSHartmut Brandt 290f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 291f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 292f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 293f06ca4afSHartmut Brandt break; 294f06ca4afSHartmut Brandt 295f06ca4afSHartmut Brandt case SNMP_CODE_OK: 29670af00a1SHartmut Brandt switch (pdu->version) { 29770af00a1SHartmut Brandt 29870af00a1SHartmut Brandt case SNMP_V1: 29970af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 30070af00a1SHartmut Brandt goto bad_vers; 30170af00a1SHartmut Brandt break; 30270af00a1SHartmut Brandt 30370af00a1SHartmut Brandt case SNMP_V2c: 30470af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 30570af00a1SHartmut Brandt goto bad_vers; 30670af00a1SHartmut Brandt break; 30770af00a1SHartmut Brandt 30870af00a1SHartmut Brandt case SNMP_Verr: 30970af00a1SHartmut Brandt goto bad_vers; 31070af00a1SHartmut Brandt } 311f06ca4afSHartmut Brandt break; 312f06ca4afSHartmut Brandt } 313f06ca4afSHartmut Brandt 314f06ca4afSHartmut Brandt if (debug.dump_pdus) { 315f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 316f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 317f06ca4afSHartmut Brandt } 318f06ca4afSHartmut Brandt 319f06ca4afSHartmut Brandt /* 320f06ca4afSHartmut Brandt * Look, whether we know the community 321f06ca4afSHartmut Brandt */ 322f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 323f06ca4afSHartmut Brandt if (comm->string != NULL && 324f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 325f06ca4afSHartmut Brandt break; 326f06ca4afSHartmut Brandt 327f06ca4afSHartmut Brandt if (comm == NULL) { 328f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 329f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 330f06ca4afSHartmut Brandt if (snmpd.auth_traps) 331f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, NULL); 332f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 333f06ca4afSHartmut Brandt } 334f06ca4afSHartmut Brandt community = comm->value; 335f06ca4afSHartmut Brandt 336f06ca4afSHartmut Brandt /* update uptime */ 337f06ca4afSHartmut Brandt this_tick = get_ticks(); 338f06ca4afSHartmut Brandt 339f06ca4afSHartmut Brandt return (ret); 340f06ca4afSHartmut Brandt } 341f06ca4afSHartmut Brandt 342f06ca4afSHartmut Brandt /* 343f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 344f06ca4afSHartmut Brandt */ 345f06ca4afSHartmut Brandt enum snmpd_input_err 346f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 347f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 348f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 349f06ca4afSHartmut Brandt { 350f06ca4afSHartmut Brandt struct snmp_pdu resp; 351f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 352f06ca4afSHartmut Brandt enum snmp_ret ret; 353f06ca4afSHartmut Brandt 354f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 355f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 356f06ca4afSHartmut Brandt 357f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 358f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 359f06ca4afSHartmut Brandt 360f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 361f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 362f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 363f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 364f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 365f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 366f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 367f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 368f06ca4afSHartmut Brandt else 369f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 370f06ca4afSHartmut Brandt 371f06ca4afSHartmut Brandt pdu->error_index = ivar; 372f06ca4afSHartmut Brandt 373f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 374f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 375f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 376f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 377f06ca4afSHartmut Brandt } 378f06ca4afSHartmut Brandt 379f06ca4afSHartmut Brandt if (debug.dump_pdus) { 380f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 381f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 382f06ca4afSHartmut Brandt } 383f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 384f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 385f06ca4afSHartmut Brandt } 386f06ca4afSHartmut Brandt 387f06ca4afSHartmut Brandt switch (pdu->type) { 388f06ca4afSHartmut Brandt 389f06ca4afSHartmut Brandt case SNMP_PDU_GET: 390f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 391f06ca4afSHartmut Brandt break; 392f06ca4afSHartmut Brandt 393f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 394f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 395f06ca4afSHartmut Brandt break; 396f06ca4afSHartmut Brandt 397f06ca4afSHartmut Brandt case SNMP_PDU_SET: 398f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 399f06ca4afSHartmut Brandt break; 400f06ca4afSHartmut Brandt 401f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 402f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 403f06ca4afSHartmut Brandt break; 404f06ca4afSHartmut Brandt 405f06ca4afSHartmut Brandt default: 406f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 407f06ca4afSHartmut Brandt break; 408f06ca4afSHartmut Brandt } 409f06ca4afSHartmut Brandt 410f06ca4afSHartmut Brandt switch (ret) { 411f06ca4afSHartmut Brandt 412f06ca4afSHartmut Brandt case SNMP_RET_OK: 413f06ca4afSHartmut Brandt /* normal return - send a response */ 414f06ca4afSHartmut Brandt if (debug.dump_pdus) { 415f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 416f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 417f06ca4afSHartmut Brandt } 418f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 419f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 420f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 421f06ca4afSHartmut Brandt 422f06ca4afSHartmut Brandt case SNMP_RET_IGN: 423f06ca4afSHartmut Brandt /* error - send nothing */ 424f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 425f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 426f06ca4afSHartmut Brandt 427f06ca4afSHartmut Brandt case SNMP_RET_ERR: 428f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 429f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 430f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 431f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 432f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 433f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 434f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 435f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 436f06ca4afSHartmut Brandt } else { 437f06ca4afSHartmut Brandt if (debug.dump_pdus) { 438f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 439f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 440f06ca4afSHartmut Brandt } 441f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 442f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 443f06ca4afSHartmut Brandt } 444f06ca4afSHartmut Brandt } 445f06ca4afSHartmut Brandt abort(); 446f06ca4afSHartmut Brandt } 447f06ca4afSHartmut Brandt 44870af00a1SHartmut Brandt /* 44970af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 45070af00a1SHartmut Brandt */ 45170af00a1SHartmut Brandt void 45270af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 45370af00a1SHartmut Brandt { 45470af00a1SHartmut Brandt struct tport *p; 455f06ca4afSHartmut Brandt 45670af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 45770af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 45870af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 45970af00a1SHartmut Brandt return; 46070af00a1SHartmut Brandt } 46170af00a1SHartmut Brandt } 46270af00a1SHartmut Brandt port->transport = t; 46370af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 46470af00a1SHartmut Brandt } 46570af00a1SHartmut Brandt 46670af00a1SHartmut Brandt /* 46770af00a1SHartmut Brandt * Remove a port from a transport's list 46870af00a1SHartmut Brandt */ 46970af00a1SHartmut Brandt void 47070af00a1SHartmut Brandt trans_remove_port(struct tport *port) 47170af00a1SHartmut Brandt { 47270af00a1SHartmut Brandt 47370af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 47470af00a1SHartmut Brandt } 47570af00a1SHartmut Brandt 47670af00a1SHartmut Brandt /* 47770af00a1SHartmut Brandt * Find a port on a transport's list 47870af00a1SHartmut Brandt */ 47970af00a1SHartmut Brandt struct tport * 48070af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 48170af00a1SHartmut Brandt { 48270af00a1SHartmut Brandt 48370af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 48470af00a1SHartmut Brandt } 48570af00a1SHartmut Brandt 48670af00a1SHartmut Brandt /* 48770af00a1SHartmut Brandt * Find next port on a transport's list 48870af00a1SHartmut Brandt */ 48970af00a1SHartmut Brandt struct tport * 49070af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 49170af00a1SHartmut Brandt { 49270af00a1SHartmut Brandt 49370af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 49470af00a1SHartmut Brandt } 49570af00a1SHartmut Brandt 49670af00a1SHartmut Brandt /* 49770af00a1SHartmut Brandt * Return first port 49870af00a1SHartmut Brandt */ 49970af00a1SHartmut Brandt struct tport * 50070af00a1SHartmut Brandt trans_first_port(struct transport *t) 50170af00a1SHartmut Brandt { 50270af00a1SHartmut Brandt 50370af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 50470af00a1SHartmut Brandt } 50570af00a1SHartmut Brandt 50670af00a1SHartmut Brandt /* 50770af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 50870af00a1SHartmut Brandt */ 50970af00a1SHartmut Brandt struct tport * 51070af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 51170af00a1SHartmut Brandt intptr_t arg) 51270af00a1SHartmut Brandt { 51370af00a1SHartmut Brandt struct tport *p; 51470af00a1SHartmut Brandt 51570af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 51670af00a1SHartmut Brandt if (func(p, arg) == 0) 51770af00a1SHartmut Brandt return (p); 51870af00a1SHartmut Brandt return (NULL); 51970af00a1SHartmut Brandt } 52070af00a1SHartmut Brandt 52170af00a1SHartmut Brandt /* 52270af00a1SHartmut Brandt * Register a transport 52370af00a1SHartmut Brandt */ 52470af00a1SHartmut Brandt int 52570af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 52670af00a1SHartmut Brandt { 52770af00a1SHartmut Brandt u_int i; 52870af00a1SHartmut Brandt char or_descr[256]; 52970af00a1SHartmut Brandt 53070af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 53170af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 53270af00a1SHartmut Brandt 53370af00a1SHartmut Brandt /* construct index */ 53470af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 53570af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 53670af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 53770af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 53870af00a1SHartmut Brandt 53970af00a1SHartmut Brandt (*pp)->vtab = def; 54070af00a1SHartmut Brandt 54170af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 54270af00a1SHartmut Brandt free(*pp); 54370af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 54470af00a1SHartmut Brandt } 54570af00a1SHartmut Brandt 54670af00a1SHartmut Brandt /* register module */ 54770af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 54870af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 54970af00a1SHartmut Brandt free(*pp); 55070af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 55170af00a1SHartmut Brandt } 55270af00a1SHartmut Brandt 55370af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 55470af00a1SHartmut Brandt 55570af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 55670af00a1SHartmut Brandt 55770af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 55870af00a1SHartmut Brandt } 55970af00a1SHartmut Brandt 56070af00a1SHartmut Brandt /* 56170af00a1SHartmut Brandt * Unregister transport 56270af00a1SHartmut Brandt */ 56370af00a1SHartmut Brandt int 56470af00a1SHartmut Brandt trans_unregister(struct transport *t) 56570af00a1SHartmut Brandt { 56670af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 56770af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 56870af00a1SHartmut Brandt 56970af00a1SHartmut Brandt or_unregister(t->or_index); 57070af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 57170af00a1SHartmut Brandt 57270af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 57370af00a1SHartmut Brandt } 574f06ca4afSHartmut Brandt 575f06ca4afSHartmut Brandt /* 576f06ca4afSHartmut Brandt * File descriptor support 577f06ca4afSHartmut Brandt */ 57870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 57970af00a1SHartmut Brandt static void 58070af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 58170af00a1SHartmut Brandt #else 582f06ca4afSHartmut Brandt static void 583f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 58470af00a1SHartmut Brandt #endif 585f06ca4afSHartmut Brandt { 586f06ca4afSHartmut Brandt struct fdesc *f = uap; 587f06ca4afSHartmut Brandt 588f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 589f06ca4afSHartmut Brandt } 590f06ca4afSHartmut Brandt 591f06ca4afSHartmut Brandt void 592f06ca4afSHartmut Brandt fd_suspend(void *p) 593f06ca4afSHartmut Brandt { 594f06ca4afSHartmut Brandt struct fdesc *f = p; 595f06ca4afSHartmut Brandt 59670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 59770af00a1SHartmut Brandt if (f->id >= 0) { 59870af00a1SHartmut Brandt poll_unregister(f->id); 59970af00a1SHartmut Brandt f->id = -1; 60070af00a1SHartmut Brandt } 60170af00a1SHartmut Brandt #else 602f06ca4afSHartmut Brandt if (evTestID(f->id)) { 603f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 604f06ca4afSHartmut Brandt evInitID(&f->id); 605f06ca4afSHartmut Brandt } 60670af00a1SHartmut Brandt #endif 607f06ca4afSHartmut Brandt } 608f06ca4afSHartmut Brandt 609f06ca4afSHartmut Brandt int 610f06ca4afSHartmut Brandt fd_resume(void *p) 611f06ca4afSHartmut Brandt { 612f06ca4afSHartmut Brandt struct fdesc *f = p; 613f06ca4afSHartmut Brandt int err; 614f06ca4afSHartmut Brandt 61570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 61670af00a1SHartmut Brandt if (f->id >= 0) 61770af00a1SHartmut Brandt return (0); 61870af00a1SHartmut Brandt if ((f->fd = poll_register(f->fd, input, f, POLL_IN)) < 0) { 61970af00a1SHartmut Brandt err = errno; 62070af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 62170af00a1SHartmut Brandt errno = err; 62270af00a1SHartmut Brandt return (-1); 62370af00a1SHartmut Brandt } 62470af00a1SHartmut Brandt #else 625f06ca4afSHartmut Brandt if (evTestID(f->id)) 626f06ca4afSHartmut Brandt return (0); 627f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 628f06ca4afSHartmut Brandt err = errno; 629f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 630f06ca4afSHartmut Brandt errno = err; 631f06ca4afSHartmut Brandt return (-1); 632f06ca4afSHartmut Brandt } 63370af00a1SHartmut Brandt #endif 634f06ca4afSHartmut Brandt return (0); 635f06ca4afSHartmut Brandt } 636f06ca4afSHartmut Brandt 637f06ca4afSHartmut Brandt void * 638f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 639f06ca4afSHartmut Brandt { 640f06ca4afSHartmut Brandt struct fdesc *f; 641f06ca4afSHartmut Brandt int err; 642f06ca4afSHartmut Brandt 643f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 644f06ca4afSHartmut Brandt err = errno; 645f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 646f06ca4afSHartmut Brandt errno = err; 647f06ca4afSHartmut Brandt return (NULL); 648f06ca4afSHartmut Brandt } 649f06ca4afSHartmut Brandt f->fd = fd; 650f06ca4afSHartmut Brandt f->func = func; 651f06ca4afSHartmut Brandt f->udata = udata; 652f06ca4afSHartmut Brandt f->owner = mod; 65370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 65470af00a1SHartmut Brandt f->id = -1; 65570af00a1SHartmut Brandt #else 656f06ca4afSHartmut Brandt evInitID(&f->id); 65770af00a1SHartmut Brandt #endif 658f06ca4afSHartmut Brandt 659f06ca4afSHartmut Brandt if (fd_resume(f)) { 660f06ca4afSHartmut Brandt err = errno; 661f06ca4afSHartmut Brandt free(f); 662f06ca4afSHartmut Brandt errno = err; 663f06ca4afSHartmut Brandt return (NULL); 664f06ca4afSHartmut Brandt } 665f06ca4afSHartmut Brandt 666f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 667f06ca4afSHartmut Brandt 668f06ca4afSHartmut Brandt return (f); 669f06ca4afSHartmut Brandt } 670f06ca4afSHartmut Brandt 671f06ca4afSHartmut Brandt void 672f06ca4afSHartmut Brandt fd_deselect(void *p) 673f06ca4afSHartmut Brandt { 674f06ca4afSHartmut Brandt struct fdesc *f = p; 675f06ca4afSHartmut Brandt 676f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 677f06ca4afSHartmut Brandt fd_suspend(f); 678f06ca4afSHartmut Brandt free(f); 679f06ca4afSHartmut Brandt } 680f06ca4afSHartmut Brandt 681f06ca4afSHartmut Brandt static void 682f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 683f06ca4afSHartmut Brandt { 684f06ca4afSHartmut Brandt struct fdesc *t, *t1; 685f06ca4afSHartmut Brandt 686f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 687f06ca4afSHartmut Brandt while (t != NULL) { 688f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 689f06ca4afSHartmut Brandt if (t->owner == mod) 690f06ca4afSHartmut Brandt fd_deselect(t); 691f06ca4afSHartmut Brandt t = t1; 692f06ca4afSHartmut Brandt } 693f06ca4afSHartmut Brandt } 694f06ca4afSHartmut Brandt 695f06ca4afSHartmut Brandt /* 69670af00a1SHartmut Brandt * Consume a message from the input buffer 697f06ca4afSHartmut Brandt */ 698f06ca4afSHartmut Brandt static void 69970af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 700f06ca4afSHartmut Brandt { 70170af00a1SHartmut Brandt if (!pi->stream) { 70270af00a1SHartmut Brandt /* always consume everything */ 70370af00a1SHartmut Brandt pi->length = 0; 70470af00a1SHartmut Brandt return; 70570af00a1SHartmut Brandt } 70670af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 70770af00a1SHartmut Brandt /* all bytes consumed */ 70870af00a1SHartmut Brandt pi->length = 0; 70970af00a1SHartmut Brandt return; 71070af00a1SHartmut Brandt } 71170af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 71270af00a1SHartmut Brandt pi->length -= pi->consumed; 71370af00a1SHartmut Brandt } 71470af00a1SHartmut Brandt 71570af00a1SHartmut Brandt struct credmsg { 71670af00a1SHartmut Brandt struct cmsghdr hdr; 71770af00a1SHartmut Brandt struct cmsgcred cred; 71870af00a1SHartmut Brandt }; 71970af00a1SHartmut Brandt 72070af00a1SHartmut Brandt static void 72170af00a1SHartmut Brandt check_priv(struct port_input *pi, struct msghdr *msg) 72270af00a1SHartmut Brandt { 72370af00a1SHartmut Brandt struct credmsg *cmsg; 72470af00a1SHartmut Brandt struct xucred ucred; 72570af00a1SHartmut Brandt socklen_t ucredlen; 72670af00a1SHartmut Brandt 72770af00a1SHartmut Brandt pi->priv = 0; 72870af00a1SHartmut Brandt 72970af00a1SHartmut Brandt if (msg->msg_controllen == sizeof(*cmsg)) { 73070af00a1SHartmut Brandt /* process explicitely sends credentials */ 73170af00a1SHartmut Brandt 73270af00a1SHartmut Brandt cmsg = (struct credmsg *)msg->msg_control; 73370af00a1SHartmut Brandt pi->priv = (cmsg->cred.cmcred_euid == 0); 73470af00a1SHartmut Brandt return; 73570af00a1SHartmut Brandt } 73670af00a1SHartmut Brandt 73770af00a1SHartmut Brandt /* ok, obtain the accept time credentials */ 73870af00a1SHartmut Brandt ucredlen = sizeof(ucred); 73970af00a1SHartmut Brandt 74070af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 74170af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 74270af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 74370af00a1SHartmut Brandt } 74470af00a1SHartmut Brandt 74570af00a1SHartmut Brandt /* 74670af00a1SHartmut Brandt * Input from a stream socket. 74770af00a1SHartmut Brandt */ 74870af00a1SHartmut Brandt static int 74970af00a1SHartmut Brandt recv_stream(struct port_input *pi) 75070af00a1SHartmut Brandt { 75170af00a1SHartmut Brandt struct msghdr msg; 75270af00a1SHartmut Brandt struct iovec iov[1]; 75370af00a1SHartmut Brandt ssize_t len; 75470af00a1SHartmut Brandt struct credmsg cmsg; 75570af00a1SHartmut Brandt 75670af00a1SHartmut Brandt if (pi->buf == NULL) { 75770af00a1SHartmut Brandt /* no buffer yet - allocate one */ 75870af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 75970af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 76070af00a1SHartmut Brandt * the caller must close the transport. */ 76170af00a1SHartmut Brandt return (-1); 76270af00a1SHartmut Brandt } 76370af00a1SHartmut Brandt pi->buflen = buf_size(0); 76470af00a1SHartmut Brandt pi->consumed = 0; 76570af00a1SHartmut Brandt pi->length = 0; 76670af00a1SHartmut Brandt } 76770af00a1SHartmut Brandt 76870af00a1SHartmut Brandt /* try to get a message */ 76970af00a1SHartmut Brandt msg.msg_name = pi->peer; 77070af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 77170af00a1SHartmut Brandt msg.msg_iov = iov; 77270af00a1SHartmut Brandt msg.msg_iovlen = 1; 77370af00a1SHartmut Brandt if (pi->cred) { 77470af00a1SHartmut Brandt msg.msg_control = &cmsg; 77570af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 77670af00a1SHartmut Brandt 77770af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 77870af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 77970af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 78070af00a1SHartmut Brandt } else { 78170af00a1SHartmut Brandt msg.msg_control = NULL; 78270af00a1SHartmut Brandt msg.msg_controllen = 0; 78370af00a1SHartmut Brandt } 78470af00a1SHartmut Brandt msg.msg_flags = 0; 78570af00a1SHartmut Brandt 78670af00a1SHartmut Brandt iov[0].iov_base = pi->buf + pi->length; 78770af00a1SHartmut Brandt iov[0].iov_len = pi->buflen - pi->length; 78870af00a1SHartmut Brandt 78970af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 79070af00a1SHartmut Brandt 79170af00a1SHartmut Brandt if (len == -1 || len == 0) 79270af00a1SHartmut Brandt /* receive error */ 79370af00a1SHartmut Brandt return (-1); 79470af00a1SHartmut Brandt 79570af00a1SHartmut Brandt pi->length += len; 79670af00a1SHartmut Brandt 79770af00a1SHartmut Brandt if (pi->cred) 79870af00a1SHartmut Brandt check_priv(pi, &msg); 79970af00a1SHartmut Brandt 80070af00a1SHartmut Brandt return (0); 80170af00a1SHartmut Brandt } 80270af00a1SHartmut Brandt 80370af00a1SHartmut Brandt /* 80470af00a1SHartmut Brandt * Input from a datagram socket. 80570af00a1SHartmut Brandt * Each receive should return one datagram. 80670af00a1SHartmut Brandt */ 80770af00a1SHartmut Brandt static int 80870af00a1SHartmut Brandt recv_dgram(struct port_input *pi) 80970af00a1SHartmut Brandt { 81070af00a1SHartmut Brandt u_char embuf[1000]; 81170af00a1SHartmut Brandt struct msghdr msg; 81270af00a1SHartmut Brandt struct iovec iov[1]; 81370af00a1SHartmut Brandt ssize_t len; 81470af00a1SHartmut Brandt struct credmsg cmsg; 81570af00a1SHartmut Brandt 81670af00a1SHartmut Brandt if (pi->buf == NULL) { 81770af00a1SHartmut Brandt /* no buffer yet - allocate one */ 81870af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 81970af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 82070af00a1SHartmut Brandt * and drop it */ 82170af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 82270af00a1SHartmut Brandt 0, NULL, NULL); 82370af00a1SHartmut Brandt /* return error */ 82470af00a1SHartmut Brandt return (-1); 82570af00a1SHartmut Brandt } 82670af00a1SHartmut Brandt pi->buflen = buf_size(0); 82770af00a1SHartmut Brandt } 82870af00a1SHartmut Brandt 82970af00a1SHartmut Brandt /* try to get a message */ 83070af00a1SHartmut Brandt msg.msg_name = pi->peer; 83170af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 83270af00a1SHartmut Brandt msg.msg_iov = iov; 83370af00a1SHartmut Brandt msg.msg_iovlen = 1; 83470af00a1SHartmut Brandt if (pi->cred) { 83570af00a1SHartmut Brandt msg.msg_control = &cmsg; 83670af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 83770af00a1SHartmut Brandt 83870af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 83970af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 84070af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 84170af00a1SHartmut Brandt } else { 84270af00a1SHartmut Brandt msg.msg_control = NULL; 8438eecd77aSHartmut Brandt msg.msg_controllen = 0; 84470af00a1SHartmut Brandt } 84570af00a1SHartmut Brandt msg.msg_flags = 0; 84670af00a1SHartmut Brandt 84770af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 84870af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 84970af00a1SHartmut Brandt 85070af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 85170af00a1SHartmut Brandt 85270af00a1SHartmut Brandt if (len == -1 || len == 0) 85370af00a1SHartmut Brandt /* receive error */ 85470af00a1SHartmut Brandt return (-1); 85570af00a1SHartmut Brandt 85670af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 85770af00a1SHartmut Brandt /* truncated - drop */ 85870af00a1SHartmut Brandt snmpd_stats.silentDrops++; 85970af00a1SHartmut Brandt snmpd_stats.inTooLong++; 86070af00a1SHartmut Brandt return (-1); 86170af00a1SHartmut Brandt } 86270af00a1SHartmut Brandt 86370af00a1SHartmut Brandt pi->length = (size_t)len; 86470af00a1SHartmut Brandt 86570af00a1SHartmut Brandt if (pi->cred) 86670af00a1SHartmut Brandt check_priv(pi, &msg); 86770af00a1SHartmut Brandt 86870af00a1SHartmut Brandt return (0); 86970af00a1SHartmut Brandt } 87070af00a1SHartmut Brandt 87170af00a1SHartmut Brandt /* 87270af00a1SHartmut Brandt * Input from a socket 87370af00a1SHartmut Brandt */ 87470af00a1SHartmut Brandt int 87570af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 87670af00a1SHartmut Brandt { 877f06ca4afSHartmut Brandt u_char *sndbuf; 878f06ca4afSHartmut Brandt size_t sndlen; 87970af00a1SHartmut Brandt struct snmp_pdu pdu; 880f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 881f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 882f06ca4afSHartmut Brandt int32_t vi; 88370af00a1SHartmut Brandt int ret; 88470af00a1SHartmut Brandt ssize_t slen; 885f06ca4afSHartmut Brandt 88670af00a1SHartmut Brandt /* get input depending on the transport */ 88770af00a1SHartmut Brandt if (pi->stream) { 88870af00a1SHartmut Brandt ret = recv_stream(pi); 88970af00a1SHartmut Brandt } else { 89070af00a1SHartmut Brandt ret = recv_dgram(pi); 891f06ca4afSHartmut Brandt } 89270af00a1SHartmut Brandt 89370af00a1SHartmut Brandt if (ret == -1) 89470af00a1SHartmut Brandt return (-1); 895f06ca4afSHartmut Brandt 896f06ca4afSHartmut Brandt /* 897f06ca4afSHartmut Brandt * Handle input 898f06ca4afSHartmut Brandt */ 89970af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 90070af00a1SHartmut Brandt &pi->consumed); 90170af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 90270af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 90370af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 90470af00a1SHartmut Brandt if (pi->stream) { 90570af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 90670af00a1SHartmut Brandt snmpd_stats.silentDrops++; 90770af00a1SHartmut Brandt return (-1); 90870af00a1SHartmut Brandt } 90970af00a1SHartmut Brandt return (0); 91070af00a1SHartmut Brandt } 91170af00a1SHartmut Brandt snmpd_stats.silentDrops++; 91270af00a1SHartmut Brandt return (-1); 91370af00a1SHartmut Brandt } 914f06ca4afSHartmut Brandt 915f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 916f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 917f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 918f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 91970af00a1SHartmut Brandt /* for streaming transports this is fatal */ 92070af00a1SHartmut Brandt if (pi->stream) 92170af00a1SHartmut Brandt return (-1); 92270af00a1SHartmut Brandt snmp_input_consume(pi); 92370af00a1SHartmut Brandt return (0); 924f06ca4afSHartmut Brandt } 925f06ca4afSHartmut Brandt 926f06ca4afSHartmut Brandt /* 927f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 928f06ca4afSHartmut Brandt * the hand it over to the module. 929f06ca4afSHartmut Brandt */ 930f06ca4afSHartmut Brandt if (comm->owner != NULL && comm->owner->config->proxy != NULL) { 93170af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 93270af00a1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, pi->priv); 933f06ca4afSHartmut Brandt 934f06ca4afSHartmut Brandt switch (perr) { 935f06ca4afSHartmut Brandt 936f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 93770af00a1SHartmut Brandt snmp_input_consume(pi); 93870af00a1SHartmut Brandt return (0); 939f06ca4afSHartmut Brandt 940f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 941f06ca4afSHartmut Brandt break; 942f06ca4afSHartmut Brandt 943f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 94470af00a1SHartmut Brandt snmp_input_consume(pi); 945f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 946f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 94770af00a1SHartmut Brandt return (0); 948f06ca4afSHartmut Brandt 949f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 95070af00a1SHartmut Brandt snmp_input_consume(pi); 951f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 952f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 953f06ca4afSHartmut Brandt if (snmpd.auth_traps) 954f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 955f06ca4afSHartmut Brandt NULL); 95670af00a1SHartmut Brandt return (0); 957f06ca4afSHartmut Brandt 958f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 95970af00a1SHartmut Brandt snmp_input_consume(pi); 960f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 961f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 962f06ca4afSHartmut Brandt if (snmpd.auth_traps) 963f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 964f06ca4afSHartmut Brandt NULL); 96570af00a1SHartmut Brandt return (0); 966f06ca4afSHartmut Brandt } 967f06ca4afSHartmut Brandt } 968f06ca4afSHartmut Brandt 969f06ca4afSHartmut Brandt /* 970f06ca4afSHartmut Brandt * Check type 971f06ca4afSHartmut Brandt */ 972f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 973f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 974f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 975f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 976f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 977f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 97870af00a1SHartmut Brandt snmp_input_consume(pi); 97970af00a1SHartmut Brandt return (0); 980f06ca4afSHartmut Brandt } 981f06ca4afSHartmut Brandt 982f06ca4afSHartmut Brandt /* 983f06ca4afSHartmut Brandt * Check community 984f06ca4afSHartmut Brandt */ 98570af00a1SHartmut Brandt if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 98670af00a1SHartmut Brandt (community != COMM_WRITE && 98770af00a1SHartmut Brandt (pdu.type == SNMP_PDU_SET || community != COMM_READ))) { 988f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 989f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 99070af00a1SHartmut Brandt snmp_input_consume(pi); 991f06ca4afSHartmut Brandt if (snmpd.auth_traps) 992f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, NULL); 99370af00a1SHartmut Brandt return (0); 994f06ca4afSHartmut Brandt } 995f06ca4afSHartmut Brandt 996f06ca4afSHartmut Brandt /* 997f06ca4afSHartmut Brandt * Execute it. 998f06ca4afSHartmut Brandt */ 999f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1000f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1001f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 100270af00a1SHartmut Brandt snmp_input_consume(pi); 100370af00a1SHartmut Brandt return (0); 1004f06ca4afSHartmut Brandt } 100570af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 100670af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1007f06ca4afSHartmut Brandt 1008f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 100970af00a1SHartmut Brandt slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 101070af00a1SHartmut Brandt if (slen == -1) 101170af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 101270af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 101370af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 101470af00a1SHartmut Brandt sndlen, (size_t)slen); 101570af00a1SHartmut Brandt } 101670af00a1SHartmut Brandt snmp_pdu_free(&pdu); 101770af00a1SHartmut Brandt free(sndbuf); 101870af00a1SHartmut Brandt snmp_input_consume(pi); 101970af00a1SHartmut Brandt 102070af00a1SHartmut Brandt return (0); 102170af00a1SHartmut Brandt } 102270af00a1SHartmut Brandt 102370af00a1SHartmut Brandt /* 102470af00a1SHartmut Brandt * Send a PDU to a given port 102570af00a1SHartmut Brandt */ 102670af00a1SHartmut Brandt void 102770af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 102870af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 102970af00a1SHartmut Brandt { 103070af00a1SHartmut Brandt struct transport *trans = targ; 103170af00a1SHartmut Brandt struct tport *tp; 103270af00a1SHartmut Brandt u_char *sndbuf; 103370af00a1SHartmut Brandt size_t sndlen; 103470af00a1SHartmut Brandt ssize_t len; 103570af00a1SHartmut Brandt 103670af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 103770af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 103870af00a1SHartmut Brandt break; 103970af00a1SHartmut Brandt if (tp == 0) 104070af00a1SHartmut Brandt return; 104170af00a1SHartmut Brandt 104270af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 104370af00a1SHartmut Brandt return; 104470af00a1SHartmut Brandt 104570af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 104670af00a1SHartmut Brandt 104770af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 104870af00a1SHartmut Brandt 104970af00a1SHartmut Brandt if (len == -1) 1050f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1051f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1052f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1053f06ca4afSHartmut Brandt sndlen, (size_t)len); 105470af00a1SHartmut Brandt 1055f06ca4afSHartmut Brandt free(sndbuf); 1056f06ca4afSHartmut Brandt } 1057f06ca4afSHartmut Brandt 1058f06ca4afSHartmut Brandt 1059f06ca4afSHartmut Brandt /* 106070af00a1SHartmut Brandt * Close an input source 1061f06ca4afSHartmut Brandt */ 1062f06ca4afSHartmut Brandt void 106370af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1064f06ca4afSHartmut Brandt { 106570af00a1SHartmut Brandt if (pi->id != NULL) 106670af00a1SHartmut Brandt fd_deselect(pi->id); 106770af00a1SHartmut Brandt if (pi->fd >= 0) 106870af00a1SHartmut Brandt (void)close(pi->fd); 106970af00a1SHartmut Brandt if (pi->buf != NULL) 107070af00a1SHartmut Brandt free(pi->buf); 1071f06ca4afSHartmut Brandt } 1072f06ca4afSHartmut Brandt 1073f06ca4afSHartmut Brandt /* 1074f06ca4afSHartmut Brandt * Dump internal state. 1075f06ca4afSHartmut Brandt */ 107670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 107770af00a1SHartmut Brandt static void 107870af00a1SHartmut Brandt info_func(void) 107970af00a1SHartmut Brandt #else 1080f06ca4afSHartmut Brandt static void 1081f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 108270af00a1SHartmut Brandt #endif 1083f06ca4afSHartmut Brandt { 1084f06ca4afSHartmut Brandt struct lmodule *m; 1085f06ca4afSHartmut Brandt u_int i; 1086f06ca4afSHartmut Brandt char buf[10000]; 1087f06ca4afSHartmut Brandt 1088f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1089f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1090f06ca4afSHartmut Brandt switch (tree[i].type) { 1091f06ca4afSHartmut Brandt 1092f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1093f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1094f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1095f06ca4afSHartmut Brandt break; 1096f06ca4afSHartmut Brandt 1097f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1098f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1099f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1100f06ca4afSHartmut Brandt break; 1101f06ca4afSHartmut Brandt } 1102f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1103f06ca4afSHartmut Brandt } 1104f06ca4afSHartmut Brandt 1105f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1106f06ca4afSHartmut Brandt if (m->config->dump) 1107f06ca4afSHartmut Brandt (*m->config->dump)(); 1108f06ca4afSHartmut Brandt } 1109f06ca4afSHartmut Brandt 1110f06ca4afSHartmut Brandt /* 1111f06ca4afSHartmut Brandt * Re-read configuration 1112f06ca4afSHartmut Brandt */ 111370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 111470af00a1SHartmut Brandt static void 111570af00a1SHartmut Brandt config_func(void) 111670af00a1SHartmut Brandt #else 1117f06ca4afSHartmut Brandt static void 1118f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1119f06ca4afSHartmut Brandt const void *tag __unused) 112070af00a1SHartmut Brandt #endif 1121f06ca4afSHartmut Brandt { 1122f06ca4afSHartmut Brandt struct lmodule *m; 1123f06ca4afSHartmut Brandt 1124f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1125f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1126f06ca4afSHartmut Brandt return; 1127f06ca4afSHartmut Brandt } 1128f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1129f06ca4afSHartmut Brandt if (m->config->config) 1130f06ca4afSHartmut Brandt (*m->config->config)(); 1131f06ca4afSHartmut Brandt } 1132f06ca4afSHartmut Brandt 1133f06ca4afSHartmut Brandt /* 1134f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1135f06ca4afSHartmut Brandt */ 1136f06ca4afSHartmut Brandt static void 1137f06ca4afSHartmut Brandt onusr1(int s __unused) 1138f06ca4afSHartmut Brandt { 113970af00a1SHartmut Brandt 1140f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1141f06ca4afSHartmut Brandt } 1142f06ca4afSHartmut Brandt static void 1143f06ca4afSHartmut Brandt onhup(int s __unused) 1144f06ca4afSHartmut Brandt { 114570af00a1SHartmut Brandt 1146f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1147f06ca4afSHartmut Brandt } 1148f06ca4afSHartmut Brandt 1149f06ca4afSHartmut Brandt static void 1150f06ca4afSHartmut Brandt onterm(int s __unused) 1151f06ca4afSHartmut Brandt { 1152f06ca4afSHartmut Brandt 115370af00a1SHartmut Brandt /* allow clean-up */ 1154f06ca4afSHartmut Brandt exit(0); 1155f06ca4afSHartmut Brandt } 1156f06ca4afSHartmut Brandt 1157f06ca4afSHartmut Brandt static void 1158f06ca4afSHartmut Brandt init_sigs(void) 1159f06ca4afSHartmut Brandt { 1160f06ca4afSHartmut Brandt struct sigaction sa; 1161f06ca4afSHartmut Brandt 1162f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1163f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1164f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1165f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1166f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1167f06ca4afSHartmut Brandt exit(1); 1168f06ca4afSHartmut Brandt } 1169f06ca4afSHartmut Brandt 1170f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1171f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1172f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1173f06ca4afSHartmut Brandt exit(1); 1174f06ca4afSHartmut Brandt } 1175f06ca4afSHartmut Brandt 1176f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1177f06ca4afSHartmut Brandt sa.sa_flags = 0; 1178f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1179f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1180f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1181f06ca4afSHartmut Brandt exit(1); 1182f06ca4afSHartmut Brandt } 1183f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1184f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1185f06ca4afSHartmut Brandt exit(1); 1186f06ca4afSHartmut Brandt } 1187f06ca4afSHartmut Brandt } 1188f06ca4afSHartmut Brandt 1189f06ca4afSHartmut Brandt static void 1190f06ca4afSHartmut Brandt block_sigs(void) 1191f06ca4afSHartmut Brandt { 1192f06ca4afSHartmut Brandt sigset_t set; 1193f06ca4afSHartmut Brandt 1194f06ca4afSHartmut Brandt sigfillset(&set); 1195f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1196f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1197f06ca4afSHartmut Brandt exit(1); 1198f06ca4afSHartmut Brandt } 1199f06ca4afSHartmut Brandt } 1200f06ca4afSHartmut Brandt static void 1201f06ca4afSHartmut Brandt unblock_sigs(void) 1202f06ca4afSHartmut Brandt { 1203f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1204f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1205f06ca4afSHartmut Brandt exit(1); 1206f06ca4afSHartmut Brandt } 1207f06ca4afSHartmut Brandt } 1208f06ca4afSHartmut Brandt 1209f06ca4afSHartmut Brandt /* 1210f06ca4afSHartmut Brandt * Shut down 1211f06ca4afSHartmut Brandt */ 1212f06ca4afSHartmut Brandt static void 1213f06ca4afSHartmut Brandt term(void) 1214f06ca4afSHartmut Brandt { 1215f06ca4afSHartmut Brandt (void)unlink(pid_file); 1216f06ca4afSHartmut Brandt } 1217f06ca4afSHartmut Brandt 121870af00a1SHartmut Brandt static void 121970af00a1SHartmut Brandt trans_stop(void) 122070af00a1SHartmut Brandt { 122170af00a1SHartmut Brandt struct transport *t; 122270af00a1SHartmut Brandt 122370af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 122470af00a1SHartmut Brandt (void)t->vtab->stop(1); 122570af00a1SHartmut Brandt } 122670af00a1SHartmut Brandt 1227f06ca4afSHartmut Brandt /* 1228f06ca4afSHartmut Brandt * Define a macro from the command line 1229f06ca4afSHartmut Brandt */ 1230f06ca4afSHartmut Brandt static void 1231f06ca4afSHartmut Brandt do_macro(char *arg) 1232f06ca4afSHartmut Brandt { 1233f06ca4afSHartmut Brandt char *eq; 1234f06ca4afSHartmut Brandt int err; 1235f06ca4afSHartmut Brandt 1236f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1237f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1238f06ca4afSHartmut Brandt else { 1239f06ca4afSHartmut Brandt *eq++ = '\0'; 1240f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1241f06ca4afSHartmut Brandt } 1242f06ca4afSHartmut Brandt if (err == -1) { 1243f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1244f06ca4afSHartmut Brandt exit(1); 1245f06ca4afSHartmut Brandt } 1246f06ca4afSHartmut Brandt } 1247f06ca4afSHartmut Brandt 1248f06ca4afSHartmut Brandt /* 1249f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1250f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1251f06ca4afSHartmut Brandt */ 1252f06ca4afSHartmut Brandt static int 1253f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1254f06ca4afSHartmut Brandt { 1255f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1256f06ca4afSHartmut Brandt u_int i; 1257f06ca4afSHartmut Brandt char *ptr; 1258f06ca4afSHartmut Brandt 1259f06ca4afSHartmut Brandt *optp = NULL; 1260f06ca4afSHartmut Brandt 1261f06ca4afSHartmut Brandt /* skip leading junk */ 1262f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1263f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1264f06ca4afSHartmut Brandt break; 1265f06ca4afSHartmut Brandt if (*ptr == '\0') { 1266f06ca4afSHartmut Brandt *arg = ptr; 1267f06ca4afSHartmut Brandt return (-1); 1268f06ca4afSHartmut Brandt } 1269f06ca4afSHartmut Brandt *optp = ptr; 1270f06ca4afSHartmut Brandt 1271f06ca4afSHartmut Brandt /* find the end of the option */ 1272f06ca4afSHartmut Brandt while (*++ptr != '\0') 1273f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1274f06ca4afSHartmut Brandt break; 1275f06ca4afSHartmut Brandt 1276f06ca4afSHartmut Brandt if (*ptr != '\0') { 1277f06ca4afSHartmut Brandt if (*ptr == '=') { 1278f06ca4afSHartmut Brandt *ptr++ = '\0'; 1279f06ca4afSHartmut Brandt *valp = ptr; 1280f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1281f06ca4afSHartmut Brandt ptr++; 1282f06ca4afSHartmut Brandt if (*ptr != '\0') 1283f06ca4afSHartmut Brandt *ptr++ = '\0'; 1284f06ca4afSHartmut Brandt } else 1285f06ca4afSHartmut Brandt *ptr++ = '\0'; 1286f06ca4afSHartmut Brandt } 1287f06ca4afSHartmut Brandt 1288f06ca4afSHartmut Brandt *arg = ptr; 1289f06ca4afSHartmut Brandt 1290f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 129170af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1292f06ca4afSHartmut Brandt return (i); 1293f06ca4afSHartmut Brandt return (-1); 1294f06ca4afSHartmut Brandt } 1295f06ca4afSHartmut Brandt 1296f06ca4afSHartmut Brandt int 1297f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1298f06ca4afSHartmut Brandt { 1299f06ca4afSHartmut Brandt int opt; 1300f06ca4afSHartmut Brandt FILE *fp; 1301f06ca4afSHartmut Brandt int background = 1; 130270af00a1SHartmut Brandt struct tport *p; 1303f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1304f06ca4afSHartmut Brandt struct lmodule *m; 1305f06ca4afSHartmut Brandt char *value, *option; 130670af00a1SHartmut Brandt struct transport *t; 1307f06ca4afSHartmut Brandt 1308f06ca4afSHartmut Brandt #define DBG_DUMP 0 1309f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1310f06ca4afSHartmut Brandt #define DBG_TRACE 2 1311f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1312f06ca4afSHartmut Brandt "dump", 1313f06ca4afSHartmut Brandt "events", 1314f06ca4afSHartmut Brandt "trace", 1315f06ca4afSHartmut Brandt NULL 1316f06ca4afSHartmut Brandt }; 1317f06ca4afSHartmut Brandt 1318f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1319f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1320f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1321f06ca4afSHartmut Brandt asn_error = asn_error_func; 1322f06ca4afSHartmut Brandt 1323f06ca4afSHartmut Brandt while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF) 1324f06ca4afSHartmut Brandt switch (opt) { 1325f06ca4afSHartmut Brandt 1326f06ca4afSHartmut Brandt case 'c': 1327f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1328f06ca4afSHartmut Brandt break; 1329f06ca4afSHartmut Brandt 1330f06ca4afSHartmut Brandt case 'd': 1331f06ca4afSHartmut Brandt background = 0; 1332f06ca4afSHartmut Brandt break; 1333f06ca4afSHartmut Brandt 1334f06ca4afSHartmut Brandt case 'D': 1335f06ca4afSHartmut Brandt while (*optarg) { 1336f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1337f06ca4afSHartmut Brandt &value, &option)) { 1338f06ca4afSHartmut Brandt 1339f06ca4afSHartmut Brandt case DBG_DUMP: 1340f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1341f06ca4afSHartmut Brandt break; 1342f06ca4afSHartmut Brandt 1343f06ca4afSHartmut Brandt case DBG_EVENTS: 1344f06ca4afSHartmut Brandt debug.evdebug++; 1345f06ca4afSHartmut Brandt break; 1346f06ca4afSHartmut Brandt 1347f06ca4afSHartmut Brandt case DBG_TRACE: 1348f06ca4afSHartmut Brandt if (value == NULL) 1349f06ca4afSHartmut Brandt syslog(LOG_ERR, 1350f06ca4afSHartmut Brandt "no value for 'trace'"); 1351f06ca4afSHartmut Brandt snmp_trace = strtoul(value, NULL, 0); 1352f06ca4afSHartmut Brandt break; 1353f06ca4afSHartmut Brandt 1354f06ca4afSHartmut Brandt case -1: 1355f06ca4afSHartmut Brandt if (suboptarg) 1356f06ca4afSHartmut Brandt syslog(LOG_ERR, 1357f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1358f06ca4afSHartmut Brandt option); 1359f06ca4afSHartmut Brandt else 1360f06ca4afSHartmut Brandt syslog(LOG_ERR, 1361f06ca4afSHartmut Brandt "missing debug flag"); 1362f06ca4afSHartmut Brandt break; 1363f06ca4afSHartmut Brandt } 1364f06ca4afSHartmut Brandt } 1365f06ca4afSHartmut Brandt break; 1366f06ca4afSHartmut Brandt 1367f06ca4afSHartmut Brandt case 'h': 1368f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1369f06ca4afSHartmut Brandt exit(0); 1370f06ca4afSHartmut Brandt 1371f06ca4afSHartmut Brandt case 'I': 1372f06ca4afSHartmut Brandt syspath = optarg; 1373f06ca4afSHartmut Brandt break; 1374f06ca4afSHartmut Brandt 1375f06ca4afSHartmut Brandt case 'l': 1376f06ca4afSHartmut Brandt prefix = optarg; 1377f06ca4afSHartmut Brandt break; 1378f06ca4afSHartmut Brandt 1379f06ca4afSHartmut Brandt case 'm': 1380f06ca4afSHartmut Brandt do_macro(optarg); 1381f06ca4afSHartmut Brandt break; 1382f06ca4afSHartmut Brandt 1383f06ca4afSHartmut Brandt case 'p': 1384f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1385f06ca4afSHartmut Brandt break; 1386f06ca4afSHartmut Brandt } 1387f06ca4afSHartmut Brandt 1388f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1389f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1390f06ca4afSHartmut Brandt 1391f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1392f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1393f06ca4afSHartmut Brandt exit(1); 1394f06ca4afSHartmut Brandt } 1395f06ca4afSHartmut Brandt 1396f06ca4afSHartmut Brandt argc -= optind; 1397f06ca4afSHartmut Brandt argv += optind; 1398f06ca4afSHartmut Brandt 1399f06ca4afSHartmut Brandt progargs = argv; 1400f06ca4afSHartmut Brandt nprogargs = argc; 1401f06ca4afSHartmut Brandt 1402f06ca4afSHartmut Brandt srandomdev(); 1403f06ca4afSHartmut Brandt 1404f06ca4afSHartmut Brandt snmp_serial_no = random(); 1405f06ca4afSHartmut Brandt 1406f06ca4afSHartmut Brandt /* 1407f06ca4afSHartmut Brandt * Initialize the tree. 1408f06ca4afSHartmut Brandt */ 1409f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1410f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1411f06ca4afSHartmut Brandt exit(1); 1412f06ca4afSHartmut Brandt } 1413f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1414f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1415f06ca4afSHartmut Brandt 1416f06ca4afSHartmut Brandt /* 1417f06ca4afSHartmut Brandt * Get standard communities 1418f06ca4afSHartmut Brandt */ 1419f06ca4afSHartmut Brandt (void)comm_define(1, "SNMP read", NULL, "public"); 1420f06ca4afSHartmut Brandt (void)comm_define(2, "SNMP write", NULL, "public"); 1421f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1422f06ca4afSHartmut Brandt 1423f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1424f06ca4afSHartmut Brandt 1425f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1426f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1427f06ca4afSHartmut Brandt 1428f06ca4afSHartmut Brandt init_actvals(); 142970af00a1SHartmut Brandt 143070af00a1SHartmut Brandt start_tick = get_ticks(); 143170af00a1SHartmut Brandt this_tick = get_ticks(); 143270af00a1SHartmut Brandt 143370af00a1SHartmut Brandt /* start transports */ 143470af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 143570af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 143670af00a1SHartmut Brandt exit(1); 143770af00a1SHartmut Brandt } 143870af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 143970af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 144070af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 144170af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 144270af00a1SHartmut Brandt 1443f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1444f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 1445f06ca4afSHartmut Brandt exit(1); 1446f06ca4afSHartmut Brandt } 1447f06ca4afSHartmut Brandt 144870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 144970af00a1SHartmut Brandt if (debug.evdebug > 0) 145070af00a1SHartmut Brandt rpoll_trace = 1; 145170af00a1SHartmut Brandt #else 1452f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1453f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1454f06ca4afSHartmut Brandt exit(1); 1455f06ca4afSHartmut Brandt } 1456f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1457f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 145870af00a1SHartmut Brandt #endif 1459f06ca4afSHartmut Brandt 146070af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 146170af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 146270af00a1SHartmut Brandt t->vtab->init_port(p); 1463f06ca4afSHartmut Brandt 1464f06ca4afSHartmut Brandt init_sigs(); 1465f06ca4afSHartmut Brandt 1466f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1467f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1468f06ca4afSHartmut Brandt 1469f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1470f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1471f06ca4afSHartmut Brandt fclose(fp); 147270af00a1SHartmut Brandt if (atexit(term) == -1) { 147370af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 147470af00a1SHartmut Brandt (void)remove(pid_file); 147570af00a1SHartmut Brandt exit(0); 1476f06ca4afSHartmut Brandt } 147770af00a1SHartmut Brandt } 1478f06ca4afSHartmut Brandt 1479f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1480f06ca4afSHartmut Brandt NULL) == 0) { 1481f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1482f06ca4afSHartmut Brandt exit(1); 1483f06ca4afSHartmut Brandt } 1484f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1485f06ca4afSHartmut Brandt NULL) == 0) { 1486f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1487f06ca4afSHartmut Brandt exit(1); 1488f06ca4afSHartmut Brandt } 1489f06ca4afSHartmut Brandt 1490f06ca4afSHartmut Brandt snmp_send_trap(&oid_coldStart, NULL); 1491f06ca4afSHartmut Brandt 1492f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1493f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1494f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1495f06ca4afSHartmut Brandt lm_start(m); 1496f06ca4afSHartmut Brandt } 1497f06ca4afSHartmut Brandt 1498f06ca4afSHartmut Brandt for (;;) { 149970af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1500f06ca4afSHartmut Brandt evEvent event; 150170af00a1SHartmut Brandt #endif 1502f06ca4afSHartmut Brandt struct lmodule *mod; 1503f06ca4afSHartmut Brandt 1504f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1505f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1506f06ca4afSHartmut Brandt (*mod->config->idle)(); 1507f06ca4afSHartmut Brandt 150870af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1509f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1510f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1511f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1512f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1513f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1514f06ca4afSHartmut Brandt exit(1); 1515f06ca4afSHartmut Brandt } 151670af00a1SHartmut Brandt #else 151770af00a1SHartmut Brandt poll_dispatch(1); 151870af00a1SHartmut Brandt #endif 1519f06ca4afSHartmut Brandt 1520f06ca4afSHartmut Brandt if (work != 0) { 1521f06ca4afSHartmut Brandt block_sigs(); 1522f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 152370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 152470af00a1SHartmut Brandt info_func(); 152570af00a1SHartmut Brandt #else 1526f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1527f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1528f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1529f06ca4afSHartmut Brandt exit(1); 1530f06ca4afSHartmut Brandt } 153170af00a1SHartmut Brandt #endif 1532f06ca4afSHartmut Brandt } 1533f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 153470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 153570af00a1SHartmut Brandt config_func(); 153670af00a1SHartmut Brandt #else 1537f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1538f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1539f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1540f06ca4afSHartmut Brandt exit(1); 1541f06ca4afSHartmut Brandt } 154270af00a1SHartmut Brandt #endif 1543f06ca4afSHartmut Brandt } 1544f06ca4afSHartmut Brandt work = 0; 1545f06ca4afSHartmut Brandt unblock_sigs(); 154670af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1547f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1548f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1549f06ca4afSHartmut Brandt exit(1); 1550f06ca4afSHartmut Brandt } 155170af00a1SHartmut Brandt #endif 1552f06ca4afSHartmut Brandt } 1553f06ca4afSHartmut Brandt } 1554f06ca4afSHartmut Brandt 1555f06ca4afSHartmut Brandt return (0); 1556f06ca4afSHartmut Brandt } 1557f06ca4afSHartmut Brandt 1558f06ca4afSHartmut Brandt 1559f06ca4afSHartmut Brandt u_int32_t 1560f06ca4afSHartmut Brandt get_ticks() 1561f06ca4afSHartmut Brandt { 1562f06ca4afSHartmut Brandt struct timeval tv; 1563f06ca4afSHartmut Brandt u_int32_t ret; 1564f06ca4afSHartmut Brandt 1565f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1566f06ca4afSHartmut Brandt abort(); 1567f06ca4afSHartmut Brandt ret = tv.tv_sec * 100 + tv.tv_usec / 10000; 1568f06ca4afSHartmut Brandt return (ret); 1569f06ca4afSHartmut Brandt } 1570f06ca4afSHartmut Brandt /* 1571f06ca4afSHartmut Brandt * Timer support 1572f06ca4afSHartmut Brandt */ 157370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 157470af00a1SHartmut Brandt static void 157570af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 157670af00a1SHartmut Brandt #else 1577f06ca4afSHartmut Brandt static void 1578f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1579f06ca4afSHartmut Brandt struct timespec inter __unused) 158070af00a1SHartmut Brandt #endif 1581f06ca4afSHartmut Brandt { 1582f06ca4afSHartmut Brandt struct timer *tp = uap; 1583f06ca4afSHartmut Brandt 1584f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1585f06ca4afSHartmut Brandt tp->func(tp->udata); 1586f06ca4afSHartmut Brandt free(tp); 1587f06ca4afSHartmut Brandt } 1588f06ca4afSHartmut Brandt 1589f06ca4afSHartmut Brandt /* 1590f06ca4afSHartmut Brandt * Start a timer 1591f06ca4afSHartmut Brandt */ 1592f06ca4afSHartmut Brandt void * 1593f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1594f06ca4afSHartmut Brandt { 1595f06ca4afSHartmut Brandt struct timer *tp; 159670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 159770af00a1SHartmut Brandt struct timeval due; 159870af00a1SHartmut Brandt #else 1599f06ca4afSHartmut Brandt struct timespec due; 160070af00a1SHartmut Brandt #endif 1601f06ca4afSHartmut Brandt 1602f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1603f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1604f06ca4afSHartmut Brandt exit(1); 1605f06ca4afSHartmut Brandt } 160670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 160770af00a1SHartmut Brandt (void)gettimeofday(&due, NULL); 160870af00a1SHartmut Brandt due.tv_sec += ticks / 100; 160970af00a1SHartmut Brandt due.tv_usec += (ticks % 100) * 10000; 161070af00a1SHartmut Brandt if (due.tv_usec >= 1000000) { 161170af00a1SHartmut Brandt due.tv_sec++; 161270af00a1SHartmut Brandt due.tv_usec -= 1000000; 161370af00a1SHartmut Brandt } 161470af00a1SHartmut Brandt #else 1615f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1616f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 161770af00a1SHartmut Brandt #endif 1618f06ca4afSHartmut Brandt 1619f06ca4afSHartmut Brandt tp->udata = udata; 1620f06ca4afSHartmut Brandt tp->owner = mod; 1621f06ca4afSHartmut Brandt tp->func = func; 1622f06ca4afSHartmut Brandt 1623f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1624f06ca4afSHartmut Brandt 162570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 162670af00a1SHartmut Brandt if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000, 162770af00a1SHartmut Brandt 0, tfunc, tp)) < 0) { 162870af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 162970af00a1SHartmut Brandt exit(1); 163070af00a1SHartmut Brandt } 163170af00a1SHartmut Brandt #else 1632f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1633f06ca4afSHartmut Brandt == -1) { 1634f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1635f06ca4afSHartmut Brandt exit(1); 1636f06ca4afSHartmut Brandt } 163770af00a1SHartmut Brandt #endif 1638f06ca4afSHartmut Brandt return (tp); 1639f06ca4afSHartmut Brandt } 1640f06ca4afSHartmut Brandt 1641f06ca4afSHartmut Brandt void 1642f06ca4afSHartmut Brandt timer_stop(void *p) 1643f06ca4afSHartmut Brandt { 1644f06ca4afSHartmut Brandt struct timer *tp = p; 1645f06ca4afSHartmut Brandt 1646f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 164770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 164870af00a1SHartmut Brandt poll_stop_timer(tp->id); 164970af00a1SHartmut Brandt #else 1650f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 1651f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 1652f06ca4afSHartmut Brandt exit(1); 1653f06ca4afSHartmut Brandt } 165470af00a1SHartmut Brandt #endif 1655f06ca4afSHartmut Brandt free(p); 1656f06ca4afSHartmut Brandt } 1657f06ca4afSHartmut Brandt 1658f06ca4afSHartmut Brandt static void 1659f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 1660f06ca4afSHartmut Brandt { 1661f06ca4afSHartmut Brandt struct timer *t, *t1; 1662f06ca4afSHartmut Brandt 1663f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 1664f06ca4afSHartmut Brandt while (t != NULL) { 1665f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1666f06ca4afSHartmut Brandt if (t->owner == mod) 1667f06ca4afSHartmut Brandt timer_stop(t); 1668f06ca4afSHartmut Brandt t = t1; 1669f06ca4afSHartmut Brandt } 1670f06ca4afSHartmut Brandt } 1671f06ca4afSHartmut Brandt 1672f06ca4afSHartmut Brandt static void 1673f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1674f06ca4afSHartmut Brandt { 1675f06ca4afSHartmut Brandt va_list ap; 1676f06ca4afSHartmut Brandt static char *pend = NULL; 1677f06ca4afSHartmut Brandt char *ret, *new; 1678f06ca4afSHartmut Brandt 1679f06ca4afSHartmut Brandt va_start(ap, fmt); 1680f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 1681f06ca4afSHartmut Brandt va_end(ap); 1682f06ca4afSHartmut Brandt 1683f06ca4afSHartmut Brandt if (ret == NULL) 1684f06ca4afSHartmut Brandt return; 1685f06ca4afSHartmut Brandt if (pend != NULL) { 1686f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1687f06ca4afSHartmut Brandt == NULL) { 1688f06ca4afSHartmut Brandt free(ret); 1689f06ca4afSHartmut Brandt return; 1690f06ca4afSHartmut Brandt } 1691f06ca4afSHartmut Brandt pend = new; 1692f06ca4afSHartmut Brandt strcat(pend, ret); 1693f06ca4afSHartmut Brandt free(ret); 1694f06ca4afSHartmut Brandt } else 1695f06ca4afSHartmut Brandt pend = ret; 1696f06ca4afSHartmut Brandt 1697f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 1698f06ca4afSHartmut Brandt *ret = '\0'; 1699f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 1700f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 1701f06ca4afSHartmut Brandt free(pend); 1702f06ca4afSHartmut Brandt pend = NULL; 1703f06ca4afSHartmut Brandt break; 1704f06ca4afSHartmut Brandt } 1705f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 1706f06ca4afSHartmut Brandt } 1707f06ca4afSHartmut Brandt } 1708f06ca4afSHartmut Brandt 1709f06ca4afSHartmut Brandt static void 1710f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 1711f06ca4afSHartmut Brandt { 1712f06ca4afSHartmut Brandt char errbuf[1000]; 1713f06ca4afSHartmut Brandt va_list ap; 1714f06ca4afSHartmut Brandt 171570af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 171670af00a1SHartmut Brandt return; 171770af00a1SHartmut Brandt 1718f06ca4afSHartmut Brandt va_start(ap, err); 1719f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 172070af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 172170af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1722f06ca4afSHartmut Brandt va_end(ap); 1723f06ca4afSHartmut Brandt 1724f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1725f06ca4afSHartmut Brandt } 1726f06ca4afSHartmut Brandt 1727f06ca4afSHartmut Brandt static void 1728f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 1729f06ca4afSHartmut Brandt { 1730f06ca4afSHartmut Brandt char errbuf[1000]; 1731f06ca4afSHartmut Brandt va_list ap; 1732f06ca4afSHartmut Brandt 1733f06ca4afSHartmut Brandt va_start(ap, err); 1734f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1735f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1736f06ca4afSHartmut Brandt err, ap); 1737f06ca4afSHartmut Brandt va_end(ap); 1738f06ca4afSHartmut Brandt 1739f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 1740f06ca4afSHartmut Brandt } 1741f06ca4afSHartmut Brandt 1742f06ca4afSHartmut Brandt static void 1743f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 1744f06ca4afSHartmut Brandt { 1745f06ca4afSHartmut Brandt char errbuf[1000]; 1746f06ca4afSHartmut Brandt va_list ap; 1747f06ca4afSHartmut Brandt u_int i; 1748f06ca4afSHartmut Brandt 174970af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 175070af00a1SHartmut Brandt return; 175170af00a1SHartmut Brandt 1752f06ca4afSHartmut Brandt va_start(ap, err); 1753f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 175470af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 175570af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1756f06ca4afSHartmut Brandt va_end(ap); 1757f06ca4afSHartmut Brandt 1758f06ca4afSHartmut Brandt if (b != NULL) { 175970af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 176070af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 1761f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 1762f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 176370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 176470af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 1765f06ca4afSHartmut Brandt } 1766f06ca4afSHartmut Brandt 1767f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1768f06ca4afSHartmut Brandt } 1769f06ca4afSHartmut Brandt 1770f06ca4afSHartmut Brandt /* 1771f06ca4afSHartmut Brandt * Create a new community 1772f06ca4afSHartmut Brandt */ 1773f06ca4afSHartmut Brandt u_int 1774f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 1775f06ca4afSHartmut Brandt const char *str) 1776f06ca4afSHartmut Brandt { 1777f06ca4afSHartmut Brandt struct community *c, *p; 1778f06ca4afSHartmut Brandt u_int ncomm; 1779f06ca4afSHartmut Brandt 1780f06ca4afSHartmut Brandt /* generate an identifier */ 1781f06ca4afSHartmut Brandt do { 1782f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 1783f06ca4afSHartmut Brandt next_community_index = 1; 1784f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 1785f06ca4afSHartmut Brandt if (c->value == ncomm) 1786f06ca4afSHartmut Brandt break; 1787f06ca4afSHartmut Brandt } while (c != NULL); 1788f06ca4afSHartmut Brandt 1789f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 1790f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 1791f06ca4afSHartmut Brandt return (0); 1792f06ca4afSHartmut Brandt } 1793f06ca4afSHartmut Brandt c->owner = owner; 1794f06ca4afSHartmut Brandt c->value = ncomm; 1795f06ca4afSHartmut Brandt c->descr = descr; 1796f06ca4afSHartmut Brandt c->string = NULL; 1797f06ca4afSHartmut Brandt c->private = priv; 1798f06ca4afSHartmut Brandt 1799f06ca4afSHartmut Brandt if (str != NULL) { 1800f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 1801f06ca4afSHartmut Brandt free(c); 1802f06ca4afSHartmut Brandt return (0); 1803f06ca4afSHartmut Brandt } 1804f06ca4afSHartmut Brandt strcpy(c->string, str); 1805f06ca4afSHartmut Brandt } 1806f06ca4afSHartmut Brandt 1807f06ca4afSHartmut Brandt /* make index */ 1808f06ca4afSHartmut Brandt if (c->owner == NULL) { 1809f06ca4afSHartmut Brandt c->index.len = 1; 1810f06ca4afSHartmut Brandt c->index.subs[0] = 0; 1811f06ca4afSHartmut Brandt } else { 1812f06ca4afSHartmut Brandt c->index = c->owner->index; 1813f06ca4afSHartmut Brandt } 1814f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 1815f06ca4afSHartmut Brandt 1816f06ca4afSHartmut Brandt /* 1817f06ca4afSHartmut Brandt * Insert ordered 1818f06ca4afSHartmut Brandt */ 1819f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 1820f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 1821f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 1822f06ca4afSHartmut Brandt break; 1823f06ca4afSHartmut Brandt } 1824f06ca4afSHartmut Brandt } 1825f06ca4afSHartmut Brandt if (p == NULL) 1826f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 1827f06ca4afSHartmut Brandt return (c->value); 1828f06ca4afSHartmut Brandt } 1829f06ca4afSHartmut Brandt 1830f06ca4afSHartmut Brandt const char * 1831f06ca4afSHartmut Brandt comm_string(u_int ncomm) 1832f06ca4afSHartmut Brandt { 1833f06ca4afSHartmut Brandt struct community *p; 1834f06ca4afSHartmut Brandt 1835f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 1836f06ca4afSHartmut Brandt if (p->value == ncomm) 1837f06ca4afSHartmut Brandt return (p->string); 1838f06ca4afSHartmut Brandt return (NULL); 1839f06ca4afSHartmut Brandt } 1840f06ca4afSHartmut Brandt 1841f06ca4afSHartmut Brandt /* 1842f06ca4afSHartmut Brandt * Delete all communities allocated by a module 1843f06ca4afSHartmut Brandt */ 1844f06ca4afSHartmut Brandt static void 1845f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 1846f06ca4afSHartmut Brandt { 1847f06ca4afSHartmut Brandt struct community *p, *p1; 1848f06ca4afSHartmut Brandt 1849f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 1850f06ca4afSHartmut Brandt while (p != NULL) { 1851f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 1852f06ca4afSHartmut Brandt if (p->owner == mod) { 1853f06ca4afSHartmut Brandt free(p->string); 1854f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 1855f06ca4afSHartmut Brandt free(p); 1856f06ca4afSHartmut Brandt } 1857f06ca4afSHartmut Brandt p = p1; 1858f06ca4afSHartmut Brandt } 1859f06ca4afSHartmut Brandt } 1860f06ca4afSHartmut Brandt 1861f06ca4afSHartmut Brandt /* 1862f06ca4afSHartmut Brandt * Request ID handling. 1863f06ca4afSHartmut Brandt * 1864f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 1865f06ca4afSHartmut Brandt */ 1866f06ca4afSHartmut Brandt u_int 1867f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 1868f06ca4afSHartmut Brandt { 1869f06ca4afSHartmut Brandt u_int type; 1870f06ca4afSHartmut Brandt struct idrange *r, *r1; 1871f06ca4afSHartmut Brandt 1872f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 1873f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 1874f06ca4afSHartmut Brandt return (0); 1875f06ca4afSHartmut Brandt } 1876f06ca4afSHartmut Brandt /* allocate a type id */ 1877f06ca4afSHartmut Brandt do { 1878f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 1879f06ca4afSHartmut Brandt next_idrange = 1; 1880f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1881f06ca4afSHartmut Brandt if (r->type == type) 1882f06ca4afSHartmut Brandt break; 1883f06ca4afSHartmut Brandt } while(r != NULL); 1884f06ca4afSHartmut Brandt 1885f06ca4afSHartmut Brandt /* find a range */ 1886f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 1887f06ca4afSHartmut Brandt r = NULL; 1888f06ca4afSHartmut Brandt else { 1889f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 1890f06ca4afSHartmut Brandt if (r->base < size) { 1891f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 1892f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 1893f06ca4afSHartmut Brandt break; 1894f06ca4afSHartmut Brandt r = r1; 1895f06ca4afSHartmut Brandt } 1896f06ca4afSHartmut Brandt r = r1; 1897f06ca4afSHartmut Brandt } 1898f06ca4afSHartmut Brandt if (r == NULL) { 1899f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 1900f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 1901f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 1902f06ca4afSHartmut Brandt return (0); 1903f06ca4afSHartmut Brandt } 1904f06ca4afSHartmut Brandt } 1905f06ca4afSHartmut Brandt } 1906f06ca4afSHartmut Brandt 1907f06ca4afSHartmut Brandt /* allocate structure */ 1908f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 1909f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 1910f06ca4afSHartmut Brandt return (0); 1911f06ca4afSHartmut Brandt } 1912f06ca4afSHartmut Brandt 1913f06ca4afSHartmut Brandt r1->type = type; 1914f06ca4afSHartmut Brandt r1->size = size; 1915f06ca4afSHartmut Brandt r1->owner = mod; 1916f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 1917f06ca4afSHartmut Brandt r1->base = 0; 1918f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 1919f06ca4afSHartmut Brandt } else if (r == NULL) { 1920f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 1921f06ca4afSHartmut Brandt r1->base = r->base + r->size; 1922f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 1923f06ca4afSHartmut Brandt } else { 1924f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 1925f06ca4afSHartmut Brandt r1->base = r->base + r->size; 1926f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 1927f06ca4afSHartmut Brandt } 1928f06ca4afSHartmut Brandt r1->next = r1->base; 1929f06ca4afSHartmut Brandt 1930f06ca4afSHartmut Brandt return (type); 1931f06ca4afSHartmut Brandt } 1932f06ca4afSHartmut Brandt 1933f06ca4afSHartmut Brandt int32_t 1934f06ca4afSHartmut Brandt reqid_next(u_int type) 1935f06ca4afSHartmut Brandt { 1936f06ca4afSHartmut Brandt struct idrange *r; 1937f06ca4afSHartmut Brandt int32_t id; 1938f06ca4afSHartmut Brandt 1939f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1940f06ca4afSHartmut Brandt if (r->type == type) 1941f06ca4afSHartmut Brandt break; 1942f06ca4afSHartmut Brandt if (r == NULL) { 1943f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 1944f06ca4afSHartmut Brandt abort(); 1945f06ca4afSHartmut Brandt } 1946f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 1947f06ca4afSHartmut Brandt r->next = r->base; 1948f06ca4afSHartmut Brandt return (id); 1949f06ca4afSHartmut Brandt } 1950f06ca4afSHartmut Brandt 1951f06ca4afSHartmut Brandt int32_t 1952f06ca4afSHartmut Brandt reqid_base(u_int type) 1953f06ca4afSHartmut Brandt { 1954f06ca4afSHartmut Brandt struct idrange *r; 1955f06ca4afSHartmut Brandt 1956f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1957f06ca4afSHartmut Brandt if (r->type == type) 1958f06ca4afSHartmut Brandt return (r->base); 1959f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 1960f06ca4afSHartmut Brandt abort(); 1961f06ca4afSHartmut Brandt } 1962f06ca4afSHartmut Brandt 1963f06ca4afSHartmut Brandt u_int 1964f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 1965f06ca4afSHartmut Brandt { 1966f06ca4afSHartmut Brandt struct idrange *r; 1967f06ca4afSHartmut Brandt 1968f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 1969f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 1970f06ca4afSHartmut Brandt return (r->type); 1971f06ca4afSHartmut Brandt return (0); 1972f06ca4afSHartmut Brandt } 1973f06ca4afSHartmut Brandt 1974f06ca4afSHartmut Brandt int 1975f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 1976f06ca4afSHartmut Brandt { 1977f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 1978f06ca4afSHartmut Brandt } 1979f06ca4afSHartmut Brandt 1980f06ca4afSHartmut Brandt /* 1981f06ca4afSHartmut Brandt * Delete all communities allocated by a module 1982f06ca4afSHartmut Brandt */ 1983f06ca4afSHartmut Brandt static void 1984f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 1985f06ca4afSHartmut Brandt { 1986f06ca4afSHartmut Brandt struct idrange *p, *p1; 1987f06ca4afSHartmut Brandt 1988f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 1989f06ca4afSHartmut Brandt while (p != NULL) { 1990f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 1991f06ca4afSHartmut Brandt if (p->owner == mod) { 1992f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 1993f06ca4afSHartmut Brandt free(p); 1994f06ca4afSHartmut Brandt } 1995f06ca4afSHartmut Brandt p = p1; 1996f06ca4afSHartmut Brandt } 1997f06ca4afSHartmut Brandt } 1998f06ca4afSHartmut Brandt 1999f06ca4afSHartmut Brandt /* 2000f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2001f06ca4afSHartmut Brandt */ 2002f06ca4afSHartmut Brandt static int 2003f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2004f06ca4afSHartmut Brandt { 2005f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2006f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2007f06ca4afSHartmut Brandt 2008f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2009f06ca4afSHartmut Brandt } 2010f06ca4afSHartmut Brandt static int 2011f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2012f06ca4afSHartmut Brandt { 2013f06ca4afSHartmut Brandt struct snmp_node *xtree; 2014f06ca4afSHartmut Brandt u_int i; 2015f06ca4afSHartmut Brandt 2016f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2017f06ca4afSHartmut Brandt if (xtree == NULL) { 20188eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2019f06ca4afSHartmut Brandt return (-1); 2020f06ca4afSHartmut Brandt } 2021f06ca4afSHartmut Brandt tree = xtree; 2022f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2023f06ca4afSHartmut Brandt 2024f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 20258eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2026f06ca4afSHartmut Brandt 2027f06ca4afSHartmut Brandt tree_size += nsize; 2028f06ca4afSHartmut Brandt 2029f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2030f06ca4afSHartmut Brandt 2031f06ca4afSHartmut Brandt return (0); 2032f06ca4afSHartmut Brandt } 2033f06ca4afSHartmut Brandt 2034f06ca4afSHartmut Brandt /* 2035f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2036f06ca4afSHartmut Brandt */ 2037f06ca4afSHartmut Brandt static void 2038f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2039f06ca4afSHartmut Brandt { 2040f06ca4afSHartmut Brandt u_int s, d; 2041f06ca4afSHartmut Brandt 2042f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 20438eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2044f06ca4afSHartmut Brandt if (s != d) 2045f06ca4afSHartmut Brandt tree[d] = tree[s]; 2046f06ca4afSHartmut Brandt d++; 2047f06ca4afSHartmut Brandt } 2048f06ca4afSHartmut Brandt tree_size = d; 2049f06ca4afSHartmut Brandt } 2050f06ca4afSHartmut Brandt 2051f06ca4afSHartmut Brandt /* 2052f06ca4afSHartmut Brandt * Loadable modules 2053f06ca4afSHartmut Brandt */ 2054f06ca4afSHartmut Brandt struct lmodule * 2055f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2056f06ca4afSHartmut Brandt { 2057f06ca4afSHartmut Brandt struct lmodule *m; 2058f06ca4afSHartmut Brandt int err; 2059f06ca4afSHartmut Brandt int i; 2060f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2061f06ca4afSHartmut Brandt int ac; 2062f06ca4afSHartmut Brandt u_int u; 2063f06ca4afSHartmut Brandt 2064f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2065f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2066f06ca4afSHartmut Brandt return (NULL); 2067f06ca4afSHartmut Brandt } 2068f06ca4afSHartmut Brandt m->handle = NULL; 2069f06ca4afSHartmut Brandt m->flags = 0; 2070f06ca4afSHartmut Brandt strcpy(m->section, section); 2071f06ca4afSHartmut Brandt 2072f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2073f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2074f06ca4afSHartmut Brandt goto err; 2075f06ca4afSHartmut Brandt } 2076f06ca4afSHartmut Brandt strcpy(m->path, path); 2077f06ca4afSHartmut Brandt 2078f06ca4afSHartmut Brandt /* 2079f06ca4afSHartmut Brandt * Make index 2080f06ca4afSHartmut Brandt */ 2081f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2082f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2083f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2084f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2085f06ca4afSHartmut Brandt 2086f06ca4afSHartmut Brandt /* 2087f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2088f06ca4afSHartmut Brandt */ 2089f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2090f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2091f06ca4afSHartmut Brandt goto err; 2092f06ca4afSHartmut Brandt } 2093f06ca4afSHartmut Brandt 2094f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2095f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2096f06ca4afSHartmut Brandt goto err; 2097f06ca4afSHartmut Brandt } 2098f06ca4afSHartmut Brandt 2099f06ca4afSHartmut Brandt /* 2100f06ca4afSHartmut Brandt * Insert it into the right place 2101f06ca4afSHartmut Brandt */ 2102f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2103f06ca4afSHartmut Brandt 2104f06ca4afSHartmut Brandt /* preserve order */ 2105f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2106f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2107f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2108f06ca4afSHartmut Brandt } 2109f06ca4afSHartmut Brandt 2110f06ca4afSHartmut Brandt /* 2111f06ca4afSHartmut Brandt * make the argument vector. 2112f06ca4afSHartmut Brandt */ 2113f06ca4afSHartmut Brandt ac = 0; 2114f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2115f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2116f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2117f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2118f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2119f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2120f06ca4afSHartmut Brandt "module '%s", section); 2121f06ca4afSHartmut Brandt break; 2122f06ca4afSHartmut Brandt } 2123f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2124f06ca4afSHartmut Brandt } 2125f06ca4afSHartmut Brandt } 2126f06ca4afSHartmut Brandt av[ac] = NULL; 2127f06ca4afSHartmut Brandt 2128f06ca4afSHartmut Brandt /* 2129f06ca4afSHartmut Brandt * Run the initialisation function 2130f06ca4afSHartmut Brandt */ 2131f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2132f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2133f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2134f06ca4afSHartmut Brandt goto err; 2135f06ca4afSHartmut Brandt } 2136f06ca4afSHartmut Brandt 2137f06ca4afSHartmut Brandt return (m); 2138f06ca4afSHartmut Brandt 2139f06ca4afSHartmut Brandt err: 2140f06ca4afSHartmut Brandt if (m->handle) 2141f06ca4afSHartmut Brandt dlclose(m->handle); 2142f06ca4afSHartmut Brandt free(m->path); 2143f06ca4afSHartmut Brandt free(m); 2144f06ca4afSHartmut Brandt return (NULL); 2145f06ca4afSHartmut Brandt } 2146f06ca4afSHartmut Brandt 2147f06ca4afSHartmut Brandt /* 2148f06ca4afSHartmut Brandt * Start a module 2149f06ca4afSHartmut Brandt */ 2150f06ca4afSHartmut Brandt void 2151f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2152f06ca4afSHartmut Brandt { 2153f06ca4afSHartmut Brandt const struct lmodule *m; 2154f06ca4afSHartmut Brandt 2155f06ca4afSHartmut Brandt /* 2156f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2157f06ca4afSHartmut Brandt */ 2158f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2159f06ca4afSHartmut Brandt lm_unload(mod); 2160f06ca4afSHartmut Brandt return; 2161f06ca4afSHartmut Brandt } 2162f06ca4afSHartmut Brandt 2163f06ca4afSHartmut Brandt /* 2164f06ca4afSHartmut Brandt * Read configuration 2165f06ca4afSHartmut Brandt */ 2166f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2167f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2168f06ca4afSHartmut Brandt lm_unload(mod); 2169f06ca4afSHartmut Brandt return; 2170f06ca4afSHartmut Brandt } 2171f06ca4afSHartmut Brandt if (mod->config->start) 2172f06ca4afSHartmut Brandt (*mod->config->start)(); 2173f06ca4afSHartmut Brandt 2174f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2175f06ca4afSHartmut Brandt 2176f06ca4afSHartmut Brandt /* 2177f06ca4afSHartmut Brandt * Inform other modules 2178f06ca4afSHartmut Brandt */ 2179f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2180f06ca4afSHartmut Brandt if (m->config->loading) 2181f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2182f06ca4afSHartmut Brandt } 2183f06ca4afSHartmut Brandt 2184f06ca4afSHartmut Brandt 2185f06ca4afSHartmut Brandt /* 2186f06ca4afSHartmut Brandt * Unload a module. 2187f06ca4afSHartmut Brandt */ 2188f06ca4afSHartmut Brandt void 2189f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2190f06ca4afSHartmut Brandt { 2191f06ca4afSHartmut Brandt int err; 2192f06ca4afSHartmut Brandt const struct lmodule *mod; 2193f06ca4afSHartmut Brandt 2194f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2195f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2196f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2197f06ca4afSHartmut Brandt tree_unmerge(m); 2198f06ca4afSHartmut Brandt 2199f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2200f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2201f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2202f06ca4afSHartmut Brandt 2203f06ca4afSHartmut Brandt comm_flush(m); 2204f06ca4afSHartmut Brandt reqid_flush(m); 2205f06ca4afSHartmut Brandt timer_flush(m); 2206f06ca4afSHartmut Brandt fd_flush(m); 2207f06ca4afSHartmut Brandt 2208f06ca4afSHartmut Brandt dlclose(m->handle); 2209f06ca4afSHartmut Brandt free(m->path); 2210f06ca4afSHartmut Brandt 2211f06ca4afSHartmut Brandt /* 2212f06ca4afSHartmut Brandt * Inform other modules 2213f06ca4afSHartmut Brandt */ 2214f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2215f06ca4afSHartmut Brandt if (mod->config->loading) 2216f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2217f06ca4afSHartmut Brandt 2218f06ca4afSHartmut Brandt free(m); 2219f06ca4afSHartmut Brandt } 2220f06ca4afSHartmut Brandt 2221f06ca4afSHartmut Brandt /* 2222f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2223f06ca4afSHartmut Brandt */ 2224f06ca4afSHartmut Brandt u_int 2225f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2226f06ca4afSHartmut Brandt { 2227f06ca4afSHartmut Brandt struct objres *objres, *or1; 2228f06ca4afSHartmut Brandt u_int idx; 2229f06ca4afSHartmut Brandt 2230f06ca4afSHartmut Brandt /* find a free index */ 2231f06ca4afSHartmut Brandt idx = 1; 2232f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2233f06ca4afSHartmut Brandt objres != NULL; 2234f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2235f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2236f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2237f06ca4afSHartmut Brandt idx = objres->index + 1; 2238f06ca4afSHartmut Brandt break; 2239f06ca4afSHartmut Brandt } 2240f06ca4afSHartmut Brandt } 2241f06ca4afSHartmut Brandt 2242f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2243f06ca4afSHartmut Brandt return (0); 2244f06ca4afSHartmut Brandt 2245f06ca4afSHartmut Brandt objres->index = idx; 2246f06ca4afSHartmut Brandt objres->oid = *or; 2247f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 2248f06ca4afSHartmut Brandt objres->uptime = get_ticks() - start_tick; 2249f06ca4afSHartmut Brandt objres->module = mod; 2250f06ca4afSHartmut Brandt 2251f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2252f06ca4afSHartmut Brandt 2253f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2254f06ca4afSHartmut Brandt 2255f06ca4afSHartmut Brandt return (idx); 2256f06ca4afSHartmut Brandt } 2257f06ca4afSHartmut Brandt 2258f06ca4afSHartmut Brandt void 2259f06ca4afSHartmut Brandt or_unregister(u_int idx) 2260f06ca4afSHartmut Brandt { 2261f06ca4afSHartmut Brandt struct objres *objres; 2262f06ca4afSHartmut Brandt 2263f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2264f06ca4afSHartmut Brandt if (objres->index == idx) { 2265f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2266f06ca4afSHartmut Brandt free(objres); 2267f06ca4afSHartmut Brandt return; 2268f06ca4afSHartmut Brandt } 2269f06ca4afSHartmut Brandt } 2270