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 * 872cd7a52SShteryana Shopova * Copyright (c) 2010 The FreeBSD Foundation 972cd7a52SShteryana Shopova * All rights reserved. 1072cd7a52SShteryana Shopova * 1172cd7a52SShteryana Shopova * Portions of this software were developed by Shteryana Sotirova Shopova 1272cd7a52SShteryana Shopova * under sponsorship from the FreeBSD Foundation. 1372cd7a52SShteryana Shopova * 14896052c1SHartmut Brandt * Redistribution and use in source and binary forms, with or without 15896052c1SHartmut Brandt * modification, are permitted provided that the following conditions 16896052c1SHartmut Brandt * are met: 17896052c1SHartmut Brandt * 1. Redistributions of source code must retain the above copyright 18896052c1SHartmut Brandt * notice, this list of conditions and the following disclaimer. 19f06ca4afSHartmut Brandt * 2. Redistributions in binary form must reproduce the above copyright 20f06ca4afSHartmut Brandt * notice, this list of conditions and the following disclaimer in the 21f06ca4afSHartmut Brandt * documentation and/or other materials provided with the distribution. 22f06ca4afSHartmut Brandt * 23896052c1SHartmut Brandt * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24896052c1SHartmut Brandt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25896052c1SHartmut Brandt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26896052c1SHartmut Brandt * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27896052c1SHartmut Brandt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28896052c1SHartmut Brandt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29896052c1SHartmut Brandt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30896052c1SHartmut Brandt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31896052c1SHartmut Brandt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32896052c1SHartmut Brandt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33896052c1SHartmut Brandt * SUCH DAMAGE. 34f06ca4afSHartmut Brandt * 35748b5b1eSHartmut Brandt * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 36f06ca4afSHartmut Brandt * 37f06ca4afSHartmut Brandt * SNMPd main stuff. 38f06ca4afSHartmut Brandt */ 39135f7de5SShteryana Shopova 40135f7de5SShteryana Shopova #include <sys/queue.h> 41f06ca4afSHartmut Brandt #include <sys/param.h> 42f06ca4afSHartmut Brandt #include <sys/un.h> 4370af00a1SHartmut Brandt #include <sys/ucred.h> 44165c5d31SHartmut Brandt #include <sys/uio.h> 45f06ca4afSHartmut Brandt #include <stdio.h> 46f06ca4afSHartmut Brandt #include <stdlib.h> 47f06ca4afSHartmut Brandt #include <stddef.h> 48f06ca4afSHartmut Brandt #include <string.h> 49f06ca4afSHartmut Brandt #include <stdarg.h> 50f06ca4afSHartmut Brandt #include <ctype.h> 51f06ca4afSHartmut Brandt #include <errno.h> 52f06ca4afSHartmut Brandt #include <syslog.h> 53f06ca4afSHartmut Brandt #include <unistd.h> 54f06ca4afSHartmut Brandt #include <signal.h> 55f06ca4afSHartmut Brandt #include <dlfcn.h> 56f06ca4afSHartmut Brandt #include <inttypes.h> 57f06ca4afSHartmut Brandt 58d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 59d7eb6b47SHartmut Brandt #include <arpa/inet.h> 60d7eb6b47SHartmut Brandt #include <tcpd.h> 61d7eb6b47SHartmut Brandt #endif 62d7eb6b47SHartmut Brandt 63748b5b1eSHartmut Brandt #include "support.h" 64f06ca4afSHartmut Brandt #include "snmpmod.h" 65f06ca4afSHartmut Brandt #include "snmpd.h" 66f06ca4afSHartmut Brandt #include "tree.h" 67f06ca4afSHartmut Brandt #include "oid.h" 68f06ca4afSHartmut Brandt 69f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 70f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 71135f7de5SShteryana Shopova #define PATH_ENGINE "/var/%s.engine" 72f06ca4afSHartmut Brandt 7369292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 7469292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 75f06ca4afSHartmut Brandt 76f06ca4afSHartmut Brandt struct systemg systemg = { 77f06ca4afSHartmut Brandt NULL, 78f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 79f06ca4afSHartmut Brandt NULL, NULL, NULL, 80f06ca4afSHartmut Brandt 64 + 8 + 4, 81f06ca4afSHartmut Brandt 0 82f06ca4afSHartmut Brandt }; 83f06ca4afSHartmut Brandt struct debug debug = { 84f06ca4afSHartmut Brandt 0, /* dump_pdus */ 85f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 86f06ca4afSHartmut Brandt 0, /* evdebug */ 87f06ca4afSHartmut Brandt }; 88f06ca4afSHartmut Brandt 89f06ca4afSHartmut Brandt struct snmpd snmpd = { 90f06ca4afSHartmut Brandt 2048, /* txbuf */ 91f06ca4afSHartmut Brandt 2048, /* rxbuf */ 92f06ca4afSHartmut Brandt 0, /* comm_dis */ 93f06ca4afSHartmut Brandt 0, /* auth_traps */ 94f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 9570af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 96f06ca4afSHartmut Brandt }; 97f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 98f06ca4afSHartmut Brandt 99135f7de5SShteryana Shopova struct snmpd_usmstat snmpd_usmstats; 100135f7de5SShteryana Shopova 101135f7de5SShteryana Shopova /* snmpEngine */ 102135f7de5SShteryana Shopova struct snmp_engine snmpd_engine; 103135f7de5SShteryana Shopova 104f06ca4afSHartmut Brandt /* snmpSerialNo */ 105f06ca4afSHartmut Brandt int32_t snmp_serial_no; 106f06ca4afSHartmut Brandt 10772cd7a52SShteryana Shopova struct snmpd_target_stats snmpd_target_stats; 10872cd7a52SShteryana Shopova 109f06ca4afSHartmut Brandt /* search path for config files */ 110f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 111f06ca4afSHartmut Brandt 112f06ca4afSHartmut Brandt /* list of all loaded modules */ 113f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 114f06ca4afSHartmut Brandt 115f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 116f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 117f06ca4afSHartmut Brandt 118f06ca4afSHartmut Brandt /* list of all known communities */ 119f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 120f06ca4afSHartmut Brandt 121135f7de5SShteryana Shopova /* list of all known USM users */ 1228cd5a258SEnji Cooper static struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 123135f7de5SShteryana Shopova 124135f7de5SShteryana Shopova /* A list of all VACM users configured, including v1, v2c and v3 */ 1258cd5a258SEnji Cooper static struct vacm_userlist vacm_userlist = 1268cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_userlist); 127135f7de5SShteryana Shopova 128135f7de5SShteryana Shopova /* A list of all VACM groups */ 1298cd5a258SEnji Cooper static struct vacm_grouplist vacm_grouplist = 1308cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_grouplist); 131135f7de5SShteryana Shopova 132135f7de5SShteryana Shopova static struct vacm_group vacm_default_group = { 133135f7de5SShteryana Shopova .groupname = "", 134135f7de5SShteryana Shopova }; 135135f7de5SShteryana Shopova 136135f7de5SShteryana Shopova /* The list of configured access entries */ 1378cd5a258SEnji Cooper static struct vacm_accesslist vacm_accesslist = 1388cd5a258SEnji Cooper TAILQ_HEAD_INITIALIZER(vacm_accesslist); 139135f7de5SShteryana Shopova 140135f7de5SShteryana Shopova /* The list of configured views */ 1418cd5a258SEnji Cooper static struct vacm_viewlist vacm_viewlist = 1428cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_viewlist); 143135f7de5SShteryana Shopova 144135f7de5SShteryana Shopova /* The list of configured contexts */ 1458cd5a258SEnji Cooper static struct vacm_contextlist vacm_contextlist = 146135f7de5SShteryana Shopova SLIST_HEAD_INITIALIZER(vacm_contextlist); 147135f7de5SShteryana Shopova 148f06ca4afSHartmut Brandt /* list of all installed object resources */ 149f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 150f06ca4afSHartmut Brandt 151f06ca4afSHartmut Brandt /* community value generator */ 152f06ca4afSHartmut Brandt static u_int next_community_index = 1; 153f06ca4afSHartmut Brandt 154f06ca4afSHartmut Brandt /* list of all known ranges */ 155f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 156f06ca4afSHartmut Brandt 157f06ca4afSHartmut Brandt /* identifier generator */ 158f06ca4afSHartmut Brandt u_int next_idrange = 1; 159f06ca4afSHartmut Brandt 160f06ca4afSHartmut Brandt /* list of all current timers */ 161f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 162f06ca4afSHartmut Brandt 163f06ca4afSHartmut Brandt /* list of file descriptors */ 164f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 165f06ca4afSHartmut Brandt 166f06ca4afSHartmut Brandt /* program arguments */ 167f06ca4afSHartmut Brandt static char **progargs; 168f06ca4afSHartmut Brandt static int nprogargs; 169f06ca4afSHartmut Brandt 170f06ca4afSHartmut Brandt /* current community */ 171f06ca4afSHartmut Brandt u_int community; 172f06ca4afSHartmut Brandt static struct community *comm; 173f06ca4afSHartmut Brandt 174135f7de5SShteryana Shopova /* current USM user */ 175135f7de5SShteryana Shopova struct usm_user *usm_user; 176135f7de5SShteryana Shopova 177f06ca4afSHartmut Brandt /* file names */ 178f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 179f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 180135f7de5SShteryana Shopova char engine_file[MAXPATHLEN + 1]; 181f06ca4afSHartmut Brandt 18270af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 183f06ca4afSHartmut Brandt /* event context */ 184f06ca4afSHartmut Brandt static evContext evctx; 18570af00a1SHartmut Brandt #endif 186f06ca4afSHartmut Brandt 187f06ca4afSHartmut Brandt /* signal mask */ 188f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 189f06ca4afSHartmut Brandt 190f06ca4afSHartmut Brandt /* signal handling */ 191f06ca4afSHartmut Brandt static int work; 192f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 193f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 194f06ca4afSHartmut Brandt 195f06ca4afSHartmut Brandt /* oids */ 196f06ca4afSHartmut Brandt static const struct asn_oid 197f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 198f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 199f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 200f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 201f06ca4afSHartmut Brandt 202f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 203f06ca4afSHartmut Brandt 204135f7de5SShteryana Shopova const struct asn_oid oid_usmUnknownEngineIDs = 205135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 206135f7de5SShteryana Shopova 207135f7de5SShteryana Shopova const struct asn_oid oid_usmNotInTimeWindows = 208135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 209135f7de5SShteryana Shopova 210f06ca4afSHartmut Brandt /* request id generator for traps */ 211f06ca4afSHartmut Brandt u_int trap_reqid; 212f06ca4afSHartmut Brandt 213f06ca4afSHartmut Brandt /* help text */ 214f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 215f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 216f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 217135f7de5SShteryana Shopova Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 218135f7de5SShteryana Shopova usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 219135f7de5SShteryana Shopova [-l prefix] [-m variable=value] [-p file]\n\ 220f06ca4afSHartmut Brandt options:\n\ 221f06ca4afSHartmut Brandt -d don't daemonize\n\ 222f06ca4afSHartmut Brandt -h print this info\n\ 223f06ca4afSHartmut Brandt -c file specify configuration file\n\ 224f06ca4afSHartmut Brandt -D options debugging options\n\ 225135f7de5SShteryana Shopova -e file specify engine id file\n\ 226f06ca4afSHartmut Brandt -I path system include path\n\ 227f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 228f06ca4afSHartmut Brandt -m var=val define variable\n\ 229f06ca4afSHartmut Brandt -p file specify pid file\n\ 230f06ca4afSHartmut Brandt "; 231f06ca4afSHartmut Brandt 232d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 233d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 234d7eb6b47SHartmut Brandt static struct request_info req; 235d7eb6b47SHartmut Brandt #endif 236d7eb6b47SHartmut Brandt 23770af00a1SHartmut Brandt /* transports */ 23870af00a1SHartmut Brandt extern const struct transport_def udp_trans; 23970af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 24070af00a1SHartmut Brandt 24170af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 24270af00a1SHartmut Brandt 243f06ca4afSHartmut Brandt /* forward declarations */ 244f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 245f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 246f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 247f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 248f06ca4afSHartmut Brandt 249f06ca4afSHartmut Brandt /* 250f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 251f06ca4afSHartmut Brandt */ 252f06ca4afSHartmut Brandt void * 253f06ca4afSHartmut Brandt buf_alloc(int tx) 254f06ca4afSHartmut Brandt { 255f06ca4afSHartmut Brandt void *buf; 256f06ca4afSHartmut Brandt 25770af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 258f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 259f06ca4afSHartmut Brandt if (tx) 260f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 261f06ca4afSHartmut Brandt else 262f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 263f06ca4afSHartmut Brandt return (NULL); 264f06ca4afSHartmut Brandt } 265f06ca4afSHartmut Brandt return (buf); 266f06ca4afSHartmut Brandt } 267f06ca4afSHartmut Brandt 268f06ca4afSHartmut Brandt /* 26970af00a1SHartmut Brandt * Return the buffer size. 270f06ca4afSHartmut Brandt */ 271f06ca4afSHartmut Brandt size_t 272f06ca4afSHartmut Brandt buf_size(int tx) 273f06ca4afSHartmut Brandt { 27470af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 275f06ca4afSHartmut Brandt } 276f06ca4afSHartmut Brandt 277f06ca4afSHartmut Brandt /* 278f06ca4afSHartmut Brandt * Prepare a PDU for output 279f06ca4afSHartmut Brandt */ 280f06ca4afSHartmut Brandt void 28170af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 282f06ca4afSHartmut Brandt const char *dest) 283f06ca4afSHartmut Brandt { 284f06ca4afSHartmut Brandt struct asn_buf resp_b; 285*f29369b7SEnji Cooper enum snmp_code code; 286f06ca4afSHartmut Brandt 287f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 288f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 289f06ca4afSHartmut Brandt 290*f29369b7SEnji Cooper if ((code = snmp_pdu_encode(pdu, &resp_b)) != SNMP_CODE_OK) { 291*f29369b7SEnji Cooper syslog(LOG_ERR, "cannot encode message (code=%d)", code); 292f06ca4afSHartmut Brandt abort(); 293f06ca4afSHartmut Brandt } 294f06ca4afSHartmut Brandt if (debug.dump_pdus) { 295f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 296f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 297f06ca4afSHartmut Brandt } 298f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 299f06ca4afSHartmut Brandt } 300f06ca4afSHartmut Brandt 301f06ca4afSHartmut Brandt /* 302135f7de5SShteryana Shopova * Check USM PDU header credentials against local SNMP Engine & users. 303135f7de5SShteryana Shopova */ 304135f7de5SShteryana Shopova static enum snmp_code 305135f7de5SShteryana Shopova snmp_pdu_auth_user(struct snmp_pdu *pdu) 306135f7de5SShteryana Shopova { 307135f7de5SShteryana Shopova uint64_t etime; 308135f7de5SShteryana Shopova usm_user = NULL; 309135f7de5SShteryana Shopova 310135f7de5SShteryana Shopova /* un-authenticated snmpEngineId discovery */ 311135f7de5SShteryana Shopova if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 312135f7de5SShteryana Shopova pdu->engine.engine_len = snmpd_engine.engine_len; 313135f7de5SShteryana Shopova memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 314135f7de5SShteryana Shopova snmpd_engine.engine_len); 315135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 316135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 317135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 318135f7de5SShteryana Shopova return (SNMP_CODE_OK); 319135f7de5SShteryana Shopova } 320135f7de5SShteryana Shopova 321135f7de5SShteryana Shopova if ((usm_user = usm_find_user(pdu->engine.engine_id, 322135f7de5SShteryana Shopova pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 323135f7de5SShteryana Shopova usm_user->status != 1 /* active */) 324135f7de5SShteryana Shopova return (SNMP_CODE_BADUSER); 325135f7de5SShteryana Shopova 326135f7de5SShteryana Shopova if (usm_user->user_engine_len != snmpd_engine.engine_len || 327135f7de5SShteryana Shopova memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 328135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 329135f7de5SShteryana Shopova return (SNMP_CODE_BADENGINE); 330135f7de5SShteryana Shopova 331135f7de5SShteryana Shopova pdu->user.priv_proto = usm_user->suser.priv_proto; 332135f7de5SShteryana Shopova memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 333135f7de5SShteryana Shopova sizeof(pdu->user.priv_key)); 334135f7de5SShteryana Shopova 335135f7de5SShteryana Shopova /* authenticated snmpEngineId discovery */ 336135f7de5SShteryana Shopova if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 337135f7de5SShteryana Shopova etime = (get_ticks() - start_tick) / 100ULL; 338135f7de5SShteryana Shopova if (etime < INT32_MAX) 339135f7de5SShteryana Shopova snmpd_engine.engine_time = etime; 340135f7de5SShteryana Shopova else { 341135f7de5SShteryana Shopova start_tick = get_ticks(); 342135f7de5SShteryana Shopova set_snmpd_engine(); 343135f7de5SShteryana Shopova snmpd_engine.engine_time = start_tick; 344135f7de5SShteryana Shopova } 345135f7de5SShteryana Shopova 346135f7de5SShteryana Shopova pdu->user.auth_proto = usm_user->suser.auth_proto; 347135f7de5SShteryana Shopova memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 348135f7de5SShteryana Shopova sizeof(pdu->user.auth_key)); 349135f7de5SShteryana Shopova 350135f7de5SShteryana Shopova if (pdu->engine.engine_boots == 0 && 351135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 352135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 353135f7de5SShteryana Shopova return (SNMP_CODE_OK); 354135f7de5SShteryana Shopova } 355135f7de5SShteryana Shopova 356135f7de5SShteryana Shopova if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 357135f7de5SShteryana Shopova abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 358135f7de5SShteryana Shopova SNMP_TIME_WINDOW) 359135f7de5SShteryana Shopova return (SNMP_CODE_NOTINTIME); 360135f7de5SShteryana Shopova } 361135f7de5SShteryana Shopova 362135f7de5SShteryana Shopova if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 363135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 364135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 365135f7de5SShteryana Shopova usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 366135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 367135f7de5SShteryana Shopova usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 368135f7de5SShteryana Shopova return (SNMP_CODE_BADSECLEVEL); 369135f7de5SShteryana Shopova 370135f7de5SShteryana Shopova return (SNMP_CODE_OK); 371135f7de5SShteryana Shopova } 372135f7de5SShteryana Shopova 373135f7de5SShteryana Shopova /* 374135f7de5SShteryana Shopova * Check whether access to each of var bindings in the PDU is allowed based 375135f7de5SShteryana Shopova * on the user credentials against the configured User groups & VACM views. 376135f7de5SShteryana Shopova */ 37772cd7a52SShteryana Shopova enum snmp_code 378135f7de5SShteryana Shopova snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 379135f7de5SShteryana Shopova { 380135f7de5SShteryana Shopova const char *uname; 381135f7de5SShteryana Shopova int32_t suboid, smodel; 382135f7de5SShteryana Shopova uint32_t i; 383135f7de5SShteryana Shopova struct vacm_user *vuser; 384135f7de5SShteryana Shopova struct vacm_access *acl; 385135f7de5SShteryana Shopova struct vacm_context *vacmctx; 386135f7de5SShteryana Shopova struct vacm_view *view; 387135f7de5SShteryana Shopova 388135f7de5SShteryana Shopova /* 389135f7de5SShteryana Shopova * At least a default context exists if the snmpd_vacm(3) module is 390135f7de5SShteryana Shopova * running. 391135f7de5SShteryana Shopova */ 392135f7de5SShteryana Shopova if (SLIST_EMPTY(&vacm_contextlist) || 393135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 394135f7de5SShteryana Shopova return (SNMP_CODE_OK); 395135f7de5SShteryana Shopova 396135f7de5SShteryana Shopova switch (pdu->version) { 397135f7de5SShteryana Shopova case SNMP_V1: 398135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 399135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 400135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv1; 401135f7de5SShteryana Shopova break; 402135f7de5SShteryana Shopova 403135f7de5SShteryana Shopova case SNMP_V2c: 404135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 405135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 406135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv2c; 407135f7de5SShteryana Shopova break; 408135f7de5SShteryana Shopova 409135f7de5SShteryana Shopova case SNMP_V3: 410135f7de5SShteryana Shopova uname = pdu->user.sec_name; 411135f7de5SShteryana Shopova if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 412135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 413135f7de5SShteryana Shopova /* Compare the PDU context engine id against the agent's */ 414135f7de5SShteryana Shopova if (pdu->context_engine_len != snmpd_engine.engine_len || 415135f7de5SShteryana Shopova memcmp(pdu->context_engine, snmpd_engine.engine_id, 416135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 417135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 418135f7de5SShteryana Shopova break; 419135f7de5SShteryana Shopova 420135f7de5SShteryana Shopova default: 421135f7de5SShteryana Shopova abort(); 422135f7de5SShteryana Shopova } 423135f7de5SShteryana Shopova 424135f7de5SShteryana Shopova SLIST_FOREACH(vuser, &vacm_userlist, vvu) 425135f7de5SShteryana Shopova if (strcmp(uname, vuser->secname) == 0 && 426135f7de5SShteryana Shopova vuser->sec_model == smodel) 427135f7de5SShteryana Shopova break; 428135f7de5SShteryana Shopova 429135f7de5SShteryana Shopova if (vuser == NULL || vuser->group == NULL) 430135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 431135f7de5SShteryana Shopova 432135f7de5SShteryana Shopova /* XXX: shteryana - recheck */ 433135f7de5SShteryana Shopova TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 434135f7de5SShteryana Shopova if (acl->group != vuser->group) 435135f7de5SShteryana Shopova continue; 436135f7de5SShteryana Shopova SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 437135f7de5SShteryana Shopova if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 438135f7de5SShteryana Shopova acl->ctx_match) == 0) 439135f7de5SShteryana Shopova goto match; 440135f7de5SShteryana Shopova } 441135f7de5SShteryana Shopova 442135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 443135f7de5SShteryana Shopova 444135f7de5SShteryana Shopova match: 445135f7de5SShteryana Shopova 446135f7de5SShteryana Shopova switch (pdu->type) { 447135f7de5SShteryana Shopova case SNMP_PDU_GET: 448135f7de5SShteryana Shopova case SNMP_PDU_GETNEXT: 449135f7de5SShteryana Shopova case SNMP_PDU_GETBULK: 450135f7de5SShteryana Shopova if ((view = acl->read_view) == NULL) 451135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 452135f7de5SShteryana Shopova break; 453135f7de5SShteryana Shopova 454135f7de5SShteryana Shopova case SNMP_PDU_SET: 455135f7de5SShteryana Shopova if ((view = acl->write_view) == NULL) 456135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 457135f7de5SShteryana Shopova break; 458135f7de5SShteryana Shopova 459135f7de5SShteryana Shopova case SNMP_PDU_TRAP: 460135f7de5SShteryana Shopova case SNMP_PDU_INFORM: 461135f7de5SShteryana Shopova case SNMP_PDU_TRAP2: 462135f7de5SShteryana Shopova case SNMP_PDU_REPORT: 463135f7de5SShteryana Shopova if ((view = acl->notify_view) == NULL) 464135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 465135f7de5SShteryana Shopova break; 466135f7de5SShteryana Shopova case SNMP_PDU_RESPONSE: 467135f7de5SShteryana Shopova /* NOTREACHED */ 468135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 469135f7de5SShteryana Shopova default: 470135f7de5SShteryana Shopova abort(); 471135f7de5SShteryana Shopova } 472135f7de5SShteryana Shopova 473135f7de5SShteryana Shopova for (i = 0; i < pdu->nbindings; i++) { 474135f7de5SShteryana Shopova /* XXX - view->mask*/ 475135f7de5SShteryana Shopova suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 476135f7de5SShteryana Shopova if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 477135f7de5SShteryana Shopova *ip = i + 1; 478135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 479135f7de5SShteryana Shopova } 480135f7de5SShteryana Shopova } 481135f7de5SShteryana Shopova 482135f7de5SShteryana Shopova return (SNMP_CODE_OK); 483135f7de5SShteryana Shopova } 484135f7de5SShteryana Shopova 485135f7de5SShteryana Shopova /* 486135f7de5SShteryana Shopova * SNMP input. Start: decode the PDU, find the user or community. 487f06ca4afSHartmut Brandt */ 488f06ca4afSHartmut Brandt enum snmpd_input_err 489f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 49070af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 491f06ca4afSHartmut Brandt { 492f06ca4afSHartmut Brandt struct asn_buf b; 493f06ca4afSHartmut Brandt enum snmp_code code; 494f06ca4afSHartmut Brandt enum snmpd_input_err ret; 49570af00a1SHartmut Brandt int sret; 496f06ca4afSHartmut Brandt 497135f7de5SShteryana Shopova /* update uptime */ 498135f7de5SShteryana Shopova this_tick = get_ticks(); 499135f7de5SShteryana Shopova 500f06ca4afSHartmut Brandt b.asn_cptr = buf; 501f06ca4afSHartmut Brandt b.asn_len = len; 50270af00a1SHartmut Brandt 50370af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 50470af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 50570af00a1SHartmut Brandt 50670af00a1SHartmut Brandt case 0: 50770af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 50870af00a1SHartmut Brandt 50970af00a1SHartmut Brandt case -1: 51070af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 51170af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 51270af00a1SHartmut Brandt } 51370af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 51470af00a1SHartmut Brandt 515135f7de5SShteryana Shopova memset(pdu, 0, sizeof(*pdu)); 516135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 517135f7de5SShteryana Shopova goto decoded; 518f06ca4afSHartmut Brandt 519135f7de5SShteryana Shopova if (pdu->version == SNMP_V3) { 520135f7de5SShteryana Shopova if (pdu->security_model != SNMP_SECMODEL_USM) { 521135f7de5SShteryana Shopova code = SNMP_CODE_FAILED; 522135f7de5SShteryana Shopova goto decoded; 523135f7de5SShteryana Shopova } 524135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 525135f7de5SShteryana Shopova goto decoded; 526135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 527135f7de5SShteryana Shopova goto decoded; 528135f7de5SShteryana Shopova } 529135f7de5SShteryana Shopova code = snmp_pdu_decode_scoped(&b, pdu, ip); 53070af00a1SHartmut Brandt 531f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 532135f7de5SShteryana Shopova 533135f7de5SShteryana Shopova decoded: 534135f7de5SShteryana Shopova snmpd_stats.inPkts++; 535135f7de5SShteryana Shopova 536f06ca4afSHartmut Brandt switch (code) { 537f06ca4afSHartmut Brandt 538f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 539f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 540f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 541f06ca4afSHartmut Brandt 542f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 54370af00a1SHartmut Brandt bad_vers: 544f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 545f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 546f06ca4afSHartmut Brandt 547f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 548f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 549f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 550f06ca4afSHartmut Brandt break; 551f06ca4afSHartmut Brandt 552f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 553f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 554f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 555f06ca4afSHartmut Brandt break; 556f06ca4afSHartmut Brandt 557f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 558f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 559f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 560f06ca4afSHartmut Brandt break; 561f06ca4afSHartmut Brandt 562135f7de5SShteryana Shopova case SNMP_CODE_BADSECLEVEL: 563135f7de5SShteryana Shopova snmpd_usmstats.unsupported_seclevels++; 564135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 565135f7de5SShteryana Shopova 566135f7de5SShteryana Shopova case SNMP_CODE_NOTINTIME: 567135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 568135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 569135f7de5SShteryana Shopova 570135f7de5SShteryana Shopova case SNMP_CODE_BADUSER: 571135f7de5SShteryana Shopova snmpd_usmstats.unknown_users++; 572135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 573135f7de5SShteryana Shopova 574135f7de5SShteryana Shopova case SNMP_CODE_BADENGINE: 575135f7de5SShteryana Shopova snmpd_usmstats.unknown_engine_ids++; 576135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 577135f7de5SShteryana Shopova 578135f7de5SShteryana Shopova case SNMP_CODE_BADDIGEST: 579135f7de5SShteryana Shopova snmpd_usmstats.wrong_digests++; 580135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 581135f7de5SShteryana Shopova 582135f7de5SShteryana Shopova case SNMP_CODE_EDECRYPT: 583135f7de5SShteryana Shopova snmpd_usmstats.decrypt_errors++; 584135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 585135f7de5SShteryana Shopova 586f06ca4afSHartmut Brandt case SNMP_CODE_OK: 58770af00a1SHartmut Brandt switch (pdu->version) { 58870af00a1SHartmut Brandt 58970af00a1SHartmut Brandt case SNMP_V1: 59070af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 59170af00a1SHartmut Brandt goto bad_vers; 59270af00a1SHartmut Brandt break; 59370af00a1SHartmut Brandt 59470af00a1SHartmut Brandt case SNMP_V2c: 59570af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 59670af00a1SHartmut Brandt goto bad_vers; 59770af00a1SHartmut Brandt break; 59870af00a1SHartmut Brandt 599135f7de5SShteryana Shopova case SNMP_V3: 600135f7de5SShteryana Shopova if (!(snmpd.version_enable & VERS_ENABLE_V3)) 601135f7de5SShteryana Shopova goto bad_vers; 602135f7de5SShteryana Shopova break; 603135f7de5SShteryana Shopova 60470af00a1SHartmut Brandt case SNMP_Verr: 60570af00a1SHartmut Brandt goto bad_vers; 60670af00a1SHartmut Brandt } 607f06ca4afSHartmut Brandt break; 608f06ca4afSHartmut Brandt } 609f06ca4afSHartmut Brandt 610f06ca4afSHartmut Brandt if (debug.dump_pdus) { 611f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 612f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 613f06ca4afSHartmut Brandt } 614f06ca4afSHartmut Brandt 615f06ca4afSHartmut Brandt /* 616135f7de5SShteryana Shopova * Look, whether we know the community or user 617f06ca4afSHartmut Brandt */ 618135f7de5SShteryana Shopova 619135f7de5SShteryana Shopova if (pdu->version != SNMP_V3) { 620f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 621f06ca4afSHartmut Brandt if (comm->string != NULL && 622f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 623f06ca4afSHartmut Brandt break; 624f06ca4afSHartmut Brandt 625f06ca4afSHartmut Brandt if (comm == NULL) { 626f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 627f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 628f06ca4afSHartmut Brandt if (snmpd.auth_traps) 629896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 630896052c1SHartmut Brandt (struct snmp_value *)NULL); 631896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 632896052c1SHartmut Brandt } else 633f06ca4afSHartmut Brandt community = comm->value; 634135f7de5SShteryana Shopova } else if (pdu->nbindings == 0) { 635135f7de5SShteryana Shopova /* RFC 3414 - snmpEngineID Discovery */ 636135f7de5SShteryana Shopova if (strlen(pdu->user.sec_name) == 0) { 637135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 638135f7de5SShteryana Shopova &oid_usmUnknownEngineIDs); 639135f7de5SShteryana Shopova pdu->context_engine_len = snmpd_engine.engine_len; 640135f7de5SShteryana Shopova memcpy(pdu->context_engine, snmpd_engine.engine_id, 641135f7de5SShteryana Shopova snmpd_engine.engine_len); 642135f7de5SShteryana Shopova } else if (pdu->engine.engine_boots == 0 && 643135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 644135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 645135f7de5SShteryana Shopova &oid_usmNotInTimeWindows); 646135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 647135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 648135f7de5SShteryana Shopova } 649135f7de5SShteryana Shopova } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 650135f7de5SShteryana Shopova (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 651135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 652126b5bb6SEnji Cooper ret = SNMPD_INPUT_FAILED; 653135f7de5SShteryana Shopova } 654f06ca4afSHartmut Brandt 655135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 656126b5bb6SEnji Cooper ret = SNMPD_INPUT_FAILED; 657f06ca4afSHartmut Brandt 658f06ca4afSHartmut Brandt return (ret); 659f06ca4afSHartmut Brandt } 660f06ca4afSHartmut Brandt 661f06ca4afSHartmut Brandt /* 662f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 663f06ca4afSHartmut Brandt */ 664f06ca4afSHartmut Brandt enum snmpd_input_err 665f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 666f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 667f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 668f06ca4afSHartmut Brandt { 669f06ca4afSHartmut Brandt struct snmp_pdu resp; 670f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 671f06ca4afSHartmut Brandt enum snmp_ret ret; 672f06ca4afSHartmut Brandt 673f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 674f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 675f06ca4afSHartmut Brandt 676f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 677f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 678f06ca4afSHartmut Brandt 679f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 680f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 681f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 682f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 683f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 684f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 685f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 686f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 687f06ca4afSHartmut Brandt else 688f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 689f06ca4afSHartmut Brandt 690f06ca4afSHartmut Brandt pdu->error_index = ivar; 691f06ca4afSHartmut Brandt 692f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 693f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 694f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 695f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 696f06ca4afSHartmut Brandt } 697f06ca4afSHartmut Brandt 698f06ca4afSHartmut Brandt if (debug.dump_pdus) { 699f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 700f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 701f06ca4afSHartmut Brandt } 702f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 703f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 704f06ca4afSHartmut Brandt } 705f06ca4afSHartmut Brandt 706f06ca4afSHartmut Brandt switch (pdu->type) { 707f06ca4afSHartmut Brandt 708f06ca4afSHartmut Brandt case SNMP_PDU_GET: 709f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 710f06ca4afSHartmut Brandt break; 711f06ca4afSHartmut Brandt 712f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 713f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 714f06ca4afSHartmut Brandt break; 715f06ca4afSHartmut Brandt 716f06ca4afSHartmut Brandt case SNMP_PDU_SET: 717f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 718f06ca4afSHartmut Brandt break; 719f06ca4afSHartmut Brandt 720f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 721f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 722f06ca4afSHartmut Brandt break; 723f06ca4afSHartmut Brandt 724f06ca4afSHartmut Brandt default: 725f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 726f06ca4afSHartmut Brandt break; 727f06ca4afSHartmut Brandt } 728f06ca4afSHartmut Brandt 729f06ca4afSHartmut Brandt switch (ret) { 730f06ca4afSHartmut Brandt 731f06ca4afSHartmut Brandt case SNMP_RET_OK: 732f06ca4afSHartmut Brandt /* normal return - send a response */ 733f06ca4afSHartmut Brandt if (debug.dump_pdus) { 734f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 735f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 736f06ca4afSHartmut Brandt } 737f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 738f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 739f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 740f06ca4afSHartmut Brandt 741f06ca4afSHartmut Brandt case SNMP_RET_IGN: 742f06ca4afSHartmut Brandt /* error - send nothing */ 743f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 744f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 745f06ca4afSHartmut Brandt 746f06ca4afSHartmut Brandt case SNMP_RET_ERR: 747f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 748f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 749f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 750f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 751f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 752f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 753f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 754f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 755f06ca4afSHartmut Brandt } else { 756f06ca4afSHartmut Brandt if (debug.dump_pdus) { 757f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 758f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 759f06ca4afSHartmut Brandt } 760f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 761f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 762f06ca4afSHartmut Brandt } 763f06ca4afSHartmut Brandt } 764f06ca4afSHartmut Brandt abort(); 765f06ca4afSHartmut Brandt } 766f06ca4afSHartmut Brandt 76770af00a1SHartmut Brandt /* 76870af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 76970af00a1SHartmut Brandt */ 77070af00a1SHartmut Brandt void 77170af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 77270af00a1SHartmut Brandt { 77370af00a1SHartmut Brandt struct tport *p; 774f06ca4afSHartmut Brandt 77570af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 77670af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 77770af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 77870af00a1SHartmut Brandt return; 77970af00a1SHartmut Brandt } 78070af00a1SHartmut Brandt } 78170af00a1SHartmut Brandt port->transport = t; 78270af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 78370af00a1SHartmut Brandt } 78470af00a1SHartmut Brandt 78570af00a1SHartmut Brandt /* 78670af00a1SHartmut Brandt * Remove a port from a transport's list 78770af00a1SHartmut Brandt */ 78870af00a1SHartmut Brandt void 78970af00a1SHartmut Brandt trans_remove_port(struct tport *port) 79070af00a1SHartmut Brandt { 79170af00a1SHartmut Brandt 79270af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 79370af00a1SHartmut Brandt } 79470af00a1SHartmut Brandt 79570af00a1SHartmut Brandt /* 79670af00a1SHartmut Brandt * Find a port on a transport's list 79770af00a1SHartmut Brandt */ 79870af00a1SHartmut Brandt struct tport * 79970af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 80070af00a1SHartmut Brandt { 80170af00a1SHartmut Brandt 80270af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 80370af00a1SHartmut Brandt } 80470af00a1SHartmut Brandt 80570af00a1SHartmut Brandt /* 80670af00a1SHartmut Brandt * Find next port on a transport's list 80770af00a1SHartmut Brandt */ 80870af00a1SHartmut Brandt struct tport * 80970af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 81070af00a1SHartmut Brandt { 81170af00a1SHartmut Brandt 81270af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 81370af00a1SHartmut Brandt } 81470af00a1SHartmut Brandt 81570af00a1SHartmut Brandt /* 81670af00a1SHartmut Brandt * Return first port 81770af00a1SHartmut Brandt */ 81870af00a1SHartmut Brandt struct tport * 81970af00a1SHartmut Brandt trans_first_port(struct transport *t) 82070af00a1SHartmut Brandt { 82170af00a1SHartmut Brandt 82270af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 82370af00a1SHartmut Brandt } 82470af00a1SHartmut Brandt 82570af00a1SHartmut Brandt /* 82670af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 82770af00a1SHartmut Brandt */ 82870af00a1SHartmut Brandt struct tport * 82970af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 83070af00a1SHartmut Brandt intptr_t arg) 83170af00a1SHartmut Brandt { 83270af00a1SHartmut Brandt struct tport *p; 83370af00a1SHartmut Brandt 83470af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 83570af00a1SHartmut Brandt if (func(p, arg) == 0) 83670af00a1SHartmut Brandt return (p); 83770af00a1SHartmut Brandt return (NULL); 83870af00a1SHartmut Brandt } 83970af00a1SHartmut Brandt 84070af00a1SHartmut Brandt /* 84170af00a1SHartmut Brandt * Register a transport 84270af00a1SHartmut Brandt */ 84370af00a1SHartmut Brandt int 84470af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 84570af00a1SHartmut Brandt { 84670af00a1SHartmut Brandt u_int i; 84770af00a1SHartmut Brandt char or_descr[256]; 84870af00a1SHartmut Brandt 84970af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 85070af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 85170af00a1SHartmut Brandt 85270af00a1SHartmut Brandt /* construct index */ 85370af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 85470af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 85570af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 85670af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 85770af00a1SHartmut Brandt 85870af00a1SHartmut Brandt (*pp)->vtab = def; 85970af00a1SHartmut Brandt 86070af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 86170af00a1SHartmut Brandt free(*pp); 86270af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 86370af00a1SHartmut Brandt } 86470af00a1SHartmut Brandt 86570af00a1SHartmut Brandt /* register module */ 86670af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 86770af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 86870af00a1SHartmut Brandt free(*pp); 86970af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 87070af00a1SHartmut Brandt } 87170af00a1SHartmut Brandt 87270af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 87370af00a1SHartmut Brandt 87470af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 87570af00a1SHartmut Brandt 87670af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 87770af00a1SHartmut Brandt } 87870af00a1SHartmut Brandt 87970af00a1SHartmut Brandt /* 88070af00a1SHartmut Brandt * Unregister transport 88170af00a1SHartmut Brandt */ 88270af00a1SHartmut Brandt int 88370af00a1SHartmut Brandt trans_unregister(struct transport *t) 88470af00a1SHartmut Brandt { 88570af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 88670af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 88770af00a1SHartmut Brandt 88870af00a1SHartmut Brandt or_unregister(t->or_index); 88970af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 89070af00a1SHartmut Brandt 89170af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 89270af00a1SHartmut Brandt } 893f06ca4afSHartmut Brandt 894f06ca4afSHartmut Brandt /* 895f06ca4afSHartmut Brandt * File descriptor support 896f06ca4afSHartmut Brandt */ 89770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 89870af00a1SHartmut Brandt static void 89970af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 90070af00a1SHartmut Brandt #else 901f06ca4afSHartmut Brandt static void 902f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 90370af00a1SHartmut Brandt #endif 904f06ca4afSHartmut Brandt { 905f06ca4afSHartmut Brandt struct fdesc *f = uap; 906f06ca4afSHartmut Brandt 907f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 908f06ca4afSHartmut Brandt } 909f06ca4afSHartmut Brandt 910f06ca4afSHartmut Brandt void 911f06ca4afSHartmut Brandt fd_suspend(void *p) 912f06ca4afSHartmut Brandt { 913f06ca4afSHartmut Brandt struct fdesc *f = p; 914f06ca4afSHartmut Brandt 91570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 91670af00a1SHartmut Brandt if (f->id >= 0) { 91770af00a1SHartmut Brandt poll_unregister(f->id); 91870af00a1SHartmut Brandt f->id = -1; 91970af00a1SHartmut Brandt } 92070af00a1SHartmut Brandt #else 921f06ca4afSHartmut Brandt if (evTestID(f->id)) { 922f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 923f06ca4afSHartmut Brandt evInitID(&f->id); 924f06ca4afSHartmut Brandt } 92570af00a1SHartmut Brandt #endif 926f06ca4afSHartmut Brandt } 927f06ca4afSHartmut Brandt 928f06ca4afSHartmut Brandt int 929f06ca4afSHartmut Brandt fd_resume(void *p) 930f06ca4afSHartmut Brandt { 931f06ca4afSHartmut Brandt struct fdesc *f = p; 932f06ca4afSHartmut Brandt int err; 933f06ca4afSHartmut Brandt 93470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 93570af00a1SHartmut Brandt if (f->id >= 0) 93670af00a1SHartmut Brandt return (0); 93794caccb3SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 93870af00a1SHartmut Brandt err = errno; 93970af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 94070af00a1SHartmut Brandt errno = err; 94170af00a1SHartmut Brandt return (-1); 94270af00a1SHartmut Brandt } 94370af00a1SHartmut Brandt #else 944f06ca4afSHartmut Brandt if (evTestID(f->id)) 945f06ca4afSHartmut Brandt return (0); 946f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 947f06ca4afSHartmut Brandt err = errno; 948f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 949f06ca4afSHartmut Brandt errno = err; 950f06ca4afSHartmut Brandt return (-1); 951f06ca4afSHartmut Brandt } 95270af00a1SHartmut Brandt #endif 953f06ca4afSHartmut Brandt return (0); 954f06ca4afSHartmut Brandt } 955f06ca4afSHartmut Brandt 956f06ca4afSHartmut Brandt void * 957f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 958f06ca4afSHartmut Brandt { 959f06ca4afSHartmut Brandt struct fdesc *f; 960f06ca4afSHartmut Brandt int err; 961f06ca4afSHartmut Brandt 962f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 963f06ca4afSHartmut Brandt err = errno; 964f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 965f06ca4afSHartmut Brandt errno = err; 966f06ca4afSHartmut Brandt return (NULL); 967f06ca4afSHartmut Brandt } 968f06ca4afSHartmut Brandt f->fd = fd; 969f06ca4afSHartmut Brandt f->func = func; 970f06ca4afSHartmut Brandt f->udata = udata; 971f06ca4afSHartmut Brandt f->owner = mod; 97270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 97370af00a1SHartmut Brandt f->id = -1; 97470af00a1SHartmut Brandt #else 975f06ca4afSHartmut Brandt evInitID(&f->id); 97670af00a1SHartmut Brandt #endif 977f06ca4afSHartmut Brandt 978f06ca4afSHartmut Brandt if (fd_resume(f)) { 979f06ca4afSHartmut Brandt err = errno; 980f06ca4afSHartmut Brandt free(f); 981f06ca4afSHartmut Brandt errno = err; 982f06ca4afSHartmut Brandt return (NULL); 983f06ca4afSHartmut Brandt } 984f06ca4afSHartmut Brandt 985f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 986f06ca4afSHartmut Brandt 987f06ca4afSHartmut Brandt return (f); 988f06ca4afSHartmut Brandt } 989f06ca4afSHartmut Brandt 990f06ca4afSHartmut Brandt void 991f06ca4afSHartmut Brandt fd_deselect(void *p) 992f06ca4afSHartmut Brandt { 993f06ca4afSHartmut Brandt struct fdesc *f = p; 994f06ca4afSHartmut Brandt 995f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 996f06ca4afSHartmut Brandt fd_suspend(f); 997f06ca4afSHartmut Brandt free(f); 998f06ca4afSHartmut Brandt } 999f06ca4afSHartmut Brandt 1000f06ca4afSHartmut Brandt static void 1001f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 1002f06ca4afSHartmut Brandt { 1003f06ca4afSHartmut Brandt struct fdesc *t, *t1; 1004f06ca4afSHartmut Brandt 1005f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 1006f06ca4afSHartmut Brandt while (t != NULL) { 1007f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1008f06ca4afSHartmut Brandt if (t->owner == mod) 1009f06ca4afSHartmut Brandt fd_deselect(t); 1010f06ca4afSHartmut Brandt t = t1; 1011f06ca4afSHartmut Brandt } 1012f06ca4afSHartmut Brandt } 1013f06ca4afSHartmut Brandt 1014f06ca4afSHartmut Brandt /* 101570af00a1SHartmut Brandt * Consume a message from the input buffer 1016f06ca4afSHartmut Brandt */ 1017f06ca4afSHartmut Brandt static void 101870af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 1019f06ca4afSHartmut Brandt { 102070af00a1SHartmut Brandt if (!pi->stream) { 102170af00a1SHartmut Brandt /* always consume everything */ 102270af00a1SHartmut Brandt pi->length = 0; 102370af00a1SHartmut Brandt return; 102470af00a1SHartmut Brandt } 102570af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 102670af00a1SHartmut Brandt /* all bytes consumed */ 102770af00a1SHartmut Brandt pi->length = 0; 102870af00a1SHartmut Brandt return; 102970af00a1SHartmut Brandt } 103070af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 103170af00a1SHartmut Brandt pi->length -= pi->consumed; 103270af00a1SHartmut Brandt } 103370af00a1SHartmut Brandt 10340cf0d912SGleb Smirnoff static void 10350cf0d912SGleb Smirnoff check_priv_dgram(struct port_input *pi, struct sockcred *cred) 10360cf0d912SGleb Smirnoff { 10370cf0d912SGleb Smirnoff 10380cf0d912SGleb Smirnoff /* process explicitly sends credentials */ 10390cf0d912SGleb Smirnoff if (cred) 10400cf0d912SGleb Smirnoff pi->priv = (cred->sc_euid == 0); 10410cf0d912SGleb Smirnoff else 10420cf0d912SGleb Smirnoff pi->priv = 0; 10430cf0d912SGleb Smirnoff } 104470af00a1SHartmut Brandt 104570af00a1SHartmut Brandt static void 10460cf0d912SGleb Smirnoff check_priv_stream(struct port_input *pi) 104770af00a1SHartmut Brandt { 104870af00a1SHartmut Brandt struct xucred ucred; 104970af00a1SHartmut Brandt socklen_t ucredlen; 105070af00a1SHartmut Brandt 10510cf0d912SGleb Smirnoff /* obtain the accept time credentials */ 105270af00a1SHartmut Brandt ucredlen = sizeof(ucred); 105370af00a1SHartmut Brandt 105470af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 105570af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 105670af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 10570cf0d912SGleb Smirnoff else 10580cf0d912SGleb Smirnoff pi->priv = 0; 105970af00a1SHartmut Brandt } 106070af00a1SHartmut Brandt 106170af00a1SHartmut Brandt /* 106270af00a1SHartmut Brandt * Input from a stream socket. 106370af00a1SHartmut Brandt */ 106470af00a1SHartmut Brandt static int 106570af00a1SHartmut Brandt recv_stream(struct port_input *pi) 106670af00a1SHartmut Brandt { 106770af00a1SHartmut Brandt struct msghdr msg; 106870af00a1SHartmut Brandt struct iovec iov[1]; 106970af00a1SHartmut Brandt ssize_t len; 107070af00a1SHartmut Brandt 107170af00a1SHartmut Brandt if (pi->buf == NULL) { 107270af00a1SHartmut Brandt /* no buffer yet - allocate one */ 107370af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 107470af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 107570af00a1SHartmut Brandt * the caller must close the transport. */ 107670af00a1SHartmut Brandt return (-1); 107770af00a1SHartmut Brandt } 107870af00a1SHartmut Brandt pi->buflen = buf_size(0); 107970af00a1SHartmut Brandt pi->consumed = 0; 108070af00a1SHartmut Brandt pi->length = 0; 108170af00a1SHartmut Brandt } 108270af00a1SHartmut Brandt 108370af00a1SHartmut Brandt /* try to get a message */ 108470af00a1SHartmut Brandt msg.msg_name = pi->peer; 108570af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 108670af00a1SHartmut Brandt msg.msg_iov = iov; 108770af00a1SHartmut Brandt msg.msg_iovlen = 1; 108870af00a1SHartmut Brandt msg.msg_control = NULL; 108970af00a1SHartmut Brandt msg.msg_controllen = 0; 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) 11040cf0d912SGleb Smirnoff check_priv_stream(pi); 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 1114f2ddd22eSGleb Smirnoff recv_dgram(struct port_input *pi, struct in_addr *laddr) 111570af00a1SHartmut Brandt { 111670af00a1SHartmut Brandt u_char embuf[1000]; 1117f2ddd22eSGleb Smirnoff char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + 1118f2ddd22eSGleb Smirnoff CMSG_SPACE(sizeof(struct in_addr))]; 111970af00a1SHartmut Brandt struct msghdr msg; 112070af00a1SHartmut Brandt struct iovec iov[1]; 112170af00a1SHartmut Brandt ssize_t len; 11220cf0d912SGleb Smirnoff struct cmsghdr *cmsg; 11230cf0d912SGleb Smirnoff struct sockcred *cred = NULL; 112470af00a1SHartmut Brandt 112570af00a1SHartmut Brandt if (pi->buf == NULL) { 112670af00a1SHartmut Brandt /* no buffer yet - allocate one */ 112770af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 112870af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 112970af00a1SHartmut Brandt * and drop it */ 113070af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 113170af00a1SHartmut Brandt 0, NULL, NULL); 113270af00a1SHartmut Brandt /* return error */ 113370af00a1SHartmut Brandt return (-1); 113470af00a1SHartmut Brandt } 113570af00a1SHartmut Brandt pi->buflen = buf_size(0); 113670af00a1SHartmut Brandt } 113770af00a1SHartmut Brandt 113870af00a1SHartmut Brandt /* try to get a message */ 113970af00a1SHartmut Brandt msg.msg_name = pi->peer; 114070af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 114170af00a1SHartmut Brandt msg.msg_iov = iov; 114270af00a1SHartmut Brandt msg.msg_iovlen = 1; 11430cf0d912SGleb Smirnoff memset(cbuf, 0, sizeof(cbuf)); 11440cf0d912SGleb Smirnoff msg.msg_control = cbuf; 11450cf0d912SGleb Smirnoff msg.msg_controllen = sizeof(cbuf); 114670af00a1SHartmut Brandt msg.msg_flags = 0; 114770af00a1SHartmut Brandt 114870af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 114970af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 115070af00a1SHartmut Brandt 115170af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 115270af00a1SHartmut Brandt 115370af00a1SHartmut Brandt if (len == -1 || len == 0) 115470af00a1SHartmut Brandt /* receive error */ 115570af00a1SHartmut Brandt return (-1); 115670af00a1SHartmut Brandt 115770af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 115870af00a1SHartmut Brandt /* truncated - drop */ 115970af00a1SHartmut Brandt snmpd_stats.silentDrops++; 116070af00a1SHartmut Brandt snmpd_stats.inTooLong++; 116170af00a1SHartmut Brandt return (-1); 116270af00a1SHartmut Brandt } 116370af00a1SHartmut Brandt 116470af00a1SHartmut Brandt pi->length = (size_t)len; 116570af00a1SHartmut Brandt 11660cf0d912SGleb Smirnoff for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 11670cf0d912SGleb Smirnoff cmsg = CMSG_NXTHDR(&msg, cmsg)) { 1168f2ddd22eSGleb Smirnoff if (cmsg->cmsg_level == IPPROTO_IP && 1169f2ddd22eSGleb Smirnoff cmsg->cmsg_type == IP_RECVDSTADDR) 1170f2ddd22eSGleb Smirnoff memcpy(laddr, CMSG_DATA(cmsg), sizeof(struct in_addr)); 11710cf0d912SGleb Smirnoff if (cmsg->cmsg_level == SOL_SOCKET && 11720cf0d912SGleb Smirnoff cmsg->cmsg_type == SCM_CREDS) 11739aa87499SGleb Smirnoff cred = (struct sockcred *)CMSG_DATA(cmsg); 11740cf0d912SGleb Smirnoff } 11750cf0d912SGleb Smirnoff 117670af00a1SHartmut Brandt if (pi->cred) 11770cf0d912SGleb Smirnoff check_priv_dgram(pi, cred); 117870af00a1SHartmut Brandt 117970af00a1SHartmut Brandt return (0); 118070af00a1SHartmut Brandt } 118170af00a1SHartmut Brandt 118270af00a1SHartmut Brandt /* 118370af00a1SHartmut Brandt * Input from a socket 118470af00a1SHartmut Brandt */ 118570af00a1SHartmut Brandt int 118670af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 118770af00a1SHartmut Brandt { 1188f06ca4afSHartmut Brandt u_char *sndbuf; 1189f06ca4afSHartmut Brandt size_t sndlen; 119070af00a1SHartmut Brandt struct snmp_pdu pdu; 1191f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 1192f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 1193f06ca4afSHartmut Brandt int32_t vi; 119470af00a1SHartmut Brandt int ret; 119570af00a1SHartmut Brandt ssize_t slen; 1196d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1197d7eb6b47SHartmut Brandt char client[16]; 1198d7eb6b47SHartmut Brandt #endif 1199f2ddd22eSGleb Smirnoff struct msghdr msg; 1200f2ddd22eSGleb Smirnoff struct iovec iov[1]; 1201f2ddd22eSGleb Smirnoff char cbuf[CMSG_SPACE(sizeof(struct in_addr))]; 1202f2ddd22eSGleb Smirnoff struct cmsghdr *cmsgp; 1203f06ca4afSHartmut Brandt 120470af00a1SHartmut Brandt /* get input depending on the transport */ 120570af00a1SHartmut Brandt if (pi->stream) { 1206f2ddd22eSGleb Smirnoff msg.msg_control = NULL; 1207f2ddd22eSGleb Smirnoff msg.msg_controllen = 0; 1208f2ddd22eSGleb Smirnoff 120970af00a1SHartmut Brandt ret = recv_stream(pi); 121070af00a1SHartmut Brandt } else { 12119aa87499SGleb Smirnoff struct in_addr *laddr; 121223cea719SGleb Smirnoff 1213f2ddd22eSGleb Smirnoff memset(cbuf, 0, CMSG_SPACE(sizeof(struct in_addr))); 1214f2ddd22eSGleb Smirnoff msg.msg_control = cbuf; 1215f2ddd22eSGleb Smirnoff msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 1216f2ddd22eSGleb Smirnoff cmsgp = CMSG_FIRSTHDR(&msg); 1217f2ddd22eSGleb Smirnoff cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1218f2ddd22eSGleb Smirnoff cmsgp->cmsg_level = IPPROTO_IP; 1219f2ddd22eSGleb Smirnoff cmsgp->cmsg_type = IP_SENDSRCADDR; 12209aa87499SGleb Smirnoff laddr = (struct in_addr *)CMSG_DATA(cmsgp); 1221f2ddd22eSGleb Smirnoff 12229aa87499SGleb Smirnoff ret = recv_dgram(pi, laddr); 122323cea719SGleb Smirnoff 12249aa87499SGleb Smirnoff if (laddr->s_addr == 0) { 122523cea719SGleb Smirnoff msg.msg_control = NULL; 122623cea719SGleb Smirnoff msg.msg_controllen = 0; 122723cea719SGleb Smirnoff } 1228f06ca4afSHartmut Brandt } 122970af00a1SHartmut Brandt 123070af00a1SHartmut Brandt if (ret == -1) 123170af00a1SHartmut Brandt return (-1); 1232f06ca4afSHartmut Brandt 1233d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1234d7eb6b47SHartmut Brandt /* 1235d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 1236d7eb6b47SHartmut Brandt */ 123781b587f3SRuslan Ermilov if (pi->peer->sa_family != AF_LOCAL && 123881b587f3SRuslan Ermilov inet_ntop(pi->peer->sa_family, 123969292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 124069292cedSHartmut Brandt client, sizeof(client)) != NULL) { 1241d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 1242d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 1243d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 1244d7eb6b47SHartmut Brandt eval_client(&req)); 1245d7eb6b47SHartmut Brandt return (-1); 1246d7eb6b47SHartmut Brandt } 124781b587f3SRuslan Ermilov } else if (pi->peer->sa_family != AF_LOCAL) 1248d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 1249d7eb6b47SHartmut Brandt #endif 1250d7eb6b47SHartmut Brandt 1251f06ca4afSHartmut Brandt /* 1252f06ca4afSHartmut Brandt * Handle input 1253f06ca4afSHartmut Brandt */ 125470af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 125570af00a1SHartmut Brandt &pi->consumed); 125670af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 125770af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 125870af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 125970af00a1SHartmut Brandt if (pi->stream) { 126070af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 126170af00a1SHartmut Brandt snmpd_stats.silentDrops++; 126270af00a1SHartmut Brandt return (-1); 126370af00a1SHartmut Brandt } 126470af00a1SHartmut Brandt return (0); 126570af00a1SHartmut Brandt } 126670af00a1SHartmut Brandt snmpd_stats.silentDrops++; 126770af00a1SHartmut Brandt return (-1); 126870af00a1SHartmut Brandt } 1269f06ca4afSHartmut Brandt 1270f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 1271f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 1272f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 1273f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 127470af00a1SHartmut Brandt /* for streaming transports this is fatal */ 127570af00a1SHartmut Brandt if (pi->stream) 127670af00a1SHartmut Brandt return (-1); 127770af00a1SHartmut Brandt snmp_input_consume(pi); 127870af00a1SHartmut Brandt return (0); 1279f06ca4afSHartmut Brandt } 1280896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 1281896052c1SHartmut Brandt snmp_input_consume(pi); 1282896052c1SHartmut Brandt return (0); 1283896052c1SHartmut Brandt } 1284f06ca4afSHartmut Brandt 1285f06ca4afSHartmut Brandt /* 1286f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 1287f06ca4afSHartmut Brandt * the hand it over to the module. 1288f06ca4afSHartmut Brandt */ 1289135f7de5SShteryana Shopova if (comm != NULL && comm->owner != NULL && 1290135f7de5SShteryana Shopova comm->owner->config->proxy != NULL) { 129170af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1292896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 1293896052c1SHartmut Brandt !pi->cred || pi->priv); 1294f06ca4afSHartmut Brandt 1295f06ca4afSHartmut Brandt switch (perr) { 1296f06ca4afSHartmut Brandt 1297f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 129870af00a1SHartmut Brandt snmp_input_consume(pi); 129970af00a1SHartmut Brandt return (0); 1300f06ca4afSHartmut Brandt 1301f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 1302f06ca4afSHartmut Brandt break; 1303f06ca4afSHartmut Brandt 1304f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 130570af00a1SHartmut Brandt snmp_input_consume(pi); 1306f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1307f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 130870af00a1SHartmut Brandt return (0); 1309f06ca4afSHartmut Brandt 1310f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 131170af00a1SHartmut Brandt snmp_input_consume(pi); 1312f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1313f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 1314f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1315f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1316896052c1SHartmut Brandt (struct snmp_value *)NULL); 131770af00a1SHartmut Brandt return (0); 1318f06ca4afSHartmut Brandt 1319f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 132070af00a1SHartmut Brandt snmp_input_consume(pi); 1321f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1322f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1323f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1324f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1325896052c1SHartmut Brandt (struct snmp_value *)NULL); 132670af00a1SHartmut Brandt return (0); 1327f06ca4afSHartmut Brandt } 1328f06ca4afSHartmut Brandt } 1329f06ca4afSHartmut Brandt 1330f06ca4afSHartmut Brandt /* 1331f06ca4afSHartmut Brandt * Check type 1332f06ca4afSHartmut Brandt */ 1333f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1334f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1335f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1336f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1337f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1338f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 133970af00a1SHartmut Brandt snmp_input_consume(pi); 134070af00a1SHartmut Brandt return (0); 1341f06ca4afSHartmut Brandt } 1342f06ca4afSHartmut Brandt 1343f06ca4afSHartmut Brandt /* 1344f06ca4afSHartmut Brandt * Check community 1345f06ca4afSHartmut Brandt */ 1346135f7de5SShteryana Shopova if (pdu.version < SNMP_V3 && 1347135f7de5SShteryana Shopova ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 134870af00a1SHartmut Brandt (community != COMM_WRITE && 1349135f7de5SShteryana Shopova (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1350f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1351f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 135270af00a1SHartmut Brandt snmp_input_consume(pi); 1353f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1354896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1355896052c1SHartmut Brandt (struct snmp_value *)NULL); 135670af00a1SHartmut Brandt return (0); 1357f06ca4afSHartmut Brandt } 1358f06ca4afSHartmut Brandt 1359f06ca4afSHartmut Brandt /* 1360f06ca4afSHartmut Brandt * Execute it. 1361f06ca4afSHartmut Brandt */ 1362f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1363f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1364f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 136570af00a1SHartmut Brandt snmp_input_consume(pi); 136670af00a1SHartmut Brandt return (0); 1367f06ca4afSHartmut Brandt } 136870af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 136970af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1370f06ca4afSHartmut Brandt 1371f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 1372f2ddd22eSGleb Smirnoff msg.msg_name = pi->peer; 1373f2ddd22eSGleb Smirnoff msg.msg_namelen = pi->peerlen; 1374f2ddd22eSGleb Smirnoff msg.msg_iov = iov; 1375f2ddd22eSGleb Smirnoff msg.msg_iovlen = 1; 1376f2ddd22eSGleb Smirnoff msg.msg_flags = 0; 1377f2ddd22eSGleb Smirnoff iov[0].iov_base = sndbuf; 1378f2ddd22eSGleb Smirnoff iov[0].iov_len = sndlen; 1379f2ddd22eSGleb Smirnoff 1380f2ddd22eSGleb Smirnoff slen = sendmsg(pi->fd, &msg, 0); 138170af00a1SHartmut Brandt if (slen == -1) 1382f2ddd22eSGleb Smirnoff syslog(LOG_ERR, "sendmsg: %m"); 138370af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 1384f2ddd22eSGleb Smirnoff syslog(LOG_ERR, "sendmsg: short write %zu/%zu", 138570af00a1SHartmut Brandt sndlen, (size_t)slen); 138670af00a1SHartmut Brandt } 138770af00a1SHartmut Brandt snmp_pdu_free(&pdu); 138870af00a1SHartmut Brandt free(sndbuf); 138970af00a1SHartmut Brandt snmp_input_consume(pi); 139070af00a1SHartmut Brandt 139170af00a1SHartmut Brandt return (0); 139270af00a1SHartmut Brandt } 139370af00a1SHartmut Brandt 139470af00a1SHartmut Brandt /* 139570af00a1SHartmut Brandt * Send a PDU to a given port 139670af00a1SHartmut Brandt */ 139770af00a1SHartmut Brandt void 139870af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 139970af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 140070af00a1SHartmut Brandt { 140170af00a1SHartmut Brandt struct transport *trans = targ; 140270af00a1SHartmut Brandt struct tport *tp; 140370af00a1SHartmut Brandt u_char *sndbuf; 140470af00a1SHartmut Brandt size_t sndlen; 140570af00a1SHartmut Brandt ssize_t len; 140670af00a1SHartmut Brandt 140770af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 140870af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 140970af00a1SHartmut Brandt break; 141070af00a1SHartmut Brandt if (tp == 0) 141170af00a1SHartmut Brandt return; 141270af00a1SHartmut Brandt 141370af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 141470af00a1SHartmut Brandt return; 141570af00a1SHartmut Brandt 141670af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 141770af00a1SHartmut Brandt 141870af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 141970af00a1SHartmut Brandt 142070af00a1SHartmut Brandt if (len == -1) 1421f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1422f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1423f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1424f06ca4afSHartmut Brandt sndlen, (size_t)len); 142570af00a1SHartmut Brandt 1426f06ca4afSHartmut Brandt free(sndbuf); 1427f06ca4afSHartmut Brandt } 1428f06ca4afSHartmut Brandt 1429f06ca4afSHartmut Brandt 1430f06ca4afSHartmut Brandt /* 143170af00a1SHartmut Brandt * Close an input source 1432f06ca4afSHartmut Brandt */ 1433f06ca4afSHartmut Brandt void 143470af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1435f06ca4afSHartmut Brandt { 143670af00a1SHartmut Brandt if (pi->id != NULL) 143770af00a1SHartmut Brandt fd_deselect(pi->id); 143870af00a1SHartmut Brandt if (pi->fd >= 0) 143970af00a1SHartmut Brandt (void)close(pi->fd); 144070af00a1SHartmut Brandt if (pi->buf != NULL) 144170af00a1SHartmut Brandt free(pi->buf); 1442f06ca4afSHartmut Brandt } 1443f06ca4afSHartmut Brandt 1444f06ca4afSHartmut Brandt /* 1445f06ca4afSHartmut Brandt * Dump internal state. 1446f06ca4afSHartmut Brandt */ 144770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 144870af00a1SHartmut Brandt static void 144970af00a1SHartmut Brandt info_func(void) 145070af00a1SHartmut Brandt #else 1451f06ca4afSHartmut Brandt static void 1452f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 145370af00a1SHartmut Brandt #endif 1454f06ca4afSHartmut Brandt { 1455f06ca4afSHartmut Brandt struct lmodule *m; 1456f06ca4afSHartmut Brandt u_int i; 1457f06ca4afSHartmut Brandt char buf[10000]; 1458f06ca4afSHartmut Brandt 1459f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1460f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1461f06ca4afSHartmut Brandt switch (tree[i].type) { 1462f06ca4afSHartmut Brandt 1463f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1464f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1465f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1466f06ca4afSHartmut Brandt break; 1467f06ca4afSHartmut Brandt 1468f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1469f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1470f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1471f06ca4afSHartmut Brandt break; 1472f06ca4afSHartmut Brandt } 1473f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1474f06ca4afSHartmut Brandt } 1475f06ca4afSHartmut Brandt 1476f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1477f06ca4afSHartmut Brandt if (m->config->dump) 1478f06ca4afSHartmut Brandt (*m->config->dump)(); 1479f06ca4afSHartmut Brandt } 1480f06ca4afSHartmut Brandt 1481f06ca4afSHartmut Brandt /* 1482f06ca4afSHartmut Brandt * Re-read configuration 1483f06ca4afSHartmut Brandt */ 148470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 148570af00a1SHartmut Brandt static void 148670af00a1SHartmut Brandt config_func(void) 148770af00a1SHartmut Brandt #else 1488f06ca4afSHartmut Brandt static void 1489f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1490f06ca4afSHartmut Brandt const void *tag __unused) 149170af00a1SHartmut Brandt #endif 1492f06ca4afSHartmut Brandt { 1493f06ca4afSHartmut Brandt struct lmodule *m; 1494f06ca4afSHartmut Brandt 1495f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1496f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1497f06ca4afSHartmut Brandt return; 1498f06ca4afSHartmut Brandt } 1499f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1500f06ca4afSHartmut Brandt if (m->config->config) 1501f06ca4afSHartmut Brandt (*m->config->config)(); 1502f06ca4afSHartmut Brandt } 1503f06ca4afSHartmut Brandt 1504f06ca4afSHartmut Brandt /* 1505f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1506f06ca4afSHartmut Brandt */ 1507f06ca4afSHartmut Brandt static void 1508f06ca4afSHartmut Brandt onusr1(int s __unused) 1509f06ca4afSHartmut Brandt { 151070af00a1SHartmut Brandt 1511f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1512f06ca4afSHartmut Brandt } 1513f06ca4afSHartmut Brandt static void 1514f06ca4afSHartmut Brandt onhup(int s __unused) 1515f06ca4afSHartmut Brandt { 151670af00a1SHartmut Brandt 1517f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1518f06ca4afSHartmut Brandt } 1519f06ca4afSHartmut Brandt 1520f06ca4afSHartmut Brandt static void 1521f06ca4afSHartmut Brandt onterm(int s __unused) 1522f06ca4afSHartmut Brandt { 1523f06ca4afSHartmut Brandt 152470af00a1SHartmut Brandt /* allow clean-up */ 1525f06ca4afSHartmut Brandt exit(0); 1526f06ca4afSHartmut Brandt } 1527f06ca4afSHartmut Brandt 1528f06ca4afSHartmut Brandt static void 1529f06ca4afSHartmut Brandt init_sigs(void) 1530f06ca4afSHartmut Brandt { 1531f06ca4afSHartmut Brandt struct sigaction sa; 1532f06ca4afSHartmut Brandt 1533f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1534f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1535f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1536f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1537f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1538f06ca4afSHartmut Brandt exit(1); 1539f06ca4afSHartmut Brandt } 1540f06ca4afSHartmut Brandt 1541f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1542f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1543f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1544f06ca4afSHartmut Brandt exit(1); 1545f06ca4afSHartmut Brandt } 1546f06ca4afSHartmut Brandt 1547f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1548f06ca4afSHartmut Brandt sa.sa_flags = 0; 1549f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1550f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1551f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1552f06ca4afSHartmut Brandt exit(1); 1553f06ca4afSHartmut Brandt } 1554f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1555f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1556f06ca4afSHartmut Brandt exit(1); 1557f06ca4afSHartmut Brandt } 1558f06ca4afSHartmut Brandt } 1559f06ca4afSHartmut Brandt 1560f06ca4afSHartmut Brandt static void 1561f06ca4afSHartmut Brandt block_sigs(void) 1562f06ca4afSHartmut Brandt { 1563f06ca4afSHartmut Brandt sigset_t set; 1564f06ca4afSHartmut Brandt 1565f06ca4afSHartmut Brandt sigfillset(&set); 1566f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1567f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1568f06ca4afSHartmut Brandt exit(1); 1569f06ca4afSHartmut Brandt } 1570f06ca4afSHartmut Brandt } 1571f06ca4afSHartmut Brandt static void 1572f06ca4afSHartmut Brandt unblock_sigs(void) 1573f06ca4afSHartmut Brandt { 1574f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1575f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1576f06ca4afSHartmut Brandt exit(1); 1577f06ca4afSHartmut Brandt } 1578f06ca4afSHartmut Brandt } 1579f06ca4afSHartmut Brandt 1580f06ca4afSHartmut Brandt /* 1581f06ca4afSHartmut Brandt * Shut down 1582f06ca4afSHartmut Brandt */ 1583f06ca4afSHartmut Brandt static void 1584f06ca4afSHartmut Brandt term(void) 1585f06ca4afSHartmut Brandt { 1586f06ca4afSHartmut Brandt (void)unlink(pid_file); 1587f06ca4afSHartmut Brandt } 1588f06ca4afSHartmut Brandt 158970af00a1SHartmut Brandt static void 159070af00a1SHartmut Brandt trans_stop(void) 159170af00a1SHartmut Brandt { 159270af00a1SHartmut Brandt struct transport *t; 159370af00a1SHartmut Brandt 159470af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 159570af00a1SHartmut Brandt (void)t->vtab->stop(1); 159670af00a1SHartmut Brandt } 159770af00a1SHartmut Brandt 1598f06ca4afSHartmut Brandt /* 1599f06ca4afSHartmut Brandt * Define a macro from the command line 1600f06ca4afSHartmut Brandt */ 1601f06ca4afSHartmut Brandt static void 1602f06ca4afSHartmut Brandt do_macro(char *arg) 1603f06ca4afSHartmut Brandt { 1604f06ca4afSHartmut Brandt char *eq; 1605f06ca4afSHartmut Brandt int err; 1606f06ca4afSHartmut Brandt 1607f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1608f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1609f06ca4afSHartmut Brandt else { 1610f06ca4afSHartmut Brandt *eq++ = '\0'; 1611f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1612f06ca4afSHartmut Brandt } 1613f06ca4afSHartmut Brandt if (err == -1) { 1614f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1615f06ca4afSHartmut Brandt exit(1); 1616f06ca4afSHartmut Brandt } 1617f06ca4afSHartmut Brandt } 1618f06ca4afSHartmut Brandt 1619f06ca4afSHartmut Brandt /* 1620f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1621f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1622f06ca4afSHartmut Brandt */ 1623f06ca4afSHartmut Brandt static int 1624f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1625f06ca4afSHartmut Brandt { 1626f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1627f06ca4afSHartmut Brandt u_int i; 1628f06ca4afSHartmut Brandt char *ptr; 1629f06ca4afSHartmut Brandt 1630f06ca4afSHartmut Brandt *optp = NULL; 1631f06ca4afSHartmut Brandt 1632f06ca4afSHartmut Brandt /* skip leading junk */ 1633f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1634f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1635f06ca4afSHartmut Brandt break; 1636f06ca4afSHartmut Brandt if (*ptr == '\0') { 1637f06ca4afSHartmut Brandt *arg = ptr; 1638f06ca4afSHartmut Brandt return (-1); 1639f06ca4afSHartmut Brandt } 1640f06ca4afSHartmut Brandt *optp = ptr; 1641f06ca4afSHartmut Brandt 1642f06ca4afSHartmut Brandt /* find the end of the option */ 1643f06ca4afSHartmut Brandt while (*++ptr != '\0') 1644f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1645f06ca4afSHartmut Brandt break; 1646f06ca4afSHartmut Brandt 1647f06ca4afSHartmut Brandt if (*ptr != '\0') { 1648f06ca4afSHartmut Brandt if (*ptr == '=') { 1649f06ca4afSHartmut Brandt *ptr++ = '\0'; 1650f06ca4afSHartmut Brandt *valp = ptr; 1651f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1652f06ca4afSHartmut Brandt ptr++; 1653f06ca4afSHartmut Brandt if (*ptr != '\0') 1654f06ca4afSHartmut Brandt *ptr++ = '\0'; 1655f06ca4afSHartmut Brandt } else 1656f06ca4afSHartmut Brandt *ptr++ = '\0'; 1657f06ca4afSHartmut Brandt } 1658f06ca4afSHartmut Brandt 1659f06ca4afSHartmut Brandt *arg = ptr; 1660f06ca4afSHartmut Brandt 1661f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 166270af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1663f06ca4afSHartmut Brandt return (i); 1664f06ca4afSHartmut Brandt return (-1); 1665f06ca4afSHartmut Brandt } 1666f06ca4afSHartmut Brandt 1667f06ca4afSHartmut Brandt int 1668f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1669f06ca4afSHartmut Brandt { 1670f06ca4afSHartmut Brandt int opt; 1671f06ca4afSHartmut Brandt FILE *fp; 1672f06ca4afSHartmut Brandt int background = 1; 167370af00a1SHartmut Brandt struct tport *p; 1674f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1675f06ca4afSHartmut Brandt struct lmodule *m; 1676135f7de5SShteryana Shopova char *value = NULL, *option; /* XXX */ 167770af00a1SHartmut Brandt struct transport *t; 1678f06ca4afSHartmut Brandt 1679f06ca4afSHartmut Brandt #define DBG_DUMP 0 1680f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1681f06ca4afSHartmut Brandt #define DBG_TRACE 2 1682f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1683f06ca4afSHartmut Brandt "dump", 1684f06ca4afSHartmut Brandt "events", 1685f06ca4afSHartmut Brandt "trace", 1686f06ca4afSHartmut Brandt NULL 1687f06ca4afSHartmut Brandt }; 1688f06ca4afSHartmut Brandt 1689f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1690f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1691f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1692f06ca4afSHartmut Brandt asn_error = asn_error_func; 1693f06ca4afSHartmut Brandt 1694135f7de5SShteryana Shopova while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1695f06ca4afSHartmut Brandt switch (opt) { 1696f06ca4afSHartmut Brandt 1697f06ca4afSHartmut Brandt case 'c': 1698f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1699f06ca4afSHartmut Brandt break; 1700f06ca4afSHartmut Brandt 1701f06ca4afSHartmut Brandt case 'd': 1702f06ca4afSHartmut Brandt background = 0; 1703f06ca4afSHartmut Brandt break; 1704f06ca4afSHartmut Brandt 1705f06ca4afSHartmut Brandt case 'D': 1706f06ca4afSHartmut Brandt while (*optarg) { 1707f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1708f06ca4afSHartmut Brandt &value, &option)) { 1709f06ca4afSHartmut Brandt 1710f06ca4afSHartmut Brandt case DBG_DUMP: 1711f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1712f06ca4afSHartmut Brandt break; 1713f06ca4afSHartmut Brandt 1714f06ca4afSHartmut Brandt case DBG_EVENTS: 1715f06ca4afSHartmut Brandt debug.evdebug++; 1716f06ca4afSHartmut Brandt break; 1717f06ca4afSHartmut Brandt 1718f06ca4afSHartmut Brandt case DBG_TRACE: 1719f06ca4afSHartmut Brandt if (value == NULL) 1720f06ca4afSHartmut Brandt syslog(LOG_ERR, 1721f06ca4afSHartmut Brandt "no value for 'trace'"); 172251054003SHartmut Brandt else 1723748b5b1eSHartmut Brandt snmp_trace = strtoul(value, 1724748b5b1eSHartmut Brandt NULL, 0); 1725f06ca4afSHartmut Brandt break; 1726f06ca4afSHartmut Brandt 1727f06ca4afSHartmut Brandt case -1: 1728f06ca4afSHartmut Brandt if (suboptarg) 1729f06ca4afSHartmut Brandt syslog(LOG_ERR, 1730f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1731f06ca4afSHartmut Brandt option); 1732f06ca4afSHartmut Brandt else 1733f06ca4afSHartmut Brandt syslog(LOG_ERR, 1734f06ca4afSHartmut Brandt "missing debug flag"); 1735f06ca4afSHartmut Brandt break; 1736f06ca4afSHartmut Brandt } 1737f06ca4afSHartmut Brandt } 1738f06ca4afSHartmut Brandt break; 1739f06ca4afSHartmut Brandt 1740135f7de5SShteryana Shopova case 'e': 1741135f7de5SShteryana Shopova strlcpy(engine_file, optarg, sizeof(engine_file)); 1742135f7de5SShteryana Shopova break; 1743f06ca4afSHartmut Brandt case 'h': 1744f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1745f06ca4afSHartmut Brandt exit(0); 1746f06ca4afSHartmut Brandt 1747f06ca4afSHartmut Brandt case 'I': 1748f06ca4afSHartmut Brandt syspath = optarg; 1749f06ca4afSHartmut Brandt break; 1750f06ca4afSHartmut Brandt 1751f06ca4afSHartmut Brandt case 'l': 1752f06ca4afSHartmut Brandt prefix = optarg; 1753f06ca4afSHartmut Brandt break; 1754f06ca4afSHartmut Brandt 1755f06ca4afSHartmut Brandt case 'm': 1756f06ca4afSHartmut Brandt do_macro(optarg); 1757f06ca4afSHartmut Brandt break; 1758f06ca4afSHartmut Brandt 1759f06ca4afSHartmut Brandt case 'p': 1760f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1761f06ca4afSHartmut Brandt break; 1762f06ca4afSHartmut Brandt } 1763f06ca4afSHartmut Brandt 1764f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1765f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1766f06ca4afSHartmut Brandt 1767f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1768f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1769f06ca4afSHartmut Brandt exit(1); 1770f06ca4afSHartmut Brandt } 1771f06ca4afSHartmut Brandt 1772f06ca4afSHartmut Brandt argc -= optind; 1773f06ca4afSHartmut Brandt argv += optind; 1774f06ca4afSHartmut Brandt 1775f06ca4afSHartmut Brandt progargs = argv; 1776f06ca4afSHartmut Brandt nprogargs = argc; 1777f06ca4afSHartmut Brandt 1778f06ca4afSHartmut Brandt srandomdev(); 1779f06ca4afSHartmut Brandt 1780f06ca4afSHartmut Brandt snmp_serial_no = random(); 1781f06ca4afSHartmut Brandt 1782d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1783d7eb6b47SHartmut Brandt /* 1784d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1785d7eb6b47SHartmut Brandt */ 1786d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1787d7eb6b47SHartmut Brandt sock_methods(&req); 1788d7eb6b47SHartmut Brandt #endif 1789d7eb6b47SHartmut Brandt 1790f06ca4afSHartmut Brandt /* 1791f06ca4afSHartmut Brandt * Initialize the tree. 1792f06ca4afSHartmut Brandt */ 1793f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1794f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1795f06ca4afSHartmut Brandt exit(1); 1796f06ca4afSHartmut Brandt } 1797f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1798f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1799f06ca4afSHartmut Brandt 1800f06ca4afSHartmut Brandt /* 1801f06ca4afSHartmut Brandt * Get standard communities 1802f06ca4afSHartmut Brandt */ 1803d4199d75SHartmut Brandt (void)comm_define(1, "SNMP read", NULL, NULL); 1804d4199d75SHartmut Brandt (void)comm_define(2, "SNMP write", NULL, NULL); 1805f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1806f06ca4afSHartmut Brandt 1807f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1808f06ca4afSHartmut Brandt 1809f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1810f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1811f06ca4afSHartmut Brandt 1812f06ca4afSHartmut Brandt init_actvals(); 1813135f7de5SShteryana Shopova init_snmpd_engine(); 181470af00a1SHartmut Brandt 181570af00a1SHartmut Brandt this_tick = get_ticks(); 181669292cedSHartmut Brandt start_tick = this_tick; 181770af00a1SHartmut Brandt 181870af00a1SHartmut Brandt /* start transports */ 181970af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 182070af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 182170af00a1SHartmut Brandt exit(1); 182270af00a1SHartmut Brandt } 182370af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 182470af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 182570af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 182670af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 182770af00a1SHartmut Brandt 182870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 182970af00a1SHartmut Brandt if (debug.evdebug > 0) 183070af00a1SHartmut Brandt rpoll_trace = 1; 183170af00a1SHartmut Brandt #else 1832f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1833f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1834f06ca4afSHartmut Brandt exit(1); 1835f06ca4afSHartmut Brandt } 1836f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1837f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 183870af00a1SHartmut Brandt #endif 1839f06ca4afSHartmut Brandt 1840135f7de5SShteryana Shopova if (engine_file[0] == '\0') 1841135f7de5SShteryana Shopova snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1842135f7de5SShteryana Shopova 1843896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1844896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1845896052c1SHartmut Brandt exit(1); 1846896052c1SHartmut Brandt } 1847896052c1SHartmut Brandt 184870af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 184970af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 185070af00a1SHartmut Brandt t->vtab->init_port(p); 1851f06ca4afSHartmut Brandt 1852f06ca4afSHartmut Brandt init_sigs(); 1853f06ca4afSHartmut Brandt 1854f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1855f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1856f06ca4afSHartmut Brandt 1857f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1858f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1859f06ca4afSHartmut Brandt fclose(fp); 186070af00a1SHartmut Brandt if (atexit(term) == -1) { 186170af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 186270af00a1SHartmut Brandt (void)remove(pid_file); 186370af00a1SHartmut Brandt exit(0); 1864f06ca4afSHartmut Brandt } 186570af00a1SHartmut Brandt } 1866f06ca4afSHartmut Brandt 1867f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1868f06ca4afSHartmut Brandt NULL) == 0) { 1869f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1870f06ca4afSHartmut Brandt exit(1); 1871f06ca4afSHartmut Brandt } 1872f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1873f06ca4afSHartmut Brandt NULL) == 0) { 1874f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1875f06ca4afSHartmut Brandt exit(1); 1876f06ca4afSHartmut Brandt } 1877f06ca4afSHartmut Brandt 1878f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1879f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1880f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1881f06ca4afSHartmut Brandt lm_start(m); 1882f06ca4afSHartmut Brandt } 1883f06ca4afSHartmut Brandt 188472cd7a52SShteryana Shopova snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 188572cd7a52SShteryana Shopova 1886f06ca4afSHartmut Brandt for (;;) { 188770af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1888f06ca4afSHartmut Brandt evEvent event; 188970af00a1SHartmut Brandt #endif 1890f06ca4afSHartmut Brandt struct lmodule *mod; 1891f06ca4afSHartmut Brandt 1892f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1893f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1894f06ca4afSHartmut Brandt (*mod->config->idle)(); 1895f06ca4afSHartmut Brandt 189670af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1897f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1898f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1899f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1900f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1901f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1902f06ca4afSHartmut Brandt exit(1); 1903f06ca4afSHartmut Brandt } 190470af00a1SHartmut Brandt #else 190570af00a1SHartmut Brandt poll_dispatch(1); 190670af00a1SHartmut Brandt #endif 1907f06ca4afSHartmut Brandt 1908f06ca4afSHartmut Brandt if (work != 0) { 1909f06ca4afSHartmut Brandt block_sigs(); 1910f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 191170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 191270af00a1SHartmut Brandt info_func(); 191370af00a1SHartmut Brandt #else 1914f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1915f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1916f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1917f06ca4afSHartmut Brandt exit(1); 1918f06ca4afSHartmut Brandt } 191970af00a1SHartmut Brandt #endif 1920f06ca4afSHartmut Brandt } 1921f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 192270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 192370af00a1SHartmut Brandt config_func(); 192470af00a1SHartmut Brandt #else 1925f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1926f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1927f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1928f06ca4afSHartmut Brandt exit(1); 1929f06ca4afSHartmut Brandt } 193070af00a1SHartmut Brandt #endif 1931f06ca4afSHartmut Brandt } 1932f06ca4afSHartmut Brandt work = 0; 1933f06ca4afSHartmut Brandt unblock_sigs(); 193470af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1935f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1936f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1937f06ca4afSHartmut Brandt exit(1); 1938f06ca4afSHartmut Brandt } 193970af00a1SHartmut Brandt #endif 1940f06ca4afSHartmut Brandt } 1941f06ca4afSHartmut Brandt } 1942f06ca4afSHartmut Brandt 1943f06ca4afSHartmut Brandt return (0); 1944f06ca4afSHartmut Brandt } 1945f06ca4afSHartmut Brandt 194669292cedSHartmut Brandt uint64_t 1947135f7de5SShteryana Shopova get_ticks(void) 1948f06ca4afSHartmut Brandt { 1949f06ca4afSHartmut Brandt struct timeval tv; 195069292cedSHartmut Brandt uint64_t ret; 1951f06ca4afSHartmut Brandt 1952f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1953f06ca4afSHartmut Brandt abort(); 195469292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1955f06ca4afSHartmut Brandt return (ret); 1956f06ca4afSHartmut Brandt } 195769292cedSHartmut Brandt 1958f06ca4afSHartmut Brandt /* 1959f06ca4afSHartmut Brandt * Timer support 1960f06ca4afSHartmut Brandt */ 1961165c5d31SHartmut Brandt 1962165c5d31SHartmut Brandt /* 1963165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1964165c5d31SHartmut Brandt */ 196570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 196670af00a1SHartmut Brandt static void 196770af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 196870af00a1SHartmut Brandt #else 1969f06ca4afSHartmut Brandt static void 1970f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1971f06ca4afSHartmut Brandt struct timespec inter __unused) 197270af00a1SHartmut Brandt #endif 1973f06ca4afSHartmut Brandt { 1974f06ca4afSHartmut Brandt struct timer *tp = uap; 1975f06ca4afSHartmut Brandt 1976f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1977f06ca4afSHartmut Brandt tp->func(tp->udata); 1978f06ca4afSHartmut Brandt free(tp); 1979f06ca4afSHartmut Brandt } 1980f06ca4afSHartmut Brandt 1981f06ca4afSHartmut Brandt /* 1982165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1983165c5d31SHartmut Brandt */ 1984165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1985165c5d31SHartmut Brandt static void 1986165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1987165c5d31SHartmut Brandt #else 1988165c5d31SHartmut Brandt static void 1989165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1990165c5d31SHartmut Brandt struct timespec inter __unused) 1991165c5d31SHartmut Brandt #endif 1992165c5d31SHartmut Brandt { 1993165c5d31SHartmut Brandt struct timer *tp = uap; 1994165c5d31SHartmut Brandt 1995165c5d31SHartmut Brandt tp->func(tp->udata); 1996165c5d31SHartmut Brandt } 1997165c5d31SHartmut Brandt 1998165c5d31SHartmut Brandt /* 1999165c5d31SHartmut Brandt * Start a one-shot timer 2000f06ca4afSHartmut Brandt */ 2001f06ca4afSHartmut Brandt void * 2002f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 2003f06ca4afSHartmut Brandt { 2004f06ca4afSHartmut Brandt struct timer *tp; 2005a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 2006f06ca4afSHartmut Brandt struct timespec due; 200770af00a1SHartmut Brandt #endif 2008f06ca4afSHartmut Brandt 2009f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 2010f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 2011f06ca4afSHartmut Brandt exit(1); 2012f06ca4afSHartmut Brandt } 2013a9bfedb7SHartmut Brandt 2014a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 2015f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 2016f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 201770af00a1SHartmut Brandt #endif 2018f06ca4afSHartmut Brandt 2019f06ca4afSHartmut Brandt tp->udata = udata; 2020f06ca4afSHartmut Brandt tp->owner = mod; 2021f06ca4afSHartmut Brandt tp->func = func; 2022f06ca4afSHartmut Brandt 2023f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 2024f06ca4afSHartmut Brandt 202570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 2026a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 202770af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 202870af00a1SHartmut Brandt exit(1); 202970af00a1SHartmut Brandt } 203070af00a1SHartmut Brandt #else 2031f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 2032f06ca4afSHartmut Brandt == -1) { 2033f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2034f06ca4afSHartmut Brandt exit(1); 2035f06ca4afSHartmut Brandt } 203670af00a1SHartmut Brandt #endif 2037f06ca4afSHartmut Brandt return (tp); 2038f06ca4afSHartmut Brandt } 2039f06ca4afSHartmut Brandt 2040165c5d31SHartmut Brandt /* 2041165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 2042165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 2043165c5d31SHartmut Brandt * repeat number of ticks. 2044165c5d31SHartmut Brandt */ 2045165c5d31SHartmut Brandt void * 2046165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 2047165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 2048165c5d31SHartmut Brandt { 2049165c5d31SHartmut Brandt struct timer *tp; 2050165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 2051165c5d31SHartmut Brandt struct timespec due; 2052165c5d31SHartmut Brandt struct timespec inter; 2053165c5d31SHartmut Brandt #endif 2054165c5d31SHartmut Brandt 2055165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 2056165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 2057165c5d31SHartmut Brandt exit(1); 2058165c5d31SHartmut Brandt } 2059165c5d31SHartmut Brandt 2060165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 2061165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 2062165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 2063165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 2064165c5d31SHartmut Brandt #endif 2065165c5d31SHartmut Brandt 2066165c5d31SHartmut Brandt tp->udata = udata; 2067165c5d31SHartmut Brandt tp->owner = mod; 2068165c5d31SHartmut Brandt tp->func = func; 2069165c5d31SHartmut Brandt 2070165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 2071165c5d31SHartmut Brandt 2072165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 2073165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 2074165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2075165c5d31SHartmut Brandt exit(1); 2076165c5d31SHartmut Brandt } 2077165c5d31SHartmut Brandt #else 2078165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 2079165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2080165c5d31SHartmut Brandt exit(1); 2081165c5d31SHartmut Brandt } 2082165c5d31SHartmut Brandt #endif 2083165c5d31SHartmut Brandt return (tp); 2084165c5d31SHartmut Brandt } 2085165c5d31SHartmut Brandt 2086165c5d31SHartmut Brandt /* 2087165c5d31SHartmut Brandt * Stop a timer. 2088165c5d31SHartmut Brandt */ 2089f06ca4afSHartmut Brandt void 2090f06ca4afSHartmut Brandt timer_stop(void *p) 2091f06ca4afSHartmut Brandt { 2092f06ca4afSHartmut Brandt struct timer *tp = p; 2093f06ca4afSHartmut Brandt 2094f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 209570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 209670af00a1SHartmut Brandt poll_stop_timer(tp->id); 209770af00a1SHartmut Brandt #else 2098f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 2099f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 2100f06ca4afSHartmut Brandt exit(1); 2101f06ca4afSHartmut Brandt } 210270af00a1SHartmut Brandt #endif 2103f06ca4afSHartmut Brandt free(p); 2104f06ca4afSHartmut Brandt } 2105f06ca4afSHartmut Brandt 2106f06ca4afSHartmut Brandt static void 2107f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 2108f06ca4afSHartmut Brandt { 2109f06ca4afSHartmut Brandt struct timer *t, *t1; 2110f06ca4afSHartmut Brandt 2111f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 2112f06ca4afSHartmut Brandt while (t != NULL) { 2113f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 2114f06ca4afSHartmut Brandt if (t->owner == mod) 2115f06ca4afSHartmut Brandt timer_stop(t); 2116f06ca4afSHartmut Brandt t = t1; 2117f06ca4afSHartmut Brandt } 2118f06ca4afSHartmut Brandt } 2119f06ca4afSHartmut Brandt 2120f06ca4afSHartmut Brandt static void 2121f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 2122f06ca4afSHartmut Brandt { 2123f06ca4afSHartmut Brandt va_list ap; 2124f06ca4afSHartmut Brandt static char *pend = NULL; 2125f06ca4afSHartmut Brandt char *ret, *new; 2126f06ca4afSHartmut Brandt 2127f06ca4afSHartmut Brandt va_start(ap, fmt); 2128f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 2129f06ca4afSHartmut Brandt va_end(ap); 2130f06ca4afSHartmut Brandt 2131f06ca4afSHartmut Brandt if (ret == NULL) 2132f06ca4afSHartmut Brandt return; 2133f06ca4afSHartmut Brandt if (pend != NULL) { 2134f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 2135f06ca4afSHartmut Brandt == NULL) { 2136f06ca4afSHartmut Brandt free(ret); 2137f06ca4afSHartmut Brandt return; 2138f06ca4afSHartmut Brandt } 2139f06ca4afSHartmut Brandt pend = new; 2140f06ca4afSHartmut Brandt strcat(pend, ret); 2141f06ca4afSHartmut Brandt free(ret); 2142f06ca4afSHartmut Brandt } else 2143f06ca4afSHartmut Brandt pend = ret; 2144f06ca4afSHartmut Brandt 2145f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 2146f06ca4afSHartmut Brandt *ret = '\0'; 2147f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 2148f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 2149f06ca4afSHartmut Brandt free(pend); 2150f06ca4afSHartmut Brandt pend = NULL; 2151f06ca4afSHartmut Brandt break; 2152f06ca4afSHartmut Brandt } 2153f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 2154f06ca4afSHartmut Brandt } 2155f06ca4afSHartmut Brandt } 2156f06ca4afSHartmut Brandt 2157f06ca4afSHartmut Brandt static void 2158f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 2159f06ca4afSHartmut Brandt { 2160f06ca4afSHartmut Brandt char errbuf[1000]; 2161f06ca4afSHartmut Brandt va_list ap; 2162f06ca4afSHartmut Brandt 216370af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 216470af00a1SHartmut Brandt return; 216570af00a1SHartmut Brandt 2166f06ca4afSHartmut Brandt va_start(ap, err); 2167f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 216870af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 216970af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2170f06ca4afSHartmut Brandt va_end(ap); 2171f06ca4afSHartmut Brandt 2172f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2173f06ca4afSHartmut Brandt } 2174f06ca4afSHartmut Brandt 2175f06ca4afSHartmut Brandt static void 2176f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 2177f06ca4afSHartmut Brandt { 2178f06ca4afSHartmut Brandt char errbuf[1000]; 2179f06ca4afSHartmut Brandt va_list ap; 2180f06ca4afSHartmut Brandt 2181f06ca4afSHartmut Brandt va_start(ap, err); 2182f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2183f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2184f06ca4afSHartmut Brandt err, ap); 2185f06ca4afSHartmut Brandt va_end(ap); 2186f06ca4afSHartmut Brandt 2187f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 2188f06ca4afSHartmut Brandt } 2189f06ca4afSHartmut Brandt 2190f06ca4afSHartmut Brandt static void 2191f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 2192f06ca4afSHartmut Brandt { 2193f06ca4afSHartmut Brandt char errbuf[1000]; 2194f06ca4afSHartmut Brandt va_list ap; 2195f06ca4afSHartmut Brandt u_int i; 2196f06ca4afSHartmut Brandt 219770af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 219870af00a1SHartmut Brandt return; 219970af00a1SHartmut Brandt 2200f06ca4afSHartmut Brandt va_start(ap, err); 2201f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 220270af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 220370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2204f06ca4afSHartmut Brandt va_end(ap); 2205f06ca4afSHartmut Brandt 2206f06ca4afSHartmut Brandt if (b != NULL) { 220770af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 220870af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 2209f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 2210f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 221170af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 221270af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 2213f06ca4afSHartmut Brandt } 2214f06ca4afSHartmut Brandt 2215f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2216f06ca4afSHartmut Brandt } 2217f06ca4afSHartmut Brandt 2218f06ca4afSHartmut Brandt /* 2219f06ca4afSHartmut Brandt * Create a new community 2220f06ca4afSHartmut Brandt */ 2221f06ca4afSHartmut Brandt u_int 2222f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 2223f06ca4afSHartmut Brandt const char *str) 2224f06ca4afSHartmut Brandt { 2225f06ca4afSHartmut Brandt struct community *c, *p; 2226f06ca4afSHartmut Brandt u_int ncomm; 2227f06ca4afSHartmut Brandt 2228f06ca4afSHartmut Brandt /* generate an identifier */ 2229f06ca4afSHartmut Brandt do { 2230f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 2231f06ca4afSHartmut Brandt next_community_index = 1; 2232f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 2233f06ca4afSHartmut Brandt if (c->value == ncomm) 2234f06ca4afSHartmut Brandt break; 2235f06ca4afSHartmut Brandt } while (c != NULL); 2236f06ca4afSHartmut Brandt 2237f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 2238f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 2239f06ca4afSHartmut Brandt return (0); 2240f06ca4afSHartmut Brandt } 2241f06ca4afSHartmut Brandt c->owner = owner; 2242f06ca4afSHartmut Brandt c->value = ncomm; 2243f06ca4afSHartmut Brandt c->descr = descr; 2244f06ca4afSHartmut Brandt c->string = NULL; 2245f06ca4afSHartmut Brandt c->private = priv; 2246f06ca4afSHartmut Brandt 2247f06ca4afSHartmut Brandt if (str != NULL) { 2248f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 2249f06ca4afSHartmut Brandt free(c); 2250f06ca4afSHartmut Brandt return (0); 2251f06ca4afSHartmut Brandt } 2252f06ca4afSHartmut Brandt strcpy(c->string, str); 2253f06ca4afSHartmut Brandt } 2254f06ca4afSHartmut Brandt 2255f06ca4afSHartmut Brandt /* make index */ 2256f06ca4afSHartmut Brandt if (c->owner == NULL) { 2257f06ca4afSHartmut Brandt c->index.len = 1; 2258f06ca4afSHartmut Brandt c->index.subs[0] = 0; 2259f06ca4afSHartmut Brandt } else { 2260f06ca4afSHartmut Brandt c->index = c->owner->index; 2261f06ca4afSHartmut Brandt } 2262f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 2263f06ca4afSHartmut Brandt 2264f06ca4afSHartmut Brandt /* 2265f06ca4afSHartmut Brandt * Insert ordered 2266f06ca4afSHartmut Brandt */ 2267f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 2268f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 2269f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 2270f06ca4afSHartmut Brandt break; 2271f06ca4afSHartmut Brandt } 2272f06ca4afSHartmut Brandt } 2273f06ca4afSHartmut Brandt if (p == NULL) 2274f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 2275f06ca4afSHartmut Brandt return (c->value); 2276f06ca4afSHartmut Brandt } 2277f06ca4afSHartmut Brandt 2278f06ca4afSHartmut Brandt const char * 2279f06ca4afSHartmut Brandt comm_string(u_int ncomm) 2280f06ca4afSHartmut Brandt { 2281f06ca4afSHartmut Brandt struct community *p; 2282f06ca4afSHartmut Brandt 2283f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 2284f06ca4afSHartmut Brandt if (p->value == ncomm) 2285f06ca4afSHartmut Brandt return (p->string); 2286f06ca4afSHartmut Brandt return (NULL); 2287f06ca4afSHartmut Brandt } 2288f06ca4afSHartmut Brandt 2289f06ca4afSHartmut Brandt /* 2290f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2291f06ca4afSHartmut Brandt */ 2292f06ca4afSHartmut Brandt static void 2293f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 2294f06ca4afSHartmut Brandt { 2295f06ca4afSHartmut Brandt struct community *p, *p1; 2296f06ca4afSHartmut Brandt 2297f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 2298f06ca4afSHartmut Brandt while (p != NULL) { 2299f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2300f06ca4afSHartmut Brandt if (p->owner == mod) { 2301f06ca4afSHartmut Brandt free(p->string); 2302f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 2303f06ca4afSHartmut Brandt free(p); 2304f06ca4afSHartmut Brandt } 2305f06ca4afSHartmut Brandt p = p1; 2306f06ca4afSHartmut Brandt } 2307f06ca4afSHartmut Brandt } 2308f06ca4afSHartmut Brandt 2309f06ca4afSHartmut Brandt /* 2310f06ca4afSHartmut Brandt * Request ID handling. 2311f06ca4afSHartmut Brandt * 2312f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 2313f06ca4afSHartmut Brandt */ 2314f06ca4afSHartmut Brandt u_int 2315f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 2316f06ca4afSHartmut Brandt { 2317f06ca4afSHartmut Brandt u_int type; 2318f06ca4afSHartmut Brandt struct idrange *r, *r1; 2319f06ca4afSHartmut Brandt 2320f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 2321f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2322f06ca4afSHartmut Brandt return (0); 2323f06ca4afSHartmut Brandt } 2324f06ca4afSHartmut Brandt /* allocate a type id */ 2325f06ca4afSHartmut Brandt do { 2326f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 2327f06ca4afSHartmut Brandt next_idrange = 1; 2328f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2329f06ca4afSHartmut Brandt if (r->type == type) 2330f06ca4afSHartmut Brandt break; 2331f06ca4afSHartmut Brandt } while(r != NULL); 2332f06ca4afSHartmut Brandt 2333f06ca4afSHartmut Brandt /* find a range */ 2334f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 2335f06ca4afSHartmut Brandt r = NULL; 2336f06ca4afSHartmut Brandt else { 2337f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 2338f06ca4afSHartmut Brandt if (r->base < size) { 2339f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2340f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 2341f06ca4afSHartmut Brandt break; 2342f06ca4afSHartmut Brandt r = r1; 2343f06ca4afSHartmut Brandt } 2344f06ca4afSHartmut Brandt r = r1; 2345f06ca4afSHartmut Brandt } 2346f06ca4afSHartmut Brandt if (r == NULL) { 2347f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2348f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2349f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2350f06ca4afSHartmut Brandt return (0); 2351f06ca4afSHartmut Brandt } 2352f06ca4afSHartmut Brandt } 2353f06ca4afSHartmut Brandt } 2354f06ca4afSHartmut Brandt 2355f06ca4afSHartmut Brandt /* allocate structure */ 2356f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2357f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2358f06ca4afSHartmut Brandt return (0); 2359f06ca4afSHartmut Brandt } 2360f06ca4afSHartmut Brandt 2361f06ca4afSHartmut Brandt r1->type = type; 2362f06ca4afSHartmut Brandt r1->size = size; 2363f06ca4afSHartmut Brandt r1->owner = mod; 2364f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2365f06ca4afSHartmut Brandt r1->base = 0; 2366f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2367f06ca4afSHartmut Brandt } else if (r == NULL) { 2368f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2369f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2370f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2371f06ca4afSHartmut Brandt } else { 2372f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2373f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2374f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2375f06ca4afSHartmut Brandt } 2376f06ca4afSHartmut Brandt r1->next = r1->base; 2377f06ca4afSHartmut Brandt 2378f06ca4afSHartmut Brandt return (type); 2379f06ca4afSHartmut Brandt } 2380f06ca4afSHartmut Brandt 2381f06ca4afSHartmut Brandt int32_t 2382f06ca4afSHartmut Brandt reqid_next(u_int type) 2383f06ca4afSHartmut Brandt { 2384f06ca4afSHartmut Brandt struct idrange *r; 2385f06ca4afSHartmut Brandt int32_t id; 2386f06ca4afSHartmut Brandt 2387f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2388f06ca4afSHartmut Brandt if (r->type == type) 2389f06ca4afSHartmut Brandt break; 2390f06ca4afSHartmut Brandt if (r == NULL) { 2391f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2392f06ca4afSHartmut Brandt abort(); 2393f06ca4afSHartmut Brandt } 2394f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2395f06ca4afSHartmut Brandt r->next = r->base; 2396f06ca4afSHartmut Brandt return (id); 2397f06ca4afSHartmut Brandt } 2398f06ca4afSHartmut Brandt 2399f06ca4afSHartmut Brandt int32_t 2400f06ca4afSHartmut Brandt reqid_base(u_int type) 2401f06ca4afSHartmut Brandt { 2402f06ca4afSHartmut Brandt struct idrange *r; 2403f06ca4afSHartmut Brandt 2404f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2405f06ca4afSHartmut Brandt if (r->type == type) 2406f06ca4afSHartmut Brandt return (r->base); 2407f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2408f06ca4afSHartmut Brandt abort(); 2409f06ca4afSHartmut Brandt } 2410f06ca4afSHartmut Brandt 2411f06ca4afSHartmut Brandt u_int 2412f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2413f06ca4afSHartmut Brandt { 2414f06ca4afSHartmut Brandt struct idrange *r; 2415f06ca4afSHartmut Brandt 2416f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2417f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2418f06ca4afSHartmut Brandt return (r->type); 2419f06ca4afSHartmut Brandt return (0); 2420f06ca4afSHartmut Brandt } 2421f06ca4afSHartmut Brandt 2422f06ca4afSHartmut Brandt int 2423f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2424f06ca4afSHartmut Brandt { 2425f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2426f06ca4afSHartmut Brandt } 2427f06ca4afSHartmut Brandt 2428f06ca4afSHartmut Brandt /* 2429f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2430f06ca4afSHartmut Brandt */ 2431f06ca4afSHartmut Brandt static void 2432f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2433f06ca4afSHartmut Brandt { 2434f06ca4afSHartmut Brandt struct idrange *p, *p1; 2435f06ca4afSHartmut Brandt 2436f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2437f06ca4afSHartmut Brandt while (p != NULL) { 2438f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2439f06ca4afSHartmut Brandt if (p->owner == mod) { 2440f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2441f06ca4afSHartmut Brandt free(p); 2442f06ca4afSHartmut Brandt } 2443f06ca4afSHartmut Brandt p = p1; 2444f06ca4afSHartmut Brandt } 2445f06ca4afSHartmut Brandt } 2446f06ca4afSHartmut Brandt 2447f06ca4afSHartmut Brandt /* 2448f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2449f06ca4afSHartmut Brandt */ 2450f06ca4afSHartmut Brandt static int 2451f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2452f06ca4afSHartmut Brandt { 2453f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2454f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2455f06ca4afSHartmut Brandt 2456f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2457f06ca4afSHartmut Brandt } 2458f06ca4afSHartmut Brandt static int 2459f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2460f06ca4afSHartmut Brandt { 2461f06ca4afSHartmut Brandt struct snmp_node *xtree; 2462f06ca4afSHartmut Brandt u_int i; 2463f06ca4afSHartmut Brandt 2464f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2465f06ca4afSHartmut Brandt if (xtree == NULL) { 24668eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2467f06ca4afSHartmut Brandt return (-1); 2468f06ca4afSHartmut Brandt } 2469f06ca4afSHartmut Brandt tree = xtree; 2470f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2471f06ca4afSHartmut Brandt 2472f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 24738eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2474f06ca4afSHartmut Brandt 2475f06ca4afSHartmut Brandt tree_size += nsize; 2476f06ca4afSHartmut Brandt 2477f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2478f06ca4afSHartmut Brandt 2479f06ca4afSHartmut Brandt return (0); 2480f06ca4afSHartmut Brandt } 2481f06ca4afSHartmut Brandt 2482f06ca4afSHartmut Brandt /* 2483f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2484f06ca4afSHartmut Brandt */ 2485f06ca4afSHartmut Brandt static void 2486f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2487f06ca4afSHartmut Brandt { 2488f06ca4afSHartmut Brandt u_int s, d; 2489f06ca4afSHartmut Brandt 2490f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 24918eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2492f06ca4afSHartmut Brandt if (s != d) 2493f06ca4afSHartmut Brandt tree[d] = tree[s]; 2494f06ca4afSHartmut Brandt d++; 2495f06ca4afSHartmut Brandt } 2496f06ca4afSHartmut Brandt tree_size = d; 2497f06ca4afSHartmut Brandt } 2498f06ca4afSHartmut Brandt 2499f06ca4afSHartmut Brandt /* 2500f06ca4afSHartmut Brandt * Loadable modules 2501f06ca4afSHartmut Brandt */ 2502f06ca4afSHartmut Brandt struct lmodule * 2503f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2504f06ca4afSHartmut Brandt { 2505f06ca4afSHartmut Brandt struct lmodule *m; 2506f06ca4afSHartmut Brandt int err; 2507f06ca4afSHartmut Brandt int i; 2508f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2509f06ca4afSHartmut Brandt int ac; 2510f06ca4afSHartmut Brandt u_int u; 2511f06ca4afSHartmut Brandt 2512f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2513f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2514f06ca4afSHartmut Brandt return (NULL); 2515f06ca4afSHartmut Brandt } 2516f06ca4afSHartmut Brandt m->handle = NULL; 2517f06ca4afSHartmut Brandt m->flags = 0; 2518f06ca4afSHartmut Brandt strcpy(m->section, section); 2519f06ca4afSHartmut Brandt 2520f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2521f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2522f06ca4afSHartmut Brandt goto err; 2523f06ca4afSHartmut Brandt } 2524f06ca4afSHartmut Brandt strcpy(m->path, path); 2525f06ca4afSHartmut Brandt 2526f06ca4afSHartmut Brandt /* 2527f06ca4afSHartmut Brandt * Make index 2528f06ca4afSHartmut Brandt */ 2529f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2530f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2531f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2532f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2533f06ca4afSHartmut Brandt 2534f06ca4afSHartmut Brandt /* 2535f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2536f06ca4afSHartmut Brandt */ 2537f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2538f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2539f06ca4afSHartmut Brandt goto err; 2540f06ca4afSHartmut Brandt } 2541f06ca4afSHartmut Brandt 2542f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2543f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2544f06ca4afSHartmut Brandt goto err; 2545f06ca4afSHartmut Brandt } 2546f06ca4afSHartmut Brandt 2547f06ca4afSHartmut Brandt /* 2548f06ca4afSHartmut Brandt * Insert it into the right place 2549f06ca4afSHartmut Brandt */ 2550f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2551f06ca4afSHartmut Brandt 2552f06ca4afSHartmut Brandt /* preserve order */ 2553f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2554f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2555f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2556f06ca4afSHartmut Brandt } 2557f06ca4afSHartmut Brandt 2558f06ca4afSHartmut Brandt /* 2559f06ca4afSHartmut Brandt * make the argument vector. 2560f06ca4afSHartmut Brandt */ 2561f06ca4afSHartmut Brandt ac = 0; 2562f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2563f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2564f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2565f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2566f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2567f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2568f06ca4afSHartmut Brandt "module '%s", section); 2569f06ca4afSHartmut Brandt break; 2570f06ca4afSHartmut Brandt } 2571f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2572f06ca4afSHartmut Brandt } 2573f06ca4afSHartmut Brandt } 2574f06ca4afSHartmut Brandt av[ac] = NULL; 2575f06ca4afSHartmut Brandt 2576f06ca4afSHartmut Brandt /* 2577165c5d31SHartmut Brandt * Run the initialization function 2578f06ca4afSHartmut Brandt */ 2579f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2580f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2581f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2582f06ca4afSHartmut Brandt goto err; 2583f06ca4afSHartmut Brandt } 2584f06ca4afSHartmut Brandt 2585f06ca4afSHartmut Brandt return (m); 2586f06ca4afSHartmut Brandt 2587f06ca4afSHartmut Brandt err: 2588691f8568SShteryana Shopova if ((m->flags & LM_ONSTARTLIST) != 0) 2589691f8568SShteryana Shopova TAILQ_REMOVE(&modules_start, m, start); 2590f06ca4afSHartmut Brandt if (m->handle) 2591f06ca4afSHartmut Brandt dlclose(m->handle); 2592f06ca4afSHartmut Brandt free(m->path); 2593f06ca4afSHartmut Brandt free(m); 2594f06ca4afSHartmut Brandt return (NULL); 2595f06ca4afSHartmut Brandt } 2596f06ca4afSHartmut Brandt 2597f06ca4afSHartmut Brandt /* 2598f06ca4afSHartmut Brandt * Start a module 2599f06ca4afSHartmut Brandt */ 2600f06ca4afSHartmut Brandt void 2601f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2602f06ca4afSHartmut Brandt { 2603f06ca4afSHartmut Brandt const struct lmodule *m; 2604f06ca4afSHartmut Brandt 2605f06ca4afSHartmut Brandt /* 2606f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2607f06ca4afSHartmut Brandt */ 2608f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2609f06ca4afSHartmut Brandt lm_unload(mod); 2610f06ca4afSHartmut Brandt return; 2611f06ca4afSHartmut Brandt } 2612f06ca4afSHartmut Brandt 2613f06ca4afSHartmut Brandt /* 2614f06ca4afSHartmut Brandt * Read configuration 2615f06ca4afSHartmut Brandt */ 2616f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2617f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2618f06ca4afSHartmut Brandt lm_unload(mod); 2619f06ca4afSHartmut Brandt return; 2620f06ca4afSHartmut Brandt } 2621f06ca4afSHartmut Brandt if (mod->config->start) 2622f06ca4afSHartmut Brandt (*mod->config->start)(); 2623f06ca4afSHartmut Brandt 2624f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2625f06ca4afSHartmut Brandt 2626f06ca4afSHartmut Brandt /* 2627f06ca4afSHartmut Brandt * Inform other modules 2628f06ca4afSHartmut Brandt */ 2629f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2630f06ca4afSHartmut Brandt if (m->config->loading) 2631f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2632f06ca4afSHartmut Brandt } 2633f06ca4afSHartmut Brandt 2634f06ca4afSHartmut Brandt 2635f06ca4afSHartmut Brandt /* 2636f06ca4afSHartmut Brandt * Unload a module. 2637f06ca4afSHartmut Brandt */ 2638f06ca4afSHartmut Brandt void 2639f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2640f06ca4afSHartmut Brandt { 2641f06ca4afSHartmut Brandt int err; 2642f06ca4afSHartmut Brandt const struct lmodule *mod; 2643f06ca4afSHartmut Brandt 2644f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2645f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2646f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2647f06ca4afSHartmut Brandt tree_unmerge(m); 2648f06ca4afSHartmut Brandt 2649f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2650f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2651f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2652f06ca4afSHartmut Brandt 2653f06ca4afSHartmut Brandt comm_flush(m); 2654f06ca4afSHartmut Brandt reqid_flush(m); 2655f06ca4afSHartmut Brandt timer_flush(m); 2656f06ca4afSHartmut Brandt fd_flush(m); 2657f06ca4afSHartmut Brandt 2658f06ca4afSHartmut Brandt dlclose(m->handle); 2659f06ca4afSHartmut Brandt free(m->path); 2660f06ca4afSHartmut Brandt 2661f06ca4afSHartmut Brandt /* 2662f06ca4afSHartmut Brandt * Inform other modules 2663f06ca4afSHartmut Brandt */ 2664f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2665f06ca4afSHartmut Brandt if (mod->config->loading) 2666f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2667f06ca4afSHartmut Brandt 2668f06ca4afSHartmut Brandt free(m); 2669f06ca4afSHartmut Brandt } 2670f06ca4afSHartmut Brandt 2671f06ca4afSHartmut Brandt /* 2672f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2673f06ca4afSHartmut Brandt */ 2674f06ca4afSHartmut Brandt u_int 2675f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2676f06ca4afSHartmut Brandt { 2677f06ca4afSHartmut Brandt struct objres *objres, *or1; 2678f06ca4afSHartmut Brandt u_int idx; 2679f06ca4afSHartmut Brandt 2680f06ca4afSHartmut Brandt /* find a free index */ 2681f06ca4afSHartmut Brandt idx = 1; 2682f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2683f06ca4afSHartmut Brandt objres != NULL; 2684f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2685f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2686f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2687f06ca4afSHartmut Brandt idx = objres->index + 1; 2688f06ca4afSHartmut Brandt break; 2689f06ca4afSHartmut Brandt } 2690f06ca4afSHartmut Brandt } 2691f06ca4afSHartmut Brandt 2692f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2693f06ca4afSHartmut Brandt return (0); 2694f06ca4afSHartmut Brandt 2695f06ca4afSHartmut Brandt objres->index = idx; 2696f06ca4afSHartmut Brandt objres->oid = *or; 2697f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 269869292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2699f06ca4afSHartmut Brandt objres->module = mod; 2700f06ca4afSHartmut Brandt 2701f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2702f06ca4afSHartmut Brandt 2703f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2704f06ca4afSHartmut Brandt 2705f06ca4afSHartmut Brandt return (idx); 2706f06ca4afSHartmut Brandt } 2707f06ca4afSHartmut Brandt 2708f06ca4afSHartmut Brandt void 2709f06ca4afSHartmut Brandt or_unregister(u_int idx) 2710f06ca4afSHartmut Brandt { 2711f06ca4afSHartmut Brandt struct objres *objres; 2712f06ca4afSHartmut Brandt 2713f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2714f06ca4afSHartmut Brandt if (objres->index == idx) { 2715f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2716f06ca4afSHartmut Brandt free(objres); 2717f06ca4afSHartmut Brandt return; 2718f06ca4afSHartmut Brandt } 2719f06ca4afSHartmut Brandt } 2720135f7de5SShteryana Shopova 2721135f7de5SShteryana Shopova /* 2722135f7de5SShteryana Shopova * RFC 3414 User-based Security Model support 2723135f7de5SShteryana Shopova */ 2724135f7de5SShteryana Shopova 2725135f7de5SShteryana Shopova struct snmpd_usmstat * 2726135f7de5SShteryana Shopova bsnmpd_get_usm_stats(void) 2727135f7de5SShteryana Shopova { 2728135f7de5SShteryana Shopova return (&snmpd_usmstats); 2729135f7de5SShteryana Shopova } 2730135f7de5SShteryana Shopova 2731135f7de5SShteryana Shopova void 2732135f7de5SShteryana Shopova bsnmpd_reset_usm_stats(void) 2733135f7de5SShteryana Shopova { 27349972acaaSHartmut Brandt memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2735135f7de5SShteryana Shopova } 2736135f7de5SShteryana Shopova 2737135f7de5SShteryana Shopova struct usm_user * 2738135f7de5SShteryana Shopova usm_first_user(void) 2739135f7de5SShteryana Shopova { 2740135f7de5SShteryana Shopova return (SLIST_FIRST(&usm_userlist)); 2741135f7de5SShteryana Shopova } 2742135f7de5SShteryana Shopova 2743135f7de5SShteryana Shopova struct usm_user * 2744135f7de5SShteryana Shopova usm_next_user(struct usm_user *uuser) 2745135f7de5SShteryana Shopova { 2746135f7de5SShteryana Shopova if (uuser == NULL) 2747135f7de5SShteryana Shopova return (NULL); 2748135f7de5SShteryana Shopova 2749135f7de5SShteryana Shopova return (SLIST_NEXT(uuser, up)); 2750135f7de5SShteryana Shopova } 2751135f7de5SShteryana Shopova 2752135f7de5SShteryana Shopova struct usm_user * 2753135f7de5SShteryana Shopova usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2754135f7de5SShteryana Shopova { 2755135f7de5SShteryana Shopova struct usm_user *uuser; 2756135f7de5SShteryana Shopova 2757135f7de5SShteryana Shopova SLIST_FOREACH(uuser, &usm_userlist, up) 2758135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2759135f7de5SShteryana Shopova memcmp(uuser->user_engine_id, engine, elen) == 0 && 2760135f7de5SShteryana Shopova strlen(uuser->suser.sec_name) == strlen(uname) && 2761135f7de5SShteryana Shopova strcmp(uuser->suser.sec_name, uname) == 0) 2762135f7de5SShteryana Shopova break; 2763135f7de5SShteryana Shopova 2764135f7de5SShteryana Shopova return (uuser); 2765135f7de5SShteryana Shopova } 2766135f7de5SShteryana Shopova 2767135f7de5SShteryana Shopova static int 2768135f7de5SShteryana Shopova usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2769135f7de5SShteryana Shopova { 2770135f7de5SShteryana Shopova uint32_t i; 2771135f7de5SShteryana Shopova 2772135f7de5SShteryana Shopova if (u1->user_engine_len < u2->user_engine_len) 2773135f7de5SShteryana Shopova return (-1); 2774135f7de5SShteryana Shopova if (u1->user_engine_len > u2->user_engine_len) 2775135f7de5SShteryana Shopova return (1); 2776135f7de5SShteryana Shopova 2777135f7de5SShteryana Shopova for (i = 0; i < u1->user_engine_len; i++) { 2778135f7de5SShteryana Shopova if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2779135f7de5SShteryana Shopova return (-1); 2780135f7de5SShteryana Shopova if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2781135f7de5SShteryana Shopova return (1); 2782135f7de5SShteryana Shopova } 2783135f7de5SShteryana Shopova 2784135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2785135f7de5SShteryana Shopova return (-1); 2786135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2787135f7de5SShteryana Shopova return (1); 2788135f7de5SShteryana Shopova 2789135f7de5SShteryana Shopova for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2790135f7de5SShteryana Shopova if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2791135f7de5SShteryana Shopova return (-1); 2792135f7de5SShteryana Shopova if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2793135f7de5SShteryana Shopova return (1); 2794135f7de5SShteryana Shopova } 2795135f7de5SShteryana Shopova 2796135f7de5SShteryana Shopova return (0); 2797135f7de5SShteryana Shopova } 2798135f7de5SShteryana Shopova 2799135f7de5SShteryana Shopova struct usm_user * 2800135f7de5SShteryana Shopova usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2801135f7de5SShteryana Shopova { 2802135f7de5SShteryana Shopova int cmp; 2803135f7de5SShteryana Shopova struct usm_user *uuser, *temp, *prev; 2804135f7de5SShteryana Shopova 2805135f7de5SShteryana Shopova for (uuser = usm_first_user(); uuser != NULL; 2806135f7de5SShteryana Shopova (uuser = usm_next_user(uuser))) { 2807135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2808135f7de5SShteryana Shopova strlen(uname) == strlen(uuser->suser.sec_name) && 2809135f7de5SShteryana Shopova strcmp(uname, uuser->suser.sec_name) == 0 && 2810135f7de5SShteryana Shopova memcmp(eid, uuser->user_engine_id, elen) == 0) 2811135f7de5SShteryana Shopova return (NULL); 2812135f7de5SShteryana Shopova } 2813135f7de5SShteryana Shopova 2814135f7de5SShteryana Shopova if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2815135f7de5SShteryana Shopova return (NULL); 2816135f7de5SShteryana Shopova 28178ad8cdc9SEnji Cooper memset(uuser, 0, sizeof(*uuser)); 2818135f7de5SShteryana Shopova strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2819135f7de5SShteryana Shopova memcpy(uuser->user_engine_id, eid, elen); 2820135f7de5SShteryana Shopova uuser->user_engine_len = elen; 2821135f7de5SShteryana Shopova 2822135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2823135f7de5SShteryana Shopova usm_compare_user(uuser, prev) < 0) { 2824135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2825135f7de5SShteryana Shopova return (uuser); 2826135f7de5SShteryana Shopova } 2827135f7de5SShteryana Shopova 2828135f7de5SShteryana Shopova SLIST_FOREACH(temp, &usm_userlist, up) { 2829135f7de5SShteryana Shopova if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2830135f7de5SShteryana Shopova break; 2831135f7de5SShteryana Shopova prev = temp; 2832135f7de5SShteryana Shopova } 2833135f7de5SShteryana Shopova 2834135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2835135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, uuser, up); 2836135f7de5SShteryana Shopova else if (cmp > 0) 2837135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, uuser, up); 2838135f7de5SShteryana Shopova else { 2839135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2840135f7de5SShteryana Shopova free(uuser); 2841135f7de5SShteryana Shopova return (NULL); 2842135f7de5SShteryana Shopova } 2843135f7de5SShteryana Shopova 2844135f7de5SShteryana Shopova return (uuser); 2845135f7de5SShteryana Shopova } 2846135f7de5SShteryana Shopova 2847135f7de5SShteryana Shopova void 2848135f7de5SShteryana Shopova usm_delete_user(struct usm_user *uuser) 2849135f7de5SShteryana Shopova { 2850135f7de5SShteryana Shopova SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2851135f7de5SShteryana Shopova free(uuser); 2852135f7de5SShteryana Shopova } 2853135f7de5SShteryana Shopova 2854135f7de5SShteryana Shopova void 2855135f7de5SShteryana Shopova usm_flush_users(void) 2856135f7de5SShteryana Shopova { 2857135f7de5SShteryana Shopova struct usm_user *uuser; 2858135f7de5SShteryana Shopova 2859135f7de5SShteryana Shopova while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2860135f7de5SShteryana Shopova SLIST_REMOVE_HEAD(&usm_userlist, up); 2861135f7de5SShteryana Shopova free(uuser); 2862135f7de5SShteryana Shopova } 2863135f7de5SShteryana Shopova 2864135f7de5SShteryana Shopova SLIST_INIT(&usm_userlist); 2865135f7de5SShteryana Shopova } 2866135f7de5SShteryana Shopova 2867135f7de5SShteryana Shopova /* 2868135f7de5SShteryana Shopova * RFC 3415 View-based Access Control Model support 2869135f7de5SShteryana Shopova */ 2870135f7de5SShteryana Shopova struct vacm_user * 2871135f7de5SShteryana Shopova vacm_first_user(void) 2872135f7de5SShteryana Shopova { 2873135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_userlist)); 2874135f7de5SShteryana Shopova } 2875135f7de5SShteryana Shopova 2876135f7de5SShteryana Shopova struct vacm_user * 2877135f7de5SShteryana Shopova vacm_next_user(struct vacm_user *vuser) 2878135f7de5SShteryana Shopova { 2879135f7de5SShteryana Shopova if (vuser == NULL) 2880135f7de5SShteryana Shopova return (NULL); 2881135f7de5SShteryana Shopova 2882135f7de5SShteryana Shopova return (SLIST_NEXT(vuser, vvu)); 2883135f7de5SShteryana Shopova } 2884135f7de5SShteryana Shopova 2885135f7de5SShteryana Shopova static int 2886135f7de5SShteryana Shopova vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2887135f7de5SShteryana Shopova { 2888135f7de5SShteryana Shopova uint32_t i; 2889135f7de5SShteryana Shopova 2890135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2891135f7de5SShteryana Shopova return (-1); 2892135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2893135f7de5SShteryana Shopova return (1); 2894135f7de5SShteryana Shopova 2895135f7de5SShteryana Shopova if (strlen(v1->secname) < strlen(v2->secname)) 2896135f7de5SShteryana Shopova return (-1); 2897135f7de5SShteryana Shopova if (strlen(v1->secname) > strlen(v2->secname)) 2898135f7de5SShteryana Shopova return (1); 2899135f7de5SShteryana Shopova 2900135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->secname); i++) { 2901135f7de5SShteryana Shopova if (v1->secname[i] < v2->secname[i]) 2902135f7de5SShteryana Shopova return (-1); 2903135f7de5SShteryana Shopova if (v1->secname[i] > v2->secname[i]) 2904135f7de5SShteryana Shopova return (1); 2905135f7de5SShteryana Shopova } 2906135f7de5SShteryana Shopova 2907135f7de5SShteryana Shopova return (0); 2908135f7de5SShteryana Shopova } 2909135f7de5SShteryana Shopova 2910135f7de5SShteryana Shopova struct vacm_user * 2911135f7de5SShteryana Shopova vacm_new_user(int32_t smodel, char *uname) 2912135f7de5SShteryana Shopova { 2913135f7de5SShteryana Shopova int cmp; 2914135f7de5SShteryana Shopova struct vacm_user *user, *temp, *prev; 2915135f7de5SShteryana Shopova 2916135f7de5SShteryana Shopova SLIST_FOREACH(user, &vacm_userlist, vvu) 2917135f7de5SShteryana Shopova if (strcmp(uname, user->secname) == 0 && 2918135f7de5SShteryana Shopova smodel == user->sec_model) 2919135f7de5SShteryana Shopova return (NULL); 2920135f7de5SShteryana Shopova 2921135f7de5SShteryana Shopova if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2922135f7de5SShteryana Shopova return (NULL); 2923135f7de5SShteryana Shopova 2924135f7de5SShteryana Shopova memset(user, 0, sizeof(*user)); 2925135f7de5SShteryana Shopova user->group = &vacm_default_group; 2926135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2927135f7de5SShteryana Shopova user->sec_model = smodel; 2928135f7de5SShteryana Shopova strlcpy(user->secname, uname, sizeof(user->secname)); 2929135f7de5SShteryana Shopova 2930135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2931135f7de5SShteryana Shopova vacm_compare_user(user, prev) < 0) { 2932135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2933135f7de5SShteryana Shopova return (user); 2934135f7de5SShteryana Shopova } 2935135f7de5SShteryana Shopova 2936135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2937135f7de5SShteryana Shopova if ((cmp = vacm_compare_user(user, temp)) <= 0) 2938135f7de5SShteryana Shopova break; 2939135f7de5SShteryana Shopova prev = temp; 2940135f7de5SShteryana Shopova } 2941135f7de5SShteryana Shopova 2942135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2943135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, user, vvu); 2944135f7de5SShteryana Shopova else if (cmp > 0) 2945135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, user, vvu); 2946135f7de5SShteryana Shopova else { 2947135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", user->secname); 2948135f7de5SShteryana Shopova free(user); 2949135f7de5SShteryana Shopova return (NULL); 2950135f7de5SShteryana Shopova } 2951135f7de5SShteryana Shopova 2952135f7de5SShteryana Shopova return (user); 2953135f7de5SShteryana Shopova } 2954135f7de5SShteryana Shopova 2955135f7de5SShteryana Shopova int 2956135f7de5SShteryana Shopova vacm_delete_user(struct vacm_user *user) 2957135f7de5SShteryana Shopova { 2958135f7de5SShteryana Shopova if (user->group != NULL && user->group != &vacm_default_group) { 2959135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2960135f7de5SShteryana Shopova if (SLIST_EMPTY(&user->group->group_users)) { 2961135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_grouplist, user->group, 2962135f7de5SShteryana Shopova vacm_group, vge); 2963135f7de5SShteryana Shopova free(user->group); 2964135f7de5SShteryana Shopova } 2965135f7de5SShteryana Shopova } 2966135f7de5SShteryana Shopova 2967135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2968135f7de5SShteryana Shopova free(user); 2969135f7de5SShteryana Shopova 2970135f7de5SShteryana Shopova return (0); 2971135f7de5SShteryana Shopova } 2972135f7de5SShteryana Shopova 2973135f7de5SShteryana Shopova int 2974135f7de5SShteryana Shopova vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2975135f7de5SShteryana Shopova { 2976135f7de5SShteryana Shopova struct vacm_group *group; 2977135f7de5SShteryana Shopova 2978135f7de5SShteryana Shopova if (len >= SNMP_ADM_STR32_SIZ) 2979135f7de5SShteryana Shopova return (-1); 2980135f7de5SShteryana Shopova 2981135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2982135f7de5SShteryana Shopova if (strlen(group->groupname) == len && 2983135f7de5SShteryana Shopova memcmp(octets, group->groupname, len) == 0) 2984135f7de5SShteryana Shopova break; 2985135f7de5SShteryana Shopova 2986135f7de5SShteryana Shopova if (group == NULL) { 2987135f7de5SShteryana Shopova if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2988135f7de5SShteryana Shopova return (-1); 2989135f7de5SShteryana Shopova memset(group, 0, sizeof(*group)); 2990135f7de5SShteryana Shopova memcpy(group->groupname, octets, len); 2991135f7de5SShteryana Shopova group->groupname[len] = '\0'; 2992135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2993135f7de5SShteryana Shopova } 2994135f7de5SShteryana Shopova 2995135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2996135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2997135f7de5SShteryana Shopova user->group = group; 2998135f7de5SShteryana Shopova 2999135f7de5SShteryana Shopova return (0); 3000135f7de5SShteryana Shopova } 3001135f7de5SShteryana Shopova 3002135f7de5SShteryana Shopova void 3003135f7de5SShteryana Shopova vacm_groups_init(void) 3004135f7de5SShteryana Shopova { 3005135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 3006135f7de5SShteryana Shopova } 3007135f7de5SShteryana Shopova 3008135f7de5SShteryana Shopova struct vacm_access * 3009135f7de5SShteryana Shopova vacm_first_access_rule(void) 3010135f7de5SShteryana Shopova { 3011135f7de5SShteryana Shopova return (TAILQ_FIRST(&vacm_accesslist)); 3012135f7de5SShteryana Shopova } 3013135f7de5SShteryana Shopova 3014135f7de5SShteryana Shopova struct vacm_access * 3015135f7de5SShteryana Shopova vacm_next_access_rule(struct vacm_access *acl) 3016135f7de5SShteryana Shopova { 3017135f7de5SShteryana Shopova if (acl == NULL) 3018135f7de5SShteryana Shopova return (NULL); 3019135f7de5SShteryana Shopova 3020135f7de5SShteryana Shopova return (TAILQ_NEXT(acl, vva)); 3021135f7de5SShteryana Shopova } 3022135f7de5SShteryana Shopova 3023135f7de5SShteryana Shopova static int 3024135f7de5SShteryana Shopova vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 3025135f7de5SShteryana Shopova { 3026135f7de5SShteryana Shopova uint32_t i; 3027135f7de5SShteryana Shopova 3028135f7de5SShteryana Shopova if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 3029135f7de5SShteryana Shopova return (-1); 3030135f7de5SShteryana Shopova if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 3031135f7de5SShteryana Shopova return (1); 3032135f7de5SShteryana Shopova 3033135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->group->groupname); i++) { 3034135f7de5SShteryana Shopova if (v1->group->groupname[i] < v2->group->groupname[i]) 3035135f7de5SShteryana Shopova return (-1); 3036135f7de5SShteryana Shopova if (v1->group->groupname[i] > v2->group->groupname[i]) 3037135f7de5SShteryana Shopova return (1); 3038135f7de5SShteryana Shopova } 3039135f7de5SShteryana Shopova 3040135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 3041135f7de5SShteryana Shopova return (-1); 3042135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 3043135f7de5SShteryana Shopova return (1); 3044135f7de5SShteryana Shopova 3045135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->ctx_prefix); i++) { 3046135f7de5SShteryana Shopova if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 3047135f7de5SShteryana Shopova return (-1); 3048135f7de5SShteryana Shopova if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 3049135f7de5SShteryana Shopova return (1); 3050135f7de5SShteryana Shopova } 3051135f7de5SShteryana Shopova 3052135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 3053135f7de5SShteryana Shopova return (-1); 3054135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 3055135f7de5SShteryana Shopova return (1); 3056135f7de5SShteryana Shopova 3057135f7de5SShteryana Shopova if (v1->sec_level < v2->sec_level) 3058135f7de5SShteryana Shopova return (-1); 3059135f7de5SShteryana Shopova if (v1->sec_level > v2->sec_level) 3060135f7de5SShteryana Shopova return (1); 3061135f7de5SShteryana Shopova 3062135f7de5SShteryana Shopova return (0); 3063135f7de5SShteryana Shopova } 3064135f7de5SShteryana Shopova 3065135f7de5SShteryana Shopova struct vacm_access * 3066135f7de5SShteryana Shopova vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 3067135f7de5SShteryana Shopova { 3068135f7de5SShteryana Shopova struct vacm_group *group; 3069135f7de5SShteryana Shopova struct vacm_access *acl, *temp; 3070135f7de5SShteryana Shopova 3071135f7de5SShteryana Shopova TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 3072135f7de5SShteryana Shopova if (acl->group == NULL) 3073135f7de5SShteryana Shopova continue; 3074135f7de5SShteryana Shopova if (strcmp(gname, acl->group->groupname) == 0 && 3075135f7de5SShteryana Shopova strcmp(cprefix, acl->ctx_prefix) == 0 && 3076135f7de5SShteryana Shopova acl->sec_model == smodel && acl->sec_level == slevel) 3077135f7de5SShteryana Shopova return (NULL); 3078135f7de5SShteryana Shopova } 3079135f7de5SShteryana Shopova 3080135f7de5SShteryana Shopova /* Make sure the group exists */ 3081135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 3082135f7de5SShteryana Shopova if (strcmp(gname, group->groupname) == 0) 3083135f7de5SShteryana Shopova break; 3084135f7de5SShteryana Shopova 3085135f7de5SShteryana Shopova if (group == NULL) 3086135f7de5SShteryana Shopova return (NULL); 3087135f7de5SShteryana Shopova 3088135f7de5SShteryana Shopova if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 3089135f7de5SShteryana Shopova return (NULL); 3090135f7de5SShteryana Shopova 3091135f7de5SShteryana Shopova memset(acl, 0, sizeof(*acl)); 3092135f7de5SShteryana Shopova acl->group = group; 3093135f7de5SShteryana Shopova strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 3094135f7de5SShteryana Shopova acl->sec_model = smodel; 3095135f7de5SShteryana Shopova acl->sec_level = slevel; 3096135f7de5SShteryana Shopova 3097135f7de5SShteryana Shopova if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 3098135f7de5SShteryana Shopova vacm_compare_access_rule(acl, temp) < 0) { 3099135f7de5SShteryana Shopova TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 3100135f7de5SShteryana Shopova return (acl); 3101135f7de5SShteryana Shopova } 3102135f7de5SShteryana Shopova 3103135f7de5SShteryana Shopova TAILQ_FOREACH(temp, &vacm_accesslist, vva) 3104135f7de5SShteryana Shopova if (vacm_compare_access_rule(acl, temp) < 0) { 3105135f7de5SShteryana Shopova TAILQ_INSERT_BEFORE(temp, acl, vva); 3106135f7de5SShteryana Shopova return (acl); 3107135f7de5SShteryana Shopova } 3108135f7de5SShteryana Shopova 3109135f7de5SShteryana Shopova TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 3110135f7de5SShteryana Shopova 3111135f7de5SShteryana Shopova return (acl); 3112135f7de5SShteryana Shopova } 3113135f7de5SShteryana Shopova 3114135f7de5SShteryana Shopova int 3115135f7de5SShteryana Shopova vacm_delete_access_rule(struct vacm_access *acl) 3116135f7de5SShteryana Shopova { 3117135f7de5SShteryana Shopova TAILQ_REMOVE(&vacm_accesslist, acl, vva); 3118135f7de5SShteryana Shopova free(acl); 3119135f7de5SShteryana Shopova 3120135f7de5SShteryana Shopova return (0); 3121135f7de5SShteryana Shopova } 3122135f7de5SShteryana Shopova 3123135f7de5SShteryana Shopova struct vacm_view * 3124135f7de5SShteryana Shopova vacm_first_view(void) 3125135f7de5SShteryana Shopova { 3126135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_viewlist)); 3127135f7de5SShteryana Shopova } 3128135f7de5SShteryana Shopova 3129135f7de5SShteryana Shopova struct vacm_view * 3130135f7de5SShteryana Shopova vacm_next_view(struct vacm_view *view) 3131135f7de5SShteryana Shopova { 3132135f7de5SShteryana Shopova if (view == NULL) 3133135f7de5SShteryana Shopova return (NULL); 3134135f7de5SShteryana Shopova 3135135f7de5SShteryana Shopova return (SLIST_NEXT(view, vvl)); 3136135f7de5SShteryana Shopova } 3137135f7de5SShteryana Shopova 3138135f7de5SShteryana Shopova static int 3139135f7de5SShteryana Shopova vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3140135f7de5SShteryana Shopova { 3141135f7de5SShteryana Shopova uint32_t i; 3142135f7de5SShteryana Shopova 3143135f7de5SShteryana Shopova if (strlen(v1->viewname) < strlen(v2->viewname)) 3144135f7de5SShteryana Shopova return (-1); 3145135f7de5SShteryana Shopova if (strlen(v1->viewname) > strlen(v2->viewname)) 3146135f7de5SShteryana Shopova return (1); 3147135f7de5SShteryana Shopova 3148135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->viewname); i++) { 3149135f7de5SShteryana Shopova if (v1->viewname[i] < v2->viewname[i]) 3150135f7de5SShteryana Shopova return (-1); 3151135f7de5SShteryana Shopova if (v1->viewname[i] > v2->viewname[i]) 3152135f7de5SShteryana Shopova return (1); 3153135f7de5SShteryana Shopova } 3154135f7de5SShteryana Shopova 3155135f7de5SShteryana Shopova return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3156135f7de5SShteryana Shopova } 3157135f7de5SShteryana Shopova 3158135f7de5SShteryana Shopova struct vacm_view * 3159135f7de5SShteryana Shopova vacm_new_view(char *vname, struct asn_oid *oid) 3160135f7de5SShteryana Shopova { 3161135f7de5SShteryana Shopova int cmp; 3162135f7de5SShteryana Shopova struct vacm_view *view, *temp, *prev; 3163135f7de5SShteryana Shopova 3164135f7de5SShteryana Shopova SLIST_FOREACH(view, &vacm_viewlist, vvl) 3165135f7de5SShteryana Shopova if (strcmp(vname, view->viewname) == 0) 3166135f7de5SShteryana Shopova return (NULL); 3167135f7de5SShteryana Shopova 3168135f7de5SShteryana Shopova if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3169135f7de5SShteryana Shopova return (NULL); 3170135f7de5SShteryana Shopova 3171135f7de5SShteryana Shopova memset(view, 0, sizeof(*view)); 3172135f7de5SShteryana Shopova strlcpy(view->viewname, vname, sizeof(view->viewname)); 3173135f7de5SShteryana Shopova asn_append_oid(&view->subtree, oid); 3174135f7de5SShteryana Shopova 3175135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3176135f7de5SShteryana Shopova vacm_compare_view(view, prev) < 0) { 3177135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3178135f7de5SShteryana Shopova return (view); 3179135f7de5SShteryana Shopova } 3180135f7de5SShteryana Shopova 3181135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3182135f7de5SShteryana Shopova if ((cmp = vacm_compare_view(view, temp)) <= 0) 3183135f7de5SShteryana Shopova break; 3184135f7de5SShteryana Shopova prev = temp; 3185135f7de5SShteryana Shopova } 3186135f7de5SShteryana Shopova 3187135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3188135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, view, vvl); 3189135f7de5SShteryana Shopova else if (cmp > 0) 3190135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, view, vvl); 3191135f7de5SShteryana Shopova else { 3192135f7de5SShteryana Shopova syslog(LOG_ERR, "View %s exists", view->viewname); 3193135f7de5SShteryana Shopova free(view); 3194135f7de5SShteryana Shopova return (NULL); 3195135f7de5SShteryana Shopova } 3196135f7de5SShteryana Shopova 3197135f7de5SShteryana Shopova return (view); 3198135f7de5SShteryana Shopova } 3199135f7de5SShteryana Shopova 3200135f7de5SShteryana Shopova int 3201135f7de5SShteryana Shopova vacm_delete_view(struct vacm_view *view) 3202135f7de5SShteryana Shopova { 3203135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3204135f7de5SShteryana Shopova free(view); 3205135f7de5SShteryana Shopova 3206135f7de5SShteryana Shopova return (0); 3207135f7de5SShteryana Shopova } 3208135f7de5SShteryana Shopova 3209135f7de5SShteryana Shopova struct vacm_context * 3210135f7de5SShteryana Shopova vacm_first_context(void) 3211135f7de5SShteryana Shopova { 3212135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_contextlist)); 3213135f7de5SShteryana Shopova } 3214135f7de5SShteryana Shopova 3215135f7de5SShteryana Shopova struct vacm_context * 3216135f7de5SShteryana Shopova vacm_next_context(struct vacm_context *vacmctx) 3217135f7de5SShteryana Shopova { 3218135f7de5SShteryana Shopova if (vacmctx == NULL) 3219135f7de5SShteryana Shopova return (NULL); 3220135f7de5SShteryana Shopova 3221135f7de5SShteryana Shopova return (SLIST_NEXT(vacmctx, vcl)); 3222135f7de5SShteryana Shopova } 3223135f7de5SShteryana Shopova 3224135f7de5SShteryana Shopova struct vacm_context * 3225135f7de5SShteryana Shopova vacm_add_context(char *ctxname, int regid) 3226135f7de5SShteryana Shopova { 3227135f7de5SShteryana Shopova int cmp; 3228135f7de5SShteryana Shopova struct vacm_context *ctx, *temp, *prev; 3229135f7de5SShteryana Shopova 3230135f7de5SShteryana Shopova SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3231135f7de5SShteryana Shopova if (strcmp(ctxname, ctx->ctxname) == 0) { 3232135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3233135f7de5SShteryana Shopova return (NULL); 3234135f7de5SShteryana Shopova } 3235135f7de5SShteryana Shopova 3236135f7de5SShteryana Shopova if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3237135f7de5SShteryana Shopova return (NULL); 3238135f7de5SShteryana Shopova 3239135f7de5SShteryana Shopova memset(ctx, 0, sizeof(*ctx)); 3240135f7de5SShteryana Shopova strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3241135f7de5SShteryana Shopova ctx->regid = regid; 3242135f7de5SShteryana Shopova 3243135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3244135f7de5SShteryana Shopova strlen(ctx->ctxname) < strlen(prev->ctxname) || 3245135f7de5SShteryana Shopova strcmp(ctx->ctxname, prev->ctxname) < 0) { 3246135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3247135f7de5SShteryana Shopova return (ctx); 3248135f7de5SShteryana Shopova } 3249135f7de5SShteryana Shopova 3250135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3251135f7de5SShteryana Shopova if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3252135f7de5SShteryana Shopova strcmp(ctx->ctxname, temp->ctxname) < 0) { 3253135f7de5SShteryana Shopova cmp = -1; 3254135f7de5SShteryana Shopova break; 3255135f7de5SShteryana Shopova } 3256135f7de5SShteryana Shopova prev = temp; 3257135f7de5SShteryana Shopova } 3258135f7de5SShteryana Shopova 3259135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3260135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, ctx, vcl); 3261135f7de5SShteryana Shopova else if (cmp > 0) 3262135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, ctx, vcl); 3263135f7de5SShteryana Shopova else { 3264135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3265135f7de5SShteryana Shopova free(ctx); 3266135f7de5SShteryana Shopova return (NULL); 3267135f7de5SShteryana Shopova } 3268135f7de5SShteryana Shopova 3269135f7de5SShteryana Shopova return (ctx); 3270135f7de5SShteryana Shopova } 3271135f7de5SShteryana Shopova 3272135f7de5SShteryana Shopova void 3273135f7de5SShteryana Shopova vacm_flush_contexts(int regid) 3274135f7de5SShteryana Shopova { 3275135f7de5SShteryana Shopova struct vacm_context *ctx, *temp; 3276135f7de5SShteryana Shopova 3277135f7de5SShteryana Shopova SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3278135f7de5SShteryana Shopova if (ctx->regid == regid) { 3279135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3280135f7de5SShteryana Shopova free(ctx); 3281135f7de5SShteryana Shopova } 3282135f7de5SShteryana Shopova } 3283