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 68f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 69f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 70135f7de5SShteryana Shopova #define PATH_ENGINE "/var/%s.engine" 71f06ca4afSHartmut Brandt 7269292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 7369292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 74f06ca4afSHartmut Brandt 75f06ca4afSHartmut Brandt struct systemg systemg = { 76f06ca4afSHartmut Brandt NULL, 77f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 78f06ca4afSHartmut Brandt NULL, NULL, NULL, 79f06ca4afSHartmut Brandt 64 + 8 + 4, 80f06ca4afSHartmut Brandt 0 81f06ca4afSHartmut Brandt }; 82f06ca4afSHartmut Brandt struct debug debug = { 83f06ca4afSHartmut Brandt 0, /* dump_pdus */ 84f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 85f06ca4afSHartmut Brandt 0, /* evdebug */ 86f06ca4afSHartmut Brandt }; 87f06ca4afSHartmut Brandt 88f06ca4afSHartmut Brandt struct snmpd snmpd = { 89f06ca4afSHartmut Brandt 2048, /* txbuf */ 90f06ca4afSHartmut Brandt 2048, /* rxbuf */ 91f06ca4afSHartmut Brandt 0, /* comm_dis */ 92f06ca4afSHartmut Brandt 0, /* auth_traps */ 93f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 9470af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 95f06ca4afSHartmut Brandt }; 96f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 97f06ca4afSHartmut Brandt 98135f7de5SShteryana Shopova struct snmpd_usmstat snmpd_usmstats; 99135f7de5SShteryana Shopova 100135f7de5SShteryana Shopova /* snmpEngine */ 101135f7de5SShteryana Shopova struct snmp_engine snmpd_engine; 102135f7de5SShteryana Shopova 103f06ca4afSHartmut Brandt /* snmpSerialNo */ 104f06ca4afSHartmut Brandt int32_t snmp_serial_no; 105f06ca4afSHartmut Brandt 10672cd7a52SShteryana Shopova struct snmpd_target_stats snmpd_target_stats; 10772cd7a52SShteryana Shopova 108f06ca4afSHartmut Brandt /* search path for config files */ 109f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 110f06ca4afSHartmut Brandt 111f06ca4afSHartmut Brandt /* list of all loaded modules */ 112f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 113f06ca4afSHartmut Brandt 114f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 115f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 116f06ca4afSHartmut Brandt 117f06ca4afSHartmut Brandt /* list of all known communities */ 118f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 119f06ca4afSHartmut Brandt 120135f7de5SShteryana Shopova /* list of all known USM users */ 1218cd5a258SEnji Cooper static struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 122135f7de5SShteryana Shopova 123135f7de5SShteryana Shopova /* A list of all VACM users configured, including v1, v2c and v3 */ 1248cd5a258SEnji Cooper static struct vacm_userlist vacm_userlist = 1258cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_userlist); 126135f7de5SShteryana Shopova 127135f7de5SShteryana Shopova /* A list of all VACM groups */ 1288cd5a258SEnji Cooper static struct vacm_grouplist vacm_grouplist = 1298cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_grouplist); 130135f7de5SShteryana Shopova 131135f7de5SShteryana Shopova static struct vacm_group vacm_default_group = { 132135f7de5SShteryana Shopova .groupname = "", 133135f7de5SShteryana Shopova }; 134135f7de5SShteryana Shopova 135135f7de5SShteryana Shopova /* The list of configured access entries */ 1368cd5a258SEnji Cooper static struct vacm_accesslist vacm_accesslist = 1378cd5a258SEnji Cooper TAILQ_HEAD_INITIALIZER(vacm_accesslist); 138135f7de5SShteryana Shopova 139135f7de5SShteryana Shopova /* The list of configured views */ 1408cd5a258SEnji Cooper static struct vacm_viewlist vacm_viewlist = 1418cd5a258SEnji Cooper SLIST_HEAD_INITIALIZER(vacm_viewlist); 142135f7de5SShteryana Shopova 143135f7de5SShteryana Shopova /* The list of configured contexts */ 1448cd5a258SEnji Cooper static struct vacm_contextlist vacm_contextlist = 145135f7de5SShteryana Shopova SLIST_HEAD_INITIALIZER(vacm_contextlist); 146135f7de5SShteryana Shopova 147f06ca4afSHartmut Brandt /* list of all installed object resources */ 148f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 149f06ca4afSHartmut Brandt 150f06ca4afSHartmut Brandt /* community value generator */ 151f06ca4afSHartmut Brandt static u_int next_community_index = 1; 152f06ca4afSHartmut Brandt 153f06ca4afSHartmut Brandt /* list of all known ranges */ 154f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 155f06ca4afSHartmut Brandt 156f06ca4afSHartmut Brandt /* identifier generator */ 157f06ca4afSHartmut Brandt u_int next_idrange = 1; 158f06ca4afSHartmut Brandt 159f06ca4afSHartmut Brandt /* list of all current timers */ 160f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 161f06ca4afSHartmut Brandt 162f06ca4afSHartmut Brandt /* list of file descriptors */ 163f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 164f06ca4afSHartmut Brandt 165f06ca4afSHartmut Brandt /* program arguments */ 166f06ca4afSHartmut Brandt static char **progargs; 167f06ca4afSHartmut Brandt static int nprogargs; 168f06ca4afSHartmut Brandt 169f06ca4afSHartmut Brandt /* current community */ 170f06ca4afSHartmut Brandt u_int community; 171f06ca4afSHartmut Brandt static struct community *comm; 172f06ca4afSHartmut Brandt 173135f7de5SShteryana Shopova /* current USM user */ 174135f7de5SShteryana Shopova struct usm_user *usm_user; 175135f7de5SShteryana Shopova 176f06ca4afSHartmut Brandt /* file names */ 177f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 178f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 179135f7de5SShteryana Shopova char engine_file[MAXPATHLEN + 1]; 180f06ca4afSHartmut Brandt 18170af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 182f06ca4afSHartmut Brandt /* event context */ 183f06ca4afSHartmut Brandt static evContext evctx; 18470af00a1SHartmut Brandt #endif 185f06ca4afSHartmut Brandt 186f06ca4afSHartmut Brandt /* signal mask */ 187f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 188f06ca4afSHartmut Brandt 189f06ca4afSHartmut Brandt /* signal handling */ 190f06ca4afSHartmut Brandt static int work; 191f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 192f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 193f06ca4afSHartmut Brandt 194f06ca4afSHartmut Brandt /* oids */ 195f06ca4afSHartmut Brandt static const struct asn_oid 196f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 197f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 198f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 199f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 200f06ca4afSHartmut Brandt 201f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 202f06ca4afSHartmut Brandt 203135f7de5SShteryana Shopova const struct asn_oid oid_usmUnknownEngineIDs = 204135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 205135f7de5SShteryana Shopova 206135f7de5SShteryana Shopova const struct asn_oid oid_usmNotInTimeWindows = 207135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 208135f7de5SShteryana Shopova 209f06ca4afSHartmut Brandt /* request id generator for traps */ 210f06ca4afSHartmut Brandt u_int trap_reqid; 211f06ca4afSHartmut Brandt 212f06ca4afSHartmut Brandt /* help text */ 213f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 214f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 215f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 216135f7de5SShteryana Shopova Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 217135f7de5SShteryana Shopova usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 218135f7de5SShteryana Shopova [-l prefix] [-m variable=value] [-p file]\n\ 219f06ca4afSHartmut Brandt options:\n\ 220f06ca4afSHartmut Brandt -d don't daemonize\n\ 221f06ca4afSHartmut Brandt -h print this info\n\ 222f06ca4afSHartmut Brandt -c file specify configuration file\n\ 223f06ca4afSHartmut Brandt -D options debugging options\n\ 224135f7de5SShteryana Shopova -e file specify engine id file\n\ 225f06ca4afSHartmut Brandt -I path system include path\n\ 226f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 227f06ca4afSHartmut Brandt -m var=val define variable\n\ 228f06ca4afSHartmut Brandt -p file specify pid file\n\ 229f06ca4afSHartmut Brandt "; 230f06ca4afSHartmut Brandt 231d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 232d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 233d7eb6b47SHartmut Brandt static struct request_info req; 234d7eb6b47SHartmut Brandt #endif 235d7eb6b47SHartmut Brandt 23670af00a1SHartmut Brandt /* transports */ 23770af00a1SHartmut Brandt extern const struct transport_def udp_trans; 23870af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 23970af00a1SHartmut Brandt 24070af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 24170af00a1SHartmut Brandt 242f06ca4afSHartmut Brandt /* forward declarations */ 243f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 244f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 245f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 246f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 247f06ca4afSHartmut Brandt 248f06ca4afSHartmut Brandt /* 249f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 250f06ca4afSHartmut Brandt */ 251f06ca4afSHartmut Brandt void * 252f06ca4afSHartmut Brandt buf_alloc(int tx) 253f06ca4afSHartmut Brandt { 254f06ca4afSHartmut Brandt void *buf; 255f06ca4afSHartmut Brandt 25670af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 257f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 258f06ca4afSHartmut Brandt if (tx) 259f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 260f06ca4afSHartmut Brandt else 261f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 262f06ca4afSHartmut Brandt return (NULL); 263f06ca4afSHartmut Brandt } 264f06ca4afSHartmut Brandt return (buf); 265f06ca4afSHartmut Brandt } 266f06ca4afSHartmut Brandt 267f06ca4afSHartmut Brandt /* 26870af00a1SHartmut Brandt * Return the buffer size. 269f06ca4afSHartmut Brandt */ 270f06ca4afSHartmut Brandt size_t 271f06ca4afSHartmut Brandt buf_size(int tx) 272f06ca4afSHartmut Brandt { 27370af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 274f06ca4afSHartmut Brandt } 275f06ca4afSHartmut Brandt 276f06ca4afSHartmut Brandt /* 277f06ca4afSHartmut Brandt * Prepare a PDU for output 278f06ca4afSHartmut Brandt */ 279f06ca4afSHartmut Brandt void 28070af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 281f06ca4afSHartmut Brandt const char *dest) 282f06ca4afSHartmut Brandt { 283f06ca4afSHartmut Brandt struct asn_buf resp_b; 284f29369b7SEnji Cooper enum snmp_code code; 285f06ca4afSHartmut Brandt 286f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 287f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 288f06ca4afSHartmut Brandt 289f29369b7SEnji Cooper if ((code = snmp_pdu_encode(pdu, &resp_b)) != SNMP_CODE_OK) { 290f29369b7SEnji Cooper syslog(LOG_ERR, "cannot encode message (code=%d)", code); 291f06ca4afSHartmut Brandt abort(); 292f06ca4afSHartmut Brandt } 293f06ca4afSHartmut Brandt if (debug.dump_pdus) { 294f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 295f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 296f06ca4afSHartmut Brandt } 297f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 298f06ca4afSHartmut Brandt } 299f06ca4afSHartmut Brandt 300f06ca4afSHartmut Brandt /* 301135f7de5SShteryana Shopova * Check USM PDU header credentials against local SNMP Engine & users. 302135f7de5SShteryana Shopova */ 303135f7de5SShteryana Shopova static enum snmp_code 304135f7de5SShteryana Shopova snmp_pdu_auth_user(struct snmp_pdu *pdu) 305135f7de5SShteryana Shopova { 306135f7de5SShteryana Shopova usm_user = NULL; 307135f7de5SShteryana Shopova 308135f7de5SShteryana Shopova /* un-authenticated snmpEngineId discovery */ 309135f7de5SShteryana Shopova if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 310135f7de5SShteryana Shopova pdu->engine.engine_len = snmpd_engine.engine_len; 311135f7de5SShteryana Shopova memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 312135f7de5SShteryana Shopova snmpd_engine.engine_len); 31388cdfafaSEnji Cooper update_snmpd_engine_time(); 314135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 315135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 316135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 317135f7de5SShteryana Shopova return (SNMP_CODE_OK); 318135f7de5SShteryana Shopova } 319135f7de5SShteryana Shopova 320135f7de5SShteryana Shopova if ((usm_user = usm_find_user(pdu->engine.engine_id, 321135f7de5SShteryana Shopova pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 322135f7de5SShteryana Shopova usm_user->status != 1 /* active */) 323135f7de5SShteryana Shopova return (SNMP_CODE_BADUSER); 324135f7de5SShteryana Shopova 325135f7de5SShteryana Shopova if (usm_user->user_engine_len != snmpd_engine.engine_len || 326135f7de5SShteryana Shopova memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 327135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 328135f7de5SShteryana Shopova return (SNMP_CODE_BADENGINE); 329135f7de5SShteryana Shopova 330135f7de5SShteryana Shopova pdu->user.priv_proto = usm_user->suser.priv_proto; 331135f7de5SShteryana Shopova memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 332135f7de5SShteryana Shopova sizeof(pdu->user.priv_key)); 333135f7de5SShteryana Shopova 334135f7de5SShteryana Shopova /* authenticated snmpEngineId discovery */ 335135f7de5SShteryana Shopova if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 33688cdfafaSEnji Cooper update_snmpd_engine_time(); 337135f7de5SShteryana Shopova pdu->user.auth_proto = usm_user->suser.auth_proto; 338135f7de5SShteryana Shopova memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 339135f7de5SShteryana Shopova sizeof(pdu->user.auth_key)); 340135f7de5SShteryana Shopova 341135f7de5SShteryana Shopova if (pdu->engine.engine_boots == 0 && 342135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 34388cdfafaSEnji Cooper update_snmpd_engine_time(); 344135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 345135f7de5SShteryana Shopova return (SNMP_CODE_OK); 346135f7de5SShteryana Shopova } 347135f7de5SShteryana Shopova 348135f7de5SShteryana Shopova if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 349135f7de5SShteryana Shopova abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 350135f7de5SShteryana Shopova SNMP_TIME_WINDOW) 351135f7de5SShteryana Shopova return (SNMP_CODE_NOTINTIME); 352135f7de5SShteryana Shopova } 353135f7de5SShteryana Shopova 354135f7de5SShteryana Shopova if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 355135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 356135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 357135f7de5SShteryana Shopova usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 358135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 359135f7de5SShteryana Shopova usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 360135f7de5SShteryana Shopova return (SNMP_CODE_BADSECLEVEL); 361135f7de5SShteryana Shopova 362135f7de5SShteryana Shopova return (SNMP_CODE_OK); 363135f7de5SShteryana Shopova } 364135f7de5SShteryana Shopova 365135f7de5SShteryana Shopova /* 366135f7de5SShteryana Shopova * Check whether access to each of var bindings in the PDU is allowed based 367135f7de5SShteryana Shopova * on the user credentials against the configured User groups & VACM views. 368135f7de5SShteryana Shopova */ 36972cd7a52SShteryana Shopova enum snmp_code 370135f7de5SShteryana Shopova snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 371135f7de5SShteryana Shopova { 372135f7de5SShteryana Shopova const char *uname; 373135f7de5SShteryana Shopova int32_t suboid, smodel; 374135f7de5SShteryana Shopova uint32_t i; 375135f7de5SShteryana Shopova struct vacm_user *vuser; 376135f7de5SShteryana Shopova struct vacm_access *acl; 377135f7de5SShteryana Shopova struct vacm_context *vacmctx; 378135f7de5SShteryana Shopova struct vacm_view *view; 379135f7de5SShteryana Shopova 380135f7de5SShteryana Shopova /* 381135f7de5SShteryana Shopova * At least a default context exists if the snmpd_vacm(3) module is 382135f7de5SShteryana Shopova * running. 383135f7de5SShteryana Shopova */ 384135f7de5SShteryana Shopova if (SLIST_EMPTY(&vacm_contextlist) || 385135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 386135f7de5SShteryana Shopova return (SNMP_CODE_OK); 387135f7de5SShteryana Shopova 388135f7de5SShteryana Shopova switch (pdu->version) { 389135f7de5SShteryana Shopova case SNMP_V1: 390135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 391135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 392135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv1; 393135f7de5SShteryana Shopova break; 394135f7de5SShteryana Shopova 395135f7de5SShteryana Shopova case SNMP_V2c: 396135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 397135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 398135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv2c; 399135f7de5SShteryana Shopova break; 400135f7de5SShteryana Shopova 401135f7de5SShteryana Shopova case SNMP_V3: 402135f7de5SShteryana Shopova uname = pdu->user.sec_name; 403135f7de5SShteryana Shopova if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 404135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 405135f7de5SShteryana Shopova /* Compare the PDU context engine id against the agent's */ 406135f7de5SShteryana Shopova if (pdu->context_engine_len != snmpd_engine.engine_len || 407135f7de5SShteryana Shopova memcmp(pdu->context_engine, snmpd_engine.engine_id, 408135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 409135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 410135f7de5SShteryana Shopova break; 411135f7de5SShteryana Shopova 412135f7de5SShteryana Shopova default: 413135f7de5SShteryana Shopova abort(); 414135f7de5SShteryana Shopova } 415135f7de5SShteryana Shopova 416135f7de5SShteryana Shopova SLIST_FOREACH(vuser, &vacm_userlist, vvu) 417135f7de5SShteryana Shopova if (strcmp(uname, vuser->secname) == 0 && 418135f7de5SShteryana Shopova vuser->sec_model == smodel) 419135f7de5SShteryana Shopova break; 420135f7de5SShteryana Shopova 421135f7de5SShteryana Shopova if (vuser == NULL || vuser->group == NULL) 422135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 423135f7de5SShteryana Shopova 424135f7de5SShteryana Shopova /* XXX: shteryana - recheck */ 425135f7de5SShteryana Shopova TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 426135f7de5SShteryana Shopova if (acl->group != vuser->group) 427135f7de5SShteryana Shopova continue; 428135f7de5SShteryana Shopova SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 429135f7de5SShteryana Shopova if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 430135f7de5SShteryana Shopova acl->ctx_match) == 0) 431135f7de5SShteryana Shopova goto match; 432135f7de5SShteryana Shopova } 433135f7de5SShteryana Shopova 434135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 435135f7de5SShteryana Shopova 436135f7de5SShteryana Shopova match: 437135f7de5SShteryana Shopova 438135f7de5SShteryana Shopova switch (pdu->type) { 439135f7de5SShteryana Shopova case SNMP_PDU_GET: 440135f7de5SShteryana Shopova case SNMP_PDU_GETNEXT: 441135f7de5SShteryana Shopova case SNMP_PDU_GETBULK: 442135f7de5SShteryana Shopova if ((view = acl->read_view) == NULL) 443135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 444135f7de5SShteryana Shopova break; 445135f7de5SShteryana Shopova 446135f7de5SShteryana Shopova case SNMP_PDU_SET: 447135f7de5SShteryana Shopova if ((view = acl->write_view) == NULL) 448135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 449135f7de5SShteryana Shopova break; 450135f7de5SShteryana Shopova 451135f7de5SShteryana Shopova case SNMP_PDU_TRAP: 452135f7de5SShteryana Shopova case SNMP_PDU_INFORM: 453135f7de5SShteryana Shopova case SNMP_PDU_TRAP2: 454135f7de5SShteryana Shopova case SNMP_PDU_REPORT: 455135f7de5SShteryana Shopova if ((view = acl->notify_view) == NULL) 456135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 457135f7de5SShteryana Shopova break; 458135f7de5SShteryana Shopova case SNMP_PDU_RESPONSE: 459135f7de5SShteryana Shopova /* NOTREACHED */ 460135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 461135f7de5SShteryana Shopova default: 462135f7de5SShteryana Shopova abort(); 463135f7de5SShteryana Shopova } 464135f7de5SShteryana Shopova 465135f7de5SShteryana Shopova for (i = 0; i < pdu->nbindings; i++) { 466135f7de5SShteryana Shopova /* XXX - view->mask*/ 467135f7de5SShteryana Shopova suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 468135f7de5SShteryana Shopova if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 469135f7de5SShteryana Shopova *ip = i + 1; 470135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 471135f7de5SShteryana Shopova } 472135f7de5SShteryana Shopova } 473135f7de5SShteryana Shopova 474135f7de5SShteryana Shopova return (SNMP_CODE_OK); 475135f7de5SShteryana Shopova } 476135f7de5SShteryana Shopova 477135f7de5SShteryana Shopova /* 478135f7de5SShteryana Shopova * SNMP input. Start: decode the PDU, find the user or community. 479f06ca4afSHartmut Brandt */ 480f06ca4afSHartmut Brandt enum snmpd_input_err 481f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 48270af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 483f06ca4afSHartmut Brandt { 484f06ca4afSHartmut Brandt struct asn_buf b; 485f06ca4afSHartmut Brandt enum snmp_code code; 486f06ca4afSHartmut Brandt enum snmpd_input_err ret; 48770af00a1SHartmut Brandt int sret; 488f06ca4afSHartmut Brandt 489135f7de5SShteryana Shopova /* update uptime */ 490135f7de5SShteryana Shopova this_tick = get_ticks(); 491135f7de5SShteryana Shopova 492f06ca4afSHartmut Brandt b.asn_cptr = buf; 493f06ca4afSHartmut Brandt b.asn_len = len; 49470af00a1SHartmut Brandt 49570af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 49670af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 49770af00a1SHartmut Brandt 49870af00a1SHartmut Brandt case 0: 49970af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 50070af00a1SHartmut Brandt 50170af00a1SHartmut Brandt case -1: 50270af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 50370af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 50470af00a1SHartmut Brandt } 50570af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 50670af00a1SHartmut Brandt 507135f7de5SShteryana Shopova memset(pdu, 0, sizeof(*pdu)); 508135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 509135f7de5SShteryana Shopova goto decoded; 510f06ca4afSHartmut Brandt 511135f7de5SShteryana Shopova if (pdu->version == SNMP_V3) { 512135f7de5SShteryana Shopova if (pdu->security_model != SNMP_SECMODEL_USM) { 513135f7de5SShteryana Shopova code = SNMP_CODE_FAILED; 514135f7de5SShteryana Shopova goto decoded; 515135f7de5SShteryana Shopova } 516135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 517135f7de5SShteryana Shopova goto decoded; 518135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 519135f7de5SShteryana Shopova goto decoded; 520135f7de5SShteryana Shopova } 521135f7de5SShteryana Shopova code = snmp_pdu_decode_scoped(&b, pdu, ip); 52270af00a1SHartmut Brandt 523f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 524135f7de5SShteryana Shopova 525135f7de5SShteryana Shopova decoded: 526135f7de5SShteryana Shopova snmpd_stats.inPkts++; 527135f7de5SShteryana Shopova 528f06ca4afSHartmut Brandt switch (code) { 529f06ca4afSHartmut Brandt 530f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 531f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 532f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 533f06ca4afSHartmut Brandt 534f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 53570af00a1SHartmut Brandt bad_vers: 536f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 537f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 538f06ca4afSHartmut Brandt 539f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 540f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 541f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 542f06ca4afSHartmut Brandt break; 543f06ca4afSHartmut Brandt 544f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 545f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 546f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 547f06ca4afSHartmut Brandt break; 548f06ca4afSHartmut Brandt 549f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 550f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 551f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 552f06ca4afSHartmut Brandt break; 553f06ca4afSHartmut Brandt 554135f7de5SShteryana Shopova case SNMP_CODE_BADSECLEVEL: 555135f7de5SShteryana Shopova snmpd_usmstats.unsupported_seclevels++; 556135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 557135f7de5SShteryana Shopova 558135f7de5SShteryana Shopova case SNMP_CODE_NOTINTIME: 559135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 560135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 561135f7de5SShteryana Shopova 562135f7de5SShteryana Shopova case SNMP_CODE_BADUSER: 563135f7de5SShteryana Shopova snmpd_usmstats.unknown_users++; 564135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 565135f7de5SShteryana Shopova 566135f7de5SShteryana Shopova case SNMP_CODE_BADENGINE: 567135f7de5SShteryana Shopova snmpd_usmstats.unknown_engine_ids++; 568135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 569135f7de5SShteryana Shopova 570135f7de5SShteryana Shopova case SNMP_CODE_BADDIGEST: 571135f7de5SShteryana Shopova snmpd_usmstats.wrong_digests++; 572135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 573135f7de5SShteryana Shopova 574135f7de5SShteryana Shopova case SNMP_CODE_EDECRYPT: 575135f7de5SShteryana Shopova snmpd_usmstats.decrypt_errors++; 576135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 577135f7de5SShteryana Shopova 578f06ca4afSHartmut Brandt case SNMP_CODE_OK: 57970af00a1SHartmut Brandt switch (pdu->version) { 58070af00a1SHartmut Brandt 58170af00a1SHartmut Brandt case SNMP_V1: 58270af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 58370af00a1SHartmut Brandt goto bad_vers; 58470af00a1SHartmut Brandt break; 58570af00a1SHartmut Brandt 58670af00a1SHartmut Brandt case SNMP_V2c: 58770af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 58870af00a1SHartmut Brandt goto bad_vers; 58970af00a1SHartmut Brandt break; 59070af00a1SHartmut Brandt 591135f7de5SShteryana Shopova case SNMP_V3: 592135f7de5SShteryana Shopova if (!(snmpd.version_enable & VERS_ENABLE_V3)) 593135f7de5SShteryana Shopova goto bad_vers; 594135f7de5SShteryana Shopova break; 595135f7de5SShteryana Shopova 59670af00a1SHartmut Brandt case SNMP_Verr: 59770af00a1SHartmut Brandt goto bad_vers; 59870af00a1SHartmut Brandt } 599f06ca4afSHartmut Brandt break; 600f06ca4afSHartmut Brandt } 601f06ca4afSHartmut Brandt 602f06ca4afSHartmut Brandt if (debug.dump_pdus) { 603f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 604f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 605f06ca4afSHartmut Brandt } 606f06ca4afSHartmut Brandt 607f06ca4afSHartmut Brandt /* 608135f7de5SShteryana Shopova * Look, whether we know the community or user 609f06ca4afSHartmut Brandt */ 610135f7de5SShteryana Shopova 611135f7de5SShteryana Shopova if (pdu->version != SNMP_V3) { 612f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 613f06ca4afSHartmut Brandt if (comm->string != NULL && 614f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 615f06ca4afSHartmut Brandt break; 616f06ca4afSHartmut Brandt 617f06ca4afSHartmut Brandt if (comm == NULL) { 618f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 619f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 620f06ca4afSHartmut Brandt if (snmpd.auth_traps) 621896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 622896052c1SHartmut Brandt (struct snmp_value *)NULL); 623896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 624896052c1SHartmut Brandt } else 625f06ca4afSHartmut Brandt community = comm->value; 626135f7de5SShteryana Shopova } else if (pdu->nbindings == 0) { 627135f7de5SShteryana Shopova /* RFC 3414 - snmpEngineID Discovery */ 628135f7de5SShteryana Shopova if (strlen(pdu->user.sec_name) == 0) { 629135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 630135f7de5SShteryana Shopova &oid_usmUnknownEngineIDs); 631135f7de5SShteryana Shopova pdu->context_engine_len = snmpd_engine.engine_len; 632135f7de5SShteryana Shopova memcpy(pdu->context_engine, snmpd_engine.engine_id, 633135f7de5SShteryana Shopova snmpd_engine.engine_len); 634135f7de5SShteryana Shopova } else if (pdu->engine.engine_boots == 0 && 635135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 636135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 637135f7de5SShteryana Shopova &oid_usmNotInTimeWindows); 63888cdfafaSEnji Cooper update_snmpd_engine_time(); 639135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 640135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 641135f7de5SShteryana Shopova } 642135f7de5SShteryana Shopova } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 643135f7de5SShteryana Shopova (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 644135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 645126b5bb6SEnji Cooper ret = SNMPD_INPUT_FAILED; 646135f7de5SShteryana Shopova } 647f06ca4afSHartmut Brandt 648135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 649126b5bb6SEnji Cooper ret = SNMPD_INPUT_FAILED; 650f06ca4afSHartmut Brandt 651f06ca4afSHartmut Brandt return (ret); 652f06ca4afSHartmut Brandt } 653f06ca4afSHartmut Brandt 654f06ca4afSHartmut Brandt /* 655f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 656f06ca4afSHartmut Brandt */ 657f06ca4afSHartmut Brandt enum snmpd_input_err 658f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 659f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 660f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 661f06ca4afSHartmut Brandt { 662f06ca4afSHartmut Brandt struct snmp_pdu resp; 663f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 664f06ca4afSHartmut Brandt enum snmp_ret ret; 665f06ca4afSHartmut Brandt 666f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 667f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 668f06ca4afSHartmut Brandt 669f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 670f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 671f06ca4afSHartmut Brandt 672f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 673f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 674f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 675f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 676f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 677f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 678f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 679f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 680f06ca4afSHartmut Brandt else 681f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 682f06ca4afSHartmut Brandt 683f06ca4afSHartmut Brandt pdu->error_index = ivar; 684f06ca4afSHartmut Brandt 685f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 686f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 687f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 688f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 689f06ca4afSHartmut Brandt } 690f06ca4afSHartmut Brandt 691f06ca4afSHartmut Brandt if (debug.dump_pdus) { 692f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 693f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 694f06ca4afSHartmut Brandt } 695f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 696f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 697f06ca4afSHartmut Brandt } 698f06ca4afSHartmut Brandt 699f06ca4afSHartmut Brandt switch (pdu->type) { 700f06ca4afSHartmut Brandt 701f06ca4afSHartmut Brandt case SNMP_PDU_GET: 702f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 703f06ca4afSHartmut Brandt break; 704f06ca4afSHartmut Brandt 705f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 706f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 707f06ca4afSHartmut Brandt break; 708f06ca4afSHartmut Brandt 709f06ca4afSHartmut Brandt case SNMP_PDU_SET: 710f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 711f06ca4afSHartmut Brandt break; 712f06ca4afSHartmut Brandt 713f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 714f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 715f06ca4afSHartmut Brandt break; 716f06ca4afSHartmut Brandt 717f06ca4afSHartmut Brandt default: 718f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 719f06ca4afSHartmut Brandt break; 720f06ca4afSHartmut Brandt } 721f06ca4afSHartmut Brandt 722f06ca4afSHartmut Brandt switch (ret) { 723f06ca4afSHartmut Brandt 724f06ca4afSHartmut Brandt case SNMP_RET_OK: 725f06ca4afSHartmut Brandt /* normal return - send a response */ 726f06ca4afSHartmut Brandt if (debug.dump_pdus) { 727f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 728f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 729f06ca4afSHartmut Brandt } 730f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 731f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 732f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 733f06ca4afSHartmut Brandt 734f06ca4afSHartmut Brandt case SNMP_RET_IGN: 735f06ca4afSHartmut Brandt /* error - send nothing */ 736f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 737f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 738f06ca4afSHartmut Brandt 739f06ca4afSHartmut Brandt case SNMP_RET_ERR: 740f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 741f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 742f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 743f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 744f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 745f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 746f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 747f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 748f06ca4afSHartmut Brandt } else { 749f06ca4afSHartmut Brandt if (debug.dump_pdus) { 750f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 751f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 752f06ca4afSHartmut Brandt } 753f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 754f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 755f06ca4afSHartmut Brandt } 756f06ca4afSHartmut Brandt } 757f06ca4afSHartmut Brandt abort(); 758f06ca4afSHartmut Brandt } 759f06ca4afSHartmut Brandt 76070af00a1SHartmut Brandt /* 76170af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 76270af00a1SHartmut Brandt */ 76370af00a1SHartmut Brandt void 76470af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 76570af00a1SHartmut Brandt { 76670af00a1SHartmut Brandt struct tport *p; 767f06ca4afSHartmut Brandt 76870af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 76970af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 77070af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 77170af00a1SHartmut Brandt return; 77270af00a1SHartmut Brandt } 77370af00a1SHartmut Brandt } 77470af00a1SHartmut Brandt port->transport = t; 77570af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 77670af00a1SHartmut Brandt } 77770af00a1SHartmut Brandt 77870af00a1SHartmut Brandt /* 77970af00a1SHartmut Brandt * Remove a port from a transport's list 78070af00a1SHartmut Brandt */ 78170af00a1SHartmut Brandt void 78270af00a1SHartmut Brandt trans_remove_port(struct tport *port) 78370af00a1SHartmut Brandt { 78470af00a1SHartmut Brandt 78570af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 78670af00a1SHartmut Brandt } 78770af00a1SHartmut Brandt 78870af00a1SHartmut Brandt /* 78970af00a1SHartmut Brandt * Find a port on a transport's list 79070af00a1SHartmut Brandt */ 79170af00a1SHartmut Brandt struct tport * 79270af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 79370af00a1SHartmut Brandt { 79470af00a1SHartmut Brandt 79570af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 79670af00a1SHartmut Brandt } 79770af00a1SHartmut Brandt 79870af00a1SHartmut Brandt /* 79970af00a1SHartmut Brandt * Find next port on a transport's list 80070af00a1SHartmut Brandt */ 80170af00a1SHartmut Brandt struct tport * 80270af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 80370af00a1SHartmut Brandt { 80470af00a1SHartmut Brandt 80570af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 80670af00a1SHartmut Brandt } 80770af00a1SHartmut Brandt 80870af00a1SHartmut Brandt /* 80970af00a1SHartmut Brandt * Return first port 81070af00a1SHartmut Brandt */ 81170af00a1SHartmut Brandt struct tport * 81270af00a1SHartmut Brandt trans_first_port(struct transport *t) 81370af00a1SHartmut Brandt { 81470af00a1SHartmut Brandt 81570af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 81670af00a1SHartmut Brandt } 81770af00a1SHartmut Brandt 81870af00a1SHartmut Brandt /* 81970af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 82070af00a1SHartmut Brandt */ 82170af00a1SHartmut Brandt struct tport * 82270af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 82370af00a1SHartmut Brandt intptr_t arg) 82470af00a1SHartmut Brandt { 82570af00a1SHartmut Brandt struct tport *p; 82670af00a1SHartmut Brandt 82770af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 82870af00a1SHartmut Brandt if (func(p, arg) == 0) 82970af00a1SHartmut Brandt return (p); 83070af00a1SHartmut Brandt return (NULL); 83170af00a1SHartmut Brandt } 83270af00a1SHartmut Brandt 83370af00a1SHartmut Brandt /* 83470af00a1SHartmut Brandt * Register a transport 83570af00a1SHartmut Brandt */ 83670af00a1SHartmut Brandt int 83770af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 83870af00a1SHartmut Brandt { 83970af00a1SHartmut Brandt u_int i; 84070af00a1SHartmut Brandt char or_descr[256]; 84170af00a1SHartmut Brandt 84270af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 84370af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 84470af00a1SHartmut Brandt 84570af00a1SHartmut Brandt /* construct index */ 84670af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 84770af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 84870af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 84970af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 85070af00a1SHartmut Brandt 85170af00a1SHartmut Brandt (*pp)->vtab = def; 85270af00a1SHartmut Brandt 85370af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 85470af00a1SHartmut Brandt free(*pp); 85570af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 85670af00a1SHartmut Brandt } 85770af00a1SHartmut Brandt 85870af00a1SHartmut Brandt /* register module */ 85970af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 86070af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 86170af00a1SHartmut Brandt free(*pp); 86270af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 86370af00a1SHartmut Brandt } 86470af00a1SHartmut Brandt 86570af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 86670af00a1SHartmut Brandt 86770af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 86870af00a1SHartmut Brandt 86970af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 87070af00a1SHartmut Brandt } 87170af00a1SHartmut Brandt 87270af00a1SHartmut Brandt /* 87370af00a1SHartmut Brandt * Unregister transport 87470af00a1SHartmut Brandt */ 87570af00a1SHartmut Brandt int 87670af00a1SHartmut Brandt trans_unregister(struct transport *t) 87770af00a1SHartmut Brandt { 87870af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 87970af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 88070af00a1SHartmut Brandt 88170af00a1SHartmut Brandt or_unregister(t->or_index); 88270af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 88370af00a1SHartmut Brandt 88470af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 88570af00a1SHartmut Brandt } 886f06ca4afSHartmut Brandt 887f06ca4afSHartmut Brandt /* 888f06ca4afSHartmut Brandt * File descriptor support 889f06ca4afSHartmut Brandt */ 89070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 89170af00a1SHartmut Brandt static void 89270af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 89370af00a1SHartmut Brandt #else 894f06ca4afSHartmut Brandt static void 895f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 89670af00a1SHartmut Brandt #endif 897f06ca4afSHartmut Brandt { 898f06ca4afSHartmut Brandt struct fdesc *f = uap; 899f06ca4afSHartmut Brandt 900f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 901f06ca4afSHartmut Brandt } 902f06ca4afSHartmut Brandt 903f06ca4afSHartmut Brandt void 904f06ca4afSHartmut Brandt fd_suspend(void *p) 905f06ca4afSHartmut Brandt { 906f06ca4afSHartmut Brandt struct fdesc *f = p; 907f06ca4afSHartmut Brandt 90870af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 90970af00a1SHartmut Brandt if (f->id >= 0) { 91070af00a1SHartmut Brandt poll_unregister(f->id); 91170af00a1SHartmut Brandt f->id = -1; 91270af00a1SHartmut Brandt } 91370af00a1SHartmut Brandt #else 914f06ca4afSHartmut Brandt if (evTestID(f->id)) { 915f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 916f06ca4afSHartmut Brandt evInitID(&f->id); 917f06ca4afSHartmut Brandt } 91870af00a1SHartmut Brandt #endif 919f06ca4afSHartmut Brandt } 920f06ca4afSHartmut Brandt 921f06ca4afSHartmut Brandt int 922f06ca4afSHartmut Brandt fd_resume(void *p) 923f06ca4afSHartmut Brandt { 924f06ca4afSHartmut Brandt struct fdesc *f = p; 925f06ca4afSHartmut Brandt int err; 926f06ca4afSHartmut Brandt 92770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 92870af00a1SHartmut Brandt if (f->id >= 0) 92970af00a1SHartmut Brandt return (0); 93094caccb3SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 93170af00a1SHartmut Brandt err = errno; 93270af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 93370af00a1SHartmut Brandt errno = err; 93470af00a1SHartmut Brandt return (-1); 93570af00a1SHartmut Brandt } 93670af00a1SHartmut Brandt #else 937f06ca4afSHartmut Brandt if (evTestID(f->id)) 938f06ca4afSHartmut Brandt return (0); 939f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 940f06ca4afSHartmut Brandt err = errno; 941f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 942f06ca4afSHartmut Brandt errno = err; 943f06ca4afSHartmut Brandt return (-1); 944f06ca4afSHartmut Brandt } 94570af00a1SHartmut Brandt #endif 946f06ca4afSHartmut Brandt return (0); 947f06ca4afSHartmut Brandt } 948f06ca4afSHartmut Brandt 949f06ca4afSHartmut Brandt void * 950f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 951f06ca4afSHartmut Brandt { 952f06ca4afSHartmut Brandt struct fdesc *f; 953f06ca4afSHartmut Brandt int err; 954f06ca4afSHartmut Brandt 955f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 956f06ca4afSHartmut Brandt err = errno; 957f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 958f06ca4afSHartmut Brandt errno = err; 959f06ca4afSHartmut Brandt return (NULL); 960f06ca4afSHartmut Brandt } 961f06ca4afSHartmut Brandt f->fd = fd; 962f06ca4afSHartmut Brandt f->func = func; 963f06ca4afSHartmut Brandt f->udata = udata; 964f06ca4afSHartmut Brandt f->owner = mod; 96570af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 96670af00a1SHartmut Brandt f->id = -1; 96770af00a1SHartmut Brandt #else 968f06ca4afSHartmut Brandt evInitID(&f->id); 96970af00a1SHartmut Brandt #endif 970f06ca4afSHartmut Brandt 971f06ca4afSHartmut Brandt if (fd_resume(f)) { 972f06ca4afSHartmut Brandt err = errno; 973f06ca4afSHartmut Brandt free(f); 974f06ca4afSHartmut Brandt errno = err; 975f06ca4afSHartmut Brandt return (NULL); 976f06ca4afSHartmut Brandt } 977f06ca4afSHartmut Brandt 978f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 979f06ca4afSHartmut Brandt 980f06ca4afSHartmut Brandt return (f); 981f06ca4afSHartmut Brandt } 982f06ca4afSHartmut Brandt 983f06ca4afSHartmut Brandt void 984f06ca4afSHartmut Brandt fd_deselect(void *p) 985f06ca4afSHartmut Brandt { 986f06ca4afSHartmut Brandt struct fdesc *f = p; 987f06ca4afSHartmut Brandt 988f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 989f06ca4afSHartmut Brandt fd_suspend(f); 990f06ca4afSHartmut Brandt free(f); 991f06ca4afSHartmut Brandt } 992f06ca4afSHartmut Brandt 993f06ca4afSHartmut Brandt static void 994f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 995f06ca4afSHartmut Brandt { 996f06ca4afSHartmut Brandt struct fdesc *t, *t1; 997f06ca4afSHartmut Brandt 998f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 999f06ca4afSHartmut Brandt while (t != NULL) { 1000f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1001f06ca4afSHartmut Brandt if (t->owner == mod) 1002f06ca4afSHartmut Brandt fd_deselect(t); 1003f06ca4afSHartmut Brandt t = t1; 1004f06ca4afSHartmut Brandt } 1005f06ca4afSHartmut Brandt } 1006f06ca4afSHartmut Brandt 1007f06ca4afSHartmut Brandt /* 100870af00a1SHartmut Brandt * Consume a message from the input buffer 1009f06ca4afSHartmut Brandt */ 1010f06ca4afSHartmut Brandt static void 101170af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 1012f06ca4afSHartmut Brandt { 101370af00a1SHartmut Brandt if (!pi->stream) { 101470af00a1SHartmut Brandt /* always consume everything */ 101570af00a1SHartmut Brandt pi->length = 0; 101670af00a1SHartmut Brandt return; 101770af00a1SHartmut Brandt } 101870af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 101970af00a1SHartmut Brandt /* all bytes consumed */ 102070af00a1SHartmut Brandt pi->length = 0; 102170af00a1SHartmut Brandt return; 102270af00a1SHartmut Brandt } 102370af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 102470af00a1SHartmut Brandt pi->length -= pi->consumed; 102570af00a1SHartmut Brandt } 102670af00a1SHartmut Brandt 102770af00a1SHartmut Brandt /* 102870af00a1SHartmut Brandt * Input from a socket 102970af00a1SHartmut Brandt */ 103070af00a1SHartmut Brandt int 103170af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 103270af00a1SHartmut Brandt { 1033f06ca4afSHartmut Brandt u_char *sndbuf; 1034f06ca4afSHartmut Brandt size_t sndlen; 103570af00a1SHartmut Brandt struct snmp_pdu pdu; 1036f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 1037f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 10380077de56SEnji Cooper ssize_t ret, slen; 1039f06ca4afSHartmut Brandt int32_t vi; 1040d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1041d7eb6b47SHartmut Brandt char client[16]; 1042d7eb6b47SHartmut Brandt #endif 1043f06ca4afSHartmut Brandt 1044*8d7f605bSEnji Cooper ret = tport->transport->vtab->recv(tport, pi); 104570af00a1SHartmut Brandt if (ret == -1) 104670af00a1SHartmut Brandt return (-1); 1047f06ca4afSHartmut Brandt 1048d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1049d7eb6b47SHartmut Brandt /* 1050d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 1051d7eb6b47SHartmut Brandt */ 105281b587f3SRuslan Ermilov if (pi->peer->sa_family != AF_LOCAL && 105381b587f3SRuslan Ermilov inet_ntop(pi->peer->sa_family, 105469292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 105569292cedSHartmut Brandt client, sizeof(client)) != NULL) { 1056d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 1057d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 1058d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 1059d7eb6b47SHartmut Brandt eval_client(&req)); 1060d7eb6b47SHartmut Brandt return (-1); 1061d7eb6b47SHartmut Brandt } 106281b587f3SRuslan Ermilov } else if (pi->peer->sa_family != AF_LOCAL) 1063d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 1064d7eb6b47SHartmut Brandt #endif 1065d7eb6b47SHartmut Brandt 1066f06ca4afSHartmut Brandt /* 1067f06ca4afSHartmut Brandt * Handle input 1068f06ca4afSHartmut Brandt */ 106970af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 107070af00a1SHartmut Brandt &pi->consumed); 107170af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 107270af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 107370af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 107470af00a1SHartmut Brandt if (pi->stream) { 107570af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 107670af00a1SHartmut Brandt snmpd_stats.silentDrops++; 107770af00a1SHartmut Brandt return (-1); 107870af00a1SHartmut Brandt } 107970af00a1SHartmut Brandt return (0); 108070af00a1SHartmut Brandt } 108170af00a1SHartmut Brandt snmpd_stats.silentDrops++; 108270af00a1SHartmut Brandt return (-1); 108370af00a1SHartmut Brandt } 1084f06ca4afSHartmut Brandt 1085f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 1086f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 1087f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 1088f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 108970af00a1SHartmut Brandt /* for streaming transports this is fatal */ 109070af00a1SHartmut Brandt if (pi->stream) 109170af00a1SHartmut Brandt return (-1); 109270af00a1SHartmut Brandt snmp_input_consume(pi); 109370af00a1SHartmut Brandt return (0); 1094f06ca4afSHartmut Brandt } 1095896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 1096896052c1SHartmut Brandt snmp_input_consume(pi); 1097896052c1SHartmut Brandt return (0); 1098896052c1SHartmut Brandt } 1099f06ca4afSHartmut Brandt 1100f06ca4afSHartmut Brandt /* 1101f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 1102f06ca4afSHartmut Brandt * the hand it over to the module. 1103f06ca4afSHartmut Brandt */ 1104135f7de5SShteryana Shopova if (comm != NULL && comm->owner != NULL && 1105135f7de5SShteryana Shopova comm->owner->config->proxy != NULL) { 110670af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1107896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 1108896052c1SHartmut Brandt !pi->cred || pi->priv); 1109f06ca4afSHartmut Brandt 1110f06ca4afSHartmut Brandt switch (perr) { 1111f06ca4afSHartmut Brandt 1112f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 111370af00a1SHartmut Brandt snmp_input_consume(pi); 111470af00a1SHartmut Brandt return (0); 1115f06ca4afSHartmut Brandt 1116f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 1117f06ca4afSHartmut Brandt break; 1118f06ca4afSHartmut Brandt 1119f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 112070af00a1SHartmut Brandt snmp_input_consume(pi); 1121f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1122f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 112370af00a1SHartmut Brandt return (0); 1124f06ca4afSHartmut Brandt 1125f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 112670af00a1SHartmut Brandt snmp_input_consume(pi); 1127f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1128f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 1129f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1130f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1131896052c1SHartmut Brandt (struct snmp_value *)NULL); 113270af00a1SHartmut Brandt return (0); 1133f06ca4afSHartmut Brandt 1134f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 113570af00a1SHartmut Brandt snmp_input_consume(pi); 1136f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1137f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1138f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1139f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1140896052c1SHartmut Brandt (struct snmp_value *)NULL); 114170af00a1SHartmut Brandt return (0); 1142f06ca4afSHartmut Brandt } 1143f06ca4afSHartmut Brandt } 1144f06ca4afSHartmut Brandt 1145f06ca4afSHartmut Brandt /* 1146f06ca4afSHartmut Brandt * Check type 1147f06ca4afSHartmut Brandt */ 1148f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1149f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1150f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1151f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1152f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1153f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 115470af00a1SHartmut Brandt snmp_input_consume(pi); 115570af00a1SHartmut Brandt return (0); 1156f06ca4afSHartmut Brandt } 1157f06ca4afSHartmut Brandt 1158f06ca4afSHartmut Brandt /* 1159f06ca4afSHartmut Brandt * Check community 1160f06ca4afSHartmut Brandt */ 1161135f7de5SShteryana Shopova if (pdu.version < SNMP_V3 && 1162135f7de5SShteryana Shopova ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 116370af00a1SHartmut Brandt (community != COMM_WRITE && 1164135f7de5SShteryana Shopova (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1165f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1166f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 116770af00a1SHartmut Brandt snmp_input_consume(pi); 1168f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1169896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1170896052c1SHartmut Brandt (struct snmp_value *)NULL); 117170af00a1SHartmut Brandt return (0); 1172f06ca4afSHartmut Brandt } 1173f06ca4afSHartmut Brandt 1174f06ca4afSHartmut Brandt /* 1175f06ca4afSHartmut Brandt * Execute it. 1176f06ca4afSHartmut Brandt */ 1177f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1178f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1179f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 118070af00a1SHartmut Brandt snmp_input_consume(pi); 118170af00a1SHartmut Brandt return (0); 1182f06ca4afSHartmut Brandt } 118370af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 118470af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1185f06ca4afSHartmut Brandt 1186f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 1187*8d7f605bSEnji Cooper slen = tport->transport->vtab->send(tport, sndbuf, sndlen, 1188*8d7f605bSEnji Cooper pi->peer, pi->peerlen); 118970af00a1SHartmut Brandt if (slen == -1) 1190*8d7f605bSEnji Cooper syslog(LOG_ERR, "send*: %m"); 119170af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 1192*8d7f605bSEnji Cooper syslog(LOG_ERR, "send*: short write %zu/%zu", sndlen, 1193*8d7f605bSEnji Cooper (size_t)slen); 119470af00a1SHartmut Brandt } 1195*8d7f605bSEnji Cooper 119670af00a1SHartmut Brandt snmp_pdu_free(&pdu); 119770af00a1SHartmut Brandt free(sndbuf); 119870af00a1SHartmut Brandt snmp_input_consume(pi); 119970af00a1SHartmut Brandt 120070af00a1SHartmut Brandt return (0); 120170af00a1SHartmut Brandt } 120270af00a1SHartmut Brandt 120370af00a1SHartmut Brandt /* 120470af00a1SHartmut Brandt * Send a PDU to a given port 120570af00a1SHartmut Brandt */ 120670af00a1SHartmut Brandt void 120770af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 120870af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 120970af00a1SHartmut Brandt { 121070af00a1SHartmut Brandt struct transport *trans = targ; 121170af00a1SHartmut Brandt struct tport *tp; 121270af00a1SHartmut Brandt u_char *sndbuf; 121370af00a1SHartmut Brandt size_t sndlen; 121470af00a1SHartmut Brandt ssize_t len; 121570af00a1SHartmut Brandt 121670af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 121770af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 121870af00a1SHartmut Brandt break; 121970af00a1SHartmut Brandt if (tp == 0) 122070af00a1SHartmut Brandt return; 122170af00a1SHartmut Brandt 122270af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 122370af00a1SHartmut Brandt return; 122470af00a1SHartmut Brandt 122570af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 122670af00a1SHartmut Brandt 122770af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 122870af00a1SHartmut Brandt 122970af00a1SHartmut Brandt if (len == -1) 1230f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1231f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1232f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1233f06ca4afSHartmut Brandt sndlen, (size_t)len); 123470af00a1SHartmut Brandt 1235f06ca4afSHartmut Brandt free(sndbuf); 1236f06ca4afSHartmut Brandt } 1237f06ca4afSHartmut Brandt 1238f06ca4afSHartmut Brandt 1239f06ca4afSHartmut Brandt /* 124070af00a1SHartmut Brandt * Close an input source 1241f06ca4afSHartmut Brandt */ 1242f06ca4afSHartmut Brandt void 124370af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1244f06ca4afSHartmut Brandt { 124570af00a1SHartmut Brandt if (pi->id != NULL) 124670af00a1SHartmut Brandt fd_deselect(pi->id); 124770af00a1SHartmut Brandt if (pi->fd >= 0) 124870af00a1SHartmut Brandt (void)close(pi->fd); 124970af00a1SHartmut Brandt if (pi->buf != NULL) 125070af00a1SHartmut Brandt free(pi->buf); 1251f06ca4afSHartmut Brandt } 1252f06ca4afSHartmut Brandt 1253f06ca4afSHartmut Brandt /* 1254f06ca4afSHartmut Brandt * Dump internal state. 1255f06ca4afSHartmut Brandt */ 125670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 125770af00a1SHartmut Brandt static void 125870af00a1SHartmut Brandt info_func(void) 125970af00a1SHartmut Brandt #else 1260f06ca4afSHartmut Brandt static void 1261f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 126270af00a1SHartmut Brandt #endif 1263f06ca4afSHartmut Brandt { 1264f06ca4afSHartmut Brandt struct lmodule *m; 1265f06ca4afSHartmut Brandt u_int i; 1266f06ca4afSHartmut Brandt char buf[10000]; 1267f06ca4afSHartmut Brandt 1268f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1269f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1270f06ca4afSHartmut Brandt switch (tree[i].type) { 1271f06ca4afSHartmut Brandt 1272f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1273f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1274f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1275f06ca4afSHartmut Brandt break; 1276f06ca4afSHartmut Brandt 1277f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1278f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1279f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1280f06ca4afSHartmut Brandt break; 1281f06ca4afSHartmut Brandt } 1282f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1283f06ca4afSHartmut Brandt } 1284f06ca4afSHartmut Brandt 1285f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1286f06ca4afSHartmut Brandt if (m->config->dump) 1287f06ca4afSHartmut Brandt (*m->config->dump)(); 1288f06ca4afSHartmut Brandt } 1289f06ca4afSHartmut Brandt 1290f06ca4afSHartmut Brandt /* 1291f06ca4afSHartmut Brandt * Re-read configuration 1292f06ca4afSHartmut Brandt */ 129370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 129470af00a1SHartmut Brandt static void 129570af00a1SHartmut Brandt config_func(void) 129670af00a1SHartmut Brandt #else 1297f06ca4afSHartmut Brandt static void 1298f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1299f06ca4afSHartmut Brandt const void *tag __unused) 130070af00a1SHartmut Brandt #endif 1301f06ca4afSHartmut Brandt { 1302f06ca4afSHartmut Brandt struct lmodule *m; 1303f06ca4afSHartmut Brandt 1304f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1305f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1306f06ca4afSHartmut Brandt return; 1307f06ca4afSHartmut Brandt } 1308f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1309f06ca4afSHartmut Brandt if (m->config->config) 1310f06ca4afSHartmut Brandt (*m->config->config)(); 1311f06ca4afSHartmut Brandt } 1312f06ca4afSHartmut Brandt 1313f06ca4afSHartmut Brandt /* 1314f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1315f06ca4afSHartmut Brandt */ 1316f06ca4afSHartmut Brandt static void 1317f06ca4afSHartmut Brandt onusr1(int s __unused) 1318f06ca4afSHartmut Brandt { 131970af00a1SHartmut Brandt 1320f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1321f06ca4afSHartmut Brandt } 1322f06ca4afSHartmut Brandt static void 1323f06ca4afSHartmut Brandt onhup(int s __unused) 1324f06ca4afSHartmut Brandt { 132570af00a1SHartmut Brandt 1326f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1327f06ca4afSHartmut Brandt } 1328f06ca4afSHartmut Brandt 1329f06ca4afSHartmut Brandt static void 1330f06ca4afSHartmut Brandt onterm(int s __unused) 1331f06ca4afSHartmut Brandt { 1332f06ca4afSHartmut Brandt 133370af00a1SHartmut Brandt /* allow clean-up */ 1334f06ca4afSHartmut Brandt exit(0); 1335f06ca4afSHartmut Brandt } 1336f06ca4afSHartmut Brandt 1337f06ca4afSHartmut Brandt static void 1338f06ca4afSHartmut Brandt init_sigs(void) 1339f06ca4afSHartmut Brandt { 1340f06ca4afSHartmut Brandt struct sigaction sa; 1341f06ca4afSHartmut Brandt 1342f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1343f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1344f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1345f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1346f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1347f06ca4afSHartmut Brandt exit(1); 1348f06ca4afSHartmut Brandt } 1349f06ca4afSHartmut Brandt 1350f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1351f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1352f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1353f06ca4afSHartmut Brandt exit(1); 1354f06ca4afSHartmut Brandt } 1355f06ca4afSHartmut Brandt 1356f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1357f06ca4afSHartmut Brandt sa.sa_flags = 0; 1358f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1359f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1360f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1361f06ca4afSHartmut Brandt exit(1); 1362f06ca4afSHartmut Brandt } 1363f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1364f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1365f06ca4afSHartmut Brandt exit(1); 1366f06ca4afSHartmut Brandt } 1367f06ca4afSHartmut Brandt } 1368f06ca4afSHartmut Brandt 1369f06ca4afSHartmut Brandt static void 1370f06ca4afSHartmut Brandt block_sigs(void) 1371f06ca4afSHartmut Brandt { 1372f06ca4afSHartmut Brandt sigset_t set; 1373f06ca4afSHartmut Brandt 1374f06ca4afSHartmut Brandt sigfillset(&set); 1375f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1376f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1377f06ca4afSHartmut Brandt exit(1); 1378f06ca4afSHartmut Brandt } 1379f06ca4afSHartmut Brandt } 1380f06ca4afSHartmut Brandt static void 1381f06ca4afSHartmut Brandt unblock_sigs(void) 1382f06ca4afSHartmut Brandt { 1383f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1384f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1385f06ca4afSHartmut Brandt exit(1); 1386f06ca4afSHartmut Brandt } 1387f06ca4afSHartmut Brandt } 1388f06ca4afSHartmut Brandt 1389f06ca4afSHartmut Brandt /* 1390f06ca4afSHartmut Brandt * Shut down 1391f06ca4afSHartmut Brandt */ 1392f06ca4afSHartmut Brandt static void 1393f06ca4afSHartmut Brandt term(void) 1394f06ca4afSHartmut Brandt { 1395f06ca4afSHartmut Brandt (void)unlink(pid_file); 1396f06ca4afSHartmut Brandt } 1397f06ca4afSHartmut Brandt 139870af00a1SHartmut Brandt static void 139970af00a1SHartmut Brandt trans_stop(void) 140070af00a1SHartmut Brandt { 140170af00a1SHartmut Brandt struct transport *t; 140270af00a1SHartmut Brandt 140370af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 140470af00a1SHartmut Brandt (void)t->vtab->stop(1); 140570af00a1SHartmut Brandt } 140670af00a1SHartmut Brandt 1407f06ca4afSHartmut Brandt /* 1408f06ca4afSHartmut Brandt * Define a macro from the command line 1409f06ca4afSHartmut Brandt */ 1410f06ca4afSHartmut Brandt static void 1411f06ca4afSHartmut Brandt do_macro(char *arg) 1412f06ca4afSHartmut Brandt { 1413f06ca4afSHartmut Brandt char *eq; 1414f06ca4afSHartmut Brandt int err; 1415f06ca4afSHartmut Brandt 1416f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1417f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1418f06ca4afSHartmut Brandt else { 1419f06ca4afSHartmut Brandt *eq++ = '\0'; 1420f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1421f06ca4afSHartmut Brandt } 1422f06ca4afSHartmut Brandt if (err == -1) { 1423f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1424f06ca4afSHartmut Brandt exit(1); 1425f06ca4afSHartmut Brandt } 1426f06ca4afSHartmut Brandt } 1427f06ca4afSHartmut Brandt 1428f06ca4afSHartmut Brandt /* 1429f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1430f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1431f06ca4afSHartmut Brandt */ 1432f06ca4afSHartmut Brandt static int 1433f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1434f06ca4afSHartmut Brandt { 1435f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1436f06ca4afSHartmut Brandt u_int i; 1437f06ca4afSHartmut Brandt char *ptr; 1438f06ca4afSHartmut Brandt 1439f06ca4afSHartmut Brandt *optp = NULL; 1440f06ca4afSHartmut Brandt 1441f06ca4afSHartmut Brandt /* skip leading junk */ 1442f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1443f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1444f06ca4afSHartmut Brandt break; 1445f06ca4afSHartmut Brandt if (*ptr == '\0') { 1446f06ca4afSHartmut Brandt *arg = ptr; 1447f06ca4afSHartmut Brandt return (-1); 1448f06ca4afSHartmut Brandt } 1449f06ca4afSHartmut Brandt *optp = ptr; 1450f06ca4afSHartmut Brandt 1451f06ca4afSHartmut Brandt /* find the end of the option */ 1452f06ca4afSHartmut Brandt while (*++ptr != '\0') 1453f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1454f06ca4afSHartmut Brandt break; 1455f06ca4afSHartmut Brandt 1456f06ca4afSHartmut Brandt if (*ptr != '\0') { 1457f06ca4afSHartmut Brandt if (*ptr == '=') { 1458f06ca4afSHartmut Brandt *ptr++ = '\0'; 1459f06ca4afSHartmut Brandt *valp = ptr; 1460f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1461f06ca4afSHartmut Brandt ptr++; 1462f06ca4afSHartmut Brandt if (*ptr != '\0') 1463f06ca4afSHartmut Brandt *ptr++ = '\0'; 1464f06ca4afSHartmut Brandt } else 1465f06ca4afSHartmut Brandt *ptr++ = '\0'; 1466f06ca4afSHartmut Brandt } 1467f06ca4afSHartmut Brandt 1468f06ca4afSHartmut Brandt *arg = ptr; 1469f06ca4afSHartmut Brandt 1470f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 147170af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1472f06ca4afSHartmut Brandt return (i); 1473f06ca4afSHartmut Brandt return (-1); 1474f06ca4afSHartmut Brandt } 1475f06ca4afSHartmut Brandt 1476f06ca4afSHartmut Brandt int 1477f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1478f06ca4afSHartmut Brandt { 1479f06ca4afSHartmut Brandt int opt; 1480f06ca4afSHartmut Brandt FILE *fp; 1481f06ca4afSHartmut Brandt int background = 1; 148270af00a1SHartmut Brandt struct tport *p; 1483f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1484f06ca4afSHartmut Brandt struct lmodule *m; 1485135f7de5SShteryana Shopova char *value = NULL, *option; /* XXX */ 148670af00a1SHartmut Brandt struct transport *t; 1487f06ca4afSHartmut Brandt 1488f06ca4afSHartmut Brandt #define DBG_DUMP 0 1489f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1490f06ca4afSHartmut Brandt #define DBG_TRACE 2 1491f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1492f06ca4afSHartmut Brandt "dump", 1493f06ca4afSHartmut Brandt "events", 1494f06ca4afSHartmut Brandt "trace", 1495f06ca4afSHartmut Brandt NULL 1496f06ca4afSHartmut Brandt }; 1497f06ca4afSHartmut Brandt 1498f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1499f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1500f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1501f06ca4afSHartmut Brandt asn_error = asn_error_func; 1502f06ca4afSHartmut Brandt 1503135f7de5SShteryana Shopova while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1504f06ca4afSHartmut Brandt switch (opt) { 1505f06ca4afSHartmut Brandt 1506f06ca4afSHartmut Brandt case 'c': 1507f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1508f06ca4afSHartmut Brandt break; 1509f06ca4afSHartmut Brandt 1510f06ca4afSHartmut Brandt case 'd': 1511f06ca4afSHartmut Brandt background = 0; 1512f06ca4afSHartmut Brandt break; 1513f06ca4afSHartmut Brandt 1514f06ca4afSHartmut Brandt case 'D': 1515f06ca4afSHartmut Brandt while (*optarg) { 1516f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1517f06ca4afSHartmut Brandt &value, &option)) { 1518f06ca4afSHartmut Brandt 1519f06ca4afSHartmut Brandt case DBG_DUMP: 1520f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1521f06ca4afSHartmut Brandt break; 1522f06ca4afSHartmut Brandt 1523f06ca4afSHartmut Brandt case DBG_EVENTS: 1524f06ca4afSHartmut Brandt debug.evdebug++; 1525f06ca4afSHartmut Brandt break; 1526f06ca4afSHartmut Brandt 1527f06ca4afSHartmut Brandt case DBG_TRACE: 1528f06ca4afSHartmut Brandt if (value == NULL) 1529f06ca4afSHartmut Brandt syslog(LOG_ERR, 1530f06ca4afSHartmut Brandt "no value for 'trace'"); 153151054003SHartmut Brandt else 1532748b5b1eSHartmut Brandt snmp_trace = strtoul(value, 1533748b5b1eSHartmut Brandt NULL, 0); 1534f06ca4afSHartmut Brandt break; 1535f06ca4afSHartmut Brandt 1536f06ca4afSHartmut Brandt case -1: 1537f06ca4afSHartmut Brandt if (suboptarg) 1538f06ca4afSHartmut Brandt syslog(LOG_ERR, 1539f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1540f06ca4afSHartmut Brandt option); 1541f06ca4afSHartmut Brandt else 1542f06ca4afSHartmut Brandt syslog(LOG_ERR, 1543f06ca4afSHartmut Brandt "missing debug flag"); 1544f06ca4afSHartmut Brandt break; 1545f06ca4afSHartmut Brandt } 1546f06ca4afSHartmut Brandt } 1547f06ca4afSHartmut Brandt break; 1548f06ca4afSHartmut Brandt 1549135f7de5SShteryana Shopova case 'e': 1550135f7de5SShteryana Shopova strlcpy(engine_file, optarg, sizeof(engine_file)); 1551135f7de5SShteryana Shopova break; 1552f06ca4afSHartmut Brandt case 'h': 1553f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1554f06ca4afSHartmut Brandt exit(0); 1555f06ca4afSHartmut Brandt 1556f06ca4afSHartmut Brandt case 'I': 1557f06ca4afSHartmut Brandt syspath = optarg; 1558f06ca4afSHartmut Brandt break; 1559f06ca4afSHartmut Brandt 1560f06ca4afSHartmut Brandt case 'l': 1561f06ca4afSHartmut Brandt prefix = optarg; 1562f06ca4afSHartmut Brandt break; 1563f06ca4afSHartmut Brandt 1564f06ca4afSHartmut Brandt case 'm': 1565f06ca4afSHartmut Brandt do_macro(optarg); 1566f06ca4afSHartmut Brandt break; 1567f06ca4afSHartmut Brandt 1568f06ca4afSHartmut Brandt case 'p': 1569f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1570f06ca4afSHartmut Brandt break; 1571f06ca4afSHartmut Brandt } 1572f06ca4afSHartmut Brandt 1573f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1574f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1575f06ca4afSHartmut Brandt 1576f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1577f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1578f06ca4afSHartmut Brandt exit(1); 1579f06ca4afSHartmut Brandt } 1580f06ca4afSHartmut Brandt 1581f06ca4afSHartmut Brandt argc -= optind; 1582f06ca4afSHartmut Brandt argv += optind; 1583f06ca4afSHartmut Brandt 1584f06ca4afSHartmut Brandt progargs = argv; 1585f06ca4afSHartmut Brandt nprogargs = argc; 1586f06ca4afSHartmut Brandt 1587f06ca4afSHartmut Brandt srandomdev(); 1588f06ca4afSHartmut Brandt 1589f06ca4afSHartmut Brandt snmp_serial_no = random(); 1590f06ca4afSHartmut Brandt 1591d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1592d7eb6b47SHartmut Brandt /* 1593d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1594d7eb6b47SHartmut Brandt */ 1595d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1596d7eb6b47SHartmut Brandt sock_methods(&req); 1597d7eb6b47SHartmut Brandt #endif 1598d7eb6b47SHartmut Brandt 1599f06ca4afSHartmut Brandt /* 1600f06ca4afSHartmut Brandt * Initialize the tree. 1601f06ca4afSHartmut Brandt */ 1602f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1603f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1604f06ca4afSHartmut Brandt exit(1); 1605f06ca4afSHartmut Brandt } 1606f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1607f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1608f06ca4afSHartmut Brandt 1609f06ca4afSHartmut Brandt /* 1610f06ca4afSHartmut Brandt * Get standard communities 1611f06ca4afSHartmut Brandt */ 1612d4199d75SHartmut Brandt (void)comm_define(1, "SNMP read", NULL, NULL); 1613d4199d75SHartmut Brandt (void)comm_define(2, "SNMP write", NULL, NULL); 1614f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1615f06ca4afSHartmut Brandt 1616f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1617f06ca4afSHartmut Brandt 1618f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1619f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1620f06ca4afSHartmut Brandt 1621f06ca4afSHartmut Brandt init_actvals(); 1622135f7de5SShteryana Shopova init_snmpd_engine(); 162370af00a1SHartmut Brandt 162470af00a1SHartmut Brandt this_tick = get_ticks(); 162569292cedSHartmut Brandt start_tick = this_tick; 162670af00a1SHartmut Brandt 162770af00a1SHartmut Brandt /* start transports */ 162870af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 162970af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 163070af00a1SHartmut Brandt exit(1); 163170af00a1SHartmut Brandt } 163270af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 163370af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 163470af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 163570af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 163670af00a1SHartmut Brandt 163770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 163870af00a1SHartmut Brandt if (debug.evdebug > 0) 163970af00a1SHartmut Brandt rpoll_trace = 1; 164070af00a1SHartmut Brandt #else 1641f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1642f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1643f06ca4afSHartmut Brandt exit(1); 1644f06ca4afSHartmut Brandt } 1645f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1646f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 164770af00a1SHartmut Brandt #endif 1648f06ca4afSHartmut Brandt 1649135f7de5SShteryana Shopova if (engine_file[0] == '\0') 1650135f7de5SShteryana Shopova snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1651135f7de5SShteryana Shopova 1652896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1653896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1654896052c1SHartmut Brandt exit(1); 1655896052c1SHartmut Brandt } 1656896052c1SHartmut Brandt 165770af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 165870af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 165970af00a1SHartmut Brandt t->vtab->init_port(p); 1660f06ca4afSHartmut Brandt 1661f06ca4afSHartmut Brandt init_sigs(); 1662f06ca4afSHartmut Brandt 1663f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1664f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1665f06ca4afSHartmut Brandt 1666f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1667f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1668f06ca4afSHartmut Brandt fclose(fp); 166970af00a1SHartmut Brandt if (atexit(term) == -1) { 167070af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 167170af00a1SHartmut Brandt (void)remove(pid_file); 167270af00a1SHartmut Brandt exit(0); 1673f06ca4afSHartmut Brandt } 167470af00a1SHartmut Brandt } 1675f06ca4afSHartmut Brandt 1676f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1677f06ca4afSHartmut Brandt NULL) == 0) { 1678f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1679f06ca4afSHartmut Brandt exit(1); 1680f06ca4afSHartmut Brandt } 1681f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1682f06ca4afSHartmut Brandt NULL) == 0) { 1683f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1684f06ca4afSHartmut Brandt exit(1); 1685f06ca4afSHartmut Brandt } 1686f06ca4afSHartmut Brandt 1687f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1688f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1689f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1690f06ca4afSHartmut Brandt lm_start(m); 1691f06ca4afSHartmut Brandt } 1692f06ca4afSHartmut Brandt 169372cd7a52SShteryana Shopova snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 169472cd7a52SShteryana Shopova 1695f06ca4afSHartmut Brandt for (;;) { 169670af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1697f06ca4afSHartmut Brandt evEvent event; 169870af00a1SHartmut Brandt #endif 1699f06ca4afSHartmut Brandt struct lmodule *mod; 1700f06ca4afSHartmut Brandt 1701f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1702f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1703f06ca4afSHartmut Brandt (*mod->config->idle)(); 1704f06ca4afSHartmut Brandt 170570af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1706f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1707f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1708f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1709f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1710f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1711f06ca4afSHartmut Brandt exit(1); 1712f06ca4afSHartmut Brandt } 171370af00a1SHartmut Brandt #else 171470af00a1SHartmut Brandt poll_dispatch(1); 171570af00a1SHartmut Brandt #endif 1716f06ca4afSHartmut Brandt 1717f06ca4afSHartmut Brandt if (work != 0) { 1718f06ca4afSHartmut Brandt block_sigs(); 1719f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 172070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 172170af00a1SHartmut Brandt info_func(); 172270af00a1SHartmut Brandt #else 1723f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1724f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1725f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1726f06ca4afSHartmut Brandt exit(1); 1727f06ca4afSHartmut Brandt } 172870af00a1SHartmut Brandt #endif 1729f06ca4afSHartmut Brandt } 1730f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 173170af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 173270af00a1SHartmut Brandt config_func(); 173370af00a1SHartmut Brandt #else 1734f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1735f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1736f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1737f06ca4afSHartmut Brandt exit(1); 1738f06ca4afSHartmut Brandt } 173970af00a1SHartmut Brandt #endif 1740f06ca4afSHartmut Brandt } 1741f06ca4afSHartmut Brandt work = 0; 1742f06ca4afSHartmut Brandt unblock_sigs(); 174370af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1744f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1745f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1746f06ca4afSHartmut Brandt exit(1); 1747f06ca4afSHartmut Brandt } 174870af00a1SHartmut Brandt #endif 1749f06ca4afSHartmut Brandt } 1750f06ca4afSHartmut Brandt } 1751f06ca4afSHartmut Brandt 1752f06ca4afSHartmut Brandt return (0); 1753f06ca4afSHartmut Brandt } 1754f06ca4afSHartmut Brandt 175569292cedSHartmut Brandt uint64_t 1756135f7de5SShteryana Shopova get_ticks(void) 1757f06ca4afSHartmut Brandt { 1758f06ca4afSHartmut Brandt struct timeval tv; 175969292cedSHartmut Brandt uint64_t ret; 1760f06ca4afSHartmut Brandt 1761f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1762f06ca4afSHartmut Brandt abort(); 176369292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1764f06ca4afSHartmut Brandt return (ret); 1765f06ca4afSHartmut Brandt } 176669292cedSHartmut Brandt 1767f06ca4afSHartmut Brandt /* 1768f06ca4afSHartmut Brandt * Timer support 1769f06ca4afSHartmut Brandt */ 1770165c5d31SHartmut Brandt 1771165c5d31SHartmut Brandt /* 1772165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1773165c5d31SHartmut Brandt */ 177470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 177570af00a1SHartmut Brandt static void 177670af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 177770af00a1SHartmut Brandt #else 1778f06ca4afSHartmut Brandt static void 1779f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1780f06ca4afSHartmut Brandt struct timespec inter __unused) 178170af00a1SHartmut Brandt #endif 1782f06ca4afSHartmut Brandt { 1783f06ca4afSHartmut Brandt struct timer *tp = uap; 1784f06ca4afSHartmut Brandt 1785f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1786f06ca4afSHartmut Brandt tp->func(tp->udata); 1787f06ca4afSHartmut Brandt free(tp); 1788f06ca4afSHartmut Brandt } 1789f06ca4afSHartmut Brandt 1790f06ca4afSHartmut Brandt /* 1791165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1792165c5d31SHartmut Brandt */ 1793165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1794165c5d31SHartmut Brandt static void 1795165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1796165c5d31SHartmut Brandt #else 1797165c5d31SHartmut Brandt static void 1798165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1799165c5d31SHartmut Brandt struct timespec inter __unused) 1800165c5d31SHartmut Brandt #endif 1801165c5d31SHartmut Brandt { 1802165c5d31SHartmut Brandt struct timer *tp = uap; 1803165c5d31SHartmut Brandt 1804165c5d31SHartmut Brandt tp->func(tp->udata); 1805165c5d31SHartmut Brandt } 1806165c5d31SHartmut Brandt 1807165c5d31SHartmut Brandt /* 1808165c5d31SHartmut Brandt * Start a one-shot timer 1809f06ca4afSHartmut Brandt */ 1810f06ca4afSHartmut Brandt void * 1811f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1812f06ca4afSHartmut Brandt { 1813f06ca4afSHartmut Brandt struct timer *tp; 1814a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1815f06ca4afSHartmut Brandt struct timespec due; 181670af00a1SHartmut Brandt #endif 1817f06ca4afSHartmut Brandt 1818f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1819f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1820f06ca4afSHartmut Brandt exit(1); 1821f06ca4afSHartmut Brandt } 1822a9bfedb7SHartmut Brandt 1823a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1824f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1825f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 182670af00a1SHartmut Brandt #endif 1827f06ca4afSHartmut Brandt 1828f06ca4afSHartmut Brandt tp->udata = udata; 1829f06ca4afSHartmut Brandt tp->owner = mod; 1830f06ca4afSHartmut Brandt tp->func = func; 1831f06ca4afSHartmut Brandt 1832f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1833f06ca4afSHartmut Brandt 183470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 1835a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 183670af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 183770af00a1SHartmut Brandt exit(1); 183870af00a1SHartmut Brandt } 183970af00a1SHartmut Brandt #else 1840f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1841f06ca4afSHartmut Brandt == -1) { 1842f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1843f06ca4afSHartmut Brandt exit(1); 1844f06ca4afSHartmut Brandt } 184570af00a1SHartmut Brandt #endif 1846f06ca4afSHartmut Brandt return (tp); 1847f06ca4afSHartmut Brandt } 1848f06ca4afSHartmut Brandt 1849165c5d31SHartmut Brandt /* 1850165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 1851165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 1852165c5d31SHartmut Brandt * repeat number of ticks. 1853165c5d31SHartmut Brandt */ 1854165c5d31SHartmut Brandt void * 1855165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 1856165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 1857165c5d31SHartmut Brandt { 1858165c5d31SHartmut Brandt struct timer *tp; 1859165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1860165c5d31SHartmut Brandt struct timespec due; 1861165c5d31SHartmut Brandt struct timespec inter; 1862165c5d31SHartmut Brandt #endif 1863165c5d31SHartmut Brandt 1864165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1865165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1866165c5d31SHartmut Brandt exit(1); 1867165c5d31SHartmut Brandt } 1868165c5d31SHartmut Brandt 1869165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 1870165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 1871165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 1872165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 1873165c5d31SHartmut Brandt #endif 1874165c5d31SHartmut Brandt 1875165c5d31SHartmut Brandt tp->udata = udata; 1876165c5d31SHartmut Brandt tp->owner = mod; 1877165c5d31SHartmut Brandt tp->func = func; 1878165c5d31SHartmut Brandt 1879165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1880165c5d31SHartmut Brandt 1881165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1882165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 1883165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1884165c5d31SHartmut Brandt exit(1); 1885165c5d31SHartmut Brandt } 1886165c5d31SHartmut Brandt #else 1887165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 1888165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 1889165c5d31SHartmut Brandt exit(1); 1890165c5d31SHartmut Brandt } 1891165c5d31SHartmut Brandt #endif 1892165c5d31SHartmut Brandt return (tp); 1893165c5d31SHartmut Brandt } 1894165c5d31SHartmut Brandt 1895165c5d31SHartmut Brandt /* 1896165c5d31SHartmut Brandt * Stop a timer. 1897165c5d31SHartmut Brandt */ 1898f06ca4afSHartmut Brandt void 1899f06ca4afSHartmut Brandt timer_stop(void *p) 1900f06ca4afSHartmut Brandt { 1901f06ca4afSHartmut Brandt struct timer *tp = p; 1902f06ca4afSHartmut Brandt 1903f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 190470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 190570af00a1SHartmut Brandt poll_stop_timer(tp->id); 190670af00a1SHartmut Brandt #else 1907f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 1908f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 1909f06ca4afSHartmut Brandt exit(1); 1910f06ca4afSHartmut Brandt } 191170af00a1SHartmut Brandt #endif 1912f06ca4afSHartmut Brandt free(p); 1913f06ca4afSHartmut Brandt } 1914f06ca4afSHartmut Brandt 1915f06ca4afSHartmut Brandt static void 1916f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 1917f06ca4afSHartmut Brandt { 1918f06ca4afSHartmut Brandt struct timer *t, *t1; 1919f06ca4afSHartmut Brandt 1920f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 1921f06ca4afSHartmut Brandt while (t != NULL) { 1922f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1923f06ca4afSHartmut Brandt if (t->owner == mod) 1924f06ca4afSHartmut Brandt timer_stop(t); 1925f06ca4afSHartmut Brandt t = t1; 1926f06ca4afSHartmut Brandt } 1927f06ca4afSHartmut Brandt } 1928f06ca4afSHartmut Brandt 1929f06ca4afSHartmut Brandt static void 1930f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1931f06ca4afSHartmut Brandt { 1932f06ca4afSHartmut Brandt va_list ap; 1933f06ca4afSHartmut Brandt static char *pend = NULL; 1934f06ca4afSHartmut Brandt char *ret, *new; 1935f06ca4afSHartmut Brandt 1936f06ca4afSHartmut Brandt va_start(ap, fmt); 1937f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 1938f06ca4afSHartmut Brandt va_end(ap); 1939f06ca4afSHartmut Brandt 1940f06ca4afSHartmut Brandt if (ret == NULL) 1941f06ca4afSHartmut Brandt return; 1942f06ca4afSHartmut Brandt if (pend != NULL) { 1943f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 1944f06ca4afSHartmut Brandt == NULL) { 1945f06ca4afSHartmut Brandt free(ret); 1946f06ca4afSHartmut Brandt return; 1947f06ca4afSHartmut Brandt } 1948f06ca4afSHartmut Brandt pend = new; 1949f06ca4afSHartmut Brandt strcat(pend, ret); 1950f06ca4afSHartmut Brandt free(ret); 1951f06ca4afSHartmut Brandt } else 1952f06ca4afSHartmut Brandt pend = ret; 1953f06ca4afSHartmut Brandt 1954f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 1955f06ca4afSHartmut Brandt *ret = '\0'; 1956f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 1957f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 1958f06ca4afSHartmut Brandt free(pend); 1959f06ca4afSHartmut Brandt pend = NULL; 1960f06ca4afSHartmut Brandt break; 1961f06ca4afSHartmut Brandt } 1962f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 1963f06ca4afSHartmut Brandt } 1964f06ca4afSHartmut Brandt } 1965f06ca4afSHartmut Brandt 1966f06ca4afSHartmut Brandt static void 1967f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 1968f06ca4afSHartmut Brandt { 1969f06ca4afSHartmut Brandt char errbuf[1000]; 1970f06ca4afSHartmut Brandt va_list ap; 1971f06ca4afSHartmut Brandt 197270af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 197370af00a1SHartmut Brandt return; 197470af00a1SHartmut Brandt 1975f06ca4afSHartmut Brandt va_start(ap, err); 1976f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 197770af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 197870af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 1979f06ca4afSHartmut Brandt va_end(ap); 1980f06ca4afSHartmut Brandt 1981f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 1982f06ca4afSHartmut Brandt } 1983f06ca4afSHartmut Brandt 1984f06ca4afSHartmut Brandt static void 1985f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 1986f06ca4afSHartmut Brandt { 1987f06ca4afSHartmut Brandt char errbuf[1000]; 1988f06ca4afSHartmut Brandt va_list ap; 1989f06ca4afSHartmut Brandt 1990f06ca4afSHartmut Brandt va_start(ap, err); 1991f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 1992f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 1993f06ca4afSHartmut Brandt err, ap); 1994f06ca4afSHartmut Brandt va_end(ap); 1995f06ca4afSHartmut Brandt 1996f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 1997f06ca4afSHartmut Brandt } 1998f06ca4afSHartmut Brandt 1999f06ca4afSHartmut Brandt static void 2000f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 2001f06ca4afSHartmut Brandt { 2002f06ca4afSHartmut Brandt char errbuf[1000]; 2003f06ca4afSHartmut Brandt va_list ap; 2004f06ca4afSHartmut Brandt u_int i; 2005f06ca4afSHartmut Brandt 200670af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 200770af00a1SHartmut Brandt return; 200870af00a1SHartmut Brandt 2009f06ca4afSHartmut Brandt va_start(ap, err); 2010f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 201170af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 201270af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2013f06ca4afSHartmut Brandt va_end(ap); 2014f06ca4afSHartmut Brandt 2015f06ca4afSHartmut Brandt if (b != NULL) { 201670af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 201770af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 2018f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 2019f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 202070af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 202170af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 2022f06ca4afSHartmut Brandt } 2023f06ca4afSHartmut Brandt 2024f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2025f06ca4afSHartmut Brandt } 2026f06ca4afSHartmut Brandt 2027f06ca4afSHartmut Brandt /* 2028f06ca4afSHartmut Brandt * Create a new community 2029f06ca4afSHartmut Brandt */ 2030f06ca4afSHartmut Brandt u_int 2031f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 2032f06ca4afSHartmut Brandt const char *str) 2033f06ca4afSHartmut Brandt { 2034f06ca4afSHartmut Brandt struct community *c, *p; 2035f06ca4afSHartmut Brandt u_int ncomm; 2036f06ca4afSHartmut Brandt 2037f06ca4afSHartmut Brandt /* generate an identifier */ 2038f06ca4afSHartmut Brandt do { 2039f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 2040f06ca4afSHartmut Brandt next_community_index = 1; 2041f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 2042f06ca4afSHartmut Brandt if (c->value == ncomm) 2043f06ca4afSHartmut Brandt break; 2044f06ca4afSHartmut Brandt } while (c != NULL); 2045f06ca4afSHartmut Brandt 2046f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 2047f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 2048f06ca4afSHartmut Brandt return (0); 2049f06ca4afSHartmut Brandt } 2050f06ca4afSHartmut Brandt c->owner = owner; 2051f06ca4afSHartmut Brandt c->value = ncomm; 2052f06ca4afSHartmut Brandt c->descr = descr; 2053f06ca4afSHartmut Brandt c->string = NULL; 2054f06ca4afSHartmut Brandt c->private = priv; 2055f06ca4afSHartmut Brandt 2056f06ca4afSHartmut Brandt if (str != NULL) { 2057f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 2058f06ca4afSHartmut Brandt free(c); 2059f06ca4afSHartmut Brandt return (0); 2060f06ca4afSHartmut Brandt } 2061f06ca4afSHartmut Brandt strcpy(c->string, str); 2062f06ca4afSHartmut Brandt } 2063f06ca4afSHartmut Brandt 2064f06ca4afSHartmut Brandt /* make index */ 2065f06ca4afSHartmut Brandt if (c->owner == NULL) { 2066f06ca4afSHartmut Brandt c->index.len = 1; 2067f06ca4afSHartmut Brandt c->index.subs[0] = 0; 2068f06ca4afSHartmut Brandt } else { 2069f06ca4afSHartmut Brandt c->index = c->owner->index; 2070f06ca4afSHartmut Brandt } 2071f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 2072f06ca4afSHartmut Brandt 2073f06ca4afSHartmut Brandt /* 2074f06ca4afSHartmut Brandt * Insert ordered 2075f06ca4afSHartmut Brandt */ 2076f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 2077f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 2078f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 2079f06ca4afSHartmut Brandt break; 2080f06ca4afSHartmut Brandt } 2081f06ca4afSHartmut Brandt } 2082f06ca4afSHartmut Brandt if (p == NULL) 2083f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 2084f06ca4afSHartmut Brandt return (c->value); 2085f06ca4afSHartmut Brandt } 2086f06ca4afSHartmut Brandt 2087f06ca4afSHartmut Brandt const char * 2088f06ca4afSHartmut Brandt comm_string(u_int ncomm) 2089f06ca4afSHartmut Brandt { 2090f06ca4afSHartmut Brandt struct community *p; 2091f06ca4afSHartmut Brandt 2092f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 2093f06ca4afSHartmut Brandt if (p->value == ncomm) 2094f06ca4afSHartmut Brandt return (p->string); 2095f06ca4afSHartmut Brandt return (NULL); 2096f06ca4afSHartmut Brandt } 2097f06ca4afSHartmut Brandt 2098f06ca4afSHartmut Brandt /* 2099f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2100f06ca4afSHartmut Brandt */ 2101f06ca4afSHartmut Brandt static void 2102f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 2103f06ca4afSHartmut Brandt { 2104f06ca4afSHartmut Brandt struct community *p, *p1; 2105f06ca4afSHartmut Brandt 2106f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 2107f06ca4afSHartmut Brandt while (p != NULL) { 2108f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2109f06ca4afSHartmut Brandt if (p->owner == mod) { 2110f06ca4afSHartmut Brandt free(p->string); 2111f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 2112f06ca4afSHartmut Brandt free(p); 2113f06ca4afSHartmut Brandt } 2114f06ca4afSHartmut Brandt p = p1; 2115f06ca4afSHartmut Brandt } 2116f06ca4afSHartmut Brandt } 2117f06ca4afSHartmut Brandt 2118f06ca4afSHartmut Brandt /* 2119f06ca4afSHartmut Brandt * Request ID handling. 2120f06ca4afSHartmut Brandt * 2121f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 2122f06ca4afSHartmut Brandt */ 2123f06ca4afSHartmut Brandt u_int 2124f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 2125f06ca4afSHartmut Brandt { 2126f06ca4afSHartmut Brandt u_int type; 2127f06ca4afSHartmut Brandt struct idrange *r, *r1; 2128f06ca4afSHartmut Brandt 2129f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 2130f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2131f06ca4afSHartmut Brandt return (0); 2132f06ca4afSHartmut Brandt } 2133f06ca4afSHartmut Brandt /* allocate a type id */ 2134f06ca4afSHartmut Brandt do { 2135f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 2136f06ca4afSHartmut Brandt next_idrange = 1; 2137f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2138f06ca4afSHartmut Brandt if (r->type == type) 2139f06ca4afSHartmut Brandt break; 2140f06ca4afSHartmut Brandt } while(r != NULL); 2141f06ca4afSHartmut Brandt 2142f06ca4afSHartmut Brandt /* find a range */ 2143f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 2144f06ca4afSHartmut Brandt r = NULL; 2145f06ca4afSHartmut Brandt else { 2146f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 2147f06ca4afSHartmut Brandt if (r->base < size) { 2148f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2149f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 2150f06ca4afSHartmut Brandt break; 2151f06ca4afSHartmut Brandt r = r1; 2152f06ca4afSHartmut Brandt } 2153f06ca4afSHartmut Brandt r = r1; 2154f06ca4afSHartmut Brandt } 2155f06ca4afSHartmut Brandt if (r == NULL) { 2156f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2157f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2158f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2159f06ca4afSHartmut Brandt return (0); 2160f06ca4afSHartmut Brandt } 2161f06ca4afSHartmut Brandt } 2162f06ca4afSHartmut Brandt } 2163f06ca4afSHartmut Brandt 2164f06ca4afSHartmut Brandt /* allocate structure */ 2165f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2166f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2167f06ca4afSHartmut Brandt return (0); 2168f06ca4afSHartmut Brandt } 2169f06ca4afSHartmut Brandt 2170f06ca4afSHartmut Brandt r1->type = type; 2171f06ca4afSHartmut Brandt r1->size = size; 2172f06ca4afSHartmut Brandt r1->owner = mod; 2173f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2174f06ca4afSHartmut Brandt r1->base = 0; 2175f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2176f06ca4afSHartmut Brandt } else if (r == NULL) { 2177f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2178f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2179f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2180f06ca4afSHartmut Brandt } else { 2181f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2182f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2183f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2184f06ca4afSHartmut Brandt } 2185f06ca4afSHartmut Brandt r1->next = r1->base; 2186f06ca4afSHartmut Brandt 2187f06ca4afSHartmut Brandt return (type); 2188f06ca4afSHartmut Brandt } 2189f06ca4afSHartmut Brandt 2190f06ca4afSHartmut Brandt int32_t 2191f06ca4afSHartmut Brandt reqid_next(u_int type) 2192f06ca4afSHartmut Brandt { 2193f06ca4afSHartmut Brandt struct idrange *r; 2194f06ca4afSHartmut Brandt int32_t id; 2195f06ca4afSHartmut Brandt 2196f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2197f06ca4afSHartmut Brandt if (r->type == type) 2198f06ca4afSHartmut Brandt break; 2199f06ca4afSHartmut Brandt if (r == NULL) { 2200f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2201f06ca4afSHartmut Brandt abort(); 2202f06ca4afSHartmut Brandt } 2203f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2204f06ca4afSHartmut Brandt r->next = r->base; 2205f06ca4afSHartmut Brandt return (id); 2206f06ca4afSHartmut Brandt } 2207f06ca4afSHartmut Brandt 2208f06ca4afSHartmut Brandt int32_t 2209f06ca4afSHartmut Brandt reqid_base(u_int type) 2210f06ca4afSHartmut Brandt { 2211f06ca4afSHartmut Brandt struct idrange *r; 2212f06ca4afSHartmut Brandt 2213f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2214f06ca4afSHartmut Brandt if (r->type == type) 2215f06ca4afSHartmut Brandt return (r->base); 2216f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2217f06ca4afSHartmut Brandt abort(); 2218f06ca4afSHartmut Brandt } 2219f06ca4afSHartmut Brandt 2220f06ca4afSHartmut Brandt u_int 2221f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2222f06ca4afSHartmut Brandt { 2223f06ca4afSHartmut Brandt struct idrange *r; 2224f06ca4afSHartmut Brandt 2225f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2226f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2227f06ca4afSHartmut Brandt return (r->type); 2228f06ca4afSHartmut Brandt return (0); 2229f06ca4afSHartmut Brandt } 2230f06ca4afSHartmut Brandt 2231f06ca4afSHartmut Brandt int 2232f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2233f06ca4afSHartmut Brandt { 2234f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2235f06ca4afSHartmut Brandt } 2236f06ca4afSHartmut Brandt 2237f06ca4afSHartmut Brandt /* 2238f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2239f06ca4afSHartmut Brandt */ 2240f06ca4afSHartmut Brandt static void 2241f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2242f06ca4afSHartmut Brandt { 2243f06ca4afSHartmut Brandt struct idrange *p, *p1; 2244f06ca4afSHartmut Brandt 2245f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2246f06ca4afSHartmut Brandt while (p != NULL) { 2247f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2248f06ca4afSHartmut Brandt if (p->owner == mod) { 2249f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2250f06ca4afSHartmut Brandt free(p); 2251f06ca4afSHartmut Brandt } 2252f06ca4afSHartmut Brandt p = p1; 2253f06ca4afSHartmut Brandt } 2254f06ca4afSHartmut Brandt } 2255f06ca4afSHartmut Brandt 2256f06ca4afSHartmut Brandt /* 2257f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2258f06ca4afSHartmut Brandt */ 2259f06ca4afSHartmut Brandt static int 2260f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2261f06ca4afSHartmut Brandt { 2262f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2263f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2264f06ca4afSHartmut Brandt 2265f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2266f06ca4afSHartmut Brandt } 2267f06ca4afSHartmut Brandt static int 2268f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2269f06ca4afSHartmut Brandt { 2270f06ca4afSHartmut Brandt struct snmp_node *xtree; 2271f06ca4afSHartmut Brandt u_int i; 2272f06ca4afSHartmut Brandt 2273f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2274f06ca4afSHartmut Brandt if (xtree == NULL) { 22758eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2276f06ca4afSHartmut Brandt return (-1); 2277f06ca4afSHartmut Brandt } 2278f06ca4afSHartmut Brandt tree = xtree; 2279f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2280f06ca4afSHartmut Brandt 2281f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 22828eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2283f06ca4afSHartmut Brandt 2284f06ca4afSHartmut Brandt tree_size += nsize; 2285f06ca4afSHartmut Brandt 2286f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2287f06ca4afSHartmut Brandt 2288f06ca4afSHartmut Brandt return (0); 2289f06ca4afSHartmut Brandt } 2290f06ca4afSHartmut Brandt 2291f06ca4afSHartmut Brandt /* 2292f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2293f06ca4afSHartmut Brandt */ 2294f06ca4afSHartmut Brandt static void 2295f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2296f06ca4afSHartmut Brandt { 2297f06ca4afSHartmut Brandt u_int s, d; 2298f06ca4afSHartmut Brandt 2299f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 23008eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2301f06ca4afSHartmut Brandt if (s != d) 2302f06ca4afSHartmut Brandt tree[d] = tree[s]; 2303f06ca4afSHartmut Brandt d++; 2304f06ca4afSHartmut Brandt } 2305f06ca4afSHartmut Brandt tree_size = d; 2306f06ca4afSHartmut Brandt } 2307f06ca4afSHartmut Brandt 2308f06ca4afSHartmut Brandt /* 2309f06ca4afSHartmut Brandt * Loadable modules 2310f06ca4afSHartmut Brandt */ 2311f06ca4afSHartmut Brandt struct lmodule * 2312f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2313f06ca4afSHartmut Brandt { 2314f06ca4afSHartmut Brandt struct lmodule *m; 2315f06ca4afSHartmut Brandt int err; 2316f06ca4afSHartmut Brandt int i; 2317f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2318f06ca4afSHartmut Brandt int ac; 2319f06ca4afSHartmut Brandt u_int u; 2320f06ca4afSHartmut Brandt 2321f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2322f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2323f06ca4afSHartmut Brandt return (NULL); 2324f06ca4afSHartmut Brandt } 2325f06ca4afSHartmut Brandt m->handle = NULL; 2326f06ca4afSHartmut Brandt m->flags = 0; 2327f06ca4afSHartmut Brandt strcpy(m->section, section); 2328f06ca4afSHartmut Brandt 2329f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2330f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2331f06ca4afSHartmut Brandt goto err; 2332f06ca4afSHartmut Brandt } 2333f06ca4afSHartmut Brandt strcpy(m->path, path); 2334f06ca4afSHartmut Brandt 2335f06ca4afSHartmut Brandt /* 2336f06ca4afSHartmut Brandt * Make index 2337f06ca4afSHartmut Brandt */ 2338f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2339f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2340f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2341f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2342f06ca4afSHartmut Brandt 2343f06ca4afSHartmut Brandt /* 2344f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2345f06ca4afSHartmut Brandt */ 2346f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2347f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2348f06ca4afSHartmut Brandt goto err; 2349f06ca4afSHartmut Brandt } 2350f06ca4afSHartmut Brandt 2351f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2352f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2353f06ca4afSHartmut Brandt goto err; 2354f06ca4afSHartmut Brandt } 2355f06ca4afSHartmut Brandt 2356f06ca4afSHartmut Brandt /* 2357f06ca4afSHartmut Brandt * Insert it into the right place 2358f06ca4afSHartmut Brandt */ 2359f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2360f06ca4afSHartmut Brandt 2361f06ca4afSHartmut Brandt /* preserve order */ 2362f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2363f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2364f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2365f06ca4afSHartmut Brandt } 2366f06ca4afSHartmut Brandt 2367f06ca4afSHartmut Brandt /* 2368f06ca4afSHartmut Brandt * make the argument vector. 2369f06ca4afSHartmut Brandt */ 2370f06ca4afSHartmut Brandt ac = 0; 2371f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2372f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2373f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2374f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2375f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2376f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2377f06ca4afSHartmut Brandt "module '%s", section); 2378f06ca4afSHartmut Brandt break; 2379f06ca4afSHartmut Brandt } 2380f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2381f06ca4afSHartmut Brandt } 2382f06ca4afSHartmut Brandt } 2383f06ca4afSHartmut Brandt av[ac] = NULL; 2384f06ca4afSHartmut Brandt 2385f06ca4afSHartmut Brandt /* 2386165c5d31SHartmut Brandt * Run the initialization function 2387f06ca4afSHartmut Brandt */ 2388f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2389f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2390f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2391f06ca4afSHartmut Brandt goto err; 2392f06ca4afSHartmut Brandt } 2393f06ca4afSHartmut Brandt 2394f06ca4afSHartmut Brandt return (m); 2395f06ca4afSHartmut Brandt 2396f06ca4afSHartmut Brandt err: 2397691f8568SShteryana Shopova if ((m->flags & LM_ONSTARTLIST) != 0) 2398691f8568SShteryana Shopova TAILQ_REMOVE(&modules_start, m, start); 2399f06ca4afSHartmut Brandt if (m->handle) 2400f06ca4afSHartmut Brandt dlclose(m->handle); 2401f06ca4afSHartmut Brandt free(m->path); 2402f06ca4afSHartmut Brandt free(m); 2403f06ca4afSHartmut Brandt return (NULL); 2404f06ca4afSHartmut Brandt } 2405f06ca4afSHartmut Brandt 2406f06ca4afSHartmut Brandt /* 2407f06ca4afSHartmut Brandt * Start a module 2408f06ca4afSHartmut Brandt */ 2409f06ca4afSHartmut Brandt void 2410f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2411f06ca4afSHartmut Brandt { 2412f06ca4afSHartmut Brandt const struct lmodule *m; 2413f06ca4afSHartmut Brandt 2414f06ca4afSHartmut Brandt /* 2415f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2416f06ca4afSHartmut Brandt */ 2417f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2418f06ca4afSHartmut Brandt lm_unload(mod); 2419f06ca4afSHartmut Brandt return; 2420f06ca4afSHartmut Brandt } 2421f06ca4afSHartmut Brandt 2422f06ca4afSHartmut Brandt /* 2423f06ca4afSHartmut Brandt * Read configuration 2424f06ca4afSHartmut Brandt */ 2425f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2426f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2427f06ca4afSHartmut Brandt lm_unload(mod); 2428f06ca4afSHartmut Brandt return; 2429f06ca4afSHartmut Brandt } 2430f06ca4afSHartmut Brandt if (mod->config->start) 2431f06ca4afSHartmut Brandt (*mod->config->start)(); 2432f06ca4afSHartmut Brandt 2433f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2434f06ca4afSHartmut Brandt 2435f06ca4afSHartmut Brandt /* 2436f06ca4afSHartmut Brandt * Inform other modules 2437f06ca4afSHartmut Brandt */ 2438f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2439f06ca4afSHartmut Brandt if (m->config->loading) 2440f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2441f06ca4afSHartmut Brandt } 2442f06ca4afSHartmut Brandt 2443f06ca4afSHartmut Brandt 2444f06ca4afSHartmut Brandt /* 2445f06ca4afSHartmut Brandt * Unload a module. 2446f06ca4afSHartmut Brandt */ 2447f06ca4afSHartmut Brandt void 2448f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2449f06ca4afSHartmut Brandt { 2450f06ca4afSHartmut Brandt int err; 2451f06ca4afSHartmut Brandt const struct lmodule *mod; 2452f06ca4afSHartmut Brandt 2453f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2454f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2455f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2456f06ca4afSHartmut Brandt tree_unmerge(m); 2457f06ca4afSHartmut Brandt 2458f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2459f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2460f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2461f06ca4afSHartmut Brandt 2462f06ca4afSHartmut Brandt comm_flush(m); 2463f06ca4afSHartmut Brandt reqid_flush(m); 2464f06ca4afSHartmut Brandt timer_flush(m); 2465f06ca4afSHartmut Brandt fd_flush(m); 2466f06ca4afSHartmut Brandt 2467f06ca4afSHartmut Brandt dlclose(m->handle); 2468f06ca4afSHartmut Brandt free(m->path); 2469f06ca4afSHartmut Brandt 2470f06ca4afSHartmut Brandt /* 2471f06ca4afSHartmut Brandt * Inform other modules 2472f06ca4afSHartmut Brandt */ 2473f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2474f06ca4afSHartmut Brandt if (mod->config->loading) 2475f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2476f06ca4afSHartmut Brandt 2477f06ca4afSHartmut Brandt free(m); 2478f06ca4afSHartmut Brandt } 2479f06ca4afSHartmut Brandt 2480f06ca4afSHartmut Brandt /* 2481f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2482f06ca4afSHartmut Brandt */ 2483f06ca4afSHartmut Brandt u_int 2484f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2485f06ca4afSHartmut Brandt { 2486f06ca4afSHartmut Brandt struct objres *objres, *or1; 2487f06ca4afSHartmut Brandt u_int idx; 2488f06ca4afSHartmut Brandt 2489f06ca4afSHartmut Brandt /* find a free index */ 2490f06ca4afSHartmut Brandt idx = 1; 2491f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2492f06ca4afSHartmut Brandt objres != NULL; 2493f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2494f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2495f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2496f06ca4afSHartmut Brandt idx = objres->index + 1; 2497f06ca4afSHartmut Brandt break; 2498f06ca4afSHartmut Brandt } 2499f06ca4afSHartmut Brandt } 2500f06ca4afSHartmut Brandt 2501f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2502f06ca4afSHartmut Brandt return (0); 2503f06ca4afSHartmut Brandt 2504f06ca4afSHartmut Brandt objres->index = idx; 2505f06ca4afSHartmut Brandt objres->oid = *or; 2506f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 250769292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2508f06ca4afSHartmut Brandt objres->module = mod; 2509f06ca4afSHartmut Brandt 2510f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2511f06ca4afSHartmut Brandt 2512f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2513f06ca4afSHartmut Brandt 2514f06ca4afSHartmut Brandt return (idx); 2515f06ca4afSHartmut Brandt } 2516f06ca4afSHartmut Brandt 2517f06ca4afSHartmut Brandt void 2518f06ca4afSHartmut Brandt or_unregister(u_int idx) 2519f06ca4afSHartmut Brandt { 2520f06ca4afSHartmut Brandt struct objres *objres; 2521f06ca4afSHartmut Brandt 2522f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2523f06ca4afSHartmut Brandt if (objres->index == idx) { 2524f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2525f06ca4afSHartmut Brandt free(objres); 2526f06ca4afSHartmut Brandt return; 2527f06ca4afSHartmut Brandt } 2528f06ca4afSHartmut Brandt } 2529135f7de5SShteryana Shopova 2530135f7de5SShteryana Shopova /* 2531135f7de5SShteryana Shopova * RFC 3414 User-based Security Model support 2532135f7de5SShteryana Shopova */ 2533135f7de5SShteryana Shopova 2534135f7de5SShteryana Shopova struct snmpd_usmstat * 2535135f7de5SShteryana Shopova bsnmpd_get_usm_stats(void) 2536135f7de5SShteryana Shopova { 2537135f7de5SShteryana Shopova return (&snmpd_usmstats); 2538135f7de5SShteryana Shopova } 2539135f7de5SShteryana Shopova 2540135f7de5SShteryana Shopova void 2541135f7de5SShteryana Shopova bsnmpd_reset_usm_stats(void) 2542135f7de5SShteryana Shopova { 25439972acaaSHartmut Brandt memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2544135f7de5SShteryana Shopova } 2545135f7de5SShteryana Shopova 2546135f7de5SShteryana Shopova struct usm_user * 2547135f7de5SShteryana Shopova usm_first_user(void) 2548135f7de5SShteryana Shopova { 2549135f7de5SShteryana Shopova return (SLIST_FIRST(&usm_userlist)); 2550135f7de5SShteryana Shopova } 2551135f7de5SShteryana Shopova 2552135f7de5SShteryana Shopova struct usm_user * 2553135f7de5SShteryana Shopova usm_next_user(struct usm_user *uuser) 2554135f7de5SShteryana Shopova { 2555135f7de5SShteryana Shopova if (uuser == NULL) 2556135f7de5SShteryana Shopova return (NULL); 2557135f7de5SShteryana Shopova 2558135f7de5SShteryana Shopova return (SLIST_NEXT(uuser, up)); 2559135f7de5SShteryana Shopova } 2560135f7de5SShteryana Shopova 2561135f7de5SShteryana Shopova struct usm_user * 2562135f7de5SShteryana Shopova usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2563135f7de5SShteryana Shopova { 2564135f7de5SShteryana Shopova struct usm_user *uuser; 2565135f7de5SShteryana Shopova 2566135f7de5SShteryana Shopova SLIST_FOREACH(uuser, &usm_userlist, up) 2567135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2568135f7de5SShteryana Shopova memcmp(uuser->user_engine_id, engine, elen) == 0 && 2569135f7de5SShteryana Shopova strlen(uuser->suser.sec_name) == strlen(uname) && 2570135f7de5SShteryana Shopova strcmp(uuser->suser.sec_name, uname) == 0) 2571135f7de5SShteryana Shopova break; 2572135f7de5SShteryana Shopova 2573135f7de5SShteryana Shopova return (uuser); 2574135f7de5SShteryana Shopova } 2575135f7de5SShteryana Shopova 2576135f7de5SShteryana Shopova static int 2577135f7de5SShteryana Shopova usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2578135f7de5SShteryana Shopova { 2579135f7de5SShteryana Shopova uint32_t i; 2580135f7de5SShteryana Shopova 2581135f7de5SShteryana Shopova if (u1->user_engine_len < u2->user_engine_len) 2582135f7de5SShteryana Shopova return (-1); 2583135f7de5SShteryana Shopova if (u1->user_engine_len > u2->user_engine_len) 2584135f7de5SShteryana Shopova return (1); 2585135f7de5SShteryana Shopova 2586135f7de5SShteryana Shopova for (i = 0; i < u1->user_engine_len; i++) { 2587135f7de5SShteryana Shopova if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2588135f7de5SShteryana Shopova return (-1); 2589135f7de5SShteryana Shopova if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2590135f7de5SShteryana Shopova return (1); 2591135f7de5SShteryana Shopova } 2592135f7de5SShteryana Shopova 2593135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2594135f7de5SShteryana Shopova return (-1); 2595135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2596135f7de5SShteryana Shopova return (1); 2597135f7de5SShteryana Shopova 2598135f7de5SShteryana Shopova for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2599135f7de5SShteryana Shopova if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2600135f7de5SShteryana Shopova return (-1); 2601135f7de5SShteryana Shopova if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2602135f7de5SShteryana Shopova return (1); 2603135f7de5SShteryana Shopova } 2604135f7de5SShteryana Shopova 2605135f7de5SShteryana Shopova return (0); 2606135f7de5SShteryana Shopova } 2607135f7de5SShteryana Shopova 2608135f7de5SShteryana Shopova struct usm_user * 2609135f7de5SShteryana Shopova usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2610135f7de5SShteryana Shopova { 2611135f7de5SShteryana Shopova int cmp; 2612135f7de5SShteryana Shopova struct usm_user *uuser, *temp, *prev; 2613135f7de5SShteryana Shopova 2614135f7de5SShteryana Shopova for (uuser = usm_first_user(); uuser != NULL; 2615135f7de5SShteryana Shopova (uuser = usm_next_user(uuser))) { 2616135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2617135f7de5SShteryana Shopova strlen(uname) == strlen(uuser->suser.sec_name) && 2618135f7de5SShteryana Shopova strcmp(uname, uuser->suser.sec_name) == 0 && 2619135f7de5SShteryana Shopova memcmp(eid, uuser->user_engine_id, elen) == 0) 2620135f7de5SShteryana Shopova return (NULL); 2621135f7de5SShteryana Shopova } 2622135f7de5SShteryana Shopova 2623135f7de5SShteryana Shopova if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2624135f7de5SShteryana Shopova return (NULL); 2625135f7de5SShteryana Shopova 26268ad8cdc9SEnji Cooper memset(uuser, 0, sizeof(*uuser)); 2627135f7de5SShteryana Shopova strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2628135f7de5SShteryana Shopova memcpy(uuser->user_engine_id, eid, elen); 2629135f7de5SShteryana Shopova uuser->user_engine_len = elen; 2630135f7de5SShteryana Shopova 2631135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2632135f7de5SShteryana Shopova usm_compare_user(uuser, prev) < 0) { 2633135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2634135f7de5SShteryana Shopova return (uuser); 2635135f7de5SShteryana Shopova } 2636135f7de5SShteryana Shopova 2637135f7de5SShteryana Shopova SLIST_FOREACH(temp, &usm_userlist, up) { 2638135f7de5SShteryana Shopova if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2639135f7de5SShteryana Shopova break; 2640135f7de5SShteryana Shopova prev = temp; 2641135f7de5SShteryana Shopova } 2642135f7de5SShteryana Shopova 2643135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2644135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, uuser, up); 2645135f7de5SShteryana Shopova else if (cmp > 0) 2646135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, uuser, up); 2647135f7de5SShteryana Shopova else { 2648135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2649135f7de5SShteryana Shopova free(uuser); 2650135f7de5SShteryana Shopova return (NULL); 2651135f7de5SShteryana Shopova } 2652135f7de5SShteryana Shopova 2653135f7de5SShteryana Shopova return (uuser); 2654135f7de5SShteryana Shopova } 2655135f7de5SShteryana Shopova 2656135f7de5SShteryana Shopova void 2657135f7de5SShteryana Shopova usm_delete_user(struct usm_user *uuser) 2658135f7de5SShteryana Shopova { 2659135f7de5SShteryana Shopova SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2660135f7de5SShteryana Shopova free(uuser); 2661135f7de5SShteryana Shopova } 2662135f7de5SShteryana Shopova 2663135f7de5SShteryana Shopova void 2664135f7de5SShteryana Shopova usm_flush_users(void) 2665135f7de5SShteryana Shopova { 2666135f7de5SShteryana Shopova struct usm_user *uuser; 2667135f7de5SShteryana Shopova 2668135f7de5SShteryana Shopova while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2669135f7de5SShteryana Shopova SLIST_REMOVE_HEAD(&usm_userlist, up); 2670135f7de5SShteryana Shopova free(uuser); 2671135f7de5SShteryana Shopova } 2672135f7de5SShteryana Shopova 2673135f7de5SShteryana Shopova SLIST_INIT(&usm_userlist); 2674135f7de5SShteryana Shopova } 2675135f7de5SShteryana Shopova 2676135f7de5SShteryana Shopova /* 2677135f7de5SShteryana Shopova * RFC 3415 View-based Access Control Model support 2678135f7de5SShteryana Shopova */ 2679135f7de5SShteryana Shopova struct vacm_user * 2680135f7de5SShteryana Shopova vacm_first_user(void) 2681135f7de5SShteryana Shopova { 2682135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_userlist)); 2683135f7de5SShteryana Shopova } 2684135f7de5SShteryana Shopova 2685135f7de5SShteryana Shopova struct vacm_user * 2686135f7de5SShteryana Shopova vacm_next_user(struct vacm_user *vuser) 2687135f7de5SShteryana Shopova { 2688135f7de5SShteryana Shopova if (vuser == NULL) 2689135f7de5SShteryana Shopova return (NULL); 2690135f7de5SShteryana Shopova 2691135f7de5SShteryana Shopova return (SLIST_NEXT(vuser, vvu)); 2692135f7de5SShteryana Shopova } 2693135f7de5SShteryana Shopova 2694135f7de5SShteryana Shopova static int 2695135f7de5SShteryana Shopova vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2696135f7de5SShteryana Shopova { 2697135f7de5SShteryana Shopova uint32_t i; 2698135f7de5SShteryana Shopova 2699135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2700135f7de5SShteryana Shopova return (-1); 2701135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2702135f7de5SShteryana Shopova return (1); 2703135f7de5SShteryana Shopova 2704135f7de5SShteryana Shopova if (strlen(v1->secname) < strlen(v2->secname)) 2705135f7de5SShteryana Shopova return (-1); 2706135f7de5SShteryana Shopova if (strlen(v1->secname) > strlen(v2->secname)) 2707135f7de5SShteryana Shopova return (1); 2708135f7de5SShteryana Shopova 2709135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->secname); i++) { 2710135f7de5SShteryana Shopova if (v1->secname[i] < v2->secname[i]) 2711135f7de5SShteryana Shopova return (-1); 2712135f7de5SShteryana Shopova if (v1->secname[i] > v2->secname[i]) 2713135f7de5SShteryana Shopova return (1); 2714135f7de5SShteryana Shopova } 2715135f7de5SShteryana Shopova 2716135f7de5SShteryana Shopova return (0); 2717135f7de5SShteryana Shopova } 2718135f7de5SShteryana Shopova 2719135f7de5SShteryana Shopova struct vacm_user * 2720135f7de5SShteryana Shopova vacm_new_user(int32_t smodel, char *uname) 2721135f7de5SShteryana Shopova { 2722135f7de5SShteryana Shopova int cmp; 2723135f7de5SShteryana Shopova struct vacm_user *user, *temp, *prev; 2724135f7de5SShteryana Shopova 2725135f7de5SShteryana Shopova SLIST_FOREACH(user, &vacm_userlist, vvu) 2726135f7de5SShteryana Shopova if (strcmp(uname, user->secname) == 0 && 2727135f7de5SShteryana Shopova smodel == user->sec_model) 2728135f7de5SShteryana Shopova return (NULL); 2729135f7de5SShteryana Shopova 2730135f7de5SShteryana Shopova if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2731135f7de5SShteryana Shopova return (NULL); 2732135f7de5SShteryana Shopova 2733135f7de5SShteryana Shopova memset(user, 0, sizeof(*user)); 2734135f7de5SShteryana Shopova user->group = &vacm_default_group; 2735135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2736135f7de5SShteryana Shopova user->sec_model = smodel; 2737135f7de5SShteryana Shopova strlcpy(user->secname, uname, sizeof(user->secname)); 2738135f7de5SShteryana Shopova 2739135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2740135f7de5SShteryana Shopova vacm_compare_user(user, prev) < 0) { 2741135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2742135f7de5SShteryana Shopova return (user); 2743135f7de5SShteryana Shopova } 2744135f7de5SShteryana Shopova 2745135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2746135f7de5SShteryana Shopova if ((cmp = vacm_compare_user(user, temp)) <= 0) 2747135f7de5SShteryana Shopova break; 2748135f7de5SShteryana Shopova prev = temp; 2749135f7de5SShteryana Shopova } 2750135f7de5SShteryana Shopova 2751135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2752135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, user, vvu); 2753135f7de5SShteryana Shopova else if (cmp > 0) 2754135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, user, vvu); 2755135f7de5SShteryana Shopova else { 2756135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", user->secname); 2757135f7de5SShteryana Shopova free(user); 2758135f7de5SShteryana Shopova return (NULL); 2759135f7de5SShteryana Shopova } 2760135f7de5SShteryana Shopova 2761135f7de5SShteryana Shopova return (user); 2762135f7de5SShteryana Shopova } 2763135f7de5SShteryana Shopova 2764135f7de5SShteryana Shopova int 2765135f7de5SShteryana Shopova vacm_delete_user(struct vacm_user *user) 2766135f7de5SShteryana Shopova { 2767135f7de5SShteryana Shopova if (user->group != NULL && user->group != &vacm_default_group) { 2768135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2769135f7de5SShteryana Shopova if (SLIST_EMPTY(&user->group->group_users)) { 2770135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_grouplist, user->group, 2771135f7de5SShteryana Shopova vacm_group, vge); 2772135f7de5SShteryana Shopova free(user->group); 2773135f7de5SShteryana Shopova } 2774135f7de5SShteryana Shopova } 2775135f7de5SShteryana Shopova 2776135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2777135f7de5SShteryana Shopova free(user); 2778135f7de5SShteryana Shopova 2779135f7de5SShteryana Shopova return (0); 2780135f7de5SShteryana Shopova } 2781135f7de5SShteryana Shopova 2782135f7de5SShteryana Shopova int 2783135f7de5SShteryana Shopova vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2784135f7de5SShteryana Shopova { 2785135f7de5SShteryana Shopova struct vacm_group *group; 2786135f7de5SShteryana Shopova 2787135f7de5SShteryana Shopova if (len >= SNMP_ADM_STR32_SIZ) 2788135f7de5SShteryana Shopova return (-1); 2789135f7de5SShteryana Shopova 2790135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2791135f7de5SShteryana Shopova if (strlen(group->groupname) == len && 2792135f7de5SShteryana Shopova memcmp(octets, group->groupname, len) == 0) 2793135f7de5SShteryana Shopova break; 2794135f7de5SShteryana Shopova 2795135f7de5SShteryana Shopova if (group == NULL) { 2796135f7de5SShteryana Shopova if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2797135f7de5SShteryana Shopova return (-1); 2798135f7de5SShteryana Shopova memset(group, 0, sizeof(*group)); 2799135f7de5SShteryana Shopova memcpy(group->groupname, octets, len); 2800135f7de5SShteryana Shopova group->groupname[len] = '\0'; 2801135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2802135f7de5SShteryana Shopova } 2803135f7de5SShteryana Shopova 2804135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2805135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2806135f7de5SShteryana Shopova user->group = group; 2807135f7de5SShteryana Shopova 2808135f7de5SShteryana Shopova return (0); 2809135f7de5SShteryana Shopova } 2810135f7de5SShteryana Shopova 2811135f7de5SShteryana Shopova void 2812135f7de5SShteryana Shopova vacm_groups_init(void) 2813135f7de5SShteryana Shopova { 2814135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2815135f7de5SShteryana Shopova } 2816135f7de5SShteryana Shopova 2817135f7de5SShteryana Shopova struct vacm_access * 2818135f7de5SShteryana Shopova vacm_first_access_rule(void) 2819135f7de5SShteryana Shopova { 2820135f7de5SShteryana Shopova return (TAILQ_FIRST(&vacm_accesslist)); 2821135f7de5SShteryana Shopova } 2822135f7de5SShteryana Shopova 2823135f7de5SShteryana Shopova struct vacm_access * 2824135f7de5SShteryana Shopova vacm_next_access_rule(struct vacm_access *acl) 2825135f7de5SShteryana Shopova { 2826135f7de5SShteryana Shopova if (acl == NULL) 2827135f7de5SShteryana Shopova return (NULL); 2828135f7de5SShteryana Shopova 2829135f7de5SShteryana Shopova return (TAILQ_NEXT(acl, vva)); 2830135f7de5SShteryana Shopova } 2831135f7de5SShteryana Shopova 2832135f7de5SShteryana Shopova static int 2833135f7de5SShteryana Shopova vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2834135f7de5SShteryana Shopova { 2835135f7de5SShteryana Shopova uint32_t i; 2836135f7de5SShteryana Shopova 2837135f7de5SShteryana Shopova if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 2838135f7de5SShteryana Shopova return (-1); 2839135f7de5SShteryana Shopova if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 2840135f7de5SShteryana Shopova return (1); 2841135f7de5SShteryana Shopova 2842135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->group->groupname); i++) { 2843135f7de5SShteryana Shopova if (v1->group->groupname[i] < v2->group->groupname[i]) 2844135f7de5SShteryana Shopova return (-1); 2845135f7de5SShteryana Shopova if (v1->group->groupname[i] > v2->group->groupname[i]) 2846135f7de5SShteryana Shopova return (1); 2847135f7de5SShteryana Shopova } 2848135f7de5SShteryana Shopova 2849135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 2850135f7de5SShteryana Shopova return (-1); 2851135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 2852135f7de5SShteryana Shopova return (1); 2853135f7de5SShteryana Shopova 2854135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->ctx_prefix); i++) { 2855135f7de5SShteryana Shopova if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 2856135f7de5SShteryana Shopova return (-1); 2857135f7de5SShteryana Shopova if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 2858135f7de5SShteryana Shopova return (1); 2859135f7de5SShteryana Shopova } 2860135f7de5SShteryana Shopova 2861135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2862135f7de5SShteryana Shopova return (-1); 2863135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2864135f7de5SShteryana Shopova return (1); 2865135f7de5SShteryana Shopova 2866135f7de5SShteryana Shopova if (v1->sec_level < v2->sec_level) 2867135f7de5SShteryana Shopova return (-1); 2868135f7de5SShteryana Shopova if (v1->sec_level > v2->sec_level) 2869135f7de5SShteryana Shopova return (1); 2870135f7de5SShteryana Shopova 2871135f7de5SShteryana Shopova return (0); 2872135f7de5SShteryana Shopova } 2873135f7de5SShteryana Shopova 2874135f7de5SShteryana Shopova struct vacm_access * 2875135f7de5SShteryana Shopova vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 2876135f7de5SShteryana Shopova { 2877135f7de5SShteryana Shopova struct vacm_group *group; 2878135f7de5SShteryana Shopova struct vacm_access *acl, *temp; 2879135f7de5SShteryana Shopova 2880135f7de5SShteryana Shopova TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 2881135f7de5SShteryana Shopova if (acl->group == NULL) 2882135f7de5SShteryana Shopova continue; 2883135f7de5SShteryana Shopova if (strcmp(gname, acl->group->groupname) == 0 && 2884135f7de5SShteryana Shopova strcmp(cprefix, acl->ctx_prefix) == 0 && 2885135f7de5SShteryana Shopova acl->sec_model == smodel && acl->sec_level == slevel) 2886135f7de5SShteryana Shopova return (NULL); 2887135f7de5SShteryana Shopova } 2888135f7de5SShteryana Shopova 2889135f7de5SShteryana Shopova /* Make sure the group exists */ 2890135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2891135f7de5SShteryana Shopova if (strcmp(gname, group->groupname) == 0) 2892135f7de5SShteryana Shopova break; 2893135f7de5SShteryana Shopova 2894135f7de5SShteryana Shopova if (group == NULL) 2895135f7de5SShteryana Shopova return (NULL); 2896135f7de5SShteryana Shopova 2897135f7de5SShteryana Shopova if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 2898135f7de5SShteryana Shopova return (NULL); 2899135f7de5SShteryana Shopova 2900135f7de5SShteryana Shopova memset(acl, 0, sizeof(*acl)); 2901135f7de5SShteryana Shopova acl->group = group; 2902135f7de5SShteryana Shopova strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 2903135f7de5SShteryana Shopova acl->sec_model = smodel; 2904135f7de5SShteryana Shopova acl->sec_level = slevel; 2905135f7de5SShteryana Shopova 2906135f7de5SShteryana Shopova if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 2907135f7de5SShteryana Shopova vacm_compare_access_rule(acl, temp) < 0) { 2908135f7de5SShteryana Shopova TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 2909135f7de5SShteryana Shopova return (acl); 2910135f7de5SShteryana Shopova } 2911135f7de5SShteryana Shopova 2912135f7de5SShteryana Shopova TAILQ_FOREACH(temp, &vacm_accesslist, vva) 2913135f7de5SShteryana Shopova if (vacm_compare_access_rule(acl, temp) < 0) { 2914135f7de5SShteryana Shopova TAILQ_INSERT_BEFORE(temp, acl, vva); 2915135f7de5SShteryana Shopova return (acl); 2916135f7de5SShteryana Shopova } 2917135f7de5SShteryana Shopova 2918135f7de5SShteryana Shopova TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 2919135f7de5SShteryana Shopova 2920135f7de5SShteryana Shopova return (acl); 2921135f7de5SShteryana Shopova } 2922135f7de5SShteryana Shopova 2923135f7de5SShteryana Shopova int 2924135f7de5SShteryana Shopova vacm_delete_access_rule(struct vacm_access *acl) 2925135f7de5SShteryana Shopova { 2926135f7de5SShteryana Shopova TAILQ_REMOVE(&vacm_accesslist, acl, vva); 2927135f7de5SShteryana Shopova free(acl); 2928135f7de5SShteryana Shopova 2929135f7de5SShteryana Shopova return (0); 2930135f7de5SShteryana Shopova } 2931135f7de5SShteryana Shopova 2932135f7de5SShteryana Shopova struct vacm_view * 2933135f7de5SShteryana Shopova vacm_first_view(void) 2934135f7de5SShteryana Shopova { 2935135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_viewlist)); 2936135f7de5SShteryana Shopova } 2937135f7de5SShteryana Shopova 2938135f7de5SShteryana Shopova struct vacm_view * 2939135f7de5SShteryana Shopova vacm_next_view(struct vacm_view *view) 2940135f7de5SShteryana Shopova { 2941135f7de5SShteryana Shopova if (view == NULL) 2942135f7de5SShteryana Shopova return (NULL); 2943135f7de5SShteryana Shopova 2944135f7de5SShteryana Shopova return (SLIST_NEXT(view, vvl)); 2945135f7de5SShteryana Shopova } 2946135f7de5SShteryana Shopova 2947135f7de5SShteryana Shopova static int 2948135f7de5SShteryana Shopova vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 2949135f7de5SShteryana Shopova { 2950135f7de5SShteryana Shopova uint32_t i; 2951135f7de5SShteryana Shopova 2952135f7de5SShteryana Shopova if (strlen(v1->viewname) < strlen(v2->viewname)) 2953135f7de5SShteryana Shopova return (-1); 2954135f7de5SShteryana Shopova if (strlen(v1->viewname) > strlen(v2->viewname)) 2955135f7de5SShteryana Shopova return (1); 2956135f7de5SShteryana Shopova 2957135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->viewname); i++) { 2958135f7de5SShteryana Shopova if (v1->viewname[i] < v2->viewname[i]) 2959135f7de5SShteryana Shopova return (-1); 2960135f7de5SShteryana Shopova if (v1->viewname[i] > v2->viewname[i]) 2961135f7de5SShteryana Shopova return (1); 2962135f7de5SShteryana Shopova } 2963135f7de5SShteryana Shopova 2964135f7de5SShteryana Shopova return (asn_compare_oid(&v1->subtree, &v2->subtree)); 2965135f7de5SShteryana Shopova } 2966135f7de5SShteryana Shopova 2967135f7de5SShteryana Shopova struct vacm_view * 2968135f7de5SShteryana Shopova vacm_new_view(char *vname, struct asn_oid *oid) 2969135f7de5SShteryana Shopova { 2970135f7de5SShteryana Shopova int cmp; 2971135f7de5SShteryana Shopova struct vacm_view *view, *temp, *prev; 2972135f7de5SShteryana Shopova 2973135f7de5SShteryana Shopova SLIST_FOREACH(view, &vacm_viewlist, vvl) 2974135f7de5SShteryana Shopova if (strcmp(vname, view->viewname) == 0) 2975135f7de5SShteryana Shopova return (NULL); 2976135f7de5SShteryana Shopova 2977135f7de5SShteryana Shopova if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 2978135f7de5SShteryana Shopova return (NULL); 2979135f7de5SShteryana Shopova 2980135f7de5SShteryana Shopova memset(view, 0, sizeof(*view)); 2981135f7de5SShteryana Shopova strlcpy(view->viewname, vname, sizeof(view->viewname)); 2982135f7de5SShteryana Shopova asn_append_oid(&view->subtree, oid); 2983135f7de5SShteryana Shopova 2984135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 2985135f7de5SShteryana Shopova vacm_compare_view(view, prev) < 0) { 2986135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 2987135f7de5SShteryana Shopova return (view); 2988135f7de5SShteryana Shopova } 2989135f7de5SShteryana Shopova 2990135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 2991135f7de5SShteryana Shopova if ((cmp = vacm_compare_view(view, temp)) <= 0) 2992135f7de5SShteryana Shopova break; 2993135f7de5SShteryana Shopova prev = temp; 2994135f7de5SShteryana Shopova } 2995135f7de5SShteryana Shopova 2996135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2997135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, view, vvl); 2998135f7de5SShteryana Shopova else if (cmp > 0) 2999135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, view, vvl); 3000135f7de5SShteryana Shopova else { 3001135f7de5SShteryana Shopova syslog(LOG_ERR, "View %s exists", view->viewname); 3002135f7de5SShteryana Shopova free(view); 3003135f7de5SShteryana Shopova return (NULL); 3004135f7de5SShteryana Shopova } 3005135f7de5SShteryana Shopova 3006135f7de5SShteryana Shopova return (view); 3007135f7de5SShteryana Shopova } 3008135f7de5SShteryana Shopova 3009135f7de5SShteryana Shopova int 3010135f7de5SShteryana Shopova vacm_delete_view(struct vacm_view *view) 3011135f7de5SShteryana Shopova { 3012135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3013135f7de5SShteryana Shopova free(view); 3014135f7de5SShteryana Shopova 3015135f7de5SShteryana Shopova return (0); 3016135f7de5SShteryana Shopova } 3017135f7de5SShteryana Shopova 3018135f7de5SShteryana Shopova struct vacm_context * 3019135f7de5SShteryana Shopova vacm_first_context(void) 3020135f7de5SShteryana Shopova { 3021135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_contextlist)); 3022135f7de5SShteryana Shopova } 3023135f7de5SShteryana Shopova 3024135f7de5SShteryana Shopova struct vacm_context * 3025135f7de5SShteryana Shopova vacm_next_context(struct vacm_context *vacmctx) 3026135f7de5SShteryana Shopova { 3027135f7de5SShteryana Shopova if (vacmctx == NULL) 3028135f7de5SShteryana Shopova return (NULL); 3029135f7de5SShteryana Shopova 3030135f7de5SShteryana Shopova return (SLIST_NEXT(vacmctx, vcl)); 3031135f7de5SShteryana Shopova } 3032135f7de5SShteryana Shopova 3033135f7de5SShteryana Shopova struct vacm_context * 3034135f7de5SShteryana Shopova vacm_add_context(char *ctxname, int regid) 3035135f7de5SShteryana Shopova { 3036135f7de5SShteryana Shopova int cmp; 3037135f7de5SShteryana Shopova struct vacm_context *ctx, *temp, *prev; 3038135f7de5SShteryana Shopova 3039135f7de5SShteryana Shopova SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3040135f7de5SShteryana Shopova if (strcmp(ctxname, ctx->ctxname) == 0) { 3041135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3042135f7de5SShteryana Shopova return (NULL); 3043135f7de5SShteryana Shopova } 3044135f7de5SShteryana Shopova 3045135f7de5SShteryana Shopova if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3046135f7de5SShteryana Shopova return (NULL); 3047135f7de5SShteryana Shopova 3048135f7de5SShteryana Shopova memset(ctx, 0, sizeof(*ctx)); 3049135f7de5SShteryana Shopova strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3050135f7de5SShteryana Shopova ctx->regid = regid; 3051135f7de5SShteryana Shopova 3052135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3053135f7de5SShteryana Shopova strlen(ctx->ctxname) < strlen(prev->ctxname) || 3054135f7de5SShteryana Shopova strcmp(ctx->ctxname, prev->ctxname) < 0) { 3055135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3056135f7de5SShteryana Shopova return (ctx); 3057135f7de5SShteryana Shopova } 3058135f7de5SShteryana Shopova 3059135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3060135f7de5SShteryana Shopova if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3061135f7de5SShteryana Shopova strcmp(ctx->ctxname, temp->ctxname) < 0) { 3062135f7de5SShteryana Shopova cmp = -1; 3063135f7de5SShteryana Shopova break; 3064135f7de5SShteryana Shopova } 3065135f7de5SShteryana Shopova prev = temp; 3066135f7de5SShteryana Shopova } 3067135f7de5SShteryana Shopova 3068135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3069135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, ctx, vcl); 3070135f7de5SShteryana Shopova else if (cmp > 0) 3071135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, ctx, vcl); 3072135f7de5SShteryana Shopova else { 3073135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3074135f7de5SShteryana Shopova free(ctx); 3075135f7de5SShteryana Shopova return (NULL); 3076135f7de5SShteryana Shopova } 3077135f7de5SShteryana Shopova 3078135f7de5SShteryana Shopova return (ctx); 3079135f7de5SShteryana Shopova } 3080135f7de5SShteryana Shopova 3081135f7de5SShteryana Shopova void 3082135f7de5SShteryana Shopova vacm_flush_contexts(int regid) 3083135f7de5SShteryana Shopova { 3084135f7de5SShteryana Shopova struct vacm_context *ctx, *temp; 3085135f7de5SShteryana Shopova 3086135f7de5SShteryana Shopova SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3087135f7de5SShteryana Shopova if (ctx->regid == regid) { 3088135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3089135f7de5SShteryana Shopova free(ctx); 3090135f7de5SShteryana Shopova } 3091135f7de5SShteryana Shopova } 3092