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