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 57d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 58d7eb6b47SHartmut Brandt #include <arpa/inet.h> 59d7eb6b47SHartmut Brandt #include <tcpd.h> 60d7eb6b47SHartmut Brandt #endif 61d7eb6b47SHartmut Brandt 62748b5b1eSHartmut Brandt #include "support.h" 63f06ca4afSHartmut Brandt #include "snmpmod.h" 64f06ca4afSHartmut Brandt #include "snmpd.h" 65f06ca4afSHartmut Brandt #include "tree.h" 66f06ca4afSHartmut Brandt #include "oid.h" 67f06ca4afSHartmut Brandt 6804d17814SAndrey V. Elsukov #include "trans_inet.h" 6904d17814SAndrey V. Elsukov 70f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 71f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 72135f7de5SShteryana Shopova #define PATH_ENGINE "/var/%s.engine" 73f06ca4afSHartmut Brandt 7469292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 7569292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 76f06ca4afSHartmut Brandt 77f06ca4afSHartmut Brandt struct systemg systemg = { 78f06ca4afSHartmut Brandt NULL, 79f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 80f06ca4afSHartmut Brandt NULL, NULL, NULL, 81f06ca4afSHartmut Brandt 64 + 8 + 4, 82f06ca4afSHartmut Brandt 0 83f06ca4afSHartmut Brandt }; 84f06ca4afSHartmut Brandt struct debug debug = { 85f06ca4afSHartmut Brandt 0, /* dump_pdus */ 86f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 87f06ca4afSHartmut Brandt 0, /* evdebug */ 88f06ca4afSHartmut Brandt }; 89f06ca4afSHartmut Brandt 90f06ca4afSHartmut Brandt struct snmpd snmpd = { 91f06ca4afSHartmut Brandt 2048, /* txbuf */ 92f06ca4afSHartmut Brandt 2048, /* rxbuf */ 93f06ca4afSHartmut Brandt 0, /* comm_dis */ 94f06ca4afSHartmut Brandt 0, /* auth_traps */ 95f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 9670af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 97f06ca4afSHartmut Brandt }; 98f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 99f06ca4afSHartmut Brandt 100135f7de5SShteryana Shopova struct snmpd_usmstat snmpd_usmstats; 101135f7de5SShteryana Shopova 102135f7de5SShteryana Shopova /* snmpEngine */ 103135f7de5SShteryana Shopova struct snmp_engine snmpd_engine; 104135f7de5SShteryana Shopova 105f06ca4afSHartmut Brandt /* snmpSerialNo */ 106f06ca4afSHartmut Brandt int32_t snmp_serial_no; 107f06ca4afSHartmut Brandt 10872cd7a52SShteryana Shopova struct snmpd_target_stats snmpd_target_stats; 10972cd7a52SShteryana Shopova 110f06ca4afSHartmut Brandt /* search path for config files */ 111f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 112f06ca4afSHartmut Brandt 113f06ca4afSHartmut Brandt /* list of all loaded modules */ 114f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 115f06ca4afSHartmut Brandt 116f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 117f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 118f06ca4afSHartmut Brandt 119f06ca4afSHartmut Brandt /* list of all known communities */ 120f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 121f06ca4afSHartmut Brandt 122135f7de5SShteryana Shopova /* list of all known USM users */ 1238cd5a258SEnji Cooper static struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 124135f7de5SShteryana Shopova 125135f7de5SShteryana Shopova /* A list of all VACM users configured, including v1, v2c and v3 */ 1268cd5a258SEnji Cooper static struct vacm_userlist vacm_userlist = 1278cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_userlist); 128135f7de5SShteryana Shopova 129135f7de5SShteryana Shopova /* A list of all VACM groups */ 1308cd5a258SEnji Cooper static struct vacm_grouplist vacm_grouplist = 1318cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_grouplist); 132135f7de5SShteryana Shopova 133135f7de5SShteryana Shopova static struct vacm_group vacm_default_group = { 134135f7de5SShteryana Shopova .groupname = "", 135135f7de5SShteryana Shopova }; 136135f7de5SShteryana Shopova 137135f7de5SShteryana Shopova /* The list of configured access entries */ 1388cd5a258SEnji Cooper static struct vacm_accesslist vacm_accesslist = 1398cd5a258SEnji Cooper TAILQ_HEAD_INITIALIZER(vacm_accesslist); 140135f7de5SShteryana Shopova 141135f7de5SShteryana Shopova /* The list of configured views */ 1428cd5a258SEnji Cooper static struct vacm_viewlist vacm_viewlist = 1438cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_viewlist); 144135f7de5SShteryana Shopova 145135f7de5SShteryana Shopova /* The list of configured contexts */ 1468cd5a258SEnji Cooper static struct vacm_contextlist vacm_contextlist = 147135f7de5SShteryana Shopova SLIST_HEAD_INITIALIZER(vacm_contextlist); 148135f7de5SShteryana Shopova 149f06ca4afSHartmut Brandt /* list of all installed object resources */ 150f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 151f06ca4afSHartmut Brandt 152f06ca4afSHartmut Brandt /* community value generator */ 153f06ca4afSHartmut Brandt static u_int next_community_index = 1; 154f06ca4afSHartmut Brandt 155f06ca4afSHartmut Brandt /* list of all known ranges */ 156f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 157f06ca4afSHartmut Brandt 158f06ca4afSHartmut Brandt /* identifier generator */ 159f06ca4afSHartmut Brandt u_int next_idrange = 1; 160f06ca4afSHartmut Brandt 161f06ca4afSHartmut Brandt /* list of all current timers */ 162f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 163f06ca4afSHartmut Brandt 164f06ca4afSHartmut Brandt /* list of file descriptors */ 165f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 166f06ca4afSHartmut Brandt 167f06ca4afSHartmut Brandt /* program arguments */ 168f06ca4afSHartmut Brandt static char **progargs; 169f06ca4afSHartmut Brandt static int nprogargs; 170f06ca4afSHartmut Brandt 171f06ca4afSHartmut Brandt /* current community */ 172f06ca4afSHartmut Brandt u_int community; 173f06ca4afSHartmut Brandt static struct community *comm; 174f06ca4afSHartmut Brandt 175135f7de5SShteryana Shopova /* current USM user */ 176135f7de5SShteryana Shopova struct usm_user *usm_user; 177135f7de5SShteryana Shopova 178f06ca4afSHartmut Brandt /* file names */ 179f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 180f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 181135f7de5SShteryana Shopova char engine_file[MAXPATHLEN + 1]; 182f06ca4afSHartmut Brandt 18370af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 184f06ca4afSHartmut Brandt /* event context */ 185f06ca4afSHartmut Brandt static evContext evctx; 18670af00a1SHartmut Brandt #endif 187f06ca4afSHartmut Brandt 188f06ca4afSHartmut Brandt /* signal mask */ 189f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 190f06ca4afSHartmut Brandt 191f06ca4afSHartmut Brandt /* signal handling */ 192f06ca4afSHartmut Brandt static int work; 193f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 194f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 195f06ca4afSHartmut Brandt 196f06ca4afSHartmut Brandt /* oids */ 197f06ca4afSHartmut Brandt static const struct asn_oid 198f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 199f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 200f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 201f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 202f06ca4afSHartmut Brandt 203f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 204f06ca4afSHartmut Brandt 205135f7de5SShteryana Shopova const struct asn_oid oid_usmUnknownEngineIDs = 206135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 207135f7de5SShteryana Shopova 208135f7de5SShteryana Shopova const struct asn_oid oid_usmNotInTimeWindows = 209135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 210135f7de5SShteryana Shopova 211f06ca4afSHartmut Brandt /* request id generator for traps */ 212f06ca4afSHartmut Brandt u_int trap_reqid; 213f06ca4afSHartmut Brandt 214f06ca4afSHartmut Brandt /* help text */ 215f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 216f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 217f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 218135f7de5SShteryana Shopova Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 219135f7de5SShteryana Shopova usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 220135f7de5SShteryana Shopova [-l prefix] [-m variable=value] [-p file]\n\ 221f06ca4afSHartmut Brandt options:\n\ 222f06ca4afSHartmut Brandt -d don't daemonize\n\ 223f06ca4afSHartmut Brandt -h print this info\n\ 224f06ca4afSHartmut Brandt -c file specify configuration file\n\ 225f06ca4afSHartmut Brandt -D options debugging options\n\ 226135f7de5SShteryana Shopova -e file specify engine id file\n\ 227f06ca4afSHartmut Brandt -I path system include path\n\ 228f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 229f06ca4afSHartmut Brandt -m var=val define variable\n\ 230f06ca4afSHartmut Brandt -p file specify pid file\n\ 231f06ca4afSHartmut Brandt "; 232f06ca4afSHartmut Brandt 233d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 234d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 235d7eb6b47SHartmut Brandt static struct request_info req; 236d7eb6b47SHartmut Brandt #endif 237d7eb6b47SHartmut Brandt 23870af00a1SHartmut Brandt /* transports */ 23970af00a1SHartmut Brandt extern const struct transport_def udp_trans; 24070af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 24170af00a1SHartmut Brandt 24270af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 24370af00a1SHartmut Brandt 244f06ca4afSHartmut Brandt /* forward declarations */ 245f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 246f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 247f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 248f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 249f06ca4afSHartmut Brandt 250f06ca4afSHartmut Brandt /* 251f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 252f06ca4afSHartmut Brandt */ 253f06ca4afSHartmut Brandt void * 254f06ca4afSHartmut Brandt buf_alloc(int tx) 255f06ca4afSHartmut Brandt { 256f06ca4afSHartmut Brandt void *buf; 257f06ca4afSHartmut Brandt 25870af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 259f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 260f06ca4afSHartmut Brandt if (tx) 261f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 262f06ca4afSHartmut Brandt else 263f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 264f06ca4afSHartmut Brandt return (NULL); 265f06ca4afSHartmut Brandt } 266f06ca4afSHartmut Brandt return (buf); 267f06ca4afSHartmut Brandt } 268f06ca4afSHartmut Brandt 269f06ca4afSHartmut Brandt /* 27070af00a1SHartmut Brandt * Return the buffer size. 271f06ca4afSHartmut Brandt */ 272f06ca4afSHartmut Brandt size_t 273f06ca4afSHartmut Brandt buf_size(int tx) 274f06ca4afSHartmut Brandt { 27570af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 276f06ca4afSHartmut Brandt } 277f06ca4afSHartmut Brandt 278f06ca4afSHartmut Brandt /* 279f06ca4afSHartmut Brandt * Prepare a PDU for output 280f06ca4afSHartmut Brandt */ 281f06ca4afSHartmut Brandt void 28270af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 283f06ca4afSHartmut Brandt const char *dest) 284f06ca4afSHartmut Brandt { 285f06ca4afSHartmut Brandt struct asn_buf resp_b; 286f29369b7SEnji Cooper enum snmp_code code; 287f06ca4afSHartmut Brandt 288f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 289f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 290f06ca4afSHartmut Brandt 291f29369b7SEnji Cooper if ((code = snmp_pdu_encode(pdu, &resp_b)) != SNMP_CODE_OK) { 292f29369b7SEnji Cooper syslog(LOG_ERR, "cannot encode message (code=%d)", code); 293f06ca4afSHartmut Brandt abort(); 294f06ca4afSHartmut Brandt } 295f06ca4afSHartmut Brandt if (debug.dump_pdus) { 296f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 297f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 298f06ca4afSHartmut Brandt } 299f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 300f06ca4afSHartmut Brandt } 301f06ca4afSHartmut Brandt 302f06ca4afSHartmut Brandt /* 303135f7de5SShteryana Shopova * Check USM PDU header credentials against local SNMP Engine & users. 304135f7de5SShteryana Shopova */ 305135f7de5SShteryana Shopova static enum snmp_code 306135f7de5SShteryana Shopova snmp_pdu_auth_user(struct snmp_pdu *pdu) 307135f7de5SShteryana Shopova { 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); 31588cdfafaSEnji Cooper update_snmpd_engine_time(); 316135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 317135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 318135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 319135f7de5SShteryana Shopova return (SNMP_CODE_OK); 320135f7de5SShteryana Shopova } 321135f7de5SShteryana Shopova 322135f7de5SShteryana Shopova if ((usm_user = usm_find_user(pdu->engine.engine_id, 323135f7de5SShteryana Shopova pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 324135f7de5SShteryana Shopova usm_user->status != 1 /* active */) 325135f7de5SShteryana Shopova return (SNMP_CODE_BADUSER); 326135f7de5SShteryana Shopova 327135f7de5SShteryana Shopova if (usm_user->user_engine_len != snmpd_engine.engine_len || 328135f7de5SShteryana Shopova memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 329135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 330135f7de5SShteryana Shopova return (SNMP_CODE_BADENGINE); 331135f7de5SShteryana Shopova 332135f7de5SShteryana Shopova pdu->user.priv_proto = usm_user->suser.priv_proto; 333135f7de5SShteryana Shopova memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 334135f7de5SShteryana Shopova sizeof(pdu->user.priv_key)); 335135f7de5SShteryana Shopova 336135f7de5SShteryana Shopova /* authenticated snmpEngineId discovery */ 337135f7de5SShteryana Shopova if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 33888cdfafaSEnji Cooper update_snmpd_engine_time(); 339135f7de5SShteryana Shopova pdu->user.auth_proto = usm_user->suser.auth_proto; 340135f7de5SShteryana Shopova memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 341135f7de5SShteryana Shopova sizeof(pdu->user.auth_key)); 342135f7de5SShteryana Shopova 343135f7de5SShteryana Shopova if (pdu->engine.engine_boots == 0 && 344135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 34588cdfafaSEnji Cooper update_snmpd_engine_time(); 346135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 347135f7de5SShteryana Shopova return (SNMP_CODE_OK); 348135f7de5SShteryana Shopova } 349135f7de5SShteryana Shopova 350135f7de5SShteryana Shopova if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 351135f7de5SShteryana Shopova abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 352135f7de5SShteryana Shopova SNMP_TIME_WINDOW) 353135f7de5SShteryana Shopova return (SNMP_CODE_NOTINTIME); 354135f7de5SShteryana Shopova } 355135f7de5SShteryana Shopova 356135f7de5SShteryana Shopova if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 357135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 358135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 359135f7de5SShteryana Shopova usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 360135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 361135f7de5SShteryana Shopova usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 362135f7de5SShteryana Shopova return (SNMP_CODE_BADSECLEVEL); 363135f7de5SShteryana Shopova 364135f7de5SShteryana Shopova return (SNMP_CODE_OK); 365135f7de5SShteryana Shopova } 366135f7de5SShteryana Shopova 367135f7de5SShteryana Shopova /* 368135f7de5SShteryana Shopova * Check whether access to each of var bindings in the PDU is allowed based 369135f7de5SShteryana Shopova * on the user credentials against the configured User groups & VACM views. 370135f7de5SShteryana Shopova */ 37172cd7a52SShteryana Shopova enum snmp_code 372135f7de5SShteryana Shopova snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 373135f7de5SShteryana Shopova { 374135f7de5SShteryana Shopova const char *uname; 375135f7de5SShteryana Shopova int32_t suboid, smodel; 376135f7de5SShteryana Shopova uint32_t i; 377135f7de5SShteryana Shopova struct vacm_user *vuser; 378135f7de5SShteryana Shopova struct vacm_access *acl; 379135f7de5SShteryana Shopova struct vacm_context *vacmctx; 380135f7de5SShteryana Shopova struct vacm_view *view; 381135f7de5SShteryana Shopova 382135f7de5SShteryana Shopova /* 383135f7de5SShteryana Shopova * At least a default context exists if the snmpd_vacm(3) module is 384135f7de5SShteryana Shopova * running. 385135f7de5SShteryana Shopova */ 386135f7de5SShteryana Shopova if (SLIST_EMPTY(&vacm_contextlist) || 387135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 388135f7de5SShteryana Shopova return (SNMP_CODE_OK); 389135f7de5SShteryana Shopova 390135f7de5SShteryana Shopova switch (pdu->version) { 391135f7de5SShteryana Shopova case SNMP_V1: 392135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 393135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 394135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv1; 395135f7de5SShteryana Shopova break; 396135f7de5SShteryana Shopova 397135f7de5SShteryana Shopova case SNMP_V2c: 398135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 399135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 400135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv2c; 401135f7de5SShteryana Shopova break; 402135f7de5SShteryana Shopova 403135f7de5SShteryana Shopova case SNMP_V3: 404135f7de5SShteryana Shopova uname = pdu->user.sec_name; 405135f7de5SShteryana Shopova if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 406135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 407135f7de5SShteryana Shopova /* Compare the PDU context engine id against the agent's */ 408135f7de5SShteryana Shopova if (pdu->context_engine_len != snmpd_engine.engine_len || 409135f7de5SShteryana Shopova memcmp(pdu->context_engine, snmpd_engine.engine_id, 410135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 411135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 412135f7de5SShteryana Shopova break; 413135f7de5SShteryana Shopova 414135f7de5SShteryana Shopova default: 415135f7de5SShteryana Shopova abort(); 416135f7de5SShteryana Shopova } 417135f7de5SShteryana Shopova 418135f7de5SShteryana Shopova SLIST_FOREACH(vuser, &vacm_userlist, vvu) 419135f7de5SShteryana Shopova if (strcmp(uname, vuser->secname) == 0 && 420135f7de5SShteryana Shopova vuser->sec_model == smodel) 421135f7de5SShteryana Shopova break; 422135f7de5SShteryana Shopova 423135f7de5SShteryana Shopova if (vuser == NULL || vuser->group == NULL) 424135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 425135f7de5SShteryana Shopova 426135f7de5SShteryana Shopova /* XXX: shteryana - recheck */ 427135f7de5SShteryana Shopova TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 428135f7de5SShteryana Shopova if (acl->group != vuser->group) 429135f7de5SShteryana Shopova continue; 430135f7de5SShteryana Shopova SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 431135f7de5SShteryana Shopova if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 432135f7de5SShteryana Shopova acl->ctx_match) == 0) 433135f7de5SShteryana Shopova goto match; 434135f7de5SShteryana Shopova } 435135f7de5SShteryana Shopova 436135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 437135f7de5SShteryana Shopova 438135f7de5SShteryana Shopova match: 439135f7de5SShteryana Shopova 440135f7de5SShteryana Shopova switch (pdu->type) { 441135f7de5SShteryana Shopova case SNMP_PDU_GET: 442135f7de5SShteryana Shopova case SNMP_PDU_GETNEXT: 443135f7de5SShteryana Shopova case SNMP_PDU_GETBULK: 444135f7de5SShteryana Shopova if ((view = acl->read_view) == NULL) 445135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 446135f7de5SShteryana Shopova break; 447135f7de5SShteryana Shopova 448135f7de5SShteryana Shopova case SNMP_PDU_SET: 449135f7de5SShteryana Shopova if ((view = acl->write_view) == NULL) 450135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 451135f7de5SShteryana Shopova break; 452135f7de5SShteryana Shopova 453135f7de5SShteryana Shopova case SNMP_PDU_TRAP: 454135f7de5SShteryana Shopova case SNMP_PDU_INFORM: 455135f7de5SShteryana Shopova case SNMP_PDU_TRAP2: 456135f7de5SShteryana Shopova case SNMP_PDU_REPORT: 457135f7de5SShteryana Shopova if ((view = acl->notify_view) == NULL) 458135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 459135f7de5SShteryana Shopova break; 460135f7de5SShteryana Shopova case SNMP_PDU_RESPONSE: 461135f7de5SShteryana Shopova /* NOTREACHED */ 462135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 463135f7de5SShteryana Shopova default: 464135f7de5SShteryana Shopova abort(); 465135f7de5SShteryana Shopova } 466135f7de5SShteryana Shopova 467135f7de5SShteryana Shopova for (i = 0; i < pdu->nbindings; i++) { 468135f7de5SShteryana Shopova /* XXX - view->mask*/ 469135f7de5SShteryana Shopova suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 470135f7de5SShteryana Shopova if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 471135f7de5SShteryana Shopova *ip = i + 1; 472135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 473135f7de5SShteryana Shopova } 474135f7de5SShteryana Shopova } 475135f7de5SShteryana Shopova 476135f7de5SShteryana Shopova return (SNMP_CODE_OK); 477135f7de5SShteryana Shopova } 478135f7de5SShteryana Shopova 479135f7de5SShteryana Shopova /* 480135f7de5SShteryana Shopova * SNMP input. Start: decode the PDU, find the user or community. 481f06ca4afSHartmut Brandt */ 482f06ca4afSHartmut Brandt enum snmpd_input_err 483f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 48470af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 485f06ca4afSHartmut Brandt { 486f06ca4afSHartmut Brandt struct asn_buf b; 487f06ca4afSHartmut Brandt enum snmp_code code; 488f06ca4afSHartmut Brandt enum snmpd_input_err ret; 48970af00a1SHartmut Brandt int sret; 490f06ca4afSHartmut Brandt 491135f7de5SShteryana Shopova /* update uptime */ 492135f7de5SShteryana Shopova this_tick = get_ticks(); 493135f7de5SShteryana Shopova 494f06ca4afSHartmut Brandt b.asn_cptr = buf; 495f06ca4afSHartmut Brandt b.asn_len = len; 49670af00a1SHartmut Brandt 49739ebb4e1SEnji Cooper ret = SNMPD_INPUT_OK; 49839ebb4e1SEnji Cooper 49970af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 50070af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 50170af00a1SHartmut Brandt 50270af00a1SHartmut Brandt case 0: 50370af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 50470af00a1SHartmut Brandt 50570af00a1SHartmut Brandt case -1: 50670af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 50770af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 50870af00a1SHartmut Brandt } 50970af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 51070af00a1SHartmut Brandt 511135f7de5SShteryana Shopova memset(pdu, 0, sizeof(*pdu)); 512135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 513135f7de5SShteryana Shopova goto decoded; 514f06ca4afSHartmut Brandt 515135f7de5SShteryana Shopova if (pdu->version == SNMP_V3) { 516135f7de5SShteryana Shopova if (pdu->security_model != SNMP_SECMODEL_USM) { 517135f7de5SShteryana Shopova code = SNMP_CODE_FAILED; 518135f7de5SShteryana Shopova goto decoded; 519135f7de5SShteryana Shopova } 520135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 521135f7de5SShteryana Shopova goto decoded; 522135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 523135f7de5SShteryana Shopova goto decoded; 524135f7de5SShteryana Shopova } 525135f7de5SShteryana Shopova code = snmp_pdu_decode_scoped(&b, pdu, ip); 52670af00a1SHartmut Brandt 527135f7de5SShteryana Shopova decoded: 528135f7de5SShteryana Shopova snmpd_stats.inPkts++; 529135f7de5SShteryana Shopova 530f06ca4afSHartmut Brandt switch (code) { 531f06ca4afSHartmut Brandt 532f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 533f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 534f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 535f06ca4afSHartmut Brandt 536f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 53770af00a1SHartmut Brandt bad_vers: 538f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 539f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 540f06ca4afSHartmut Brandt 541f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 542f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 543f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 544f06ca4afSHartmut Brandt break; 545f06ca4afSHartmut Brandt 546f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 547f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 548f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 549f06ca4afSHartmut Brandt break; 550f06ca4afSHartmut Brandt 551f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 552f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 553f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 554f06ca4afSHartmut Brandt break; 555f06ca4afSHartmut Brandt 556135f7de5SShteryana Shopova case SNMP_CODE_BADSECLEVEL: 557135f7de5SShteryana Shopova snmpd_usmstats.unsupported_seclevels++; 558135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 559135f7de5SShteryana Shopova 560135f7de5SShteryana Shopova case SNMP_CODE_NOTINTIME: 561135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 562135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 563135f7de5SShteryana Shopova 564135f7de5SShteryana Shopova case SNMP_CODE_BADUSER: 565135f7de5SShteryana Shopova snmpd_usmstats.unknown_users++; 566135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 567135f7de5SShteryana Shopova 568135f7de5SShteryana Shopova case SNMP_CODE_BADENGINE: 569135f7de5SShteryana Shopova snmpd_usmstats.unknown_engine_ids++; 570135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 571135f7de5SShteryana Shopova 572135f7de5SShteryana Shopova case SNMP_CODE_BADDIGEST: 573135f7de5SShteryana Shopova snmpd_usmstats.wrong_digests++; 574135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 575135f7de5SShteryana Shopova 576135f7de5SShteryana Shopova case SNMP_CODE_EDECRYPT: 577135f7de5SShteryana Shopova snmpd_usmstats.decrypt_errors++; 578135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 579135f7de5SShteryana Shopova 580f06ca4afSHartmut Brandt case SNMP_CODE_OK: 58170af00a1SHartmut Brandt switch (pdu->version) { 58270af00a1SHartmut Brandt 58370af00a1SHartmut Brandt case SNMP_V1: 58470af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 58570af00a1SHartmut Brandt goto bad_vers; 58670af00a1SHartmut Brandt break; 58770af00a1SHartmut Brandt 58870af00a1SHartmut Brandt case SNMP_V2c: 58970af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 59070af00a1SHartmut Brandt goto bad_vers; 59170af00a1SHartmut Brandt break; 59270af00a1SHartmut Brandt 593135f7de5SShteryana Shopova case SNMP_V3: 594135f7de5SShteryana Shopova if (!(snmpd.version_enable & VERS_ENABLE_V3)) 595135f7de5SShteryana Shopova goto bad_vers; 596135f7de5SShteryana Shopova break; 597135f7de5SShteryana Shopova 59870af00a1SHartmut Brandt case SNMP_Verr: 59970af00a1SHartmut Brandt goto bad_vers; 60070af00a1SHartmut Brandt } 601f06ca4afSHartmut Brandt break; 602f06ca4afSHartmut Brandt } 603f06ca4afSHartmut Brandt 604f06ca4afSHartmut Brandt if (debug.dump_pdus) { 605f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 606f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 607f06ca4afSHartmut Brandt } 608f06ca4afSHartmut Brandt 609f06ca4afSHartmut Brandt /* 610135f7de5SShteryana Shopova * Look, whether we know the community or user 611f06ca4afSHartmut Brandt */ 612135f7de5SShteryana Shopova 613135f7de5SShteryana Shopova if (pdu->version != SNMP_V3) { 614f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 615f06ca4afSHartmut Brandt if (comm->string != NULL && 616f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 617f06ca4afSHartmut Brandt break; 618f06ca4afSHartmut Brandt 619f06ca4afSHartmut Brandt if (comm == NULL) { 620f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 621f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 622f06ca4afSHartmut Brandt if (snmpd.auth_traps) 623896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 624896052c1SHartmut Brandt (struct snmp_value *)NULL); 625896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 626896052c1SHartmut Brandt } else 627f06ca4afSHartmut Brandt community = comm->value; 628135f7de5SShteryana Shopova } else if (pdu->nbindings == 0) { 629135f7de5SShteryana Shopova /* RFC 3414 - snmpEngineID Discovery */ 630135f7de5SShteryana Shopova if (strlen(pdu->user.sec_name) == 0) { 631135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 632135f7de5SShteryana Shopova &oid_usmUnknownEngineIDs); 633135f7de5SShteryana Shopova pdu->context_engine_len = snmpd_engine.engine_len; 634135f7de5SShteryana Shopova memcpy(pdu->context_engine, snmpd_engine.engine_id, 635135f7de5SShteryana Shopova snmpd_engine.engine_len); 636135f7de5SShteryana Shopova } else if (pdu->engine.engine_boots == 0 && 637135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 638135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 639135f7de5SShteryana Shopova &oid_usmNotInTimeWindows); 64088cdfafaSEnji Cooper update_snmpd_engine_time(); 641135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 642135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 643135f7de5SShteryana Shopova } 644*8b959dd6SShteryana Shopova } else if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && 645135f7de5SShteryana Shopova (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 646135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 647126b5bb6SEnji Cooper ret = SNMPD_INPUT_FAILED; 648135f7de5SShteryana Shopova } 649f06ca4afSHartmut Brandt 650135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 651126b5bb6SEnji Cooper ret = SNMPD_INPUT_FAILED; 652f06ca4afSHartmut Brandt 653f06ca4afSHartmut Brandt return (ret); 654f06ca4afSHartmut Brandt } 655f06ca4afSHartmut Brandt 656f06ca4afSHartmut Brandt /* 657f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 658f06ca4afSHartmut Brandt */ 659f06ca4afSHartmut Brandt enum snmpd_input_err 660f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 661f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 662f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 663f06ca4afSHartmut Brandt { 664f06ca4afSHartmut Brandt struct snmp_pdu resp; 665f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 666f06ca4afSHartmut Brandt enum snmp_ret ret; 667f06ca4afSHartmut Brandt 668f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 669f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 670f06ca4afSHartmut Brandt 671f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 672f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 673f06ca4afSHartmut Brandt 674f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 675f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 676f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 677f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 678f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 679f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 680f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 681f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 682f06ca4afSHartmut Brandt else 683f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 684f06ca4afSHartmut Brandt 685f06ca4afSHartmut Brandt pdu->error_index = ivar; 686f06ca4afSHartmut Brandt 687f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 688f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 689f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 690f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 691f06ca4afSHartmut Brandt } 692f06ca4afSHartmut Brandt 693f06ca4afSHartmut Brandt if (debug.dump_pdus) { 694f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 695f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 696f06ca4afSHartmut Brandt } 697f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 698f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 699f06ca4afSHartmut Brandt } 700f06ca4afSHartmut Brandt 701f06ca4afSHartmut Brandt switch (pdu->type) { 702f06ca4afSHartmut Brandt 703f06ca4afSHartmut Brandt case SNMP_PDU_GET: 704f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 705f06ca4afSHartmut Brandt break; 706f06ca4afSHartmut Brandt 707f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 708f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 709f06ca4afSHartmut Brandt break; 710f06ca4afSHartmut Brandt 711f06ca4afSHartmut Brandt case SNMP_PDU_SET: 712f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 713f06ca4afSHartmut Brandt break; 714f06ca4afSHartmut Brandt 715f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 716f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 717f06ca4afSHartmut Brandt break; 718f06ca4afSHartmut Brandt 719f06ca4afSHartmut Brandt default: 720f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 721f06ca4afSHartmut Brandt break; 722f06ca4afSHartmut Brandt } 723f06ca4afSHartmut Brandt 724f06ca4afSHartmut Brandt switch (ret) { 725f06ca4afSHartmut Brandt 726f06ca4afSHartmut Brandt case SNMP_RET_OK: 727f06ca4afSHartmut Brandt /* normal return - send a response */ 728f06ca4afSHartmut Brandt if (debug.dump_pdus) { 729f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 730f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 731f06ca4afSHartmut Brandt } 732f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 733f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 734f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 735f06ca4afSHartmut Brandt 736f06ca4afSHartmut Brandt case SNMP_RET_IGN: 737f06ca4afSHartmut Brandt /* error - send nothing */ 738f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 739f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 740f06ca4afSHartmut Brandt 741f06ca4afSHartmut Brandt case SNMP_RET_ERR: 742f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 743f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 744f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 745f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 746f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 747f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 748f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 749f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 750f06ca4afSHartmut Brandt } else { 751f06ca4afSHartmut Brandt if (debug.dump_pdus) { 752f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 753f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 754f06ca4afSHartmut Brandt } 755f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 756f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 757f06ca4afSHartmut Brandt } 758f06ca4afSHartmut Brandt } 759f06ca4afSHartmut Brandt abort(); 760f06ca4afSHartmut Brandt } 761f06ca4afSHartmut Brandt 76270af00a1SHartmut Brandt /* 76370af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 76470af00a1SHartmut Brandt */ 76570af00a1SHartmut Brandt void 76670af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 76770af00a1SHartmut Brandt { 76870af00a1SHartmut Brandt struct tport *p; 769f06ca4afSHartmut Brandt 770f321675aSEnji Cooper port->transport = t; 77170af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 77270af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 77370af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 77470af00a1SHartmut Brandt return; 77570af00a1SHartmut Brandt } 77670af00a1SHartmut Brandt } 77770af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 77870af00a1SHartmut Brandt } 77970af00a1SHartmut Brandt 78070af00a1SHartmut Brandt /* 78170af00a1SHartmut Brandt * Remove a port from a transport's list 78270af00a1SHartmut Brandt */ 78370af00a1SHartmut Brandt void 78470af00a1SHartmut Brandt trans_remove_port(struct tport *port) 78570af00a1SHartmut Brandt { 78670af00a1SHartmut Brandt 78770af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 78870af00a1SHartmut Brandt } 78970af00a1SHartmut Brandt 79070af00a1SHartmut Brandt /* 79170af00a1SHartmut Brandt * Find a port on a transport's list 79270af00a1SHartmut Brandt */ 79370af00a1SHartmut Brandt struct tport * 79470af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 79570af00a1SHartmut Brandt { 79670af00a1SHartmut Brandt 79770af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 79870af00a1SHartmut Brandt } 79970af00a1SHartmut Brandt 80070af00a1SHartmut Brandt /* 80170af00a1SHartmut Brandt * Find next port on a transport's list 80270af00a1SHartmut Brandt */ 80370af00a1SHartmut Brandt struct tport * 80470af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 80570af00a1SHartmut Brandt { 80670af00a1SHartmut Brandt 80770af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 80870af00a1SHartmut Brandt } 80970af00a1SHartmut Brandt 81070af00a1SHartmut Brandt /* 81170af00a1SHartmut Brandt * Return first port 81270af00a1SHartmut Brandt */ 81370af00a1SHartmut Brandt struct tport * 81470af00a1SHartmut Brandt trans_first_port(struct transport *t) 81570af00a1SHartmut Brandt { 81670af00a1SHartmut Brandt 81770af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 81870af00a1SHartmut Brandt } 81970af00a1SHartmut Brandt 82070af00a1SHartmut Brandt /* 82170af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 82270af00a1SHartmut Brandt */ 82370af00a1SHartmut Brandt struct tport * 82470af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 82570af00a1SHartmut Brandt intptr_t arg) 82670af00a1SHartmut Brandt { 82770af00a1SHartmut Brandt struct tport *p; 82870af00a1SHartmut Brandt 82970af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 83070af00a1SHartmut Brandt if (func(p, arg) == 0) 83170af00a1SHartmut Brandt return (p); 83270af00a1SHartmut Brandt return (NULL); 83370af00a1SHartmut Brandt } 83470af00a1SHartmut Brandt 83570af00a1SHartmut Brandt /* 83670af00a1SHartmut Brandt * Register a transport 83770af00a1SHartmut Brandt */ 83870af00a1SHartmut Brandt int 83970af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 84070af00a1SHartmut Brandt { 84170af00a1SHartmut Brandt u_int i; 84270af00a1SHartmut Brandt char or_descr[256]; 84370af00a1SHartmut Brandt 84470af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 84570af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 84670af00a1SHartmut Brandt 84770af00a1SHartmut Brandt /* construct index */ 84870af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 84970af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 85070af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 85170af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 85270af00a1SHartmut Brandt 85370af00a1SHartmut Brandt (*pp)->vtab = def; 85470af00a1SHartmut Brandt 85570af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 85670af00a1SHartmut Brandt free(*pp); 85770af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 85870af00a1SHartmut Brandt } 85970af00a1SHartmut Brandt 86070af00a1SHartmut Brandt /* register module */ 86170af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 86270af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 86370af00a1SHartmut Brandt free(*pp); 86470af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 86570af00a1SHartmut Brandt } 86670af00a1SHartmut Brandt 86770af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 86870af00a1SHartmut Brandt 86970af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 87070af00a1SHartmut Brandt 87170af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 87270af00a1SHartmut Brandt } 87370af00a1SHartmut Brandt 87470af00a1SHartmut Brandt /* 87570af00a1SHartmut Brandt * Unregister transport 87670af00a1SHartmut Brandt */ 87770af00a1SHartmut Brandt int 87870af00a1SHartmut Brandt trans_unregister(struct transport *t) 87970af00a1SHartmut Brandt { 88070af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 88170af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 88270af00a1SHartmut Brandt 88370af00a1SHartmut Brandt or_unregister(t->or_index); 88470af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 88570af00a1SHartmut Brandt 88670af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 88770af00a1SHartmut Brandt } 888f06ca4afSHartmut Brandt 889f06ca4afSHartmut Brandt /* 890f06ca4afSHartmut Brandt * File descriptor support 891f06ca4afSHartmut Brandt */ 89270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 89370af00a1SHartmut Brandt static void 89470af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 89570af00a1SHartmut Brandt #else 896f06ca4afSHartmut Brandt static void 897f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 89870af00a1SHartmut Brandt #endif 899f06ca4afSHartmut Brandt { 900f06ca4afSHartmut Brandt struct fdesc *f = uap; 901f06ca4afSHartmut Brandt 902f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 903f06ca4afSHartmut Brandt } 904f06ca4afSHartmut Brandt 905f06ca4afSHartmut Brandt void 906f06ca4afSHartmut Brandt fd_suspend(void *p) 907f06ca4afSHartmut Brandt { 908f06ca4afSHartmut Brandt struct fdesc *f = p; 909f06ca4afSHartmut Brandt 91070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 91170af00a1SHartmut Brandt if (f->id >= 0) { 91270af00a1SHartmut Brandt poll_unregister(f->id); 91370af00a1SHartmut Brandt f->id = -1; 91470af00a1SHartmut Brandt } 91570af00a1SHartmut Brandt #else 916f06ca4afSHartmut Brandt if (evTestID(f->id)) { 917f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 918f06ca4afSHartmut Brandt evInitID(&f->id); 919f06ca4afSHartmut Brandt } 92070af00a1SHartmut Brandt #endif 921f06ca4afSHartmut Brandt } 922f06ca4afSHartmut Brandt 923f06ca4afSHartmut Brandt int 924f06ca4afSHartmut Brandt fd_resume(void *p) 925f06ca4afSHartmut Brandt { 926f06ca4afSHartmut Brandt struct fdesc *f = p; 927f06ca4afSHartmut Brandt int err; 928f06ca4afSHartmut Brandt 92970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 93070af00a1SHartmut Brandt if (f->id >= 0) 93170af00a1SHartmut Brandt return (0); 9328e9b3e70SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, RPOLL_IN)) < 0) { 93370af00a1SHartmut Brandt err = errno; 93470af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 93570af00a1SHartmut Brandt errno = err; 93670af00a1SHartmut Brandt return (-1); 93770af00a1SHartmut Brandt } 93870af00a1SHartmut Brandt #else 939f06ca4afSHartmut Brandt if (evTestID(f->id)) 940f06ca4afSHartmut Brandt return (0); 941f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 942f06ca4afSHartmut Brandt err = errno; 943f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 944f06ca4afSHartmut Brandt errno = err; 945f06ca4afSHartmut Brandt return (-1); 946f06ca4afSHartmut Brandt } 94770af00a1SHartmut Brandt #endif 948f06ca4afSHartmut Brandt return (0); 949f06ca4afSHartmut Brandt } 950f06ca4afSHartmut Brandt 951f06ca4afSHartmut Brandt void * 952f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 953f06ca4afSHartmut Brandt { 954f06ca4afSHartmut Brandt struct fdesc *f; 955f06ca4afSHartmut Brandt int err; 956f06ca4afSHartmut Brandt 957f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 958f06ca4afSHartmut Brandt err = errno; 959f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 960f06ca4afSHartmut Brandt errno = err; 961f06ca4afSHartmut Brandt return (NULL); 962f06ca4afSHartmut Brandt } 963f06ca4afSHartmut Brandt f->fd = fd; 964f06ca4afSHartmut Brandt f->func = func; 965f06ca4afSHartmut Brandt f->udata = udata; 966f06ca4afSHartmut Brandt f->owner = mod; 96770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 96870af00a1SHartmut Brandt f->id = -1; 96970af00a1SHartmut Brandt #else 970f06ca4afSHartmut Brandt evInitID(&f->id); 97170af00a1SHartmut Brandt #endif 972f06ca4afSHartmut Brandt 973f06ca4afSHartmut Brandt if (fd_resume(f)) { 974f06ca4afSHartmut Brandt err = errno; 975f06ca4afSHartmut Brandt free(f); 976f06ca4afSHartmut Brandt errno = err; 977f06ca4afSHartmut Brandt return (NULL); 978f06ca4afSHartmut Brandt } 979f06ca4afSHartmut Brandt 980f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 981f06ca4afSHartmut Brandt 982f06ca4afSHartmut Brandt return (f); 983f06ca4afSHartmut Brandt } 984f06ca4afSHartmut Brandt 985f06ca4afSHartmut Brandt void 986f06ca4afSHartmut Brandt fd_deselect(void *p) 987f06ca4afSHartmut Brandt { 988f06ca4afSHartmut Brandt struct fdesc *f = p; 989f06ca4afSHartmut Brandt 990f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 991f06ca4afSHartmut Brandt fd_suspend(f); 992f06ca4afSHartmut Brandt free(f); 993f06ca4afSHartmut Brandt } 994f06ca4afSHartmut Brandt 995f06ca4afSHartmut Brandt static void 996f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 997f06ca4afSHartmut Brandt { 998f06ca4afSHartmut Brandt struct fdesc *t, *t1; 999f06ca4afSHartmut Brandt 1000f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 1001f06ca4afSHartmut Brandt while (t != NULL) { 1002f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1003f06ca4afSHartmut Brandt if (t->owner == mod) 1004f06ca4afSHartmut Brandt fd_deselect(t); 1005f06ca4afSHartmut Brandt t = t1; 1006f06ca4afSHartmut Brandt } 1007f06ca4afSHartmut Brandt } 1008f06ca4afSHartmut Brandt 1009f06ca4afSHartmut Brandt /* 101070af00a1SHartmut Brandt * Consume a message from the input buffer 1011f06ca4afSHartmut Brandt */ 1012f06ca4afSHartmut Brandt static void 101370af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 1014f06ca4afSHartmut Brandt { 101570af00a1SHartmut Brandt if (!pi->stream) { 101670af00a1SHartmut Brandt /* always consume everything */ 101770af00a1SHartmut Brandt pi->length = 0; 101870af00a1SHartmut Brandt return; 101970af00a1SHartmut Brandt } 102070af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 102170af00a1SHartmut Brandt /* all bytes consumed */ 102270af00a1SHartmut Brandt pi->length = 0; 102370af00a1SHartmut Brandt return; 102470af00a1SHartmut Brandt } 102570af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 102670af00a1SHartmut Brandt pi->length -= pi->consumed; 102770af00a1SHartmut Brandt } 102870af00a1SHartmut Brandt 102970af00a1SHartmut Brandt /* 103070af00a1SHartmut Brandt * Input from a socket 103170af00a1SHartmut Brandt */ 103270af00a1SHartmut Brandt int 103370af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 103470af00a1SHartmut Brandt { 1035f06ca4afSHartmut Brandt u_char *sndbuf; 1036f06ca4afSHartmut Brandt size_t sndlen; 103770af00a1SHartmut Brandt struct snmp_pdu pdu; 1038f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 1039f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 10400077de56SEnji Cooper ssize_t ret, slen; 1041f06ca4afSHartmut Brandt int32_t vi; 1042d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 104304d17814SAndrey V. Elsukov char client[INET6_ADDRSTRLEN]; 1044d7eb6b47SHartmut Brandt #endif 1045f06ca4afSHartmut Brandt 10468d7f605bSEnji Cooper ret = tport->transport->vtab->recv(tport, pi); 104770af00a1SHartmut Brandt if (ret == -1) 104870af00a1SHartmut Brandt return (-1); 1049f06ca4afSHartmut Brandt 1050d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1051d7eb6b47SHartmut Brandt /* 1052d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 1053d7eb6b47SHartmut Brandt */ 105481b587f3SRuslan Ermilov if (pi->peer->sa_family != AF_LOCAL && 105581b587f3SRuslan Ermilov inet_ntop(pi->peer->sa_family, 105669292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 105769292cedSHartmut Brandt client, sizeof(client)) != NULL) { 1058d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 1059d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 1060d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 1061d7eb6b47SHartmut Brandt eval_client(&req)); 1062d7eb6b47SHartmut Brandt return (-1); 1063d7eb6b47SHartmut Brandt } 106481b587f3SRuslan Ermilov } else if (pi->peer->sa_family != AF_LOCAL) 1065d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 1066d7eb6b47SHartmut Brandt #endif 1067d7eb6b47SHartmut Brandt 1068f06ca4afSHartmut Brandt /* 1069f06ca4afSHartmut Brandt * Handle input 1070f06ca4afSHartmut Brandt */ 107170af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 107270af00a1SHartmut Brandt &pi->consumed); 107370af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 107470af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 107570af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 107670af00a1SHartmut Brandt if (pi->stream) { 107770af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 107870af00a1SHartmut Brandt snmpd_stats.silentDrops++; 107970af00a1SHartmut Brandt return (-1); 108070af00a1SHartmut Brandt } 108170af00a1SHartmut Brandt return (0); 108270af00a1SHartmut Brandt } 108370af00a1SHartmut Brandt snmpd_stats.silentDrops++; 108470af00a1SHartmut Brandt return (-1); 108570af00a1SHartmut Brandt } 1086f06ca4afSHartmut Brandt 1087f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 1088f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 1089f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 1090f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 109170af00a1SHartmut Brandt /* for streaming transports this is fatal */ 109270af00a1SHartmut Brandt if (pi->stream) 109370af00a1SHartmut Brandt return (-1); 109470af00a1SHartmut Brandt snmp_input_consume(pi); 109570af00a1SHartmut Brandt return (0); 1096f06ca4afSHartmut Brandt } 1097896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 1098896052c1SHartmut Brandt snmp_input_consume(pi); 1099896052c1SHartmut Brandt return (0); 1100896052c1SHartmut Brandt } 1101f06ca4afSHartmut Brandt 1102f06ca4afSHartmut Brandt /* 1103f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 1104f06ca4afSHartmut Brandt * the hand it over to the module. 1105f06ca4afSHartmut Brandt */ 1106135f7de5SShteryana Shopova if (comm != NULL && comm->owner != NULL && 1107135f7de5SShteryana Shopova comm->owner->config->proxy != NULL) { 110870af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1109896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 1110896052c1SHartmut Brandt !pi->cred || pi->priv); 1111f06ca4afSHartmut Brandt 1112f06ca4afSHartmut Brandt switch (perr) { 1113f06ca4afSHartmut Brandt 1114f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 111570af00a1SHartmut Brandt snmp_input_consume(pi); 111670af00a1SHartmut Brandt return (0); 1117f06ca4afSHartmut Brandt 1118f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 1119f06ca4afSHartmut Brandt break; 1120f06ca4afSHartmut Brandt 1121f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 112270af00a1SHartmut Brandt snmp_input_consume(pi); 1123f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1124f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 112570af00a1SHartmut Brandt return (0); 1126f06ca4afSHartmut Brandt 1127f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 112870af00a1SHartmut Brandt snmp_input_consume(pi); 1129f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1130f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 1131f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1132f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1133896052c1SHartmut Brandt (struct snmp_value *)NULL); 113470af00a1SHartmut Brandt return (0); 1135f06ca4afSHartmut Brandt 1136f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 113770af00a1SHartmut Brandt snmp_input_consume(pi); 1138f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1139f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1140f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1141f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1142896052c1SHartmut Brandt (struct snmp_value *)NULL); 114370af00a1SHartmut Brandt return (0); 1144f06ca4afSHartmut Brandt } 1145f06ca4afSHartmut Brandt } 1146f06ca4afSHartmut Brandt 1147f06ca4afSHartmut Brandt /* 1148f06ca4afSHartmut Brandt * Check type 1149f06ca4afSHartmut Brandt */ 1150f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1151f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1152f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1153f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1154f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1155f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 115670af00a1SHartmut Brandt snmp_input_consume(pi); 115770af00a1SHartmut Brandt return (0); 1158f06ca4afSHartmut Brandt } 1159f06ca4afSHartmut Brandt 1160f06ca4afSHartmut Brandt /* 1161f06ca4afSHartmut Brandt * Check community 1162f06ca4afSHartmut Brandt */ 1163135f7de5SShteryana Shopova if (pdu.version < SNMP_V3 && 1164135f7de5SShteryana Shopova ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1165f3afd27fSAndrey V. Elsukov (comm != NULL && comm->private != COMM_WRITE && 1166f3afd27fSAndrey V. Elsukov (pdu.type == SNMP_PDU_SET || comm->private != COMM_READ)))) { 1167f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1168f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 116970af00a1SHartmut Brandt snmp_input_consume(pi); 1170f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1171896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1172896052c1SHartmut Brandt (struct snmp_value *)NULL); 117370af00a1SHartmut Brandt return (0); 1174f06ca4afSHartmut Brandt } 1175f06ca4afSHartmut Brandt 1176f06ca4afSHartmut Brandt /* 1177f06ca4afSHartmut Brandt * Execute it. 1178f06ca4afSHartmut Brandt */ 1179f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1180f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1181f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 118270af00a1SHartmut Brandt snmp_input_consume(pi); 118370af00a1SHartmut Brandt return (0); 1184f06ca4afSHartmut Brandt } 118570af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 118670af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1187f06ca4afSHartmut Brandt 1188f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 118904d17814SAndrey V. Elsukov if (tport->transport->vtab->send != NULL) 119004d17814SAndrey V. Elsukov slen = tport->transport->vtab->send(tport, sndbuf, 119104d17814SAndrey V. Elsukov sndlen, pi->peer, pi->peerlen); 119204d17814SAndrey V. Elsukov else 119304d17814SAndrey V. Elsukov slen = tport->transport->vtab->send2(tport, sndbuf, 119404d17814SAndrey V. Elsukov sndlen, pi); 119570af00a1SHartmut Brandt if (slen == -1) 11968d7f605bSEnji Cooper syslog(LOG_ERR, "send*: %m"); 119770af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 11988d7f605bSEnji Cooper syslog(LOG_ERR, "send*: short write %zu/%zu", sndlen, 11998d7f605bSEnji Cooper (size_t)slen); 120070af00a1SHartmut Brandt } 12018d7f605bSEnji Cooper 120270af00a1SHartmut Brandt snmp_pdu_free(&pdu); 120370af00a1SHartmut Brandt free(sndbuf); 120470af00a1SHartmut Brandt snmp_input_consume(pi); 120570af00a1SHartmut Brandt 120670af00a1SHartmut Brandt return (0); 120770af00a1SHartmut Brandt } 120870af00a1SHartmut Brandt 120970af00a1SHartmut Brandt /* 121004d17814SAndrey V. Elsukov * Send a PDU to a given port. If this is a multi-socket port, use the 121104d17814SAndrey V. Elsukov * first socket. 121270af00a1SHartmut Brandt */ 121370af00a1SHartmut Brandt void 121470af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 121570af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 121670af00a1SHartmut Brandt { 121770af00a1SHartmut Brandt struct transport *trans = targ; 121870af00a1SHartmut Brandt struct tport *tp; 121970af00a1SHartmut Brandt u_char *sndbuf; 122070af00a1SHartmut Brandt size_t sndlen; 122170af00a1SHartmut Brandt ssize_t len; 122270af00a1SHartmut Brandt 122370af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 122470af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 122570af00a1SHartmut Brandt break; 122670af00a1SHartmut Brandt if (tp == 0) 122770af00a1SHartmut Brandt return; 122870af00a1SHartmut Brandt 122970af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 123070af00a1SHartmut Brandt return; 123170af00a1SHartmut Brandt 123270af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 123370af00a1SHartmut Brandt 123404d17814SAndrey V. Elsukov if (trans->vtab->send != NULL) 123570af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 123604d17814SAndrey V. Elsukov else 123704d17814SAndrey V. Elsukov len = trans->vtab->send2(tp, sndbuf, sndlen, NULL); 123870af00a1SHartmut Brandt 123970af00a1SHartmut Brandt if (len == -1) 1240f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1241f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1242f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1243f06ca4afSHartmut Brandt sndlen, (size_t)len); 124470af00a1SHartmut Brandt 1245f06ca4afSHartmut Brandt free(sndbuf); 1246f06ca4afSHartmut Brandt } 1247f06ca4afSHartmut Brandt 1248f06ca4afSHartmut Brandt 1249f06ca4afSHartmut Brandt /* 125070af00a1SHartmut Brandt * Close an input source 125104d17814SAndrey V. Elsukov * 125204d17814SAndrey V. Elsukov * \param pi input instance 1253f06ca4afSHartmut Brandt */ 1254f06ca4afSHartmut Brandt void 125570af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1256f06ca4afSHartmut Brandt { 125704d17814SAndrey V. Elsukov if (pi->id != NULL) { 125870af00a1SHartmut Brandt fd_deselect(pi->id); 125904d17814SAndrey V. Elsukov pi->id = NULL; 126004d17814SAndrey V. Elsukov } 126104d17814SAndrey V. Elsukov if (pi->fd >= 0) { 126270af00a1SHartmut Brandt (void)close(pi->fd); 126304d17814SAndrey V. Elsukov pi->fd = -1; 126404d17814SAndrey V. Elsukov } 126504d17814SAndrey V. Elsukov if (pi->buf != NULL) { 126670af00a1SHartmut Brandt free(pi->buf); 126704d17814SAndrey V. Elsukov pi->buf = NULL; 126804d17814SAndrey V. Elsukov } 126904d17814SAndrey V. Elsukov } 127004d17814SAndrey V. Elsukov 127104d17814SAndrey V. Elsukov /* 127204d17814SAndrey V. Elsukov * Initialize an input source. 127304d17814SAndrey V. Elsukov * 127404d17814SAndrey V. Elsukov * \param pi input instance 127504d17814SAndrey V. Elsukov */ 127604d17814SAndrey V. Elsukov void 127704d17814SAndrey V. Elsukov snmpd_input_init(struct port_input *pi) 127804d17814SAndrey V. Elsukov { 127904d17814SAndrey V. Elsukov pi->id = NULL; 128004d17814SAndrey V. Elsukov pi->fd = -1; 128104d17814SAndrey V. Elsukov pi->buf = NULL; 1282f06ca4afSHartmut Brandt } 1283f06ca4afSHartmut Brandt 1284f06ca4afSHartmut Brandt /* 1285f06ca4afSHartmut Brandt * Dump internal state. 1286f06ca4afSHartmut Brandt */ 128770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 128870af00a1SHartmut Brandt static void 128970af00a1SHartmut Brandt info_func(void) 129070af00a1SHartmut Brandt #else 1291f06ca4afSHartmut Brandt static void 1292f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 129370af00a1SHartmut Brandt #endif 1294f06ca4afSHartmut Brandt { 1295f06ca4afSHartmut Brandt struct lmodule *m; 1296f06ca4afSHartmut Brandt u_int i; 1297f06ca4afSHartmut Brandt char buf[10000]; 1298f06ca4afSHartmut Brandt 1299f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1300f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1301f06ca4afSHartmut Brandt switch (tree[i].type) { 1302f06ca4afSHartmut Brandt 1303f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1304f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1305f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1306f06ca4afSHartmut Brandt break; 1307f06ca4afSHartmut Brandt 1308f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1309f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1310f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1311f06ca4afSHartmut Brandt break; 1312f06ca4afSHartmut Brandt } 1313f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1314f06ca4afSHartmut Brandt } 1315f06ca4afSHartmut Brandt 1316f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1317f06ca4afSHartmut Brandt if (m->config->dump) 1318f06ca4afSHartmut Brandt (*m->config->dump)(); 1319f06ca4afSHartmut Brandt } 1320f06ca4afSHartmut Brandt 1321f06ca4afSHartmut Brandt /* 1322f06ca4afSHartmut Brandt * Re-read configuration 1323f06ca4afSHartmut Brandt */ 132470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 132570af00a1SHartmut Brandt static void 132670af00a1SHartmut Brandt config_func(void) 132770af00a1SHartmut Brandt #else 1328f06ca4afSHartmut Brandt static void 1329f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1330f06ca4afSHartmut Brandt const void *tag __unused) 133170af00a1SHartmut Brandt #endif 1332f06ca4afSHartmut Brandt { 1333f06ca4afSHartmut Brandt struct lmodule *m; 1334f06ca4afSHartmut Brandt 1335f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1336f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1337f06ca4afSHartmut Brandt return; 1338f06ca4afSHartmut Brandt } 1339f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1340f06ca4afSHartmut Brandt if (m->config->config) 1341f06ca4afSHartmut Brandt (*m->config->config)(); 1342f06ca4afSHartmut Brandt } 1343f06ca4afSHartmut Brandt 1344f06ca4afSHartmut Brandt /* 1345f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1346f06ca4afSHartmut Brandt */ 1347f06ca4afSHartmut Brandt static void 1348f06ca4afSHartmut Brandt onusr1(int s __unused) 1349f06ca4afSHartmut Brandt { 135070af00a1SHartmut Brandt 1351f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1352f06ca4afSHartmut Brandt } 1353f06ca4afSHartmut Brandt static void 1354f06ca4afSHartmut Brandt onhup(int s __unused) 1355f06ca4afSHartmut Brandt { 135670af00a1SHartmut Brandt 1357f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1358f06ca4afSHartmut Brandt } 1359f06ca4afSHartmut Brandt 1360f06ca4afSHartmut Brandt static void 1361f06ca4afSHartmut Brandt onterm(int s __unused) 1362f06ca4afSHartmut Brandt { 1363f06ca4afSHartmut Brandt 136470af00a1SHartmut Brandt /* allow clean-up */ 1365f06ca4afSHartmut Brandt exit(0); 1366f06ca4afSHartmut Brandt } 1367f06ca4afSHartmut Brandt 1368f06ca4afSHartmut Brandt static void 1369f06ca4afSHartmut Brandt init_sigs(void) 1370f06ca4afSHartmut Brandt { 1371f06ca4afSHartmut Brandt struct sigaction sa; 1372f06ca4afSHartmut Brandt 1373f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1374f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1375f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1376f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1377f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1378f06ca4afSHartmut Brandt exit(1); 1379f06ca4afSHartmut Brandt } 1380f06ca4afSHartmut Brandt 1381f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1382f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1383f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1384f06ca4afSHartmut Brandt exit(1); 1385f06ca4afSHartmut Brandt } 1386f06ca4afSHartmut Brandt 1387f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1388f06ca4afSHartmut Brandt sa.sa_flags = 0; 1389f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1390f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1391f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1392f06ca4afSHartmut Brandt exit(1); 1393f06ca4afSHartmut Brandt } 1394f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1395f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1396f06ca4afSHartmut Brandt exit(1); 1397f06ca4afSHartmut Brandt } 1398f06ca4afSHartmut Brandt } 1399f06ca4afSHartmut Brandt 1400f06ca4afSHartmut Brandt static void 1401f06ca4afSHartmut Brandt block_sigs(void) 1402f06ca4afSHartmut Brandt { 1403f06ca4afSHartmut Brandt sigset_t set; 1404f06ca4afSHartmut Brandt 1405f06ca4afSHartmut Brandt sigfillset(&set); 1406f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1407f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1408f06ca4afSHartmut Brandt exit(1); 1409f06ca4afSHartmut Brandt } 1410f06ca4afSHartmut Brandt } 1411f06ca4afSHartmut Brandt static void 1412f06ca4afSHartmut Brandt unblock_sigs(void) 1413f06ca4afSHartmut Brandt { 1414f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1415f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1416f06ca4afSHartmut Brandt exit(1); 1417f06ca4afSHartmut Brandt } 1418f06ca4afSHartmut Brandt } 1419f06ca4afSHartmut Brandt 1420f06ca4afSHartmut Brandt /* 1421f06ca4afSHartmut Brandt * Shut down 1422f06ca4afSHartmut Brandt */ 1423f06ca4afSHartmut Brandt static void 1424f06ca4afSHartmut Brandt term(void) 1425f06ca4afSHartmut Brandt { 1426f06ca4afSHartmut Brandt (void)unlink(pid_file); 1427f06ca4afSHartmut Brandt } 1428f06ca4afSHartmut Brandt 142970af00a1SHartmut Brandt static void 143070af00a1SHartmut Brandt trans_stop(void) 143170af00a1SHartmut Brandt { 143270af00a1SHartmut Brandt struct transport *t; 143370af00a1SHartmut Brandt 143470af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 143570af00a1SHartmut Brandt (void)t->vtab->stop(1); 143670af00a1SHartmut Brandt } 143770af00a1SHartmut Brandt 1438f06ca4afSHartmut Brandt /* 1439f06ca4afSHartmut Brandt * Define a macro from the command line 1440f06ca4afSHartmut Brandt */ 1441f06ca4afSHartmut Brandt static void 1442f06ca4afSHartmut Brandt do_macro(char *arg) 1443f06ca4afSHartmut Brandt { 1444f06ca4afSHartmut Brandt char *eq; 1445f06ca4afSHartmut Brandt int err; 1446f06ca4afSHartmut Brandt 1447f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1448f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1449f06ca4afSHartmut Brandt else { 1450f06ca4afSHartmut Brandt *eq++ = '\0'; 1451f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1452f06ca4afSHartmut Brandt } 1453f06ca4afSHartmut Brandt if (err == -1) { 1454f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1455f06ca4afSHartmut Brandt exit(1); 1456f06ca4afSHartmut Brandt } 1457f06ca4afSHartmut Brandt } 1458f06ca4afSHartmut Brandt 1459f06ca4afSHartmut Brandt /* 1460f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1461f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1462f06ca4afSHartmut Brandt */ 1463f06ca4afSHartmut Brandt static int 1464f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1465f06ca4afSHartmut Brandt { 1466f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1467f06ca4afSHartmut Brandt u_int i; 1468f06ca4afSHartmut Brandt char *ptr; 1469f06ca4afSHartmut Brandt 1470f06ca4afSHartmut Brandt *optp = NULL; 1471f06ca4afSHartmut Brandt 1472f06ca4afSHartmut Brandt /* skip leading junk */ 1473f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1474f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1475f06ca4afSHartmut Brandt break; 1476f06ca4afSHartmut Brandt if (*ptr == '\0') { 1477f06ca4afSHartmut Brandt *arg = ptr; 1478f06ca4afSHartmut Brandt return (-1); 1479f06ca4afSHartmut Brandt } 1480f06ca4afSHartmut Brandt *optp = ptr; 1481f06ca4afSHartmut Brandt 1482f06ca4afSHartmut Brandt /* find the end of the option */ 1483f06ca4afSHartmut Brandt while (*++ptr != '\0') 1484f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1485f06ca4afSHartmut Brandt break; 1486f06ca4afSHartmut Brandt 1487f06ca4afSHartmut Brandt if (*ptr != '\0') { 1488f06ca4afSHartmut Brandt if (*ptr == '=') { 1489f06ca4afSHartmut Brandt *ptr++ = '\0'; 1490f06ca4afSHartmut Brandt *valp = ptr; 1491f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1492f06ca4afSHartmut Brandt ptr++; 1493f06ca4afSHartmut Brandt if (*ptr != '\0') 1494f06ca4afSHartmut Brandt *ptr++ = '\0'; 1495f06ca4afSHartmut Brandt } else 1496f06ca4afSHartmut Brandt *ptr++ = '\0'; 1497f06ca4afSHartmut Brandt } 1498f06ca4afSHartmut Brandt 1499f06ca4afSHartmut Brandt *arg = ptr; 1500f06ca4afSHartmut Brandt 1501f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 150270af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1503f06ca4afSHartmut Brandt return (i); 1504f06ca4afSHartmut Brandt return (-1); 1505f06ca4afSHartmut Brandt } 1506f06ca4afSHartmut Brandt 1507f06ca4afSHartmut Brandt int 1508f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1509f06ca4afSHartmut Brandt { 1510f06ca4afSHartmut Brandt int opt; 1511f06ca4afSHartmut Brandt FILE *fp; 1512f06ca4afSHartmut Brandt int background = 1; 151370af00a1SHartmut Brandt struct tport *p; 1514f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1515f06ca4afSHartmut Brandt struct lmodule *m; 1516135f7de5SShteryana Shopova char *value = NULL, *option; /* XXX */ 151770af00a1SHartmut Brandt struct transport *t; 1518f06ca4afSHartmut Brandt 1519f06ca4afSHartmut Brandt #define DBG_DUMP 0 1520f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1521f06ca4afSHartmut Brandt #define DBG_TRACE 2 1522f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1523f06ca4afSHartmut Brandt "dump", 1524f06ca4afSHartmut Brandt "events", 1525f06ca4afSHartmut Brandt "trace", 1526f06ca4afSHartmut Brandt NULL 1527f06ca4afSHartmut Brandt }; 1528f06ca4afSHartmut Brandt 1529f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1530f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1531f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1532f06ca4afSHartmut Brandt asn_error = asn_error_func; 1533f06ca4afSHartmut Brandt 1534135f7de5SShteryana Shopova while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1535f06ca4afSHartmut Brandt switch (opt) { 1536f06ca4afSHartmut Brandt 1537f06ca4afSHartmut Brandt case 'c': 1538f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1539f06ca4afSHartmut Brandt break; 1540f06ca4afSHartmut Brandt 1541f06ca4afSHartmut Brandt case 'd': 1542f06ca4afSHartmut Brandt background = 0; 1543f06ca4afSHartmut Brandt break; 1544f06ca4afSHartmut Brandt 1545f06ca4afSHartmut Brandt case 'D': 1546f06ca4afSHartmut Brandt while (*optarg) { 1547f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1548f06ca4afSHartmut Brandt &value, &option)) { 1549f06ca4afSHartmut Brandt 1550f06ca4afSHartmut Brandt case DBG_DUMP: 1551f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1552f06ca4afSHartmut Brandt break; 1553f06ca4afSHartmut Brandt 1554f06ca4afSHartmut Brandt case DBG_EVENTS: 1555f06ca4afSHartmut Brandt debug.evdebug++; 1556f06ca4afSHartmut Brandt break; 1557f06ca4afSHartmut Brandt 1558f06ca4afSHartmut Brandt case DBG_TRACE: 1559f06ca4afSHartmut Brandt if (value == NULL) 1560f06ca4afSHartmut Brandt syslog(LOG_ERR, 1561f06ca4afSHartmut Brandt "no value for 'trace'"); 156251054003SHartmut Brandt else 1563748b5b1eSHartmut Brandt snmp_trace = strtoul(value, 1564748b5b1eSHartmut Brandt NULL, 0); 1565f06ca4afSHartmut Brandt break; 1566f06ca4afSHartmut Brandt 1567f06ca4afSHartmut Brandt case -1: 1568f06ca4afSHartmut Brandt if (suboptarg) 1569f06ca4afSHartmut Brandt syslog(LOG_ERR, 1570f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1571f06ca4afSHartmut Brandt option); 1572f06ca4afSHartmut Brandt else 1573f06ca4afSHartmut Brandt syslog(LOG_ERR, 1574f06ca4afSHartmut Brandt "missing debug flag"); 1575f06ca4afSHartmut Brandt break; 1576f06ca4afSHartmut Brandt } 1577f06ca4afSHartmut Brandt } 1578f06ca4afSHartmut Brandt break; 1579f06ca4afSHartmut Brandt 1580135f7de5SShteryana Shopova case 'e': 1581135f7de5SShteryana Shopova strlcpy(engine_file, optarg, sizeof(engine_file)); 1582135f7de5SShteryana Shopova break; 1583f06ca4afSHartmut Brandt case 'h': 1584f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1585f06ca4afSHartmut Brandt exit(0); 1586f06ca4afSHartmut Brandt 1587f06ca4afSHartmut Brandt case 'I': 1588f06ca4afSHartmut Brandt syspath = optarg; 1589f06ca4afSHartmut Brandt break; 1590f06ca4afSHartmut Brandt 1591f06ca4afSHartmut Brandt case 'l': 1592f06ca4afSHartmut Brandt prefix = optarg; 1593f06ca4afSHartmut Brandt break; 1594f06ca4afSHartmut Brandt 1595f06ca4afSHartmut Brandt case 'm': 1596f06ca4afSHartmut Brandt do_macro(optarg); 1597f06ca4afSHartmut Brandt break; 1598f06ca4afSHartmut Brandt 1599f06ca4afSHartmut Brandt case 'p': 1600f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1601f06ca4afSHartmut Brandt break; 1602f06ca4afSHartmut Brandt } 1603f06ca4afSHartmut Brandt 1604f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1605f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1606f06ca4afSHartmut Brandt 1607f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1608f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1609f06ca4afSHartmut Brandt exit(1); 1610f06ca4afSHartmut Brandt } 1611f06ca4afSHartmut Brandt 1612f06ca4afSHartmut Brandt argc -= optind; 1613f06ca4afSHartmut Brandt argv += optind; 1614f06ca4afSHartmut Brandt 1615f06ca4afSHartmut Brandt progargs = argv; 1616f06ca4afSHartmut Brandt nprogargs = argc; 1617f06ca4afSHartmut Brandt 161844d780e3SConrad Meyer snmp_serial_no = arc4random(); 1619f06ca4afSHartmut Brandt 1620d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1621d7eb6b47SHartmut Brandt /* 1622d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1623d7eb6b47SHartmut Brandt */ 1624d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1625d7eb6b47SHartmut Brandt sock_methods(&req); 1626d7eb6b47SHartmut Brandt #endif 1627d7eb6b47SHartmut Brandt 1628f06ca4afSHartmut Brandt /* 1629f06ca4afSHartmut Brandt * Initialize the tree. 1630f06ca4afSHartmut Brandt */ 1631f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1632f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1633f06ca4afSHartmut Brandt exit(1); 1634f06ca4afSHartmut Brandt } 1635f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1636f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1637f06ca4afSHartmut Brandt 1638f06ca4afSHartmut Brandt /* 1639f06ca4afSHartmut Brandt * Get standard communities 1640f06ca4afSHartmut Brandt */ 1641f3afd27fSAndrey V. Elsukov comm_define(COMM_READ, "SNMP read", NULL, NULL); 1642f3afd27fSAndrey V. Elsukov comm_define(COMM_WRITE, "SNMP write", NULL, NULL); 1643f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1644f06ca4afSHartmut Brandt 1645f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1646f06ca4afSHartmut Brandt 1647f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1648f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1649f06ca4afSHartmut Brandt 1650f06ca4afSHartmut Brandt init_actvals(); 1651135f7de5SShteryana Shopova init_snmpd_engine(); 165270af00a1SHartmut Brandt 165370af00a1SHartmut Brandt this_tick = get_ticks(); 165469292cedSHartmut Brandt start_tick = this_tick; 165570af00a1SHartmut Brandt 165670af00a1SHartmut Brandt /* start transports */ 165770af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 165870af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 165970af00a1SHartmut Brandt exit(1); 166070af00a1SHartmut Brandt } 166170af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 166270af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 166370af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 166470af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 166504d17814SAndrey V. Elsukov if (inet_trans.start() != SNMP_ERR_NOERROR) 166604d17814SAndrey V. Elsukov syslog(LOG_WARNING, "cannot start INET transport"); 166770af00a1SHartmut Brandt 166870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 166970af00a1SHartmut Brandt if (debug.evdebug > 0) 167070af00a1SHartmut Brandt rpoll_trace = 1; 167170af00a1SHartmut Brandt #else 1672f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1673f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1674f06ca4afSHartmut Brandt exit(1); 1675f06ca4afSHartmut Brandt } 1676f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1677f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 167870af00a1SHartmut Brandt #endif 1679f06ca4afSHartmut Brandt 1680135f7de5SShteryana Shopova if (engine_file[0] == '\0') 1681135f7de5SShteryana Shopova snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1682135f7de5SShteryana Shopova 1683896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1684896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1685896052c1SHartmut Brandt exit(1); 1686896052c1SHartmut Brandt } 1687896052c1SHartmut Brandt 168870af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 168970af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 169070af00a1SHartmut Brandt t->vtab->init_port(p); 1691f06ca4afSHartmut Brandt 1692f06ca4afSHartmut Brandt init_sigs(); 1693f06ca4afSHartmut Brandt 1694f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1695f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1696f06ca4afSHartmut Brandt 1697f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1698f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1699f06ca4afSHartmut Brandt fclose(fp); 170070af00a1SHartmut Brandt if (atexit(term) == -1) { 170170af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 170270af00a1SHartmut Brandt (void)remove(pid_file); 170370af00a1SHartmut Brandt exit(0); 1704f06ca4afSHartmut Brandt } 170570af00a1SHartmut Brandt } 1706f06ca4afSHartmut Brandt 1707f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1708f06ca4afSHartmut Brandt NULL) == 0) { 1709f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1710f06ca4afSHartmut Brandt exit(1); 1711f06ca4afSHartmut Brandt } 1712f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1713f06ca4afSHartmut Brandt NULL) == 0) { 1714f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1715f06ca4afSHartmut Brandt exit(1); 1716f06ca4afSHartmut Brandt } 1717f06ca4afSHartmut Brandt 1718f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1719f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1720f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1721f06ca4afSHartmut Brandt lm_start(m); 1722f06ca4afSHartmut Brandt } 1723f06ca4afSHartmut Brandt 172472cd7a52SShteryana Shopova snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 172572cd7a52SShteryana Shopova 1726f06ca4afSHartmut Brandt for (;;) { 172770af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1728f06ca4afSHartmut Brandt evEvent event; 172970af00a1SHartmut Brandt #endif 1730f06ca4afSHartmut Brandt struct lmodule *mod; 1731f06ca4afSHartmut Brandt 1732f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1733f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1734f06ca4afSHartmut Brandt (*mod->config->idle)(); 1735f06ca4afSHartmut Brandt 173670af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1737f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1738f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1739f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1740f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1741f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1742f06ca4afSHartmut Brandt exit(1); 1743f06ca4afSHartmut Brandt } 174470af00a1SHartmut Brandt #else 174570af00a1SHartmut Brandt poll_dispatch(1); 174670af00a1SHartmut Brandt #endif 1747f06ca4afSHartmut Brandt 1748f06ca4afSHartmut Brandt if (work != 0) { 1749f06ca4afSHartmut Brandt block_sigs(); 1750f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 175170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 175270af00a1SHartmut Brandt info_func(); 175370af00a1SHartmut Brandt #else 1754f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1755f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1756f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1757f06ca4afSHartmut Brandt exit(1); 1758f06ca4afSHartmut Brandt } 175970af00a1SHartmut Brandt #endif 1760f06ca4afSHartmut Brandt } 1761f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 176270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 176370af00a1SHartmut Brandt config_func(); 176470af00a1SHartmut Brandt #else 1765f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1766f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1767f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1768f06ca4afSHartmut Brandt exit(1); 1769f06ca4afSHartmut Brandt } 177070af00a1SHartmut Brandt #endif 1771f06ca4afSHartmut Brandt } 1772f06ca4afSHartmut Brandt work = 0; 1773f06ca4afSHartmut Brandt unblock_sigs(); 177470af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1775f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1776f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1777f06ca4afSHartmut Brandt exit(1); 1778f06ca4afSHartmut Brandt } 177970af00a1SHartmut Brandt #endif 1780f06ca4afSHartmut Brandt } 1781f06ca4afSHartmut Brandt } 1782f06ca4afSHartmut Brandt 1783f06ca4afSHartmut Brandt return (0); 1784f06ca4afSHartmut Brandt } 1785f06ca4afSHartmut Brandt 178669292cedSHartmut Brandt uint64_t 1787135f7de5SShteryana Shopova get_ticks(void) 1788f06ca4afSHartmut Brandt { 1789f06ca4afSHartmut Brandt struct timeval tv; 179069292cedSHartmut Brandt uint64_t ret; 1791f06ca4afSHartmut Brandt 1792f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1793f06ca4afSHartmut Brandt abort(); 179469292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1795f06ca4afSHartmut Brandt return (ret); 1796f06ca4afSHartmut Brandt } 179769292cedSHartmut Brandt 1798f06ca4afSHartmut Brandt /* 1799f06ca4afSHartmut Brandt * Timer support 1800f06ca4afSHartmut Brandt */ 1801165c5d31SHartmut Brandt 1802165c5d31SHartmut Brandt /* 1803165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1804165c5d31SHartmut Brandt */ 180570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 180670af00a1SHartmut Brandt static void 180770af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 180870af00a1SHartmut Brandt #else 1809f06ca4afSHartmut Brandt static void 1810f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1811f06ca4afSHartmut Brandt struct timespec inter __unused) 181270af00a1SHartmut Brandt #endif 1813f06ca4afSHartmut Brandt { 1814f06ca4afSHartmut Brandt struct timer *tp = uap; 1815f06ca4afSHartmut Brandt 1816f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1817f06ca4afSHartmut Brandt tp->func(tp->udata); 1818f06ca4afSHartmut Brandt free(tp); 1819f06ca4afSHartmut Brandt } 1820f06ca4afSHartmut Brandt 1821f06ca4afSHartmut Brandt /* 1822165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1823165c5d31SHartmut Brandt */ 1824165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1825165c5d31SHartmut Brandt static void 1826165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1827165c5d31SHartmut Brandt #else 1828165c5d31SHartmut Brandt static void 1829165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1830165c5d31SHartmut Brandt struct timespec inter __unused) 1831165c5d31SHartmut Brandt #endif 1832165c5d31SHartmut Brandt { 1833165c5d31SHartmut Brandt struct timer *tp = uap; 1834165c5d31SHartmut Brandt 1835165c5d31SHartmut Brandt tp->func(tp->udata); 1836165c5d31SHartmut Brandt } 1837165c5d31SHartmut Brandt 1838165c5d31SHartmut Brandt /* 1839165c5d31SHartmut Brandt * Start a one-shot timer 1840f06ca4afSHartmut Brandt */ 1841f06ca4afSHartmut Brandt void * 1842f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1843f06ca4afSHartmut Brandt { 1844f06ca4afSHartmut Brandt struct timer *tp; 1845a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1846f06ca4afSHartmut Brandt struct timespec due; 184770af00a1SHartmut Brandt #endif 1848f06ca4afSHartmut Brandt 1849f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1850f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1851f06ca4afSHartmut Brandt exit(1); 1852f06ca4afSHartmut Brandt } 1853a9bfedb7SHartmut Brandt 1854a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1855f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1856f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 185770af00a1SHartmut Brandt #endif 1858f06ca4afSHartmut Brandt 1859f06ca4afSHartmut Brandt tp->udata = udata; 1860f06ca4afSHartmut Brandt tp->owner = mod; 1861f06ca4afSHartmut Brandt tp->func = func; 1862f06ca4afSHartmut Brandt 1863f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1864f06ca4afSHartmut Brandt 186570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 1866a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 186770af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 186870af00a1SHartmut Brandt exit(1); 186970af00a1SHartmut Brandt } 187070af00a1SHartmut Brandt #else 1871f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1872f06ca4afSHartmut Brandt == -1) { 1873f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1874f06ca4afSHartmut Brandt exit(1); 1875f06ca4afSHartmut Brandt } 187670af00a1SHartmut Brandt #endif 1877f06ca4afSHartmut Brandt return (tp); 1878f06ca4afSHartmut Brandt } 1879f06ca4afSHartmut Brandt 1880165c5d31SHartmut Brandt /* 1881165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 1882165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 1883165c5d31SHartmut Brandt * repeat number of ticks. 1884165c5d31SHartmut Brandt */ 1885165c5d31SHartmut Brandt void * 1886165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 1887165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 1888165c5d31SHartmut Brandt { 1889165c5d31SHartmut Brandt struct timer *tp; 1890165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1891165c5d31SHartmut Brandt struct timespec due; 1892165c5d31SHartmut Brandt struct timespec inter; 1893165c5d31SHartmut Brandt #endif 1894165c5d31SHartmut Brandt 1895165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1896165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1897165c5d31SHartmut Brandt exit(1); 1898165c5d31SHartmut Brandt } 1899165c5d31SHartmut Brandt 1900165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1901165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 1902165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 1903165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 1904165c5d31SHartmut Brandt #endif 1905165c5d31SHartmut Brandt 1906165c5d31SHartmut Brandt tp->udata = udata; 1907165c5d31SHartmut Brandt tp->owner = mod; 1908165c5d31SHartmut Brandt tp->func = func; 1909165c5d31SHartmut Brandt 1910165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1911165c5d31SHartmut Brandt 1912165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1913165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 1914165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1915165c5d31SHartmut Brandt exit(1); 1916165c5d31SHartmut Brandt } 1917165c5d31SHartmut Brandt #else 1918165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 1919165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1920165c5d31SHartmut Brandt exit(1); 1921165c5d31SHartmut Brandt } 1922165c5d31SHartmut Brandt #endif 1923165c5d31SHartmut Brandt return (tp); 1924165c5d31SHartmut Brandt } 1925165c5d31SHartmut Brandt 1926165c5d31SHartmut Brandt /* 1927165c5d31SHartmut Brandt * Stop a timer. 1928165c5d31SHartmut Brandt */ 1929f06ca4afSHartmut Brandt void 1930f06ca4afSHartmut Brandt timer_stop(void *p) 1931f06ca4afSHartmut Brandt { 1932f06ca4afSHartmut Brandt struct timer *tp = p; 1933f06ca4afSHartmut Brandt 1934f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 193570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 193670af00a1SHartmut Brandt poll_stop_timer(tp->id); 193770af00a1SHartmut Brandt #else 1938f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 1939f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 1940f06ca4afSHartmut Brandt exit(1); 1941f06ca4afSHartmut Brandt } 194270af00a1SHartmut Brandt #endif 1943f06ca4afSHartmut Brandt free(p); 1944f06ca4afSHartmut Brandt } 1945f06ca4afSHartmut Brandt 1946f06ca4afSHartmut Brandt static void 1947f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 1948f06ca4afSHartmut Brandt { 1949f06ca4afSHartmut Brandt struct timer *t, *t1; 1950f06ca4afSHartmut Brandt 1951f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 1952f06ca4afSHartmut Brandt while (t != NULL) { 1953f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1954f06ca4afSHartmut Brandt if (t->owner == mod) 1955f06ca4afSHartmut Brandt timer_stop(t); 1956f06ca4afSHartmut Brandt t = t1; 1957f06ca4afSHartmut Brandt } 1958f06ca4afSHartmut Brandt } 1959f06ca4afSHartmut Brandt 1960f06ca4afSHartmut Brandt static void 1961f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1962f06ca4afSHartmut Brandt { 1963f06ca4afSHartmut Brandt va_list ap; 1964f06ca4afSHartmut Brandt static char *pend = NULL; 1965f06ca4afSHartmut Brandt char *ret, *new; 1966f06ca4afSHartmut Brandt 1967f06ca4afSHartmut Brandt va_start(ap, fmt); 1968f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 1969f06ca4afSHartmut Brandt va_end(ap); 1970f06ca4afSHartmut Brandt 1971f06ca4afSHartmut Brandt if (ret == NULL) 1972f06ca4afSHartmut Brandt return; 1973f06ca4afSHartmut Brandt if (pend != NULL) { 1974f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1975f06ca4afSHartmut Brandt == NULL) { 1976f06ca4afSHartmut Brandt free(ret); 1977f06ca4afSHartmut Brandt return; 1978f06ca4afSHartmut Brandt } 1979f06ca4afSHartmut Brandt pend = new; 1980f06ca4afSHartmut Brandt strcat(pend, ret); 1981f06ca4afSHartmut Brandt free(ret); 1982f06ca4afSHartmut Brandt } else 1983f06ca4afSHartmut Brandt pend = ret; 1984f06ca4afSHartmut Brandt 1985f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 1986f06ca4afSHartmut Brandt *ret = '\0'; 1987f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 1988f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 1989f06ca4afSHartmut Brandt free(pend); 1990f06ca4afSHartmut Brandt pend = NULL; 1991f06ca4afSHartmut Brandt break; 1992f06ca4afSHartmut Brandt } 1993f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 1994f06ca4afSHartmut Brandt } 1995f06ca4afSHartmut Brandt } 1996f06ca4afSHartmut Brandt 1997f06ca4afSHartmut Brandt static void 1998f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 1999f06ca4afSHartmut Brandt { 2000f06ca4afSHartmut Brandt char errbuf[1000]; 2001f06ca4afSHartmut Brandt va_list ap; 2002f06ca4afSHartmut Brandt 200370af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 200470af00a1SHartmut Brandt return; 200570af00a1SHartmut Brandt 2006f06ca4afSHartmut Brandt va_start(ap, err); 2007f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 200870af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 200970af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2010f06ca4afSHartmut Brandt va_end(ap); 2011f06ca4afSHartmut Brandt 2012f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2013f06ca4afSHartmut Brandt } 2014f06ca4afSHartmut Brandt 2015f06ca4afSHartmut Brandt static void 2016f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 2017f06ca4afSHartmut Brandt { 2018f06ca4afSHartmut Brandt char errbuf[1000]; 2019f06ca4afSHartmut Brandt va_list ap; 2020f06ca4afSHartmut Brandt 2021f06ca4afSHartmut Brandt va_start(ap, err); 2022f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2023f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2024f06ca4afSHartmut Brandt err, ap); 2025f06ca4afSHartmut Brandt va_end(ap); 2026f06ca4afSHartmut Brandt 2027f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 2028f06ca4afSHartmut Brandt } 2029f06ca4afSHartmut Brandt 2030f06ca4afSHartmut Brandt static void 2031f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 2032f06ca4afSHartmut Brandt { 2033f06ca4afSHartmut Brandt char errbuf[1000]; 2034f06ca4afSHartmut Brandt va_list ap; 2035f06ca4afSHartmut Brandt u_int i; 2036f06ca4afSHartmut Brandt 203770af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 203870af00a1SHartmut Brandt return; 203970af00a1SHartmut Brandt 2040f06ca4afSHartmut Brandt va_start(ap, err); 2041f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 204270af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 204370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2044f06ca4afSHartmut Brandt va_end(ap); 2045f06ca4afSHartmut Brandt 2046f06ca4afSHartmut Brandt if (b != NULL) { 204770af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 204870af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 2049f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 2050f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 205170af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 205270af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 2053f06ca4afSHartmut Brandt } 2054f06ca4afSHartmut Brandt 2055f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2056f06ca4afSHartmut Brandt } 2057f06ca4afSHartmut Brandt 2058f06ca4afSHartmut Brandt /* 2059f06ca4afSHartmut Brandt * Create a new community 2060f06ca4afSHartmut Brandt */ 2061f3afd27fSAndrey V. Elsukov struct community* 20627e03e181SAndrey V. Elsukov comm_define_ordered(u_int priv, const char *descr, struct asn_oid *idx, 2063f3afd27fSAndrey V. Elsukov struct lmodule *owner, const char *str) 2064f3afd27fSAndrey V. Elsukov { 2065f3afd27fSAndrey V. Elsukov struct community *c, *p; 2066f3afd27fSAndrey V. Elsukov u_int ncomm; 2067f3afd27fSAndrey V. Elsukov 20687e03e181SAndrey V. Elsukov ncomm = idx->subs[idx->len - 1]; 2069f3afd27fSAndrey V. Elsukov 2070f3afd27fSAndrey V. Elsukov /* check that community doesn't already exist */ 2071f3afd27fSAndrey V. Elsukov TAILQ_FOREACH(c, &community_list, link) 2072f3afd27fSAndrey V. Elsukov if (c->value == ncomm) 2073f3afd27fSAndrey V. Elsukov return (c); 2074f3afd27fSAndrey V. Elsukov 2075f3afd27fSAndrey V. Elsukov if ((c = malloc(sizeof(struct community))) == NULL) { 2076f3afd27fSAndrey V. Elsukov syslog(LOG_ERR, "%s: %m", __func__); 2077f3afd27fSAndrey V. Elsukov return (NULL); 2078f3afd27fSAndrey V. Elsukov } 2079f3afd27fSAndrey V. Elsukov c->owner = owner; 2080f3afd27fSAndrey V. Elsukov c->value = ncomm; 2081f3afd27fSAndrey V. Elsukov c->descr = descr; 2082f3afd27fSAndrey V. Elsukov c->string = NULL; 2083f3afd27fSAndrey V. Elsukov c->private = priv; 2084f3afd27fSAndrey V. Elsukov 2085f3afd27fSAndrey V. Elsukov if (str != NULL) { 2086f3afd27fSAndrey V. Elsukov if((c->string = malloc(strlen(str)+1)) == NULL) { 2087f3afd27fSAndrey V. Elsukov free(c); 2088f3afd27fSAndrey V. Elsukov return (NULL); 2089f3afd27fSAndrey V. Elsukov } 2090f3afd27fSAndrey V. Elsukov strcpy(c->string, str); 2091f3afd27fSAndrey V. Elsukov } 2092f3afd27fSAndrey V. Elsukov /* 2093f3afd27fSAndrey V. Elsukov * Insert ordered 2094f3afd27fSAndrey V. Elsukov */ 20957e03e181SAndrey V. Elsukov c->index = *idx; 2096f3afd27fSAndrey V. Elsukov TAILQ_FOREACH(p, &community_list, link) { 2097f3afd27fSAndrey V. Elsukov if (asn_compare_oid(&p->index, &c->index) > 0) { 2098f3afd27fSAndrey V. Elsukov TAILQ_INSERT_BEFORE(p, c, link); 2099f3afd27fSAndrey V. Elsukov break; 2100f3afd27fSAndrey V. Elsukov } 2101f3afd27fSAndrey V. Elsukov } 2102f3afd27fSAndrey V. Elsukov if (p == NULL) 2103f3afd27fSAndrey V. Elsukov TAILQ_INSERT_TAIL(&community_list, c, link); 2104f3afd27fSAndrey V. Elsukov return (c); 2105f3afd27fSAndrey V. Elsukov } 2106f3afd27fSAndrey V. Elsukov 2107f06ca4afSHartmut Brandt u_int 2108f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 2109f06ca4afSHartmut Brandt const char *str) 2110f06ca4afSHartmut Brandt { 21117e03e181SAndrey V. Elsukov struct asn_oid idx, *p; 2112f3afd27fSAndrey V. Elsukov struct community *c; 2113f06ca4afSHartmut Brandt u_int ncomm; 2114f06ca4afSHartmut Brandt 2115f06ca4afSHartmut Brandt /* generate an identifier */ 2116f06ca4afSHartmut Brandt do { 2117f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 2118f06ca4afSHartmut Brandt next_community_index = 1; 2119f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 2120f06ca4afSHartmut Brandt if (c->value == ncomm) 2121f06ca4afSHartmut Brandt break; 2122f06ca4afSHartmut Brandt } while (c != NULL); 2123f06ca4afSHartmut Brandt 2124f06ca4afSHartmut Brandt /* make index */ 2125f3afd27fSAndrey V. Elsukov if (owner != NULL) 2126f3afd27fSAndrey V. Elsukov p = &owner->index; 2127f3afd27fSAndrey V. Elsukov else { 21287e03e181SAndrey V. Elsukov p = &idx; 2129f3afd27fSAndrey V. Elsukov p->len = 1; 2130f3afd27fSAndrey V. Elsukov p->subs[0] = 0; 2131f06ca4afSHartmut Brandt } 2132f3afd27fSAndrey V. Elsukov p->subs[p->len++] = ncomm; 2133f3afd27fSAndrey V. Elsukov c = comm_define_ordered(priv, descr, p, owner, str); 2134f3afd27fSAndrey V. Elsukov if (c == NULL) 2135f3afd27fSAndrey V. Elsukov return (0); 2136f06ca4afSHartmut Brandt return (c->value); 2137f06ca4afSHartmut Brandt } 2138f06ca4afSHartmut Brandt 2139f06ca4afSHartmut Brandt const char * 2140f06ca4afSHartmut Brandt comm_string(u_int ncomm) 2141f06ca4afSHartmut Brandt { 2142f06ca4afSHartmut Brandt struct community *p; 2143f06ca4afSHartmut Brandt 2144f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 2145f06ca4afSHartmut Brandt if (p->value == ncomm) 2146f06ca4afSHartmut Brandt return (p->string); 2147f06ca4afSHartmut Brandt return (NULL); 2148f06ca4afSHartmut Brandt } 2149f06ca4afSHartmut Brandt 2150f06ca4afSHartmut Brandt /* 2151f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2152f06ca4afSHartmut Brandt */ 2153f06ca4afSHartmut Brandt static void 2154f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 2155f06ca4afSHartmut Brandt { 2156f06ca4afSHartmut Brandt struct community *p, *p1; 2157f06ca4afSHartmut Brandt 2158f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 2159f06ca4afSHartmut Brandt while (p != NULL) { 2160f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2161f06ca4afSHartmut Brandt if (p->owner == mod) { 2162f06ca4afSHartmut Brandt free(p->string); 2163f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 2164f06ca4afSHartmut Brandt free(p); 2165f06ca4afSHartmut Brandt } 2166f06ca4afSHartmut Brandt p = p1; 2167f06ca4afSHartmut Brandt } 2168f06ca4afSHartmut Brandt } 2169f06ca4afSHartmut Brandt 2170f06ca4afSHartmut Brandt /* 2171f06ca4afSHartmut Brandt * Request ID handling. 2172f06ca4afSHartmut Brandt * 2173f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 2174f06ca4afSHartmut Brandt */ 2175f06ca4afSHartmut Brandt u_int 2176f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 2177f06ca4afSHartmut Brandt { 2178f06ca4afSHartmut Brandt u_int type; 2179f06ca4afSHartmut Brandt struct idrange *r, *r1; 2180f06ca4afSHartmut Brandt 2181f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 2182f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2183f06ca4afSHartmut Brandt return (0); 2184f06ca4afSHartmut Brandt } 2185f06ca4afSHartmut Brandt /* allocate a type id */ 2186f06ca4afSHartmut Brandt do { 2187f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 2188f06ca4afSHartmut Brandt next_idrange = 1; 2189f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2190f06ca4afSHartmut Brandt if (r->type == type) 2191f06ca4afSHartmut Brandt break; 2192f06ca4afSHartmut Brandt } while(r != NULL); 2193f06ca4afSHartmut Brandt 2194f06ca4afSHartmut Brandt /* find a range */ 2195f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 2196f06ca4afSHartmut Brandt r = NULL; 2197f06ca4afSHartmut Brandt else { 2198f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 2199f06ca4afSHartmut Brandt if (r->base < size) { 2200f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2201f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 2202f06ca4afSHartmut Brandt break; 2203f06ca4afSHartmut Brandt r = r1; 2204f06ca4afSHartmut Brandt } 2205f06ca4afSHartmut Brandt r = r1; 2206f06ca4afSHartmut Brandt } 2207f06ca4afSHartmut Brandt if (r == NULL) { 2208f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2209f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2210f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2211f06ca4afSHartmut Brandt return (0); 2212f06ca4afSHartmut Brandt } 2213f06ca4afSHartmut Brandt } 2214f06ca4afSHartmut Brandt } 2215f06ca4afSHartmut Brandt 2216f06ca4afSHartmut Brandt /* allocate structure */ 2217f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2218f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2219f06ca4afSHartmut Brandt return (0); 2220f06ca4afSHartmut Brandt } 2221f06ca4afSHartmut Brandt 2222f06ca4afSHartmut Brandt r1->type = type; 2223f06ca4afSHartmut Brandt r1->size = size; 2224f06ca4afSHartmut Brandt r1->owner = mod; 2225f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2226f06ca4afSHartmut Brandt r1->base = 0; 2227f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2228f06ca4afSHartmut Brandt } else if (r == NULL) { 2229f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2230f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2231f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2232f06ca4afSHartmut Brandt } else { 2233f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2234f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2235f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2236f06ca4afSHartmut Brandt } 2237f06ca4afSHartmut Brandt r1->next = r1->base; 2238f06ca4afSHartmut Brandt 2239f06ca4afSHartmut Brandt return (type); 2240f06ca4afSHartmut Brandt } 2241f06ca4afSHartmut Brandt 2242f06ca4afSHartmut Brandt int32_t 2243f06ca4afSHartmut Brandt reqid_next(u_int type) 2244f06ca4afSHartmut Brandt { 2245f06ca4afSHartmut Brandt struct idrange *r; 2246f06ca4afSHartmut Brandt int32_t id; 2247f06ca4afSHartmut Brandt 2248f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2249f06ca4afSHartmut Brandt if (r->type == type) 2250f06ca4afSHartmut Brandt break; 2251f06ca4afSHartmut Brandt if (r == NULL) { 2252f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2253f06ca4afSHartmut Brandt abort(); 2254f06ca4afSHartmut Brandt } 2255f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2256f06ca4afSHartmut Brandt r->next = r->base; 2257f06ca4afSHartmut Brandt return (id); 2258f06ca4afSHartmut Brandt } 2259f06ca4afSHartmut Brandt 2260f06ca4afSHartmut Brandt int32_t 2261f06ca4afSHartmut Brandt reqid_base(u_int type) 2262f06ca4afSHartmut Brandt { 2263f06ca4afSHartmut Brandt struct idrange *r; 2264f06ca4afSHartmut Brandt 2265f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2266f06ca4afSHartmut Brandt if (r->type == type) 2267f06ca4afSHartmut Brandt return (r->base); 2268f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2269f06ca4afSHartmut Brandt abort(); 2270f06ca4afSHartmut Brandt } 2271f06ca4afSHartmut Brandt 2272f06ca4afSHartmut Brandt u_int 2273f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2274f06ca4afSHartmut Brandt { 2275f06ca4afSHartmut Brandt struct idrange *r; 2276f06ca4afSHartmut Brandt 2277f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2278f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2279f06ca4afSHartmut Brandt return (r->type); 2280f06ca4afSHartmut Brandt return (0); 2281f06ca4afSHartmut Brandt } 2282f06ca4afSHartmut Brandt 2283f06ca4afSHartmut Brandt int 2284f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2285f06ca4afSHartmut Brandt { 2286f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2287f06ca4afSHartmut Brandt } 2288f06ca4afSHartmut Brandt 2289f06ca4afSHartmut Brandt /* 2290f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2291f06ca4afSHartmut Brandt */ 2292f06ca4afSHartmut Brandt static void 2293f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2294f06ca4afSHartmut Brandt { 2295f06ca4afSHartmut Brandt struct idrange *p, *p1; 2296f06ca4afSHartmut Brandt 2297f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2298f06ca4afSHartmut Brandt while (p != NULL) { 2299f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2300f06ca4afSHartmut Brandt if (p->owner == mod) { 2301f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2302f06ca4afSHartmut Brandt free(p); 2303f06ca4afSHartmut Brandt } 2304f06ca4afSHartmut Brandt p = p1; 2305f06ca4afSHartmut Brandt } 2306f06ca4afSHartmut Brandt } 2307f06ca4afSHartmut Brandt 2308f06ca4afSHartmut Brandt /* 2309f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2310f06ca4afSHartmut Brandt */ 2311f06ca4afSHartmut Brandt static int 2312f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2313f06ca4afSHartmut Brandt { 2314f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2315f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2316f06ca4afSHartmut Brandt 2317f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2318f06ca4afSHartmut Brandt } 2319f06ca4afSHartmut Brandt static int 2320f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2321f06ca4afSHartmut Brandt { 2322f06ca4afSHartmut Brandt struct snmp_node *xtree; 2323f06ca4afSHartmut Brandt u_int i; 2324f06ca4afSHartmut Brandt 2325f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2326f06ca4afSHartmut Brandt if (xtree == NULL) { 23278eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2328f06ca4afSHartmut Brandt return (-1); 2329f06ca4afSHartmut Brandt } 2330f06ca4afSHartmut Brandt tree = xtree; 2331f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2332f06ca4afSHartmut Brandt 2333f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 23348eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2335f06ca4afSHartmut Brandt 2336f06ca4afSHartmut Brandt tree_size += nsize; 2337f06ca4afSHartmut Brandt 2338f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2339f06ca4afSHartmut Brandt 2340f06ca4afSHartmut Brandt return (0); 2341f06ca4afSHartmut Brandt } 2342f06ca4afSHartmut Brandt 2343f06ca4afSHartmut Brandt /* 2344f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2345f06ca4afSHartmut Brandt */ 2346f06ca4afSHartmut Brandt static void 2347f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2348f06ca4afSHartmut Brandt { 2349f06ca4afSHartmut Brandt u_int s, d; 2350f06ca4afSHartmut Brandt 2351f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 23528eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2353f06ca4afSHartmut Brandt if (s != d) 2354f06ca4afSHartmut Brandt tree[d] = tree[s]; 2355f06ca4afSHartmut Brandt d++; 2356f06ca4afSHartmut Brandt } 2357f06ca4afSHartmut Brandt tree_size = d; 2358f06ca4afSHartmut Brandt } 2359f06ca4afSHartmut Brandt 2360f06ca4afSHartmut Brandt /* 2361f06ca4afSHartmut Brandt * Loadable modules 2362f06ca4afSHartmut Brandt */ 2363f06ca4afSHartmut Brandt struct lmodule * 2364f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2365f06ca4afSHartmut Brandt { 2366f06ca4afSHartmut Brandt struct lmodule *m; 2367f06ca4afSHartmut Brandt int err; 2368f06ca4afSHartmut Brandt int i; 2369f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2370f06ca4afSHartmut Brandt int ac; 2371f06ca4afSHartmut Brandt u_int u; 2372f06ca4afSHartmut Brandt 2373f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2374f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2375f06ca4afSHartmut Brandt return (NULL); 2376f06ca4afSHartmut Brandt } 2377f06ca4afSHartmut Brandt m->handle = NULL; 2378f06ca4afSHartmut Brandt m->flags = 0; 237910a0306aSEnji Cooper strlcpy(m->section, section, sizeof(m->section)); 2380f06ca4afSHartmut Brandt 238110a0306aSEnji Cooper if ((m->path = strdup(path)) == NULL) { 2382f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2383f06ca4afSHartmut Brandt goto err; 2384f06ca4afSHartmut Brandt } 2385f06ca4afSHartmut Brandt 2386f06ca4afSHartmut Brandt /* 2387f06ca4afSHartmut Brandt * Make index 2388f06ca4afSHartmut Brandt */ 2389f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2390f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2391f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2392f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2393f06ca4afSHartmut Brandt 2394f06ca4afSHartmut Brandt /* 2395f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2396f06ca4afSHartmut Brandt */ 2397f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2398f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2399f06ca4afSHartmut Brandt goto err; 2400f06ca4afSHartmut Brandt } 2401f06ca4afSHartmut Brandt 2402f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2403f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2404f06ca4afSHartmut Brandt goto err; 2405f06ca4afSHartmut Brandt } 2406f06ca4afSHartmut Brandt 2407f06ca4afSHartmut Brandt /* 2408f06ca4afSHartmut Brandt * Insert it into the right place 2409f06ca4afSHartmut Brandt */ 2410f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2411f06ca4afSHartmut Brandt 2412f06ca4afSHartmut Brandt /* preserve order */ 2413f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2414f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2415f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2416f06ca4afSHartmut Brandt } 2417f06ca4afSHartmut Brandt 2418f06ca4afSHartmut Brandt /* 2419f06ca4afSHartmut Brandt * make the argument vector. 2420f06ca4afSHartmut Brandt */ 2421f06ca4afSHartmut Brandt ac = 0; 2422f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2423f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2424f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2425f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2426f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2427f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2428f06ca4afSHartmut Brandt "module '%s", section); 2429f06ca4afSHartmut Brandt break; 2430f06ca4afSHartmut Brandt } 2431f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2432f06ca4afSHartmut Brandt } 2433f06ca4afSHartmut Brandt } 2434f06ca4afSHartmut Brandt av[ac] = NULL; 2435f06ca4afSHartmut Brandt 2436f06ca4afSHartmut Brandt /* 2437165c5d31SHartmut Brandt * Run the initialization function 2438f06ca4afSHartmut Brandt */ 2439f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2440f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2441f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2442f06ca4afSHartmut Brandt goto err; 2443f06ca4afSHartmut Brandt } 2444f06ca4afSHartmut Brandt 2445f06ca4afSHartmut Brandt return (m); 2446f06ca4afSHartmut Brandt 2447f06ca4afSHartmut Brandt err: 2448691f8568SShteryana Shopova if ((m->flags & LM_ONSTARTLIST) != 0) 2449691f8568SShteryana Shopova TAILQ_REMOVE(&modules_start, m, start); 2450f06ca4afSHartmut Brandt if (m->handle) 2451f06ca4afSHartmut Brandt dlclose(m->handle); 2452f06ca4afSHartmut Brandt free(m->path); 2453f06ca4afSHartmut Brandt free(m); 2454f06ca4afSHartmut Brandt return (NULL); 2455f06ca4afSHartmut Brandt } 2456f06ca4afSHartmut Brandt 2457f06ca4afSHartmut Brandt /* 2458f06ca4afSHartmut Brandt * Start a module 2459f06ca4afSHartmut Brandt */ 2460f06ca4afSHartmut Brandt void 2461f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2462f06ca4afSHartmut Brandt { 2463f06ca4afSHartmut Brandt const struct lmodule *m; 2464f06ca4afSHartmut Brandt 2465f06ca4afSHartmut Brandt /* 2466f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2467f06ca4afSHartmut Brandt */ 2468f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2469f06ca4afSHartmut Brandt lm_unload(mod); 2470f06ca4afSHartmut Brandt return; 2471f06ca4afSHartmut Brandt } 2472f06ca4afSHartmut Brandt 2473f06ca4afSHartmut Brandt /* 2474f06ca4afSHartmut Brandt * Read configuration 2475f06ca4afSHartmut Brandt */ 2476f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2477f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2478f06ca4afSHartmut Brandt lm_unload(mod); 2479f06ca4afSHartmut Brandt return; 2480f06ca4afSHartmut Brandt } 2481f06ca4afSHartmut Brandt if (mod->config->start) 2482f06ca4afSHartmut Brandt (*mod->config->start)(); 2483f06ca4afSHartmut Brandt 2484f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2485f06ca4afSHartmut Brandt 2486f06ca4afSHartmut Brandt /* 2487f06ca4afSHartmut Brandt * Inform other modules 2488f06ca4afSHartmut Brandt */ 2489f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2490f06ca4afSHartmut Brandt if (m->config->loading) 2491f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2492f06ca4afSHartmut Brandt } 2493f06ca4afSHartmut Brandt 2494f06ca4afSHartmut Brandt 2495f06ca4afSHartmut Brandt /* 2496f06ca4afSHartmut Brandt * Unload a module. 2497f06ca4afSHartmut Brandt */ 2498f06ca4afSHartmut Brandt void 2499f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2500f06ca4afSHartmut Brandt { 2501f06ca4afSHartmut Brandt int err; 2502f06ca4afSHartmut Brandt const struct lmodule *mod; 2503f06ca4afSHartmut Brandt 2504f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2505f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2506f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2507f06ca4afSHartmut Brandt tree_unmerge(m); 2508f06ca4afSHartmut Brandt 2509f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2510f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2511f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2512f06ca4afSHartmut Brandt 2513f06ca4afSHartmut Brandt comm_flush(m); 2514f06ca4afSHartmut Brandt reqid_flush(m); 2515f06ca4afSHartmut Brandt timer_flush(m); 2516f06ca4afSHartmut Brandt fd_flush(m); 2517f06ca4afSHartmut Brandt 2518f06ca4afSHartmut Brandt dlclose(m->handle); 2519f06ca4afSHartmut Brandt free(m->path); 2520f06ca4afSHartmut Brandt 2521f06ca4afSHartmut Brandt /* 2522f06ca4afSHartmut Brandt * Inform other modules 2523f06ca4afSHartmut Brandt */ 2524f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2525f06ca4afSHartmut Brandt if (mod->config->loading) 2526f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2527f06ca4afSHartmut Brandt 2528f06ca4afSHartmut Brandt free(m); 2529f06ca4afSHartmut Brandt } 2530f06ca4afSHartmut Brandt 2531f06ca4afSHartmut Brandt /* 2532f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2533f06ca4afSHartmut Brandt */ 2534f06ca4afSHartmut Brandt u_int 2535f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2536f06ca4afSHartmut Brandt { 2537f06ca4afSHartmut Brandt struct objres *objres, *or1; 2538f06ca4afSHartmut Brandt u_int idx; 2539f06ca4afSHartmut Brandt 2540f06ca4afSHartmut Brandt /* find a free index */ 2541f06ca4afSHartmut Brandt idx = 1; 2542f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2543f06ca4afSHartmut Brandt objres != NULL; 2544f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2545f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2546f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2547f06ca4afSHartmut Brandt idx = objres->index + 1; 2548f06ca4afSHartmut Brandt break; 2549f06ca4afSHartmut Brandt } 2550f06ca4afSHartmut Brandt } 2551f06ca4afSHartmut Brandt 2552f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2553f06ca4afSHartmut Brandt return (0); 2554f06ca4afSHartmut Brandt 2555f06ca4afSHartmut Brandt objres->index = idx; 2556f06ca4afSHartmut Brandt objres->oid = *or; 2557f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 255869292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2559f06ca4afSHartmut Brandt objres->module = mod; 2560f06ca4afSHartmut Brandt 2561f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2562f06ca4afSHartmut Brandt 2563f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2564f06ca4afSHartmut Brandt 2565f06ca4afSHartmut Brandt return (idx); 2566f06ca4afSHartmut Brandt } 2567f06ca4afSHartmut Brandt 2568f06ca4afSHartmut Brandt void 2569f06ca4afSHartmut Brandt or_unregister(u_int idx) 2570f06ca4afSHartmut Brandt { 2571f06ca4afSHartmut Brandt struct objres *objres; 2572f06ca4afSHartmut Brandt 2573f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2574f06ca4afSHartmut Brandt if (objres->index == idx) { 2575f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2576f06ca4afSHartmut Brandt free(objres); 2577f06ca4afSHartmut Brandt return; 2578f06ca4afSHartmut Brandt } 2579f06ca4afSHartmut Brandt } 2580135f7de5SShteryana Shopova 2581135f7de5SShteryana Shopova /* 2582135f7de5SShteryana Shopova * RFC 3414 User-based Security Model support 2583135f7de5SShteryana Shopova */ 2584135f7de5SShteryana Shopova 2585135f7de5SShteryana Shopova struct snmpd_usmstat * 2586135f7de5SShteryana Shopova bsnmpd_get_usm_stats(void) 2587135f7de5SShteryana Shopova { 2588135f7de5SShteryana Shopova return (&snmpd_usmstats); 2589135f7de5SShteryana Shopova } 2590135f7de5SShteryana Shopova 2591135f7de5SShteryana Shopova void 2592135f7de5SShteryana Shopova bsnmpd_reset_usm_stats(void) 2593135f7de5SShteryana Shopova { 25949972acaaSHartmut Brandt memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2595135f7de5SShteryana Shopova } 2596135f7de5SShteryana Shopova 2597135f7de5SShteryana Shopova struct usm_user * 2598135f7de5SShteryana Shopova usm_first_user(void) 2599135f7de5SShteryana Shopova { 2600135f7de5SShteryana Shopova return (SLIST_FIRST(&usm_userlist)); 2601135f7de5SShteryana Shopova } 2602135f7de5SShteryana Shopova 2603135f7de5SShteryana Shopova struct usm_user * 2604135f7de5SShteryana Shopova usm_next_user(struct usm_user *uuser) 2605135f7de5SShteryana Shopova { 2606135f7de5SShteryana Shopova if (uuser == NULL) 2607135f7de5SShteryana Shopova return (NULL); 2608135f7de5SShteryana Shopova 2609135f7de5SShteryana Shopova return (SLIST_NEXT(uuser, up)); 2610135f7de5SShteryana Shopova } 2611135f7de5SShteryana Shopova 2612135f7de5SShteryana Shopova struct usm_user * 2613135f7de5SShteryana Shopova usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2614135f7de5SShteryana Shopova { 2615135f7de5SShteryana Shopova struct usm_user *uuser; 2616135f7de5SShteryana Shopova 2617135f7de5SShteryana Shopova SLIST_FOREACH(uuser, &usm_userlist, up) 2618135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2619135f7de5SShteryana Shopova memcmp(uuser->user_engine_id, engine, elen) == 0 && 2620135f7de5SShteryana Shopova strlen(uuser->suser.sec_name) == strlen(uname) && 2621135f7de5SShteryana Shopova strcmp(uuser->suser.sec_name, uname) == 0) 2622135f7de5SShteryana Shopova break; 2623135f7de5SShteryana Shopova 2624135f7de5SShteryana Shopova return (uuser); 2625135f7de5SShteryana Shopova } 2626135f7de5SShteryana Shopova 2627135f7de5SShteryana Shopova static int 2628135f7de5SShteryana Shopova usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2629135f7de5SShteryana Shopova { 2630135f7de5SShteryana Shopova uint32_t i; 2631135f7de5SShteryana Shopova 2632135f7de5SShteryana Shopova if (u1->user_engine_len < u2->user_engine_len) 2633135f7de5SShteryana Shopova return (-1); 2634135f7de5SShteryana Shopova if (u1->user_engine_len > u2->user_engine_len) 2635135f7de5SShteryana Shopova return (1); 2636135f7de5SShteryana Shopova 2637135f7de5SShteryana Shopova for (i = 0; i < u1->user_engine_len; i++) { 2638135f7de5SShteryana Shopova if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2639135f7de5SShteryana Shopova return (-1); 2640135f7de5SShteryana Shopova if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2641135f7de5SShteryana Shopova return (1); 2642135f7de5SShteryana Shopova } 2643135f7de5SShteryana Shopova 2644135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2645135f7de5SShteryana Shopova return (-1); 2646135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2647135f7de5SShteryana Shopova return (1); 2648135f7de5SShteryana Shopova 2649135f7de5SShteryana Shopova for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2650135f7de5SShteryana Shopova if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2651135f7de5SShteryana Shopova return (-1); 2652135f7de5SShteryana Shopova if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2653135f7de5SShteryana Shopova return (1); 2654135f7de5SShteryana Shopova } 2655135f7de5SShteryana Shopova 2656135f7de5SShteryana Shopova return (0); 2657135f7de5SShteryana Shopova } 2658135f7de5SShteryana Shopova 2659135f7de5SShteryana Shopova struct usm_user * 2660135f7de5SShteryana Shopova usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2661135f7de5SShteryana Shopova { 2662135f7de5SShteryana Shopova int cmp; 2663135f7de5SShteryana Shopova struct usm_user *uuser, *temp, *prev; 2664135f7de5SShteryana Shopova 2665135f7de5SShteryana Shopova for (uuser = usm_first_user(); uuser != NULL; 2666135f7de5SShteryana Shopova (uuser = usm_next_user(uuser))) { 2667135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2668135f7de5SShteryana Shopova strlen(uname) == strlen(uuser->suser.sec_name) && 2669135f7de5SShteryana Shopova strcmp(uname, uuser->suser.sec_name) == 0 && 2670135f7de5SShteryana Shopova memcmp(eid, uuser->user_engine_id, elen) == 0) 2671135f7de5SShteryana Shopova return (NULL); 2672135f7de5SShteryana Shopova } 2673135f7de5SShteryana Shopova 2674135f7de5SShteryana Shopova if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2675135f7de5SShteryana Shopova return (NULL); 2676135f7de5SShteryana Shopova 26778ad8cdc9SEnji Cooper memset(uuser, 0, sizeof(*uuser)); 2678135f7de5SShteryana Shopova strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2679135f7de5SShteryana Shopova memcpy(uuser->user_engine_id, eid, elen); 2680135f7de5SShteryana Shopova uuser->user_engine_len = elen; 2681135f7de5SShteryana Shopova 2682135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2683135f7de5SShteryana Shopova usm_compare_user(uuser, prev) < 0) { 2684135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2685135f7de5SShteryana Shopova return (uuser); 2686135f7de5SShteryana Shopova } 2687135f7de5SShteryana Shopova 2688135f7de5SShteryana Shopova SLIST_FOREACH(temp, &usm_userlist, up) { 2689135f7de5SShteryana Shopova if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2690135f7de5SShteryana Shopova break; 2691135f7de5SShteryana Shopova prev = temp; 2692135f7de5SShteryana Shopova } 2693135f7de5SShteryana Shopova 2694135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2695135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, uuser, up); 2696135f7de5SShteryana Shopova else if (cmp > 0) 2697135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, uuser, up); 2698135f7de5SShteryana Shopova else { 2699135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2700135f7de5SShteryana Shopova free(uuser); 2701135f7de5SShteryana Shopova return (NULL); 2702135f7de5SShteryana Shopova } 2703135f7de5SShteryana Shopova 2704135f7de5SShteryana Shopova return (uuser); 2705135f7de5SShteryana Shopova } 2706135f7de5SShteryana Shopova 2707135f7de5SShteryana Shopova void 2708135f7de5SShteryana Shopova usm_delete_user(struct usm_user *uuser) 2709135f7de5SShteryana Shopova { 2710135f7de5SShteryana Shopova SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2711135f7de5SShteryana Shopova free(uuser); 2712135f7de5SShteryana Shopova } 2713135f7de5SShteryana Shopova 2714135f7de5SShteryana Shopova void 2715135f7de5SShteryana Shopova usm_flush_users(void) 2716135f7de5SShteryana Shopova { 2717135f7de5SShteryana Shopova struct usm_user *uuser; 2718135f7de5SShteryana Shopova 2719135f7de5SShteryana Shopova while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2720135f7de5SShteryana Shopova SLIST_REMOVE_HEAD(&usm_userlist, up); 2721135f7de5SShteryana Shopova free(uuser); 2722135f7de5SShteryana Shopova } 2723135f7de5SShteryana Shopova 2724135f7de5SShteryana Shopova SLIST_INIT(&usm_userlist); 2725135f7de5SShteryana Shopova } 2726135f7de5SShteryana Shopova 2727135f7de5SShteryana Shopova /* 2728135f7de5SShteryana Shopova * RFC 3415 View-based Access Control Model support 2729135f7de5SShteryana Shopova */ 2730135f7de5SShteryana Shopova struct vacm_user * 2731135f7de5SShteryana Shopova vacm_first_user(void) 2732135f7de5SShteryana Shopova { 2733135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_userlist)); 2734135f7de5SShteryana Shopova } 2735135f7de5SShteryana Shopova 2736135f7de5SShteryana Shopova struct vacm_user * 2737135f7de5SShteryana Shopova vacm_next_user(struct vacm_user *vuser) 2738135f7de5SShteryana Shopova { 2739135f7de5SShteryana Shopova if (vuser == NULL) 2740135f7de5SShteryana Shopova return (NULL); 2741135f7de5SShteryana Shopova 2742135f7de5SShteryana Shopova return (SLIST_NEXT(vuser, vvu)); 2743135f7de5SShteryana Shopova } 2744135f7de5SShteryana Shopova 2745135f7de5SShteryana Shopova static int 2746135f7de5SShteryana Shopova vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2747135f7de5SShteryana Shopova { 2748135f7de5SShteryana Shopova uint32_t i; 2749135f7de5SShteryana Shopova 2750135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2751135f7de5SShteryana Shopova return (-1); 2752135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2753135f7de5SShteryana Shopova return (1); 2754135f7de5SShteryana Shopova 2755135f7de5SShteryana Shopova if (strlen(v1->secname) < strlen(v2->secname)) 2756135f7de5SShteryana Shopova return (-1); 2757135f7de5SShteryana Shopova if (strlen(v1->secname) > strlen(v2->secname)) 2758135f7de5SShteryana Shopova return (1); 2759135f7de5SShteryana Shopova 2760135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->secname); i++) { 2761135f7de5SShteryana Shopova if (v1->secname[i] < v2->secname[i]) 2762135f7de5SShteryana Shopova return (-1); 2763135f7de5SShteryana Shopova if (v1->secname[i] > v2->secname[i]) 2764135f7de5SShteryana Shopova return (1); 2765135f7de5SShteryana Shopova } 2766135f7de5SShteryana Shopova 2767135f7de5SShteryana Shopova return (0); 2768135f7de5SShteryana Shopova } 2769135f7de5SShteryana Shopova 2770135f7de5SShteryana Shopova struct vacm_user * 2771135f7de5SShteryana Shopova vacm_new_user(int32_t smodel, char *uname) 2772135f7de5SShteryana Shopova { 2773135f7de5SShteryana Shopova int cmp; 2774135f7de5SShteryana Shopova struct vacm_user *user, *temp, *prev; 2775135f7de5SShteryana Shopova 2776135f7de5SShteryana Shopova SLIST_FOREACH(user, &vacm_userlist, vvu) 2777135f7de5SShteryana Shopova if (strcmp(uname, user->secname) == 0 && 2778135f7de5SShteryana Shopova smodel == user->sec_model) 2779135f7de5SShteryana Shopova return (NULL); 2780135f7de5SShteryana Shopova 2781135f7de5SShteryana Shopova if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2782135f7de5SShteryana Shopova return (NULL); 2783135f7de5SShteryana Shopova 2784135f7de5SShteryana Shopova memset(user, 0, sizeof(*user)); 2785135f7de5SShteryana Shopova user->group = &vacm_default_group; 2786135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2787135f7de5SShteryana Shopova user->sec_model = smodel; 2788135f7de5SShteryana Shopova strlcpy(user->secname, uname, sizeof(user->secname)); 2789135f7de5SShteryana Shopova 2790135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2791135f7de5SShteryana Shopova vacm_compare_user(user, prev) < 0) { 2792135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2793135f7de5SShteryana Shopova return (user); 2794135f7de5SShteryana Shopova } 2795135f7de5SShteryana Shopova 2796135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2797135f7de5SShteryana Shopova if ((cmp = vacm_compare_user(user, temp)) <= 0) 2798135f7de5SShteryana Shopova break; 2799135f7de5SShteryana Shopova prev = temp; 2800135f7de5SShteryana Shopova } 2801135f7de5SShteryana Shopova 2802135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2803135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, user, vvu); 2804135f7de5SShteryana Shopova else if (cmp > 0) 2805135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, user, vvu); 2806135f7de5SShteryana Shopova else { 2807135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", user->secname); 2808135f7de5SShteryana Shopova free(user); 2809135f7de5SShteryana Shopova return (NULL); 2810135f7de5SShteryana Shopova } 2811135f7de5SShteryana Shopova 2812135f7de5SShteryana Shopova return (user); 2813135f7de5SShteryana Shopova } 2814135f7de5SShteryana Shopova 2815135f7de5SShteryana Shopova int 2816135f7de5SShteryana Shopova vacm_delete_user(struct vacm_user *user) 2817135f7de5SShteryana Shopova { 2818135f7de5SShteryana Shopova if (user->group != NULL && user->group != &vacm_default_group) { 2819135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2820135f7de5SShteryana Shopova if (SLIST_EMPTY(&user->group->group_users)) { 2821135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_grouplist, user->group, 2822135f7de5SShteryana Shopova vacm_group, vge); 2823135f7de5SShteryana Shopova free(user->group); 2824135f7de5SShteryana Shopova } 2825135f7de5SShteryana Shopova } 2826135f7de5SShteryana Shopova 2827135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2828135f7de5SShteryana Shopova free(user); 2829135f7de5SShteryana Shopova 2830135f7de5SShteryana Shopova return (0); 2831135f7de5SShteryana Shopova } 2832135f7de5SShteryana Shopova 2833135f7de5SShteryana Shopova int 2834135f7de5SShteryana Shopova vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2835135f7de5SShteryana Shopova { 2836135f7de5SShteryana Shopova struct vacm_group *group; 2837135f7de5SShteryana Shopova 2838135f7de5SShteryana Shopova if (len >= SNMP_ADM_STR32_SIZ) 2839135f7de5SShteryana Shopova return (-1); 2840135f7de5SShteryana Shopova 2841135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2842135f7de5SShteryana Shopova if (strlen(group->groupname) == len && 2843135f7de5SShteryana Shopova memcmp(octets, group->groupname, len) == 0) 2844135f7de5SShteryana Shopova break; 2845135f7de5SShteryana Shopova 2846135f7de5SShteryana Shopova if (group == NULL) { 2847135f7de5SShteryana Shopova if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2848135f7de5SShteryana Shopova return (-1); 2849135f7de5SShteryana Shopova memset(group, 0, sizeof(*group)); 2850135f7de5SShteryana Shopova memcpy(group->groupname, octets, len); 2851135f7de5SShteryana Shopova group->groupname[len] = '\0'; 2852135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2853135f7de5SShteryana Shopova } 2854135f7de5SShteryana Shopova 2855135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2856135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2857135f7de5SShteryana Shopova user->group = group; 2858135f7de5SShteryana Shopova 2859135f7de5SShteryana Shopova return (0); 2860135f7de5SShteryana Shopova } 2861135f7de5SShteryana Shopova 2862135f7de5SShteryana Shopova void 2863135f7de5SShteryana Shopova vacm_groups_init(void) 2864135f7de5SShteryana Shopova { 2865135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2866135f7de5SShteryana Shopova } 2867135f7de5SShteryana Shopova 2868135f7de5SShteryana Shopova struct vacm_access * 2869135f7de5SShteryana Shopova vacm_first_access_rule(void) 2870135f7de5SShteryana Shopova { 2871135f7de5SShteryana Shopova return (TAILQ_FIRST(&vacm_accesslist)); 2872135f7de5SShteryana Shopova } 2873135f7de5SShteryana Shopova 2874135f7de5SShteryana Shopova struct vacm_access * 2875135f7de5SShteryana Shopova vacm_next_access_rule(struct vacm_access *acl) 2876135f7de5SShteryana Shopova { 2877135f7de5SShteryana Shopova if (acl == NULL) 2878135f7de5SShteryana Shopova return (NULL); 2879135f7de5SShteryana Shopova 2880135f7de5SShteryana Shopova return (TAILQ_NEXT(acl, vva)); 2881135f7de5SShteryana Shopova } 2882135f7de5SShteryana Shopova 2883135f7de5SShteryana Shopova static int 2884135f7de5SShteryana Shopova vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2885135f7de5SShteryana Shopova { 2886135f7de5SShteryana Shopova uint32_t i; 2887135f7de5SShteryana Shopova 2888135f7de5SShteryana Shopova if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 2889135f7de5SShteryana Shopova return (-1); 2890135f7de5SShteryana Shopova if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 2891135f7de5SShteryana Shopova return (1); 2892135f7de5SShteryana Shopova 2893135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->group->groupname); i++) { 2894135f7de5SShteryana Shopova if (v1->group->groupname[i] < v2->group->groupname[i]) 2895135f7de5SShteryana Shopova return (-1); 2896135f7de5SShteryana Shopova if (v1->group->groupname[i] > v2->group->groupname[i]) 2897135f7de5SShteryana Shopova return (1); 2898135f7de5SShteryana Shopova } 2899135f7de5SShteryana Shopova 2900135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 2901135f7de5SShteryana Shopova return (-1); 2902135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 2903135f7de5SShteryana Shopova return (1); 2904135f7de5SShteryana Shopova 2905135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->ctx_prefix); i++) { 2906135f7de5SShteryana Shopova if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 2907135f7de5SShteryana Shopova return (-1); 2908135f7de5SShteryana Shopova if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 2909135f7de5SShteryana Shopova return (1); 2910135f7de5SShteryana Shopova } 2911135f7de5SShteryana Shopova 2912135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2913135f7de5SShteryana Shopova return (-1); 2914135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2915135f7de5SShteryana Shopova return (1); 2916135f7de5SShteryana Shopova 2917135f7de5SShteryana Shopova if (v1->sec_level < v2->sec_level) 2918135f7de5SShteryana Shopova return (-1); 2919135f7de5SShteryana Shopova if (v1->sec_level > v2->sec_level) 2920135f7de5SShteryana Shopova return (1); 2921135f7de5SShteryana Shopova 2922135f7de5SShteryana Shopova return (0); 2923135f7de5SShteryana Shopova } 2924135f7de5SShteryana Shopova 2925135f7de5SShteryana Shopova struct vacm_access * 2926135f7de5SShteryana Shopova vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 2927135f7de5SShteryana Shopova { 2928135f7de5SShteryana Shopova struct vacm_group *group; 2929135f7de5SShteryana Shopova struct vacm_access *acl, *temp; 2930135f7de5SShteryana Shopova 2931135f7de5SShteryana Shopova TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 2932135f7de5SShteryana Shopova if (acl->group == NULL) 2933135f7de5SShteryana Shopova continue; 2934135f7de5SShteryana Shopova if (strcmp(gname, acl->group->groupname) == 0 && 2935135f7de5SShteryana Shopova strcmp(cprefix, acl->ctx_prefix) == 0 && 2936135f7de5SShteryana Shopova acl->sec_model == smodel && acl->sec_level == slevel) 2937135f7de5SShteryana Shopova return (NULL); 2938135f7de5SShteryana Shopova } 2939135f7de5SShteryana Shopova 2940135f7de5SShteryana Shopova /* Make sure the group exists */ 2941135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2942135f7de5SShteryana Shopova if (strcmp(gname, group->groupname) == 0) 2943135f7de5SShteryana Shopova break; 2944135f7de5SShteryana Shopova 2945135f7de5SShteryana Shopova if (group == NULL) 2946135f7de5SShteryana Shopova return (NULL); 2947135f7de5SShteryana Shopova 2948135f7de5SShteryana Shopova if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 2949135f7de5SShteryana Shopova return (NULL); 2950135f7de5SShteryana Shopova 2951135f7de5SShteryana Shopova memset(acl, 0, sizeof(*acl)); 2952135f7de5SShteryana Shopova acl->group = group; 2953135f7de5SShteryana Shopova strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 2954135f7de5SShteryana Shopova acl->sec_model = smodel; 2955135f7de5SShteryana Shopova acl->sec_level = slevel; 2956135f7de5SShteryana Shopova 2957135f7de5SShteryana Shopova if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 2958135f7de5SShteryana Shopova vacm_compare_access_rule(acl, temp) < 0) { 2959135f7de5SShteryana Shopova TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 2960135f7de5SShteryana Shopova return (acl); 2961135f7de5SShteryana Shopova } 2962135f7de5SShteryana Shopova 2963135f7de5SShteryana Shopova TAILQ_FOREACH(temp, &vacm_accesslist, vva) 2964135f7de5SShteryana Shopova if (vacm_compare_access_rule(acl, temp) < 0) { 2965135f7de5SShteryana Shopova TAILQ_INSERT_BEFORE(temp, acl, vva); 2966135f7de5SShteryana Shopova return (acl); 2967135f7de5SShteryana Shopova } 2968135f7de5SShteryana Shopova 2969135f7de5SShteryana Shopova TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 2970135f7de5SShteryana Shopova 2971135f7de5SShteryana Shopova return (acl); 2972135f7de5SShteryana Shopova } 2973135f7de5SShteryana Shopova 2974135f7de5SShteryana Shopova int 2975135f7de5SShteryana Shopova vacm_delete_access_rule(struct vacm_access *acl) 2976135f7de5SShteryana Shopova { 2977135f7de5SShteryana Shopova TAILQ_REMOVE(&vacm_accesslist, acl, vva); 2978135f7de5SShteryana Shopova free(acl); 2979135f7de5SShteryana Shopova 2980135f7de5SShteryana Shopova return (0); 2981135f7de5SShteryana Shopova } 2982135f7de5SShteryana Shopova 2983135f7de5SShteryana Shopova struct vacm_view * 2984135f7de5SShteryana Shopova vacm_first_view(void) 2985135f7de5SShteryana Shopova { 2986135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_viewlist)); 2987135f7de5SShteryana Shopova } 2988135f7de5SShteryana Shopova 2989135f7de5SShteryana Shopova struct vacm_view * 2990135f7de5SShteryana Shopova vacm_next_view(struct vacm_view *view) 2991135f7de5SShteryana Shopova { 2992135f7de5SShteryana Shopova if (view == NULL) 2993135f7de5SShteryana Shopova return (NULL); 2994135f7de5SShteryana Shopova 2995135f7de5SShteryana Shopova return (SLIST_NEXT(view, vvl)); 2996135f7de5SShteryana Shopova } 2997135f7de5SShteryana Shopova 2998135f7de5SShteryana Shopova static int 2999135f7de5SShteryana Shopova vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3000135f7de5SShteryana Shopova { 3001135f7de5SShteryana Shopova uint32_t i; 3002135f7de5SShteryana Shopova 3003135f7de5SShteryana Shopova if (strlen(v1->viewname) < strlen(v2->viewname)) 3004135f7de5SShteryana Shopova return (-1); 3005135f7de5SShteryana Shopova if (strlen(v1->viewname) > strlen(v2->viewname)) 3006135f7de5SShteryana Shopova return (1); 3007135f7de5SShteryana Shopova 3008135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->viewname); i++) { 3009135f7de5SShteryana Shopova if (v1->viewname[i] < v2->viewname[i]) 3010135f7de5SShteryana Shopova return (-1); 3011135f7de5SShteryana Shopova if (v1->viewname[i] > v2->viewname[i]) 3012135f7de5SShteryana Shopova return (1); 3013135f7de5SShteryana Shopova } 3014135f7de5SShteryana Shopova 3015135f7de5SShteryana Shopova return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3016135f7de5SShteryana Shopova } 3017135f7de5SShteryana Shopova 3018135f7de5SShteryana Shopova struct vacm_view * 3019135f7de5SShteryana Shopova vacm_new_view(char *vname, struct asn_oid *oid) 3020135f7de5SShteryana Shopova { 3021135f7de5SShteryana Shopova int cmp; 3022135f7de5SShteryana Shopova struct vacm_view *view, *temp, *prev; 3023135f7de5SShteryana Shopova 3024135f7de5SShteryana Shopova SLIST_FOREACH(view, &vacm_viewlist, vvl) 3025135f7de5SShteryana Shopova if (strcmp(vname, view->viewname) == 0) 3026135f7de5SShteryana Shopova return (NULL); 3027135f7de5SShteryana Shopova 3028135f7de5SShteryana Shopova if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3029135f7de5SShteryana Shopova return (NULL); 3030135f7de5SShteryana Shopova 3031135f7de5SShteryana Shopova memset(view, 0, sizeof(*view)); 3032135f7de5SShteryana Shopova strlcpy(view->viewname, vname, sizeof(view->viewname)); 3033135f7de5SShteryana Shopova asn_append_oid(&view->subtree, oid); 3034135f7de5SShteryana Shopova 3035135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3036135f7de5SShteryana Shopova vacm_compare_view(view, prev) < 0) { 3037135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3038135f7de5SShteryana Shopova return (view); 3039135f7de5SShteryana Shopova } 3040135f7de5SShteryana Shopova 3041135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3042135f7de5SShteryana Shopova if ((cmp = vacm_compare_view(view, temp)) <= 0) 3043135f7de5SShteryana Shopova break; 3044135f7de5SShteryana Shopova prev = temp; 3045135f7de5SShteryana Shopova } 3046135f7de5SShteryana Shopova 3047135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3048135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, view, vvl); 3049135f7de5SShteryana Shopova else if (cmp > 0) 3050135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, view, vvl); 3051135f7de5SShteryana Shopova else { 3052135f7de5SShteryana Shopova syslog(LOG_ERR, "View %s exists", view->viewname); 3053135f7de5SShteryana Shopova free(view); 3054135f7de5SShteryana Shopova return (NULL); 3055135f7de5SShteryana Shopova } 3056135f7de5SShteryana Shopova 3057135f7de5SShteryana Shopova return (view); 3058135f7de5SShteryana Shopova } 3059135f7de5SShteryana Shopova 3060135f7de5SShteryana Shopova int 3061135f7de5SShteryana Shopova vacm_delete_view(struct vacm_view *view) 3062135f7de5SShteryana Shopova { 3063135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3064135f7de5SShteryana Shopova free(view); 3065135f7de5SShteryana Shopova 3066135f7de5SShteryana Shopova return (0); 3067135f7de5SShteryana Shopova } 3068135f7de5SShteryana Shopova 3069135f7de5SShteryana Shopova struct vacm_context * 3070135f7de5SShteryana Shopova vacm_first_context(void) 3071135f7de5SShteryana Shopova { 3072135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_contextlist)); 3073135f7de5SShteryana Shopova } 3074135f7de5SShteryana Shopova 3075135f7de5SShteryana Shopova struct vacm_context * 3076135f7de5SShteryana Shopova vacm_next_context(struct vacm_context *vacmctx) 3077135f7de5SShteryana Shopova { 3078135f7de5SShteryana Shopova if (vacmctx == NULL) 3079135f7de5SShteryana Shopova return (NULL); 3080135f7de5SShteryana Shopova 3081135f7de5SShteryana Shopova return (SLIST_NEXT(vacmctx, vcl)); 3082135f7de5SShteryana Shopova } 3083135f7de5SShteryana Shopova 3084135f7de5SShteryana Shopova struct vacm_context * 3085135f7de5SShteryana Shopova vacm_add_context(char *ctxname, int regid) 3086135f7de5SShteryana Shopova { 3087135f7de5SShteryana Shopova int cmp; 3088135f7de5SShteryana Shopova struct vacm_context *ctx, *temp, *prev; 3089135f7de5SShteryana Shopova 3090135f7de5SShteryana Shopova SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3091135f7de5SShteryana Shopova if (strcmp(ctxname, ctx->ctxname) == 0) { 3092135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3093135f7de5SShteryana Shopova return (NULL); 3094135f7de5SShteryana Shopova } 3095135f7de5SShteryana Shopova 3096135f7de5SShteryana Shopova if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3097135f7de5SShteryana Shopova return (NULL); 3098135f7de5SShteryana Shopova 3099135f7de5SShteryana Shopova memset(ctx, 0, sizeof(*ctx)); 3100135f7de5SShteryana Shopova strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3101135f7de5SShteryana Shopova ctx->regid = regid; 3102135f7de5SShteryana Shopova 3103135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3104135f7de5SShteryana Shopova strlen(ctx->ctxname) < strlen(prev->ctxname) || 3105135f7de5SShteryana Shopova strcmp(ctx->ctxname, prev->ctxname) < 0) { 3106135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3107135f7de5SShteryana Shopova return (ctx); 3108135f7de5SShteryana Shopova } 3109135f7de5SShteryana Shopova 3110135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3111135f7de5SShteryana Shopova if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3112135f7de5SShteryana Shopova strcmp(ctx->ctxname, temp->ctxname) < 0) { 3113135f7de5SShteryana Shopova cmp = -1; 3114135f7de5SShteryana Shopova break; 3115135f7de5SShteryana Shopova } 3116135f7de5SShteryana Shopova prev = temp; 3117135f7de5SShteryana Shopova } 3118135f7de5SShteryana Shopova 3119135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3120135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, ctx, vcl); 3121135f7de5SShteryana Shopova else if (cmp > 0) 3122135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, ctx, vcl); 3123135f7de5SShteryana Shopova else { 3124135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3125135f7de5SShteryana Shopova free(ctx); 3126135f7de5SShteryana Shopova return (NULL); 3127135f7de5SShteryana Shopova } 3128135f7de5SShteryana Shopova 3129135f7de5SShteryana Shopova return (ctx); 3130135f7de5SShteryana Shopova } 3131135f7de5SShteryana Shopova 3132135f7de5SShteryana Shopova void 3133135f7de5SShteryana Shopova vacm_flush_contexts(int regid) 3134135f7de5SShteryana Shopova { 3135135f7de5SShteryana Shopova struct vacm_context *ctx, *temp; 3136135f7de5SShteryana Shopova 3137135f7de5SShteryana Shopova SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3138135f7de5SShteryana Shopova if (ctx->regid == regid) { 3139135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3140135f7de5SShteryana Shopova free(ctx); 3141135f7de5SShteryana Shopova } 3142135f7de5SShteryana Shopova } 3143