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 * 29748b5b1eSHartmut Brandt * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 30f06ca4afSHartmut Brandt * 31f06ca4afSHartmut Brandt * SNMPd main stuff. 32f06ca4afSHartmut Brandt */ 33*135f7de5SShteryana Shopova 34*135f7de5SShteryana Shopova #include <sys/queue.h> 35f06ca4afSHartmut Brandt #include <sys/param.h> 36f06ca4afSHartmut Brandt #include <sys/un.h> 3770af00a1SHartmut Brandt #include <sys/ucred.h> 38165c5d31SHartmut Brandt #include <sys/uio.h> 39f06ca4afSHartmut Brandt #include <stdio.h> 40f06ca4afSHartmut Brandt #include <stdlib.h> 41f06ca4afSHartmut Brandt #include <stddef.h> 42f06ca4afSHartmut Brandt #include <string.h> 43f06ca4afSHartmut Brandt #include <stdarg.h> 44f06ca4afSHartmut Brandt #include <ctype.h> 45f06ca4afSHartmut Brandt #include <errno.h> 46f06ca4afSHartmut Brandt #include <syslog.h> 47f06ca4afSHartmut Brandt #include <unistd.h> 48f06ca4afSHartmut Brandt #include <signal.h> 49f06ca4afSHartmut Brandt #include <dlfcn.h> 50f06ca4afSHartmut Brandt #include <inttypes.h> 51f06ca4afSHartmut Brandt 52d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 53d7eb6b47SHartmut Brandt #include <arpa/inet.h> 54d7eb6b47SHartmut Brandt #include <tcpd.h> 55d7eb6b47SHartmut Brandt #endif 56d7eb6b47SHartmut Brandt 57748b5b1eSHartmut Brandt #include "support.h" 58f06ca4afSHartmut Brandt #include "snmpmod.h" 59f06ca4afSHartmut Brandt #include "snmpd.h" 60f06ca4afSHartmut Brandt #include "tree.h" 61f06ca4afSHartmut Brandt #include "oid.h" 62f06ca4afSHartmut Brandt 63f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 64f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 65*135f7de5SShteryana Shopova #define PATH_ENGINE "/var/%s.engine" 66f06ca4afSHartmut Brandt 6769292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 6869292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 69f06ca4afSHartmut Brandt 70f06ca4afSHartmut Brandt struct systemg systemg = { 71f06ca4afSHartmut Brandt NULL, 72f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 73f06ca4afSHartmut Brandt NULL, NULL, NULL, 74f06ca4afSHartmut Brandt 64 + 8 + 4, 75f06ca4afSHartmut Brandt 0 76f06ca4afSHartmut Brandt }; 77f06ca4afSHartmut Brandt struct debug debug = { 78f06ca4afSHartmut Brandt 0, /* dump_pdus */ 79f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 80f06ca4afSHartmut Brandt 0, /* evdebug */ 81f06ca4afSHartmut Brandt }; 82f06ca4afSHartmut Brandt 83f06ca4afSHartmut Brandt struct snmpd snmpd = { 84f06ca4afSHartmut Brandt 2048, /* txbuf */ 85f06ca4afSHartmut Brandt 2048, /* rxbuf */ 86f06ca4afSHartmut Brandt 0, /* comm_dis */ 87f06ca4afSHartmut Brandt 0, /* auth_traps */ 88f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 8970af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 90f06ca4afSHartmut Brandt }; 91f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 92f06ca4afSHartmut Brandt 93*135f7de5SShteryana Shopova struct snmpd_usmstat snmpd_usmstats; 94*135f7de5SShteryana Shopova 95*135f7de5SShteryana Shopova /* snmpEngine */ 96*135f7de5SShteryana Shopova struct snmp_engine snmpd_engine; 97*135f7de5SShteryana Shopova 98f06ca4afSHartmut Brandt /* snmpSerialNo */ 99f06ca4afSHartmut Brandt int32_t snmp_serial_no; 100f06ca4afSHartmut Brandt 101f06ca4afSHartmut Brandt /* search path for config files */ 102f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 103f06ca4afSHartmut Brandt 104f06ca4afSHartmut Brandt /* list of all loaded modules */ 105f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 106f06ca4afSHartmut Brandt 107f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 108f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 109f06ca4afSHartmut Brandt 110f06ca4afSHartmut Brandt /* list of all known communities */ 111f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 112f06ca4afSHartmut Brandt 113*135f7de5SShteryana Shopova /* list of all known USM users */ 114*135f7de5SShteryana Shopova struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 115*135f7de5SShteryana Shopova 116*135f7de5SShteryana Shopova /* A list of all VACM users configured, including v1, v2c and v3 */ 117*135f7de5SShteryana Shopova struct vacm_userlist vacm_userlist = SLIST_HEAD_INITIALIZER(vacm_userlist); 118*135f7de5SShteryana Shopova 119*135f7de5SShteryana Shopova /* A list of all VACM groups */ 120*135f7de5SShteryana Shopova struct vacm_grouplist vacm_grouplist = SLIST_HEAD_INITIALIZER(vacm_grouplist); 121*135f7de5SShteryana Shopova 122*135f7de5SShteryana Shopova static struct vacm_group vacm_default_group = { 123*135f7de5SShteryana Shopova .groupname = "", 124*135f7de5SShteryana Shopova }; 125*135f7de5SShteryana Shopova 126*135f7de5SShteryana Shopova /* The list of configured access entries */ 127*135f7de5SShteryana Shopova struct vacm_accesslist vacm_accesslist = TAILQ_HEAD_INITIALIZER(vacm_accesslist); 128*135f7de5SShteryana Shopova 129*135f7de5SShteryana Shopova /* The list of configured views */ 130*135f7de5SShteryana Shopova struct vacm_viewlist vacm_viewlist = SLIST_HEAD_INITIALIZER(vacm_viewlist); 131*135f7de5SShteryana Shopova 132*135f7de5SShteryana Shopova /* The list of configured contexts */ 133*135f7de5SShteryana Shopova struct vacm_contextlist vacm_contextlist = 134*135f7de5SShteryana Shopova SLIST_HEAD_INITIALIZER(vacm_contextlist); 135*135f7de5SShteryana Shopova 136f06ca4afSHartmut Brandt /* list of all installed object resources */ 137f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 138f06ca4afSHartmut Brandt 139f06ca4afSHartmut Brandt /* community value generator */ 140f06ca4afSHartmut Brandt static u_int next_community_index = 1; 141f06ca4afSHartmut Brandt 142f06ca4afSHartmut Brandt /* list of all known ranges */ 143f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 144f06ca4afSHartmut Brandt 145f06ca4afSHartmut Brandt /* identifier generator */ 146f06ca4afSHartmut Brandt u_int next_idrange = 1; 147f06ca4afSHartmut Brandt 148f06ca4afSHartmut Brandt /* list of all current timers */ 149f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 150f06ca4afSHartmut Brandt 151f06ca4afSHartmut Brandt /* list of file descriptors */ 152f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 153f06ca4afSHartmut Brandt 154f06ca4afSHartmut Brandt /* program arguments */ 155f06ca4afSHartmut Brandt static char **progargs; 156f06ca4afSHartmut Brandt static int nprogargs; 157f06ca4afSHartmut Brandt 158f06ca4afSHartmut Brandt /* current community */ 159f06ca4afSHartmut Brandt u_int community; 160f06ca4afSHartmut Brandt static struct community *comm; 161f06ca4afSHartmut Brandt 162*135f7de5SShteryana Shopova /* current USM user */ 163*135f7de5SShteryana Shopova struct usm_user *usm_user; 164*135f7de5SShteryana Shopova 165f06ca4afSHartmut Brandt /* file names */ 166f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 167f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 168*135f7de5SShteryana Shopova char engine_file[MAXPATHLEN + 1]; 169f06ca4afSHartmut Brandt 17070af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 171f06ca4afSHartmut Brandt /* event context */ 172f06ca4afSHartmut Brandt static evContext evctx; 17370af00a1SHartmut Brandt #endif 174f06ca4afSHartmut Brandt 175f06ca4afSHartmut Brandt /* signal mask */ 176f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 177f06ca4afSHartmut Brandt 178f06ca4afSHartmut Brandt /* signal handling */ 179f06ca4afSHartmut Brandt static int work; 180f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 181f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 182f06ca4afSHartmut Brandt 183f06ca4afSHartmut Brandt /* oids */ 184f06ca4afSHartmut Brandt static const struct asn_oid 185f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 186f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 187f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 188f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 189f06ca4afSHartmut Brandt 190f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 191f06ca4afSHartmut Brandt 192*135f7de5SShteryana Shopova const struct asn_oid oid_usmUnknownEngineIDs = 193*135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 194*135f7de5SShteryana Shopova 195*135f7de5SShteryana Shopova const struct asn_oid oid_usmNotInTimeWindows = 196*135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 197*135f7de5SShteryana Shopova 198f06ca4afSHartmut Brandt /* request id generator for traps */ 199f06ca4afSHartmut Brandt u_int trap_reqid; 200f06ca4afSHartmut Brandt 201f06ca4afSHartmut Brandt /* help text */ 202f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 203f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 204f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 205*135f7de5SShteryana Shopova Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 206*135f7de5SShteryana Shopova usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 207*135f7de5SShteryana Shopova [-l prefix] [-m variable=value] [-p file]\n\ 208f06ca4afSHartmut Brandt options:\n\ 209f06ca4afSHartmut Brandt -d don't daemonize\n\ 210f06ca4afSHartmut Brandt -h print this info\n\ 211f06ca4afSHartmut Brandt -c file specify configuration file\n\ 212f06ca4afSHartmut Brandt -D options debugging options\n\ 213*135f7de5SShteryana Shopova -e file specify engine id file\n\ 214f06ca4afSHartmut Brandt -I path system include path\n\ 215f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 216f06ca4afSHartmut Brandt -m var=val define variable\n\ 217f06ca4afSHartmut Brandt -p file specify pid file\n\ 218f06ca4afSHartmut Brandt "; 219f06ca4afSHartmut Brandt 220d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 221d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 222d7eb6b47SHartmut Brandt static struct request_info req; 223d7eb6b47SHartmut Brandt #endif 224d7eb6b47SHartmut Brandt 22570af00a1SHartmut Brandt /* transports */ 22670af00a1SHartmut Brandt extern const struct transport_def udp_trans; 22770af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 22870af00a1SHartmut Brandt 22970af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 23070af00a1SHartmut Brandt 231f06ca4afSHartmut Brandt /* forward declarations */ 232f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 233f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 234f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 235f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 236f06ca4afSHartmut Brandt 237f06ca4afSHartmut Brandt /* 238f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 239f06ca4afSHartmut Brandt */ 240f06ca4afSHartmut Brandt void * 241f06ca4afSHartmut Brandt buf_alloc(int tx) 242f06ca4afSHartmut Brandt { 243f06ca4afSHartmut Brandt void *buf; 244f06ca4afSHartmut Brandt 24570af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 246f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 247f06ca4afSHartmut Brandt if (tx) 248f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 249f06ca4afSHartmut Brandt else 250f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 251f06ca4afSHartmut Brandt return (NULL); 252f06ca4afSHartmut Brandt } 253f06ca4afSHartmut Brandt return (buf); 254f06ca4afSHartmut Brandt } 255f06ca4afSHartmut Brandt 256f06ca4afSHartmut Brandt /* 25770af00a1SHartmut Brandt * Return the buffer size. 258f06ca4afSHartmut Brandt */ 259f06ca4afSHartmut Brandt size_t 260f06ca4afSHartmut Brandt buf_size(int tx) 261f06ca4afSHartmut Brandt { 26270af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 263f06ca4afSHartmut Brandt } 264f06ca4afSHartmut Brandt 265f06ca4afSHartmut Brandt /* 266f06ca4afSHartmut Brandt * Prepare a PDU for output 267f06ca4afSHartmut Brandt */ 268f06ca4afSHartmut Brandt void 26970af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 270f06ca4afSHartmut Brandt const char *dest) 271f06ca4afSHartmut Brandt { 272f06ca4afSHartmut Brandt struct asn_buf resp_b; 273f06ca4afSHartmut Brandt 274f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 275f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 276f06ca4afSHartmut Brandt 277f06ca4afSHartmut Brandt if (snmp_pdu_encode(pdu, &resp_b) != 0) { 278f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot encode message"); 279f06ca4afSHartmut Brandt abort(); 280f06ca4afSHartmut Brandt } 281f06ca4afSHartmut Brandt if (debug.dump_pdus) { 282f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 283f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 284f06ca4afSHartmut Brandt } 285f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 286f06ca4afSHartmut Brandt } 287f06ca4afSHartmut Brandt 288f06ca4afSHartmut Brandt /* 289*135f7de5SShteryana Shopova * Check USM PDU header credentials against local SNMP Engine & users. 290*135f7de5SShteryana Shopova */ 291*135f7de5SShteryana Shopova static enum snmp_code 292*135f7de5SShteryana Shopova snmp_pdu_auth_user(struct snmp_pdu *pdu) 293*135f7de5SShteryana Shopova { 294*135f7de5SShteryana Shopova uint64_t etime; 295*135f7de5SShteryana Shopova usm_user = NULL; 296*135f7de5SShteryana Shopova 297*135f7de5SShteryana Shopova /* un-authenticated snmpEngineId discovery */ 298*135f7de5SShteryana Shopova if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 299*135f7de5SShteryana Shopova pdu->engine.engine_len = snmpd_engine.engine_len; 300*135f7de5SShteryana Shopova memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 301*135f7de5SShteryana Shopova snmpd_engine.engine_len); 302*135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 303*135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 304*135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 305*135f7de5SShteryana Shopova return (SNMP_CODE_OK); 306*135f7de5SShteryana Shopova } 307*135f7de5SShteryana Shopova 308*135f7de5SShteryana Shopova if ((usm_user = usm_find_user(pdu->engine.engine_id, 309*135f7de5SShteryana Shopova pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 310*135f7de5SShteryana Shopova usm_user->status != 1 /* active */) 311*135f7de5SShteryana Shopova return (SNMP_CODE_BADUSER); 312*135f7de5SShteryana Shopova 313*135f7de5SShteryana Shopova if (usm_user->user_engine_len != snmpd_engine.engine_len || 314*135f7de5SShteryana Shopova memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 315*135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 316*135f7de5SShteryana Shopova return (SNMP_CODE_BADENGINE); 317*135f7de5SShteryana Shopova 318*135f7de5SShteryana Shopova pdu->user.priv_proto = usm_user->suser.priv_proto; 319*135f7de5SShteryana Shopova memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 320*135f7de5SShteryana Shopova sizeof(pdu->user.priv_key)); 321*135f7de5SShteryana Shopova 322*135f7de5SShteryana Shopova /* authenticated snmpEngineId discovery */ 323*135f7de5SShteryana Shopova if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 324*135f7de5SShteryana Shopova etime = (get_ticks() - start_tick) / 100ULL; 325*135f7de5SShteryana Shopova if (etime < INT32_MAX) 326*135f7de5SShteryana Shopova snmpd_engine.engine_time = etime; 327*135f7de5SShteryana Shopova else { 328*135f7de5SShteryana Shopova start_tick = get_ticks(); 329*135f7de5SShteryana Shopova set_snmpd_engine(); 330*135f7de5SShteryana Shopova snmpd_engine.engine_time = start_tick; 331*135f7de5SShteryana Shopova } 332*135f7de5SShteryana Shopova 333*135f7de5SShteryana Shopova pdu->user.auth_proto = usm_user->suser.auth_proto; 334*135f7de5SShteryana Shopova memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 335*135f7de5SShteryana Shopova sizeof(pdu->user.auth_key)); 336*135f7de5SShteryana Shopova 337*135f7de5SShteryana Shopova if (pdu->engine.engine_boots == 0 && 338*135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 339*135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 340*135f7de5SShteryana Shopova return (SNMP_CODE_OK); 341*135f7de5SShteryana Shopova } 342*135f7de5SShteryana Shopova 343*135f7de5SShteryana Shopova if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 344*135f7de5SShteryana Shopova abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 345*135f7de5SShteryana Shopova SNMP_TIME_WINDOW) 346*135f7de5SShteryana Shopova return (SNMP_CODE_NOTINTIME); 347*135f7de5SShteryana Shopova } 348*135f7de5SShteryana Shopova 349*135f7de5SShteryana Shopova if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 350*135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 351*135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 352*135f7de5SShteryana Shopova usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 353*135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 354*135f7de5SShteryana Shopova usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 355*135f7de5SShteryana Shopova return (SNMP_CODE_BADSECLEVEL); 356*135f7de5SShteryana Shopova 357*135f7de5SShteryana Shopova return (SNMP_CODE_OK); 358*135f7de5SShteryana Shopova } 359*135f7de5SShteryana Shopova 360*135f7de5SShteryana Shopova /* 361*135f7de5SShteryana Shopova * Check whether access to each of var bindings in the PDU is allowed based 362*135f7de5SShteryana Shopova * on the user credentials against the configured User groups & VACM views. 363*135f7de5SShteryana Shopova */ 364*135f7de5SShteryana Shopova static enum snmp_code 365*135f7de5SShteryana Shopova snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 366*135f7de5SShteryana Shopova { 367*135f7de5SShteryana Shopova const char *uname; 368*135f7de5SShteryana Shopova int32_t suboid, smodel; 369*135f7de5SShteryana Shopova uint32_t i; 370*135f7de5SShteryana Shopova struct vacm_user *vuser; 371*135f7de5SShteryana Shopova struct vacm_access *acl; 372*135f7de5SShteryana Shopova struct vacm_context *vacmctx; 373*135f7de5SShteryana Shopova struct vacm_view *view; 374*135f7de5SShteryana Shopova 375*135f7de5SShteryana Shopova /* 376*135f7de5SShteryana Shopova * At least a default context exists if the snmpd_vacm(3) module is 377*135f7de5SShteryana Shopova * running. 378*135f7de5SShteryana Shopova */ 379*135f7de5SShteryana Shopova if (SLIST_EMPTY(&vacm_contextlist) || 380*135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 381*135f7de5SShteryana Shopova return (SNMP_CODE_OK); 382*135f7de5SShteryana Shopova 383*135f7de5SShteryana Shopova switch (pdu->version) { 384*135f7de5SShteryana Shopova case SNMP_V1: 385*135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 386*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 387*135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv1; 388*135f7de5SShteryana Shopova break; 389*135f7de5SShteryana Shopova 390*135f7de5SShteryana Shopova case SNMP_V2c: 391*135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 392*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 393*135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv2c; 394*135f7de5SShteryana Shopova break; 395*135f7de5SShteryana Shopova 396*135f7de5SShteryana Shopova case SNMP_V3: 397*135f7de5SShteryana Shopova uname = pdu->user.sec_name; 398*135f7de5SShteryana Shopova if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 399*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 400*135f7de5SShteryana Shopova /* Compare the PDU context engine id against the agent's */ 401*135f7de5SShteryana Shopova if (pdu->context_engine_len != snmpd_engine.engine_len || 402*135f7de5SShteryana Shopova memcmp(pdu->context_engine, snmpd_engine.engine_id, 403*135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 404*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 405*135f7de5SShteryana Shopova break; 406*135f7de5SShteryana Shopova 407*135f7de5SShteryana Shopova default: 408*135f7de5SShteryana Shopova abort(); 409*135f7de5SShteryana Shopova } 410*135f7de5SShteryana Shopova 411*135f7de5SShteryana Shopova SLIST_FOREACH(vuser, &vacm_userlist, vvu) 412*135f7de5SShteryana Shopova if (strcmp(uname, vuser->secname) == 0 && 413*135f7de5SShteryana Shopova vuser->sec_model == smodel) 414*135f7de5SShteryana Shopova break; 415*135f7de5SShteryana Shopova 416*135f7de5SShteryana Shopova if (vuser == NULL || vuser->group == NULL) 417*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 418*135f7de5SShteryana Shopova 419*135f7de5SShteryana Shopova /* XXX: shteryana - recheck */ 420*135f7de5SShteryana Shopova TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 421*135f7de5SShteryana Shopova if (acl->group != vuser->group) 422*135f7de5SShteryana Shopova continue; 423*135f7de5SShteryana Shopova SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 424*135f7de5SShteryana Shopova if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 425*135f7de5SShteryana Shopova acl->ctx_match) == 0) 426*135f7de5SShteryana Shopova goto match; 427*135f7de5SShteryana Shopova } 428*135f7de5SShteryana Shopova 429*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 430*135f7de5SShteryana Shopova 431*135f7de5SShteryana Shopova match: 432*135f7de5SShteryana Shopova 433*135f7de5SShteryana Shopova switch (pdu->type) { 434*135f7de5SShteryana Shopova case SNMP_PDU_GET: 435*135f7de5SShteryana Shopova case SNMP_PDU_GETNEXT: 436*135f7de5SShteryana Shopova case SNMP_PDU_GETBULK: 437*135f7de5SShteryana Shopova if ((view = acl->read_view) == NULL) 438*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 439*135f7de5SShteryana Shopova break; 440*135f7de5SShteryana Shopova 441*135f7de5SShteryana Shopova case SNMP_PDU_SET: 442*135f7de5SShteryana Shopova if ((view = acl->write_view) == NULL) 443*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 444*135f7de5SShteryana Shopova break; 445*135f7de5SShteryana Shopova 446*135f7de5SShteryana Shopova case SNMP_PDU_TRAP: 447*135f7de5SShteryana Shopova case SNMP_PDU_INFORM: 448*135f7de5SShteryana Shopova case SNMP_PDU_TRAP2: 449*135f7de5SShteryana Shopova case SNMP_PDU_REPORT: 450*135f7de5SShteryana Shopova if ((view = acl->notify_view) == NULL) 451*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 452*135f7de5SShteryana Shopova break; 453*135f7de5SShteryana Shopova case SNMP_PDU_RESPONSE: 454*135f7de5SShteryana Shopova /* NOTREACHED */ 455*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 456*135f7de5SShteryana Shopova default: 457*135f7de5SShteryana Shopova abort(); 458*135f7de5SShteryana Shopova } 459*135f7de5SShteryana Shopova 460*135f7de5SShteryana Shopova for (i = 0; i < pdu->nbindings; i++) { 461*135f7de5SShteryana Shopova /* XXX - view->mask*/ 462*135f7de5SShteryana Shopova suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 463*135f7de5SShteryana Shopova if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 464*135f7de5SShteryana Shopova *ip = i + 1; 465*135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 466*135f7de5SShteryana Shopova } 467*135f7de5SShteryana Shopova } 468*135f7de5SShteryana Shopova 469*135f7de5SShteryana Shopova return (SNMP_CODE_OK); 470*135f7de5SShteryana Shopova } 471*135f7de5SShteryana Shopova 472*135f7de5SShteryana Shopova /* 473*135f7de5SShteryana Shopova * SNMP input. Start: decode the PDU, find the user or community. 474f06ca4afSHartmut Brandt */ 475f06ca4afSHartmut Brandt enum snmpd_input_err 476f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 47770af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 478f06ca4afSHartmut Brandt { 479f06ca4afSHartmut Brandt struct asn_buf b; 480f06ca4afSHartmut Brandt enum snmp_code code; 481f06ca4afSHartmut Brandt enum snmpd_input_err ret; 48270af00a1SHartmut Brandt int sret; 483f06ca4afSHartmut Brandt 484*135f7de5SShteryana Shopova /* update uptime */ 485*135f7de5SShteryana Shopova this_tick = get_ticks(); 486*135f7de5SShteryana Shopova 487f06ca4afSHartmut Brandt b.asn_cptr = buf; 488f06ca4afSHartmut Brandt b.asn_len = len; 48970af00a1SHartmut Brandt 49070af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 49170af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 49270af00a1SHartmut Brandt 49370af00a1SHartmut Brandt case 0: 49470af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 49570af00a1SHartmut Brandt 49670af00a1SHartmut Brandt case -1: 49770af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 49870af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 49970af00a1SHartmut Brandt } 50070af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 50170af00a1SHartmut Brandt 502*135f7de5SShteryana Shopova memset(pdu, 0, sizeof(*pdu)); 503*135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 504*135f7de5SShteryana Shopova goto decoded; 505f06ca4afSHartmut Brandt 506*135f7de5SShteryana Shopova if (pdu->version == SNMP_V3) { 507*135f7de5SShteryana Shopova if (pdu->security_model != SNMP_SECMODEL_USM) { 508*135f7de5SShteryana Shopova code = SNMP_CODE_FAILED; 509*135f7de5SShteryana Shopova goto decoded; 510*135f7de5SShteryana Shopova } 511*135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 512*135f7de5SShteryana Shopova goto decoded; 513*135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 514*135f7de5SShteryana Shopova goto decoded; 515*135f7de5SShteryana Shopova } 516*135f7de5SShteryana Shopova code = snmp_pdu_decode_scoped(&b, pdu, ip); 51770af00a1SHartmut Brandt 518f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 519*135f7de5SShteryana Shopova 520*135f7de5SShteryana Shopova decoded: 521*135f7de5SShteryana Shopova snmpd_stats.inPkts++; 522*135f7de5SShteryana Shopova 523f06ca4afSHartmut Brandt switch (code) { 524f06ca4afSHartmut Brandt 525f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 526f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 527f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 528f06ca4afSHartmut Brandt 529f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 53070af00a1SHartmut Brandt bad_vers: 531f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 532f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 533f06ca4afSHartmut Brandt 534f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 535f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 536f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 537f06ca4afSHartmut Brandt break; 538f06ca4afSHartmut Brandt 539f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 540f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 541f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 542f06ca4afSHartmut Brandt break; 543f06ca4afSHartmut Brandt 544f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 545f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 546f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 547f06ca4afSHartmut Brandt break; 548f06ca4afSHartmut Brandt 549*135f7de5SShteryana Shopova case SNMP_CODE_BADSECLEVEL: 550*135f7de5SShteryana Shopova snmpd_usmstats.unsupported_seclevels++; 551*135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 552*135f7de5SShteryana Shopova 553*135f7de5SShteryana Shopova case SNMP_CODE_NOTINTIME: 554*135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 555*135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 556*135f7de5SShteryana Shopova 557*135f7de5SShteryana Shopova case SNMP_CODE_BADUSER: 558*135f7de5SShteryana Shopova snmpd_usmstats.unknown_users++; 559*135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 560*135f7de5SShteryana Shopova 561*135f7de5SShteryana Shopova case SNMP_CODE_BADENGINE: 562*135f7de5SShteryana Shopova snmpd_usmstats.unknown_engine_ids++; 563*135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 564*135f7de5SShteryana Shopova 565*135f7de5SShteryana Shopova case SNMP_CODE_BADDIGEST: 566*135f7de5SShteryana Shopova snmpd_usmstats.wrong_digests++; 567*135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 568*135f7de5SShteryana Shopova 569*135f7de5SShteryana Shopova case SNMP_CODE_EDECRYPT: 570*135f7de5SShteryana Shopova snmpd_usmstats.decrypt_errors++; 571*135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 572*135f7de5SShteryana Shopova 573f06ca4afSHartmut Brandt case SNMP_CODE_OK: 57470af00a1SHartmut Brandt switch (pdu->version) { 57570af00a1SHartmut Brandt 57670af00a1SHartmut Brandt case SNMP_V1: 57770af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 57870af00a1SHartmut Brandt goto bad_vers; 57970af00a1SHartmut Brandt break; 58070af00a1SHartmut Brandt 58170af00a1SHartmut Brandt case SNMP_V2c: 58270af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 58370af00a1SHartmut Brandt goto bad_vers; 58470af00a1SHartmut Brandt break; 58570af00a1SHartmut Brandt 586*135f7de5SShteryana Shopova case SNMP_V3: 587*135f7de5SShteryana Shopova if (!(snmpd.version_enable & VERS_ENABLE_V3)) 588*135f7de5SShteryana Shopova goto bad_vers; 589*135f7de5SShteryana Shopova break; 590*135f7de5SShteryana Shopova 59170af00a1SHartmut Brandt case SNMP_Verr: 59270af00a1SHartmut Brandt goto bad_vers; 59370af00a1SHartmut Brandt } 594f06ca4afSHartmut Brandt break; 595f06ca4afSHartmut Brandt } 596f06ca4afSHartmut Brandt 597f06ca4afSHartmut Brandt if (debug.dump_pdus) { 598f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 599f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 600f06ca4afSHartmut Brandt } 601f06ca4afSHartmut Brandt 602f06ca4afSHartmut Brandt /* 603*135f7de5SShteryana Shopova * Look, whether we know the community or user 604f06ca4afSHartmut Brandt */ 605*135f7de5SShteryana Shopova 606*135f7de5SShteryana Shopova if (pdu->version != SNMP_V3) { 607f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 608f06ca4afSHartmut Brandt if (comm->string != NULL && 609f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 610f06ca4afSHartmut Brandt break; 611f06ca4afSHartmut Brandt 612f06ca4afSHartmut Brandt if (comm == NULL) { 613f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 614f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 615f06ca4afSHartmut Brandt if (snmpd.auth_traps) 616896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 617896052c1SHartmut Brandt (struct snmp_value *)NULL); 618896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 619896052c1SHartmut Brandt } else 620f06ca4afSHartmut Brandt community = comm->value; 621*135f7de5SShteryana Shopova } else if (pdu->nbindings == 0) { 622*135f7de5SShteryana Shopova /* RFC 3414 - snmpEngineID Discovery */ 623*135f7de5SShteryana Shopova if (strlen(pdu->user.sec_name) == 0) { 624*135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 625*135f7de5SShteryana Shopova &oid_usmUnknownEngineIDs); 626*135f7de5SShteryana Shopova pdu->context_engine_len = snmpd_engine.engine_len; 627*135f7de5SShteryana Shopova memcpy(pdu->context_engine, snmpd_engine.engine_id, 628*135f7de5SShteryana Shopova snmpd_engine.engine_len); 629*135f7de5SShteryana Shopova } else if (pdu->engine.engine_boots == 0 && 630*135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 631*135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 632*135f7de5SShteryana Shopova &oid_usmNotInTimeWindows); 633*135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 634*135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 635*135f7de5SShteryana Shopova } 636*135f7de5SShteryana Shopova } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 637*135f7de5SShteryana Shopova (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 638*135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 639*135f7de5SShteryana Shopova ret = SNMP_CODE_FAILED; 640*135f7de5SShteryana Shopova } 641f06ca4afSHartmut Brandt 642*135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 643*135f7de5SShteryana Shopova ret = SNMP_CODE_FAILED; 644f06ca4afSHartmut Brandt 645f06ca4afSHartmut Brandt return (ret); 646f06ca4afSHartmut Brandt } 647f06ca4afSHartmut Brandt 648f06ca4afSHartmut Brandt /* 649f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 650f06ca4afSHartmut Brandt */ 651f06ca4afSHartmut Brandt enum snmpd_input_err 652f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 653f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 654f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 655f06ca4afSHartmut Brandt { 656f06ca4afSHartmut Brandt struct snmp_pdu resp; 657f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 658f06ca4afSHartmut Brandt enum snmp_ret ret; 659f06ca4afSHartmut Brandt 660f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 661f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 662f06ca4afSHartmut Brandt 663f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 664f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 665f06ca4afSHartmut Brandt 666f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 667f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 668f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 669f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 670f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 671f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 672f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 673f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 674f06ca4afSHartmut Brandt else 675f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 676f06ca4afSHartmut Brandt 677f06ca4afSHartmut Brandt pdu->error_index = ivar; 678f06ca4afSHartmut Brandt 679f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 680f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 681f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 682f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 683f06ca4afSHartmut Brandt } 684f06ca4afSHartmut Brandt 685f06ca4afSHartmut Brandt if (debug.dump_pdus) { 686f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 687f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 688f06ca4afSHartmut Brandt } 689f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 690f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 691f06ca4afSHartmut Brandt } 692f06ca4afSHartmut Brandt 693f06ca4afSHartmut Brandt switch (pdu->type) { 694f06ca4afSHartmut Brandt 695f06ca4afSHartmut Brandt case SNMP_PDU_GET: 696f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 697f06ca4afSHartmut Brandt break; 698f06ca4afSHartmut Brandt 699f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 700f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 701f06ca4afSHartmut Brandt break; 702f06ca4afSHartmut Brandt 703f06ca4afSHartmut Brandt case SNMP_PDU_SET: 704f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 705f06ca4afSHartmut Brandt break; 706f06ca4afSHartmut Brandt 707f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 708f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 709f06ca4afSHartmut Brandt break; 710f06ca4afSHartmut Brandt 711f06ca4afSHartmut Brandt default: 712f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 713f06ca4afSHartmut Brandt break; 714f06ca4afSHartmut Brandt } 715f06ca4afSHartmut Brandt 716f06ca4afSHartmut Brandt switch (ret) { 717f06ca4afSHartmut Brandt 718f06ca4afSHartmut Brandt case SNMP_RET_OK: 719f06ca4afSHartmut Brandt /* normal return - send a response */ 720f06ca4afSHartmut Brandt if (debug.dump_pdus) { 721f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 722f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 723f06ca4afSHartmut Brandt } 724f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 725f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 726f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 727f06ca4afSHartmut Brandt 728f06ca4afSHartmut Brandt case SNMP_RET_IGN: 729f06ca4afSHartmut Brandt /* error - send nothing */ 730f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 731f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 732f06ca4afSHartmut Brandt 733f06ca4afSHartmut Brandt case SNMP_RET_ERR: 734f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 735f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 736f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 737f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 738f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 739f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 740f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 741f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 742f06ca4afSHartmut Brandt } else { 743f06ca4afSHartmut Brandt if (debug.dump_pdus) { 744f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 745f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 746f06ca4afSHartmut Brandt } 747f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 748f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 749f06ca4afSHartmut Brandt } 750f06ca4afSHartmut Brandt } 751f06ca4afSHartmut Brandt abort(); 752f06ca4afSHartmut Brandt } 753f06ca4afSHartmut Brandt 75470af00a1SHartmut Brandt /* 75570af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 75670af00a1SHartmut Brandt */ 75770af00a1SHartmut Brandt void 75870af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 75970af00a1SHartmut Brandt { 76070af00a1SHartmut Brandt struct tport *p; 761f06ca4afSHartmut Brandt 76270af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 76370af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 76470af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 76570af00a1SHartmut Brandt return; 76670af00a1SHartmut Brandt } 76770af00a1SHartmut Brandt } 76870af00a1SHartmut Brandt port->transport = t; 76970af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 77070af00a1SHartmut Brandt } 77170af00a1SHartmut Brandt 77270af00a1SHartmut Brandt /* 77370af00a1SHartmut Brandt * Remove a port from a transport's list 77470af00a1SHartmut Brandt */ 77570af00a1SHartmut Brandt void 77670af00a1SHartmut Brandt trans_remove_port(struct tport *port) 77770af00a1SHartmut Brandt { 77870af00a1SHartmut Brandt 77970af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 78070af00a1SHartmut Brandt } 78170af00a1SHartmut Brandt 78270af00a1SHartmut Brandt /* 78370af00a1SHartmut Brandt * Find a port on a transport's list 78470af00a1SHartmut Brandt */ 78570af00a1SHartmut Brandt struct tport * 78670af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 78770af00a1SHartmut Brandt { 78870af00a1SHartmut Brandt 78970af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 79070af00a1SHartmut Brandt } 79170af00a1SHartmut Brandt 79270af00a1SHartmut Brandt /* 79370af00a1SHartmut Brandt * Find next port on a transport's list 79470af00a1SHartmut Brandt */ 79570af00a1SHartmut Brandt struct tport * 79670af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 79770af00a1SHartmut Brandt { 79870af00a1SHartmut Brandt 79970af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 80070af00a1SHartmut Brandt } 80170af00a1SHartmut Brandt 80270af00a1SHartmut Brandt /* 80370af00a1SHartmut Brandt * Return first port 80470af00a1SHartmut Brandt */ 80570af00a1SHartmut Brandt struct tport * 80670af00a1SHartmut Brandt trans_first_port(struct transport *t) 80770af00a1SHartmut Brandt { 80870af00a1SHartmut Brandt 80970af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 81070af00a1SHartmut Brandt } 81170af00a1SHartmut Brandt 81270af00a1SHartmut Brandt /* 81370af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 81470af00a1SHartmut Brandt */ 81570af00a1SHartmut Brandt struct tport * 81670af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 81770af00a1SHartmut Brandt intptr_t arg) 81870af00a1SHartmut Brandt { 81970af00a1SHartmut Brandt struct tport *p; 82070af00a1SHartmut Brandt 82170af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 82270af00a1SHartmut Brandt if (func(p, arg) == 0) 82370af00a1SHartmut Brandt return (p); 82470af00a1SHartmut Brandt return (NULL); 82570af00a1SHartmut Brandt } 82670af00a1SHartmut Brandt 82770af00a1SHartmut Brandt /* 82870af00a1SHartmut Brandt * Register a transport 82970af00a1SHartmut Brandt */ 83070af00a1SHartmut Brandt int 83170af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 83270af00a1SHartmut Brandt { 83370af00a1SHartmut Brandt u_int i; 83470af00a1SHartmut Brandt char or_descr[256]; 83570af00a1SHartmut Brandt 83670af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 83770af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 83870af00a1SHartmut Brandt 83970af00a1SHartmut Brandt /* construct index */ 84070af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 84170af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 84270af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 84370af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 84470af00a1SHartmut Brandt 84570af00a1SHartmut Brandt (*pp)->vtab = def; 84670af00a1SHartmut Brandt 84770af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 84870af00a1SHartmut Brandt free(*pp); 84970af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 85070af00a1SHartmut Brandt } 85170af00a1SHartmut Brandt 85270af00a1SHartmut Brandt /* register module */ 85370af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 85470af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 85570af00a1SHartmut Brandt free(*pp); 85670af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 85770af00a1SHartmut Brandt } 85870af00a1SHartmut Brandt 85970af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 86070af00a1SHartmut Brandt 86170af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 86270af00a1SHartmut Brandt 86370af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 86470af00a1SHartmut Brandt } 86570af00a1SHartmut Brandt 86670af00a1SHartmut Brandt /* 86770af00a1SHartmut Brandt * Unregister transport 86870af00a1SHartmut Brandt */ 86970af00a1SHartmut Brandt int 87070af00a1SHartmut Brandt trans_unregister(struct transport *t) 87170af00a1SHartmut Brandt { 87270af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 87370af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 87470af00a1SHartmut Brandt 87570af00a1SHartmut Brandt or_unregister(t->or_index); 87670af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 87770af00a1SHartmut Brandt 87870af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 87970af00a1SHartmut Brandt } 880f06ca4afSHartmut Brandt 881f06ca4afSHartmut Brandt /* 882f06ca4afSHartmut Brandt * File descriptor support 883f06ca4afSHartmut Brandt */ 88470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 88570af00a1SHartmut Brandt static void 88670af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 88770af00a1SHartmut Brandt #else 888f06ca4afSHartmut Brandt static void 889f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 89070af00a1SHartmut Brandt #endif 891f06ca4afSHartmut Brandt { 892f06ca4afSHartmut Brandt struct fdesc *f = uap; 893f06ca4afSHartmut Brandt 894f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 895f06ca4afSHartmut Brandt } 896f06ca4afSHartmut Brandt 897f06ca4afSHartmut Brandt void 898f06ca4afSHartmut Brandt fd_suspend(void *p) 899f06ca4afSHartmut Brandt { 900f06ca4afSHartmut Brandt struct fdesc *f = p; 901f06ca4afSHartmut Brandt 90270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 90370af00a1SHartmut Brandt if (f->id >= 0) { 90470af00a1SHartmut Brandt poll_unregister(f->id); 90570af00a1SHartmut Brandt f->id = -1; 90670af00a1SHartmut Brandt } 90770af00a1SHartmut Brandt #else 908f06ca4afSHartmut Brandt if (evTestID(f->id)) { 909f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 910f06ca4afSHartmut Brandt evInitID(&f->id); 911f06ca4afSHartmut Brandt } 91270af00a1SHartmut Brandt #endif 913f06ca4afSHartmut Brandt } 914f06ca4afSHartmut Brandt 915f06ca4afSHartmut Brandt int 916f06ca4afSHartmut Brandt fd_resume(void *p) 917f06ca4afSHartmut Brandt { 918f06ca4afSHartmut Brandt struct fdesc *f = p; 919f06ca4afSHartmut Brandt int err; 920f06ca4afSHartmut Brandt 92170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 92270af00a1SHartmut Brandt if (f->id >= 0) 92370af00a1SHartmut Brandt return (0); 92494caccb3SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 92570af00a1SHartmut Brandt err = errno; 92670af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 92770af00a1SHartmut Brandt errno = err; 92870af00a1SHartmut Brandt return (-1); 92970af00a1SHartmut Brandt } 93070af00a1SHartmut Brandt #else 931f06ca4afSHartmut Brandt if (evTestID(f->id)) 932f06ca4afSHartmut Brandt return (0); 933f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 934f06ca4afSHartmut Brandt err = errno; 935f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 936f06ca4afSHartmut Brandt errno = err; 937f06ca4afSHartmut Brandt return (-1); 938f06ca4afSHartmut Brandt } 93970af00a1SHartmut Brandt #endif 940f06ca4afSHartmut Brandt return (0); 941f06ca4afSHartmut Brandt } 942f06ca4afSHartmut Brandt 943f06ca4afSHartmut Brandt void * 944f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 945f06ca4afSHartmut Brandt { 946f06ca4afSHartmut Brandt struct fdesc *f; 947f06ca4afSHartmut Brandt int err; 948f06ca4afSHartmut Brandt 949f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 950f06ca4afSHartmut Brandt err = errno; 951f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 952f06ca4afSHartmut Brandt errno = err; 953f06ca4afSHartmut Brandt return (NULL); 954f06ca4afSHartmut Brandt } 955f06ca4afSHartmut Brandt f->fd = fd; 956f06ca4afSHartmut Brandt f->func = func; 957f06ca4afSHartmut Brandt f->udata = udata; 958f06ca4afSHartmut Brandt f->owner = mod; 95970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 96070af00a1SHartmut Brandt f->id = -1; 96170af00a1SHartmut Brandt #else 962f06ca4afSHartmut Brandt evInitID(&f->id); 96370af00a1SHartmut Brandt #endif 964f06ca4afSHartmut Brandt 965f06ca4afSHartmut Brandt if (fd_resume(f)) { 966f06ca4afSHartmut Brandt err = errno; 967f06ca4afSHartmut Brandt free(f); 968f06ca4afSHartmut Brandt errno = err; 969f06ca4afSHartmut Brandt return (NULL); 970f06ca4afSHartmut Brandt } 971f06ca4afSHartmut Brandt 972f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 973f06ca4afSHartmut Brandt 974f06ca4afSHartmut Brandt return (f); 975f06ca4afSHartmut Brandt } 976f06ca4afSHartmut Brandt 977f06ca4afSHartmut Brandt void 978f06ca4afSHartmut Brandt fd_deselect(void *p) 979f06ca4afSHartmut Brandt { 980f06ca4afSHartmut Brandt struct fdesc *f = p; 981f06ca4afSHartmut Brandt 982f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 983f06ca4afSHartmut Brandt fd_suspend(f); 984f06ca4afSHartmut Brandt free(f); 985f06ca4afSHartmut Brandt } 986f06ca4afSHartmut Brandt 987f06ca4afSHartmut Brandt static void 988f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 989f06ca4afSHartmut Brandt { 990f06ca4afSHartmut Brandt struct fdesc *t, *t1; 991f06ca4afSHartmut Brandt 992f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 993f06ca4afSHartmut Brandt while (t != NULL) { 994f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 995f06ca4afSHartmut Brandt if (t->owner == mod) 996f06ca4afSHartmut Brandt fd_deselect(t); 997f06ca4afSHartmut Brandt t = t1; 998f06ca4afSHartmut Brandt } 999f06ca4afSHartmut Brandt } 1000f06ca4afSHartmut Brandt 1001f06ca4afSHartmut Brandt /* 100270af00a1SHartmut Brandt * Consume a message from the input buffer 1003f06ca4afSHartmut Brandt */ 1004f06ca4afSHartmut Brandt static void 100570af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 1006f06ca4afSHartmut Brandt { 100770af00a1SHartmut Brandt if (!pi->stream) { 100870af00a1SHartmut Brandt /* always consume everything */ 100970af00a1SHartmut Brandt pi->length = 0; 101070af00a1SHartmut Brandt return; 101170af00a1SHartmut Brandt } 101270af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 101370af00a1SHartmut Brandt /* all bytes consumed */ 101470af00a1SHartmut Brandt pi->length = 0; 101570af00a1SHartmut Brandt return; 101670af00a1SHartmut Brandt } 101770af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 101870af00a1SHartmut Brandt pi->length -= pi->consumed; 101970af00a1SHartmut Brandt } 102070af00a1SHartmut Brandt 102170af00a1SHartmut Brandt struct credmsg { 102270af00a1SHartmut Brandt struct cmsghdr hdr; 102370af00a1SHartmut Brandt struct cmsgcred cred; 102470af00a1SHartmut Brandt }; 102570af00a1SHartmut Brandt 102670af00a1SHartmut Brandt static void 102770af00a1SHartmut Brandt check_priv(struct port_input *pi, struct msghdr *msg) 102870af00a1SHartmut Brandt { 102970af00a1SHartmut Brandt struct credmsg *cmsg; 103070af00a1SHartmut Brandt struct xucred ucred; 103170af00a1SHartmut Brandt socklen_t ucredlen; 103270af00a1SHartmut Brandt 103370af00a1SHartmut Brandt pi->priv = 0; 103470af00a1SHartmut Brandt 103570af00a1SHartmut Brandt if (msg->msg_controllen == sizeof(*cmsg)) { 1036165c5d31SHartmut Brandt /* process explicitly sends credentials */ 103770af00a1SHartmut Brandt 103870af00a1SHartmut Brandt cmsg = (struct credmsg *)msg->msg_control; 103970af00a1SHartmut Brandt pi->priv = (cmsg->cred.cmcred_euid == 0); 104070af00a1SHartmut Brandt return; 104170af00a1SHartmut Brandt } 104270af00a1SHartmut Brandt 104370af00a1SHartmut Brandt /* ok, obtain the accept time credentials */ 104470af00a1SHartmut Brandt ucredlen = sizeof(ucred); 104570af00a1SHartmut Brandt 104670af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 104770af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 104870af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 104970af00a1SHartmut Brandt } 105070af00a1SHartmut Brandt 105170af00a1SHartmut Brandt /* 105270af00a1SHartmut Brandt * Input from a stream socket. 105370af00a1SHartmut Brandt */ 105470af00a1SHartmut Brandt static int 105570af00a1SHartmut Brandt recv_stream(struct port_input *pi) 105670af00a1SHartmut Brandt { 105770af00a1SHartmut Brandt struct msghdr msg; 105870af00a1SHartmut Brandt struct iovec iov[1]; 105970af00a1SHartmut Brandt ssize_t len; 106070af00a1SHartmut Brandt struct credmsg cmsg; 106170af00a1SHartmut Brandt 106270af00a1SHartmut Brandt if (pi->buf == NULL) { 106370af00a1SHartmut Brandt /* no buffer yet - allocate one */ 106470af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 106570af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 106670af00a1SHartmut Brandt * the caller must close the transport. */ 106770af00a1SHartmut Brandt return (-1); 106870af00a1SHartmut Brandt } 106970af00a1SHartmut Brandt pi->buflen = buf_size(0); 107070af00a1SHartmut Brandt pi->consumed = 0; 107170af00a1SHartmut Brandt pi->length = 0; 107270af00a1SHartmut Brandt } 107370af00a1SHartmut Brandt 107470af00a1SHartmut Brandt /* try to get a message */ 107570af00a1SHartmut Brandt msg.msg_name = pi->peer; 107670af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 107770af00a1SHartmut Brandt msg.msg_iov = iov; 107870af00a1SHartmut Brandt msg.msg_iovlen = 1; 107970af00a1SHartmut Brandt if (pi->cred) { 108070af00a1SHartmut Brandt msg.msg_control = &cmsg; 108170af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 108270af00a1SHartmut Brandt 108370af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 108470af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 108570af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 108670af00a1SHartmut Brandt } else { 108770af00a1SHartmut Brandt msg.msg_control = NULL; 108870af00a1SHartmut Brandt msg.msg_controllen = 0; 108970af00a1SHartmut Brandt } 109070af00a1SHartmut Brandt msg.msg_flags = 0; 109170af00a1SHartmut Brandt 109270af00a1SHartmut Brandt iov[0].iov_base = pi->buf + pi->length; 109370af00a1SHartmut Brandt iov[0].iov_len = pi->buflen - pi->length; 109470af00a1SHartmut Brandt 109570af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 109670af00a1SHartmut Brandt 109770af00a1SHartmut Brandt if (len == -1 || len == 0) 109870af00a1SHartmut Brandt /* receive error */ 109970af00a1SHartmut Brandt return (-1); 110070af00a1SHartmut Brandt 110170af00a1SHartmut Brandt pi->length += len; 110270af00a1SHartmut Brandt 110370af00a1SHartmut Brandt if (pi->cred) 110470af00a1SHartmut Brandt check_priv(pi, &msg); 110570af00a1SHartmut Brandt 110670af00a1SHartmut Brandt return (0); 110770af00a1SHartmut Brandt } 110870af00a1SHartmut Brandt 110970af00a1SHartmut Brandt /* 111070af00a1SHartmut Brandt * Input from a datagram socket. 111170af00a1SHartmut Brandt * Each receive should return one datagram. 111270af00a1SHartmut Brandt */ 111370af00a1SHartmut Brandt static int 111470af00a1SHartmut Brandt recv_dgram(struct port_input *pi) 111570af00a1SHartmut Brandt { 111670af00a1SHartmut Brandt u_char embuf[1000]; 111770af00a1SHartmut Brandt struct msghdr msg; 111870af00a1SHartmut Brandt struct iovec iov[1]; 111970af00a1SHartmut Brandt ssize_t len; 112070af00a1SHartmut Brandt struct credmsg cmsg; 112170af00a1SHartmut Brandt 112270af00a1SHartmut Brandt if (pi->buf == NULL) { 112370af00a1SHartmut Brandt /* no buffer yet - allocate one */ 112470af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 112570af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 112670af00a1SHartmut Brandt * and drop it */ 112770af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 112870af00a1SHartmut Brandt 0, NULL, NULL); 112970af00a1SHartmut Brandt /* return error */ 113070af00a1SHartmut Brandt return (-1); 113170af00a1SHartmut Brandt } 113270af00a1SHartmut Brandt pi->buflen = buf_size(0); 113370af00a1SHartmut Brandt } 113470af00a1SHartmut Brandt 113570af00a1SHartmut Brandt /* try to get a message */ 113670af00a1SHartmut Brandt msg.msg_name = pi->peer; 113770af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 113870af00a1SHartmut Brandt msg.msg_iov = iov; 113970af00a1SHartmut Brandt msg.msg_iovlen = 1; 114070af00a1SHartmut Brandt if (pi->cred) { 114170af00a1SHartmut Brandt msg.msg_control = &cmsg; 114270af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 114370af00a1SHartmut Brandt 114470af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 114570af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 114670af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 114770af00a1SHartmut Brandt } else { 114870af00a1SHartmut Brandt msg.msg_control = NULL; 11498eecd77aSHartmut Brandt msg.msg_controllen = 0; 115070af00a1SHartmut Brandt } 115170af00a1SHartmut Brandt msg.msg_flags = 0; 115270af00a1SHartmut Brandt 115370af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 115470af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 115570af00a1SHartmut Brandt 115670af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 115770af00a1SHartmut Brandt 115870af00a1SHartmut Brandt if (len == -1 || len == 0) 115970af00a1SHartmut Brandt /* receive error */ 116070af00a1SHartmut Brandt return (-1); 116170af00a1SHartmut Brandt 116270af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 116370af00a1SHartmut Brandt /* truncated - drop */ 116470af00a1SHartmut Brandt snmpd_stats.silentDrops++; 116570af00a1SHartmut Brandt snmpd_stats.inTooLong++; 116670af00a1SHartmut Brandt return (-1); 116770af00a1SHartmut Brandt } 116870af00a1SHartmut Brandt 116970af00a1SHartmut Brandt pi->length = (size_t)len; 117070af00a1SHartmut Brandt 117170af00a1SHartmut Brandt if (pi->cred) 117270af00a1SHartmut Brandt check_priv(pi, &msg); 117370af00a1SHartmut Brandt 117470af00a1SHartmut Brandt return (0); 117570af00a1SHartmut Brandt } 117670af00a1SHartmut Brandt 117770af00a1SHartmut Brandt /* 117870af00a1SHartmut Brandt * Input from a socket 117970af00a1SHartmut Brandt */ 118070af00a1SHartmut Brandt int 118170af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 118270af00a1SHartmut Brandt { 1183f06ca4afSHartmut Brandt u_char *sndbuf; 1184f06ca4afSHartmut Brandt size_t sndlen; 118570af00a1SHartmut Brandt struct snmp_pdu pdu; 1186f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 1187f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 1188f06ca4afSHartmut Brandt int32_t vi; 118970af00a1SHartmut Brandt int ret; 119070af00a1SHartmut Brandt ssize_t slen; 1191d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1192d7eb6b47SHartmut Brandt char client[16]; 1193d7eb6b47SHartmut Brandt #endif 1194f06ca4afSHartmut Brandt 119570af00a1SHartmut Brandt /* get input depending on the transport */ 119670af00a1SHartmut Brandt if (pi->stream) { 119770af00a1SHartmut Brandt ret = recv_stream(pi); 119870af00a1SHartmut Brandt } else { 119970af00a1SHartmut Brandt ret = recv_dgram(pi); 1200f06ca4afSHartmut Brandt } 120170af00a1SHartmut Brandt 120270af00a1SHartmut Brandt if (ret == -1) 120370af00a1SHartmut Brandt return (-1); 1204f06ca4afSHartmut Brandt 1205d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1206d7eb6b47SHartmut Brandt /* 1207d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 1208d7eb6b47SHartmut Brandt */ 1209d7eb6b47SHartmut Brandt if (inet_ntop(pi->peer->sa_family, 121069292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 121169292cedSHartmut Brandt client, sizeof(client)) != NULL) { 1212d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 1213d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 1214d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 1215d7eb6b47SHartmut Brandt eval_client(&req)); 1216d7eb6b47SHartmut Brandt return (-1); 1217d7eb6b47SHartmut Brandt } 1218d7eb6b47SHartmut Brandt } else 1219d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 1220d7eb6b47SHartmut Brandt #endif 1221d7eb6b47SHartmut Brandt 1222f06ca4afSHartmut Brandt /* 1223f06ca4afSHartmut Brandt * Handle input 1224f06ca4afSHartmut Brandt */ 122570af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 122670af00a1SHartmut Brandt &pi->consumed); 122770af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 122870af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 122970af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 123070af00a1SHartmut Brandt if (pi->stream) { 123170af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 123270af00a1SHartmut Brandt snmpd_stats.silentDrops++; 123370af00a1SHartmut Brandt return (-1); 123470af00a1SHartmut Brandt } 123570af00a1SHartmut Brandt return (0); 123670af00a1SHartmut Brandt } 123770af00a1SHartmut Brandt snmpd_stats.silentDrops++; 123870af00a1SHartmut Brandt return (-1); 123970af00a1SHartmut Brandt } 1240f06ca4afSHartmut Brandt 1241f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 1242f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 1243f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 1244f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 124570af00a1SHartmut Brandt /* for streaming transports this is fatal */ 124670af00a1SHartmut Brandt if (pi->stream) 124770af00a1SHartmut Brandt return (-1); 124870af00a1SHartmut Brandt snmp_input_consume(pi); 124970af00a1SHartmut Brandt return (0); 1250f06ca4afSHartmut Brandt } 1251896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 1252896052c1SHartmut Brandt snmp_input_consume(pi); 1253896052c1SHartmut Brandt return (0); 1254896052c1SHartmut Brandt } 1255f06ca4afSHartmut Brandt 1256f06ca4afSHartmut Brandt /* 1257f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 1258f06ca4afSHartmut Brandt * the hand it over to the module. 1259f06ca4afSHartmut Brandt */ 1260*135f7de5SShteryana Shopova if (comm != NULL && comm->owner != NULL && 1261*135f7de5SShteryana Shopova comm->owner->config->proxy != NULL) { 126270af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1263896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 1264896052c1SHartmut Brandt !pi->cred || pi->priv); 1265f06ca4afSHartmut Brandt 1266f06ca4afSHartmut Brandt switch (perr) { 1267f06ca4afSHartmut Brandt 1268f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 126970af00a1SHartmut Brandt snmp_input_consume(pi); 127070af00a1SHartmut Brandt return (0); 1271f06ca4afSHartmut Brandt 1272f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 1273f06ca4afSHartmut Brandt break; 1274f06ca4afSHartmut Brandt 1275f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 127670af00a1SHartmut Brandt snmp_input_consume(pi); 1277f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1278f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 127970af00a1SHartmut Brandt return (0); 1280f06ca4afSHartmut Brandt 1281f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 128270af00a1SHartmut Brandt snmp_input_consume(pi); 1283f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1284f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 1285f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1286f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1287896052c1SHartmut Brandt (struct snmp_value *)NULL); 128870af00a1SHartmut Brandt return (0); 1289f06ca4afSHartmut Brandt 1290f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 129170af00a1SHartmut Brandt snmp_input_consume(pi); 1292f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1293f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1294f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1295f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1296896052c1SHartmut Brandt (struct snmp_value *)NULL); 129770af00a1SHartmut Brandt return (0); 1298f06ca4afSHartmut Brandt } 1299f06ca4afSHartmut Brandt } 1300f06ca4afSHartmut Brandt 1301f06ca4afSHartmut Brandt /* 1302f06ca4afSHartmut Brandt * Check type 1303f06ca4afSHartmut Brandt */ 1304f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1305f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1306f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1307f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1308f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1309f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 131070af00a1SHartmut Brandt snmp_input_consume(pi); 131170af00a1SHartmut Brandt return (0); 1312f06ca4afSHartmut Brandt } 1313f06ca4afSHartmut Brandt 1314f06ca4afSHartmut Brandt /* 1315f06ca4afSHartmut Brandt * Check community 1316f06ca4afSHartmut Brandt */ 1317*135f7de5SShteryana Shopova if (pdu.version < SNMP_V3 && 1318*135f7de5SShteryana Shopova ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 131970af00a1SHartmut Brandt (community != COMM_WRITE && 1320*135f7de5SShteryana Shopova (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1321f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1322f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 132370af00a1SHartmut Brandt snmp_input_consume(pi); 1324f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1325896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1326896052c1SHartmut Brandt (struct snmp_value *)NULL); 132770af00a1SHartmut Brandt return (0); 1328f06ca4afSHartmut Brandt } 1329f06ca4afSHartmut Brandt 1330f06ca4afSHartmut Brandt /* 1331f06ca4afSHartmut Brandt * Execute it. 1332f06ca4afSHartmut Brandt */ 1333f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1334f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1335f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 133670af00a1SHartmut Brandt snmp_input_consume(pi); 133770af00a1SHartmut Brandt return (0); 1338f06ca4afSHartmut Brandt } 133970af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 134070af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1341f06ca4afSHartmut Brandt 1342f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 134370af00a1SHartmut Brandt slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 134470af00a1SHartmut Brandt if (slen == -1) 134570af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 134670af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 134770af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 134870af00a1SHartmut Brandt sndlen, (size_t)slen); 134970af00a1SHartmut Brandt } 135070af00a1SHartmut Brandt snmp_pdu_free(&pdu); 135170af00a1SHartmut Brandt free(sndbuf); 135270af00a1SHartmut Brandt snmp_input_consume(pi); 135370af00a1SHartmut Brandt 135470af00a1SHartmut Brandt return (0); 135570af00a1SHartmut Brandt } 135670af00a1SHartmut Brandt 135770af00a1SHartmut Brandt /* 135870af00a1SHartmut Brandt * Send a PDU to a given port 135970af00a1SHartmut Brandt */ 136070af00a1SHartmut Brandt void 136170af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 136270af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 136370af00a1SHartmut Brandt { 136470af00a1SHartmut Brandt struct transport *trans = targ; 136570af00a1SHartmut Brandt struct tport *tp; 136670af00a1SHartmut Brandt u_char *sndbuf; 136770af00a1SHartmut Brandt size_t sndlen; 136870af00a1SHartmut Brandt ssize_t len; 136970af00a1SHartmut Brandt 137070af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 137170af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 137270af00a1SHartmut Brandt break; 137370af00a1SHartmut Brandt if (tp == 0) 137470af00a1SHartmut Brandt return; 137570af00a1SHartmut Brandt 137670af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 137770af00a1SHartmut Brandt return; 137870af00a1SHartmut Brandt 137970af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 138070af00a1SHartmut Brandt 138170af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 138270af00a1SHartmut Brandt 138370af00a1SHartmut Brandt if (len == -1) 1384f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1385f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1386f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1387f06ca4afSHartmut Brandt sndlen, (size_t)len); 138870af00a1SHartmut Brandt 1389f06ca4afSHartmut Brandt free(sndbuf); 1390f06ca4afSHartmut Brandt } 1391f06ca4afSHartmut Brandt 1392f06ca4afSHartmut Brandt 1393f06ca4afSHartmut Brandt /* 139470af00a1SHartmut Brandt * Close an input source 1395f06ca4afSHartmut Brandt */ 1396f06ca4afSHartmut Brandt void 139770af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1398f06ca4afSHartmut Brandt { 139970af00a1SHartmut Brandt if (pi->id != NULL) 140070af00a1SHartmut Brandt fd_deselect(pi->id); 140170af00a1SHartmut Brandt if (pi->fd >= 0) 140270af00a1SHartmut Brandt (void)close(pi->fd); 140370af00a1SHartmut Brandt if (pi->buf != NULL) 140470af00a1SHartmut Brandt free(pi->buf); 1405f06ca4afSHartmut Brandt } 1406f06ca4afSHartmut Brandt 1407f06ca4afSHartmut Brandt /* 1408f06ca4afSHartmut Brandt * Dump internal state. 1409f06ca4afSHartmut Brandt */ 141070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 141170af00a1SHartmut Brandt static void 141270af00a1SHartmut Brandt info_func(void) 141370af00a1SHartmut Brandt #else 1414f06ca4afSHartmut Brandt static void 1415f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 141670af00a1SHartmut Brandt #endif 1417f06ca4afSHartmut Brandt { 1418f06ca4afSHartmut Brandt struct lmodule *m; 1419f06ca4afSHartmut Brandt u_int i; 1420f06ca4afSHartmut Brandt char buf[10000]; 1421f06ca4afSHartmut Brandt 1422f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1423f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1424f06ca4afSHartmut Brandt switch (tree[i].type) { 1425f06ca4afSHartmut Brandt 1426f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1427f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1428f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1429f06ca4afSHartmut Brandt break; 1430f06ca4afSHartmut Brandt 1431f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1432f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1433f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1434f06ca4afSHartmut Brandt break; 1435f06ca4afSHartmut Brandt } 1436f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1437f06ca4afSHartmut Brandt } 1438f06ca4afSHartmut Brandt 1439f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1440f06ca4afSHartmut Brandt if (m->config->dump) 1441f06ca4afSHartmut Brandt (*m->config->dump)(); 1442f06ca4afSHartmut Brandt } 1443f06ca4afSHartmut Brandt 1444f06ca4afSHartmut Brandt /* 1445f06ca4afSHartmut Brandt * Re-read configuration 1446f06ca4afSHartmut Brandt */ 144770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 144870af00a1SHartmut Brandt static void 144970af00a1SHartmut Brandt config_func(void) 145070af00a1SHartmut Brandt #else 1451f06ca4afSHartmut Brandt static void 1452f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1453f06ca4afSHartmut Brandt const void *tag __unused) 145470af00a1SHartmut Brandt #endif 1455f06ca4afSHartmut Brandt { 1456f06ca4afSHartmut Brandt struct lmodule *m; 1457f06ca4afSHartmut Brandt 1458f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1459f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1460f06ca4afSHartmut Brandt return; 1461f06ca4afSHartmut Brandt } 1462f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1463f06ca4afSHartmut Brandt if (m->config->config) 1464f06ca4afSHartmut Brandt (*m->config->config)(); 1465f06ca4afSHartmut Brandt } 1466f06ca4afSHartmut Brandt 1467f06ca4afSHartmut Brandt /* 1468f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1469f06ca4afSHartmut Brandt */ 1470f06ca4afSHartmut Brandt static void 1471f06ca4afSHartmut Brandt onusr1(int s __unused) 1472f06ca4afSHartmut Brandt { 147370af00a1SHartmut Brandt 1474f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1475f06ca4afSHartmut Brandt } 1476f06ca4afSHartmut Brandt static void 1477f06ca4afSHartmut Brandt onhup(int s __unused) 1478f06ca4afSHartmut Brandt { 147970af00a1SHartmut Brandt 1480f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1481f06ca4afSHartmut Brandt } 1482f06ca4afSHartmut Brandt 1483f06ca4afSHartmut Brandt static void 1484f06ca4afSHartmut Brandt onterm(int s __unused) 1485f06ca4afSHartmut Brandt { 1486f06ca4afSHartmut Brandt 148770af00a1SHartmut Brandt /* allow clean-up */ 1488f06ca4afSHartmut Brandt exit(0); 1489f06ca4afSHartmut Brandt } 1490f06ca4afSHartmut Brandt 1491f06ca4afSHartmut Brandt static void 1492f06ca4afSHartmut Brandt init_sigs(void) 1493f06ca4afSHartmut Brandt { 1494f06ca4afSHartmut Brandt struct sigaction sa; 1495f06ca4afSHartmut Brandt 1496f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1497f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1498f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1499f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1500f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1501f06ca4afSHartmut Brandt exit(1); 1502f06ca4afSHartmut Brandt } 1503f06ca4afSHartmut Brandt 1504f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1505f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1506f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1507f06ca4afSHartmut Brandt exit(1); 1508f06ca4afSHartmut Brandt } 1509f06ca4afSHartmut Brandt 1510f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1511f06ca4afSHartmut Brandt sa.sa_flags = 0; 1512f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1513f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1514f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1515f06ca4afSHartmut Brandt exit(1); 1516f06ca4afSHartmut Brandt } 1517f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1518f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1519f06ca4afSHartmut Brandt exit(1); 1520f06ca4afSHartmut Brandt } 1521f06ca4afSHartmut Brandt } 1522f06ca4afSHartmut Brandt 1523f06ca4afSHartmut Brandt static void 1524f06ca4afSHartmut Brandt block_sigs(void) 1525f06ca4afSHartmut Brandt { 1526f06ca4afSHartmut Brandt sigset_t set; 1527f06ca4afSHartmut Brandt 1528f06ca4afSHartmut Brandt sigfillset(&set); 1529f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1530f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1531f06ca4afSHartmut Brandt exit(1); 1532f06ca4afSHartmut Brandt } 1533f06ca4afSHartmut Brandt } 1534f06ca4afSHartmut Brandt static void 1535f06ca4afSHartmut Brandt unblock_sigs(void) 1536f06ca4afSHartmut Brandt { 1537f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1538f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1539f06ca4afSHartmut Brandt exit(1); 1540f06ca4afSHartmut Brandt } 1541f06ca4afSHartmut Brandt } 1542f06ca4afSHartmut Brandt 1543f06ca4afSHartmut Brandt /* 1544f06ca4afSHartmut Brandt * Shut down 1545f06ca4afSHartmut Brandt */ 1546f06ca4afSHartmut Brandt static void 1547f06ca4afSHartmut Brandt term(void) 1548f06ca4afSHartmut Brandt { 1549f06ca4afSHartmut Brandt (void)unlink(pid_file); 1550f06ca4afSHartmut Brandt } 1551f06ca4afSHartmut Brandt 155270af00a1SHartmut Brandt static void 155370af00a1SHartmut Brandt trans_stop(void) 155470af00a1SHartmut Brandt { 155570af00a1SHartmut Brandt struct transport *t; 155670af00a1SHartmut Brandt 155770af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 155870af00a1SHartmut Brandt (void)t->vtab->stop(1); 155970af00a1SHartmut Brandt } 156070af00a1SHartmut Brandt 1561f06ca4afSHartmut Brandt /* 1562f06ca4afSHartmut Brandt * Define a macro from the command line 1563f06ca4afSHartmut Brandt */ 1564f06ca4afSHartmut Brandt static void 1565f06ca4afSHartmut Brandt do_macro(char *arg) 1566f06ca4afSHartmut Brandt { 1567f06ca4afSHartmut Brandt char *eq; 1568f06ca4afSHartmut Brandt int err; 1569f06ca4afSHartmut Brandt 1570f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1571f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1572f06ca4afSHartmut Brandt else { 1573f06ca4afSHartmut Brandt *eq++ = '\0'; 1574f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1575f06ca4afSHartmut Brandt } 1576f06ca4afSHartmut Brandt if (err == -1) { 1577f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1578f06ca4afSHartmut Brandt exit(1); 1579f06ca4afSHartmut Brandt } 1580f06ca4afSHartmut Brandt } 1581f06ca4afSHartmut Brandt 1582f06ca4afSHartmut Brandt /* 1583f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1584f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1585f06ca4afSHartmut Brandt */ 1586f06ca4afSHartmut Brandt static int 1587f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1588f06ca4afSHartmut Brandt { 1589f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1590f06ca4afSHartmut Brandt u_int i; 1591f06ca4afSHartmut Brandt char *ptr; 1592f06ca4afSHartmut Brandt 1593f06ca4afSHartmut Brandt *optp = NULL; 1594f06ca4afSHartmut Brandt 1595f06ca4afSHartmut Brandt /* skip leading junk */ 1596f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1597f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1598f06ca4afSHartmut Brandt break; 1599f06ca4afSHartmut Brandt if (*ptr == '\0') { 1600f06ca4afSHartmut Brandt *arg = ptr; 1601f06ca4afSHartmut Brandt return (-1); 1602f06ca4afSHartmut Brandt } 1603f06ca4afSHartmut Brandt *optp = ptr; 1604f06ca4afSHartmut Brandt 1605f06ca4afSHartmut Brandt /* find the end of the option */ 1606f06ca4afSHartmut Brandt while (*++ptr != '\0') 1607f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1608f06ca4afSHartmut Brandt break; 1609f06ca4afSHartmut Brandt 1610f06ca4afSHartmut Brandt if (*ptr != '\0') { 1611f06ca4afSHartmut Brandt if (*ptr == '=') { 1612f06ca4afSHartmut Brandt *ptr++ = '\0'; 1613f06ca4afSHartmut Brandt *valp = ptr; 1614f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1615f06ca4afSHartmut Brandt ptr++; 1616f06ca4afSHartmut Brandt if (*ptr != '\0') 1617f06ca4afSHartmut Brandt *ptr++ = '\0'; 1618f06ca4afSHartmut Brandt } else 1619f06ca4afSHartmut Brandt *ptr++ = '\0'; 1620f06ca4afSHartmut Brandt } 1621f06ca4afSHartmut Brandt 1622f06ca4afSHartmut Brandt *arg = ptr; 1623f06ca4afSHartmut Brandt 1624f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 162570af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1626f06ca4afSHartmut Brandt return (i); 1627f06ca4afSHartmut Brandt return (-1); 1628f06ca4afSHartmut Brandt } 1629f06ca4afSHartmut Brandt 1630f06ca4afSHartmut Brandt int 1631f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1632f06ca4afSHartmut Brandt { 1633f06ca4afSHartmut Brandt int opt; 1634f06ca4afSHartmut Brandt FILE *fp; 1635f06ca4afSHartmut Brandt int background = 1; 163670af00a1SHartmut Brandt struct tport *p; 1637f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1638f06ca4afSHartmut Brandt struct lmodule *m; 1639*135f7de5SShteryana Shopova char *value = NULL, *option; /* XXX */ 164070af00a1SHartmut Brandt struct transport *t; 1641f06ca4afSHartmut Brandt 1642f06ca4afSHartmut Brandt #define DBG_DUMP 0 1643f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1644f06ca4afSHartmut Brandt #define DBG_TRACE 2 1645f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1646f06ca4afSHartmut Brandt "dump", 1647f06ca4afSHartmut Brandt "events", 1648f06ca4afSHartmut Brandt "trace", 1649f06ca4afSHartmut Brandt NULL 1650f06ca4afSHartmut Brandt }; 1651f06ca4afSHartmut Brandt 1652f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1653f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1654f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1655f06ca4afSHartmut Brandt asn_error = asn_error_func; 1656f06ca4afSHartmut Brandt 1657*135f7de5SShteryana Shopova while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1658f06ca4afSHartmut Brandt switch (opt) { 1659f06ca4afSHartmut Brandt 1660f06ca4afSHartmut Brandt case 'c': 1661f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1662f06ca4afSHartmut Brandt break; 1663f06ca4afSHartmut Brandt 1664f06ca4afSHartmut Brandt case 'd': 1665f06ca4afSHartmut Brandt background = 0; 1666f06ca4afSHartmut Brandt break; 1667f06ca4afSHartmut Brandt 1668f06ca4afSHartmut Brandt case 'D': 1669f06ca4afSHartmut Brandt while (*optarg) { 1670f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1671f06ca4afSHartmut Brandt &value, &option)) { 1672f06ca4afSHartmut Brandt 1673f06ca4afSHartmut Brandt case DBG_DUMP: 1674f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1675f06ca4afSHartmut Brandt break; 1676f06ca4afSHartmut Brandt 1677f06ca4afSHartmut Brandt case DBG_EVENTS: 1678f06ca4afSHartmut Brandt debug.evdebug++; 1679f06ca4afSHartmut Brandt break; 1680f06ca4afSHartmut Brandt 1681f06ca4afSHartmut Brandt case DBG_TRACE: 1682f06ca4afSHartmut Brandt if (value == NULL) 1683f06ca4afSHartmut Brandt syslog(LOG_ERR, 1684f06ca4afSHartmut Brandt "no value for 'trace'"); 168551054003SHartmut Brandt else 1686748b5b1eSHartmut Brandt snmp_trace = strtoul(value, 1687748b5b1eSHartmut Brandt NULL, 0); 1688f06ca4afSHartmut Brandt break; 1689f06ca4afSHartmut Brandt 1690f06ca4afSHartmut Brandt case -1: 1691f06ca4afSHartmut Brandt if (suboptarg) 1692f06ca4afSHartmut Brandt syslog(LOG_ERR, 1693f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1694f06ca4afSHartmut Brandt option); 1695f06ca4afSHartmut Brandt else 1696f06ca4afSHartmut Brandt syslog(LOG_ERR, 1697f06ca4afSHartmut Brandt "missing debug flag"); 1698f06ca4afSHartmut Brandt break; 1699f06ca4afSHartmut Brandt } 1700f06ca4afSHartmut Brandt } 1701f06ca4afSHartmut Brandt break; 1702f06ca4afSHartmut Brandt 1703*135f7de5SShteryana Shopova case 'e': 1704*135f7de5SShteryana Shopova strlcpy(engine_file, optarg, sizeof(engine_file)); 1705*135f7de5SShteryana Shopova break; 1706f06ca4afSHartmut Brandt case 'h': 1707f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1708f06ca4afSHartmut Brandt exit(0); 1709f06ca4afSHartmut Brandt 1710f06ca4afSHartmut Brandt case 'I': 1711f06ca4afSHartmut Brandt syspath = optarg; 1712f06ca4afSHartmut Brandt break; 1713f06ca4afSHartmut Brandt 1714f06ca4afSHartmut Brandt case 'l': 1715f06ca4afSHartmut Brandt prefix = optarg; 1716f06ca4afSHartmut Brandt break; 1717f06ca4afSHartmut Brandt 1718f06ca4afSHartmut Brandt case 'm': 1719f06ca4afSHartmut Brandt do_macro(optarg); 1720f06ca4afSHartmut Brandt break; 1721f06ca4afSHartmut Brandt 1722f06ca4afSHartmut Brandt case 'p': 1723f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1724f06ca4afSHartmut Brandt break; 1725f06ca4afSHartmut Brandt } 1726f06ca4afSHartmut Brandt 1727f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1728f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1729f06ca4afSHartmut Brandt 1730f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1731f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1732f06ca4afSHartmut Brandt exit(1); 1733f06ca4afSHartmut Brandt } 1734f06ca4afSHartmut Brandt 1735f06ca4afSHartmut Brandt argc -= optind; 1736f06ca4afSHartmut Brandt argv += optind; 1737f06ca4afSHartmut Brandt 1738f06ca4afSHartmut Brandt progargs = argv; 1739f06ca4afSHartmut Brandt nprogargs = argc; 1740f06ca4afSHartmut Brandt 1741f06ca4afSHartmut Brandt srandomdev(); 1742f06ca4afSHartmut Brandt 1743f06ca4afSHartmut Brandt snmp_serial_no = random(); 1744f06ca4afSHartmut Brandt 1745d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1746d7eb6b47SHartmut Brandt /* 1747d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1748d7eb6b47SHartmut Brandt */ 1749d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1750d7eb6b47SHartmut Brandt sock_methods(&req); 1751d7eb6b47SHartmut Brandt #endif 1752d7eb6b47SHartmut Brandt 1753f06ca4afSHartmut Brandt /* 1754f06ca4afSHartmut Brandt * Initialize the tree. 1755f06ca4afSHartmut Brandt */ 1756f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1757f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1758f06ca4afSHartmut Brandt exit(1); 1759f06ca4afSHartmut Brandt } 1760f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1761f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1762f06ca4afSHartmut Brandt 1763f06ca4afSHartmut Brandt /* 1764f06ca4afSHartmut Brandt * Get standard communities 1765f06ca4afSHartmut Brandt */ 1766d4199d75SHartmut Brandt (void)comm_define(1, "SNMP read", NULL, NULL); 1767d4199d75SHartmut Brandt (void)comm_define(2, "SNMP write", NULL, NULL); 1768f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1769f06ca4afSHartmut Brandt 1770f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1771f06ca4afSHartmut Brandt 1772f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1773f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1774f06ca4afSHartmut Brandt 1775f06ca4afSHartmut Brandt init_actvals(); 1776*135f7de5SShteryana Shopova init_snmpd_engine(); 177770af00a1SHartmut Brandt 177870af00a1SHartmut Brandt this_tick = get_ticks(); 177969292cedSHartmut Brandt start_tick = this_tick; 178070af00a1SHartmut Brandt 178170af00a1SHartmut Brandt /* start transports */ 178270af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 178370af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 178470af00a1SHartmut Brandt exit(1); 178570af00a1SHartmut Brandt } 178670af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 178770af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 178870af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 178970af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 179070af00a1SHartmut Brandt 179170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 179270af00a1SHartmut Brandt if (debug.evdebug > 0) 179370af00a1SHartmut Brandt rpoll_trace = 1; 179470af00a1SHartmut Brandt #else 1795f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1796f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1797f06ca4afSHartmut Brandt exit(1); 1798f06ca4afSHartmut Brandt } 1799f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1800f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 180170af00a1SHartmut Brandt #endif 1802f06ca4afSHartmut Brandt 1803*135f7de5SShteryana Shopova if (engine_file[0] == '\0') 1804*135f7de5SShteryana Shopova snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1805*135f7de5SShteryana Shopova 1806896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1807896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1808896052c1SHartmut Brandt exit(1); 1809896052c1SHartmut Brandt } 1810896052c1SHartmut Brandt 181170af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 181270af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 181370af00a1SHartmut Brandt t->vtab->init_port(p); 1814f06ca4afSHartmut Brandt 1815f06ca4afSHartmut Brandt init_sigs(); 1816f06ca4afSHartmut Brandt 1817f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1818f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1819f06ca4afSHartmut Brandt 1820f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1821f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1822f06ca4afSHartmut Brandt fclose(fp); 182370af00a1SHartmut Brandt if (atexit(term) == -1) { 182470af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 182570af00a1SHartmut Brandt (void)remove(pid_file); 182670af00a1SHartmut Brandt exit(0); 1827f06ca4afSHartmut Brandt } 182870af00a1SHartmut Brandt } 1829f06ca4afSHartmut Brandt 1830f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1831f06ca4afSHartmut Brandt NULL) == 0) { 1832f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1833f06ca4afSHartmut Brandt exit(1); 1834f06ca4afSHartmut Brandt } 1835f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1836f06ca4afSHartmut Brandt NULL) == 0) { 1837f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1838f06ca4afSHartmut Brandt exit(1); 1839f06ca4afSHartmut Brandt } 1840f06ca4afSHartmut Brandt 1841896052c1SHartmut Brandt snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1842f06ca4afSHartmut Brandt 1843f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1844f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1845f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1846f06ca4afSHartmut Brandt lm_start(m); 1847f06ca4afSHartmut Brandt } 1848f06ca4afSHartmut Brandt 1849f06ca4afSHartmut Brandt for (;;) { 185070af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1851f06ca4afSHartmut Brandt evEvent event; 185270af00a1SHartmut Brandt #endif 1853f06ca4afSHartmut Brandt struct lmodule *mod; 1854f06ca4afSHartmut Brandt 1855f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1856f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1857f06ca4afSHartmut Brandt (*mod->config->idle)(); 1858f06ca4afSHartmut Brandt 185970af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1860f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1861f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1862f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1863f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1864f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1865f06ca4afSHartmut Brandt exit(1); 1866f06ca4afSHartmut Brandt } 186770af00a1SHartmut Brandt #else 186870af00a1SHartmut Brandt poll_dispatch(1); 186970af00a1SHartmut Brandt #endif 1870f06ca4afSHartmut Brandt 1871f06ca4afSHartmut Brandt if (work != 0) { 1872f06ca4afSHartmut Brandt block_sigs(); 1873f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 187470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 187570af00a1SHartmut Brandt info_func(); 187670af00a1SHartmut Brandt #else 1877f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1878f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1879f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1880f06ca4afSHartmut Brandt exit(1); 1881f06ca4afSHartmut Brandt } 188270af00a1SHartmut Brandt #endif 1883f06ca4afSHartmut Brandt } 1884f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 188570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 188670af00a1SHartmut Brandt config_func(); 188770af00a1SHartmut Brandt #else 1888f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1889f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1890f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1891f06ca4afSHartmut Brandt exit(1); 1892f06ca4afSHartmut Brandt } 189370af00a1SHartmut Brandt #endif 1894f06ca4afSHartmut Brandt } 1895f06ca4afSHartmut Brandt work = 0; 1896f06ca4afSHartmut Brandt unblock_sigs(); 189770af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1898f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1899f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1900f06ca4afSHartmut Brandt exit(1); 1901f06ca4afSHartmut Brandt } 190270af00a1SHartmut Brandt #endif 1903f06ca4afSHartmut Brandt } 1904f06ca4afSHartmut Brandt } 1905f06ca4afSHartmut Brandt 1906f06ca4afSHartmut Brandt return (0); 1907f06ca4afSHartmut Brandt } 1908f06ca4afSHartmut Brandt 190969292cedSHartmut Brandt uint64_t 1910*135f7de5SShteryana Shopova get_ticks(void) 1911f06ca4afSHartmut Brandt { 1912f06ca4afSHartmut Brandt struct timeval tv; 191369292cedSHartmut Brandt uint64_t ret; 1914f06ca4afSHartmut Brandt 1915f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1916f06ca4afSHartmut Brandt abort(); 191769292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1918f06ca4afSHartmut Brandt return (ret); 1919f06ca4afSHartmut Brandt } 192069292cedSHartmut Brandt 1921f06ca4afSHartmut Brandt /* 1922f06ca4afSHartmut Brandt * Timer support 1923f06ca4afSHartmut Brandt */ 1924165c5d31SHartmut Brandt 1925165c5d31SHartmut Brandt /* 1926165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1927165c5d31SHartmut Brandt */ 192870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 192970af00a1SHartmut Brandt static void 193070af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 193170af00a1SHartmut Brandt #else 1932f06ca4afSHartmut Brandt static void 1933f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1934f06ca4afSHartmut Brandt struct timespec inter __unused) 193570af00a1SHartmut Brandt #endif 1936f06ca4afSHartmut Brandt { 1937f06ca4afSHartmut Brandt struct timer *tp = uap; 1938f06ca4afSHartmut Brandt 1939f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1940f06ca4afSHartmut Brandt tp->func(tp->udata); 1941f06ca4afSHartmut Brandt free(tp); 1942f06ca4afSHartmut Brandt } 1943f06ca4afSHartmut Brandt 1944f06ca4afSHartmut Brandt /* 1945165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1946165c5d31SHartmut Brandt */ 1947165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1948165c5d31SHartmut Brandt static void 1949165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1950165c5d31SHartmut Brandt #else 1951165c5d31SHartmut Brandt static void 1952165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1953165c5d31SHartmut Brandt struct timespec inter __unused) 1954165c5d31SHartmut Brandt #endif 1955165c5d31SHartmut Brandt { 1956165c5d31SHartmut Brandt struct timer *tp = uap; 1957165c5d31SHartmut Brandt 1958165c5d31SHartmut Brandt tp->func(tp->udata); 1959165c5d31SHartmut Brandt } 1960165c5d31SHartmut Brandt 1961165c5d31SHartmut Brandt /* 1962165c5d31SHartmut Brandt * Start a one-shot timer 1963f06ca4afSHartmut Brandt */ 1964f06ca4afSHartmut Brandt void * 1965f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1966f06ca4afSHartmut Brandt { 1967f06ca4afSHartmut Brandt struct timer *tp; 1968a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1969f06ca4afSHartmut Brandt struct timespec due; 197070af00a1SHartmut Brandt #endif 1971f06ca4afSHartmut Brandt 1972f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1973f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1974f06ca4afSHartmut Brandt exit(1); 1975f06ca4afSHartmut Brandt } 1976a9bfedb7SHartmut Brandt 1977a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1978f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1979f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 198070af00a1SHartmut Brandt #endif 1981f06ca4afSHartmut Brandt 1982f06ca4afSHartmut Brandt tp->udata = udata; 1983f06ca4afSHartmut Brandt tp->owner = mod; 1984f06ca4afSHartmut Brandt tp->func = func; 1985f06ca4afSHartmut Brandt 1986f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1987f06ca4afSHartmut Brandt 198870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 1989a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 199070af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 199170af00a1SHartmut Brandt exit(1); 199270af00a1SHartmut Brandt } 199370af00a1SHartmut Brandt #else 1994f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1995f06ca4afSHartmut Brandt == -1) { 1996f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1997f06ca4afSHartmut Brandt exit(1); 1998f06ca4afSHartmut Brandt } 199970af00a1SHartmut Brandt #endif 2000f06ca4afSHartmut Brandt return (tp); 2001f06ca4afSHartmut Brandt } 2002f06ca4afSHartmut Brandt 2003165c5d31SHartmut Brandt /* 2004165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 2005165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 2006165c5d31SHartmut Brandt * repeat number of ticks. 2007165c5d31SHartmut Brandt */ 2008165c5d31SHartmut Brandt void * 2009165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 2010165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 2011165c5d31SHartmut Brandt { 2012165c5d31SHartmut Brandt struct timer *tp; 2013165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 2014165c5d31SHartmut Brandt struct timespec due; 2015165c5d31SHartmut Brandt struct timespec inter; 2016165c5d31SHartmut Brandt #endif 2017165c5d31SHartmut Brandt 2018165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 2019165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 2020165c5d31SHartmut Brandt exit(1); 2021165c5d31SHartmut Brandt } 2022165c5d31SHartmut Brandt 2023165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 2024165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 2025165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 2026165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 2027165c5d31SHartmut Brandt #endif 2028165c5d31SHartmut Brandt 2029165c5d31SHartmut Brandt tp->udata = udata; 2030165c5d31SHartmut Brandt tp->owner = mod; 2031165c5d31SHartmut Brandt tp->func = func; 2032165c5d31SHartmut Brandt 2033165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 2034165c5d31SHartmut Brandt 2035165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 2036165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 2037165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2038165c5d31SHartmut Brandt exit(1); 2039165c5d31SHartmut Brandt } 2040165c5d31SHartmut Brandt #else 2041165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 2042165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2043165c5d31SHartmut Brandt exit(1); 2044165c5d31SHartmut Brandt } 2045165c5d31SHartmut Brandt #endif 2046165c5d31SHartmut Brandt return (tp); 2047165c5d31SHartmut Brandt } 2048165c5d31SHartmut Brandt 2049165c5d31SHartmut Brandt /* 2050165c5d31SHartmut Brandt * Stop a timer. 2051165c5d31SHartmut Brandt */ 2052f06ca4afSHartmut Brandt void 2053f06ca4afSHartmut Brandt timer_stop(void *p) 2054f06ca4afSHartmut Brandt { 2055f06ca4afSHartmut Brandt struct timer *tp = p; 2056f06ca4afSHartmut Brandt 2057f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 205870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 205970af00a1SHartmut Brandt poll_stop_timer(tp->id); 206070af00a1SHartmut Brandt #else 2061f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 2062f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 2063f06ca4afSHartmut Brandt exit(1); 2064f06ca4afSHartmut Brandt } 206570af00a1SHartmut Brandt #endif 2066f06ca4afSHartmut Brandt free(p); 2067f06ca4afSHartmut Brandt } 2068f06ca4afSHartmut Brandt 2069f06ca4afSHartmut Brandt static void 2070f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 2071f06ca4afSHartmut Brandt { 2072f06ca4afSHartmut Brandt struct timer *t, *t1; 2073f06ca4afSHartmut Brandt 2074f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 2075f06ca4afSHartmut Brandt while (t != NULL) { 2076f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 2077f06ca4afSHartmut Brandt if (t->owner == mod) 2078f06ca4afSHartmut Brandt timer_stop(t); 2079f06ca4afSHartmut Brandt t = t1; 2080f06ca4afSHartmut Brandt } 2081f06ca4afSHartmut Brandt } 2082f06ca4afSHartmut Brandt 2083f06ca4afSHartmut Brandt static void 2084f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 2085f06ca4afSHartmut Brandt { 2086f06ca4afSHartmut Brandt va_list ap; 2087f06ca4afSHartmut Brandt static char *pend = NULL; 2088f06ca4afSHartmut Brandt char *ret, *new; 2089f06ca4afSHartmut Brandt 2090f06ca4afSHartmut Brandt va_start(ap, fmt); 2091f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 2092f06ca4afSHartmut Brandt va_end(ap); 2093f06ca4afSHartmut Brandt 2094f06ca4afSHartmut Brandt if (ret == NULL) 2095f06ca4afSHartmut Brandt return; 2096f06ca4afSHartmut Brandt if (pend != NULL) { 2097f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 2098f06ca4afSHartmut Brandt == NULL) { 2099f06ca4afSHartmut Brandt free(ret); 2100f06ca4afSHartmut Brandt return; 2101f06ca4afSHartmut Brandt } 2102f06ca4afSHartmut Brandt pend = new; 2103f06ca4afSHartmut Brandt strcat(pend, ret); 2104f06ca4afSHartmut Brandt free(ret); 2105f06ca4afSHartmut Brandt } else 2106f06ca4afSHartmut Brandt pend = ret; 2107f06ca4afSHartmut Brandt 2108f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 2109f06ca4afSHartmut Brandt *ret = '\0'; 2110f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 2111f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 2112f06ca4afSHartmut Brandt free(pend); 2113f06ca4afSHartmut Brandt pend = NULL; 2114f06ca4afSHartmut Brandt break; 2115f06ca4afSHartmut Brandt } 2116f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 2117f06ca4afSHartmut Brandt } 2118f06ca4afSHartmut Brandt } 2119f06ca4afSHartmut Brandt 2120f06ca4afSHartmut Brandt static void 2121f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 2122f06ca4afSHartmut Brandt { 2123f06ca4afSHartmut Brandt char errbuf[1000]; 2124f06ca4afSHartmut Brandt va_list ap; 2125f06ca4afSHartmut Brandt 212670af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 212770af00a1SHartmut Brandt return; 212870af00a1SHartmut Brandt 2129f06ca4afSHartmut Brandt va_start(ap, err); 2130f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 213170af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 213270af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2133f06ca4afSHartmut Brandt va_end(ap); 2134f06ca4afSHartmut Brandt 2135f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2136f06ca4afSHartmut Brandt } 2137f06ca4afSHartmut Brandt 2138f06ca4afSHartmut Brandt static void 2139f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 2140f06ca4afSHartmut Brandt { 2141f06ca4afSHartmut Brandt char errbuf[1000]; 2142f06ca4afSHartmut Brandt va_list ap; 2143f06ca4afSHartmut Brandt 2144f06ca4afSHartmut Brandt va_start(ap, err); 2145f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2146f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2147f06ca4afSHartmut Brandt err, ap); 2148f06ca4afSHartmut Brandt va_end(ap); 2149f06ca4afSHartmut Brandt 2150f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 2151f06ca4afSHartmut Brandt } 2152f06ca4afSHartmut Brandt 2153f06ca4afSHartmut Brandt static void 2154f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 2155f06ca4afSHartmut Brandt { 2156f06ca4afSHartmut Brandt char errbuf[1000]; 2157f06ca4afSHartmut Brandt va_list ap; 2158f06ca4afSHartmut Brandt u_int i; 2159f06ca4afSHartmut Brandt 216070af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 216170af00a1SHartmut Brandt return; 216270af00a1SHartmut Brandt 2163f06ca4afSHartmut Brandt va_start(ap, err); 2164f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 216570af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 216670af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2167f06ca4afSHartmut Brandt va_end(ap); 2168f06ca4afSHartmut Brandt 2169f06ca4afSHartmut Brandt if (b != NULL) { 217070af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 217170af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 2172f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 2173f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 217470af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 217570af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 2176f06ca4afSHartmut Brandt } 2177f06ca4afSHartmut Brandt 2178f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2179f06ca4afSHartmut Brandt } 2180f06ca4afSHartmut Brandt 2181f06ca4afSHartmut Brandt /* 2182f06ca4afSHartmut Brandt * Create a new community 2183f06ca4afSHartmut Brandt */ 2184f06ca4afSHartmut Brandt u_int 2185f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 2186f06ca4afSHartmut Brandt const char *str) 2187f06ca4afSHartmut Brandt { 2188f06ca4afSHartmut Brandt struct community *c, *p; 2189f06ca4afSHartmut Brandt u_int ncomm; 2190f06ca4afSHartmut Brandt 2191f06ca4afSHartmut Brandt /* generate an identifier */ 2192f06ca4afSHartmut Brandt do { 2193f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 2194f06ca4afSHartmut Brandt next_community_index = 1; 2195f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 2196f06ca4afSHartmut Brandt if (c->value == ncomm) 2197f06ca4afSHartmut Brandt break; 2198f06ca4afSHartmut Brandt } while (c != NULL); 2199f06ca4afSHartmut Brandt 2200f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 2201f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 2202f06ca4afSHartmut Brandt return (0); 2203f06ca4afSHartmut Brandt } 2204f06ca4afSHartmut Brandt c->owner = owner; 2205f06ca4afSHartmut Brandt c->value = ncomm; 2206f06ca4afSHartmut Brandt c->descr = descr; 2207f06ca4afSHartmut Brandt c->string = NULL; 2208f06ca4afSHartmut Brandt c->private = priv; 2209f06ca4afSHartmut Brandt 2210f06ca4afSHartmut Brandt if (str != NULL) { 2211f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 2212f06ca4afSHartmut Brandt free(c); 2213f06ca4afSHartmut Brandt return (0); 2214f06ca4afSHartmut Brandt } 2215f06ca4afSHartmut Brandt strcpy(c->string, str); 2216f06ca4afSHartmut Brandt } 2217f06ca4afSHartmut Brandt 2218f06ca4afSHartmut Brandt /* make index */ 2219f06ca4afSHartmut Brandt if (c->owner == NULL) { 2220f06ca4afSHartmut Brandt c->index.len = 1; 2221f06ca4afSHartmut Brandt c->index.subs[0] = 0; 2222f06ca4afSHartmut Brandt } else { 2223f06ca4afSHartmut Brandt c->index = c->owner->index; 2224f06ca4afSHartmut Brandt } 2225f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 2226f06ca4afSHartmut Brandt 2227f06ca4afSHartmut Brandt /* 2228f06ca4afSHartmut Brandt * Insert ordered 2229f06ca4afSHartmut Brandt */ 2230f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 2231f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 2232f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 2233f06ca4afSHartmut Brandt break; 2234f06ca4afSHartmut Brandt } 2235f06ca4afSHartmut Brandt } 2236f06ca4afSHartmut Brandt if (p == NULL) 2237f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 2238f06ca4afSHartmut Brandt return (c->value); 2239f06ca4afSHartmut Brandt } 2240f06ca4afSHartmut Brandt 2241f06ca4afSHartmut Brandt const char * 2242f06ca4afSHartmut Brandt comm_string(u_int ncomm) 2243f06ca4afSHartmut Brandt { 2244f06ca4afSHartmut Brandt struct community *p; 2245f06ca4afSHartmut Brandt 2246f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 2247f06ca4afSHartmut Brandt if (p->value == ncomm) 2248f06ca4afSHartmut Brandt return (p->string); 2249f06ca4afSHartmut Brandt return (NULL); 2250f06ca4afSHartmut Brandt } 2251f06ca4afSHartmut Brandt 2252f06ca4afSHartmut Brandt /* 2253f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2254f06ca4afSHartmut Brandt */ 2255f06ca4afSHartmut Brandt static void 2256f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 2257f06ca4afSHartmut Brandt { 2258f06ca4afSHartmut Brandt struct community *p, *p1; 2259f06ca4afSHartmut Brandt 2260f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 2261f06ca4afSHartmut Brandt while (p != NULL) { 2262f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2263f06ca4afSHartmut Brandt if (p->owner == mod) { 2264f06ca4afSHartmut Brandt free(p->string); 2265f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 2266f06ca4afSHartmut Brandt free(p); 2267f06ca4afSHartmut Brandt } 2268f06ca4afSHartmut Brandt p = p1; 2269f06ca4afSHartmut Brandt } 2270f06ca4afSHartmut Brandt } 2271f06ca4afSHartmut Brandt 2272f06ca4afSHartmut Brandt /* 2273f06ca4afSHartmut Brandt * Request ID handling. 2274f06ca4afSHartmut Brandt * 2275f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 2276f06ca4afSHartmut Brandt */ 2277f06ca4afSHartmut Brandt u_int 2278f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 2279f06ca4afSHartmut Brandt { 2280f06ca4afSHartmut Brandt u_int type; 2281f06ca4afSHartmut Brandt struct idrange *r, *r1; 2282f06ca4afSHartmut Brandt 2283f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 2284f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2285f06ca4afSHartmut Brandt return (0); 2286f06ca4afSHartmut Brandt } 2287f06ca4afSHartmut Brandt /* allocate a type id */ 2288f06ca4afSHartmut Brandt do { 2289f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 2290f06ca4afSHartmut Brandt next_idrange = 1; 2291f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2292f06ca4afSHartmut Brandt if (r->type == type) 2293f06ca4afSHartmut Brandt break; 2294f06ca4afSHartmut Brandt } while(r != NULL); 2295f06ca4afSHartmut Brandt 2296f06ca4afSHartmut Brandt /* find a range */ 2297f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 2298f06ca4afSHartmut Brandt r = NULL; 2299f06ca4afSHartmut Brandt else { 2300f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 2301f06ca4afSHartmut Brandt if (r->base < size) { 2302f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2303f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 2304f06ca4afSHartmut Brandt break; 2305f06ca4afSHartmut Brandt r = r1; 2306f06ca4afSHartmut Brandt } 2307f06ca4afSHartmut Brandt r = r1; 2308f06ca4afSHartmut Brandt } 2309f06ca4afSHartmut Brandt if (r == NULL) { 2310f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2311f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2312f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2313f06ca4afSHartmut Brandt return (0); 2314f06ca4afSHartmut Brandt } 2315f06ca4afSHartmut Brandt } 2316f06ca4afSHartmut Brandt } 2317f06ca4afSHartmut Brandt 2318f06ca4afSHartmut Brandt /* allocate structure */ 2319f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2320f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2321f06ca4afSHartmut Brandt return (0); 2322f06ca4afSHartmut Brandt } 2323f06ca4afSHartmut Brandt 2324f06ca4afSHartmut Brandt r1->type = type; 2325f06ca4afSHartmut Brandt r1->size = size; 2326f06ca4afSHartmut Brandt r1->owner = mod; 2327f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2328f06ca4afSHartmut Brandt r1->base = 0; 2329f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2330f06ca4afSHartmut Brandt } else if (r == NULL) { 2331f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2332f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2333f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2334f06ca4afSHartmut Brandt } else { 2335f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2336f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2337f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2338f06ca4afSHartmut Brandt } 2339f06ca4afSHartmut Brandt r1->next = r1->base; 2340f06ca4afSHartmut Brandt 2341f06ca4afSHartmut Brandt return (type); 2342f06ca4afSHartmut Brandt } 2343f06ca4afSHartmut Brandt 2344f06ca4afSHartmut Brandt int32_t 2345f06ca4afSHartmut Brandt reqid_next(u_int type) 2346f06ca4afSHartmut Brandt { 2347f06ca4afSHartmut Brandt struct idrange *r; 2348f06ca4afSHartmut Brandt int32_t id; 2349f06ca4afSHartmut Brandt 2350f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2351f06ca4afSHartmut Brandt if (r->type == type) 2352f06ca4afSHartmut Brandt break; 2353f06ca4afSHartmut Brandt if (r == NULL) { 2354f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2355f06ca4afSHartmut Brandt abort(); 2356f06ca4afSHartmut Brandt } 2357f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2358f06ca4afSHartmut Brandt r->next = r->base; 2359f06ca4afSHartmut Brandt return (id); 2360f06ca4afSHartmut Brandt } 2361f06ca4afSHartmut Brandt 2362f06ca4afSHartmut Brandt int32_t 2363f06ca4afSHartmut Brandt reqid_base(u_int type) 2364f06ca4afSHartmut Brandt { 2365f06ca4afSHartmut Brandt struct idrange *r; 2366f06ca4afSHartmut Brandt 2367f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2368f06ca4afSHartmut Brandt if (r->type == type) 2369f06ca4afSHartmut Brandt return (r->base); 2370f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2371f06ca4afSHartmut Brandt abort(); 2372f06ca4afSHartmut Brandt } 2373f06ca4afSHartmut Brandt 2374f06ca4afSHartmut Brandt u_int 2375f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2376f06ca4afSHartmut Brandt { 2377f06ca4afSHartmut Brandt struct idrange *r; 2378f06ca4afSHartmut Brandt 2379f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2380f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2381f06ca4afSHartmut Brandt return (r->type); 2382f06ca4afSHartmut Brandt return (0); 2383f06ca4afSHartmut Brandt } 2384f06ca4afSHartmut Brandt 2385f06ca4afSHartmut Brandt int 2386f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2387f06ca4afSHartmut Brandt { 2388f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2389f06ca4afSHartmut Brandt } 2390f06ca4afSHartmut Brandt 2391f06ca4afSHartmut Brandt /* 2392f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2393f06ca4afSHartmut Brandt */ 2394f06ca4afSHartmut Brandt static void 2395f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2396f06ca4afSHartmut Brandt { 2397f06ca4afSHartmut Brandt struct idrange *p, *p1; 2398f06ca4afSHartmut Brandt 2399f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2400f06ca4afSHartmut Brandt while (p != NULL) { 2401f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2402f06ca4afSHartmut Brandt if (p->owner == mod) { 2403f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2404f06ca4afSHartmut Brandt free(p); 2405f06ca4afSHartmut Brandt } 2406f06ca4afSHartmut Brandt p = p1; 2407f06ca4afSHartmut Brandt } 2408f06ca4afSHartmut Brandt } 2409f06ca4afSHartmut Brandt 2410f06ca4afSHartmut Brandt /* 2411f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2412f06ca4afSHartmut Brandt */ 2413f06ca4afSHartmut Brandt static int 2414f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2415f06ca4afSHartmut Brandt { 2416f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2417f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2418f06ca4afSHartmut Brandt 2419f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2420f06ca4afSHartmut Brandt } 2421f06ca4afSHartmut Brandt static int 2422f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2423f06ca4afSHartmut Brandt { 2424f06ca4afSHartmut Brandt struct snmp_node *xtree; 2425f06ca4afSHartmut Brandt u_int i; 2426f06ca4afSHartmut Brandt 2427f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2428f06ca4afSHartmut Brandt if (xtree == NULL) { 24298eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2430f06ca4afSHartmut Brandt return (-1); 2431f06ca4afSHartmut Brandt } 2432f06ca4afSHartmut Brandt tree = xtree; 2433f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2434f06ca4afSHartmut Brandt 2435f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 24368eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2437f06ca4afSHartmut Brandt 2438f06ca4afSHartmut Brandt tree_size += nsize; 2439f06ca4afSHartmut Brandt 2440f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2441f06ca4afSHartmut Brandt 2442f06ca4afSHartmut Brandt return (0); 2443f06ca4afSHartmut Brandt } 2444f06ca4afSHartmut Brandt 2445f06ca4afSHartmut Brandt /* 2446f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2447f06ca4afSHartmut Brandt */ 2448f06ca4afSHartmut Brandt static void 2449f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2450f06ca4afSHartmut Brandt { 2451f06ca4afSHartmut Brandt u_int s, d; 2452f06ca4afSHartmut Brandt 2453f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 24548eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2455f06ca4afSHartmut Brandt if (s != d) 2456f06ca4afSHartmut Brandt tree[d] = tree[s]; 2457f06ca4afSHartmut Brandt d++; 2458f06ca4afSHartmut Brandt } 2459f06ca4afSHartmut Brandt tree_size = d; 2460f06ca4afSHartmut Brandt } 2461f06ca4afSHartmut Brandt 2462f06ca4afSHartmut Brandt /* 2463f06ca4afSHartmut Brandt * Loadable modules 2464f06ca4afSHartmut Brandt */ 2465f06ca4afSHartmut Brandt struct lmodule * 2466f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2467f06ca4afSHartmut Brandt { 2468f06ca4afSHartmut Brandt struct lmodule *m; 2469f06ca4afSHartmut Brandt int err; 2470f06ca4afSHartmut Brandt int i; 2471f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2472f06ca4afSHartmut Brandt int ac; 2473f06ca4afSHartmut Brandt u_int u; 2474f06ca4afSHartmut Brandt 2475f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2476f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2477f06ca4afSHartmut Brandt return (NULL); 2478f06ca4afSHartmut Brandt } 2479f06ca4afSHartmut Brandt m->handle = NULL; 2480f06ca4afSHartmut Brandt m->flags = 0; 2481f06ca4afSHartmut Brandt strcpy(m->section, section); 2482f06ca4afSHartmut Brandt 2483f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2484f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2485f06ca4afSHartmut Brandt goto err; 2486f06ca4afSHartmut Brandt } 2487f06ca4afSHartmut Brandt strcpy(m->path, path); 2488f06ca4afSHartmut Brandt 2489f06ca4afSHartmut Brandt /* 2490f06ca4afSHartmut Brandt * Make index 2491f06ca4afSHartmut Brandt */ 2492f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2493f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2494f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2495f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2496f06ca4afSHartmut Brandt 2497f06ca4afSHartmut Brandt /* 2498f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2499f06ca4afSHartmut Brandt */ 2500f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2501f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2502f06ca4afSHartmut Brandt goto err; 2503f06ca4afSHartmut Brandt } 2504f06ca4afSHartmut Brandt 2505f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2506f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2507f06ca4afSHartmut Brandt goto err; 2508f06ca4afSHartmut Brandt } 2509f06ca4afSHartmut Brandt 2510f06ca4afSHartmut Brandt /* 2511f06ca4afSHartmut Brandt * Insert it into the right place 2512f06ca4afSHartmut Brandt */ 2513f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2514f06ca4afSHartmut Brandt 2515f06ca4afSHartmut Brandt /* preserve order */ 2516f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2517f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2518f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2519f06ca4afSHartmut Brandt } 2520f06ca4afSHartmut Brandt 2521f06ca4afSHartmut Brandt /* 2522f06ca4afSHartmut Brandt * make the argument vector. 2523f06ca4afSHartmut Brandt */ 2524f06ca4afSHartmut Brandt ac = 0; 2525f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2526f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2527f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2528f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2529f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2530f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2531f06ca4afSHartmut Brandt "module '%s", section); 2532f06ca4afSHartmut Brandt break; 2533f06ca4afSHartmut Brandt } 2534f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2535f06ca4afSHartmut Brandt } 2536f06ca4afSHartmut Brandt } 2537f06ca4afSHartmut Brandt av[ac] = NULL; 2538f06ca4afSHartmut Brandt 2539f06ca4afSHartmut Brandt /* 2540165c5d31SHartmut Brandt * Run the initialization function 2541f06ca4afSHartmut Brandt */ 2542f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2543f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2544f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2545f06ca4afSHartmut Brandt goto err; 2546f06ca4afSHartmut Brandt } 2547f06ca4afSHartmut Brandt 2548f06ca4afSHartmut Brandt return (m); 2549f06ca4afSHartmut Brandt 2550f06ca4afSHartmut Brandt err: 2551691f8568SShteryana Shopova if ((m->flags & LM_ONSTARTLIST) != 0) 2552691f8568SShteryana Shopova TAILQ_REMOVE(&modules_start, m, start); 2553f06ca4afSHartmut Brandt if (m->handle) 2554f06ca4afSHartmut Brandt dlclose(m->handle); 2555f06ca4afSHartmut Brandt free(m->path); 2556f06ca4afSHartmut Brandt free(m); 2557f06ca4afSHartmut Brandt return (NULL); 2558f06ca4afSHartmut Brandt } 2559f06ca4afSHartmut Brandt 2560f06ca4afSHartmut Brandt /* 2561f06ca4afSHartmut Brandt * Start a module 2562f06ca4afSHartmut Brandt */ 2563f06ca4afSHartmut Brandt void 2564f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2565f06ca4afSHartmut Brandt { 2566f06ca4afSHartmut Brandt const struct lmodule *m; 2567f06ca4afSHartmut Brandt 2568f06ca4afSHartmut Brandt /* 2569f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2570f06ca4afSHartmut Brandt */ 2571f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2572f06ca4afSHartmut Brandt lm_unload(mod); 2573f06ca4afSHartmut Brandt return; 2574f06ca4afSHartmut Brandt } 2575f06ca4afSHartmut Brandt 2576f06ca4afSHartmut Brandt /* 2577f06ca4afSHartmut Brandt * Read configuration 2578f06ca4afSHartmut Brandt */ 2579f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2580f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2581f06ca4afSHartmut Brandt lm_unload(mod); 2582f06ca4afSHartmut Brandt return; 2583f06ca4afSHartmut Brandt } 2584f06ca4afSHartmut Brandt if (mod->config->start) 2585f06ca4afSHartmut Brandt (*mod->config->start)(); 2586f06ca4afSHartmut Brandt 2587f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2588f06ca4afSHartmut Brandt 2589f06ca4afSHartmut Brandt /* 2590f06ca4afSHartmut Brandt * Inform other modules 2591f06ca4afSHartmut Brandt */ 2592f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2593f06ca4afSHartmut Brandt if (m->config->loading) 2594f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2595f06ca4afSHartmut Brandt } 2596f06ca4afSHartmut Brandt 2597f06ca4afSHartmut Brandt 2598f06ca4afSHartmut Brandt /* 2599f06ca4afSHartmut Brandt * Unload a module. 2600f06ca4afSHartmut Brandt */ 2601f06ca4afSHartmut Brandt void 2602f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2603f06ca4afSHartmut Brandt { 2604f06ca4afSHartmut Brandt int err; 2605f06ca4afSHartmut Brandt const struct lmodule *mod; 2606f06ca4afSHartmut Brandt 2607f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2608f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2609f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2610f06ca4afSHartmut Brandt tree_unmerge(m); 2611f06ca4afSHartmut Brandt 2612f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2613f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2614f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2615f06ca4afSHartmut Brandt 2616f06ca4afSHartmut Brandt comm_flush(m); 2617f06ca4afSHartmut Brandt reqid_flush(m); 2618f06ca4afSHartmut Brandt timer_flush(m); 2619f06ca4afSHartmut Brandt fd_flush(m); 2620f06ca4afSHartmut Brandt 2621f06ca4afSHartmut Brandt dlclose(m->handle); 2622f06ca4afSHartmut Brandt free(m->path); 2623f06ca4afSHartmut Brandt 2624f06ca4afSHartmut Brandt /* 2625f06ca4afSHartmut Brandt * Inform other modules 2626f06ca4afSHartmut Brandt */ 2627f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2628f06ca4afSHartmut Brandt if (mod->config->loading) 2629f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2630f06ca4afSHartmut Brandt 2631f06ca4afSHartmut Brandt free(m); 2632f06ca4afSHartmut Brandt } 2633f06ca4afSHartmut Brandt 2634f06ca4afSHartmut Brandt /* 2635f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2636f06ca4afSHartmut Brandt */ 2637f06ca4afSHartmut Brandt u_int 2638f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2639f06ca4afSHartmut Brandt { 2640f06ca4afSHartmut Brandt struct objres *objres, *or1; 2641f06ca4afSHartmut Brandt u_int idx; 2642f06ca4afSHartmut Brandt 2643f06ca4afSHartmut Brandt /* find a free index */ 2644f06ca4afSHartmut Brandt idx = 1; 2645f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2646f06ca4afSHartmut Brandt objres != NULL; 2647f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2648f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2649f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2650f06ca4afSHartmut Brandt idx = objres->index + 1; 2651f06ca4afSHartmut Brandt break; 2652f06ca4afSHartmut Brandt } 2653f06ca4afSHartmut Brandt } 2654f06ca4afSHartmut Brandt 2655f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2656f06ca4afSHartmut Brandt return (0); 2657f06ca4afSHartmut Brandt 2658f06ca4afSHartmut Brandt objres->index = idx; 2659f06ca4afSHartmut Brandt objres->oid = *or; 2660f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 266169292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2662f06ca4afSHartmut Brandt objres->module = mod; 2663f06ca4afSHartmut Brandt 2664f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2665f06ca4afSHartmut Brandt 2666f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2667f06ca4afSHartmut Brandt 2668f06ca4afSHartmut Brandt return (idx); 2669f06ca4afSHartmut Brandt } 2670f06ca4afSHartmut Brandt 2671f06ca4afSHartmut Brandt void 2672f06ca4afSHartmut Brandt or_unregister(u_int idx) 2673f06ca4afSHartmut Brandt { 2674f06ca4afSHartmut Brandt struct objres *objres; 2675f06ca4afSHartmut Brandt 2676f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2677f06ca4afSHartmut Brandt if (objres->index == idx) { 2678f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2679f06ca4afSHartmut Brandt free(objres); 2680f06ca4afSHartmut Brandt return; 2681f06ca4afSHartmut Brandt } 2682f06ca4afSHartmut Brandt } 2683*135f7de5SShteryana Shopova 2684*135f7de5SShteryana Shopova /* 2685*135f7de5SShteryana Shopova * RFC 3414 User-based Security Model support 2686*135f7de5SShteryana Shopova */ 2687*135f7de5SShteryana Shopova 2688*135f7de5SShteryana Shopova struct snmpd_usmstat * 2689*135f7de5SShteryana Shopova bsnmpd_get_usm_stats(void) 2690*135f7de5SShteryana Shopova { 2691*135f7de5SShteryana Shopova return (&snmpd_usmstats); 2692*135f7de5SShteryana Shopova } 2693*135f7de5SShteryana Shopova 2694*135f7de5SShteryana Shopova void 2695*135f7de5SShteryana Shopova bsnmpd_reset_usm_stats(void) 2696*135f7de5SShteryana Shopova { 2697*135f7de5SShteryana Shopova memset(&snmpd_usmstats, 0, sizeof(&snmpd_usmstats)); 2698*135f7de5SShteryana Shopova } 2699*135f7de5SShteryana Shopova 2700*135f7de5SShteryana Shopova struct usm_user * 2701*135f7de5SShteryana Shopova usm_first_user(void) 2702*135f7de5SShteryana Shopova { 2703*135f7de5SShteryana Shopova return (SLIST_FIRST(&usm_userlist)); 2704*135f7de5SShteryana Shopova } 2705*135f7de5SShteryana Shopova 2706*135f7de5SShteryana Shopova struct usm_user * 2707*135f7de5SShteryana Shopova usm_next_user(struct usm_user *uuser) 2708*135f7de5SShteryana Shopova { 2709*135f7de5SShteryana Shopova if (uuser == NULL) 2710*135f7de5SShteryana Shopova return (NULL); 2711*135f7de5SShteryana Shopova 2712*135f7de5SShteryana Shopova return (SLIST_NEXT(uuser, up)); 2713*135f7de5SShteryana Shopova } 2714*135f7de5SShteryana Shopova 2715*135f7de5SShteryana Shopova struct usm_user * 2716*135f7de5SShteryana Shopova usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2717*135f7de5SShteryana Shopova { 2718*135f7de5SShteryana Shopova struct usm_user *uuser; 2719*135f7de5SShteryana Shopova 2720*135f7de5SShteryana Shopova SLIST_FOREACH(uuser, &usm_userlist, up) 2721*135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2722*135f7de5SShteryana Shopova memcmp(uuser->user_engine_id, engine, elen) == 0 && 2723*135f7de5SShteryana Shopova strlen(uuser->suser.sec_name) == strlen(uname) && 2724*135f7de5SShteryana Shopova strcmp(uuser->suser.sec_name, uname) == 0) 2725*135f7de5SShteryana Shopova break; 2726*135f7de5SShteryana Shopova 2727*135f7de5SShteryana Shopova return (uuser); 2728*135f7de5SShteryana Shopova } 2729*135f7de5SShteryana Shopova 2730*135f7de5SShteryana Shopova static int 2731*135f7de5SShteryana Shopova usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2732*135f7de5SShteryana Shopova { 2733*135f7de5SShteryana Shopova uint32_t i; 2734*135f7de5SShteryana Shopova 2735*135f7de5SShteryana Shopova if (u1->user_engine_len < u2->user_engine_len) 2736*135f7de5SShteryana Shopova return (-1); 2737*135f7de5SShteryana Shopova if (u1->user_engine_len > u2->user_engine_len) 2738*135f7de5SShteryana Shopova return (1); 2739*135f7de5SShteryana Shopova 2740*135f7de5SShteryana Shopova for (i = 0; i < u1->user_engine_len; i++) { 2741*135f7de5SShteryana Shopova if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2742*135f7de5SShteryana Shopova return (-1); 2743*135f7de5SShteryana Shopova if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2744*135f7de5SShteryana Shopova return (1); 2745*135f7de5SShteryana Shopova } 2746*135f7de5SShteryana Shopova 2747*135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2748*135f7de5SShteryana Shopova return (-1); 2749*135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2750*135f7de5SShteryana Shopova return (1); 2751*135f7de5SShteryana Shopova 2752*135f7de5SShteryana Shopova for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2753*135f7de5SShteryana Shopova if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2754*135f7de5SShteryana Shopova return (-1); 2755*135f7de5SShteryana Shopova if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2756*135f7de5SShteryana Shopova return (1); 2757*135f7de5SShteryana Shopova } 2758*135f7de5SShteryana Shopova 2759*135f7de5SShteryana Shopova return (0); 2760*135f7de5SShteryana Shopova } 2761*135f7de5SShteryana Shopova 2762*135f7de5SShteryana Shopova struct usm_user * 2763*135f7de5SShteryana Shopova usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2764*135f7de5SShteryana Shopova { 2765*135f7de5SShteryana Shopova int cmp; 2766*135f7de5SShteryana Shopova struct usm_user *uuser, *temp, *prev; 2767*135f7de5SShteryana Shopova 2768*135f7de5SShteryana Shopova for (uuser = usm_first_user(); uuser != NULL; 2769*135f7de5SShteryana Shopova (uuser = usm_next_user(uuser))) { 2770*135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2771*135f7de5SShteryana Shopova strlen(uname) == strlen(uuser->suser.sec_name) && 2772*135f7de5SShteryana Shopova strcmp(uname, uuser->suser.sec_name) == 0 && 2773*135f7de5SShteryana Shopova memcmp(eid, uuser->user_engine_id, elen) == 0) 2774*135f7de5SShteryana Shopova return (NULL); 2775*135f7de5SShteryana Shopova } 2776*135f7de5SShteryana Shopova 2777*135f7de5SShteryana Shopova if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2778*135f7de5SShteryana Shopova return (NULL); 2779*135f7de5SShteryana Shopova 2780*135f7de5SShteryana Shopova memset(uuser, 0, sizeof(struct usm_user)); 2781*135f7de5SShteryana Shopova strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2782*135f7de5SShteryana Shopova memcpy(uuser->user_engine_id, eid, elen); 2783*135f7de5SShteryana Shopova uuser->user_engine_len = elen; 2784*135f7de5SShteryana Shopova 2785*135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2786*135f7de5SShteryana Shopova usm_compare_user(uuser, prev) < 0) { 2787*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2788*135f7de5SShteryana Shopova return (uuser); 2789*135f7de5SShteryana Shopova } 2790*135f7de5SShteryana Shopova 2791*135f7de5SShteryana Shopova SLIST_FOREACH(temp, &usm_userlist, up) { 2792*135f7de5SShteryana Shopova if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2793*135f7de5SShteryana Shopova break; 2794*135f7de5SShteryana Shopova prev = temp; 2795*135f7de5SShteryana Shopova } 2796*135f7de5SShteryana Shopova 2797*135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2798*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, uuser, up); 2799*135f7de5SShteryana Shopova else if (cmp > 0) 2800*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, uuser, up); 2801*135f7de5SShteryana Shopova else { 2802*135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2803*135f7de5SShteryana Shopova free(uuser); 2804*135f7de5SShteryana Shopova return (NULL); 2805*135f7de5SShteryana Shopova } 2806*135f7de5SShteryana Shopova 2807*135f7de5SShteryana Shopova return (uuser); 2808*135f7de5SShteryana Shopova } 2809*135f7de5SShteryana Shopova 2810*135f7de5SShteryana Shopova void 2811*135f7de5SShteryana Shopova usm_delete_user(struct usm_user *uuser) 2812*135f7de5SShteryana Shopova { 2813*135f7de5SShteryana Shopova SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2814*135f7de5SShteryana Shopova free(uuser); 2815*135f7de5SShteryana Shopova } 2816*135f7de5SShteryana Shopova 2817*135f7de5SShteryana Shopova void 2818*135f7de5SShteryana Shopova usm_flush_users(void) 2819*135f7de5SShteryana Shopova { 2820*135f7de5SShteryana Shopova struct usm_user *uuser; 2821*135f7de5SShteryana Shopova 2822*135f7de5SShteryana Shopova while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2823*135f7de5SShteryana Shopova SLIST_REMOVE_HEAD(&usm_userlist, up); 2824*135f7de5SShteryana Shopova free(uuser); 2825*135f7de5SShteryana Shopova } 2826*135f7de5SShteryana Shopova 2827*135f7de5SShteryana Shopova SLIST_INIT(&usm_userlist); 2828*135f7de5SShteryana Shopova } 2829*135f7de5SShteryana Shopova 2830*135f7de5SShteryana Shopova /* 2831*135f7de5SShteryana Shopova * RFC 3415 View-based Access Control Model support 2832*135f7de5SShteryana Shopova */ 2833*135f7de5SShteryana Shopova struct vacm_user * 2834*135f7de5SShteryana Shopova vacm_first_user(void) 2835*135f7de5SShteryana Shopova { 2836*135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_userlist)); 2837*135f7de5SShteryana Shopova } 2838*135f7de5SShteryana Shopova 2839*135f7de5SShteryana Shopova struct vacm_user * 2840*135f7de5SShteryana Shopova vacm_next_user(struct vacm_user *vuser) 2841*135f7de5SShteryana Shopova { 2842*135f7de5SShteryana Shopova if (vuser == NULL) 2843*135f7de5SShteryana Shopova return (NULL); 2844*135f7de5SShteryana Shopova 2845*135f7de5SShteryana Shopova return (SLIST_NEXT(vuser, vvu)); 2846*135f7de5SShteryana Shopova } 2847*135f7de5SShteryana Shopova 2848*135f7de5SShteryana Shopova static int 2849*135f7de5SShteryana Shopova vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2850*135f7de5SShteryana Shopova { 2851*135f7de5SShteryana Shopova uint32_t i; 2852*135f7de5SShteryana Shopova 2853*135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2854*135f7de5SShteryana Shopova return (-1); 2855*135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2856*135f7de5SShteryana Shopova return (1); 2857*135f7de5SShteryana Shopova 2858*135f7de5SShteryana Shopova if (strlen(v1->secname) < strlen(v2->secname)) 2859*135f7de5SShteryana Shopova return (-1); 2860*135f7de5SShteryana Shopova if (strlen(v1->secname) > strlen(v2->secname)) 2861*135f7de5SShteryana Shopova return (1); 2862*135f7de5SShteryana Shopova 2863*135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->secname); i++) { 2864*135f7de5SShteryana Shopova if (v1->secname[i] < v2->secname[i]) 2865*135f7de5SShteryana Shopova return (-1); 2866*135f7de5SShteryana Shopova if (v1->secname[i] > v2->secname[i]) 2867*135f7de5SShteryana Shopova return (1); 2868*135f7de5SShteryana Shopova } 2869*135f7de5SShteryana Shopova 2870*135f7de5SShteryana Shopova return (0); 2871*135f7de5SShteryana Shopova } 2872*135f7de5SShteryana Shopova 2873*135f7de5SShteryana Shopova struct vacm_user * 2874*135f7de5SShteryana Shopova vacm_new_user(int32_t smodel, char *uname) 2875*135f7de5SShteryana Shopova { 2876*135f7de5SShteryana Shopova int cmp; 2877*135f7de5SShteryana Shopova struct vacm_user *user, *temp, *prev; 2878*135f7de5SShteryana Shopova 2879*135f7de5SShteryana Shopova SLIST_FOREACH(user, &vacm_userlist, vvu) 2880*135f7de5SShteryana Shopova if (strcmp(uname, user->secname) == 0 && 2881*135f7de5SShteryana Shopova smodel == user->sec_model) 2882*135f7de5SShteryana Shopova return (NULL); 2883*135f7de5SShteryana Shopova 2884*135f7de5SShteryana Shopova if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2885*135f7de5SShteryana Shopova return (NULL); 2886*135f7de5SShteryana Shopova 2887*135f7de5SShteryana Shopova memset(user, 0, sizeof(*user)); 2888*135f7de5SShteryana Shopova user->group = &vacm_default_group; 2889*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2890*135f7de5SShteryana Shopova user->sec_model = smodel; 2891*135f7de5SShteryana Shopova strlcpy(user->secname, uname, sizeof(user->secname)); 2892*135f7de5SShteryana Shopova 2893*135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2894*135f7de5SShteryana Shopova vacm_compare_user(user, prev) < 0) { 2895*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2896*135f7de5SShteryana Shopova return (user); 2897*135f7de5SShteryana Shopova } 2898*135f7de5SShteryana Shopova 2899*135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2900*135f7de5SShteryana Shopova if ((cmp = vacm_compare_user(user, temp)) <= 0) 2901*135f7de5SShteryana Shopova break; 2902*135f7de5SShteryana Shopova prev = temp; 2903*135f7de5SShteryana Shopova } 2904*135f7de5SShteryana Shopova 2905*135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2906*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, user, vvu); 2907*135f7de5SShteryana Shopova else if (cmp > 0) 2908*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, user, vvu); 2909*135f7de5SShteryana Shopova else { 2910*135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", user->secname); 2911*135f7de5SShteryana Shopova free(user); 2912*135f7de5SShteryana Shopova return (NULL); 2913*135f7de5SShteryana Shopova } 2914*135f7de5SShteryana Shopova 2915*135f7de5SShteryana Shopova return (user); 2916*135f7de5SShteryana Shopova } 2917*135f7de5SShteryana Shopova 2918*135f7de5SShteryana Shopova int 2919*135f7de5SShteryana Shopova vacm_delete_user(struct vacm_user *user) 2920*135f7de5SShteryana Shopova { 2921*135f7de5SShteryana Shopova if (user->group != NULL && user->group != &vacm_default_group) { 2922*135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2923*135f7de5SShteryana Shopova if (SLIST_EMPTY(&user->group->group_users)) { 2924*135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_grouplist, user->group, 2925*135f7de5SShteryana Shopova vacm_group, vge); 2926*135f7de5SShteryana Shopova free(user->group); 2927*135f7de5SShteryana Shopova } 2928*135f7de5SShteryana Shopova } 2929*135f7de5SShteryana Shopova 2930*135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2931*135f7de5SShteryana Shopova free(user); 2932*135f7de5SShteryana Shopova 2933*135f7de5SShteryana Shopova return (0); 2934*135f7de5SShteryana Shopova } 2935*135f7de5SShteryana Shopova 2936*135f7de5SShteryana Shopova int 2937*135f7de5SShteryana Shopova vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2938*135f7de5SShteryana Shopova { 2939*135f7de5SShteryana Shopova struct vacm_group *group; 2940*135f7de5SShteryana Shopova 2941*135f7de5SShteryana Shopova if (len >= SNMP_ADM_STR32_SIZ) 2942*135f7de5SShteryana Shopova return (-1); 2943*135f7de5SShteryana Shopova 2944*135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2945*135f7de5SShteryana Shopova if (strlen(group->groupname) == len && 2946*135f7de5SShteryana Shopova memcmp(octets, group->groupname, len) == 0) 2947*135f7de5SShteryana Shopova break; 2948*135f7de5SShteryana Shopova 2949*135f7de5SShteryana Shopova if (group == NULL) { 2950*135f7de5SShteryana Shopova if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2951*135f7de5SShteryana Shopova return (-1); 2952*135f7de5SShteryana Shopova memset(group, 0, sizeof(*group)); 2953*135f7de5SShteryana Shopova memcpy(group->groupname, octets, len); 2954*135f7de5SShteryana Shopova group->groupname[len] = '\0'; 2955*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2956*135f7de5SShteryana Shopova } 2957*135f7de5SShteryana Shopova 2958*135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2959*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2960*135f7de5SShteryana Shopova user->group = group; 2961*135f7de5SShteryana Shopova 2962*135f7de5SShteryana Shopova return (0); 2963*135f7de5SShteryana Shopova } 2964*135f7de5SShteryana Shopova 2965*135f7de5SShteryana Shopova void 2966*135f7de5SShteryana Shopova vacm_groups_init(void) 2967*135f7de5SShteryana Shopova { 2968*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2969*135f7de5SShteryana Shopova } 2970*135f7de5SShteryana Shopova 2971*135f7de5SShteryana Shopova struct vacm_access * 2972*135f7de5SShteryana Shopova vacm_first_access_rule(void) 2973*135f7de5SShteryana Shopova { 2974*135f7de5SShteryana Shopova return (TAILQ_FIRST(&vacm_accesslist)); 2975*135f7de5SShteryana Shopova } 2976*135f7de5SShteryana Shopova 2977*135f7de5SShteryana Shopova struct vacm_access * 2978*135f7de5SShteryana Shopova vacm_next_access_rule(struct vacm_access *acl) 2979*135f7de5SShteryana Shopova { 2980*135f7de5SShteryana Shopova if (acl == NULL) 2981*135f7de5SShteryana Shopova return (NULL); 2982*135f7de5SShteryana Shopova 2983*135f7de5SShteryana Shopova return (TAILQ_NEXT(acl, vva)); 2984*135f7de5SShteryana Shopova } 2985*135f7de5SShteryana Shopova 2986*135f7de5SShteryana Shopova static int 2987*135f7de5SShteryana Shopova vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2988*135f7de5SShteryana Shopova { 2989*135f7de5SShteryana Shopova uint32_t i; 2990*135f7de5SShteryana Shopova 2991*135f7de5SShteryana Shopova if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 2992*135f7de5SShteryana Shopova return (-1); 2993*135f7de5SShteryana Shopova if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 2994*135f7de5SShteryana Shopova return (1); 2995*135f7de5SShteryana Shopova 2996*135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->group->groupname); i++) { 2997*135f7de5SShteryana Shopova if (v1->group->groupname[i] < v2->group->groupname[i]) 2998*135f7de5SShteryana Shopova return (-1); 2999*135f7de5SShteryana Shopova if (v1->group->groupname[i] > v2->group->groupname[i]) 3000*135f7de5SShteryana Shopova return (1); 3001*135f7de5SShteryana Shopova } 3002*135f7de5SShteryana Shopova 3003*135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 3004*135f7de5SShteryana Shopova return (-1); 3005*135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 3006*135f7de5SShteryana Shopova return (1); 3007*135f7de5SShteryana Shopova 3008*135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->ctx_prefix); i++) { 3009*135f7de5SShteryana Shopova if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 3010*135f7de5SShteryana Shopova return (-1); 3011*135f7de5SShteryana Shopova if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 3012*135f7de5SShteryana Shopova return (1); 3013*135f7de5SShteryana Shopova } 3014*135f7de5SShteryana Shopova 3015*135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 3016*135f7de5SShteryana Shopova return (-1); 3017*135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 3018*135f7de5SShteryana Shopova return (1); 3019*135f7de5SShteryana Shopova 3020*135f7de5SShteryana Shopova if (v1->sec_level < v2->sec_level) 3021*135f7de5SShteryana Shopova return (-1); 3022*135f7de5SShteryana Shopova if (v1->sec_level > v2->sec_level) 3023*135f7de5SShteryana Shopova return (1); 3024*135f7de5SShteryana Shopova 3025*135f7de5SShteryana Shopova return (0); 3026*135f7de5SShteryana Shopova } 3027*135f7de5SShteryana Shopova 3028*135f7de5SShteryana Shopova struct vacm_access * 3029*135f7de5SShteryana Shopova vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 3030*135f7de5SShteryana Shopova { 3031*135f7de5SShteryana Shopova struct vacm_group *group; 3032*135f7de5SShteryana Shopova struct vacm_access *acl, *temp; 3033*135f7de5SShteryana Shopova 3034*135f7de5SShteryana Shopova TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 3035*135f7de5SShteryana Shopova if (acl->group == NULL) 3036*135f7de5SShteryana Shopova continue; 3037*135f7de5SShteryana Shopova if (strcmp(gname, acl->group->groupname) == 0 && 3038*135f7de5SShteryana Shopova strcmp(cprefix, acl->ctx_prefix) == 0 && 3039*135f7de5SShteryana Shopova acl->sec_model == smodel && acl->sec_level == slevel) 3040*135f7de5SShteryana Shopova return (NULL); 3041*135f7de5SShteryana Shopova } 3042*135f7de5SShteryana Shopova 3043*135f7de5SShteryana Shopova /* Make sure the group exists */ 3044*135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 3045*135f7de5SShteryana Shopova if (strcmp(gname, group->groupname) == 0) 3046*135f7de5SShteryana Shopova break; 3047*135f7de5SShteryana Shopova 3048*135f7de5SShteryana Shopova if (group == NULL) 3049*135f7de5SShteryana Shopova return (NULL); 3050*135f7de5SShteryana Shopova 3051*135f7de5SShteryana Shopova if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 3052*135f7de5SShteryana Shopova return (NULL); 3053*135f7de5SShteryana Shopova 3054*135f7de5SShteryana Shopova memset(acl, 0, sizeof(*acl)); 3055*135f7de5SShteryana Shopova acl->group = group; 3056*135f7de5SShteryana Shopova strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 3057*135f7de5SShteryana Shopova acl->sec_model = smodel; 3058*135f7de5SShteryana Shopova acl->sec_level = slevel; 3059*135f7de5SShteryana Shopova 3060*135f7de5SShteryana Shopova if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 3061*135f7de5SShteryana Shopova vacm_compare_access_rule(acl, temp) < 0) { 3062*135f7de5SShteryana Shopova TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 3063*135f7de5SShteryana Shopova return (acl); 3064*135f7de5SShteryana Shopova } 3065*135f7de5SShteryana Shopova 3066*135f7de5SShteryana Shopova TAILQ_FOREACH(temp, &vacm_accesslist, vva) 3067*135f7de5SShteryana Shopova if (vacm_compare_access_rule(acl, temp) < 0) { 3068*135f7de5SShteryana Shopova TAILQ_INSERT_BEFORE(temp, acl, vva); 3069*135f7de5SShteryana Shopova return (acl); 3070*135f7de5SShteryana Shopova } 3071*135f7de5SShteryana Shopova 3072*135f7de5SShteryana Shopova TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 3073*135f7de5SShteryana Shopova 3074*135f7de5SShteryana Shopova return (acl); 3075*135f7de5SShteryana Shopova } 3076*135f7de5SShteryana Shopova 3077*135f7de5SShteryana Shopova int 3078*135f7de5SShteryana Shopova vacm_delete_access_rule(struct vacm_access *acl) 3079*135f7de5SShteryana Shopova { 3080*135f7de5SShteryana Shopova TAILQ_REMOVE(&vacm_accesslist, acl, vva); 3081*135f7de5SShteryana Shopova free(acl); 3082*135f7de5SShteryana Shopova 3083*135f7de5SShteryana Shopova return (0); 3084*135f7de5SShteryana Shopova } 3085*135f7de5SShteryana Shopova 3086*135f7de5SShteryana Shopova struct vacm_view * 3087*135f7de5SShteryana Shopova vacm_first_view(void) 3088*135f7de5SShteryana Shopova { 3089*135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_viewlist)); 3090*135f7de5SShteryana Shopova } 3091*135f7de5SShteryana Shopova 3092*135f7de5SShteryana Shopova struct vacm_view * 3093*135f7de5SShteryana Shopova vacm_next_view(struct vacm_view *view) 3094*135f7de5SShteryana Shopova { 3095*135f7de5SShteryana Shopova if (view == NULL) 3096*135f7de5SShteryana Shopova return (NULL); 3097*135f7de5SShteryana Shopova 3098*135f7de5SShteryana Shopova return (SLIST_NEXT(view, vvl)); 3099*135f7de5SShteryana Shopova } 3100*135f7de5SShteryana Shopova 3101*135f7de5SShteryana Shopova static int 3102*135f7de5SShteryana Shopova vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3103*135f7de5SShteryana Shopova { 3104*135f7de5SShteryana Shopova uint32_t i; 3105*135f7de5SShteryana Shopova 3106*135f7de5SShteryana Shopova if (strlen(v1->viewname) < strlen(v2->viewname)) 3107*135f7de5SShteryana Shopova return (-1); 3108*135f7de5SShteryana Shopova if (strlen(v1->viewname) > strlen(v2->viewname)) 3109*135f7de5SShteryana Shopova return (1); 3110*135f7de5SShteryana Shopova 3111*135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->viewname); i++) { 3112*135f7de5SShteryana Shopova if (v1->viewname[i] < v2->viewname[i]) 3113*135f7de5SShteryana Shopova return (-1); 3114*135f7de5SShteryana Shopova if (v1->viewname[i] > v2->viewname[i]) 3115*135f7de5SShteryana Shopova return (1); 3116*135f7de5SShteryana Shopova } 3117*135f7de5SShteryana Shopova 3118*135f7de5SShteryana Shopova return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3119*135f7de5SShteryana Shopova } 3120*135f7de5SShteryana Shopova 3121*135f7de5SShteryana Shopova struct vacm_view * 3122*135f7de5SShteryana Shopova vacm_new_view(char *vname, struct asn_oid *oid) 3123*135f7de5SShteryana Shopova { 3124*135f7de5SShteryana Shopova int cmp; 3125*135f7de5SShteryana Shopova struct vacm_view *view, *temp, *prev; 3126*135f7de5SShteryana Shopova 3127*135f7de5SShteryana Shopova SLIST_FOREACH(view, &vacm_viewlist, vvl) 3128*135f7de5SShteryana Shopova if (strcmp(vname, view->viewname) == 0) 3129*135f7de5SShteryana Shopova return (NULL); 3130*135f7de5SShteryana Shopova 3131*135f7de5SShteryana Shopova if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3132*135f7de5SShteryana Shopova return (NULL); 3133*135f7de5SShteryana Shopova 3134*135f7de5SShteryana Shopova memset(view, 0, sizeof(*view)); 3135*135f7de5SShteryana Shopova strlcpy(view->viewname, vname, sizeof(view->viewname)); 3136*135f7de5SShteryana Shopova asn_append_oid(&view->subtree, oid); 3137*135f7de5SShteryana Shopova 3138*135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3139*135f7de5SShteryana Shopova vacm_compare_view(view, prev) < 0) { 3140*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3141*135f7de5SShteryana Shopova return (view); 3142*135f7de5SShteryana Shopova } 3143*135f7de5SShteryana Shopova 3144*135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3145*135f7de5SShteryana Shopova if ((cmp = vacm_compare_view(view, temp)) <= 0) 3146*135f7de5SShteryana Shopova break; 3147*135f7de5SShteryana Shopova prev = temp; 3148*135f7de5SShteryana Shopova } 3149*135f7de5SShteryana Shopova 3150*135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3151*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, view, vvl); 3152*135f7de5SShteryana Shopova else if (cmp > 0) 3153*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, view, vvl); 3154*135f7de5SShteryana Shopova else { 3155*135f7de5SShteryana Shopova syslog(LOG_ERR, "View %s exists", view->viewname); 3156*135f7de5SShteryana Shopova free(view); 3157*135f7de5SShteryana Shopova return (NULL); 3158*135f7de5SShteryana Shopova } 3159*135f7de5SShteryana Shopova 3160*135f7de5SShteryana Shopova return (view); 3161*135f7de5SShteryana Shopova } 3162*135f7de5SShteryana Shopova 3163*135f7de5SShteryana Shopova int 3164*135f7de5SShteryana Shopova vacm_delete_view(struct vacm_view *view) 3165*135f7de5SShteryana Shopova { 3166*135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3167*135f7de5SShteryana Shopova free(view); 3168*135f7de5SShteryana Shopova 3169*135f7de5SShteryana Shopova return (0); 3170*135f7de5SShteryana Shopova } 3171*135f7de5SShteryana Shopova 3172*135f7de5SShteryana Shopova struct vacm_context * 3173*135f7de5SShteryana Shopova vacm_first_context(void) 3174*135f7de5SShteryana Shopova { 3175*135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_contextlist)); 3176*135f7de5SShteryana Shopova } 3177*135f7de5SShteryana Shopova 3178*135f7de5SShteryana Shopova struct vacm_context * 3179*135f7de5SShteryana Shopova vacm_next_context(struct vacm_context *vacmctx) 3180*135f7de5SShteryana Shopova { 3181*135f7de5SShteryana Shopova if (vacmctx == NULL) 3182*135f7de5SShteryana Shopova return (NULL); 3183*135f7de5SShteryana Shopova 3184*135f7de5SShteryana Shopova return (SLIST_NEXT(vacmctx, vcl)); 3185*135f7de5SShteryana Shopova } 3186*135f7de5SShteryana Shopova 3187*135f7de5SShteryana Shopova struct vacm_context * 3188*135f7de5SShteryana Shopova vacm_add_context(char *ctxname, int regid) 3189*135f7de5SShteryana Shopova { 3190*135f7de5SShteryana Shopova int cmp; 3191*135f7de5SShteryana Shopova struct vacm_context *ctx, *temp, *prev; 3192*135f7de5SShteryana Shopova 3193*135f7de5SShteryana Shopova SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3194*135f7de5SShteryana Shopova if (strcmp(ctxname, ctx->ctxname) == 0) { 3195*135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3196*135f7de5SShteryana Shopova return (NULL); 3197*135f7de5SShteryana Shopova } 3198*135f7de5SShteryana Shopova 3199*135f7de5SShteryana Shopova if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3200*135f7de5SShteryana Shopova return (NULL); 3201*135f7de5SShteryana Shopova 3202*135f7de5SShteryana Shopova memset(ctx, 0, sizeof(*ctx)); 3203*135f7de5SShteryana Shopova strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3204*135f7de5SShteryana Shopova ctx->regid = regid; 3205*135f7de5SShteryana Shopova 3206*135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3207*135f7de5SShteryana Shopova strlen(ctx->ctxname) < strlen(prev->ctxname) || 3208*135f7de5SShteryana Shopova strcmp(ctx->ctxname, prev->ctxname) < 0) { 3209*135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3210*135f7de5SShteryana Shopova return (ctx); 3211*135f7de5SShteryana Shopova } 3212*135f7de5SShteryana Shopova 3213*135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3214*135f7de5SShteryana Shopova if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3215*135f7de5SShteryana Shopova strcmp(ctx->ctxname, temp->ctxname) < 0) { 3216*135f7de5SShteryana Shopova cmp = -1; 3217*135f7de5SShteryana Shopova break; 3218*135f7de5SShteryana Shopova } 3219*135f7de5SShteryana Shopova prev = temp; 3220*135f7de5SShteryana Shopova } 3221*135f7de5SShteryana Shopova 3222*135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3223*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, ctx, vcl); 3224*135f7de5SShteryana Shopova else if (cmp > 0) 3225*135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, ctx, vcl); 3226*135f7de5SShteryana Shopova else { 3227*135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3228*135f7de5SShteryana Shopova free(ctx); 3229*135f7de5SShteryana Shopova return (NULL); 3230*135f7de5SShteryana Shopova } 3231*135f7de5SShteryana Shopova 3232*135f7de5SShteryana Shopova return (ctx); 3233*135f7de5SShteryana Shopova } 3234*135f7de5SShteryana Shopova 3235*135f7de5SShteryana Shopova void 3236*135f7de5SShteryana Shopova vacm_flush_contexts(int regid) 3237*135f7de5SShteryana Shopova { 3238*135f7de5SShteryana Shopova struct vacm_context *ctx, *temp; 3239*135f7de5SShteryana Shopova 3240*135f7de5SShteryana Shopova SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3241*135f7de5SShteryana Shopova if (ctx->regid == regid) { 3242*135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3243*135f7de5SShteryana Shopova free(ctx); 3244*135f7de5SShteryana Shopova } 3245*135f7de5SShteryana Shopova } 3246