1f06ca4afSHartmut Brandt /* 2f06ca4afSHartmut Brandt * Copyright (c) 2001-2003 3f06ca4afSHartmut Brandt * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4f06ca4afSHartmut Brandt * All rights reserved. 5f06ca4afSHartmut Brandt * 6f06ca4afSHartmut Brandt * Author: Harti Brandt <harti@freebsd.org> 7f06ca4afSHartmut Brandt * 872cd7a52SShteryana Shopova * Copyright (c) 2010 The FreeBSD Foundation 972cd7a52SShteryana Shopova * All rights reserved. 1072cd7a52SShteryana Shopova * 1172cd7a52SShteryana Shopova * Portions of this software were developed by Shteryana Sotirova Shopova 1272cd7a52SShteryana Shopova * under sponsorship from the FreeBSD Foundation. 1372cd7a52SShteryana Shopova * 14896052c1SHartmut Brandt * Redistribution and use in source and binary forms, with or without 15896052c1SHartmut Brandt * modification, are permitted provided that the following conditions 16896052c1SHartmut Brandt * are met: 17896052c1SHartmut Brandt * 1. Redistributions of source code must retain the above copyright 18896052c1SHartmut Brandt * notice, this list of conditions and the following disclaimer. 19f06ca4afSHartmut Brandt * 2. Redistributions in binary form must reproduce the above copyright 20f06ca4afSHartmut Brandt * notice, this list of conditions and the following disclaimer in the 21f06ca4afSHartmut Brandt * documentation and/or other materials provided with the distribution. 22f06ca4afSHartmut Brandt * 23896052c1SHartmut Brandt * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24896052c1SHartmut Brandt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25896052c1SHartmut Brandt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26896052c1SHartmut Brandt * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27896052c1SHartmut Brandt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28896052c1SHartmut Brandt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29896052c1SHartmut Brandt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30896052c1SHartmut Brandt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31896052c1SHartmut Brandt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32896052c1SHartmut Brandt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33896052c1SHartmut Brandt * SUCH DAMAGE. 34f06ca4afSHartmut Brandt * 35748b5b1eSHartmut Brandt * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 36f06ca4afSHartmut Brandt * 37f06ca4afSHartmut Brandt * SNMPd main stuff. 38f06ca4afSHartmut Brandt */ 39135f7de5SShteryana Shopova 40135f7de5SShteryana Shopova #include <sys/queue.h> 41f06ca4afSHartmut Brandt #include <sys/param.h> 42f06ca4afSHartmut Brandt #include <sys/un.h> 4370af00a1SHartmut Brandt #include <sys/ucred.h> 44165c5d31SHartmut Brandt #include <sys/uio.h> 45f06ca4afSHartmut Brandt #include <stdio.h> 46f06ca4afSHartmut Brandt #include <stdlib.h> 47f06ca4afSHartmut Brandt #include <stddef.h> 48f06ca4afSHartmut Brandt #include <string.h> 49f06ca4afSHartmut Brandt #include <stdarg.h> 50f06ca4afSHartmut Brandt #include <ctype.h> 51f06ca4afSHartmut Brandt #include <errno.h> 52f06ca4afSHartmut Brandt #include <syslog.h> 53f06ca4afSHartmut Brandt #include <unistd.h> 54f06ca4afSHartmut Brandt #include <signal.h> 55f06ca4afSHartmut Brandt #include <dlfcn.h> 56f06ca4afSHartmut Brandt #include <inttypes.h> 57f06ca4afSHartmut Brandt 58d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 59d7eb6b47SHartmut Brandt #include <arpa/inet.h> 60d7eb6b47SHartmut Brandt #include <tcpd.h> 61d7eb6b47SHartmut Brandt #endif 62d7eb6b47SHartmut Brandt 63748b5b1eSHartmut Brandt #include "support.h" 64f06ca4afSHartmut Brandt #include "snmpmod.h" 65f06ca4afSHartmut Brandt #include "snmpd.h" 66f06ca4afSHartmut Brandt #include "tree.h" 67f06ca4afSHartmut Brandt #include "oid.h" 68f06ca4afSHartmut Brandt 69f06ca4afSHartmut Brandt #define PATH_PID "/var/run/%s.pid" 70f06ca4afSHartmut Brandt #define PATH_CONFIG "/etc/%s.config" 71135f7de5SShteryana Shopova #define PATH_ENGINE "/var/%s.engine" 72f06ca4afSHartmut Brandt 7369292cedSHartmut Brandt uint64_t this_tick; /* start of processing of current packet (absolute) */ 7469292cedSHartmut Brandt uint64_t start_tick; /* start of processing */ 75f06ca4afSHartmut Brandt 76f06ca4afSHartmut Brandt struct systemg systemg = { 77f06ca4afSHartmut Brandt NULL, 78f06ca4afSHartmut Brandt { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 79f06ca4afSHartmut Brandt NULL, NULL, NULL, 80f06ca4afSHartmut Brandt 64 + 8 + 4, 81f06ca4afSHartmut Brandt 0 82f06ca4afSHartmut Brandt }; 83f06ca4afSHartmut Brandt struct debug debug = { 84f06ca4afSHartmut Brandt 0, /* dump_pdus */ 85f06ca4afSHartmut Brandt LOG_DEBUG, /* log_pri */ 86f06ca4afSHartmut Brandt 0, /* evdebug */ 87f06ca4afSHartmut Brandt }; 88f06ca4afSHartmut Brandt 89f06ca4afSHartmut Brandt struct snmpd snmpd = { 90f06ca4afSHartmut Brandt 2048, /* txbuf */ 91f06ca4afSHartmut Brandt 2048, /* rxbuf */ 92f06ca4afSHartmut Brandt 0, /* comm_dis */ 93f06ca4afSHartmut Brandt 0, /* auth_traps */ 94f06ca4afSHartmut Brandt {0, 0, 0, 0}, /* trap1addr */ 9570af00a1SHartmut Brandt VERS_ENABLE_ALL,/* version_enable */ 96f06ca4afSHartmut Brandt }; 97f06ca4afSHartmut Brandt struct snmpd_stats snmpd_stats; 98f06ca4afSHartmut Brandt 99135f7de5SShteryana Shopova struct snmpd_usmstat snmpd_usmstats; 100135f7de5SShteryana Shopova 101135f7de5SShteryana Shopova /* snmpEngine */ 102135f7de5SShteryana Shopova struct snmp_engine snmpd_engine; 103135f7de5SShteryana Shopova 104f06ca4afSHartmut Brandt /* snmpSerialNo */ 105f06ca4afSHartmut Brandt int32_t snmp_serial_no; 106f06ca4afSHartmut Brandt 10772cd7a52SShteryana Shopova struct snmpd_target_stats snmpd_target_stats; 10872cd7a52SShteryana Shopova 109f06ca4afSHartmut Brandt /* search path for config files */ 110f06ca4afSHartmut Brandt const char *syspath = PATH_SYSCONFIG; 111f06ca4afSHartmut Brandt 112f06ca4afSHartmut Brandt /* list of all loaded modules */ 113f06ca4afSHartmut Brandt struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 114f06ca4afSHartmut Brandt 115f06ca4afSHartmut Brandt /* list of loaded modules during start-up in the order they were loaded */ 116f06ca4afSHartmut Brandt static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 117f06ca4afSHartmut Brandt 118f06ca4afSHartmut Brandt /* list of all known communities */ 119f06ca4afSHartmut Brandt struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 120f06ca4afSHartmut Brandt 121135f7de5SShteryana Shopova /* list of all known USM users */ 122135f7de5SShteryana Shopova struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 123135f7de5SShteryana Shopova 124135f7de5SShteryana Shopova /* A list of all VACM users configured, including v1, v2c and v3 */ 125135f7de5SShteryana Shopova struct vacm_userlist vacm_userlist = SLIST_HEAD_INITIALIZER(vacm_userlist); 126135f7de5SShteryana Shopova 127135f7de5SShteryana Shopova /* A list of all VACM groups */ 128135f7de5SShteryana Shopova struct vacm_grouplist vacm_grouplist = SLIST_HEAD_INITIALIZER(vacm_grouplist); 129135f7de5SShteryana Shopova 130135f7de5SShteryana Shopova static struct vacm_group vacm_default_group = { 131135f7de5SShteryana Shopova .groupname = "", 132135f7de5SShteryana Shopova }; 133135f7de5SShteryana Shopova 134135f7de5SShteryana Shopova /* The list of configured access entries */ 135135f7de5SShteryana Shopova struct vacm_accesslist vacm_accesslist = TAILQ_HEAD_INITIALIZER(vacm_accesslist); 136135f7de5SShteryana Shopova 137135f7de5SShteryana Shopova /* The list of configured views */ 138135f7de5SShteryana Shopova struct vacm_viewlist vacm_viewlist = SLIST_HEAD_INITIALIZER(vacm_viewlist); 139135f7de5SShteryana Shopova 140135f7de5SShteryana Shopova /* The list of configured contexts */ 141135f7de5SShteryana Shopova struct vacm_contextlist vacm_contextlist = 142135f7de5SShteryana Shopova SLIST_HEAD_INITIALIZER(vacm_contextlist); 143135f7de5SShteryana Shopova 144f06ca4afSHartmut Brandt /* list of all installed object resources */ 145f06ca4afSHartmut Brandt struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 146f06ca4afSHartmut Brandt 147f06ca4afSHartmut Brandt /* community value generator */ 148f06ca4afSHartmut Brandt static u_int next_community_index = 1; 149f06ca4afSHartmut Brandt 150f06ca4afSHartmut Brandt /* list of all known ranges */ 151f06ca4afSHartmut Brandt struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 152f06ca4afSHartmut Brandt 153f06ca4afSHartmut Brandt /* identifier generator */ 154f06ca4afSHartmut Brandt u_int next_idrange = 1; 155f06ca4afSHartmut Brandt 156f06ca4afSHartmut Brandt /* list of all current timers */ 157f06ca4afSHartmut Brandt struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 158f06ca4afSHartmut Brandt 159f06ca4afSHartmut Brandt /* list of file descriptors */ 160f06ca4afSHartmut Brandt struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 161f06ca4afSHartmut Brandt 162f06ca4afSHartmut Brandt /* program arguments */ 163f06ca4afSHartmut Brandt static char **progargs; 164f06ca4afSHartmut Brandt static int nprogargs; 165f06ca4afSHartmut Brandt 166f06ca4afSHartmut Brandt /* current community */ 167f06ca4afSHartmut Brandt u_int community; 168f06ca4afSHartmut Brandt static struct community *comm; 169f06ca4afSHartmut Brandt 170135f7de5SShteryana Shopova /* current USM user */ 171135f7de5SShteryana Shopova struct usm_user *usm_user; 172135f7de5SShteryana Shopova 173f06ca4afSHartmut Brandt /* file names */ 174f06ca4afSHartmut Brandt static char config_file[MAXPATHLEN + 1]; 175f06ca4afSHartmut Brandt static char pid_file[MAXPATHLEN + 1]; 176135f7de5SShteryana Shopova char engine_file[MAXPATHLEN + 1]; 177f06ca4afSHartmut Brandt 17870af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 179f06ca4afSHartmut Brandt /* event context */ 180f06ca4afSHartmut Brandt static evContext evctx; 18170af00a1SHartmut Brandt #endif 182f06ca4afSHartmut Brandt 183f06ca4afSHartmut Brandt /* signal mask */ 184f06ca4afSHartmut Brandt static sigset_t blocked_sigs; 185f06ca4afSHartmut Brandt 186f06ca4afSHartmut Brandt /* signal handling */ 187f06ca4afSHartmut Brandt static int work; 188f06ca4afSHartmut Brandt #define WORK_DOINFO 0x0001 189f06ca4afSHartmut Brandt #define WORK_RECONFIG 0x0002 190f06ca4afSHartmut Brandt 191f06ca4afSHartmut Brandt /* oids */ 192f06ca4afSHartmut Brandt static const struct asn_oid 193f06ca4afSHartmut Brandt oid_snmpMIB = OIDX_snmpMIB, 194f06ca4afSHartmut Brandt oid_begemotSnmpd = OIDX_begemotSnmpd, 195f06ca4afSHartmut Brandt oid_coldStart = OIDX_coldStart, 196f06ca4afSHartmut Brandt oid_authenticationFailure = OIDX_authenticationFailure; 197f06ca4afSHartmut Brandt 198f06ca4afSHartmut Brandt const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 199f06ca4afSHartmut Brandt 200135f7de5SShteryana Shopova const struct asn_oid oid_usmUnknownEngineIDs = 201135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 202135f7de5SShteryana Shopova 203135f7de5SShteryana Shopova const struct asn_oid oid_usmNotInTimeWindows = 204135f7de5SShteryana Shopova { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 205135f7de5SShteryana Shopova 206f06ca4afSHartmut Brandt /* request id generator for traps */ 207f06ca4afSHartmut Brandt u_int trap_reqid; 208f06ca4afSHartmut Brandt 209f06ca4afSHartmut Brandt /* help text */ 210f06ca4afSHartmut Brandt static const char usgtxt[] = "\ 211f06ca4afSHartmut Brandt Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 212f06ca4afSHartmut Brandt Open Communication Systems (FhG Fokus). All rights reserved.\n\ 213135f7de5SShteryana Shopova Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 214135f7de5SShteryana Shopova usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 215135f7de5SShteryana Shopova [-l prefix] [-m variable=value] [-p file]\n\ 216f06ca4afSHartmut Brandt options:\n\ 217f06ca4afSHartmut Brandt -d don't daemonize\n\ 218f06ca4afSHartmut Brandt -h print this info\n\ 219f06ca4afSHartmut Brandt -c file specify configuration file\n\ 220f06ca4afSHartmut Brandt -D options debugging options\n\ 221135f7de5SShteryana Shopova -e file specify engine id file\n\ 222f06ca4afSHartmut Brandt -I path system include path\n\ 223f06ca4afSHartmut Brandt -l prefix default basename for pid and config file\n\ 224f06ca4afSHartmut Brandt -m var=val define variable\n\ 225f06ca4afSHartmut Brandt -p file specify pid file\n\ 226f06ca4afSHartmut Brandt "; 227f06ca4afSHartmut Brandt 228d7eb6b47SHartmut Brandt /* hosts_access(3) request */ 229d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 230d7eb6b47SHartmut Brandt static struct request_info req; 231d7eb6b47SHartmut Brandt #endif 232d7eb6b47SHartmut Brandt 23370af00a1SHartmut Brandt /* transports */ 23470af00a1SHartmut Brandt extern const struct transport_def udp_trans; 23570af00a1SHartmut Brandt extern const struct transport_def lsock_trans; 23670af00a1SHartmut Brandt 23770af00a1SHartmut Brandt struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 23870af00a1SHartmut Brandt 239f06ca4afSHartmut Brandt /* forward declarations */ 240f06ca4afSHartmut Brandt static void snmp_printf_func(const char *fmt, ...); 241f06ca4afSHartmut Brandt static void snmp_error_func(const char *err, ...); 242f06ca4afSHartmut Brandt static void snmp_debug_func(const char *err, ...); 243f06ca4afSHartmut Brandt static void asn_error_func(const struct asn_buf *b, const char *err, ...); 244f06ca4afSHartmut Brandt 245f06ca4afSHartmut Brandt /* 246f06ca4afSHartmut Brandt * Allocate rx/tx buffer. We allocate one byte more for rx. 247f06ca4afSHartmut Brandt */ 248f06ca4afSHartmut Brandt void * 249f06ca4afSHartmut Brandt buf_alloc(int tx) 250f06ca4afSHartmut Brandt { 251f06ca4afSHartmut Brandt void *buf; 252f06ca4afSHartmut Brandt 25370af00a1SHartmut Brandt if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 254f06ca4afSHartmut Brandt syslog(LOG_CRIT, "cannot allocate buffer"); 255f06ca4afSHartmut Brandt if (tx) 256f06ca4afSHartmut Brandt snmpd_stats.noTxbuf++; 257f06ca4afSHartmut Brandt else 258f06ca4afSHartmut Brandt snmpd_stats.noRxbuf++; 259f06ca4afSHartmut Brandt return (NULL); 260f06ca4afSHartmut Brandt } 261f06ca4afSHartmut Brandt return (buf); 262f06ca4afSHartmut Brandt } 263f06ca4afSHartmut Brandt 264f06ca4afSHartmut Brandt /* 26570af00a1SHartmut Brandt * Return the buffer size. 266f06ca4afSHartmut Brandt */ 267f06ca4afSHartmut Brandt size_t 268f06ca4afSHartmut Brandt buf_size(int tx) 269f06ca4afSHartmut Brandt { 27070af00a1SHartmut Brandt return (tx ? snmpd.txbuf : snmpd.rxbuf); 271f06ca4afSHartmut Brandt } 272f06ca4afSHartmut Brandt 273f06ca4afSHartmut Brandt /* 274f06ca4afSHartmut Brandt * Prepare a PDU for output 275f06ca4afSHartmut Brandt */ 276f06ca4afSHartmut Brandt void 27770af00a1SHartmut Brandt snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 278f06ca4afSHartmut Brandt const char *dest) 279f06ca4afSHartmut Brandt { 280f06ca4afSHartmut Brandt struct asn_buf resp_b; 281f06ca4afSHartmut Brandt 282f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 283f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 284f06ca4afSHartmut Brandt 285f06ca4afSHartmut Brandt if (snmp_pdu_encode(pdu, &resp_b) != 0) { 286f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot encode message"); 287f06ca4afSHartmut Brandt abort(); 288f06ca4afSHartmut Brandt } 289f06ca4afSHartmut Brandt if (debug.dump_pdus) { 290f06ca4afSHartmut Brandt snmp_printf("%s <- ", dest); 291f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 292f06ca4afSHartmut Brandt } 293f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 294f06ca4afSHartmut Brandt } 295f06ca4afSHartmut Brandt 296f06ca4afSHartmut Brandt /* 297135f7de5SShteryana Shopova * Check USM PDU header credentials against local SNMP Engine & users. 298135f7de5SShteryana Shopova */ 299135f7de5SShteryana Shopova static enum snmp_code 300135f7de5SShteryana Shopova snmp_pdu_auth_user(struct snmp_pdu *pdu) 301135f7de5SShteryana Shopova { 302135f7de5SShteryana Shopova uint64_t etime; 303135f7de5SShteryana Shopova usm_user = NULL; 304135f7de5SShteryana Shopova 305135f7de5SShteryana Shopova /* un-authenticated snmpEngineId discovery */ 306135f7de5SShteryana Shopova if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 307135f7de5SShteryana Shopova pdu->engine.engine_len = snmpd_engine.engine_len; 308135f7de5SShteryana Shopova memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 309135f7de5SShteryana Shopova snmpd_engine.engine_len); 310135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 311135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 312135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 313135f7de5SShteryana Shopova return (SNMP_CODE_OK); 314135f7de5SShteryana Shopova } 315135f7de5SShteryana Shopova 316135f7de5SShteryana Shopova if ((usm_user = usm_find_user(pdu->engine.engine_id, 317135f7de5SShteryana Shopova pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 318135f7de5SShteryana Shopova usm_user->status != 1 /* active */) 319135f7de5SShteryana Shopova return (SNMP_CODE_BADUSER); 320135f7de5SShteryana Shopova 321135f7de5SShteryana Shopova if (usm_user->user_engine_len != snmpd_engine.engine_len || 322135f7de5SShteryana Shopova memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 323135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 324135f7de5SShteryana Shopova return (SNMP_CODE_BADENGINE); 325135f7de5SShteryana Shopova 326135f7de5SShteryana Shopova pdu->user.priv_proto = usm_user->suser.priv_proto; 327135f7de5SShteryana Shopova memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 328135f7de5SShteryana Shopova sizeof(pdu->user.priv_key)); 329135f7de5SShteryana Shopova 330135f7de5SShteryana Shopova /* authenticated snmpEngineId discovery */ 331135f7de5SShteryana Shopova if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 332135f7de5SShteryana Shopova etime = (get_ticks() - start_tick) / 100ULL; 333135f7de5SShteryana Shopova if (etime < INT32_MAX) 334135f7de5SShteryana Shopova snmpd_engine.engine_time = etime; 335135f7de5SShteryana Shopova else { 336135f7de5SShteryana Shopova start_tick = get_ticks(); 337135f7de5SShteryana Shopova set_snmpd_engine(); 338135f7de5SShteryana Shopova snmpd_engine.engine_time = start_tick; 339135f7de5SShteryana Shopova } 340135f7de5SShteryana Shopova 341135f7de5SShteryana Shopova pdu->user.auth_proto = usm_user->suser.auth_proto; 342135f7de5SShteryana Shopova memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 343135f7de5SShteryana Shopova sizeof(pdu->user.auth_key)); 344135f7de5SShteryana Shopova 345135f7de5SShteryana Shopova if (pdu->engine.engine_boots == 0 && 346135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 347135f7de5SShteryana Shopova pdu->flags |= SNMP_MSG_AUTODISCOVER; 348135f7de5SShteryana Shopova return (SNMP_CODE_OK); 349135f7de5SShteryana Shopova } 350135f7de5SShteryana Shopova 351135f7de5SShteryana Shopova if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 352135f7de5SShteryana Shopova abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 353135f7de5SShteryana Shopova SNMP_TIME_WINDOW) 354135f7de5SShteryana Shopova return (SNMP_CODE_NOTINTIME); 355135f7de5SShteryana Shopova } 356135f7de5SShteryana Shopova 357135f7de5SShteryana Shopova if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 358135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 359135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 360135f7de5SShteryana Shopova usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 361135f7de5SShteryana Shopova ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 362135f7de5SShteryana Shopova usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 363135f7de5SShteryana Shopova return (SNMP_CODE_BADSECLEVEL); 364135f7de5SShteryana Shopova 365135f7de5SShteryana Shopova return (SNMP_CODE_OK); 366135f7de5SShteryana Shopova } 367135f7de5SShteryana Shopova 368135f7de5SShteryana Shopova /* 369135f7de5SShteryana Shopova * Check whether access to each of var bindings in the PDU is allowed based 370135f7de5SShteryana Shopova * on the user credentials against the configured User groups & VACM views. 371135f7de5SShteryana Shopova */ 37272cd7a52SShteryana Shopova enum snmp_code 373135f7de5SShteryana Shopova snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 374135f7de5SShteryana Shopova { 375135f7de5SShteryana Shopova const char *uname; 376135f7de5SShteryana Shopova int32_t suboid, smodel; 377135f7de5SShteryana Shopova uint32_t i; 378135f7de5SShteryana Shopova struct vacm_user *vuser; 379135f7de5SShteryana Shopova struct vacm_access *acl; 380135f7de5SShteryana Shopova struct vacm_context *vacmctx; 381135f7de5SShteryana Shopova struct vacm_view *view; 382135f7de5SShteryana Shopova 383135f7de5SShteryana Shopova /* 384135f7de5SShteryana Shopova * At least a default context exists if the snmpd_vacm(3) module is 385135f7de5SShteryana Shopova * running. 386135f7de5SShteryana Shopova */ 387135f7de5SShteryana Shopova if (SLIST_EMPTY(&vacm_contextlist) || 388135f7de5SShteryana Shopova (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 389135f7de5SShteryana Shopova return (SNMP_CODE_OK); 390135f7de5SShteryana Shopova 391135f7de5SShteryana Shopova switch (pdu->version) { 392135f7de5SShteryana Shopova case SNMP_V1: 393135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 394135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 395135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv1; 396135f7de5SShteryana Shopova break; 397135f7de5SShteryana Shopova 398135f7de5SShteryana Shopova case SNMP_V2c: 399135f7de5SShteryana Shopova if ((uname = comm_string(community)) == NULL) 400135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 401135f7de5SShteryana Shopova smodel = SNMP_SECMODEL_SNMPv2c; 402135f7de5SShteryana Shopova break; 403135f7de5SShteryana Shopova 404135f7de5SShteryana Shopova case SNMP_V3: 405135f7de5SShteryana Shopova uname = pdu->user.sec_name; 406135f7de5SShteryana Shopova if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 407135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 408135f7de5SShteryana Shopova /* Compare the PDU context engine id against the agent's */ 409135f7de5SShteryana Shopova if (pdu->context_engine_len != snmpd_engine.engine_len || 410135f7de5SShteryana Shopova memcmp(pdu->context_engine, snmpd_engine.engine_id, 411135f7de5SShteryana Shopova snmpd_engine.engine_len) != 0) 412135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 413135f7de5SShteryana Shopova break; 414135f7de5SShteryana Shopova 415135f7de5SShteryana Shopova default: 416135f7de5SShteryana Shopova abort(); 417135f7de5SShteryana Shopova } 418135f7de5SShteryana Shopova 419135f7de5SShteryana Shopova SLIST_FOREACH(vuser, &vacm_userlist, vvu) 420135f7de5SShteryana Shopova if (strcmp(uname, vuser->secname) == 0 && 421135f7de5SShteryana Shopova vuser->sec_model == smodel) 422135f7de5SShteryana Shopova break; 423135f7de5SShteryana Shopova 424135f7de5SShteryana Shopova if (vuser == NULL || vuser->group == NULL) 425135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 426135f7de5SShteryana Shopova 427135f7de5SShteryana Shopova /* XXX: shteryana - recheck */ 428135f7de5SShteryana Shopova TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 429135f7de5SShteryana Shopova if (acl->group != vuser->group) 430135f7de5SShteryana Shopova continue; 431135f7de5SShteryana Shopova SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 432135f7de5SShteryana Shopova if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 433135f7de5SShteryana Shopova acl->ctx_match) == 0) 434135f7de5SShteryana Shopova goto match; 435135f7de5SShteryana Shopova } 436135f7de5SShteryana Shopova 437135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 438135f7de5SShteryana Shopova 439135f7de5SShteryana Shopova match: 440135f7de5SShteryana Shopova 441135f7de5SShteryana Shopova switch (pdu->type) { 442135f7de5SShteryana Shopova case SNMP_PDU_GET: 443135f7de5SShteryana Shopova case SNMP_PDU_GETNEXT: 444135f7de5SShteryana Shopova case SNMP_PDU_GETBULK: 445135f7de5SShteryana Shopova if ((view = acl->read_view) == NULL) 446135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 447135f7de5SShteryana Shopova break; 448135f7de5SShteryana Shopova 449135f7de5SShteryana Shopova case SNMP_PDU_SET: 450135f7de5SShteryana Shopova if ((view = acl->write_view) == NULL) 451135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 452135f7de5SShteryana Shopova break; 453135f7de5SShteryana Shopova 454135f7de5SShteryana Shopova case SNMP_PDU_TRAP: 455135f7de5SShteryana Shopova case SNMP_PDU_INFORM: 456135f7de5SShteryana Shopova case SNMP_PDU_TRAP2: 457135f7de5SShteryana Shopova case SNMP_PDU_REPORT: 458135f7de5SShteryana Shopova if ((view = acl->notify_view) == NULL) 459135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 460135f7de5SShteryana Shopova break; 461135f7de5SShteryana Shopova case SNMP_PDU_RESPONSE: 462135f7de5SShteryana Shopova /* NOTREACHED */ 463135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 464135f7de5SShteryana Shopova default: 465135f7de5SShteryana Shopova abort(); 466135f7de5SShteryana Shopova } 467135f7de5SShteryana Shopova 468135f7de5SShteryana Shopova for (i = 0; i < pdu->nbindings; i++) { 469135f7de5SShteryana Shopova /* XXX - view->mask*/ 470135f7de5SShteryana Shopova suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 471135f7de5SShteryana Shopova if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 472135f7de5SShteryana Shopova *ip = i + 1; 473135f7de5SShteryana Shopova return (SNMP_CODE_FAILED); 474135f7de5SShteryana Shopova } 475135f7de5SShteryana Shopova } 476135f7de5SShteryana Shopova 477135f7de5SShteryana Shopova return (SNMP_CODE_OK); 478135f7de5SShteryana Shopova } 479135f7de5SShteryana Shopova 480135f7de5SShteryana Shopova /* 481135f7de5SShteryana Shopova * SNMP input. Start: decode the PDU, find the user or community. 482f06ca4afSHartmut Brandt */ 483f06ca4afSHartmut Brandt enum snmpd_input_err 484f06ca4afSHartmut Brandt snmp_input_start(const u_char *buf, size_t len, const char *source, 48570af00a1SHartmut Brandt struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 486f06ca4afSHartmut Brandt { 487f06ca4afSHartmut Brandt struct asn_buf b; 488f06ca4afSHartmut Brandt enum snmp_code code; 489f06ca4afSHartmut Brandt enum snmpd_input_err ret; 49070af00a1SHartmut Brandt int sret; 491f06ca4afSHartmut Brandt 492135f7de5SShteryana Shopova /* update uptime */ 493135f7de5SShteryana Shopova this_tick = get_ticks(); 494135f7de5SShteryana Shopova 495f06ca4afSHartmut Brandt b.asn_cptr = buf; 496f06ca4afSHartmut Brandt b.asn_len = len; 49770af00a1SHartmut Brandt 49870af00a1SHartmut Brandt /* look whether we have enough bytes for the entire PDU. */ 49970af00a1SHartmut Brandt switch (sret = snmp_pdu_snoop(&b)) { 50070af00a1SHartmut Brandt 50170af00a1SHartmut Brandt case 0: 50270af00a1SHartmut Brandt return (SNMPD_INPUT_TRUNC); 50370af00a1SHartmut Brandt 50470af00a1SHartmut Brandt case -1: 50570af00a1SHartmut Brandt snmpd_stats.inASNParseErrs++; 50670af00a1SHartmut Brandt return (SNMPD_INPUT_FAILED); 50770af00a1SHartmut Brandt } 50870af00a1SHartmut Brandt b.asn_len = *pdulen = (size_t)sret; 50970af00a1SHartmut Brandt 510135f7de5SShteryana Shopova memset(pdu, 0, sizeof(*pdu)); 511135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 512135f7de5SShteryana Shopova goto decoded; 513f06ca4afSHartmut Brandt 514135f7de5SShteryana Shopova if (pdu->version == SNMP_V3) { 515135f7de5SShteryana Shopova if (pdu->security_model != SNMP_SECMODEL_USM) { 516135f7de5SShteryana Shopova code = SNMP_CODE_FAILED; 517135f7de5SShteryana Shopova goto decoded; 518135f7de5SShteryana Shopova } 519135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 520135f7de5SShteryana Shopova goto decoded; 521135f7de5SShteryana Shopova if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 522135f7de5SShteryana Shopova goto decoded; 523135f7de5SShteryana Shopova } 524135f7de5SShteryana Shopova code = snmp_pdu_decode_scoped(&b, pdu, ip); 52570af00a1SHartmut Brandt 526f06ca4afSHartmut Brandt ret = SNMPD_INPUT_OK; 527135f7de5SShteryana Shopova 528135f7de5SShteryana Shopova decoded: 529135f7de5SShteryana Shopova snmpd_stats.inPkts++; 530135f7de5SShteryana Shopova 531f06ca4afSHartmut Brandt switch (code) { 532f06ca4afSHartmut Brandt 533f06ca4afSHartmut Brandt case SNMP_CODE_FAILED: 534f06ca4afSHartmut Brandt snmpd_stats.inASNParseErrs++; 535f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 536f06ca4afSHartmut Brandt 537f06ca4afSHartmut Brandt case SNMP_CODE_BADVERS: 53870af00a1SHartmut Brandt bad_vers: 539f06ca4afSHartmut Brandt snmpd_stats.inBadVersions++; 540f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 541f06ca4afSHartmut Brandt 542f06ca4afSHartmut Brandt case SNMP_CODE_BADLEN: 543f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 544f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADLEN; 545f06ca4afSHartmut Brandt break; 546f06ca4afSHartmut Brandt 547f06ca4afSHartmut Brandt case SNMP_CODE_OORANGE: 548f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 549f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALRANGE; 550f06ca4afSHartmut Brandt break; 551f06ca4afSHartmut Brandt 552f06ca4afSHartmut Brandt case SNMP_CODE_BADENC: 553f06ca4afSHartmut Brandt if (pdu->type == SNMP_OP_SET) 554f06ca4afSHartmut Brandt ret = SNMPD_INPUT_VALBADENC; 555f06ca4afSHartmut Brandt break; 556f06ca4afSHartmut Brandt 557135f7de5SShteryana Shopova case SNMP_CODE_BADSECLEVEL: 558135f7de5SShteryana Shopova snmpd_usmstats.unsupported_seclevels++; 559135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 560135f7de5SShteryana Shopova 561135f7de5SShteryana Shopova case SNMP_CODE_NOTINTIME: 562135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 563135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 564135f7de5SShteryana Shopova 565135f7de5SShteryana Shopova case SNMP_CODE_BADUSER: 566135f7de5SShteryana Shopova snmpd_usmstats.unknown_users++; 567135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 568135f7de5SShteryana Shopova 569135f7de5SShteryana Shopova case SNMP_CODE_BADENGINE: 570135f7de5SShteryana Shopova snmpd_usmstats.unknown_engine_ids++; 571135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 572135f7de5SShteryana Shopova 573135f7de5SShteryana Shopova case SNMP_CODE_BADDIGEST: 574135f7de5SShteryana Shopova snmpd_usmstats.wrong_digests++; 575135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 576135f7de5SShteryana Shopova 577135f7de5SShteryana Shopova case SNMP_CODE_EDECRYPT: 578135f7de5SShteryana Shopova snmpd_usmstats.decrypt_errors++; 579135f7de5SShteryana Shopova return (SNMPD_INPUT_FAILED); 580135f7de5SShteryana Shopova 581f06ca4afSHartmut Brandt case SNMP_CODE_OK: 58270af00a1SHartmut Brandt switch (pdu->version) { 58370af00a1SHartmut Brandt 58470af00a1SHartmut Brandt case SNMP_V1: 58570af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V1)) 58670af00a1SHartmut Brandt goto bad_vers; 58770af00a1SHartmut Brandt break; 58870af00a1SHartmut Brandt 58970af00a1SHartmut Brandt case SNMP_V2c: 59070af00a1SHartmut Brandt if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 59170af00a1SHartmut Brandt goto bad_vers; 59270af00a1SHartmut Brandt break; 59370af00a1SHartmut Brandt 594135f7de5SShteryana Shopova case SNMP_V3: 595135f7de5SShteryana Shopova if (!(snmpd.version_enable & VERS_ENABLE_V3)) 596135f7de5SShteryana Shopova goto bad_vers; 597135f7de5SShteryana Shopova break; 598135f7de5SShteryana Shopova 59970af00a1SHartmut Brandt case SNMP_Verr: 60070af00a1SHartmut Brandt goto bad_vers; 60170af00a1SHartmut Brandt } 602f06ca4afSHartmut Brandt break; 603f06ca4afSHartmut Brandt } 604f06ca4afSHartmut Brandt 605f06ca4afSHartmut Brandt if (debug.dump_pdus) { 606f06ca4afSHartmut Brandt snmp_printf("%s -> ", source); 607f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 608f06ca4afSHartmut Brandt } 609f06ca4afSHartmut Brandt 610f06ca4afSHartmut Brandt /* 611135f7de5SShteryana Shopova * Look, whether we know the community or user 612f06ca4afSHartmut Brandt */ 613135f7de5SShteryana Shopova 614135f7de5SShteryana Shopova if (pdu->version != SNMP_V3) { 615f06ca4afSHartmut Brandt TAILQ_FOREACH(comm, &community_list, link) 616f06ca4afSHartmut Brandt if (comm->string != NULL && 617f06ca4afSHartmut Brandt strcmp(comm->string, pdu->community) == 0) 618f06ca4afSHartmut Brandt break; 619f06ca4afSHartmut Brandt 620f06ca4afSHartmut Brandt if (comm == NULL) { 621f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 622f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 623f06ca4afSHartmut Brandt if (snmpd.auth_traps) 624896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 625896052c1SHartmut Brandt (struct snmp_value *)NULL); 626896052c1SHartmut Brandt ret = SNMPD_INPUT_BAD_COMM; 627896052c1SHartmut Brandt } else 628f06ca4afSHartmut Brandt community = comm->value; 629135f7de5SShteryana Shopova } else if (pdu->nbindings == 0) { 630135f7de5SShteryana Shopova /* RFC 3414 - snmpEngineID Discovery */ 631135f7de5SShteryana Shopova if (strlen(pdu->user.sec_name) == 0) { 632135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 633135f7de5SShteryana Shopova &oid_usmUnknownEngineIDs); 634135f7de5SShteryana Shopova pdu->context_engine_len = snmpd_engine.engine_len; 635135f7de5SShteryana Shopova memcpy(pdu->context_engine, snmpd_engine.engine_id, 636135f7de5SShteryana Shopova snmpd_engine.engine_len); 637135f7de5SShteryana Shopova } else if (pdu->engine.engine_boots == 0 && 638135f7de5SShteryana Shopova pdu->engine.engine_time == 0) { 639135f7de5SShteryana Shopova asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 640135f7de5SShteryana Shopova &oid_usmNotInTimeWindows); 641135f7de5SShteryana Shopova pdu->engine.engine_boots = snmpd_engine.engine_boots; 642135f7de5SShteryana Shopova pdu->engine.engine_time = snmpd_engine.engine_time; 643135f7de5SShteryana Shopova } 644135f7de5SShteryana Shopova } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 645135f7de5SShteryana Shopova (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 646135f7de5SShteryana Shopova snmpd_usmstats.not_in_time_windows++; 647135f7de5SShteryana Shopova ret = SNMP_CODE_FAILED; 648135f7de5SShteryana Shopova } 649f06ca4afSHartmut Brandt 650135f7de5SShteryana Shopova if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 651135f7de5SShteryana Shopova ret = SNMP_CODE_FAILED; 652f06ca4afSHartmut Brandt 653f06ca4afSHartmut Brandt return (ret); 654f06ca4afSHartmut Brandt } 655f06ca4afSHartmut Brandt 656f06ca4afSHartmut Brandt /* 657f06ca4afSHartmut Brandt * Will return only _OK or _FAILED 658f06ca4afSHartmut Brandt */ 659f06ca4afSHartmut Brandt enum snmpd_input_err 660f06ca4afSHartmut Brandt snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 661f06ca4afSHartmut Brandt u_char *sndbuf, size_t *sndlen, const char *source, 662f06ca4afSHartmut Brandt enum snmpd_input_err ierr, int32_t ivar, void *data) 663f06ca4afSHartmut Brandt { 664f06ca4afSHartmut Brandt struct snmp_pdu resp; 665f06ca4afSHartmut Brandt struct asn_buf resp_b, pdu_b; 666f06ca4afSHartmut Brandt enum snmp_ret ret; 667f06ca4afSHartmut Brandt 668f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 669f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 670f06ca4afSHartmut Brandt 671f06ca4afSHartmut Brandt pdu_b.asn_cptr = rcvbuf; 672f06ca4afSHartmut Brandt pdu_b.asn_len = rcvlen; 673f06ca4afSHartmut Brandt 674f06ca4afSHartmut Brandt if (ierr != SNMPD_INPUT_OK) { 675f06ca4afSHartmut Brandt /* error decoding the input of a SET */ 676f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 677f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_BADVALUE; 678f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALBADLEN) 679f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_LENGTH; 680f06ca4afSHartmut Brandt else if (ierr == SNMPD_INPUT_VALRANGE) 681f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_VALUE; 682f06ca4afSHartmut Brandt else 683f06ca4afSHartmut Brandt pdu->error_status = SNMP_ERR_WRONG_ENCODING; 684f06ca4afSHartmut Brandt 685f06ca4afSHartmut Brandt pdu->error_index = ivar; 686f06ca4afSHartmut Brandt 687f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 688f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 689f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 690f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 691f06ca4afSHartmut Brandt } 692f06ca4afSHartmut Brandt 693f06ca4afSHartmut Brandt if (debug.dump_pdus) { 694f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 695f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 696f06ca4afSHartmut Brandt } 697f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 698f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 699f06ca4afSHartmut Brandt } 700f06ca4afSHartmut Brandt 701f06ca4afSHartmut Brandt switch (pdu->type) { 702f06ca4afSHartmut Brandt 703f06ca4afSHartmut Brandt case SNMP_PDU_GET: 704f06ca4afSHartmut Brandt ret = snmp_get(pdu, &resp_b, &resp, data); 705f06ca4afSHartmut Brandt break; 706f06ca4afSHartmut Brandt 707f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 708f06ca4afSHartmut Brandt ret = snmp_getnext(pdu, &resp_b, &resp, data); 709f06ca4afSHartmut Brandt break; 710f06ca4afSHartmut Brandt 711f06ca4afSHartmut Brandt case SNMP_PDU_SET: 712f06ca4afSHartmut Brandt ret = snmp_set(pdu, &resp_b, &resp, data); 713f06ca4afSHartmut Brandt break; 714f06ca4afSHartmut Brandt 715f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 716f06ca4afSHartmut Brandt ret = snmp_getbulk(pdu, &resp_b, &resp, data); 717f06ca4afSHartmut Brandt break; 718f06ca4afSHartmut Brandt 719f06ca4afSHartmut Brandt default: 720f06ca4afSHartmut Brandt ret = SNMP_RET_IGN; 721f06ca4afSHartmut Brandt break; 722f06ca4afSHartmut Brandt } 723f06ca4afSHartmut Brandt 724f06ca4afSHartmut Brandt switch (ret) { 725f06ca4afSHartmut Brandt 726f06ca4afSHartmut Brandt case SNMP_RET_OK: 727f06ca4afSHartmut Brandt /* normal return - send a response */ 728f06ca4afSHartmut Brandt if (debug.dump_pdus) { 729f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 730f06ca4afSHartmut Brandt snmp_pdu_dump(&resp); 731f06ca4afSHartmut Brandt } 732f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 733f06ca4afSHartmut Brandt snmp_pdu_free(&resp); 734f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 735f06ca4afSHartmut Brandt 736f06ca4afSHartmut Brandt case SNMP_RET_IGN: 737f06ca4afSHartmut Brandt /* error - send nothing */ 738f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 739f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 740f06ca4afSHartmut Brandt 741f06ca4afSHartmut Brandt case SNMP_RET_ERR: 742f06ca4afSHartmut Brandt /* error - send error response. The snmp routine has 743f06ca4afSHartmut Brandt * changed the error fields in the original message. */ 744f06ca4afSHartmut Brandt resp_b.asn_ptr = sndbuf; 745f06ca4afSHartmut Brandt resp_b.asn_len = snmpd.txbuf; 746f06ca4afSHartmut Brandt if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 747f06ca4afSHartmut Brandt syslog(LOG_WARNING, "could not encode error response"); 748f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 749f06ca4afSHartmut Brandt return (SNMPD_INPUT_FAILED); 750f06ca4afSHartmut Brandt } else { 751f06ca4afSHartmut Brandt if (debug.dump_pdus) { 752f06ca4afSHartmut Brandt snmp_printf("%s <- ", source); 753f06ca4afSHartmut Brandt snmp_pdu_dump(pdu); 754f06ca4afSHartmut Brandt } 755f06ca4afSHartmut Brandt *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 756f06ca4afSHartmut Brandt return (SNMPD_INPUT_OK); 757f06ca4afSHartmut Brandt } 758f06ca4afSHartmut Brandt } 759f06ca4afSHartmut Brandt abort(); 760f06ca4afSHartmut Brandt } 761f06ca4afSHartmut Brandt 76270af00a1SHartmut Brandt /* 76370af00a1SHartmut Brandt * Insert a port into the right place in the transport's table of ports 76470af00a1SHartmut Brandt */ 76570af00a1SHartmut Brandt void 76670af00a1SHartmut Brandt trans_insert_port(struct transport *t, struct tport *port) 76770af00a1SHartmut Brandt { 76870af00a1SHartmut Brandt struct tport *p; 769f06ca4afSHartmut Brandt 77070af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) { 77170af00a1SHartmut Brandt if (asn_compare_oid(&p->index, &port->index) > 0) { 77270af00a1SHartmut Brandt TAILQ_INSERT_BEFORE(p, port, link); 77370af00a1SHartmut Brandt return; 77470af00a1SHartmut Brandt } 77570af00a1SHartmut Brandt } 77670af00a1SHartmut Brandt port->transport = t; 77770af00a1SHartmut Brandt TAILQ_INSERT_TAIL(&t->table, port, link); 77870af00a1SHartmut Brandt } 77970af00a1SHartmut Brandt 78070af00a1SHartmut Brandt /* 78170af00a1SHartmut Brandt * Remove a port from a transport's list 78270af00a1SHartmut Brandt */ 78370af00a1SHartmut Brandt void 78470af00a1SHartmut Brandt trans_remove_port(struct tport *port) 78570af00a1SHartmut Brandt { 78670af00a1SHartmut Brandt 78770af00a1SHartmut Brandt TAILQ_REMOVE(&port->transport->table, port, link); 78870af00a1SHartmut Brandt } 78970af00a1SHartmut Brandt 79070af00a1SHartmut Brandt /* 79170af00a1SHartmut Brandt * Find a port on a transport's list 79270af00a1SHartmut Brandt */ 79370af00a1SHartmut Brandt struct tport * 79470af00a1SHartmut Brandt trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 79570af00a1SHartmut Brandt { 79670af00a1SHartmut Brandt 79770af00a1SHartmut Brandt return (FIND_OBJECT_OID(&t->table, idx, sub)); 79870af00a1SHartmut Brandt } 79970af00a1SHartmut Brandt 80070af00a1SHartmut Brandt /* 80170af00a1SHartmut Brandt * Find next port on a transport's list 80270af00a1SHartmut Brandt */ 80370af00a1SHartmut Brandt struct tport * 80470af00a1SHartmut Brandt trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 80570af00a1SHartmut Brandt { 80670af00a1SHartmut Brandt 80770af00a1SHartmut Brandt return (NEXT_OBJECT_OID(&t->table, idx, sub)); 80870af00a1SHartmut Brandt } 80970af00a1SHartmut Brandt 81070af00a1SHartmut Brandt /* 81170af00a1SHartmut Brandt * Return first port 81270af00a1SHartmut Brandt */ 81370af00a1SHartmut Brandt struct tport * 81470af00a1SHartmut Brandt trans_first_port(struct transport *t) 81570af00a1SHartmut Brandt { 81670af00a1SHartmut Brandt 81770af00a1SHartmut Brandt return (TAILQ_FIRST(&t->table)); 81870af00a1SHartmut Brandt } 81970af00a1SHartmut Brandt 82070af00a1SHartmut Brandt /* 82170af00a1SHartmut Brandt * Iterate through all ports until a function returns a 0. 82270af00a1SHartmut Brandt */ 82370af00a1SHartmut Brandt struct tport * 82470af00a1SHartmut Brandt trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 82570af00a1SHartmut Brandt intptr_t arg) 82670af00a1SHartmut Brandt { 82770af00a1SHartmut Brandt struct tport *p; 82870af00a1SHartmut Brandt 82970af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 83070af00a1SHartmut Brandt if (func(p, arg) == 0) 83170af00a1SHartmut Brandt return (p); 83270af00a1SHartmut Brandt return (NULL); 83370af00a1SHartmut Brandt } 83470af00a1SHartmut Brandt 83570af00a1SHartmut Brandt /* 83670af00a1SHartmut Brandt * Register a transport 83770af00a1SHartmut Brandt */ 83870af00a1SHartmut Brandt int 83970af00a1SHartmut Brandt trans_register(const struct transport_def *def, struct transport **pp) 84070af00a1SHartmut Brandt { 84170af00a1SHartmut Brandt u_int i; 84270af00a1SHartmut Brandt char or_descr[256]; 84370af00a1SHartmut Brandt 84470af00a1SHartmut Brandt if ((*pp = malloc(sizeof(**pp))) == NULL) 84570af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 84670af00a1SHartmut Brandt 84770af00a1SHartmut Brandt /* construct index */ 84870af00a1SHartmut Brandt (*pp)->index.len = strlen(def->name) + 1; 84970af00a1SHartmut Brandt (*pp)->index.subs[0] = strlen(def->name); 85070af00a1SHartmut Brandt for (i = 0; i < (*pp)->index.subs[0]; i++) 85170af00a1SHartmut Brandt (*pp)->index.subs[i + 1] = def->name[i]; 85270af00a1SHartmut Brandt 85370af00a1SHartmut Brandt (*pp)->vtab = def; 85470af00a1SHartmut Brandt 85570af00a1SHartmut Brandt if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 85670af00a1SHartmut Brandt free(*pp); 85770af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 85870af00a1SHartmut Brandt } 85970af00a1SHartmut Brandt 86070af00a1SHartmut Brandt /* register module */ 86170af00a1SHartmut Brandt snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 86270af00a1SHartmut Brandt if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 86370af00a1SHartmut Brandt free(*pp); 86470af00a1SHartmut Brandt return (SNMP_ERR_GENERR); 86570af00a1SHartmut Brandt } 86670af00a1SHartmut Brandt 86770af00a1SHartmut Brandt INSERT_OBJECT_OID((*pp), &transport_list); 86870af00a1SHartmut Brandt 86970af00a1SHartmut Brandt TAILQ_INIT(&(*pp)->table); 87070af00a1SHartmut Brandt 87170af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 87270af00a1SHartmut Brandt } 87370af00a1SHartmut Brandt 87470af00a1SHartmut Brandt /* 87570af00a1SHartmut Brandt * Unregister transport 87670af00a1SHartmut Brandt */ 87770af00a1SHartmut Brandt int 87870af00a1SHartmut Brandt trans_unregister(struct transport *t) 87970af00a1SHartmut Brandt { 88070af00a1SHartmut Brandt if (!TAILQ_EMPTY(&t->table)) 88170af00a1SHartmut Brandt return (SNMP_ERR_INCONS_VALUE); 88270af00a1SHartmut Brandt 88370af00a1SHartmut Brandt or_unregister(t->or_index); 88470af00a1SHartmut Brandt TAILQ_REMOVE(&transport_list, t, link); 88570af00a1SHartmut Brandt 88670af00a1SHartmut Brandt return (SNMP_ERR_NOERROR); 88770af00a1SHartmut Brandt } 888f06ca4afSHartmut Brandt 889f06ca4afSHartmut Brandt /* 890f06ca4afSHartmut Brandt * File descriptor support 891f06ca4afSHartmut Brandt */ 89270af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 89370af00a1SHartmut Brandt static void 89470af00a1SHartmut Brandt input(int fd, int mask __unused, void *uap) 89570af00a1SHartmut Brandt #else 896f06ca4afSHartmut Brandt static void 897f06ca4afSHartmut Brandt input(evContext ctx __unused, void *uap, int fd, int mask __unused) 89870af00a1SHartmut Brandt #endif 899f06ca4afSHartmut Brandt { 900f06ca4afSHartmut Brandt struct fdesc *f = uap; 901f06ca4afSHartmut Brandt 902f06ca4afSHartmut Brandt (*f->func)(fd, f->udata); 903f06ca4afSHartmut Brandt } 904f06ca4afSHartmut Brandt 905f06ca4afSHartmut Brandt void 906f06ca4afSHartmut Brandt fd_suspend(void *p) 907f06ca4afSHartmut Brandt { 908f06ca4afSHartmut Brandt struct fdesc *f = p; 909f06ca4afSHartmut Brandt 91070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 91170af00a1SHartmut Brandt if (f->id >= 0) { 91270af00a1SHartmut Brandt poll_unregister(f->id); 91370af00a1SHartmut Brandt f->id = -1; 91470af00a1SHartmut Brandt } 91570af00a1SHartmut Brandt #else 916f06ca4afSHartmut Brandt if (evTestID(f->id)) { 917f06ca4afSHartmut Brandt (void)evDeselectFD(evctx, f->id); 918f06ca4afSHartmut Brandt evInitID(&f->id); 919f06ca4afSHartmut Brandt } 92070af00a1SHartmut Brandt #endif 921f06ca4afSHartmut Brandt } 922f06ca4afSHartmut Brandt 923f06ca4afSHartmut Brandt int 924f06ca4afSHartmut Brandt fd_resume(void *p) 925f06ca4afSHartmut Brandt { 926f06ca4afSHartmut Brandt struct fdesc *f = p; 927f06ca4afSHartmut Brandt int err; 928f06ca4afSHartmut Brandt 92970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 93070af00a1SHartmut Brandt if (f->id >= 0) 93170af00a1SHartmut Brandt return (0); 93294caccb3SHartmut Brandt if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 93370af00a1SHartmut Brandt err = errno; 93470af00a1SHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 93570af00a1SHartmut Brandt errno = err; 93670af00a1SHartmut Brandt return (-1); 93770af00a1SHartmut Brandt } 93870af00a1SHartmut Brandt #else 939f06ca4afSHartmut Brandt if (evTestID(f->id)) 940f06ca4afSHartmut Brandt return (0); 941f06ca4afSHartmut Brandt if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 942f06ca4afSHartmut Brandt err = errno; 943f06ca4afSHartmut Brandt syslog(LOG_ERR, "select fd %d: %m", f->fd); 944f06ca4afSHartmut Brandt errno = err; 945f06ca4afSHartmut Brandt return (-1); 946f06ca4afSHartmut Brandt } 94770af00a1SHartmut Brandt #endif 948f06ca4afSHartmut Brandt return (0); 949f06ca4afSHartmut Brandt } 950f06ca4afSHartmut Brandt 951f06ca4afSHartmut Brandt void * 952f06ca4afSHartmut Brandt fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 953f06ca4afSHartmut Brandt { 954f06ca4afSHartmut Brandt struct fdesc *f; 955f06ca4afSHartmut Brandt int err; 956f06ca4afSHartmut Brandt 957f06ca4afSHartmut Brandt if ((f = malloc(sizeof(struct fdesc))) == NULL) { 958f06ca4afSHartmut Brandt err = errno; 959f06ca4afSHartmut Brandt syslog(LOG_ERR, "fd_select: %m"); 960f06ca4afSHartmut Brandt errno = err; 961f06ca4afSHartmut Brandt return (NULL); 962f06ca4afSHartmut Brandt } 963f06ca4afSHartmut Brandt f->fd = fd; 964f06ca4afSHartmut Brandt f->func = func; 965f06ca4afSHartmut Brandt f->udata = udata; 966f06ca4afSHartmut Brandt f->owner = mod; 96770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 96870af00a1SHartmut Brandt f->id = -1; 96970af00a1SHartmut Brandt #else 970f06ca4afSHartmut Brandt evInitID(&f->id); 97170af00a1SHartmut Brandt #endif 972f06ca4afSHartmut Brandt 973f06ca4afSHartmut Brandt if (fd_resume(f)) { 974f06ca4afSHartmut Brandt err = errno; 975f06ca4afSHartmut Brandt free(f); 976f06ca4afSHartmut Brandt errno = err; 977f06ca4afSHartmut Brandt return (NULL); 978f06ca4afSHartmut Brandt } 979f06ca4afSHartmut Brandt 980f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&fdesc_list, f, link); 981f06ca4afSHartmut Brandt 982f06ca4afSHartmut Brandt return (f); 983f06ca4afSHartmut Brandt } 984f06ca4afSHartmut Brandt 985f06ca4afSHartmut Brandt void 986f06ca4afSHartmut Brandt fd_deselect(void *p) 987f06ca4afSHartmut Brandt { 988f06ca4afSHartmut Brandt struct fdesc *f = p; 989f06ca4afSHartmut Brandt 990f06ca4afSHartmut Brandt LIST_REMOVE(f, link); 991f06ca4afSHartmut Brandt fd_suspend(f); 992f06ca4afSHartmut Brandt free(f); 993f06ca4afSHartmut Brandt } 994f06ca4afSHartmut Brandt 995f06ca4afSHartmut Brandt static void 996f06ca4afSHartmut Brandt fd_flush(struct lmodule *mod) 997f06ca4afSHartmut Brandt { 998f06ca4afSHartmut Brandt struct fdesc *t, *t1; 999f06ca4afSHartmut Brandt 1000f06ca4afSHartmut Brandt t = LIST_FIRST(&fdesc_list); 1001f06ca4afSHartmut Brandt while (t != NULL) { 1002f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 1003f06ca4afSHartmut Brandt if (t->owner == mod) 1004f06ca4afSHartmut Brandt fd_deselect(t); 1005f06ca4afSHartmut Brandt t = t1; 1006f06ca4afSHartmut Brandt } 1007f06ca4afSHartmut Brandt } 1008f06ca4afSHartmut Brandt 1009f06ca4afSHartmut Brandt /* 101070af00a1SHartmut Brandt * Consume a message from the input buffer 1011f06ca4afSHartmut Brandt */ 1012f06ca4afSHartmut Brandt static void 101370af00a1SHartmut Brandt snmp_input_consume(struct port_input *pi) 1014f06ca4afSHartmut Brandt { 101570af00a1SHartmut Brandt if (!pi->stream) { 101670af00a1SHartmut Brandt /* always consume everything */ 101770af00a1SHartmut Brandt pi->length = 0; 101870af00a1SHartmut Brandt return; 101970af00a1SHartmut Brandt } 102070af00a1SHartmut Brandt if (pi->consumed >= pi->length) { 102170af00a1SHartmut Brandt /* all bytes consumed */ 102270af00a1SHartmut Brandt pi->length = 0; 102370af00a1SHartmut Brandt return; 102470af00a1SHartmut Brandt } 102570af00a1SHartmut Brandt memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 102670af00a1SHartmut Brandt pi->length -= pi->consumed; 102770af00a1SHartmut Brandt } 102870af00a1SHartmut Brandt 102970af00a1SHartmut Brandt struct credmsg { 103070af00a1SHartmut Brandt struct cmsghdr hdr; 103170af00a1SHartmut Brandt struct cmsgcred cred; 103270af00a1SHartmut Brandt }; 103370af00a1SHartmut Brandt 103470af00a1SHartmut Brandt static void 103570af00a1SHartmut Brandt check_priv(struct port_input *pi, struct msghdr *msg) 103670af00a1SHartmut Brandt { 103770af00a1SHartmut Brandt struct credmsg *cmsg; 103870af00a1SHartmut Brandt struct xucred ucred; 103970af00a1SHartmut Brandt socklen_t ucredlen; 104070af00a1SHartmut Brandt 104170af00a1SHartmut Brandt pi->priv = 0; 104270af00a1SHartmut Brandt 104370af00a1SHartmut Brandt if (msg->msg_controllen == sizeof(*cmsg)) { 1044165c5d31SHartmut Brandt /* process explicitly sends credentials */ 104570af00a1SHartmut Brandt 104670af00a1SHartmut Brandt cmsg = (struct credmsg *)msg->msg_control; 104770af00a1SHartmut Brandt pi->priv = (cmsg->cred.cmcred_euid == 0); 104870af00a1SHartmut Brandt return; 104970af00a1SHartmut Brandt } 105070af00a1SHartmut Brandt 105170af00a1SHartmut Brandt /* ok, obtain the accept time credentials */ 105270af00a1SHartmut Brandt ucredlen = sizeof(ucred); 105370af00a1SHartmut Brandt 105470af00a1SHartmut Brandt if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 105570af00a1SHartmut Brandt ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 105670af00a1SHartmut Brandt pi->priv = (ucred.cr_uid == 0); 105770af00a1SHartmut Brandt } 105870af00a1SHartmut Brandt 105970af00a1SHartmut Brandt /* 106070af00a1SHartmut Brandt * Input from a stream socket. 106170af00a1SHartmut Brandt */ 106270af00a1SHartmut Brandt static int 106370af00a1SHartmut Brandt recv_stream(struct port_input *pi) 106470af00a1SHartmut Brandt { 106570af00a1SHartmut Brandt struct msghdr msg; 106670af00a1SHartmut Brandt struct iovec iov[1]; 106770af00a1SHartmut Brandt ssize_t len; 106870af00a1SHartmut Brandt struct credmsg cmsg; 106970af00a1SHartmut Brandt 107070af00a1SHartmut Brandt if (pi->buf == NULL) { 107170af00a1SHartmut Brandt /* no buffer yet - allocate one */ 107270af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 107370af00a1SHartmut Brandt /* ups - could not get buffer. Return an error 107470af00a1SHartmut Brandt * the caller must close the transport. */ 107570af00a1SHartmut Brandt return (-1); 107670af00a1SHartmut Brandt } 107770af00a1SHartmut Brandt pi->buflen = buf_size(0); 107870af00a1SHartmut Brandt pi->consumed = 0; 107970af00a1SHartmut Brandt pi->length = 0; 108070af00a1SHartmut Brandt } 108170af00a1SHartmut Brandt 108270af00a1SHartmut Brandt /* try to get a message */ 108370af00a1SHartmut Brandt msg.msg_name = pi->peer; 108470af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 108570af00a1SHartmut Brandt msg.msg_iov = iov; 108670af00a1SHartmut Brandt msg.msg_iovlen = 1; 108770af00a1SHartmut Brandt if (pi->cred) { 108870af00a1SHartmut Brandt msg.msg_control = &cmsg; 108970af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 109070af00a1SHartmut Brandt 109170af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 109270af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 109370af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 109470af00a1SHartmut Brandt } else { 109570af00a1SHartmut Brandt msg.msg_control = NULL; 109670af00a1SHartmut Brandt msg.msg_controllen = 0; 109770af00a1SHartmut Brandt } 109870af00a1SHartmut Brandt msg.msg_flags = 0; 109970af00a1SHartmut Brandt 110070af00a1SHartmut Brandt iov[0].iov_base = pi->buf + pi->length; 110170af00a1SHartmut Brandt iov[0].iov_len = pi->buflen - pi->length; 110270af00a1SHartmut Brandt 110370af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 110470af00a1SHartmut Brandt 110570af00a1SHartmut Brandt if (len == -1 || len == 0) 110670af00a1SHartmut Brandt /* receive error */ 110770af00a1SHartmut Brandt return (-1); 110870af00a1SHartmut Brandt 110970af00a1SHartmut Brandt pi->length += len; 111070af00a1SHartmut Brandt 111170af00a1SHartmut Brandt if (pi->cred) 111270af00a1SHartmut Brandt check_priv(pi, &msg); 111370af00a1SHartmut Brandt 111470af00a1SHartmut Brandt return (0); 111570af00a1SHartmut Brandt } 111670af00a1SHartmut Brandt 111770af00a1SHartmut Brandt /* 111870af00a1SHartmut Brandt * Input from a datagram socket. 111970af00a1SHartmut Brandt * Each receive should return one datagram. 112070af00a1SHartmut Brandt */ 112170af00a1SHartmut Brandt static int 112270af00a1SHartmut Brandt recv_dgram(struct port_input *pi) 112370af00a1SHartmut Brandt { 112470af00a1SHartmut Brandt u_char embuf[1000]; 112570af00a1SHartmut Brandt struct msghdr msg; 112670af00a1SHartmut Brandt struct iovec iov[1]; 112770af00a1SHartmut Brandt ssize_t len; 112870af00a1SHartmut Brandt struct credmsg cmsg; 112970af00a1SHartmut Brandt 113070af00a1SHartmut Brandt if (pi->buf == NULL) { 113170af00a1SHartmut Brandt /* no buffer yet - allocate one */ 113270af00a1SHartmut Brandt if ((pi->buf = buf_alloc(0)) == NULL) { 113370af00a1SHartmut Brandt /* ups - could not get buffer. Read away input 113470af00a1SHartmut Brandt * and drop it */ 113570af00a1SHartmut Brandt (void)recvfrom(pi->fd, embuf, sizeof(embuf), 113670af00a1SHartmut Brandt 0, NULL, NULL); 113770af00a1SHartmut Brandt /* return error */ 113870af00a1SHartmut Brandt return (-1); 113970af00a1SHartmut Brandt } 114070af00a1SHartmut Brandt pi->buflen = buf_size(0); 114170af00a1SHartmut Brandt } 114270af00a1SHartmut Brandt 114370af00a1SHartmut Brandt /* try to get a message */ 114470af00a1SHartmut Brandt msg.msg_name = pi->peer; 114570af00a1SHartmut Brandt msg.msg_namelen = pi->peerlen; 114670af00a1SHartmut Brandt msg.msg_iov = iov; 114770af00a1SHartmut Brandt msg.msg_iovlen = 1; 114870af00a1SHartmut Brandt if (pi->cred) { 114970af00a1SHartmut Brandt msg.msg_control = &cmsg; 115070af00a1SHartmut Brandt msg.msg_controllen = sizeof(cmsg); 115170af00a1SHartmut Brandt 115270af00a1SHartmut Brandt cmsg.hdr.cmsg_len = sizeof(cmsg); 115370af00a1SHartmut Brandt cmsg.hdr.cmsg_level = SOL_SOCKET; 115470af00a1SHartmut Brandt cmsg.hdr.cmsg_type = SCM_CREDS; 115570af00a1SHartmut Brandt } else { 115670af00a1SHartmut Brandt msg.msg_control = NULL; 11578eecd77aSHartmut Brandt msg.msg_controllen = 0; 115870af00a1SHartmut Brandt } 115970af00a1SHartmut Brandt msg.msg_flags = 0; 116070af00a1SHartmut Brandt 116170af00a1SHartmut Brandt iov[0].iov_base = pi->buf; 116270af00a1SHartmut Brandt iov[0].iov_len = pi->buflen; 116370af00a1SHartmut Brandt 116470af00a1SHartmut Brandt len = recvmsg(pi->fd, &msg, 0); 116570af00a1SHartmut Brandt 116670af00a1SHartmut Brandt if (len == -1 || len == 0) 116770af00a1SHartmut Brandt /* receive error */ 116870af00a1SHartmut Brandt return (-1); 116970af00a1SHartmut Brandt 117070af00a1SHartmut Brandt if (msg.msg_flags & MSG_TRUNC) { 117170af00a1SHartmut Brandt /* truncated - drop */ 117270af00a1SHartmut Brandt snmpd_stats.silentDrops++; 117370af00a1SHartmut Brandt snmpd_stats.inTooLong++; 117470af00a1SHartmut Brandt return (-1); 117570af00a1SHartmut Brandt } 117670af00a1SHartmut Brandt 117770af00a1SHartmut Brandt pi->length = (size_t)len; 117870af00a1SHartmut Brandt 117970af00a1SHartmut Brandt if (pi->cred) 118070af00a1SHartmut Brandt check_priv(pi, &msg); 118170af00a1SHartmut Brandt 118270af00a1SHartmut Brandt return (0); 118370af00a1SHartmut Brandt } 118470af00a1SHartmut Brandt 118570af00a1SHartmut Brandt /* 118670af00a1SHartmut Brandt * Input from a socket 118770af00a1SHartmut Brandt */ 118870af00a1SHartmut Brandt int 118970af00a1SHartmut Brandt snmpd_input(struct port_input *pi, struct tport *tport) 119070af00a1SHartmut Brandt { 1191f06ca4afSHartmut Brandt u_char *sndbuf; 1192f06ca4afSHartmut Brandt size_t sndlen; 119370af00a1SHartmut Brandt struct snmp_pdu pdu; 1194f06ca4afSHartmut Brandt enum snmpd_input_err ierr, ferr; 1195f06ca4afSHartmut Brandt enum snmpd_proxy_err perr; 1196f06ca4afSHartmut Brandt int32_t vi; 119770af00a1SHartmut Brandt int ret; 119870af00a1SHartmut Brandt ssize_t slen; 1199d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1200d7eb6b47SHartmut Brandt char client[16]; 1201d7eb6b47SHartmut Brandt #endif 1202f06ca4afSHartmut Brandt 120370af00a1SHartmut Brandt /* get input depending on the transport */ 120470af00a1SHartmut Brandt if (pi->stream) { 120570af00a1SHartmut Brandt ret = recv_stream(pi); 120670af00a1SHartmut Brandt } else { 120770af00a1SHartmut Brandt ret = recv_dgram(pi); 1208f06ca4afSHartmut Brandt } 120970af00a1SHartmut Brandt 121070af00a1SHartmut Brandt if (ret == -1) 121170af00a1SHartmut Brandt return (-1); 1212f06ca4afSHartmut Brandt 1213d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1214d7eb6b47SHartmut Brandt /* 1215d7eb6b47SHartmut Brandt * In case of AF_INET{6} peer, do hosts_access(5) check. 1216d7eb6b47SHartmut Brandt */ 121781b587f3SRuslan Ermilov if (pi->peer->sa_family != AF_LOCAL && 121881b587f3SRuslan Ermilov inet_ntop(pi->peer->sa_family, 121969292cedSHartmut Brandt &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 122069292cedSHartmut Brandt client, sizeof(client)) != NULL) { 1221d7eb6b47SHartmut Brandt request_set(&req, RQ_CLIENT_ADDR, client, 0); 1222d7eb6b47SHartmut Brandt if (hosts_access(&req) == 0) { 1223d7eb6b47SHartmut Brandt syslog(LOG_ERR, "refused connection from %.500s", 1224d7eb6b47SHartmut Brandt eval_client(&req)); 1225d7eb6b47SHartmut Brandt return (-1); 1226d7eb6b47SHartmut Brandt } 122781b587f3SRuslan Ermilov } else if (pi->peer->sa_family != AF_LOCAL) 1228d7eb6b47SHartmut Brandt syslog(LOG_ERR, "inet_ntop(): %m"); 1229d7eb6b47SHartmut Brandt #endif 1230d7eb6b47SHartmut Brandt 1231f06ca4afSHartmut Brandt /* 1232f06ca4afSHartmut Brandt * Handle input 1233f06ca4afSHartmut Brandt */ 123470af00a1SHartmut Brandt ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 123570af00a1SHartmut Brandt &pi->consumed); 123670af00a1SHartmut Brandt if (ierr == SNMPD_INPUT_TRUNC) { 123770af00a1SHartmut Brandt /* need more bytes. This is ok only for streaming transports. 123870af00a1SHartmut Brandt * but only if we have not reached bufsiz yet. */ 123970af00a1SHartmut Brandt if (pi->stream) { 124070af00a1SHartmut Brandt if (pi->length == buf_size(0)) { 124170af00a1SHartmut Brandt snmpd_stats.silentDrops++; 124270af00a1SHartmut Brandt return (-1); 124370af00a1SHartmut Brandt } 124470af00a1SHartmut Brandt return (0); 124570af00a1SHartmut Brandt } 124670af00a1SHartmut Brandt snmpd_stats.silentDrops++; 124770af00a1SHartmut Brandt return (-1); 124870af00a1SHartmut Brandt } 1249f06ca4afSHartmut Brandt 1250f06ca4afSHartmut Brandt /* can't check for bad SET pdus here, because a proxy may have to 1251f06ca4afSHartmut Brandt * check the access first. We don't want to return an error response 1252f06ca4afSHartmut Brandt * to a proxy PDU with a wrong community */ 1253f06ca4afSHartmut Brandt if (ierr == SNMPD_INPUT_FAILED) { 125470af00a1SHartmut Brandt /* for streaming transports this is fatal */ 125570af00a1SHartmut Brandt if (pi->stream) 125670af00a1SHartmut Brandt return (-1); 125770af00a1SHartmut Brandt snmp_input_consume(pi); 125870af00a1SHartmut Brandt return (0); 1259f06ca4afSHartmut Brandt } 1260896052c1SHartmut Brandt if (ierr == SNMPD_INPUT_BAD_COMM) { 1261896052c1SHartmut Brandt snmp_input_consume(pi); 1262896052c1SHartmut Brandt return (0); 1263896052c1SHartmut Brandt } 1264f06ca4afSHartmut Brandt 1265f06ca4afSHartmut Brandt /* 1266f06ca4afSHartmut Brandt * If that is a module community and the module has a proxy function, 1267f06ca4afSHartmut Brandt * the hand it over to the module. 1268f06ca4afSHartmut Brandt */ 1269135f7de5SShteryana Shopova if (comm != NULL && comm->owner != NULL && 1270135f7de5SShteryana Shopova comm->owner->config->proxy != NULL) { 127170af00a1SHartmut Brandt perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1272896052c1SHartmut Brandt &tport->index, pi->peer, pi->peerlen, ierr, vi, 1273896052c1SHartmut Brandt !pi->cred || pi->priv); 1274f06ca4afSHartmut Brandt 1275f06ca4afSHartmut Brandt switch (perr) { 1276f06ca4afSHartmut Brandt 1277f06ca4afSHartmut Brandt case SNMPD_PROXY_OK: 127870af00a1SHartmut Brandt snmp_input_consume(pi); 127970af00a1SHartmut Brandt return (0); 1280f06ca4afSHartmut Brandt 1281f06ca4afSHartmut Brandt case SNMPD_PROXY_REJ: 1282f06ca4afSHartmut Brandt break; 1283f06ca4afSHartmut Brandt 1284f06ca4afSHartmut Brandt case SNMPD_PROXY_DROP: 128570af00a1SHartmut Brandt snmp_input_consume(pi); 1286f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1287f06ca4afSHartmut Brandt snmpd_stats.proxyDrops++; 128870af00a1SHartmut Brandt return (0); 1289f06ca4afSHartmut Brandt 1290f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMM: 129170af00a1SHartmut Brandt snmp_input_consume(pi); 1292f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1293f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityNames++; 1294f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1295f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1296896052c1SHartmut Brandt (struct snmp_value *)NULL); 129770af00a1SHartmut Brandt return (0); 1298f06ca4afSHartmut Brandt 1299f06ca4afSHartmut Brandt case SNMPD_PROXY_BADCOMMUSE: 130070af00a1SHartmut Brandt snmp_input_consume(pi); 1301f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 1302f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1303f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1304f06ca4afSHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1305896052c1SHartmut Brandt (struct snmp_value *)NULL); 130670af00a1SHartmut Brandt return (0); 1307f06ca4afSHartmut Brandt } 1308f06ca4afSHartmut Brandt } 1309f06ca4afSHartmut Brandt 1310f06ca4afSHartmut Brandt /* 1311f06ca4afSHartmut Brandt * Check type 1312f06ca4afSHartmut Brandt */ 1313f06ca4afSHartmut Brandt if (pdu.type == SNMP_PDU_RESPONSE || 1314f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP || 1315f06ca4afSHartmut Brandt pdu.type == SNMP_PDU_TRAP2) { 1316f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1317f06ca4afSHartmut Brandt snmpd_stats.inBadPduTypes++; 1318f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 131970af00a1SHartmut Brandt snmp_input_consume(pi); 132070af00a1SHartmut Brandt return (0); 1321f06ca4afSHartmut Brandt } 1322f06ca4afSHartmut Brandt 1323f06ca4afSHartmut Brandt /* 1324f06ca4afSHartmut Brandt * Check community 1325f06ca4afSHartmut Brandt */ 1326135f7de5SShteryana Shopova if (pdu.version < SNMP_V3 && 1327135f7de5SShteryana Shopova ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 132870af00a1SHartmut Brandt (community != COMM_WRITE && 1329135f7de5SShteryana Shopova (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1330f06ca4afSHartmut Brandt snmpd_stats.inBadCommunityUses++; 1331f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 133270af00a1SHartmut Brandt snmp_input_consume(pi); 1333f06ca4afSHartmut Brandt if (snmpd.auth_traps) 1334896052c1SHartmut Brandt snmp_send_trap(&oid_authenticationFailure, 1335896052c1SHartmut Brandt (struct snmp_value *)NULL); 133670af00a1SHartmut Brandt return (0); 1337f06ca4afSHartmut Brandt } 1338f06ca4afSHartmut Brandt 1339f06ca4afSHartmut Brandt /* 1340f06ca4afSHartmut Brandt * Execute it. 1341f06ca4afSHartmut Brandt */ 1342f06ca4afSHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) { 1343f06ca4afSHartmut Brandt snmpd_stats.silentDrops++; 1344f06ca4afSHartmut Brandt snmp_pdu_free(&pdu); 134570af00a1SHartmut Brandt snmp_input_consume(pi); 134670af00a1SHartmut Brandt return (0); 1347f06ca4afSHartmut Brandt } 134870af00a1SHartmut Brandt ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 134970af00a1SHartmut Brandt sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1350f06ca4afSHartmut Brandt 1351f06ca4afSHartmut Brandt if (ferr == SNMPD_INPUT_OK) { 135270af00a1SHartmut Brandt slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 135370af00a1SHartmut Brandt if (slen == -1) 135470af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 135570af00a1SHartmut Brandt else if ((size_t)slen != sndlen) 135670af00a1SHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 135770af00a1SHartmut Brandt sndlen, (size_t)slen); 135870af00a1SHartmut Brandt } 135970af00a1SHartmut Brandt snmp_pdu_free(&pdu); 136070af00a1SHartmut Brandt free(sndbuf); 136170af00a1SHartmut Brandt snmp_input_consume(pi); 136270af00a1SHartmut Brandt 136370af00a1SHartmut Brandt return (0); 136470af00a1SHartmut Brandt } 136570af00a1SHartmut Brandt 136670af00a1SHartmut Brandt /* 136770af00a1SHartmut Brandt * Send a PDU to a given port 136870af00a1SHartmut Brandt */ 136970af00a1SHartmut Brandt void 137070af00a1SHartmut Brandt snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 137170af00a1SHartmut Brandt const struct sockaddr *addr, socklen_t addrlen) 137270af00a1SHartmut Brandt { 137370af00a1SHartmut Brandt struct transport *trans = targ; 137470af00a1SHartmut Brandt struct tport *tp; 137570af00a1SHartmut Brandt u_char *sndbuf; 137670af00a1SHartmut Brandt size_t sndlen; 137770af00a1SHartmut Brandt ssize_t len; 137870af00a1SHartmut Brandt 137970af00a1SHartmut Brandt TAILQ_FOREACH(tp, &trans->table, link) 138070af00a1SHartmut Brandt if (asn_compare_oid(port, &tp->index) == 0) 138170af00a1SHartmut Brandt break; 138270af00a1SHartmut Brandt if (tp == 0) 138370af00a1SHartmut Brandt return; 138470af00a1SHartmut Brandt 138570af00a1SHartmut Brandt if ((sndbuf = buf_alloc(1)) == NULL) 138670af00a1SHartmut Brandt return; 138770af00a1SHartmut Brandt 138870af00a1SHartmut Brandt snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 138970af00a1SHartmut Brandt 139070af00a1SHartmut Brandt len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 139170af00a1SHartmut Brandt 139270af00a1SHartmut Brandt if (len == -1) 1393f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: %m"); 1394f06ca4afSHartmut Brandt else if ((size_t)len != sndlen) 1395f06ca4afSHartmut Brandt syslog(LOG_ERR, "sendto: short write %zu/%zu", 1396f06ca4afSHartmut Brandt sndlen, (size_t)len); 139770af00a1SHartmut Brandt 1398f06ca4afSHartmut Brandt free(sndbuf); 1399f06ca4afSHartmut Brandt } 1400f06ca4afSHartmut Brandt 1401f06ca4afSHartmut Brandt 1402f06ca4afSHartmut Brandt /* 140370af00a1SHartmut Brandt * Close an input source 1404f06ca4afSHartmut Brandt */ 1405f06ca4afSHartmut Brandt void 140670af00a1SHartmut Brandt snmpd_input_close(struct port_input *pi) 1407f06ca4afSHartmut Brandt { 140870af00a1SHartmut Brandt if (pi->id != NULL) 140970af00a1SHartmut Brandt fd_deselect(pi->id); 141070af00a1SHartmut Brandt if (pi->fd >= 0) 141170af00a1SHartmut Brandt (void)close(pi->fd); 141270af00a1SHartmut Brandt if (pi->buf != NULL) 141370af00a1SHartmut Brandt free(pi->buf); 1414f06ca4afSHartmut Brandt } 1415f06ca4afSHartmut Brandt 1416f06ca4afSHartmut Brandt /* 1417f06ca4afSHartmut Brandt * Dump internal state. 1418f06ca4afSHartmut Brandt */ 141970af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 142070af00a1SHartmut Brandt static void 142170af00a1SHartmut Brandt info_func(void) 142270af00a1SHartmut Brandt #else 1423f06ca4afSHartmut Brandt static void 1424f06ca4afSHartmut Brandt info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 142570af00a1SHartmut Brandt #endif 1426f06ca4afSHartmut Brandt { 1427f06ca4afSHartmut Brandt struct lmodule *m; 1428f06ca4afSHartmut Brandt u_int i; 1429f06ca4afSHartmut Brandt char buf[10000]; 1430f06ca4afSHartmut Brandt 1431f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1432f06ca4afSHartmut Brandt for (i = 0; i < tree_size; i++) { 1433f06ca4afSHartmut Brandt switch (tree[i].type) { 1434f06ca4afSHartmut Brandt 1435f06ca4afSHartmut Brandt case SNMP_NODE_LEAF: 1436f06ca4afSHartmut Brandt sprintf(buf, "LEAF: %s %s", tree[i].name, 1437f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1438f06ca4afSHartmut Brandt break; 1439f06ca4afSHartmut Brandt 1440f06ca4afSHartmut Brandt case SNMP_NODE_COLUMN: 1441f06ca4afSHartmut Brandt sprintf(buf, "COL: %s %s", tree[i].name, 1442f06ca4afSHartmut Brandt asn_oid2str(&tree[i].oid)); 1443f06ca4afSHartmut Brandt break; 1444f06ca4afSHartmut Brandt } 1445f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", buf); 1446f06ca4afSHartmut Brandt } 1447f06ca4afSHartmut Brandt 1448f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1449f06ca4afSHartmut Brandt if (m->config->dump) 1450f06ca4afSHartmut Brandt (*m->config->dump)(); 1451f06ca4afSHartmut Brandt } 1452f06ca4afSHartmut Brandt 1453f06ca4afSHartmut Brandt /* 1454f06ca4afSHartmut Brandt * Re-read configuration 1455f06ca4afSHartmut Brandt */ 145670af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 145770af00a1SHartmut Brandt static void 145870af00a1SHartmut Brandt config_func(void) 145970af00a1SHartmut Brandt #else 1460f06ca4afSHartmut Brandt static void 1461f06ca4afSHartmut Brandt config_func(evContext ctx __unused, void *uap __unused, 1462f06ca4afSHartmut Brandt const void *tag __unused) 146370af00a1SHartmut Brandt #endif 1464f06ca4afSHartmut Brandt { 1465f06ca4afSHartmut Brandt struct lmodule *m; 1466f06ca4afSHartmut Brandt 1467f06ca4afSHartmut Brandt if (read_config(config_file, NULL)) { 1468f06ca4afSHartmut Brandt syslog(LOG_ERR, "error reading config file '%s'", config_file); 1469f06ca4afSHartmut Brandt return; 1470f06ca4afSHartmut Brandt } 1471f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 1472f06ca4afSHartmut Brandt if (m->config->config) 1473f06ca4afSHartmut Brandt (*m->config->config)(); 1474f06ca4afSHartmut Brandt } 1475f06ca4afSHartmut Brandt 1476f06ca4afSHartmut Brandt /* 1477f06ca4afSHartmut Brandt * On USR1 dump actual configuration. 1478f06ca4afSHartmut Brandt */ 1479f06ca4afSHartmut Brandt static void 1480f06ca4afSHartmut Brandt onusr1(int s __unused) 1481f06ca4afSHartmut Brandt { 148270af00a1SHartmut Brandt 1483f06ca4afSHartmut Brandt work |= WORK_DOINFO; 1484f06ca4afSHartmut Brandt } 1485f06ca4afSHartmut Brandt static void 1486f06ca4afSHartmut Brandt onhup(int s __unused) 1487f06ca4afSHartmut Brandt { 148870af00a1SHartmut Brandt 1489f06ca4afSHartmut Brandt work |= WORK_RECONFIG; 1490f06ca4afSHartmut Brandt } 1491f06ca4afSHartmut Brandt 1492f06ca4afSHartmut Brandt static void 1493f06ca4afSHartmut Brandt onterm(int s __unused) 1494f06ca4afSHartmut Brandt { 1495f06ca4afSHartmut Brandt 149670af00a1SHartmut Brandt /* allow clean-up */ 1497f06ca4afSHartmut Brandt exit(0); 1498f06ca4afSHartmut Brandt } 1499f06ca4afSHartmut Brandt 1500f06ca4afSHartmut Brandt static void 1501f06ca4afSHartmut Brandt init_sigs(void) 1502f06ca4afSHartmut Brandt { 1503f06ca4afSHartmut Brandt struct sigaction sa; 1504f06ca4afSHartmut Brandt 1505f06ca4afSHartmut Brandt sa.sa_handler = onusr1; 1506f06ca4afSHartmut Brandt sa.sa_flags = SA_RESTART; 1507f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1508f06ca4afSHartmut Brandt if (sigaction(SIGUSR1, &sa, NULL)) { 1509f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1510f06ca4afSHartmut Brandt exit(1); 1511f06ca4afSHartmut Brandt } 1512f06ca4afSHartmut Brandt 1513f06ca4afSHartmut Brandt sa.sa_handler = onhup; 1514f06ca4afSHartmut Brandt if (sigaction(SIGHUP, &sa, NULL)) { 1515f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1516f06ca4afSHartmut Brandt exit(1); 1517f06ca4afSHartmut Brandt } 1518f06ca4afSHartmut Brandt 1519f06ca4afSHartmut Brandt sa.sa_handler = onterm; 1520f06ca4afSHartmut Brandt sa.sa_flags = 0; 1521f06ca4afSHartmut Brandt sigemptyset(&sa.sa_mask); 1522f06ca4afSHartmut Brandt if (sigaction(SIGTERM, &sa, NULL)) { 1523f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1524f06ca4afSHartmut Brandt exit(1); 1525f06ca4afSHartmut Brandt } 1526f06ca4afSHartmut Brandt if (sigaction(SIGINT, &sa, NULL)) { 1527f06ca4afSHartmut Brandt syslog(LOG_ERR, "sigaction: %m"); 1528f06ca4afSHartmut Brandt exit(1); 1529f06ca4afSHartmut Brandt } 1530f06ca4afSHartmut Brandt } 1531f06ca4afSHartmut Brandt 1532f06ca4afSHartmut Brandt static void 1533f06ca4afSHartmut Brandt block_sigs(void) 1534f06ca4afSHartmut Brandt { 1535f06ca4afSHartmut Brandt sigset_t set; 1536f06ca4afSHartmut Brandt 1537f06ca4afSHartmut Brandt sigfillset(&set); 1538f06ca4afSHartmut Brandt if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1539f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_BLOCK: %m"); 1540f06ca4afSHartmut Brandt exit(1); 1541f06ca4afSHartmut Brandt } 1542f06ca4afSHartmut Brandt } 1543f06ca4afSHartmut Brandt static void 1544f06ca4afSHartmut Brandt unblock_sigs(void) 1545f06ca4afSHartmut Brandt { 1546f06ca4afSHartmut Brandt if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1547f06ca4afSHartmut Brandt syslog(LOG_ERR, "SIG_SETMASK: %m"); 1548f06ca4afSHartmut Brandt exit(1); 1549f06ca4afSHartmut Brandt } 1550f06ca4afSHartmut Brandt } 1551f06ca4afSHartmut Brandt 1552f06ca4afSHartmut Brandt /* 1553f06ca4afSHartmut Brandt * Shut down 1554f06ca4afSHartmut Brandt */ 1555f06ca4afSHartmut Brandt static void 1556f06ca4afSHartmut Brandt term(void) 1557f06ca4afSHartmut Brandt { 1558f06ca4afSHartmut Brandt (void)unlink(pid_file); 1559f06ca4afSHartmut Brandt } 1560f06ca4afSHartmut Brandt 156170af00a1SHartmut Brandt static void 156270af00a1SHartmut Brandt trans_stop(void) 156370af00a1SHartmut Brandt { 156470af00a1SHartmut Brandt struct transport *t; 156570af00a1SHartmut Brandt 156670af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 156770af00a1SHartmut Brandt (void)t->vtab->stop(1); 156870af00a1SHartmut Brandt } 156970af00a1SHartmut Brandt 1570f06ca4afSHartmut Brandt /* 1571f06ca4afSHartmut Brandt * Define a macro from the command line 1572f06ca4afSHartmut Brandt */ 1573f06ca4afSHartmut Brandt static void 1574f06ca4afSHartmut Brandt do_macro(char *arg) 1575f06ca4afSHartmut Brandt { 1576f06ca4afSHartmut Brandt char *eq; 1577f06ca4afSHartmut Brandt int err; 1578f06ca4afSHartmut Brandt 1579f06ca4afSHartmut Brandt if ((eq = strchr(arg, '=')) == NULL) 1580f06ca4afSHartmut Brandt err = define_macro(arg, ""); 1581f06ca4afSHartmut Brandt else { 1582f06ca4afSHartmut Brandt *eq++ = '\0'; 1583f06ca4afSHartmut Brandt err = define_macro(arg, eq); 1584f06ca4afSHartmut Brandt } 1585f06ca4afSHartmut Brandt if (err == -1) { 1586f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot save macro: %m"); 1587f06ca4afSHartmut Brandt exit(1); 1588f06ca4afSHartmut Brandt } 1589f06ca4afSHartmut Brandt } 1590f06ca4afSHartmut Brandt 1591f06ca4afSHartmut Brandt /* 1592f06ca4afSHartmut Brandt * Re-implement getsubopt from scratch, because the second argument is broken 1593f06ca4afSHartmut Brandt * and will not compile with WARNS=5. 1594f06ca4afSHartmut Brandt */ 1595f06ca4afSHartmut Brandt static int 1596f06ca4afSHartmut Brandt getsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1597f06ca4afSHartmut Brandt { 1598f06ca4afSHartmut Brandt static const char *const delim = ",\t "; 1599f06ca4afSHartmut Brandt u_int i; 1600f06ca4afSHartmut Brandt char *ptr; 1601f06ca4afSHartmut Brandt 1602f06ca4afSHartmut Brandt *optp = NULL; 1603f06ca4afSHartmut Brandt 1604f06ca4afSHartmut Brandt /* skip leading junk */ 1605f06ca4afSHartmut Brandt for (ptr = *arg; *ptr != '\0'; ptr++) 1606f06ca4afSHartmut Brandt if (strchr(delim, *ptr) == NULL) 1607f06ca4afSHartmut Brandt break; 1608f06ca4afSHartmut Brandt if (*ptr == '\0') { 1609f06ca4afSHartmut Brandt *arg = ptr; 1610f06ca4afSHartmut Brandt return (-1); 1611f06ca4afSHartmut Brandt } 1612f06ca4afSHartmut Brandt *optp = ptr; 1613f06ca4afSHartmut Brandt 1614f06ca4afSHartmut Brandt /* find the end of the option */ 1615f06ca4afSHartmut Brandt while (*++ptr != '\0') 1616f06ca4afSHartmut Brandt if (strchr(delim, *ptr) != NULL || *ptr == '=') 1617f06ca4afSHartmut Brandt break; 1618f06ca4afSHartmut Brandt 1619f06ca4afSHartmut Brandt if (*ptr != '\0') { 1620f06ca4afSHartmut Brandt if (*ptr == '=') { 1621f06ca4afSHartmut Brandt *ptr++ = '\0'; 1622f06ca4afSHartmut Brandt *valp = ptr; 1623f06ca4afSHartmut Brandt while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1624f06ca4afSHartmut Brandt ptr++; 1625f06ca4afSHartmut Brandt if (*ptr != '\0') 1626f06ca4afSHartmut Brandt *ptr++ = '\0'; 1627f06ca4afSHartmut Brandt } else 1628f06ca4afSHartmut Brandt *ptr++ = '\0'; 1629f06ca4afSHartmut Brandt } 1630f06ca4afSHartmut Brandt 1631f06ca4afSHartmut Brandt *arg = ptr; 1632f06ca4afSHartmut Brandt 1633f06ca4afSHartmut Brandt for (i = 0; *options != NULL; options++, i++) 163470af00a1SHartmut Brandt if (strcmp(*optp, *options) == 0) 1635f06ca4afSHartmut Brandt return (i); 1636f06ca4afSHartmut Brandt return (-1); 1637f06ca4afSHartmut Brandt } 1638f06ca4afSHartmut Brandt 1639f06ca4afSHartmut Brandt int 1640f06ca4afSHartmut Brandt main(int argc, char *argv[]) 1641f06ca4afSHartmut Brandt { 1642f06ca4afSHartmut Brandt int opt; 1643f06ca4afSHartmut Brandt FILE *fp; 1644f06ca4afSHartmut Brandt int background = 1; 164570af00a1SHartmut Brandt struct tport *p; 1646f06ca4afSHartmut Brandt const char *prefix = "snmpd"; 1647f06ca4afSHartmut Brandt struct lmodule *m; 1648135f7de5SShteryana Shopova char *value = NULL, *option; /* XXX */ 164970af00a1SHartmut Brandt struct transport *t; 1650f06ca4afSHartmut Brandt 1651f06ca4afSHartmut Brandt #define DBG_DUMP 0 1652f06ca4afSHartmut Brandt #define DBG_EVENTS 1 1653f06ca4afSHartmut Brandt #define DBG_TRACE 2 1654f06ca4afSHartmut Brandt static const char *const debug_opts[] = { 1655f06ca4afSHartmut Brandt "dump", 1656f06ca4afSHartmut Brandt "events", 1657f06ca4afSHartmut Brandt "trace", 1658f06ca4afSHartmut Brandt NULL 1659f06ca4afSHartmut Brandt }; 1660f06ca4afSHartmut Brandt 1661f06ca4afSHartmut Brandt snmp_printf = snmp_printf_func; 1662f06ca4afSHartmut Brandt snmp_error = snmp_error_func; 1663f06ca4afSHartmut Brandt snmp_debug = snmp_debug_func; 1664f06ca4afSHartmut Brandt asn_error = asn_error_func; 1665f06ca4afSHartmut Brandt 1666135f7de5SShteryana Shopova while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1667f06ca4afSHartmut Brandt switch (opt) { 1668f06ca4afSHartmut Brandt 1669f06ca4afSHartmut Brandt case 'c': 1670f06ca4afSHartmut Brandt strlcpy(config_file, optarg, sizeof(config_file)); 1671f06ca4afSHartmut Brandt break; 1672f06ca4afSHartmut Brandt 1673f06ca4afSHartmut Brandt case 'd': 1674f06ca4afSHartmut Brandt background = 0; 1675f06ca4afSHartmut Brandt break; 1676f06ca4afSHartmut Brandt 1677f06ca4afSHartmut Brandt case 'D': 1678f06ca4afSHartmut Brandt while (*optarg) { 1679f06ca4afSHartmut Brandt switch (getsubopt1(&optarg, debug_opts, 1680f06ca4afSHartmut Brandt &value, &option)) { 1681f06ca4afSHartmut Brandt 1682f06ca4afSHartmut Brandt case DBG_DUMP: 1683f06ca4afSHartmut Brandt debug.dump_pdus = 1; 1684f06ca4afSHartmut Brandt break; 1685f06ca4afSHartmut Brandt 1686f06ca4afSHartmut Brandt case DBG_EVENTS: 1687f06ca4afSHartmut Brandt debug.evdebug++; 1688f06ca4afSHartmut Brandt break; 1689f06ca4afSHartmut Brandt 1690f06ca4afSHartmut Brandt case DBG_TRACE: 1691f06ca4afSHartmut Brandt if (value == NULL) 1692f06ca4afSHartmut Brandt syslog(LOG_ERR, 1693f06ca4afSHartmut Brandt "no value for 'trace'"); 169451054003SHartmut Brandt else 1695748b5b1eSHartmut Brandt snmp_trace = strtoul(value, 1696748b5b1eSHartmut Brandt NULL, 0); 1697f06ca4afSHartmut Brandt break; 1698f06ca4afSHartmut Brandt 1699f06ca4afSHartmut Brandt case -1: 1700f06ca4afSHartmut Brandt if (suboptarg) 1701f06ca4afSHartmut Brandt syslog(LOG_ERR, 1702f06ca4afSHartmut Brandt "unknown debug flag '%s'", 1703f06ca4afSHartmut Brandt option); 1704f06ca4afSHartmut Brandt else 1705f06ca4afSHartmut Brandt syslog(LOG_ERR, 1706f06ca4afSHartmut Brandt "missing debug flag"); 1707f06ca4afSHartmut Brandt break; 1708f06ca4afSHartmut Brandt } 1709f06ca4afSHartmut Brandt } 1710f06ca4afSHartmut Brandt break; 1711f06ca4afSHartmut Brandt 1712135f7de5SShteryana Shopova case 'e': 1713135f7de5SShteryana Shopova strlcpy(engine_file, optarg, sizeof(engine_file)); 1714135f7de5SShteryana Shopova break; 1715f06ca4afSHartmut Brandt case 'h': 1716f06ca4afSHartmut Brandt fprintf(stderr, "%s", usgtxt); 1717f06ca4afSHartmut Brandt exit(0); 1718f06ca4afSHartmut Brandt 1719f06ca4afSHartmut Brandt case 'I': 1720f06ca4afSHartmut Brandt syspath = optarg; 1721f06ca4afSHartmut Brandt break; 1722f06ca4afSHartmut Brandt 1723f06ca4afSHartmut Brandt case 'l': 1724f06ca4afSHartmut Brandt prefix = optarg; 1725f06ca4afSHartmut Brandt break; 1726f06ca4afSHartmut Brandt 1727f06ca4afSHartmut Brandt case 'm': 1728f06ca4afSHartmut Brandt do_macro(optarg); 1729f06ca4afSHartmut Brandt break; 1730f06ca4afSHartmut Brandt 1731f06ca4afSHartmut Brandt case 'p': 1732f06ca4afSHartmut Brandt strlcpy(pid_file, optarg, sizeof(pid_file)); 1733f06ca4afSHartmut Brandt break; 1734f06ca4afSHartmut Brandt } 1735f06ca4afSHartmut Brandt 1736f06ca4afSHartmut Brandt openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1737f06ca4afSHartmut Brandt setlogmask(LOG_UPTO(debug.logpri - 1)); 1738f06ca4afSHartmut Brandt 1739f06ca4afSHartmut Brandt if (background && daemon(0, 0) < 0) { 1740f06ca4afSHartmut Brandt syslog(LOG_ERR, "daemon: %m"); 1741f06ca4afSHartmut Brandt exit(1); 1742f06ca4afSHartmut Brandt } 1743f06ca4afSHartmut Brandt 1744f06ca4afSHartmut Brandt argc -= optind; 1745f06ca4afSHartmut Brandt argv += optind; 1746f06ca4afSHartmut Brandt 1747f06ca4afSHartmut Brandt progargs = argv; 1748f06ca4afSHartmut Brandt nprogargs = argc; 1749f06ca4afSHartmut Brandt 1750f06ca4afSHartmut Brandt srandomdev(); 1751f06ca4afSHartmut Brandt 1752f06ca4afSHartmut Brandt snmp_serial_no = random(); 1753f06ca4afSHartmut Brandt 1754d7eb6b47SHartmut Brandt #ifdef USE_TCPWRAPPERS 1755d7eb6b47SHartmut Brandt /* 1756d7eb6b47SHartmut Brandt * Initialize hosts_access(3) handler. 1757d7eb6b47SHartmut Brandt */ 1758d7eb6b47SHartmut Brandt request_init(&req, RQ_DAEMON, "snmpd", 0); 1759d7eb6b47SHartmut Brandt sock_methods(&req); 1760d7eb6b47SHartmut Brandt #endif 1761d7eb6b47SHartmut Brandt 1762f06ca4afSHartmut Brandt /* 1763f06ca4afSHartmut Brandt * Initialize the tree. 1764f06ca4afSHartmut Brandt */ 1765f06ca4afSHartmut Brandt if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1766f06ca4afSHartmut Brandt syslog(LOG_ERR, "%m"); 1767f06ca4afSHartmut Brandt exit(1); 1768f06ca4afSHartmut Brandt } 1769f06ca4afSHartmut Brandt memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1770f06ca4afSHartmut Brandt tree_size = CTREE_SIZE; 1771f06ca4afSHartmut Brandt 1772f06ca4afSHartmut Brandt /* 1773f06ca4afSHartmut Brandt * Get standard communities 1774f06ca4afSHartmut Brandt */ 1775d4199d75SHartmut Brandt (void)comm_define(1, "SNMP read", NULL, NULL); 1776d4199d75SHartmut Brandt (void)comm_define(2, "SNMP write", NULL, NULL); 1777f06ca4afSHartmut Brandt community = COMM_INITIALIZE; 1778f06ca4afSHartmut Brandt 1779f06ca4afSHartmut Brandt trap_reqid = reqid_allocate(512, NULL); 1780f06ca4afSHartmut Brandt 1781f06ca4afSHartmut Brandt if (config_file[0] == '\0') 1782f06ca4afSHartmut Brandt snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1783f06ca4afSHartmut Brandt 1784f06ca4afSHartmut Brandt init_actvals(); 1785135f7de5SShteryana Shopova init_snmpd_engine(); 178670af00a1SHartmut Brandt 178770af00a1SHartmut Brandt this_tick = get_ticks(); 178869292cedSHartmut Brandt start_tick = this_tick; 178970af00a1SHartmut Brandt 179070af00a1SHartmut Brandt /* start transports */ 179170af00a1SHartmut Brandt if (atexit(trans_stop) == -1) { 179270af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 179370af00a1SHartmut Brandt exit(1); 179470af00a1SHartmut Brandt } 179570af00a1SHartmut Brandt if (udp_trans.start() != SNMP_ERR_NOERROR) 179670af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start UDP transport"); 179770af00a1SHartmut Brandt if (lsock_trans.start() != SNMP_ERR_NOERROR) 179870af00a1SHartmut Brandt syslog(LOG_WARNING, "cannot start LSOCK transport"); 179970af00a1SHartmut Brandt 180070af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 180170af00a1SHartmut Brandt if (debug.evdebug > 0) 180270af00a1SHartmut Brandt rpoll_trace = 1; 180370af00a1SHartmut Brandt #else 1804f06ca4afSHartmut Brandt if (evCreate(&evctx)) { 1805f06ca4afSHartmut Brandt syslog(LOG_ERR, "evCreate: %m"); 1806f06ca4afSHartmut Brandt exit(1); 1807f06ca4afSHartmut Brandt } 1808f06ca4afSHartmut Brandt if (debug.evdebug > 0) 1809f06ca4afSHartmut Brandt evSetDebug(evctx, 10, stderr); 181070af00a1SHartmut Brandt #endif 1811f06ca4afSHartmut Brandt 1812135f7de5SShteryana Shopova if (engine_file[0] == '\0') 1813135f7de5SShteryana Shopova snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1814135f7de5SShteryana Shopova 1815896052c1SHartmut Brandt if (read_config(config_file, NULL)) { 1816896052c1SHartmut Brandt syslog(LOG_ERR, "error in config file"); 1817896052c1SHartmut Brandt exit(1); 1818896052c1SHartmut Brandt } 1819896052c1SHartmut Brandt 182070af00a1SHartmut Brandt TAILQ_FOREACH(t, &transport_list, link) 182170af00a1SHartmut Brandt TAILQ_FOREACH(p, &t->table, link) 182270af00a1SHartmut Brandt t->vtab->init_port(p); 1823f06ca4afSHartmut Brandt 1824f06ca4afSHartmut Brandt init_sigs(); 1825f06ca4afSHartmut Brandt 1826f06ca4afSHartmut Brandt if (pid_file[0] == '\0') 1827f06ca4afSHartmut Brandt snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1828f06ca4afSHartmut Brandt 1829f06ca4afSHartmut Brandt if ((fp = fopen(pid_file, "w")) != NULL) { 1830f06ca4afSHartmut Brandt fprintf(fp, "%u", getpid()); 1831f06ca4afSHartmut Brandt fclose(fp); 183270af00a1SHartmut Brandt if (atexit(term) == -1) { 183370af00a1SHartmut Brandt syslog(LOG_ERR, "atexit failed: %m"); 183470af00a1SHartmut Brandt (void)remove(pid_file); 183570af00a1SHartmut Brandt exit(0); 1836f06ca4afSHartmut Brandt } 183770af00a1SHartmut Brandt } 1838f06ca4afSHartmut Brandt 1839f06ca4afSHartmut Brandt if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1840f06ca4afSHartmut Brandt NULL) == 0) { 1841f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1842f06ca4afSHartmut Brandt exit(1); 1843f06ca4afSHartmut Brandt } 1844f06ca4afSHartmut Brandt if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1845f06ca4afSHartmut Brandt NULL) == 0) { 1846f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1847f06ca4afSHartmut Brandt exit(1); 1848f06ca4afSHartmut Brandt } 1849f06ca4afSHartmut Brandt 1850f06ca4afSHartmut Brandt while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1851f06ca4afSHartmut Brandt m->flags &= ~LM_ONSTARTLIST; 1852f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 1853f06ca4afSHartmut Brandt lm_start(m); 1854f06ca4afSHartmut Brandt } 1855f06ca4afSHartmut Brandt 185672cd7a52SShteryana Shopova snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 185772cd7a52SShteryana Shopova 1858f06ca4afSHartmut Brandt for (;;) { 185970af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1860f06ca4afSHartmut Brandt evEvent event; 186170af00a1SHartmut Brandt #endif 1862f06ca4afSHartmut Brandt struct lmodule *mod; 1863f06ca4afSHartmut Brandt 1864f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 1865f06ca4afSHartmut Brandt if (mod->config->idle != NULL) 1866f06ca4afSHartmut Brandt (*mod->config->idle)(); 1867f06ca4afSHartmut Brandt 186870af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1869f06ca4afSHartmut Brandt if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1870f06ca4afSHartmut Brandt if (evDispatch(evctx, event)) 1871f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDispatch: %m"); 1872f06ca4afSHartmut Brandt } else if (errno != EINTR) { 1873f06ca4afSHartmut Brandt syslog(LOG_ERR, "evGetNext: %m"); 1874f06ca4afSHartmut Brandt exit(1); 1875f06ca4afSHartmut Brandt } 187670af00a1SHartmut Brandt #else 187770af00a1SHartmut Brandt poll_dispatch(1); 187870af00a1SHartmut Brandt #endif 1879f06ca4afSHartmut Brandt 1880f06ca4afSHartmut Brandt if (work != 0) { 1881f06ca4afSHartmut Brandt block_sigs(); 1882f06ca4afSHartmut Brandt if (work & WORK_DOINFO) { 188370af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 188470af00a1SHartmut Brandt info_func(); 188570af00a1SHartmut Brandt #else 1886f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, info_func, 1887f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1888f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1889f06ca4afSHartmut Brandt exit(1); 1890f06ca4afSHartmut Brandt } 189170af00a1SHartmut Brandt #endif 1892f06ca4afSHartmut Brandt } 1893f06ca4afSHartmut Brandt if (work & WORK_RECONFIG) { 189470af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 189570af00a1SHartmut Brandt config_func(); 189670af00a1SHartmut Brandt #else 1897f06ca4afSHartmut Brandt if (evWaitFor(evctx, &work, config_func, 1898f06ca4afSHartmut Brandt NULL, NULL) == -1) { 1899f06ca4afSHartmut Brandt syslog(LOG_ERR, "evWaitFor: %m"); 1900f06ca4afSHartmut Brandt exit(1); 1901f06ca4afSHartmut Brandt } 190270af00a1SHartmut Brandt #endif 1903f06ca4afSHartmut Brandt } 1904f06ca4afSHartmut Brandt work = 0; 1905f06ca4afSHartmut Brandt unblock_sigs(); 190670af00a1SHartmut Brandt #ifndef USE_LIBBEGEMOT 1907f06ca4afSHartmut Brandt if (evDo(evctx, &work) == -1) { 1908f06ca4afSHartmut Brandt syslog(LOG_ERR, "evDo: %m"); 1909f06ca4afSHartmut Brandt exit(1); 1910f06ca4afSHartmut Brandt } 191170af00a1SHartmut Brandt #endif 1912f06ca4afSHartmut Brandt } 1913f06ca4afSHartmut Brandt } 1914f06ca4afSHartmut Brandt 1915f06ca4afSHartmut Brandt return (0); 1916f06ca4afSHartmut Brandt } 1917f06ca4afSHartmut Brandt 191869292cedSHartmut Brandt uint64_t 1919135f7de5SShteryana Shopova get_ticks(void) 1920f06ca4afSHartmut Brandt { 1921f06ca4afSHartmut Brandt struct timeval tv; 192269292cedSHartmut Brandt uint64_t ret; 1923f06ca4afSHartmut Brandt 1924f06ca4afSHartmut Brandt if (gettimeofday(&tv, NULL)) 1925f06ca4afSHartmut Brandt abort(); 192669292cedSHartmut Brandt ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1927f06ca4afSHartmut Brandt return (ret); 1928f06ca4afSHartmut Brandt } 192969292cedSHartmut Brandt 1930f06ca4afSHartmut Brandt /* 1931f06ca4afSHartmut Brandt * Timer support 1932f06ca4afSHartmut Brandt */ 1933165c5d31SHartmut Brandt 1934165c5d31SHartmut Brandt /* 1935165c5d31SHartmut Brandt * Trampoline for the non-repeatable timers. 1936165c5d31SHartmut Brandt */ 193770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 193870af00a1SHartmut Brandt static void 193970af00a1SHartmut Brandt tfunc(int tid __unused, void *uap) 194070af00a1SHartmut Brandt #else 1941f06ca4afSHartmut Brandt static void 1942f06ca4afSHartmut Brandt tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1943f06ca4afSHartmut Brandt struct timespec inter __unused) 194470af00a1SHartmut Brandt #endif 1945f06ca4afSHartmut Brandt { 1946f06ca4afSHartmut Brandt struct timer *tp = uap; 1947f06ca4afSHartmut Brandt 1948f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 1949f06ca4afSHartmut Brandt tp->func(tp->udata); 1950f06ca4afSHartmut Brandt free(tp); 1951f06ca4afSHartmut Brandt } 1952f06ca4afSHartmut Brandt 1953f06ca4afSHartmut Brandt /* 1954165c5d31SHartmut Brandt * Trampoline for the repeatable timers. 1955165c5d31SHartmut Brandt */ 1956165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 1957165c5d31SHartmut Brandt static void 1958165c5d31SHartmut Brandt trfunc(int tid __unused, void *uap) 1959165c5d31SHartmut Brandt #else 1960165c5d31SHartmut Brandt static void 1961165c5d31SHartmut Brandt trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1962165c5d31SHartmut Brandt struct timespec inter __unused) 1963165c5d31SHartmut Brandt #endif 1964165c5d31SHartmut Brandt { 1965165c5d31SHartmut Brandt struct timer *tp = uap; 1966165c5d31SHartmut Brandt 1967165c5d31SHartmut Brandt tp->func(tp->udata); 1968165c5d31SHartmut Brandt } 1969165c5d31SHartmut Brandt 1970165c5d31SHartmut Brandt /* 1971165c5d31SHartmut Brandt * Start a one-shot timer 1972f06ca4afSHartmut Brandt */ 1973f06ca4afSHartmut Brandt void * 1974f06ca4afSHartmut Brandt timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1975f06ca4afSHartmut Brandt { 1976f06ca4afSHartmut Brandt struct timer *tp; 1977a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1978f06ca4afSHartmut Brandt struct timespec due; 197970af00a1SHartmut Brandt #endif 1980f06ca4afSHartmut Brandt 1981f06ca4afSHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 1982f06ca4afSHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 1983f06ca4afSHartmut Brandt exit(1); 1984f06ca4afSHartmut Brandt } 1985a9bfedb7SHartmut Brandt 1986a9bfedb7SHartmut Brandt #ifndef USE_LIBBEGEMOT 1987f06ca4afSHartmut Brandt due = evAddTime(evNowTime(), 1988f06ca4afSHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 198970af00a1SHartmut Brandt #endif 1990f06ca4afSHartmut Brandt 1991f06ca4afSHartmut Brandt tp->udata = udata; 1992f06ca4afSHartmut Brandt tp->owner = mod; 1993f06ca4afSHartmut Brandt tp->func = func; 1994f06ca4afSHartmut Brandt 1995f06ca4afSHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 1996f06ca4afSHartmut Brandt 199770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 1998a9bfedb7SHartmut Brandt if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 199970af00a1SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 200070af00a1SHartmut Brandt exit(1); 200170af00a1SHartmut Brandt } 200270af00a1SHartmut Brandt #else 2003f06ca4afSHartmut Brandt if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 2004f06ca4afSHartmut Brandt == -1) { 2005f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2006f06ca4afSHartmut Brandt exit(1); 2007f06ca4afSHartmut Brandt } 200870af00a1SHartmut Brandt #endif 2009f06ca4afSHartmut Brandt return (tp); 2010f06ca4afSHartmut Brandt } 2011f06ca4afSHartmut Brandt 2012165c5d31SHartmut Brandt /* 2013165c5d31SHartmut Brandt * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 2014165c5d31SHartmut Brandt * is currently ignored and the initial number of ticks is set to the 2015165c5d31SHartmut Brandt * repeat number of ticks. 2016165c5d31SHartmut Brandt */ 2017165c5d31SHartmut Brandt void * 2018165c5d31SHartmut Brandt timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 2019165c5d31SHartmut Brandt void (*func)(void *), void *udata, struct lmodule *mod) 2020165c5d31SHartmut Brandt { 2021165c5d31SHartmut Brandt struct timer *tp; 2022165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 2023165c5d31SHartmut Brandt struct timespec due; 2024165c5d31SHartmut Brandt struct timespec inter; 2025165c5d31SHartmut Brandt #endif 2026165c5d31SHartmut Brandt 2027165c5d31SHartmut Brandt if ((tp = malloc(sizeof(struct timer))) == NULL) { 2028165c5d31SHartmut Brandt syslog(LOG_CRIT, "out of memory for timer"); 2029165c5d31SHartmut Brandt exit(1); 2030165c5d31SHartmut Brandt } 2031165c5d31SHartmut Brandt 2032165c5d31SHartmut Brandt #ifndef USE_LIBBEGEMOT 2033165c5d31SHartmut Brandt due = evAddTime(evNowTime(), 2034165c5d31SHartmut Brandt evConsTime(ticks / 100, (ticks % 100) * 10000)); 2035165c5d31SHartmut Brandt inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 2036165c5d31SHartmut Brandt #endif 2037165c5d31SHartmut Brandt 2038165c5d31SHartmut Brandt tp->udata = udata; 2039165c5d31SHartmut Brandt tp->owner = mod; 2040165c5d31SHartmut Brandt tp->func = func; 2041165c5d31SHartmut Brandt 2042165c5d31SHartmut Brandt LIST_INSERT_HEAD(&timer_list, tp, link); 2043165c5d31SHartmut Brandt 2044165c5d31SHartmut Brandt #ifdef USE_LIBBEGEMOT 2045165c5d31SHartmut Brandt if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 2046165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2047165c5d31SHartmut Brandt exit(1); 2048165c5d31SHartmut Brandt } 2049165c5d31SHartmut Brandt #else 2050165c5d31SHartmut Brandt if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 2051165c5d31SHartmut Brandt syslog(LOG_ERR, "cannot set timer: %m"); 2052165c5d31SHartmut Brandt exit(1); 2053165c5d31SHartmut Brandt } 2054165c5d31SHartmut Brandt #endif 2055165c5d31SHartmut Brandt return (tp); 2056165c5d31SHartmut Brandt } 2057165c5d31SHartmut Brandt 2058165c5d31SHartmut Brandt /* 2059165c5d31SHartmut Brandt * Stop a timer. 2060165c5d31SHartmut Brandt */ 2061f06ca4afSHartmut Brandt void 2062f06ca4afSHartmut Brandt timer_stop(void *p) 2063f06ca4afSHartmut Brandt { 2064f06ca4afSHartmut Brandt struct timer *tp = p; 2065f06ca4afSHartmut Brandt 2066f06ca4afSHartmut Brandt LIST_REMOVE(tp, link); 206770af00a1SHartmut Brandt #ifdef USE_LIBBEGEMOT 206870af00a1SHartmut Brandt poll_stop_timer(tp->id); 206970af00a1SHartmut Brandt #else 2070f06ca4afSHartmut Brandt if (evClearTimer(evctx, tp->id) == -1) { 2071f06ca4afSHartmut Brandt syslog(LOG_ERR, "cannot stop timer: %m"); 2072f06ca4afSHartmut Brandt exit(1); 2073f06ca4afSHartmut Brandt } 207470af00a1SHartmut Brandt #endif 2075f06ca4afSHartmut Brandt free(p); 2076f06ca4afSHartmut Brandt } 2077f06ca4afSHartmut Brandt 2078f06ca4afSHartmut Brandt static void 2079f06ca4afSHartmut Brandt timer_flush(struct lmodule *mod) 2080f06ca4afSHartmut Brandt { 2081f06ca4afSHartmut Brandt struct timer *t, *t1; 2082f06ca4afSHartmut Brandt 2083f06ca4afSHartmut Brandt t = LIST_FIRST(&timer_list); 2084f06ca4afSHartmut Brandt while (t != NULL) { 2085f06ca4afSHartmut Brandt t1 = LIST_NEXT(t, link); 2086f06ca4afSHartmut Brandt if (t->owner == mod) 2087f06ca4afSHartmut Brandt timer_stop(t); 2088f06ca4afSHartmut Brandt t = t1; 2089f06ca4afSHartmut Brandt } 2090f06ca4afSHartmut Brandt } 2091f06ca4afSHartmut Brandt 2092f06ca4afSHartmut Brandt static void 2093f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 2094f06ca4afSHartmut Brandt { 2095f06ca4afSHartmut Brandt va_list ap; 2096f06ca4afSHartmut Brandt static char *pend = NULL; 2097f06ca4afSHartmut Brandt char *ret, *new; 2098f06ca4afSHartmut Brandt 2099f06ca4afSHartmut Brandt va_start(ap, fmt); 2100f06ca4afSHartmut Brandt vasprintf(&ret, fmt, ap); 2101f06ca4afSHartmut Brandt va_end(ap); 2102f06ca4afSHartmut Brandt 2103f06ca4afSHartmut Brandt if (ret == NULL) 2104f06ca4afSHartmut Brandt return; 2105f06ca4afSHartmut Brandt if (pend != NULL) { 2106f06ca4afSHartmut Brandt if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 2107f06ca4afSHartmut Brandt == NULL) { 2108f06ca4afSHartmut Brandt free(ret); 2109f06ca4afSHartmut Brandt return; 2110f06ca4afSHartmut Brandt } 2111f06ca4afSHartmut Brandt pend = new; 2112f06ca4afSHartmut Brandt strcat(pend, ret); 2113f06ca4afSHartmut Brandt free(ret); 2114f06ca4afSHartmut Brandt } else 2115f06ca4afSHartmut Brandt pend = ret; 2116f06ca4afSHartmut Brandt 2117f06ca4afSHartmut Brandt while ((ret = strchr(pend, '\n')) != NULL) { 2118f06ca4afSHartmut Brandt *ret = '\0'; 2119f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", pend); 2120f06ca4afSHartmut Brandt if (strlen(ret + 1) == 0) { 2121f06ca4afSHartmut Brandt free(pend); 2122f06ca4afSHartmut Brandt pend = NULL; 2123f06ca4afSHartmut Brandt break; 2124f06ca4afSHartmut Brandt } 2125f06ca4afSHartmut Brandt strcpy(pend, ret + 1); 2126f06ca4afSHartmut Brandt } 2127f06ca4afSHartmut Brandt } 2128f06ca4afSHartmut Brandt 2129f06ca4afSHartmut Brandt static void 2130f06ca4afSHartmut Brandt snmp_error_func(const char *err, ...) 2131f06ca4afSHartmut Brandt { 2132f06ca4afSHartmut Brandt char errbuf[1000]; 2133f06ca4afSHartmut Brandt va_list ap; 2134f06ca4afSHartmut Brandt 213570af00a1SHartmut Brandt if (!(snmp_trace & LOG_SNMP_ERRORS)) 213670af00a1SHartmut Brandt return; 213770af00a1SHartmut Brandt 2138f06ca4afSHartmut Brandt va_start(ap, err); 2139f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 214070af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 214170af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2142f06ca4afSHartmut Brandt va_end(ap); 2143f06ca4afSHartmut Brandt 2144f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2145f06ca4afSHartmut Brandt } 2146f06ca4afSHartmut Brandt 2147f06ca4afSHartmut Brandt static void 2148f06ca4afSHartmut Brandt snmp_debug_func(const char *err, ...) 2149f06ca4afSHartmut Brandt { 2150f06ca4afSHartmut Brandt char errbuf[1000]; 2151f06ca4afSHartmut Brandt va_list ap; 2152f06ca4afSHartmut Brandt 2153f06ca4afSHartmut Brandt va_start(ap, err); 2154f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2155f06ca4afSHartmut Brandt vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2156f06ca4afSHartmut Brandt err, ap); 2157f06ca4afSHartmut Brandt va_end(ap); 2158f06ca4afSHartmut Brandt 2159f06ca4afSHartmut Brandt syslog(LOG_DEBUG, "%s", errbuf); 2160f06ca4afSHartmut Brandt } 2161f06ca4afSHartmut Brandt 2162f06ca4afSHartmut Brandt static void 2163f06ca4afSHartmut Brandt asn_error_func(const struct asn_buf *b, const char *err, ...) 2164f06ca4afSHartmut Brandt { 2165f06ca4afSHartmut Brandt char errbuf[1000]; 2166f06ca4afSHartmut Brandt va_list ap; 2167f06ca4afSHartmut Brandt u_int i; 2168f06ca4afSHartmut Brandt 216970af00a1SHartmut Brandt if (!(snmp_trace & LOG_ASN1_ERRORS)) 217070af00a1SHartmut Brandt return; 217170af00a1SHartmut Brandt 2172f06ca4afSHartmut Brandt va_start(ap, err); 2173f06ca4afSHartmut Brandt snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 217470af00a1SHartmut Brandt vsnprintf(errbuf + strlen(errbuf), 217570af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), err, ap); 2176f06ca4afSHartmut Brandt va_end(ap); 2177f06ca4afSHartmut Brandt 2178f06ca4afSHartmut Brandt if (b != NULL) { 217970af00a1SHartmut Brandt snprintf(errbuf + strlen(errbuf), 218070af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), " at"); 2181f06ca4afSHartmut Brandt for (i = 0; b->asn_len > i; i++) 2182f06ca4afSHartmut Brandt snprintf(errbuf + strlen(errbuf), 218370af00a1SHartmut Brandt sizeof(errbuf) - strlen(errbuf), 218470af00a1SHartmut Brandt " %02x", b->asn_cptr[i]); 2185f06ca4afSHartmut Brandt } 2186f06ca4afSHartmut Brandt 2187f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s", errbuf); 2188f06ca4afSHartmut Brandt } 2189f06ca4afSHartmut Brandt 2190f06ca4afSHartmut Brandt /* 2191f06ca4afSHartmut Brandt * Create a new community 2192f06ca4afSHartmut Brandt */ 2193f06ca4afSHartmut Brandt u_int 2194f06ca4afSHartmut Brandt comm_define(u_int priv, const char *descr, struct lmodule *owner, 2195f06ca4afSHartmut Brandt const char *str) 2196f06ca4afSHartmut Brandt { 2197f06ca4afSHartmut Brandt struct community *c, *p; 2198f06ca4afSHartmut Brandt u_int ncomm; 2199f06ca4afSHartmut Brandt 2200f06ca4afSHartmut Brandt /* generate an identifier */ 2201f06ca4afSHartmut Brandt do { 2202f06ca4afSHartmut Brandt if ((ncomm = next_community_index++) == UINT_MAX) 2203f06ca4afSHartmut Brandt next_community_index = 1; 2204f06ca4afSHartmut Brandt TAILQ_FOREACH(c, &community_list, link) 2205f06ca4afSHartmut Brandt if (c->value == ncomm) 2206f06ca4afSHartmut Brandt break; 2207f06ca4afSHartmut Brandt } while (c != NULL); 2208f06ca4afSHartmut Brandt 2209f06ca4afSHartmut Brandt if ((c = malloc(sizeof(struct community))) == NULL) { 2210f06ca4afSHartmut Brandt syslog(LOG_ERR, "comm_define: %m"); 2211f06ca4afSHartmut Brandt return (0); 2212f06ca4afSHartmut Brandt } 2213f06ca4afSHartmut Brandt c->owner = owner; 2214f06ca4afSHartmut Brandt c->value = ncomm; 2215f06ca4afSHartmut Brandt c->descr = descr; 2216f06ca4afSHartmut Brandt c->string = NULL; 2217f06ca4afSHartmut Brandt c->private = priv; 2218f06ca4afSHartmut Brandt 2219f06ca4afSHartmut Brandt if (str != NULL) { 2220f06ca4afSHartmut Brandt if((c->string = malloc(strlen(str)+1)) == NULL) { 2221f06ca4afSHartmut Brandt free(c); 2222f06ca4afSHartmut Brandt return (0); 2223f06ca4afSHartmut Brandt } 2224f06ca4afSHartmut Brandt strcpy(c->string, str); 2225f06ca4afSHartmut Brandt } 2226f06ca4afSHartmut Brandt 2227f06ca4afSHartmut Brandt /* make index */ 2228f06ca4afSHartmut Brandt if (c->owner == NULL) { 2229f06ca4afSHartmut Brandt c->index.len = 1; 2230f06ca4afSHartmut Brandt c->index.subs[0] = 0; 2231f06ca4afSHartmut Brandt } else { 2232f06ca4afSHartmut Brandt c->index = c->owner->index; 2233f06ca4afSHartmut Brandt } 2234f06ca4afSHartmut Brandt c->index.subs[c->index.len++] = c->private; 2235f06ca4afSHartmut Brandt 2236f06ca4afSHartmut Brandt /* 2237f06ca4afSHartmut Brandt * Insert ordered 2238f06ca4afSHartmut Brandt */ 2239f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) { 2240f06ca4afSHartmut Brandt if (asn_compare_oid(&p->index, &c->index) > 0) { 2241f06ca4afSHartmut Brandt TAILQ_INSERT_BEFORE(p, c, link); 2242f06ca4afSHartmut Brandt break; 2243f06ca4afSHartmut Brandt } 2244f06ca4afSHartmut Brandt } 2245f06ca4afSHartmut Brandt if (p == NULL) 2246f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&community_list, c, link); 2247f06ca4afSHartmut Brandt return (c->value); 2248f06ca4afSHartmut Brandt } 2249f06ca4afSHartmut Brandt 2250f06ca4afSHartmut Brandt const char * 2251f06ca4afSHartmut Brandt comm_string(u_int ncomm) 2252f06ca4afSHartmut Brandt { 2253f06ca4afSHartmut Brandt struct community *p; 2254f06ca4afSHartmut Brandt 2255f06ca4afSHartmut Brandt TAILQ_FOREACH(p, &community_list, link) 2256f06ca4afSHartmut Brandt if (p->value == ncomm) 2257f06ca4afSHartmut Brandt return (p->string); 2258f06ca4afSHartmut Brandt return (NULL); 2259f06ca4afSHartmut Brandt } 2260f06ca4afSHartmut Brandt 2261f06ca4afSHartmut Brandt /* 2262f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2263f06ca4afSHartmut Brandt */ 2264f06ca4afSHartmut Brandt static void 2265f06ca4afSHartmut Brandt comm_flush(struct lmodule *mod) 2266f06ca4afSHartmut Brandt { 2267f06ca4afSHartmut Brandt struct community *p, *p1; 2268f06ca4afSHartmut Brandt 2269f06ca4afSHartmut Brandt p = TAILQ_FIRST(&community_list); 2270f06ca4afSHartmut Brandt while (p != NULL) { 2271f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2272f06ca4afSHartmut Brandt if (p->owner == mod) { 2273f06ca4afSHartmut Brandt free(p->string); 2274f06ca4afSHartmut Brandt TAILQ_REMOVE(&community_list, p, link); 2275f06ca4afSHartmut Brandt free(p); 2276f06ca4afSHartmut Brandt } 2277f06ca4afSHartmut Brandt p = p1; 2278f06ca4afSHartmut Brandt } 2279f06ca4afSHartmut Brandt } 2280f06ca4afSHartmut Brandt 2281f06ca4afSHartmut Brandt /* 2282f06ca4afSHartmut Brandt * Request ID handling. 2283f06ca4afSHartmut Brandt * 2284f06ca4afSHartmut Brandt * Allocate a new range of request ids. Use a first fit algorithm. 2285f06ca4afSHartmut Brandt */ 2286f06ca4afSHartmut Brandt u_int 2287f06ca4afSHartmut Brandt reqid_allocate(int size, struct lmodule *mod) 2288f06ca4afSHartmut Brandt { 2289f06ca4afSHartmut Brandt u_int type; 2290f06ca4afSHartmut Brandt struct idrange *r, *r1; 2291f06ca4afSHartmut Brandt 2292f06ca4afSHartmut Brandt if (size <= 0 || size > INT32_MAX) { 2293f06ca4afSHartmut Brandt syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2294f06ca4afSHartmut Brandt return (0); 2295f06ca4afSHartmut Brandt } 2296f06ca4afSHartmut Brandt /* allocate a type id */ 2297f06ca4afSHartmut Brandt do { 2298f06ca4afSHartmut Brandt if ((type = next_idrange++) == UINT_MAX) 2299f06ca4afSHartmut Brandt next_idrange = 1; 2300f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2301f06ca4afSHartmut Brandt if (r->type == type) 2302f06ca4afSHartmut Brandt break; 2303f06ca4afSHartmut Brandt } while(r != NULL); 2304f06ca4afSHartmut Brandt 2305f06ca4afSHartmut Brandt /* find a range */ 2306f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list)) 2307f06ca4afSHartmut Brandt r = NULL; 2308f06ca4afSHartmut Brandt else { 2309f06ca4afSHartmut Brandt r = TAILQ_FIRST(&idrange_list); 2310f06ca4afSHartmut Brandt if (r->base < size) { 2311f06ca4afSHartmut Brandt while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2312f06ca4afSHartmut Brandt if (r1->base - (r->base + r->size) >= size) 2313f06ca4afSHartmut Brandt break; 2314f06ca4afSHartmut Brandt r = r1; 2315f06ca4afSHartmut Brandt } 2316f06ca4afSHartmut Brandt r = r1; 2317f06ca4afSHartmut Brandt } 2318f06ca4afSHartmut Brandt if (r == NULL) { 2319f06ca4afSHartmut Brandt r1 = TAILQ_LAST(&idrange_list, idrange_list); 2320f06ca4afSHartmut Brandt if (INT32_MAX - size + 1 < r1->base + r1->size) { 2321f06ca4afSHartmut Brandt syslog(LOG_ERR, "out of id ranges (%u)", size); 2322f06ca4afSHartmut Brandt return (0); 2323f06ca4afSHartmut Brandt } 2324f06ca4afSHartmut Brandt } 2325f06ca4afSHartmut Brandt } 2326f06ca4afSHartmut Brandt 2327f06ca4afSHartmut Brandt /* allocate structure */ 2328f06ca4afSHartmut Brandt if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2329f06ca4afSHartmut Brandt syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2330f06ca4afSHartmut Brandt return (0); 2331f06ca4afSHartmut Brandt } 2332f06ca4afSHartmut Brandt 2333f06ca4afSHartmut Brandt r1->type = type; 2334f06ca4afSHartmut Brandt r1->size = size; 2335f06ca4afSHartmut Brandt r1->owner = mod; 2336f06ca4afSHartmut Brandt if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2337f06ca4afSHartmut Brandt r1->base = 0; 2338f06ca4afSHartmut Brandt TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2339f06ca4afSHartmut Brandt } else if (r == NULL) { 2340f06ca4afSHartmut Brandt r = TAILQ_LAST(&idrange_list, idrange_list); 2341f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2342f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2343f06ca4afSHartmut Brandt } else { 2344f06ca4afSHartmut Brandt r = TAILQ_PREV(r, idrange_list, link); 2345f06ca4afSHartmut Brandt r1->base = r->base + r->size; 2346f06ca4afSHartmut Brandt TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2347f06ca4afSHartmut Brandt } 2348f06ca4afSHartmut Brandt r1->next = r1->base; 2349f06ca4afSHartmut Brandt 2350f06ca4afSHartmut Brandt return (type); 2351f06ca4afSHartmut Brandt } 2352f06ca4afSHartmut Brandt 2353f06ca4afSHartmut Brandt int32_t 2354f06ca4afSHartmut Brandt reqid_next(u_int type) 2355f06ca4afSHartmut Brandt { 2356f06ca4afSHartmut Brandt struct idrange *r; 2357f06ca4afSHartmut Brandt int32_t id; 2358f06ca4afSHartmut Brandt 2359f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2360f06ca4afSHartmut Brandt if (r->type == type) 2361f06ca4afSHartmut Brandt break; 2362f06ca4afSHartmut Brandt if (r == NULL) { 2363f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2364f06ca4afSHartmut Brandt abort(); 2365f06ca4afSHartmut Brandt } 2366f06ca4afSHartmut Brandt if ((id = r->next++) == r->base + (r->size - 1)) 2367f06ca4afSHartmut Brandt r->next = r->base; 2368f06ca4afSHartmut Brandt return (id); 2369f06ca4afSHartmut Brandt } 2370f06ca4afSHartmut Brandt 2371f06ca4afSHartmut Brandt int32_t 2372f06ca4afSHartmut Brandt reqid_base(u_int type) 2373f06ca4afSHartmut Brandt { 2374f06ca4afSHartmut Brandt struct idrange *r; 2375f06ca4afSHartmut Brandt 2376f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2377f06ca4afSHartmut Brandt if (r->type == type) 2378f06ca4afSHartmut Brandt return (r->base); 2379f06ca4afSHartmut Brandt syslog(LOG_CRIT, "wrong idrange type"); 2380f06ca4afSHartmut Brandt abort(); 2381f06ca4afSHartmut Brandt } 2382f06ca4afSHartmut Brandt 2383f06ca4afSHartmut Brandt u_int 2384f06ca4afSHartmut Brandt reqid_type(int32_t reqid) 2385f06ca4afSHartmut Brandt { 2386f06ca4afSHartmut Brandt struct idrange *r; 2387f06ca4afSHartmut Brandt 2388f06ca4afSHartmut Brandt TAILQ_FOREACH(r, &idrange_list, link) 2389f06ca4afSHartmut Brandt if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2390f06ca4afSHartmut Brandt return (r->type); 2391f06ca4afSHartmut Brandt return (0); 2392f06ca4afSHartmut Brandt } 2393f06ca4afSHartmut Brandt 2394f06ca4afSHartmut Brandt int 2395f06ca4afSHartmut Brandt reqid_istype(int32_t reqid, u_int type) 2396f06ca4afSHartmut Brandt { 2397f06ca4afSHartmut Brandt return (reqid_type(reqid) == type); 2398f06ca4afSHartmut Brandt } 2399f06ca4afSHartmut Brandt 2400f06ca4afSHartmut Brandt /* 2401f06ca4afSHartmut Brandt * Delete all communities allocated by a module 2402f06ca4afSHartmut Brandt */ 2403f06ca4afSHartmut Brandt static void 2404f06ca4afSHartmut Brandt reqid_flush(struct lmodule *mod) 2405f06ca4afSHartmut Brandt { 2406f06ca4afSHartmut Brandt struct idrange *p, *p1; 2407f06ca4afSHartmut Brandt 2408f06ca4afSHartmut Brandt p = TAILQ_FIRST(&idrange_list); 2409f06ca4afSHartmut Brandt while (p != NULL) { 2410f06ca4afSHartmut Brandt p1 = TAILQ_NEXT(p, link); 2411f06ca4afSHartmut Brandt if (p->owner == mod) { 2412f06ca4afSHartmut Brandt TAILQ_REMOVE(&idrange_list, p, link); 2413f06ca4afSHartmut Brandt free(p); 2414f06ca4afSHartmut Brandt } 2415f06ca4afSHartmut Brandt p = p1; 2416f06ca4afSHartmut Brandt } 2417f06ca4afSHartmut Brandt } 2418f06ca4afSHartmut Brandt 2419f06ca4afSHartmut Brandt /* 2420f06ca4afSHartmut Brandt * Merge the given tree for the given module into the main tree. 2421f06ca4afSHartmut Brandt */ 2422f06ca4afSHartmut Brandt static int 2423f06ca4afSHartmut Brandt compare_node(const void *v1, const void *v2) 2424f06ca4afSHartmut Brandt { 2425f06ca4afSHartmut Brandt const struct snmp_node *n1 = v1; 2426f06ca4afSHartmut Brandt const struct snmp_node *n2 = v2; 2427f06ca4afSHartmut Brandt 2428f06ca4afSHartmut Brandt return (asn_compare_oid(&n1->oid, &n2->oid)); 2429f06ca4afSHartmut Brandt } 2430f06ca4afSHartmut Brandt static int 2431f06ca4afSHartmut Brandt tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2432f06ca4afSHartmut Brandt { 2433f06ca4afSHartmut Brandt struct snmp_node *xtree; 2434f06ca4afSHartmut Brandt u_int i; 2435f06ca4afSHartmut Brandt 2436f06ca4afSHartmut Brandt xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2437f06ca4afSHartmut Brandt if (xtree == NULL) { 24388eecd77aSHartmut Brandt syslog(LOG_ERR, "tree_merge: %m"); 2439f06ca4afSHartmut Brandt return (-1); 2440f06ca4afSHartmut Brandt } 2441f06ca4afSHartmut Brandt tree = xtree; 2442f06ca4afSHartmut Brandt memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2443f06ca4afSHartmut Brandt 2444f06ca4afSHartmut Brandt for (i = 0; i < nsize; i++) 24458eecd77aSHartmut Brandt tree[tree_size + i].tree_data = mod; 2446f06ca4afSHartmut Brandt 2447f06ca4afSHartmut Brandt tree_size += nsize; 2448f06ca4afSHartmut Brandt 2449f06ca4afSHartmut Brandt qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2450f06ca4afSHartmut Brandt 2451f06ca4afSHartmut Brandt return (0); 2452f06ca4afSHartmut Brandt } 2453f06ca4afSHartmut Brandt 2454f06ca4afSHartmut Brandt /* 2455f06ca4afSHartmut Brandt * Remove all nodes belonging to the loadable module 2456f06ca4afSHartmut Brandt */ 2457f06ca4afSHartmut Brandt static void 2458f06ca4afSHartmut Brandt tree_unmerge(struct lmodule *mod) 2459f06ca4afSHartmut Brandt { 2460f06ca4afSHartmut Brandt u_int s, d; 2461f06ca4afSHartmut Brandt 2462f06ca4afSHartmut Brandt for(s = d = 0; s < tree_size; s++) 24638eecd77aSHartmut Brandt if (tree[s].tree_data != mod) { 2464f06ca4afSHartmut Brandt if (s != d) 2465f06ca4afSHartmut Brandt tree[d] = tree[s]; 2466f06ca4afSHartmut Brandt d++; 2467f06ca4afSHartmut Brandt } 2468f06ca4afSHartmut Brandt tree_size = d; 2469f06ca4afSHartmut Brandt } 2470f06ca4afSHartmut Brandt 2471f06ca4afSHartmut Brandt /* 2472f06ca4afSHartmut Brandt * Loadable modules 2473f06ca4afSHartmut Brandt */ 2474f06ca4afSHartmut Brandt struct lmodule * 2475f06ca4afSHartmut Brandt lm_load(const char *path, const char *section) 2476f06ca4afSHartmut Brandt { 2477f06ca4afSHartmut Brandt struct lmodule *m; 2478f06ca4afSHartmut Brandt int err; 2479f06ca4afSHartmut Brandt int i; 2480f06ca4afSHartmut Brandt char *av[MAX_MOD_ARGS + 1]; 2481f06ca4afSHartmut Brandt int ac; 2482f06ca4afSHartmut Brandt u_int u; 2483f06ca4afSHartmut Brandt 2484f06ca4afSHartmut Brandt if ((m = malloc(sizeof(*m))) == NULL) { 2485f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2486f06ca4afSHartmut Brandt return (NULL); 2487f06ca4afSHartmut Brandt } 2488f06ca4afSHartmut Brandt m->handle = NULL; 2489f06ca4afSHartmut Brandt m->flags = 0; 2490f06ca4afSHartmut Brandt strcpy(m->section, section); 2491f06ca4afSHartmut Brandt 2492f06ca4afSHartmut Brandt if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2493f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: %m"); 2494f06ca4afSHartmut Brandt goto err; 2495f06ca4afSHartmut Brandt } 2496f06ca4afSHartmut Brandt strcpy(m->path, path); 2497f06ca4afSHartmut Brandt 2498f06ca4afSHartmut Brandt /* 2499f06ca4afSHartmut Brandt * Make index 2500f06ca4afSHartmut Brandt */ 2501f06ca4afSHartmut Brandt m->index.subs[0] = strlen(section); 2502f06ca4afSHartmut Brandt m->index.len = m->index.subs[0] + 1; 2503f06ca4afSHartmut Brandt for (u = 0; u < m->index.subs[0]; u++) 2504f06ca4afSHartmut Brandt m->index.subs[u + 1] = section[u]; 2505f06ca4afSHartmut Brandt 2506f06ca4afSHartmut Brandt /* 2507f06ca4afSHartmut Brandt * Load the object file and locate the config structure 2508f06ca4afSHartmut Brandt */ 2509f06ca4afSHartmut Brandt if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2510f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2511f06ca4afSHartmut Brandt goto err; 2512f06ca4afSHartmut Brandt } 2513f06ca4afSHartmut Brandt 2514f06ca4afSHartmut Brandt if ((m->config = dlsym(m->handle, "config")) == NULL) { 2515f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2516f06ca4afSHartmut Brandt goto err; 2517f06ca4afSHartmut Brandt } 2518f06ca4afSHartmut Brandt 2519f06ca4afSHartmut Brandt /* 2520f06ca4afSHartmut Brandt * Insert it into the right place 2521f06ca4afSHartmut Brandt */ 2522f06ca4afSHartmut Brandt INSERT_OBJECT_OID(m, &lmodules); 2523f06ca4afSHartmut Brandt 2524f06ca4afSHartmut Brandt /* preserve order */ 2525f06ca4afSHartmut Brandt if (community == COMM_INITIALIZE) { 2526f06ca4afSHartmut Brandt m->flags |= LM_ONSTARTLIST; 2527f06ca4afSHartmut Brandt TAILQ_INSERT_TAIL(&modules_start, m, start); 2528f06ca4afSHartmut Brandt } 2529f06ca4afSHartmut Brandt 2530f06ca4afSHartmut Brandt /* 2531f06ca4afSHartmut Brandt * make the argument vector. 2532f06ca4afSHartmut Brandt */ 2533f06ca4afSHartmut Brandt ac = 0; 2534f06ca4afSHartmut Brandt for (i = 0; i < nprogargs; i++) { 2535f06ca4afSHartmut Brandt if (strlen(progargs[i]) >= strlen(section) + 1 && 2536f06ca4afSHartmut Brandt strncmp(progargs[i], section, strlen(section)) == 0 && 2537f06ca4afSHartmut Brandt progargs[i][strlen(section)] == ':') { 2538f06ca4afSHartmut Brandt if (ac == MAX_MOD_ARGS) { 2539f06ca4afSHartmut Brandt syslog(LOG_WARNING, "too many arguments for " 2540f06ca4afSHartmut Brandt "module '%s", section); 2541f06ca4afSHartmut Brandt break; 2542f06ca4afSHartmut Brandt } 2543f06ca4afSHartmut Brandt av[ac++] = &progargs[i][strlen(section)+1]; 2544f06ca4afSHartmut Brandt } 2545f06ca4afSHartmut Brandt } 2546f06ca4afSHartmut Brandt av[ac] = NULL; 2547f06ca4afSHartmut Brandt 2548f06ca4afSHartmut Brandt /* 2549165c5d31SHartmut Brandt * Run the initialization function 2550f06ca4afSHartmut Brandt */ 2551f06ca4afSHartmut Brandt if ((err = (*m->config->init)(m, ac, av)) != 0) { 2552f06ca4afSHartmut Brandt syslog(LOG_ERR, "lm_load: init failed: %d", err); 2553f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2554f06ca4afSHartmut Brandt goto err; 2555f06ca4afSHartmut Brandt } 2556f06ca4afSHartmut Brandt 2557f06ca4afSHartmut Brandt return (m); 2558f06ca4afSHartmut Brandt 2559f06ca4afSHartmut Brandt err: 2560691f8568SShteryana Shopova if ((m->flags & LM_ONSTARTLIST) != 0) 2561691f8568SShteryana Shopova TAILQ_REMOVE(&modules_start, m, start); 2562f06ca4afSHartmut Brandt if (m->handle) 2563f06ca4afSHartmut Brandt dlclose(m->handle); 2564f06ca4afSHartmut Brandt free(m->path); 2565f06ca4afSHartmut Brandt free(m); 2566f06ca4afSHartmut Brandt return (NULL); 2567f06ca4afSHartmut Brandt } 2568f06ca4afSHartmut Brandt 2569f06ca4afSHartmut Brandt /* 2570f06ca4afSHartmut Brandt * Start a module 2571f06ca4afSHartmut Brandt */ 2572f06ca4afSHartmut Brandt void 2573f06ca4afSHartmut Brandt lm_start(struct lmodule *mod) 2574f06ca4afSHartmut Brandt { 2575f06ca4afSHartmut Brandt const struct lmodule *m; 2576f06ca4afSHartmut Brandt 2577f06ca4afSHartmut Brandt /* 2578f06ca4afSHartmut Brandt * Merge tree. If this fails, unload the module. 2579f06ca4afSHartmut Brandt */ 2580f06ca4afSHartmut Brandt if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2581f06ca4afSHartmut Brandt lm_unload(mod); 2582f06ca4afSHartmut Brandt return; 2583f06ca4afSHartmut Brandt } 2584f06ca4afSHartmut Brandt 2585f06ca4afSHartmut Brandt /* 2586f06ca4afSHartmut Brandt * Read configuration 2587f06ca4afSHartmut Brandt */ 2588f06ca4afSHartmut Brandt if (read_config(config_file, mod)) { 2589f06ca4afSHartmut Brandt syslog(LOG_ERR, "error in config file"); 2590f06ca4afSHartmut Brandt lm_unload(mod); 2591f06ca4afSHartmut Brandt return; 2592f06ca4afSHartmut Brandt } 2593f06ca4afSHartmut Brandt if (mod->config->start) 2594f06ca4afSHartmut Brandt (*mod->config->start)(); 2595f06ca4afSHartmut Brandt 2596f06ca4afSHartmut Brandt mod->flags |= LM_STARTED; 2597f06ca4afSHartmut Brandt 2598f06ca4afSHartmut Brandt /* 2599f06ca4afSHartmut Brandt * Inform other modules 2600f06ca4afSHartmut Brandt */ 2601f06ca4afSHartmut Brandt TAILQ_FOREACH(m, &lmodules, link) 2602f06ca4afSHartmut Brandt if (m->config->loading) 2603f06ca4afSHartmut Brandt (*m->config->loading)(mod, 1); 2604f06ca4afSHartmut Brandt } 2605f06ca4afSHartmut Brandt 2606f06ca4afSHartmut Brandt 2607f06ca4afSHartmut Brandt /* 2608f06ca4afSHartmut Brandt * Unload a module. 2609f06ca4afSHartmut Brandt */ 2610f06ca4afSHartmut Brandt void 2611f06ca4afSHartmut Brandt lm_unload(struct lmodule *m) 2612f06ca4afSHartmut Brandt { 2613f06ca4afSHartmut Brandt int err; 2614f06ca4afSHartmut Brandt const struct lmodule *mod; 2615f06ca4afSHartmut Brandt 2616f06ca4afSHartmut Brandt TAILQ_REMOVE(&lmodules, m, link); 2617f06ca4afSHartmut Brandt if (m->flags & LM_ONSTARTLIST) 2618f06ca4afSHartmut Brandt TAILQ_REMOVE(&modules_start, m, start); 2619f06ca4afSHartmut Brandt tree_unmerge(m); 2620f06ca4afSHartmut Brandt 2621f06ca4afSHartmut Brandt if ((m->flags & LM_STARTED) && m->config->fini && 2622f06ca4afSHartmut Brandt (err = (*m->config->fini)()) != 0) 2623f06ca4afSHartmut Brandt syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2624f06ca4afSHartmut Brandt 2625f06ca4afSHartmut Brandt comm_flush(m); 2626f06ca4afSHartmut Brandt reqid_flush(m); 2627f06ca4afSHartmut Brandt timer_flush(m); 2628f06ca4afSHartmut Brandt fd_flush(m); 2629f06ca4afSHartmut Brandt 2630f06ca4afSHartmut Brandt dlclose(m->handle); 2631f06ca4afSHartmut Brandt free(m->path); 2632f06ca4afSHartmut Brandt 2633f06ca4afSHartmut Brandt /* 2634f06ca4afSHartmut Brandt * Inform other modules 2635f06ca4afSHartmut Brandt */ 2636f06ca4afSHartmut Brandt TAILQ_FOREACH(mod, &lmodules, link) 2637f06ca4afSHartmut Brandt if (mod->config->loading) 2638f06ca4afSHartmut Brandt (*mod->config->loading)(m, 0); 2639f06ca4afSHartmut Brandt 2640f06ca4afSHartmut Brandt free(m); 2641f06ca4afSHartmut Brandt } 2642f06ca4afSHartmut Brandt 2643f06ca4afSHartmut Brandt /* 2644f06ca4afSHartmut Brandt * Register an object resource and return the index (or 0 on failures) 2645f06ca4afSHartmut Brandt */ 2646f06ca4afSHartmut Brandt u_int 2647f06ca4afSHartmut Brandt or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2648f06ca4afSHartmut Brandt { 2649f06ca4afSHartmut Brandt struct objres *objres, *or1; 2650f06ca4afSHartmut Brandt u_int idx; 2651f06ca4afSHartmut Brandt 2652f06ca4afSHartmut Brandt /* find a free index */ 2653f06ca4afSHartmut Brandt idx = 1; 2654f06ca4afSHartmut Brandt for (objres = TAILQ_FIRST(&objres_list); 2655f06ca4afSHartmut Brandt objres != NULL; 2656f06ca4afSHartmut Brandt objres = TAILQ_NEXT(objres, link)) { 2657f06ca4afSHartmut Brandt if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2658f06ca4afSHartmut Brandt or1->index > objres->index + 1) { 2659f06ca4afSHartmut Brandt idx = objres->index + 1; 2660f06ca4afSHartmut Brandt break; 2661f06ca4afSHartmut Brandt } 2662f06ca4afSHartmut Brandt } 2663f06ca4afSHartmut Brandt 2664f06ca4afSHartmut Brandt if ((objres = malloc(sizeof(*objres))) == NULL) 2665f06ca4afSHartmut Brandt return (0); 2666f06ca4afSHartmut Brandt 2667f06ca4afSHartmut Brandt objres->index = idx; 2668f06ca4afSHartmut Brandt objres->oid = *or; 2669f06ca4afSHartmut Brandt strlcpy(objres->descr, descr, sizeof(objres->descr)); 267069292cedSHartmut Brandt objres->uptime = (uint32_t)(get_ticks() - start_tick); 2671f06ca4afSHartmut Brandt objres->module = mod; 2672f06ca4afSHartmut Brandt 2673f06ca4afSHartmut Brandt INSERT_OBJECT_INT(objres, &objres_list); 2674f06ca4afSHartmut Brandt 2675f06ca4afSHartmut Brandt systemg.or_last_change = objres->uptime; 2676f06ca4afSHartmut Brandt 2677f06ca4afSHartmut Brandt return (idx); 2678f06ca4afSHartmut Brandt } 2679f06ca4afSHartmut Brandt 2680f06ca4afSHartmut Brandt void 2681f06ca4afSHartmut Brandt or_unregister(u_int idx) 2682f06ca4afSHartmut Brandt { 2683f06ca4afSHartmut Brandt struct objres *objres; 2684f06ca4afSHartmut Brandt 2685f06ca4afSHartmut Brandt TAILQ_FOREACH(objres, &objres_list, link) 2686f06ca4afSHartmut Brandt if (objres->index == idx) { 2687f06ca4afSHartmut Brandt TAILQ_REMOVE(&objres_list, objres, link); 2688f06ca4afSHartmut Brandt free(objres); 2689f06ca4afSHartmut Brandt return; 2690f06ca4afSHartmut Brandt } 2691f06ca4afSHartmut Brandt } 2692135f7de5SShteryana Shopova 2693135f7de5SShteryana Shopova /* 2694135f7de5SShteryana Shopova * RFC 3414 User-based Security Model support 2695135f7de5SShteryana Shopova */ 2696135f7de5SShteryana Shopova 2697135f7de5SShteryana Shopova struct snmpd_usmstat * 2698135f7de5SShteryana Shopova bsnmpd_get_usm_stats(void) 2699135f7de5SShteryana Shopova { 2700135f7de5SShteryana Shopova return (&snmpd_usmstats); 2701135f7de5SShteryana Shopova } 2702135f7de5SShteryana Shopova 2703135f7de5SShteryana Shopova void 2704135f7de5SShteryana Shopova bsnmpd_reset_usm_stats(void) 2705135f7de5SShteryana Shopova { 2706*9972acaaSHartmut Brandt memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2707135f7de5SShteryana Shopova } 2708135f7de5SShteryana Shopova 2709135f7de5SShteryana Shopova struct usm_user * 2710135f7de5SShteryana Shopova usm_first_user(void) 2711135f7de5SShteryana Shopova { 2712135f7de5SShteryana Shopova return (SLIST_FIRST(&usm_userlist)); 2713135f7de5SShteryana Shopova } 2714135f7de5SShteryana Shopova 2715135f7de5SShteryana Shopova struct usm_user * 2716135f7de5SShteryana Shopova usm_next_user(struct usm_user *uuser) 2717135f7de5SShteryana Shopova { 2718135f7de5SShteryana Shopova if (uuser == NULL) 2719135f7de5SShteryana Shopova return (NULL); 2720135f7de5SShteryana Shopova 2721135f7de5SShteryana Shopova return (SLIST_NEXT(uuser, up)); 2722135f7de5SShteryana Shopova } 2723135f7de5SShteryana Shopova 2724135f7de5SShteryana Shopova struct usm_user * 2725135f7de5SShteryana Shopova usm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2726135f7de5SShteryana Shopova { 2727135f7de5SShteryana Shopova struct usm_user *uuser; 2728135f7de5SShteryana Shopova 2729135f7de5SShteryana Shopova SLIST_FOREACH(uuser, &usm_userlist, up) 2730135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2731135f7de5SShteryana Shopova memcmp(uuser->user_engine_id, engine, elen) == 0 && 2732135f7de5SShteryana Shopova strlen(uuser->suser.sec_name) == strlen(uname) && 2733135f7de5SShteryana Shopova strcmp(uuser->suser.sec_name, uname) == 0) 2734135f7de5SShteryana Shopova break; 2735135f7de5SShteryana Shopova 2736135f7de5SShteryana Shopova return (uuser); 2737135f7de5SShteryana Shopova } 2738135f7de5SShteryana Shopova 2739135f7de5SShteryana Shopova static int 2740135f7de5SShteryana Shopova usm_compare_user(struct usm_user *u1, struct usm_user *u2) 2741135f7de5SShteryana Shopova { 2742135f7de5SShteryana Shopova uint32_t i; 2743135f7de5SShteryana Shopova 2744135f7de5SShteryana Shopova if (u1->user_engine_len < u2->user_engine_len) 2745135f7de5SShteryana Shopova return (-1); 2746135f7de5SShteryana Shopova if (u1->user_engine_len > u2->user_engine_len) 2747135f7de5SShteryana Shopova return (1); 2748135f7de5SShteryana Shopova 2749135f7de5SShteryana Shopova for (i = 0; i < u1->user_engine_len; i++) { 2750135f7de5SShteryana Shopova if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2751135f7de5SShteryana Shopova return (-1); 2752135f7de5SShteryana Shopova if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2753135f7de5SShteryana Shopova return (1); 2754135f7de5SShteryana Shopova } 2755135f7de5SShteryana Shopova 2756135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2757135f7de5SShteryana Shopova return (-1); 2758135f7de5SShteryana Shopova if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2759135f7de5SShteryana Shopova return (1); 2760135f7de5SShteryana Shopova 2761135f7de5SShteryana Shopova for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2762135f7de5SShteryana Shopova if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2763135f7de5SShteryana Shopova return (-1); 2764135f7de5SShteryana Shopova if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2765135f7de5SShteryana Shopova return (1); 2766135f7de5SShteryana Shopova } 2767135f7de5SShteryana Shopova 2768135f7de5SShteryana Shopova return (0); 2769135f7de5SShteryana Shopova } 2770135f7de5SShteryana Shopova 2771135f7de5SShteryana Shopova struct usm_user * 2772135f7de5SShteryana Shopova usm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2773135f7de5SShteryana Shopova { 2774135f7de5SShteryana Shopova int cmp; 2775135f7de5SShteryana Shopova struct usm_user *uuser, *temp, *prev; 2776135f7de5SShteryana Shopova 2777135f7de5SShteryana Shopova for (uuser = usm_first_user(); uuser != NULL; 2778135f7de5SShteryana Shopova (uuser = usm_next_user(uuser))) { 2779135f7de5SShteryana Shopova if (uuser->user_engine_len == elen && 2780135f7de5SShteryana Shopova strlen(uname) == strlen(uuser->suser.sec_name) && 2781135f7de5SShteryana Shopova strcmp(uname, uuser->suser.sec_name) == 0 && 2782135f7de5SShteryana Shopova memcmp(eid, uuser->user_engine_id, elen) == 0) 2783135f7de5SShteryana Shopova return (NULL); 2784135f7de5SShteryana Shopova } 2785135f7de5SShteryana Shopova 2786135f7de5SShteryana Shopova if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2787135f7de5SShteryana Shopova return (NULL); 2788135f7de5SShteryana Shopova 2789135f7de5SShteryana Shopova memset(uuser, 0, sizeof(struct usm_user)); 2790135f7de5SShteryana Shopova strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2791135f7de5SShteryana Shopova memcpy(uuser->user_engine_id, eid, elen); 2792135f7de5SShteryana Shopova uuser->user_engine_len = elen; 2793135f7de5SShteryana Shopova 2794135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2795135f7de5SShteryana Shopova usm_compare_user(uuser, prev) < 0) { 2796135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2797135f7de5SShteryana Shopova return (uuser); 2798135f7de5SShteryana Shopova } 2799135f7de5SShteryana Shopova 2800135f7de5SShteryana Shopova SLIST_FOREACH(temp, &usm_userlist, up) { 2801135f7de5SShteryana Shopova if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2802135f7de5SShteryana Shopova break; 2803135f7de5SShteryana Shopova prev = temp; 2804135f7de5SShteryana Shopova } 2805135f7de5SShteryana Shopova 2806135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2807135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, uuser, up); 2808135f7de5SShteryana Shopova else if (cmp > 0) 2809135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, uuser, up); 2810135f7de5SShteryana Shopova else { 2811135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2812135f7de5SShteryana Shopova free(uuser); 2813135f7de5SShteryana Shopova return (NULL); 2814135f7de5SShteryana Shopova } 2815135f7de5SShteryana Shopova 2816135f7de5SShteryana Shopova return (uuser); 2817135f7de5SShteryana Shopova } 2818135f7de5SShteryana Shopova 2819135f7de5SShteryana Shopova void 2820135f7de5SShteryana Shopova usm_delete_user(struct usm_user *uuser) 2821135f7de5SShteryana Shopova { 2822135f7de5SShteryana Shopova SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2823135f7de5SShteryana Shopova free(uuser); 2824135f7de5SShteryana Shopova } 2825135f7de5SShteryana Shopova 2826135f7de5SShteryana Shopova void 2827135f7de5SShteryana Shopova usm_flush_users(void) 2828135f7de5SShteryana Shopova { 2829135f7de5SShteryana Shopova struct usm_user *uuser; 2830135f7de5SShteryana Shopova 2831135f7de5SShteryana Shopova while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2832135f7de5SShteryana Shopova SLIST_REMOVE_HEAD(&usm_userlist, up); 2833135f7de5SShteryana Shopova free(uuser); 2834135f7de5SShteryana Shopova } 2835135f7de5SShteryana Shopova 2836135f7de5SShteryana Shopova SLIST_INIT(&usm_userlist); 2837135f7de5SShteryana Shopova } 2838135f7de5SShteryana Shopova 2839135f7de5SShteryana Shopova /* 2840135f7de5SShteryana Shopova * RFC 3415 View-based Access Control Model support 2841135f7de5SShteryana Shopova */ 2842135f7de5SShteryana Shopova struct vacm_user * 2843135f7de5SShteryana Shopova vacm_first_user(void) 2844135f7de5SShteryana Shopova { 2845135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_userlist)); 2846135f7de5SShteryana Shopova } 2847135f7de5SShteryana Shopova 2848135f7de5SShteryana Shopova struct vacm_user * 2849135f7de5SShteryana Shopova vacm_next_user(struct vacm_user *vuser) 2850135f7de5SShteryana Shopova { 2851135f7de5SShteryana Shopova if (vuser == NULL) 2852135f7de5SShteryana Shopova return (NULL); 2853135f7de5SShteryana Shopova 2854135f7de5SShteryana Shopova return (SLIST_NEXT(vuser, vvu)); 2855135f7de5SShteryana Shopova } 2856135f7de5SShteryana Shopova 2857135f7de5SShteryana Shopova static int 2858135f7de5SShteryana Shopova vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2859135f7de5SShteryana Shopova { 2860135f7de5SShteryana Shopova uint32_t i; 2861135f7de5SShteryana Shopova 2862135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 2863135f7de5SShteryana Shopova return (-1); 2864135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 2865135f7de5SShteryana Shopova return (1); 2866135f7de5SShteryana Shopova 2867135f7de5SShteryana Shopova if (strlen(v1->secname) < strlen(v2->secname)) 2868135f7de5SShteryana Shopova return (-1); 2869135f7de5SShteryana Shopova if (strlen(v1->secname) > strlen(v2->secname)) 2870135f7de5SShteryana Shopova return (1); 2871135f7de5SShteryana Shopova 2872135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->secname); i++) { 2873135f7de5SShteryana Shopova if (v1->secname[i] < v2->secname[i]) 2874135f7de5SShteryana Shopova return (-1); 2875135f7de5SShteryana Shopova if (v1->secname[i] > v2->secname[i]) 2876135f7de5SShteryana Shopova return (1); 2877135f7de5SShteryana Shopova } 2878135f7de5SShteryana Shopova 2879135f7de5SShteryana Shopova return (0); 2880135f7de5SShteryana Shopova } 2881135f7de5SShteryana Shopova 2882135f7de5SShteryana Shopova struct vacm_user * 2883135f7de5SShteryana Shopova vacm_new_user(int32_t smodel, char *uname) 2884135f7de5SShteryana Shopova { 2885135f7de5SShteryana Shopova int cmp; 2886135f7de5SShteryana Shopova struct vacm_user *user, *temp, *prev; 2887135f7de5SShteryana Shopova 2888135f7de5SShteryana Shopova SLIST_FOREACH(user, &vacm_userlist, vvu) 2889135f7de5SShteryana Shopova if (strcmp(uname, user->secname) == 0 && 2890135f7de5SShteryana Shopova smodel == user->sec_model) 2891135f7de5SShteryana Shopova return (NULL); 2892135f7de5SShteryana Shopova 2893135f7de5SShteryana Shopova if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2894135f7de5SShteryana Shopova return (NULL); 2895135f7de5SShteryana Shopova 2896135f7de5SShteryana Shopova memset(user, 0, sizeof(*user)); 2897135f7de5SShteryana Shopova user->group = &vacm_default_group; 2898135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2899135f7de5SShteryana Shopova user->sec_model = smodel; 2900135f7de5SShteryana Shopova strlcpy(user->secname, uname, sizeof(user->secname)); 2901135f7de5SShteryana Shopova 2902135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2903135f7de5SShteryana Shopova vacm_compare_user(user, prev) < 0) { 2904135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2905135f7de5SShteryana Shopova return (user); 2906135f7de5SShteryana Shopova } 2907135f7de5SShteryana Shopova 2908135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2909135f7de5SShteryana Shopova if ((cmp = vacm_compare_user(user, temp)) <= 0) 2910135f7de5SShteryana Shopova break; 2911135f7de5SShteryana Shopova prev = temp; 2912135f7de5SShteryana Shopova } 2913135f7de5SShteryana Shopova 2914135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 2915135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, user, vvu); 2916135f7de5SShteryana Shopova else if (cmp > 0) 2917135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, user, vvu); 2918135f7de5SShteryana Shopova else { 2919135f7de5SShteryana Shopova syslog(LOG_ERR, "User %s exists", user->secname); 2920135f7de5SShteryana Shopova free(user); 2921135f7de5SShteryana Shopova return (NULL); 2922135f7de5SShteryana Shopova } 2923135f7de5SShteryana Shopova 2924135f7de5SShteryana Shopova return (user); 2925135f7de5SShteryana Shopova } 2926135f7de5SShteryana Shopova 2927135f7de5SShteryana Shopova int 2928135f7de5SShteryana Shopova vacm_delete_user(struct vacm_user *user) 2929135f7de5SShteryana Shopova { 2930135f7de5SShteryana Shopova if (user->group != NULL && user->group != &vacm_default_group) { 2931135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2932135f7de5SShteryana Shopova if (SLIST_EMPTY(&user->group->group_users)) { 2933135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_grouplist, user->group, 2934135f7de5SShteryana Shopova vacm_group, vge); 2935135f7de5SShteryana Shopova free(user->group); 2936135f7de5SShteryana Shopova } 2937135f7de5SShteryana Shopova } 2938135f7de5SShteryana Shopova 2939135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2940135f7de5SShteryana Shopova free(user); 2941135f7de5SShteryana Shopova 2942135f7de5SShteryana Shopova return (0); 2943135f7de5SShteryana Shopova } 2944135f7de5SShteryana Shopova 2945135f7de5SShteryana Shopova int 2946135f7de5SShteryana Shopova vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2947135f7de5SShteryana Shopova { 2948135f7de5SShteryana Shopova struct vacm_group *group; 2949135f7de5SShteryana Shopova 2950135f7de5SShteryana Shopova if (len >= SNMP_ADM_STR32_SIZ) 2951135f7de5SShteryana Shopova return (-1); 2952135f7de5SShteryana Shopova 2953135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 2954135f7de5SShteryana Shopova if (strlen(group->groupname) == len && 2955135f7de5SShteryana Shopova memcmp(octets, group->groupname, len) == 0) 2956135f7de5SShteryana Shopova break; 2957135f7de5SShteryana Shopova 2958135f7de5SShteryana Shopova if (group == NULL) { 2959135f7de5SShteryana Shopova if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2960135f7de5SShteryana Shopova return (-1); 2961135f7de5SShteryana Shopova memset(group, 0, sizeof(*group)); 2962135f7de5SShteryana Shopova memcpy(group->groupname, octets, len); 2963135f7de5SShteryana Shopova group->groupname[len] = '\0'; 2964135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2965135f7de5SShteryana Shopova } 2966135f7de5SShteryana Shopova 2967135f7de5SShteryana Shopova SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2968135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2969135f7de5SShteryana Shopova user->group = group; 2970135f7de5SShteryana Shopova 2971135f7de5SShteryana Shopova return (0); 2972135f7de5SShteryana Shopova } 2973135f7de5SShteryana Shopova 2974135f7de5SShteryana Shopova void 2975135f7de5SShteryana Shopova vacm_groups_init(void) 2976135f7de5SShteryana Shopova { 2977135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2978135f7de5SShteryana Shopova } 2979135f7de5SShteryana Shopova 2980135f7de5SShteryana Shopova struct vacm_access * 2981135f7de5SShteryana Shopova vacm_first_access_rule(void) 2982135f7de5SShteryana Shopova { 2983135f7de5SShteryana Shopova return (TAILQ_FIRST(&vacm_accesslist)); 2984135f7de5SShteryana Shopova } 2985135f7de5SShteryana Shopova 2986135f7de5SShteryana Shopova struct vacm_access * 2987135f7de5SShteryana Shopova vacm_next_access_rule(struct vacm_access *acl) 2988135f7de5SShteryana Shopova { 2989135f7de5SShteryana Shopova if (acl == NULL) 2990135f7de5SShteryana Shopova return (NULL); 2991135f7de5SShteryana Shopova 2992135f7de5SShteryana Shopova return (TAILQ_NEXT(acl, vva)); 2993135f7de5SShteryana Shopova } 2994135f7de5SShteryana Shopova 2995135f7de5SShteryana Shopova static int 2996135f7de5SShteryana Shopova vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2997135f7de5SShteryana Shopova { 2998135f7de5SShteryana Shopova uint32_t i; 2999135f7de5SShteryana Shopova 3000135f7de5SShteryana Shopova if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 3001135f7de5SShteryana Shopova return (-1); 3002135f7de5SShteryana Shopova if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 3003135f7de5SShteryana Shopova return (1); 3004135f7de5SShteryana Shopova 3005135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->group->groupname); i++) { 3006135f7de5SShteryana Shopova if (v1->group->groupname[i] < v2->group->groupname[i]) 3007135f7de5SShteryana Shopova return (-1); 3008135f7de5SShteryana Shopova if (v1->group->groupname[i] > v2->group->groupname[i]) 3009135f7de5SShteryana Shopova return (1); 3010135f7de5SShteryana Shopova } 3011135f7de5SShteryana Shopova 3012135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 3013135f7de5SShteryana Shopova return (-1); 3014135f7de5SShteryana Shopova if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 3015135f7de5SShteryana Shopova return (1); 3016135f7de5SShteryana Shopova 3017135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->ctx_prefix); i++) { 3018135f7de5SShteryana Shopova if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 3019135f7de5SShteryana Shopova return (-1); 3020135f7de5SShteryana Shopova if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 3021135f7de5SShteryana Shopova return (1); 3022135f7de5SShteryana Shopova } 3023135f7de5SShteryana Shopova 3024135f7de5SShteryana Shopova if (v1->sec_model < v2->sec_model) 3025135f7de5SShteryana Shopova return (-1); 3026135f7de5SShteryana Shopova if (v1->sec_model > v2->sec_model) 3027135f7de5SShteryana Shopova return (1); 3028135f7de5SShteryana Shopova 3029135f7de5SShteryana Shopova if (v1->sec_level < v2->sec_level) 3030135f7de5SShteryana Shopova return (-1); 3031135f7de5SShteryana Shopova if (v1->sec_level > v2->sec_level) 3032135f7de5SShteryana Shopova return (1); 3033135f7de5SShteryana Shopova 3034135f7de5SShteryana Shopova return (0); 3035135f7de5SShteryana Shopova } 3036135f7de5SShteryana Shopova 3037135f7de5SShteryana Shopova struct vacm_access * 3038135f7de5SShteryana Shopova vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 3039135f7de5SShteryana Shopova { 3040135f7de5SShteryana Shopova struct vacm_group *group; 3041135f7de5SShteryana Shopova struct vacm_access *acl, *temp; 3042135f7de5SShteryana Shopova 3043135f7de5SShteryana Shopova TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 3044135f7de5SShteryana Shopova if (acl->group == NULL) 3045135f7de5SShteryana Shopova continue; 3046135f7de5SShteryana Shopova if (strcmp(gname, acl->group->groupname) == 0 && 3047135f7de5SShteryana Shopova strcmp(cprefix, acl->ctx_prefix) == 0 && 3048135f7de5SShteryana Shopova acl->sec_model == smodel && acl->sec_level == slevel) 3049135f7de5SShteryana Shopova return (NULL); 3050135f7de5SShteryana Shopova } 3051135f7de5SShteryana Shopova 3052135f7de5SShteryana Shopova /* Make sure the group exists */ 3053135f7de5SShteryana Shopova SLIST_FOREACH(group, &vacm_grouplist, vge) 3054135f7de5SShteryana Shopova if (strcmp(gname, group->groupname) == 0) 3055135f7de5SShteryana Shopova break; 3056135f7de5SShteryana Shopova 3057135f7de5SShteryana Shopova if (group == NULL) 3058135f7de5SShteryana Shopova return (NULL); 3059135f7de5SShteryana Shopova 3060135f7de5SShteryana Shopova if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 3061135f7de5SShteryana Shopova return (NULL); 3062135f7de5SShteryana Shopova 3063135f7de5SShteryana Shopova memset(acl, 0, sizeof(*acl)); 3064135f7de5SShteryana Shopova acl->group = group; 3065135f7de5SShteryana Shopova strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 3066135f7de5SShteryana Shopova acl->sec_model = smodel; 3067135f7de5SShteryana Shopova acl->sec_level = slevel; 3068135f7de5SShteryana Shopova 3069135f7de5SShteryana Shopova if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 3070135f7de5SShteryana Shopova vacm_compare_access_rule(acl, temp) < 0) { 3071135f7de5SShteryana Shopova TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 3072135f7de5SShteryana Shopova return (acl); 3073135f7de5SShteryana Shopova } 3074135f7de5SShteryana Shopova 3075135f7de5SShteryana Shopova TAILQ_FOREACH(temp, &vacm_accesslist, vva) 3076135f7de5SShteryana Shopova if (vacm_compare_access_rule(acl, temp) < 0) { 3077135f7de5SShteryana Shopova TAILQ_INSERT_BEFORE(temp, acl, vva); 3078135f7de5SShteryana Shopova return (acl); 3079135f7de5SShteryana Shopova } 3080135f7de5SShteryana Shopova 3081135f7de5SShteryana Shopova TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 3082135f7de5SShteryana Shopova 3083135f7de5SShteryana Shopova return (acl); 3084135f7de5SShteryana Shopova } 3085135f7de5SShteryana Shopova 3086135f7de5SShteryana Shopova int 3087135f7de5SShteryana Shopova vacm_delete_access_rule(struct vacm_access *acl) 3088135f7de5SShteryana Shopova { 3089135f7de5SShteryana Shopova TAILQ_REMOVE(&vacm_accesslist, acl, vva); 3090135f7de5SShteryana Shopova free(acl); 3091135f7de5SShteryana Shopova 3092135f7de5SShteryana Shopova return (0); 3093135f7de5SShteryana Shopova } 3094135f7de5SShteryana Shopova 3095135f7de5SShteryana Shopova struct vacm_view * 3096135f7de5SShteryana Shopova vacm_first_view(void) 3097135f7de5SShteryana Shopova { 3098135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_viewlist)); 3099135f7de5SShteryana Shopova } 3100135f7de5SShteryana Shopova 3101135f7de5SShteryana Shopova struct vacm_view * 3102135f7de5SShteryana Shopova vacm_next_view(struct vacm_view *view) 3103135f7de5SShteryana Shopova { 3104135f7de5SShteryana Shopova if (view == NULL) 3105135f7de5SShteryana Shopova return (NULL); 3106135f7de5SShteryana Shopova 3107135f7de5SShteryana Shopova return (SLIST_NEXT(view, vvl)); 3108135f7de5SShteryana Shopova } 3109135f7de5SShteryana Shopova 3110135f7de5SShteryana Shopova static int 3111135f7de5SShteryana Shopova vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3112135f7de5SShteryana Shopova { 3113135f7de5SShteryana Shopova uint32_t i; 3114135f7de5SShteryana Shopova 3115135f7de5SShteryana Shopova if (strlen(v1->viewname) < strlen(v2->viewname)) 3116135f7de5SShteryana Shopova return (-1); 3117135f7de5SShteryana Shopova if (strlen(v1->viewname) > strlen(v2->viewname)) 3118135f7de5SShteryana Shopova return (1); 3119135f7de5SShteryana Shopova 3120135f7de5SShteryana Shopova for (i = 0; i < strlen(v1->viewname); i++) { 3121135f7de5SShteryana Shopova if (v1->viewname[i] < v2->viewname[i]) 3122135f7de5SShteryana Shopova return (-1); 3123135f7de5SShteryana Shopova if (v1->viewname[i] > v2->viewname[i]) 3124135f7de5SShteryana Shopova return (1); 3125135f7de5SShteryana Shopova } 3126135f7de5SShteryana Shopova 3127135f7de5SShteryana Shopova return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3128135f7de5SShteryana Shopova } 3129135f7de5SShteryana Shopova 3130135f7de5SShteryana Shopova struct vacm_view * 3131135f7de5SShteryana Shopova vacm_new_view(char *vname, struct asn_oid *oid) 3132135f7de5SShteryana Shopova { 3133135f7de5SShteryana Shopova int cmp; 3134135f7de5SShteryana Shopova struct vacm_view *view, *temp, *prev; 3135135f7de5SShteryana Shopova 3136135f7de5SShteryana Shopova SLIST_FOREACH(view, &vacm_viewlist, vvl) 3137135f7de5SShteryana Shopova if (strcmp(vname, view->viewname) == 0) 3138135f7de5SShteryana Shopova return (NULL); 3139135f7de5SShteryana Shopova 3140135f7de5SShteryana Shopova if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3141135f7de5SShteryana Shopova return (NULL); 3142135f7de5SShteryana Shopova 3143135f7de5SShteryana Shopova memset(view, 0, sizeof(*view)); 3144135f7de5SShteryana Shopova strlcpy(view->viewname, vname, sizeof(view->viewname)); 3145135f7de5SShteryana Shopova asn_append_oid(&view->subtree, oid); 3146135f7de5SShteryana Shopova 3147135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3148135f7de5SShteryana Shopova vacm_compare_view(view, prev) < 0) { 3149135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3150135f7de5SShteryana Shopova return (view); 3151135f7de5SShteryana Shopova } 3152135f7de5SShteryana Shopova 3153135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3154135f7de5SShteryana Shopova if ((cmp = vacm_compare_view(view, temp)) <= 0) 3155135f7de5SShteryana Shopova break; 3156135f7de5SShteryana Shopova prev = temp; 3157135f7de5SShteryana Shopova } 3158135f7de5SShteryana Shopova 3159135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3160135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, view, vvl); 3161135f7de5SShteryana Shopova else if (cmp > 0) 3162135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, view, vvl); 3163135f7de5SShteryana Shopova else { 3164135f7de5SShteryana Shopova syslog(LOG_ERR, "View %s exists", view->viewname); 3165135f7de5SShteryana Shopova free(view); 3166135f7de5SShteryana Shopova return (NULL); 3167135f7de5SShteryana Shopova } 3168135f7de5SShteryana Shopova 3169135f7de5SShteryana Shopova return (view); 3170135f7de5SShteryana Shopova } 3171135f7de5SShteryana Shopova 3172135f7de5SShteryana Shopova int 3173135f7de5SShteryana Shopova vacm_delete_view(struct vacm_view *view) 3174135f7de5SShteryana Shopova { 3175135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3176135f7de5SShteryana Shopova free(view); 3177135f7de5SShteryana Shopova 3178135f7de5SShteryana Shopova return (0); 3179135f7de5SShteryana Shopova } 3180135f7de5SShteryana Shopova 3181135f7de5SShteryana Shopova struct vacm_context * 3182135f7de5SShteryana Shopova vacm_first_context(void) 3183135f7de5SShteryana Shopova { 3184135f7de5SShteryana Shopova return (SLIST_FIRST(&vacm_contextlist)); 3185135f7de5SShteryana Shopova } 3186135f7de5SShteryana Shopova 3187135f7de5SShteryana Shopova struct vacm_context * 3188135f7de5SShteryana Shopova vacm_next_context(struct vacm_context *vacmctx) 3189135f7de5SShteryana Shopova { 3190135f7de5SShteryana Shopova if (vacmctx == NULL) 3191135f7de5SShteryana Shopova return (NULL); 3192135f7de5SShteryana Shopova 3193135f7de5SShteryana Shopova return (SLIST_NEXT(vacmctx, vcl)); 3194135f7de5SShteryana Shopova } 3195135f7de5SShteryana Shopova 3196135f7de5SShteryana Shopova struct vacm_context * 3197135f7de5SShteryana Shopova vacm_add_context(char *ctxname, int regid) 3198135f7de5SShteryana Shopova { 3199135f7de5SShteryana Shopova int cmp; 3200135f7de5SShteryana Shopova struct vacm_context *ctx, *temp, *prev; 3201135f7de5SShteryana Shopova 3202135f7de5SShteryana Shopova SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3203135f7de5SShteryana Shopova if (strcmp(ctxname, ctx->ctxname) == 0) { 3204135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3205135f7de5SShteryana Shopova return (NULL); 3206135f7de5SShteryana Shopova } 3207135f7de5SShteryana Shopova 3208135f7de5SShteryana Shopova if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3209135f7de5SShteryana Shopova return (NULL); 3210135f7de5SShteryana Shopova 3211135f7de5SShteryana Shopova memset(ctx, 0, sizeof(*ctx)); 3212135f7de5SShteryana Shopova strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3213135f7de5SShteryana Shopova ctx->regid = regid; 3214135f7de5SShteryana Shopova 3215135f7de5SShteryana Shopova if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3216135f7de5SShteryana Shopova strlen(ctx->ctxname) < strlen(prev->ctxname) || 3217135f7de5SShteryana Shopova strcmp(ctx->ctxname, prev->ctxname) < 0) { 3218135f7de5SShteryana Shopova SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3219135f7de5SShteryana Shopova return (ctx); 3220135f7de5SShteryana Shopova } 3221135f7de5SShteryana Shopova 3222135f7de5SShteryana Shopova SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3223135f7de5SShteryana Shopova if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3224135f7de5SShteryana Shopova strcmp(ctx->ctxname, temp->ctxname) < 0) { 3225135f7de5SShteryana Shopova cmp = -1; 3226135f7de5SShteryana Shopova break; 3227135f7de5SShteryana Shopova } 3228135f7de5SShteryana Shopova prev = temp; 3229135f7de5SShteryana Shopova } 3230135f7de5SShteryana Shopova 3231135f7de5SShteryana Shopova if (temp == NULL || cmp < 0) 3232135f7de5SShteryana Shopova SLIST_INSERT_AFTER(prev, ctx, vcl); 3233135f7de5SShteryana Shopova else if (cmp > 0) 3234135f7de5SShteryana Shopova SLIST_INSERT_AFTER(temp, ctx, vcl); 3235135f7de5SShteryana Shopova else { 3236135f7de5SShteryana Shopova syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3237135f7de5SShteryana Shopova free(ctx); 3238135f7de5SShteryana Shopova return (NULL); 3239135f7de5SShteryana Shopova } 3240135f7de5SShteryana Shopova 3241135f7de5SShteryana Shopova return (ctx); 3242135f7de5SShteryana Shopova } 3243135f7de5SShteryana Shopova 3244135f7de5SShteryana Shopova void 3245135f7de5SShteryana Shopova vacm_flush_contexts(int regid) 3246135f7de5SShteryana Shopova { 3247135f7de5SShteryana Shopova struct vacm_context *ctx, *temp; 3248135f7de5SShteryana Shopova 3249135f7de5SShteryana Shopova SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3250135f7de5SShteryana Shopova if (ctx->regid == regid) { 3251135f7de5SShteryana Shopova SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3252135f7de5SShteryana Shopova free(ctx); 3253135f7de5SShteryana Shopova } 3254135f7de5SShteryana Shopova } 3255