1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7133211Sharti * 8216594Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation 9216594Ssyrinx * All rights reserved. 10216594Ssyrinx * 11216594Ssyrinx * Portions of this software were developed by Shteryana Sotirova Shopova 12216594Ssyrinx * under sponsorship from the FreeBSD Foundation. 13216594Ssyrinx * 14133211Sharti * Redistribution and use in source and binary forms, with or without 15133211Sharti * modification, are permitted provided that the following conditions 16133211Sharti * are met: 17133211Sharti * 1. Redistributions of source code must retain the above copyright 18133211Sharti * notice, this list of conditions and the following disclaimer. 19122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 20122394Sharti * notice, this list of conditions and the following disclaimer in the 21122394Sharti * documentation and/or other materials provided with the distribution. 22133211Sharti * 23133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33133211Sharti * SUCH DAMAGE. 34122394Sharti * 35156066Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 36122394Sharti * 37122394Sharti * SNMPd main stuff. 38122394Sharti */ 39216294Ssyrinx 40216294Ssyrinx#include <sys/queue.h> 41122394Sharti#include <sys/param.h> 42122394Sharti#include <sys/un.h> 43124861Sharti#include <sys/ucred.h> 44150920Sharti#include <sys/uio.h> 45122394Sharti#include <stdio.h> 46122394Sharti#include <stdlib.h> 47122394Sharti#include <stddef.h> 48122394Sharti#include <string.h> 49122394Sharti#include <stdarg.h> 50122394Sharti#include <ctype.h> 51122394Sharti#include <errno.h> 52122394Sharti#include <syslog.h> 53122394Sharti#include <unistd.h> 54122394Sharti#include <signal.h> 55122394Sharti#include <dlfcn.h> 56122394Sharti#include <inttypes.h> 57122394Sharti 58145557Sharti#ifdef USE_TCPWRAPPERS 59145557Sharti#include <arpa/inet.h> 60145557Sharti#include <tcpd.h> 61145557Sharti#endif 62145557Sharti 63156066Sharti#include "support.h" 64122394Sharti#include "snmpmod.h" 65122394Sharti#include "snmpd.h" 66122394Sharti#include "tree.h" 67122394Sharti#include "oid.h" 68122394Sharti 69122394Sharti#define PATH_PID "/var/run/%s.pid" 70122394Sharti#define PATH_CONFIG "/etc/%s.config" 71216294Ssyrinx#define PATH_ENGINE "/var/%s.engine" 72122394Sharti 73146525Shartiuint64_t this_tick; /* start of processing of current packet (absolute) */ 74146525Shartiuint64_t start_tick; /* start of processing */ 75122394Sharti 76122394Shartistruct systemg systemg = { 77122394Sharti NULL, 78122394Sharti { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 79122394Sharti NULL, NULL, NULL, 80122394Sharti 64 + 8 + 4, 81122394Sharti 0 82122394Sharti}; 83122394Shartistruct debug debug = { 84122394Sharti 0, /* dump_pdus */ 85122394Sharti LOG_DEBUG, /* log_pri */ 86122394Sharti 0, /* evdebug */ 87122394Sharti}; 88122394Sharti 89122394Shartistruct snmpd snmpd = { 90122394Sharti 2048, /* txbuf */ 91122394Sharti 2048, /* rxbuf */ 92122394Sharti 0, /* comm_dis */ 93122394Sharti 0, /* auth_traps */ 94122394Sharti {0, 0, 0, 0}, /* trap1addr */ 95124861Sharti VERS_ENABLE_ALL,/* version_enable */ 96122394Sharti}; 97122394Shartistruct snmpd_stats snmpd_stats; 98122394Sharti 99216294Ssyrinxstruct snmpd_usmstat snmpd_usmstats; 100216294Ssyrinx 101216294Ssyrinx/* snmpEngine */ 102216294Ssyrinxstruct snmp_engine snmpd_engine; 103216294Ssyrinx 104122394Sharti/* snmpSerialNo */ 105122394Shartiint32_t snmp_serial_no; 106122394Sharti 107216594Ssyrinxstruct snmpd_target_stats snmpd_target_stats; 108216594Ssyrinx 109122394Sharti/* search path for config files */ 110122394Sharticonst char *syspath = PATH_SYSCONFIG; 111122394Sharti 112122394Sharti/* list of all loaded modules */ 113122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 114122394Sharti 115122394Sharti/* list of loaded modules during start-up in the order they were loaded */ 116122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 117122394Sharti 118122394Sharti/* list of all known communities */ 119122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 120122394Sharti 121216294Ssyrinx/* list of all known USM users */ 122216294Ssyrinxstruct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 123216294Ssyrinx 124216294Ssyrinx/* A list of all VACM users configured, including v1, v2c and v3 */ 125216294Ssyrinxstruct vacm_userlist vacm_userlist = SLIST_HEAD_INITIALIZER(vacm_userlist); 126216294Ssyrinx 127216294Ssyrinx/* A list of all VACM groups */ 128216294Ssyrinxstruct vacm_grouplist vacm_grouplist = SLIST_HEAD_INITIALIZER(vacm_grouplist); 129216294Ssyrinx 130216294Ssyrinxstatic struct vacm_group vacm_default_group = { 131216294Ssyrinx .groupname = "", 132216294Ssyrinx}; 133216294Ssyrinx 134216294Ssyrinx/* The list of configured access entries */ 135216294Ssyrinxstruct vacm_accesslist vacm_accesslist = TAILQ_HEAD_INITIALIZER(vacm_accesslist); 136216294Ssyrinx 137216294Ssyrinx/* The list of configured views */ 138216294Ssyrinxstruct vacm_viewlist vacm_viewlist = SLIST_HEAD_INITIALIZER(vacm_viewlist); 139216294Ssyrinx 140216294Ssyrinx/* The list of configured contexts */ 141216294Ssyrinxstruct vacm_contextlist vacm_contextlist = 142216294Ssyrinx SLIST_HEAD_INITIALIZER(vacm_contextlist); 143216294Ssyrinx 144122394Sharti/* list of all installed object resources */ 145122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 146122394Sharti 147122394Sharti/* community value generator */ 148122394Shartistatic u_int next_community_index = 1; 149122394Sharti 150122394Sharti/* list of all known ranges */ 151122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 152122394Sharti 153122394Sharti/* identifier generator */ 154122394Shartiu_int next_idrange = 1; 155122394Sharti 156122394Sharti/* list of all current timers */ 157122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 158122394Sharti 159122394Sharti/* list of file descriptors */ 160122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 161122394Sharti 162122394Sharti/* program arguments */ 163122394Shartistatic char **progargs; 164122394Shartistatic int nprogargs; 165122394Sharti 166122394Sharti/* current community */ 167122394Shartiu_int community; 168122394Shartistatic struct community *comm; 169122394Sharti 170216294Ssyrinx/* current USM user */ 171216294Ssyrinxstruct usm_user *usm_user; 172216294Ssyrinx 173122394Sharti/* file names */ 174122394Shartistatic char config_file[MAXPATHLEN + 1]; 175122394Shartistatic char pid_file[MAXPATHLEN + 1]; 176216294Ssyrinxchar engine_file[MAXPATHLEN + 1]; 177122394Sharti 178124861Sharti#ifndef USE_LIBBEGEMOT 179122394Sharti/* event context */ 180122394Shartistatic evContext evctx; 181124861Sharti#endif 182122394Sharti 183122394Sharti/* signal mask */ 184122394Shartistatic sigset_t blocked_sigs; 185122394Sharti 186122394Sharti/* signal handling */ 187122394Shartistatic int work; 188122394Sharti#define WORK_DOINFO 0x0001 189122394Sharti#define WORK_RECONFIG 0x0002 190122394Sharti 191122394Sharti/* oids */ 192122394Shartistatic const struct asn_oid 193122394Sharti oid_snmpMIB = OIDX_snmpMIB, 194122394Sharti oid_begemotSnmpd = OIDX_begemotSnmpd, 195122394Sharti oid_coldStart = OIDX_coldStart, 196122394Sharti oid_authenticationFailure = OIDX_authenticationFailure; 197122394Sharti 198122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 199122394Sharti 200216294Ssyrinxconst struct asn_oid oid_usmUnknownEngineIDs = 201216294Ssyrinx { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 202216294Ssyrinx 203216294Ssyrinxconst struct asn_oid oid_usmNotInTimeWindows = 204216294Ssyrinx { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 205216294Ssyrinx 206122394Sharti/* request id generator for traps */ 207122394Shartiu_int trap_reqid; 208122394Sharti 209122394Sharti/* help text */ 210122394Shartistatic const char usgtxt[] = "\ 211122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 212122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 213216294SsyrinxCopyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 214216294Ssyrinxusage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 215216294Ssyrinx [-l prefix] [-m variable=value] [-p file]\n\ 216122394Shartioptions:\n\ 217122394Sharti -d don't daemonize\n\ 218122394Sharti -h print this info\n\ 219122394Sharti -c file specify configuration file\n\ 220122394Sharti -D options debugging options\n\ 221216294Ssyrinx -e file specify engine id file\n\ 222122394Sharti -I path system include path\n\ 223122394Sharti -l prefix default basename for pid and config file\n\ 224122394Sharti -m var=val define variable\n\ 225122394Sharti -p file specify pid file\n\ 226122394Sharti"; 227122394Sharti 228145557Sharti/* hosts_access(3) request */ 229145557Sharti#ifdef USE_TCPWRAPPERS 230145557Shartistatic struct request_info req; 231145557Sharti#endif 232145557Sharti 233124861Sharti/* transports */ 234124861Shartiextern const struct transport_def udp_trans; 235124861Shartiextern const struct transport_def lsock_trans; 236124861Sharti 237124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 238124861Sharti 239122394Sharti/* forward declarations */ 240122394Shartistatic void snmp_printf_func(const char *fmt, ...); 241122394Shartistatic void snmp_error_func(const char *err, ...); 242122394Shartistatic void snmp_debug_func(const char *err, ...); 243122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...); 244122394Sharti 245122394Sharti/* 246122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx. 247122394Sharti */ 248122394Shartivoid * 249122394Shartibuf_alloc(int tx) 250122394Sharti{ 251122394Sharti void *buf; 252122394Sharti 253124861Sharti if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 254122394Sharti syslog(LOG_CRIT, "cannot allocate buffer"); 255122394Sharti if (tx) 256122394Sharti snmpd_stats.noTxbuf++; 257122394Sharti else 258122394Sharti snmpd_stats.noRxbuf++; 259122394Sharti return (NULL); 260122394Sharti } 261122394Sharti return (buf); 262122394Sharti} 263122394Sharti 264122394Sharti/* 265124861Sharti * Return the buffer size. 266122394Sharti */ 267122394Shartisize_t 268122394Shartibuf_size(int tx) 269122394Sharti{ 270124861Sharti return (tx ? snmpd.txbuf : snmpd.rxbuf); 271122394Sharti} 272122394Sharti 273122394Sharti/* 274122394Sharti * Prepare a PDU for output 275122394Sharti */ 276122394Shartivoid 277124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 278122394Sharti const char *dest) 279122394Sharti{ 280122394Sharti struct asn_buf resp_b; 281122394Sharti 282122394Sharti resp_b.asn_ptr = sndbuf; 283122394Sharti resp_b.asn_len = snmpd.txbuf; 284122394Sharti 285122394Sharti if (snmp_pdu_encode(pdu, &resp_b) != 0) { 286122394Sharti syslog(LOG_ERR, "cannot encode message"); 287122394Sharti abort(); 288122394Sharti } 289122394Sharti if (debug.dump_pdus) { 290122394Sharti snmp_printf("%s <- ", dest); 291122394Sharti snmp_pdu_dump(pdu); 292122394Sharti } 293122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 294122394Sharti} 295122394Sharti 296122394Sharti/* 297216294Ssyrinx * Check USM PDU header credentials against local SNMP Engine & users. 298122394Sharti */ 299216294Ssyrinxstatic enum snmp_code 300216294Ssyrinxsnmp_pdu_auth_user(struct snmp_pdu *pdu) 301216294Ssyrinx{ 302216294Ssyrinx uint64_t etime; 303216294Ssyrinx usm_user = NULL; 304216294Ssyrinx 305216294Ssyrinx /* un-authenticated snmpEngineId discovery */ 306216294Ssyrinx if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 307216294Ssyrinx pdu->engine.engine_len = snmpd_engine.engine_len; 308216294Ssyrinx memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 309216294Ssyrinx snmpd_engine.engine_len); 310216294Ssyrinx pdu->engine.engine_boots = snmpd_engine.engine_boots; 311216294Ssyrinx pdu->engine.engine_time = snmpd_engine.engine_time; 312216294Ssyrinx pdu->flags |= SNMP_MSG_AUTODISCOVER; 313216294Ssyrinx return (SNMP_CODE_OK); 314216294Ssyrinx } 315216294Ssyrinx 316216294Ssyrinx if ((usm_user = usm_find_user(pdu->engine.engine_id, 317216294Ssyrinx pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 318216294Ssyrinx usm_user->status != 1 /* active */) 319216294Ssyrinx return (SNMP_CODE_BADUSER); 320216294Ssyrinx 321216294Ssyrinx if (usm_user->user_engine_len != snmpd_engine.engine_len || 322216294Ssyrinx memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 323216294Ssyrinx snmpd_engine.engine_len) != 0) 324216294Ssyrinx return (SNMP_CODE_BADENGINE); 325216294Ssyrinx 326216294Ssyrinx pdu->user.priv_proto = usm_user->suser.priv_proto; 327216294Ssyrinx memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 328216294Ssyrinx sizeof(pdu->user.priv_key)); 329216294Ssyrinx 330216294Ssyrinx /* authenticated snmpEngineId discovery */ 331216294Ssyrinx if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 332216294Ssyrinx etime = (get_ticks() - start_tick) / 100ULL; 333216294Ssyrinx if (etime < INT32_MAX) 334216294Ssyrinx snmpd_engine.engine_time = etime; 335216294Ssyrinx else { 336216294Ssyrinx start_tick = get_ticks(); 337216294Ssyrinx set_snmpd_engine(); 338216294Ssyrinx snmpd_engine.engine_time = start_tick; 339216294Ssyrinx } 340216294Ssyrinx 341216294Ssyrinx pdu->user.auth_proto = usm_user->suser.auth_proto; 342216294Ssyrinx memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 343216294Ssyrinx sizeof(pdu->user.auth_key)); 344216294Ssyrinx 345216294Ssyrinx if (pdu->engine.engine_boots == 0 && 346216294Ssyrinx pdu->engine.engine_time == 0) { 347216294Ssyrinx pdu->flags |= SNMP_MSG_AUTODISCOVER; 348216294Ssyrinx return (SNMP_CODE_OK); 349216294Ssyrinx } 350216294Ssyrinx 351216294Ssyrinx if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 352216294Ssyrinx abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 353216294Ssyrinx SNMP_TIME_WINDOW) 354216294Ssyrinx return (SNMP_CODE_NOTINTIME); 355216294Ssyrinx } 356216294Ssyrinx 357216294Ssyrinx if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 358216294Ssyrinx (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 359216294Ssyrinx ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 360216294Ssyrinx usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 361216294Ssyrinx ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 362216294Ssyrinx usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 363216294Ssyrinx return (SNMP_CODE_BADSECLEVEL); 364216294Ssyrinx 365216294Ssyrinx return (SNMP_CODE_OK); 366216294Ssyrinx} 367216294Ssyrinx 368216294Ssyrinx/* 369216294Ssyrinx * Check whether access to each of var bindings in the PDU is allowed based 370216294Ssyrinx * on the user credentials against the configured User groups & VACM views. 371216294Ssyrinx */ 372216594Ssyrinxenum snmp_code 373216294Ssyrinxsnmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 374216294Ssyrinx{ 375216294Ssyrinx const char *uname; 376216294Ssyrinx int32_t suboid, smodel; 377216294Ssyrinx uint32_t i; 378216294Ssyrinx struct vacm_user *vuser; 379216294Ssyrinx struct vacm_access *acl; 380216294Ssyrinx struct vacm_context *vacmctx; 381216294Ssyrinx struct vacm_view *view; 382216294Ssyrinx 383216294Ssyrinx /* 384216294Ssyrinx * At least a default context exists if the snmpd_vacm(3) module is 385216294Ssyrinx * running. 386216294Ssyrinx */ 387216294Ssyrinx if (SLIST_EMPTY(&vacm_contextlist) || 388216294Ssyrinx (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 389216294Ssyrinx return (SNMP_CODE_OK); 390216294Ssyrinx 391216294Ssyrinx switch (pdu->version) { 392216294Ssyrinx case SNMP_V1: 393216294Ssyrinx if ((uname = comm_string(community)) == NULL) 394216294Ssyrinx return (SNMP_CODE_FAILED); 395216294Ssyrinx smodel = SNMP_SECMODEL_SNMPv1; 396216294Ssyrinx break; 397216294Ssyrinx 398216294Ssyrinx case SNMP_V2c: 399216294Ssyrinx if ((uname = comm_string(community)) == NULL) 400216294Ssyrinx return (SNMP_CODE_FAILED); 401216294Ssyrinx smodel = SNMP_SECMODEL_SNMPv2c; 402216294Ssyrinx break; 403216294Ssyrinx 404216294Ssyrinx case SNMP_V3: 405216294Ssyrinx uname = pdu->user.sec_name; 406216294Ssyrinx if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 407216294Ssyrinx return (SNMP_CODE_FAILED); 408216294Ssyrinx /* Compare the PDU context engine id against the agent's */ 409216294Ssyrinx if (pdu->context_engine_len != snmpd_engine.engine_len || 410216294Ssyrinx memcmp(pdu->context_engine, snmpd_engine.engine_id, 411216294Ssyrinx snmpd_engine.engine_len) != 0) 412216294Ssyrinx return (SNMP_CODE_FAILED); 413216294Ssyrinx break; 414216294Ssyrinx 415216294Ssyrinx default: 416216294Ssyrinx abort(); 417216294Ssyrinx } 418216294Ssyrinx 419216294Ssyrinx SLIST_FOREACH(vuser, &vacm_userlist, vvu) 420216294Ssyrinx if (strcmp(uname, vuser->secname) == 0 && 421216294Ssyrinx vuser->sec_model == smodel) 422216294Ssyrinx break; 423216294Ssyrinx 424216294Ssyrinx if (vuser == NULL || vuser->group == NULL) 425216294Ssyrinx return (SNMP_CODE_FAILED); 426216294Ssyrinx 427216294Ssyrinx /* XXX: shteryana - recheck */ 428216294Ssyrinx TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 429216294Ssyrinx if (acl->group != vuser->group) 430216294Ssyrinx continue; 431216294Ssyrinx SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 432216294Ssyrinx if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 433216294Ssyrinx acl->ctx_match) == 0) 434216294Ssyrinx goto match; 435216294Ssyrinx } 436216294Ssyrinx 437216294Ssyrinx return (SNMP_CODE_FAILED); 438216294Ssyrinx 439216294Ssyrinxmatch: 440216294Ssyrinx 441216294Ssyrinx switch (pdu->type) { 442216294Ssyrinx case SNMP_PDU_GET: 443216294Ssyrinx case SNMP_PDU_GETNEXT: 444216294Ssyrinx case SNMP_PDU_GETBULK: 445216294Ssyrinx if ((view = acl->read_view) == NULL) 446216294Ssyrinx return (SNMP_CODE_FAILED); 447216294Ssyrinx break; 448216294Ssyrinx 449216294Ssyrinx case SNMP_PDU_SET: 450216294Ssyrinx if ((view = acl->write_view) == NULL) 451216294Ssyrinx return (SNMP_CODE_FAILED); 452216294Ssyrinx break; 453216294Ssyrinx 454216294Ssyrinx case SNMP_PDU_TRAP: 455216294Ssyrinx case SNMP_PDU_INFORM: 456216294Ssyrinx case SNMP_PDU_TRAP2: 457216294Ssyrinx case SNMP_PDU_REPORT: 458216294Ssyrinx if ((view = acl->notify_view) == NULL) 459216294Ssyrinx return (SNMP_CODE_FAILED); 460216294Ssyrinx break; 461216294Ssyrinx case SNMP_PDU_RESPONSE: 462216294Ssyrinx /* NOTREACHED */ 463216294Ssyrinx return (SNMP_CODE_FAILED); 464216294Ssyrinx default: 465216294Ssyrinx abort(); 466216294Ssyrinx } 467216294Ssyrinx 468216294Ssyrinx for (i = 0; i < pdu->nbindings; i++) { 469216294Ssyrinx /* XXX - view->mask*/ 470216294Ssyrinx suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 471216294Ssyrinx if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 472216294Ssyrinx *ip = i + 1; 473216294Ssyrinx return (SNMP_CODE_FAILED); 474216294Ssyrinx } 475216294Ssyrinx } 476216294Ssyrinx 477216294Ssyrinx return (SNMP_CODE_OK); 478216294Ssyrinx} 479216294Ssyrinx 480216294Ssyrinx/* 481216294Ssyrinx * SNMP input. Start: decode the PDU, find the user or community. 482216294Ssyrinx */ 483122394Shartienum snmpd_input_err 484122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source, 485124861Sharti struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 486122394Sharti{ 487122394Sharti struct asn_buf b; 488122394Sharti enum snmp_code code; 489122394Sharti enum snmpd_input_err ret; 490124861Sharti int sret; 491122394Sharti 492216294Ssyrinx /* update uptime */ 493216294Ssyrinx this_tick = get_ticks(); 494216294Ssyrinx 495122394Sharti b.asn_cptr = buf; 496122394Sharti b.asn_len = len; 497124861Sharti 498124861Sharti /* look whether we have enough bytes for the entire PDU. */ 499124861Sharti switch (sret = snmp_pdu_snoop(&b)) { 500124861Sharti 501124861Sharti case 0: 502124861Sharti return (SNMPD_INPUT_TRUNC); 503124861Sharti 504124861Sharti case -1: 505124861Sharti snmpd_stats.inASNParseErrs++; 506124861Sharti return (SNMPD_INPUT_FAILED); 507124861Sharti } 508124861Sharti b.asn_len = *pdulen = (size_t)sret; 509124861Sharti 510216294Ssyrinx memset(pdu, 0, sizeof(*pdu)); 511216294Ssyrinx if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 512216294Ssyrinx goto decoded; 513122394Sharti 514216294Ssyrinx if (pdu->version == SNMP_V3) { 515216294Ssyrinx if (pdu->security_model != SNMP_SECMODEL_USM) { 516216294Ssyrinx code = SNMP_CODE_FAILED; 517216294Ssyrinx goto decoded; 518216294Ssyrinx } 519216294Ssyrinx if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 520216294Ssyrinx goto decoded; 521216294Ssyrinx if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 522216294Ssyrinx goto decoded; 523216294Ssyrinx } 524216294Ssyrinx code = snmp_pdu_decode_scoped(&b, pdu, ip); 525216294Ssyrinx 526216294Ssyrinx ret = SNMPD_INPUT_OK; 527216294Ssyrinx 528216294Ssyrinxdecoded: 529124861Sharti snmpd_stats.inPkts++; 530124861Sharti 531122394Sharti switch (code) { 532122394Sharti 533122394Sharti case SNMP_CODE_FAILED: 534122394Sharti snmpd_stats.inASNParseErrs++; 535122394Sharti return (SNMPD_INPUT_FAILED); 536122394Sharti 537122394Sharti case SNMP_CODE_BADVERS: 538124861Sharti bad_vers: 539122394Sharti snmpd_stats.inBadVersions++; 540122394Sharti return (SNMPD_INPUT_FAILED); 541122394Sharti 542122394Sharti case SNMP_CODE_BADLEN: 543122394Sharti if (pdu->type == SNMP_OP_SET) 544122394Sharti ret = SNMPD_INPUT_VALBADLEN; 545122394Sharti break; 546122394Sharti 547122394Sharti case SNMP_CODE_OORANGE: 548122394Sharti if (pdu->type == SNMP_OP_SET) 549122394Sharti ret = SNMPD_INPUT_VALRANGE; 550122394Sharti break; 551122394Sharti 552122394Sharti case SNMP_CODE_BADENC: 553122394Sharti if (pdu->type == SNMP_OP_SET) 554122394Sharti ret = SNMPD_INPUT_VALBADENC; 555122394Sharti break; 556122394Sharti 557216294Ssyrinx case SNMP_CODE_BADSECLEVEL: 558216294Ssyrinx snmpd_usmstats.unsupported_seclevels++; 559216294Ssyrinx return (SNMPD_INPUT_FAILED); 560216294Ssyrinx 561216294Ssyrinx case SNMP_CODE_NOTINTIME: 562216294Ssyrinx snmpd_usmstats.not_in_time_windows++; 563216294Ssyrinx return (SNMPD_INPUT_FAILED); 564216294Ssyrinx 565216294Ssyrinx case SNMP_CODE_BADUSER: 566216294Ssyrinx snmpd_usmstats.unknown_users++; 567216294Ssyrinx return (SNMPD_INPUT_FAILED); 568216294Ssyrinx 569216294Ssyrinx case SNMP_CODE_BADENGINE: 570216294Ssyrinx snmpd_usmstats.unknown_engine_ids++; 571216294Ssyrinx return (SNMPD_INPUT_FAILED); 572216294Ssyrinx 573216294Ssyrinx case SNMP_CODE_BADDIGEST: 574216294Ssyrinx snmpd_usmstats.wrong_digests++; 575216294Ssyrinx return (SNMPD_INPUT_FAILED); 576216294Ssyrinx 577216294Ssyrinx case SNMP_CODE_EDECRYPT: 578216294Ssyrinx snmpd_usmstats.decrypt_errors++; 579216294Ssyrinx return (SNMPD_INPUT_FAILED); 580216294Ssyrinx 581122394Sharti case SNMP_CODE_OK: 582124861Sharti switch (pdu->version) { 583124861Sharti 584124861Sharti case SNMP_V1: 585124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V1)) 586124861Sharti goto bad_vers; 587124861Sharti break; 588124861Sharti 589124861Sharti case SNMP_V2c: 590124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 591124861Sharti goto bad_vers; 592124861Sharti break; 593124861Sharti 594216294Ssyrinx case SNMP_V3: 595216294Ssyrinx if (!(snmpd.version_enable & VERS_ENABLE_V3)) 596216294Ssyrinx goto bad_vers; 597216294Ssyrinx break; 598216294Ssyrinx 599124861Sharti case SNMP_Verr: 600124861Sharti goto bad_vers; 601124861Sharti } 602122394Sharti break; 603122394Sharti } 604122394Sharti 605122394Sharti if (debug.dump_pdus) { 606122394Sharti snmp_printf("%s -> ", source); 607122394Sharti snmp_pdu_dump(pdu); 608122394Sharti } 609122394Sharti 610122394Sharti /* 611216294Ssyrinx * Look, whether we know the community or user 612122394Sharti */ 613122394Sharti 614216294Ssyrinx if (pdu->version != SNMP_V3) { 615216294Ssyrinx TAILQ_FOREACH(comm, &community_list, link) 616216294Ssyrinx if (comm->string != NULL && 617216294Ssyrinx strcmp(comm->string, pdu->community) == 0) 618216294Ssyrinx break; 619122394Sharti 620216294Ssyrinx if (comm == NULL) { 621216294Ssyrinx snmpd_stats.inBadCommunityNames++; 622216294Ssyrinx snmp_pdu_free(pdu); 623216294Ssyrinx if (snmpd.auth_traps) 624216294Ssyrinx snmp_send_trap(&oid_authenticationFailure, 625216294Ssyrinx (struct snmp_value *)NULL); 626216294Ssyrinx ret = SNMPD_INPUT_BAD_COMM; 627216294Ssyrinx } else 628216294Ssyrinx community = comm->value; 629216294Ssyrinx } else if (pdu->nbindings == 0) { 630216294Ssyrinx /* RFC 3414 - snmpEngineID Discovery */ 631216294Ssyrinx if (strlen(pdu->user.sec_name) == 0) { 632216294Ssyrinx asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 633216294Ssyrinx &oid_usmUnknownEngineIDs); 634216294Ssyrinx pdu->context_engine_len = snmpd_engine.engine_len; 635216294Ssyrinx memcpy(pdu->context_engine, snmpd_engine.engine_id, 636216294Ssyrinx snmpd_engine.engine_len); 637216294Ssyrinx } else if (pdu->engine.engine_boots == 0 && 638216294Ssyrinx pdu->engine.engine_time == 0) { 639216294Ssyrinx asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 640216294Ssyrinx &oid_usmNotInTimeWindows); 641216294Ssyrinx pdu->engine.engine_boots = snmpd_engine.engine_boots; 642216294Ssyrinx pdu->engine.engine_time = snmpd_engine.engine_time; 643216294Ssyrinx } 644216294Ssyrinx } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 645216294Ssyrinx (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 646216294Ssyrinx snmpd_usmstats.not_in_time_windows++; 647216294Ssyrinx ret = SNMP_CODE_FAILED; 648216294Ssyrinx } 649122394Sharti 650216294Ssyrinx if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 651216294Ssyrinx ret = SNMP_CODE_FAILED; 652216294Ssyrinx 653122394Sharti return (ret); 654122394Sharti} 655122394Sharti 656122394Sharti/* 657122394Sharti * Will return only _OK or _FAILED 658122394Sharti */ 659122394Shartienum snmpd_input_err 660122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 661122394Sharti u_char *sndbuf, size_t *sndlen, const char *source, 662122394Sharti enum snmpd_input_err ierr, int32_t ivar, void *data) 663122394Sharti{ 664122394Sharti struct snmp_pdu resp; 665122394Sharti struct asn_buf resp_b, pdu_b; 666122394Sharti enum snmp_ret ret; 667122394Sharti 668122394Sharti resp_b.asn_ptr = sndbuf; 669122394Sharti resp_b.asn_len = snmpd.txbuf; 670122394Sharti 671122394Sharti pdu_b.asn_cptr = rcvbuf; 672122394Sharti pdu_b.asn_len = rcvlen; 673122394Sharti 674122394Sharti if (ierr != SNMPD_INPUT_OK) { 675122394Sharti /* error decoding the input of a SET */ 676122394Sharti if (pdu->version == SNMP_V1) 677122394Sharti pdu->error_status = SNMP_ERR_BADVALUE; 678122394Sharti else if (ierr == SNMPD_INPUT_VALBADLEN) 679122394Sharti pdu->error_status = SNMP_ERR_WRONG_LENGTH; 680122394Sharti else if (ierr == SNMPD_INPUT_VALRANGE) 681122394Sharti pdu->error_status = SNMP_ERR_WRONG_VALUE; 682122394Sharti else 683122394Sharti pdu->error_status = SNMP_ERR_WRONG_ENCODING; 684122394Sharti 685122394Sharti pdu->error_index = ivar; 686122394Sharti 687122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 688122394Sharti syslog(LOG_WARNING, "could not encode error response"); 689122394Sharti snmpd_stats.silentDrops++; 690122394Sharti return (SNMPD_INPUT_FAILED); 691122394Sharti } 692122394Sharti 693122394Sharti if (debug.dump_pdus) { 694122394Sharti snmp_printf("%s <- ", source); 695122394Sharti snmp_pdu_dump(pdu); 696122394Sharti } 697122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 698122394Sharti return (SNMPD_INPUT_OK); 699122394Sharti } 700122394Sharti 701122394Sharti switch (pdu->type) { 702122394Sharti 703122394Sharti case SNMP_PDU_GET: 704122394Sharti ret = snmp_get(pdu, &resp_b, &resp, data); 705122394Sharti break; 706122394Sharti 707122394Sharti case SNMP_PDU_GETNEXT: 708122394Sharti ret = snmp_getnext(pdu, &resp_b, &resp, data); 709122394Sharti break; 710122394Sharti 711122394Sharti case SNMP_PDU_SET: 712122394Sharti ret = snmp_set(pdu, &resp_b, &resp, data); 713122394Sharti break; 714122394Sharti 715122394Sharti case SNMP_PDU_GETBULK: 716122394Sharti ret = snmp_getbulk(pdu, &resp_b, &resp, data); 717122394Sharti break; 718122394Sharti 719122394Sharti default: 720122394Sharti ret = SNMP_RET_IGN; 721122394Sharti break; 722122394Sharti } 723122394Sharti 724122394Sharti switch (ret) { 725122394Sharti 726122394Sharti case SNMP_RET_OK: 727122394Sharti /* normal return - send a response */ 728122394Sharti if (debug.dump_pdus) { 729122394Sharti snmp_printf("%s <- ", source); 730122394Sharti snmp_pdu_dump(&resp); 731122394Sharti } 732122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 733122394Sharti snmp_pdu_free(&resp); 734122394Sharti return (SNMPD_INPUT_OK); 735122394Sharti 736122394Sharti case SNMP_RET_IGN: 737122394Sharti /* error - send nothing */ 738122394Sharti snmpd_stats.silentDrops++; 739122394Sharti return (SNMPD_INPUT_FAILED); 740122394Sharti 741122394Sharti case SNMP_RET_ERR: 742122394Sharti /* error - send error response. The snmp routine has 743122394Sharti * changed the error fields in the original message. */ 744122394Sharti resp_b.asn_ptr = sndbuf; 745122394Sharti resp_b.asn_len = snmpd.txbuf; 746122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 747122394Sharti syslog(LOG_WARNING, "could not encode error response"); 748122394Sharti snmpd_stats.silentDrops++; 749122394Sharti return (SNMPD_INPUT_FAILED); 750122394Sharti } else { 751122394Sharti if (debug.dump_pdus) { 752122394Sharti snmp_printf("%s <- ", source); 753122394Sharti snmp_pdu_dump(pdu); 754122394Sharti } 755122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 756122394Sharti return (SNMPD_INPUT_OK); 757122394Sharti } 758122394Sharti } 759122394Sharti abort(); 760122394Sharti} 761122394Sharti 762124861Sharti/* 763124861Sharti * Insert a port into the right place in the transport's table of ports 764124861Sharti */ 765124861Shartivoid 766124861Shartitrans_insert_port(struct transport *t, struct tport *port) 767124861Sharti{ 768124861Sharti struct tport *p; 769122394Sharti 770124861Sharti TAILQ_FOREACH(p, &t->table, link) { 771124861Sharti if (asn_compare_oid(&p->index, &port->index) > 0) { 772124861Sharti TAILQ_INSERT_BEFORE(p, port, link); 773124861Sharti return; 774124861Sharti } 775124861Sharti } 776124861Sharti port->transport = t; 777124861Sharti TAILQ_INSERT_TAIL(&t->table, port, link); 778124861Sharti} 779122394Sharti 780122394Sharti/* 781124861Sharti * Remove a port from a transport's list 782124861Sharti */ 783124861Shartivoid 784124861Shartitrans_remove_port(struct tport *port) 785124861Sharti{ 786124861Sharti 787124861Sharti TAILQ_REMOVE(&port->transport->table, port, link); 788124861Sharti} 789124861Sharti 790124861Sharti/* 791124861Sharti * Find a port on a transport's list 792124861Sharti */ 793124861Shartistruct tport * 794124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 795124861Sharti{ 796124861Sharti 797124861Sharti return (FIND_OBJECT_OID(&t->table, idx, sub)); 798124861Sharti} 799124861Sharti 800124861Sharti/* 801124861Sharti * Find next port on a transport's list 802124861Sharti */ 803124861Shartistruct tport * 804124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 805124861Sharti{ 806124861Sharti 807124861Sharti return (NEXT_OBJECT_OID(&t->table, idx, sub)); 808124861Sharti} 809124861Sharti 810124861Sharti/* 811124861Sharti * Return first port 812124861Sharti */ 813124861Shartistruct tport * 814124861Shartitrans_first_port(struct transport *t) 815124861Sharti{ 816124861Sharti 817124861Sharti return (TAILQ_FIRST(&t->table)); 818124861Sharti} 819124861Sharti 820124861Sharti/* 821124861Sharti * Iterate through all ports until a function returns a 0. 822124861Sharti */ 823124861Shartistruct tport * 824124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 825124861Sharti intptr_t arg) 826124861Sharti{ 827124861Sharti struct tport *p; 828124861Sharti 829124861Sharti TAILQ_FOREACH(p, &t->table, link) 830124861Sharti if (func(p, arg) == 0) 831124861Sharti return (p); 832124861Sharti return (NULL); 833124861Sharti} 834124861Sharti 835124861Sharti/* 836124861Sharti * Register a transport 837124861Sharti */ 838124861Shartiint 839124861Shartitrans_register(const struct transport_def *def, struct transport **pp) 840124861Sharti{ 841124861Sharti u_int i; 842124861Sharti char or_descr[256]; 843124861Sharti 844124861Sharti if ((*pp = malloc(sizeof(**pp))) == NULL) 845124861Sharti return (SNMP_ERR_GENERR); 846124861Sharti 847124861Sharti /* construct index */ 848124861Sharti (*pp)->index.len = strlen(def->name) + 1; 849124861Sharti (*pp)->index.subs[0] = strlen(def->name); 850124861Sharti for (i = 0; i < (*pp)->index.subs[0]; i++) 851124861Sharti (*pp)->index.subs[i + 1] = def->name[i]; 852124861Sharti 853124861Sharti (*pp)->vtab = def; 854124861Sharti 855124861Sharti if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 856124861Sharti free(*pp); 857124861Sharti return (SNMP_ERR_INCONS_VALUE); 858124861Sharti } 859124861Sharti 860124861Sharti /* register module */ 861124861Sharti snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 862124861Sharti if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 863124861Sharti free(*pp); 864124861Sharti return (SNMP_ERR_GENERR); 865124861Sharti } 866124861Sharti 867124861Sharti INSERT_OBJECT_OID((*pp), &transport_list); 868124861Sharti 869124861Sharti TAILQ_INIT(&(*pp)->table); 870124861Sharti 871124861Sharti return (SNMP_ERR_NOERROR); 872124861Sharti} 873124861Sharti 874124861Sharti/* 875124861Sharti * Unregister transport 876124861Sharti */ 877124861Shartiint 878124861Shartitrans_unregister(struct transport *t) 879124861Sharti{ 880124861Sharti if (!TAILQ_EMPTY(&t->table)) 881124861Sharti return (SNMP_ERR_INCONS_VALUE); 882124861Sharti 883124861Sharti or_unregister(t->or_index); 884124861Sharti TAILQ_REMOVE(&transport_list, t, link); 885124861Sharti 886124861Sharti return (SNMP_ERR_NOERROR); 887124861Sharti} 888124861Sharti 889124861Sharti/* 890122394Sharti * File descriptor support 891122394Sharti */ 892124861Sharti#ifdef USE_LIBBEGEMOT 893122394Shartistatic void 894124861Shartiinput(int fd, int mask __unused, void *uap) 895124861Sharti#else 896124861Shartistatic void 897122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused) 898124861Sharti#endif 899122394Sharti{ 900122394Sharti struct fdesc *f = uap; 901122394Sharti 902122394Sharti (*f->func)(fd, f->udata); 903122394Sharti} 904122394Sharti 905122394Shartivoid 906122394Shartifd_suspend(void *p) 907122394Sharti{ 908122394Sharti struct fdesc *f = p; 909122394Sharti 910124861Sharti#ifdef USE_LIBBEGEMOT 911124861Sharti if (f->id >= 0) { 912124861Sharti poll_unregister(f->id); 913124861Sharti f->id = -1; 914124861Sharti } 915124861Sharti#else 916122394Sharti if (evTestID(f->id)) { 917122394Sharti (void)evDeselectFD(evctx, f->id); 918122394Sharti evInitID(&f->id); 919122394Sharti } 920124861Sharti#endif 921122394Sharti} 922122394Sharti 923122394Shartiint 924122394Shartifd_resume(void *p) 925122394Sharti{ 926122394Sharti struct fdesc *f = p; 927122394Sharti int err; 928122394Sharti 929124861Sharti#ifdef USE_LIBBEGEMOT 930124861Sharti if (f->id >= 0) 931124861Sharti return (0); 932142810Sharti if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 933124861Sharti err = errno; 934124861Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 935124861Sharti errno = err; 936124861Sharti return (-1); 937124861Sharti } 938124861Sharti#else 939122394Sharti if (evTestID(f->id)) 940122394Sharti return (0); 941122394Sharti if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 942122394Sharti err = errno; 943122394Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 944122394Sharti errno = err; 945122394Sharti return (-1); 946122394Sharti } 947124861Sharti#endif 948122394Sharti return (0); 949122394Sharti} 950122394Sharti 951122394Shartivoid * 952122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 953122394Sharti{ 954122394Sharti struct fdesc *f; 955122394Sharti int err; 956122394Sharti 957122394Sharti if ((f = malloc(sizeof(struct fdesc))) == NULL) { 958122394Sharti err = errno; 959122394Sharti syslog(LOG_ERR, "fd_select: %m"); 960122394Sharti errno = err; 961122394Sharti return (NULL); 962122394Sharti } 963122394Sharti f->fd = fd; 964122394Sharti f->func = func; 965122394Sharti f->udata = udata; 966122394Sharti f->owner = mod; 967124861Sharti#ifdef USE_LIBBEGEMOT 968124861Sharti f->id = -1; 969124861Sharti#else 970122394Sharti evInitID(&f->id); 971124861Sharti#endif 972122394Sharti 973122394Sharti if (fd_resume(f)) { 974122394Sharti err = errno; 975122394Sharti free(f); 976122394Sharti errno = err; 977122394Sharti return (NULL); 978122394Sharti } 979122394Sharti 980122394Sharti LIST_INSERT_HEAD(&fdesc_list, f, link); 981122394Sharti 982122394Sharti return (f); 983122394Sharti} 984122394Sharti 985122394Shartivoid 986122394Shartifd_deselect(void *p) 987122394Sharti{ 988122394Sharti struct fdesc *f = p; 989122394Sharti 990122394Sharti LIST_REMOVE(f, link); 991122394Sharti fd_suspend(f); 992122394Sharti free(f); 993122394Sharti} 994122394Sharti 995122394Shartistatic void 996122394Shartifd_flush(struct lmodule *mod) 997122394Sharti{ 998122394Sharti struct fdesc *t, *t1; 999122394Sharti 1000122394Sharti t = LIST_FIRST(&fdesc_list); 1001122394Sharti while (t != NULL) { 1002122394Sharti t1 = LIST_NEXT(t, link); 1003122394Sharti if (t->owner == mod) 1004122394Sharti fd_deselect(t); 1005122394Sharti t = t1; 1006122394Sharti } 1007122394Sharti} 1008122394Sharti 1009122394Sharti/* 1010124861Sharti * Consume a message from the input buffer 1011122394Sharti */ 1012122394Shartistatic void 1013124861Shartisnmp_input_consume(struct port_input *pi) 1014122394Sharti{ 1015124861Sharti if (!pi->stream) { 1016124861Sharti /* always consume everything */ 1017124861Sharti pi->length = 0; 1018122394Sharti return; 1019122394Sharti } 1020124861Sharti if (pi->consumed >= pi->length) { 1021124861Sharti /* all bytes consumed */ 1022124861Sharti pi->length = 0; 1023122394Sharti return; 1024122394Sharti } 1025124861Sharti memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 1026124861Sharti pi->length -= pi->consumed; 1027124861Sharti} 1028124861Sharti 1029240234Sglebiusstatic void 1030240234Sglebiuscheck_priv_dgram(struct port_input *pi, struct sockcred *cred) 1031240234Sglebius{ 1032124861Sharti 1033240234Sglebius /* process explicitly sends credentials */ 1034240234Sglebius if (cred) 1035240234Sglebius pi->priv = (cred->sc_euid == 0); 1036240234Sglebius else 1037240234Sglebius pi->priv = 0; 1038240234Sglebius} 1039240234Sglebius 1040124861Shartistatic void 1041240234Sglebiuscheck_priv_stream(struct port_input *pi) 1042124861Sharti{ 1043124861Sharti struct xucred ucred; 1044124861Sharti socklen_t ucredlen; 1045124861Sharti 1046240234Sglebius /* obtain the accept time credentials */ 1047124861Sharti ucredlen = sizeof(ucred); 1048124861Sharti 1049124861Sharti if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 1050124861Sharti ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 1051124861Sharti pi->priv = (ucred.cr_uid == 0); 1052240234Sglebius else 1053240234Sglebius pi->priv = 0; 1054124861Sharti} 1055124861Sharti 1056124861Sharti/* 1057124861Sharti * Input from a stream socket. 1058124861Sharti */ 1059124861Shartistatic int 1060124861Shartirecv_stream(struct port_input *pi) 1061124861Sharti{ 1062124861Sharti struct msghdr msg; 1063124861Sharti struct iovec iov[1]; 1064124861Sharti ssize_t len; 1065124861Sharti 1066124861Sharti if (pi->buf == NULL) { 1067124861Sharti /* no buffer yet - allocate one */ 1068124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 1069124861Sharti /* ups - could not get buffer. Return an error 1070124861Sharti * the caller must close the transport. */ 1071124861Sharti return (-1); 1072124861Sharti } 1073124861Sharti pi->buflen = buf_size(0); 1074124861Sharti pi->consumed = 0; 1075124861Sharti pi->length = 0; 1076124861Sharti } 1077124861Sharti 1078124861Sharti /* try to get a message */ 1079124861Sharti msg.msg_name = pi->peer; 1080124861Sharti msg.msg_namelen = pi->peerlen; 1081124861Sharti msg.msg_iov = iov; 1082124861Sharti msg.msg_iovlen = 1; 1083240234Sglebius msg.msg_control = NULL; 1084240234Sglebius msg.msg_controllen = 0; 1085124861Sharti msg.msg_flags = 0; 1086124861Sharti 1087124861Sharti iov[0].iov_base = pi->buf + pi->length; 1088124861Sharti iov[0].iov_len = pi->buflen - pi->length; 1089124861Sharti 1090124861Sharti len = recvmsg(pi->fd, &msg, 0); 1091124861Sharti 1092124861Sharti if (len == -1 || len == 0) 1093124861Sharti /* receive error */ 1094124861Sharti return (-1); 1095124861Sharti 1096124861Sharti pi->length += len; 1097124861Sharti 1098124861Sharti if (pi->cred) 1099240234Sglebius check_priv_stream(pi); 1100124861Sharti 1101124861Sharti return (0); 1102124861Sharti} 1103124861Sharti 1104124861Sharti/* 1105124861Sharti * Input from a datagram socket. 1106124861Sharti * Each receive should return one datagram. 1107124861Sharti */ 1108124861Shartistatic int 1109240271Sglebiusrecv_dgram(struct port_input *pi, struct in_addr *laddr) 1110124861Sharti{ 1111124861Sharti u_char embuf[1000]; 1112240271Sglebius char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + 1113240271Sglebius CMSG_SPACE(sizeof(struct in_addr))]; 1114124861Sharti struct msghdr msg; 1115124861Sharti struct iovec iov[1]; 1116124861Sharti ssize_t len; 1117240234Sglebius struct cmsghdr *cmsg; 1118240234Sglebius struct sockcred *cred = NULL; 1119124861Sharti 1120124861Sharti if (pi->buf == NULL) { 1121124861Sharti /* no buffer yet - allocate one */ 1122124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 1123124861Sharti /* ups - could not get buffer. Read away input 1124124861Sharti * and drop it */ 1125124861Sharti (void)recvfrom(pi->fd, embuf, sizeof(embuf), 1126124861Sharti 0, NULL, NULL); 1127124861Sharti /* return error */ 1128124861Sharti return (-1); 1129124861Sharti } 1130124861Sharti pi->buflen = buf_size(0); 1131124861Sharti } 1132124861Sharti 1133124861Sharti /* try to get a message */ 1134124861Sharti msg.msg_name = pi->peer; 1135124861Sharti msg.msg_namelen = pi->peerlen; 1136124861Sharti msg.msg_iov = iov; 1137124861Sharti msg.msg_iovlen = 1; 1138240234Sglebius memset(cbuf, 0, sizeof(cbuf)); 1139240234Sglebius msg.msg_control = cbuf; 1140240234Sglebius msg.msg_controllen = sizeof(cbuf); 1141124861Sharti msg.msg_flags = 0; 1142124861Sharti 1143124861Sharti iov[0].iov_base = pi->buf; 1144124861Sharti iov[0].iov_len = pi->buflen; 1145124861Sharti 1146124861Sharti len = recvmsg(pi->fd, &msg, 0); 1147124861Sharti 1148124861Sharti if (len == -1 || len == 0) 1149124861Sharti /* receive error */ 1150124861Sharti return (-1); 1151124861Sharti 1152124861Sharti if (msg.msg_flags & MSG_TRUNC) { 1153124861Sharti /* truncated - drop */ 1154122394Sharti snmpd_stats.silentDrops++; 1155122394Sharti snmpd_stats.inTooLong++; 1156124861Sharti return (-1); 1157122394Sharti } 1158122394Sharti 1159124861Sharti pi->length = (size_t)len; 1160124861Sharti 1161240234Sglebius for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 1162240234Sglebius cmsg = CMSG_NXTHDR(&msg, cmsg)) { 1163240271Sglebius if (cmsg->cmsg_level == IPPROTO_IP && 1164240271Sglebius cmsg->cmsg_type == IP_RECVDSTADDR) 1165240271Sglebius memcpy(laddr, CMSG_DATA(cmsg), sizeof(struct in_addr)); 1166240234Sglebius if (cmsg->cmsg_level == SOL_SOCKET && 1167240234Sglebius cmsg->cmsg_type == SCM_CREDS) 1168240234Sglebius cred = (struct sockcred *)CMSG_DATA(cmsg); 1169240234Sglebius } 1170240234Sglebius 1171124861Sharti if (pi->cred) 1172240234Sglebius check_priv_dgram(pi, cred); 1173124861Sharti 1174124861Sharti return (0); 1175124861Sharti} 1176124861Sharti 1177124861Sharti/* 1178124861Sharti * Input from a socket 1179124861Sharti */ 1180124861Shartiint 1181124861Shartisnmpd_input(struct port_input *pi, struct tport *tport) 1182124861Sharti{ 1183124861Sharti u_char *sndbuf; 1184124861Sharti size_t sndlen; 1185124861Sharti struct snmp_pdu pdu; 1186124861Sharti enum snmpd_input_err ierr, ferr; 1187124861Sharti enum snmpd_proxy_err perr; 1188124861Sharti int32_t vi; 1189124861Sharti int ret; 1190124861Sharti ssize_t slen; 1191145557Sharti#ifdef USE_TCPWRAPPERS 1192145557Sharti char client[16]; 1193145557Sharti#endif 1194240271Sglebius struct msghdr msg; 1195240271Sglebius struct iovec iov[1]; 1196240271Sglebius char cbuf[CMSG_SPACE(sizeof(struct in_addr))]; 1197240271Sglebius struct cmsghdr *cmsgp; 1198124861Sharti 1199124861Sharti /* get input depending on the transport */ 1200124861Sharti if (pi->stream) { 1201240271Sglebius msg.msg_control = NULL; 1202240271Sglebius msg.msg_controllen = 0; 1203240271Sglebius 1204124861Sharti ret = recv_stream(pi); 1205124861Sharti } else { 1206240734Sglebius struct in_addr *laddr; 1207240734Sglebius 1208240271Sglebius memset(cbuf, 0, CMSG_SPACE(sizeof(struct in_addr))); 1209240271Sglebius msg.msg_control = cbuf; 1210240271Sglebius msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 1211240271Sglebius cmsgp = CMSG_FIRSTHDR(&msg); 1212240271Sglebius cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 1213240271Sglebius cmsgp->cmsg_level = IPPROTO_IP; 1214240271Sglebius cmsgp->cmsg_type = IP_SENDSRCADDR; 1215240734Sglebius laddr = (struct in_addr *)CMSG_DATA(cmsgp); 1216240271Sglebius 1217240734Sglebius ret = recv_dgram(pi, laddr); 1218240734Sglebius 1219240734Sglebius if (laddr->s_addr == 0) { 1220240734Sglebius msg.msg_control = NULL; 1221240734Sglebius msg.msg_controllen = 0; 1222240734Sglebius } 1223124861Sharti } 1224124861Sharti 1225124861Sharti if (ret == -1) 1226124861Sharti return (-1); 1227124861Sharti 1228145557Sharti#ifdef USE_TCPWRAPPERS 1229122394Sharti /* 1230145557Sharti * In case of AF_INET{6} peer, do hosts_access(5) check. 1231145557Sharti */ 1232220882Sru if (pi->peer->sa_family != AF_LOCAL && 1233220882Sru inet_ntop(pi->peer->sa_family, 1234146525Sharti &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 1235146525Sharti client, sizeof(client)) != NULL) { 1236145557Sharti request_set(&req, RQ_CLIENT_ADDR, client, 0); 1237145557Sharti if (hosts_access(&req) == 0) { 1238145557Sharti syslog(LOG_ERR, "refused connection from %.500s", 1239145557Sharti eval_client(&req)); 1240145557Sharti return (-1); 1241145557Sharti } 1242220882Sru } else if (pi->peer->sa_family != AF_LOCAL) 1243145557Sharti syslog(LOG_ERR, "inet_ntop(): %m"); 1244145557Sharti#endif 1245145557Sharti 1246145557Sharti /* 1247122394Sharti * Handle input 1248122394Sharti */ 1249124861Sharti ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 1250124861Sharti &pi->consumed); 1251124861Sharti if (ierr == SNMPD_INPUT_TRUNC) { 1252124861Sharti /* need more bytes. This is ok only for streaming transports. 1253124861Sharti * but only if we have not reached bufsiz yet. */ 1254124861Sharti if (pi->stream) { 1255124861Sharti if (pi->length == buf_size(0)) { 1256124861Sharti snmpd_stats.silentDrops++; 1257124861Sharti return (-1); 1258124861Sharti } 1259124861Sharti return (0); 1260124861Sharti } 1261124861Sharti snmpd_stats.silentDrops++; 1262124861Sharti return (-1); 1263124861Sharti } 1264122394Sharti 1265122394Sharti /* can't check for bad SET pdus here, because a proxy may have to 1266122394Sharti * check the access first. We don't want to return an error response 1267122394Sharti * to a proxy PDU with a wrong community */ 1268122394Sharti if (ierr == SNMPD_INPUT_FAILED) { 1269124861Sharti /* for streaming transports this is fatal */ 1270124861Sharti if (pi->stream) 1271124861Sharti return (-1); 1272124861Sharti snmp_input_consume(pi); 1273124861Sharti return (0); 1274122394Sharti } 1275133211Sharti if (ierr == SNMPD_INPUT_BAD_COMM) { 1276133211Sharti snmp_input_consume(pi); 1277133211Sharti return (0); 1278133211Sharti } 1279122394Sharti 1280122394Sharti /* 1281122394Sharti * If that is a module community and the module has a proxy function, 1282122394Sharti * the hand it over to the module. 1283122394Sharti */ 1284216294Ssyrinx if (comm != NULL && comm->owner != NULL && 1285216294Ssyrinx comm->owner->config->proxy != NULL) { 1286124861Sharti perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1287133211Sharti &tport->index, pi->peer, pi->peerlen, ierr, vi, 1288133211Sharti !pi->cred || pi->priv); 1289122394Sharti 1290122394Sharti switch (perr) { 1291122394Sharti 1292122394Sharti case SNMPD_PROXY_OK: 1293124861Sharti snmp_input_consume(pi); 1294124861Sharti return (0); 1295122394Sharti 1296122394Sharti case SNMPD_PROXY_REJ: 1297122394Sharti break; 1298122394Sharti 1299122394Sharti case SNMPD_PROXY_DROP: 1300124861Sharti snmp_input_consume(pi); 1301122394Sharti snmp_pdu_free(&pdu); 1302122394Sharti snmpd_stats.proxyDrops++; 1303124861Sharti return (0); 1304122394Sharti 1305122394Sharti case SNMPD_PROXY_BADCOMM: 1306124861Sharti snmp_input_consume(pi); 1307122394Sharti snmp_pdu_free(&pdu); 1308122394Sharti snmpd_stats.inBadCommunityNames++; 1309122394Sharti if (snmpd.auth_traps) 1310122394Sharti snmp_send_trap(&oid_authenticationFailure, 1311133211Sharti (struct snmp_value *)NULL); 1312124861Sharti return (0); 1313122394Sharti 1314122394Sharti case SNMPD_PROXY_BADCOMMUSE: 1315124861Sharti snmp_input_consume(pi); 1316122394Sharti snmp_pdu_free(&pdu); 1317122394Sharti snmpd_stats.inBadCommunityUses++; 1318122394Sharti if (snmpd.auth_traps) 1319122394Sharti snmp_send_trap(&oid_authenticationFailure, 1320133211Sharti (struct snmp_value *)NULL); 1321124861Sharti return (0); 1322122394Sharti } 1323122394Sharti } 1324122394Sharti 1325122394Sharti /* 1326122394Sharti * Check type 1327122394Sharti */ 1328122394Sharti if (pdu.type == SNMP_PDU_RESPONSE || 1329122394Sharti pdu.type == SNMP_PDU_TRAP || 1330122394Sharti pdu.type == SNMP_PDU_TRAP2) { 1331122394Sharti snmpd_stats.silentDrops++; 1332122394Sharti snmpd_stats.inBadPduTypes++; 1333122394Sharti snmp_pdu_free(&pdu); 1334124861Sharti snmp_input_consume(pi); 1335124861Sharti return (0); 1336122394Sharti } 1337122394Sharti 1338122394Sharti /* 1339122394Sharti * Check community 1340122394Sharti */ 1341216294Ssyrinx if (pdu.version < SNMP_V3 && 1342216294Ssyrinx ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1343124861Sharti (community != COMM_WRITE && 1344216294Ssyrinx (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1345122394Sharti snmpd_stats.inBadCommunityUses++; 1346122394Sharti snmp_pdu_free(&pdu); 1347124861Sharti snmp_input_consume(pi); 1348122394Sharti if (snmpd.auth_traps) 1349133211Sharti snmp_send_trap(&oid_authenticationFailure, 1350133211Sharti (struct snmp_value *)NULL); 1351124861Sharti return (0); 1352122394Sharti } 1353122394Sharti 1354122394Sharti /* 1355122394Sharti * Execute it. 1356122394Sharti */ 1357122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 1358122394Sharti snmpd_stats.silentDrops++; 1359122394Sharti snmp_pdu_free(&pdu); 1360124861Sharti snmp_input_consume(pi); 1361124861Sharti return (0); 1362122394Sharti } 1363124861Sharti ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1364124861Sharti sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1365122394Sharti 1366122394Sharti if (ferr == SNMPD_INPUT_OK) { 1367240271Sglebius msg.msg_name = pi->peer; 1368240271Sglebius msg.msg_namelen = pi->peerlen; 1369240271Sglebius msg.msg_iov = iov; 1370240271Sglebius msg.msg_iovlen = 1; 1371240271Sglebius msg.msg_flags = 0; 1372240271Sglebius iov[0].iov_base = sndbuf; 1373240271Sglebius iov[0].iov_len = sndlen; 1374240271Sglebius 1375240271Sglebius slen = sendmsg(pi->fd, &msg, 0); 1376124861Sharti if (slen == -1) 1377240271Sglebius syslog(LOG_ERR, "sendmsg: %m"); 1378124861Sharti else if ((size_t)slen != sndlen) 1379240271Sglebius syslog(LOG_ERR, "sendmsg: short write %zu/%zu", 1380124861Sharti sndlen, (size_t)slen); 1381122394Sharti } 1382122394Sharti snmp_pdu_free(&pdu); 1383122394Sharti free(sndbuf); 1384124861Sharti snmp_input_consume(pi); 1385122394Sharti 1386124861Sharti return (0); 1387122394Sharti} 1388122394Sharti 1389122394Sharti/* 1390124861Sharti * Send a PDU to a given port 1391122394Sharti */ 1392124861Shartivoid 1393124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1394124861Sharti const struct sockaddr *addr, socklen_t addrlen) 1395122394Sharti{ 1396124861Sharti struct transport *trans = targ; 1397124861Sharti struct tport *tp; 1398124861Sharti u_char *sndbuf; 1399124861Sharti size_t sndlen; 1400124861Sharti ssize_t len; 1401122394Sharti 1402124861Sharti TAILQ_FOREACH(tp, &trans->table, link) 1403124861Sharti if (asn_compare_oid(port, &tp->index) == 0) 1404122394Sharti break; 1405124861Sharti if (tp == 0) 1406124861Sharti return; 1407122394Sharti 1408124861Sharti if ((sndbuf = buf_alloc(1)) == NULL) 1409124861Sharti return; 1410122394Sharti 1411124861Sharti snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1412122394Sharti 1413124861Sharti len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1414122394Sharti 1415124861Sharti if (len == -1) 1416124861Sharti syslog(LOG_ERR, "sendto: %m"); 1417124861Sharti else if ((size_t)len != sndlen) 1418124861Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1419124861Sharti sndlen, (size_t)len); 1420122394Sharti 1421124861Sharti free(sndbuf); 1422122394Sharti} 1423122394Sharti 1424122394Sharti 1425122394Sharti/* 1426124861Sharti * Close an input source 1427122394Sharti */ 1428122394Shartivoid 1429124861Shartisnmpd_input_close(struct port_input *pi) 1430122394Sharti{ 1431124861Sharti if (pi->id != NULL) 1432124861Sharti fd_deselect(pi->id); 1433124861Sharti if (pi->fd >= 0) 1434124861Sharti (void)close(pi->fd); 1435124861Sharti if (pi->buf != NULL) 1436124861Sharti free(pi->buf); 1437122394Sharti} 1438122394Sharti 1439122394Sharti/* 1440122394Sharti * Dump internal state. 1441122394Sharti */ 1442124861Sharti#ifdef USE_LIBBEGEMOT 1443122394Shartistatic void 1444124861Shartiinfo_func(void) 1445124861Sharti#else 1446124861Shartistatic void 1447122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1448124861Sharti#endif 1449122394Sharti{ 1450122394Sharti struct lmodule *m; 1451122394Sharti u_int i; 1452122394Sharti char buf[10000]; 1453122394Sharti 1454122394Sharti syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1455122394Sharti for (i = 0; i < tree_size; i++) { 1456122394Sharti switch (tree[i].type) { 1457122394Sharti 1458122394Sharti case SNMP_NODE_LEAF: 1459122394Sharti sprintf(buf, "LEAF: %s %s", tree[i].name, 1460122394Sharti asn_oid2str(&tree[i].oid)); 1461122394Sharti break; 1462122394Sharti 1463122394Sharti case SNMP_NODE_COLUMN: 1464122394Sharti sprintf(buf, "COL: %s %s", tree[i].name, 1465122394Sharti asn_oid2str(&tree[i].oid)); 1466122394Sharti break; 1467122394Sharti } 1468122394Sharti syslog(LOG_DEBUG, "%s", buf); 1469122394Sharti } 1470122394Sharti 1471122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1472122394Sharti if (m->config->dump) 1473122394Sharti (*m->config->dump)(); 1474122394Sharti} 1475122394Sharti 1476122394Sharti/* 1477122394Sharti * Re-read configuration 1478122394Sharti */ 1479124861Sharti#ifdef USE_LIBBEGEMOT 1480122394Shartistatic void 1481124861Sharticonfig_func(void) 1482124861Sharti#else 1483124861Shartistatic void 1484122394Sharticonfig_func(evContext ctx __unused, void *uap __unused, 1485122394Sharti const void *tag __unused) 1486124861Sharti#endif 1487122394Sharti{ 1488122394Sharti struct lmodule *m; 1489122394Sharti 1490122394Sharti if (read_config(config_file, NULL)) { 1491122394Sharti syslog(LOG_ERR, "error reading config file '%s'", config_file); 1492122394Sharti return; 1493122394Sharti } 1494122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1495122394Sharti if (m->config->config) 1496122394Sharti (*m->config->config)(); 1497122394Sharti} 1498122394Sharti 1499122394Sharti/* 1500122394Sharti * On USR1 dump actual configuration. 1501122394Sharti */ 1502122394Shartistatic void 1503122394Shartionusr1(int s __unused) 1504122394Sharti{ 1505124861Sharti 1506122394Sharti work |= WORK_DOINFO; 1507122394Sharti} 1508122394Shartistatic void 1509122394Shartionhup(int s __unused) 1510122394Sharti{ 1511124861Sharti 1512122394Sharti work |= WORK_RECONFIG; 1513122394Sharti} 1514122394Sharti 1515122394Shartistatic void 1516122394Shartionterm(int s __unused) 1517122394Sharti{ 1518122394Sharti 1519124861Sharti /* allow clean-up */ 1520122394Sharti exit(0); 1521122394Sharti} 1522122394Sharti 1523122394Shartistatic void 1524122394Shartiinit_sigs(void) 1525122394Sharti{ 1526122394Sharti struct sigaction sa; 1527122394Sharti 1528122394Sharti sa.sa_handler = onusr1; 1529122394Sharti sa.sa_flags = SA_RESTART; 1530122394Sharti sigemptyset(&sa.sa_mask); 1531122394Sharti if (sigaction(SIGUSR1, &sa, NULL)) { 1532122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1533122394Sharti exit(1); 1534122394Sharti } 1535122394Sharti 1536122394Sharti sa.sa_handler = onhup; 1537122394Sharti if (sigaction(SIGHUP, &sa, NULL)) { 1538122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1539122394Sharti exit(1); 1540122394Sharti } 1541122394Sharti 1542122394Sharti sa.sa_handler = onterm; 1543122394Sharti sa.sa_flags = 0; 1544122394Sharti sigemptyset(&sa.sa_mask); 1545122394Sharti if (sigaction(SIGTERM, &sa, NULL)) { 1546122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1547122394Sharti exit(1); 1548122394Sharti } 1549122394Sharti if (sigaction(SIGINT, &sa, NULL)) { 1550122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1551122394Sharti exit(1); 1552122394Sharti } 1553122394Sharti} 1554122394Sharti 1555122394Shartistatic void 1556122394Shartiblock_sigs(void) 1557122394Sharti{ 1558122394Sharti sigset_t set; 1559122394Sharti 1560122394Sharti sigfillset(&set); 1561122394Sharti if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1562122394Sharti syslog(LOG_ERR, "SIG_BLOCK: %m"); 1563122394Sharti exit(1); 1564122394Sharti } 1565122394Sharti} 1566122394Shartistatic void 1567122394Shartiunblock_sigs(void) 1568122394Sharti{ 1569122394Sharti if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1570122394Sharti syslog(LOG_ERR, "SIG_SETMASK: %m"); 1571122394Sharti exit(1); 1572122394Sharti } 1573122394Sharti} 1574122394Sharti 1575122394Sharti/* 1576122394Sharti * Shut down 1577122394Sharti */ 1578122394Shartistatic void 1579122394Shartiterm(void) 1580122394Sharti{ 1581122394Sharti (void)unlink(pid_file); 1582122394Sharti} 1583122394Sharti 1584124861Shartistatic void 1585124861Shartitrans_stop(void) 1586124861Sharti{ 1587124861Sharti struct transport *t; 1588124861Sharti 1589124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1590124861Sharti (void)t->vtab->stop(1); 1591124861Sharti} 1592124861Sharti 1593122394Sharti/* 1594122394Sharti * Define a macro from the command line 1595122394Sharti */ 1596122394Shartistatic void 1597122394Shartido_macro(char *arg) 1598122394Sharti{ 1599122394Sharti char *eq; 1600122394Sharti int err; 1601122394Sharti 1602122394Sharti if ((eq = strchr(arg, '=')) == NULL) 1603122394Sharti err = define_macro(arg, ""); 1604122394Sharti else { 1605122394Sharti *eq++ = '\0'; 1606122394Sharti err = define_macro(arg, eq); 1607122394Sharti } 1608122394Sharti if (err == -1) { 1609122394Sharti syslog(LOG_ERR, "cannot save macro: %m"); 1610122394Sharti exit(1); 1611122394Sharti } 1612122394Sharti} 1613122394Sharti 1614122394Sharti/* 1615122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken 1616122394Sharti * and will not compile with WARNS=5. 1617122394Sharti */ 1618122394Shartistatic int 1619122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1620122394Sharti{ 1621122394Sharti static const char *const delim = ",\t "; 1622122394Sharti u_int i; 1623122394Sharti char *ptr; 1624122394Sharti 1625122394Sharti *optp = NULL; 1626122394Sharti 1627122394Sharti /* skip leading junk */ 1628122394Sharti for (ptr = *arg; *ptr != '\0'; ptr++) 1629122394Sharti if (strchr(delim, *ptr) == NULL) 1630122394Sharti break; 1631122394Sharti if (*ptr == '\0') { 1632122394Sharti *arg = ptr; 1633122394Sharti return (-1); 1634122394Sharti } 1635122394Sharti *optp = ptr; 1636122394Sharti 1637122394Sharti /* find the end of the option */ 1638122394Sharti while (*++ptr != '\0') 1639122394Sharti if (strchr(delim, *ptr) != NULL || *ptr == '=') 1640122394Sharti break; 1641122394Sharti 1642122394Sharti if (*ptr != '\0') { 1643122394Sharti if (*ptr == '=') { 1644122394Sharti *ptr++ = '\0'; 1645122394Sharti *valp = ptr; 1646122394Sharti while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1647122394Sharti ptr++; 1648122394Sharti if (*ptr != '\0') 1649122394Sharti *ptr++ = '\0'; 1650122394Sharti } else 1651122394Sharti *ptr++ = '\0'; 1652122394Sharti } 1653122394Sharti 1654122394Sharti *arg = ptr; 1655122394Sharti 1656122394Sharti for (i = 0; *options != NULL; options++, i++) 1657124861Sharti if (strcmp(*optp, *options) == 0) 1658122394Sharti return (i); 1659122394Sharti return (-1); 1660122394Sharti} 1661122394Sharti 1662122394Shartiint 1663122394Shartimain(int argc, char *argv[]) 1664122394Sharti{ 1665122394Sharti int opt; 1666122394Sharti FILE *fp; 1667122394Sharti int background = 1; 1668124861Sharti struct tport *p; 1669122394Sharti const char *prefix = "snmpd"; 1670122394Sharti struct lmodule *m; 1671216294Ssyrinx char *value = NULL, *option; /* XXX */ 1672124861Sharti struct transport *t; 1673122394Sharti 1674122394Sharti#define DBG_DUMP 0 1675122394Sharti#define DBG_EVENTS 1 1676122394Sharti#define DBG_TRACE 2 1677122394Sharti static const char *const debug_opts[] = { 1678122394Sharti "dump", 1679122394Sharti "events", 1680122394Sharti "trace", 1681122394Sharti NULL 1682122394Sharti }; 1683122394Sharti 1684122394Sharti snmp_printf = snmp_printf_func; 1685122394Sharti snmp_error = snmp_error_func; 1686122394Sharti snmp_debug = snmp_debug_func; 1687122394Sharti asn_error = asn_error_func; 1688122394Sharti 1689216294Ssyrinx while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1690122394Sharti switch (opt) { 1691122394Sharti 1692122394Sharti case 'c': 1693122394Sharti strlcpy(config_file, optarg, sizeof(config_file)); 1694122394Sharti break; 1695122394Sharti 1696122394Sharti case 'd': 1697122394Sharti background = 0; 1698122394Sharti break; 1699122394Sharti 1700122394Sharti case 'D': 1701122394Sharti while (*optarg) { 1702122394Sharti switch (getsubopt1(&optarg, debug_opts, 1703122394Sharti &value, &option)) { 1704122394Sharti 1705122394Sharti case DBG_DUMP: 1706122394Sharti debug.dump_pdus = 1; 1707122394Sharti break; 1708122394Sharti 1709122394Sharti case DBG_EVENTS: 1710122394Sharti debug.evdebug++; 1711122394Sharti break; 1712122394Sharti 1713122394Sharti case DBG_TRACE: 1714122394Sharti if (value == NULL) 1715122394Sharti syslog(LOG_ERR, 1716122394Sharti "no value for 'trace'"); 1717155094Sharti else 1718156066Sharti snmp_trace = strtoul(value, 1719156066Sharti NULL, 0); 1720122394Sharti break; 1721122394Sharti 1722122394Sharti case -1: 1723122394Sharti if (suboptarg) 1724122394Sharti syslog(LOG_ERR, 1725122394Sharti "unknown debug flag '%s'", 1726122394Sharti option); 1727122394Sharti else 1728122394Sharti syslog(LOG_ERR, 1729122394Sharti "missing debug flag"); 1730122394Sharti break; 1731122394Sharti } 1732122394Sharti } 1733122394Sharti break; 1734122394Sharti 1735216294Ssyrinx case 'e': 1736216294Ssyrinx strlcpy(engine_file, optarg, sizeof(engine_file)); 1737216294Ssyrinx break; 1738122394Sharti case 'h': 1739122394Sharti fprintf(stderr, "%s", usgtxt); 1740122394Sharti exit(0); 1741122394Sharti 1742122394Sharti case 'I': 1743122394Sharti syspath = optarg; 1744122394Sharti break; 1745122394Sharti 1746122394Sharti case 'l': 1747122394Sharti prefix = optarg; 1748122394Sharti break; 1749122394Sharti 1750122394Sharti case 'm': 1751122394Sharti do_macro(optarg); 1752122394Sharti break; 1753122394Sharti 1754122394Sharti case 'p': 1755122394Sharti strlcpy(pid_file, optarg, sizeof(pid_file)); 1756122394Sharti break; 1757122394Sharti } 1758122394Sharti 1759122394Sharti openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1760122394Sharti setlogmask(LOG_UPTO(debug.logpri - 1)); 1761122394Sharti 1762122394Sharti if (background && daemon(0, 0) < 0) { 1763122394Sharti syslog(LOG_ERR, "daemon: %m"); 1764122394Sharti exit(1); 1765122394Sharti } 1766122394Sharti 1767122394Sharti argc -= optind; 1768122394Sharti argv += optind; 1769122394Sharti 1770122394Sharti progargs = argv; 1771122394Sharti nprogargs = argc; 1772122394Sharti 1773122394Sharti srandomdev(); 1774122394Sharti 1775122394Sharti snmp_serial_no = random(); 1776122394Sharti 1777145557Sharti#ifdef USE_TCPWRAPPERS 1778122394Sharti /* 1779145557Sharti * Initialize hosts_access(3) handler. 1780145557Sharti */ 1781145557Sharti request_init(&req, RQ_DAEMON, "snmpd", 0); 1782145557Sharti sock_methods(&req); 1783145557Sharti#endif 1784145557Sharti 1785145557Sharti /* 1786122394Sharti * Initialize the tree. 1787122394Sharti */ 1788122394Sharti if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1789122394Sharti syslog(LOG_ERR, "%m"); 1790122394Sharti exit(1); 1791122394Sharti } 1792122394Sharti memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1793122394Sharti tree_size = CTREE_SIZE; 1794122394Sharti 1795122394Sharti /* 1796122394Sharti * Get standard communities 1797122394Sharti */ 1798154180Sharti (void)comm_define(1, "SNMP read", NULL, NULL); 1799154180Sharti (void)comm_define(2, "SNMP write", NULL, NULL); 1800122394Sharti community = COMM_INITIALIZE; 1801122394Sharti 1802122394Sharti trap_reqid = reqid_allocate(512, NULL); 1803122394Sharti 1804122394Sharti if (config_file[0] == '\0') 1805122394Sharti snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1806122394Sharti 1807122394Sharti init_actvals(); 1808216294Ssyrinx init_snmpd_engine(); 1809124861Sharti 1810124861Sharti this_tick = get_ticks(); 1811146525Sharti start_tick = this_tick; 1812124861Sharti 1813124861Sharti /* start transports */ 1814124861Sharti if (atexit(trans_stop) == -1) { 1815124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1816124861Sharti exit(1); 1817124861Sharti } 1818124861Sharti if (udp_trans.start() != SNMP_ERR_NOERROR) 1819124861Sharti syslog(LOG_WARNING, "cannot start UDP transport"); 1820124861Sharti if (lsock_trans.start() != SNMP_ERR_NOERROR) 1821124861Sharti syslog(LOG_WARNING, "cannot start LSOCK transport"); 1822124861Sharti 1823124861Sharti#ifdef USE_LIBBEGEMOT 1824124861Sharti if (debug.evdebug > 0) 1825124861Sharti rpoll_trace = 1; 1826124861Sharti#else 1827122394Sharti if (evCreate(&evctx)) { 1828122394Sharti syslog(LOG_ERR, "evCreate: %m"); 1829122394Sharti exit(1); 1830122394Sharti } 1831122394Sharti if (debug.evdebug > 0) 1832122394Sharti evSetDebug(evctx, 10, stderr); 1833124861Sharti#endif 1834122394Sharti 1835216294Ssyrinx if (engine_file[0] == '\0') 1836216294Ssyrinx snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1837216294Ssyrinx 1838133211Sharti if (read_config(config_file, NULL)) { 1839133211Sharti syslog(LOG_ERR, "error in config file"); 1840133211Sharti exit(1); 1841133211Sharti } 1842133211Sharti 1843124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1844124861Sharti TAILQ_FOREACH(p, &t->table, link) 1845124861Sharti t->vtab->init_port(p); 1846122394Sharti 1847122394Sharti init_sigs(); 1848122394Sharti 1849122394Sharti if (pid_file[0] == '\0') 1850122394Sharti snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1851122394Sharti 1852122394Sharti if ((fp = fopen(pid_file, "w")) != NULL) { 1853122394Sharti fprintf(fp, "%u", getpid()); 1854122394Sharti fclose(fp); 1855124861Sharti if (atexit(term) == -1) { 1856124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1857124861Sharti (void)remove(pid_file); 1858124861Sharti exit(0); 1859124861Sharti } 1860122394Sharti } 1861122394Sharti 1862122394Sharti if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1863122394Sharti NULL) == 0) { 1864122394Sharti syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1865122394Sharti exit(1); 1866122394Sharti } 1867122394Sharti if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1868122394Sharti NULL) == 0) { 1869122394Sharti syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1870122394Sharti exit(1); 1871122394Sharti } 1872122394Sharti 1873122394Sharti while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1874122394Sharti m->flags &= ~LM_ONSTARTLIST; 1875122394Sharti TAILQ_REMOVE(&modules_start, m, start); 1876122394Sharti lm_start(m); 1877122394Sharti } 1878122394Sharti 1879216594Ssyrinx snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1880216594Ssyrinx 1881122394Sharti for (;;) { 1882124861Sharti#ifndef USE_LIBBEGEMOT 1883122394Sharti evEvent event; 1884124861Sharti#endif 1885122394Sharti struct lmodule *mod; 1886122394Sharti 1887122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 1888122394Sharti if (mod->config->idle != NULL) 1889122394Sharti (*mod->config->idle)(); 1890122394Sharti 1891124861Sharti#ifndef USE_LIBBEGEMOT 1892122394Sharti if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1893122394Sharti if (evDispatch(evctx, event)) 1894122394Sharti syslog(LOG_ERR, "evDispatch: %m"); 1895122394Sharti } else if (errno != EINTR) { 1896122394Sharti syslog(LOG_ERR, "evGetNext: %m"); 1897122394Sharti exit(1); 1898122394Sharti } 1899124861Sharti#else 1900124861Sharti poll_dispatch(1); 1901124861Sharti#endif 1902122394Sharti 1903122394Sharti if (work != 0) { 1904122394Sharti block_sigs(); 1905122394Sharti if (work & WORK_DOINFO) { 1906124861Sharti#ifdef USE_LIBBEGEMOT 1907124861Sharti info_func(); 1908124861Sharti#else 1909122394Sharti if (evWaitFor(evctx, &work, info_func, 1910122394Sharti NULL, NULL) == -1) { 1911122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1912122394Sharti exit(1); 1913122394Sharti } 1914124861Sharti#endif 1915122394Sharti } 1916122394Sharti if (work & WORK_RECONFIG) { 1917124861Sharti#ifdef USE_LIBBEGEMOT 1918124861Sharti config_func(); 1919124861Sharti#else 1920122394Sharti if (evWaitFor(evctx, &work, config_func, 1921122394Sharti NULL, NULL) == -1) { 1922122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1923122394Sharti exit(1); 1924122394Sharti } 1925124861Sharti#endif 1926122394Sharti } 1927122394Sharti work = 0; 1928122394Sharti unblock_sigs(); 1929124861Sharti#ifndef USE_LIBBEGEMOT 1930122394Sharti if (evDo(evctx, &work) == -1) { 1931122394Sharti syslog(LOG_ERR, "evDo: %m"); 1932122394Sharti exit(1); 1933122394Sharti } 1934124861Sharti#endif 1935122394Sharti } 1936122394Sharti } 1937122394Sharti 1938122394Sharti return (0); 1939122394Sharti} 1940122394Sharti 1941146525Shartiuint64_t 1942216294Ssyrinxget_ticks(void) 1943122394Sharti{ 1944122394Sharti struct timeval tv; 1945146525Sharti uint64_t ret; 1946122394Sharti 1947122394Sharti if (gettimeofday(&tv, NULL)) 1948122394Sharti abort(); 1949146525Sharti ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1950122394Sharti return (ret); 1951122394Sharti} 1952146525Sharti 1953122394Sharti/* 1954122394Sharti * Timer support 1955122394Sharti */ 1956150920Sharti 1957150920Sharti/* 1958150920Sharti * Trampoline for the non-repeatable timers. 1959150920Sharti */ 1960124861Sharti#ifdef USE_LIBBEGEMOT 1961122394Shartistatic void 1962124861Shartitfunc(int tid __unused, void *uap) 1963124861Sharti#else 1964124861Shartistatic void 1965122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1966122394Sharti struct timespec inter __unused) 1967124861Sharti#endif 1968122394Sharti{ 1969122394Sharti struct timer *tp = uap; 1970122394Sharti 1971122394Sharti LIST_REMOVE(tp, link); 1972122394Sharti tp->func(tp->udata); 1973122394Sharti free(tp); 1974122394Sharti} 1975122394Sharti 1976122394Sharti/* 1977150920Sharti * Trampoline for the repeatable timers. 1978122394Sharti */ 1979150920Sharti#ifdef USE_LIBBEGEMOT 1980150920Shartistatic void 1981150920Shartitrfunc(int tid __unused, void *uap) 1982150920Sharti#else 1983150920Shartistatic void 1984150920Shartitrfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1985150920Sharti struct timespec inter __unused) 1986150920Sharti#endif 1987150920Sharti{ 1988150920Sharti struct timer *tp = uap; 1989150920Sharti 1990150920Sharti tp->func(tp->udata); 1991150920Sharti} 1992150920Sharti 1993150920Sharti/* 1994150920Sharti * Start a one-shot timer 1995150920Sharti */ 1996122394Shartivoid * 1997122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1998122394Sharti{ 1999122394Sharti struct timer *tp; 2000145673Sharti#ifndef USE_LIBBEGEMOT 2001122394Sharti struct timespec due; 2002124861Sharti#endif 2003122394Sharti 2004122394Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 2005122394Sharti syslog(LOG_CRIT, "out of memory for timer"); 2006122394Sharti exit(1); 2007122394Sharti } 2008145673Sharti 2009145673Sharti#ifndef USE_LIBBEGEMOT 2010122394Sharti due = evAddTime(evNowTime(), 2011124861Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 2012124861Sharti#endif 2013122394Sharti 2014122394Sharti tp->udata = udata; 2015122394Sharti tp->owner = mod; 2016122394Sharti tp->func = func; 2017122394Sharti 2018122394Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 2019122394Sharti 2020124861Sharti#ifdef USE_LIBBEGEMOT 2021145673Sharti if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 2022124861Sharti syslog(LOG_ERR, "cannot set timer: %m"); 2023124861Sharti exit(1); 2024124861Sharti } 2025124861Sharti#else 2026122394Sharti if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 2027122394Sharti == -1) { 2028122394Sharti syslog(LOG_ERR, "cannot set timer: %m"); 2029122394Sharti exit(1); 2030122394Sharti } 2031124861Sharti#endif 2032122394Sharti return (tp); 2033122394Sharti} 2034122394Sharti 2035150920Sharti/* 2036150920Sharti * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 2037150920Sharti * is currently ignored and the initial number of ticks is set to the 2038150920Sharti * repeat number of ticks. 2039150920Sharti */ 2040150920Shartivoid * 2041150920Shartitimer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 2042150920Sharti void (*func)(void *), void *udata, struct lmodule *mod) 2043150920Sharti{ 2044150920Sharti struct timer *tp; 2045150920Sharti#ifndef USE_LIBBEGEMOT 2046150920Sharti struct timespec due; 2047150920Sharti struct timespec inter; 2048150920Sharti#endif 2049150920Sharti 2050150920Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 2051150920Sharti syslog(LOG_CRIT, "out of memory for timer"); 2052150920Sharti exit(1); 2053150920Sharti } 2054150920Sharti 2055150920Sharti#ifndef USE_LIBBEGEMOT 2056150920Sharti due = evAddTime(evNowTime(), 2057150920Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 2058150920Sharti inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 2059150920Sharti#endif 2060150920Sharti 2061150920Sharti tp->udata = udata; 2062150920Sharti tp->owner = mod; 2063150920Sharti tp->func = func; 2064150920Sharti 2065150920Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 2066150920Sharti 2067150920Sharti#ifdef USE_LIBBEGEMOT 2068150920Sharti if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 2069150920Sharti syslog(LOG_ERR, "cannot set timer: %m"); 2070150920Sharti exit(1); 2071150920Sharti } 2072150920Sharti#else 2073150920Sharti if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 2074150920Sharti syslog(LOG_ERR, "cannot set timer: %m"); 2075150920Sharti exit(1); 2076150920Sharti } 2077150920Sharti#endif 2078150920Sharti return (tp); 2079150920Sharti} 2080150920Sharti 2081150920Sharti/* 2082150920Sharti * Stop a timer. 2083150920Sharti */ 2084122394Shartivoid 2085122394Shartitimer_stop(void *p) 2086122394Sharti{ 2087122394Sharti struct timer *tp = p; 2088122394Sharti 2089122394Sharti LIST_REMOVE(tp, link); 2090124861Sharti#ifdef USE_LIBBEGEMOT 2091124861Sharti poll_stop_timer(tp->id); 2092124861Sharti#else 2093122394Sharti if (evClearTimer(evctx, tp->id) == -1) { 2094122394Sharti syslog(LOG_ERR, "cannot stop timer: %m"); 2095122394Sharti exit(1); 2096122394Sharti } 2097124861Sharti#endif 2098122394Sharti free(p); 2099122394Sharti} 2100122394Sharti 2101122394Shartistatic void 2102122394Shartitimer_flush(struct lmodule *mod) 2103122394Sharti{ 2104122394Sharti struct timer *t, *t1; 2105122394Sharti 2106122394Sharti t = LIST_FIRST(&timer_list); 2107122394Sharti while (t != NULL) { 2108122394Sharti t1 = LIST_NEXT(t, link); 2109122394Sharti if (t->owner == mod) 2110122394Sharti timer_stop(t); 2111122394Sharti t = t1; 2112122394Sharti } 2113122394Sharti} 2114122394Sharti 2115122394Shartistatic void 2116122394Shartisnmp_printf_func(const char *fmt, ...) 2117122394Sharti{ 2118122394Sharti va_list ap; 2119122394Sharti static char *pend = NULL; 2120122394Sharti char *ret, *new; 2121122394Sharti 2122122394Sharti va_start(ap, fmt); 2123122394Sharti vasprintf(&ret, fmt, ap); 2124122394Sharti va_end(ap); 2125122394Sharti 2126122394Sharti if (ret == NULL) 2127122394Sharti return; 2128122394Sharti if (pend != NULL) { 2129122394Sharti if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 2130122394Sharti == NULL) { 2131122394Sharti free(ret); 2132122394Sharti return; 2133122394Sharti } 2134122394Sharti pend = new; 2135122394Sharti strcat(pend, ret); 2136122394Sharti free(ret); 2137122394Sharti } else 2138122394Sharti pend = ret; 2139122394Sharti 2140122394Sharti while ((ret = strchr(pend, '\n')) != NULL) { 2141122394Sharti *ret = '\0'; 2142122394Sharti syslog(LOG_DEBUG, "%s", pend); 2143122394Sharti if (strlen(ret + 1) == 0) { 2144122394Sharti free(pend); 2145122394Sharti pend = NULL; 2146122394Sharti break; 2147122394Sharti } 2148122394Sharti strcpy(pend, ret + 1); 2149122394Sharti } 2150122394Sharti} 2151122394Sharti 2152122394Shartistatic void 2153122394Shartisnmp_error_func(const char *err, ...) 2154122394Sharti{ 2155122394Sharti char errbuf[1000]; 2156122394Sharti va_list ap; 2157122394Sharti 2158124861Sharti if (!(snmp_trace & LOG_SNMP_ERRORS)) 2159124861Sharti return; 2160124861Sharti 2161122394Sharti va_start(ap, err); 2162122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2163124861Sharti vsnprintf(errbuf + strlen(errbuf), 2164124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 2165122394Sharti va_end(ap); 2166122394Sharti 2167122394Sharti syslog(LOG_ERR, "%s", errbuf); 2168122394Sharti} 2169122394Sharti 2170122394Shartistatic void 2171122394Shartisnmp_debug_func(const char *err, ...) 2172122394Sharti{ 2173122394Sharti char errbuf[1000]; 2174122394Sharti va_list ap; 2175122394Sharti 2176122394Sharti va_start(ap, err); 2177122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2178122394Sharti vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2179122394Sharti err, ap); 2180122394Sharti va_end(ap); 2181122394Sharti 2182122394Sharti syslog(LOG_DEBUG, "%s", errbuf); 2183122394Sharti} 2184122394Sharti 2185122394Shartistatic void 2186122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...) 2187122394Sharti{ 2188122394Sharti char errbuf[1000]; 2189122394Sharti va_list ap; 2190122394Sharti u_int i; 2191122394Sharti 2192124861Sharti if (!(snmp_trace & LOG_ASN1_ERRORS)) 2193124861Sharti return; 2194124861Sharti 2195122394Sharti va_start(ap, err); 2196122394Sharti snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 2197124861Sharti vsnprintf(errbuf + strlen(errbuf), 2198124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 2199122394Sharti va_end(ap); 2200122394Sharti 2201122394Sharti if (b != NULL) { 2202124861Sharti snprintf(errbuf + strlen(errbuf), 2203124861Sharti sizeof(errbuf) - strlen(errbuf), " at"); 2204122394Sharti for (i = 0; b->asn_len > i; i++) 2205124861Sharti snprintf(errbuf + strlen(errbuf), 2206124861Sharti sizeof(errbuf) - strlen(errbuf), 2207124861Sharti " %02x", b->asn_cptr[i]); 2208122394Sharti } 2209122394Sharti 2210122394Sharti syslog(LOG_ERR, "%s", errbuf); 2211122394Sharti} 2212122394Sharti 2213122394Sharti/* 2214122394Sharti * Create a new community 2215122394Sharti */ 2216122394Shartiu_int 2217122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner, 2218122394Sharti const char *str) 2219122394Sharti{ 2220122394Sharti struct community *c, *p; 2221122394Sharti u_int ncomm; 2222122394Sharti 2223122394Sharti /* generate an identifier */ 2224122394Sharti do { 2225122394Sharti if ((ncomm = next_community_index++) == UINT_MAX) 2226122394Sharti next_community_index = 1; 2227122394Sharti TAILQ_FOREACH(c, &community_list, link) 2228122394Sharti if (c->value == ncomm) 2229122394Sharti break; 2230122394Sharti } while (c != NULL); 2231122394Sharti 2232122394Sharti if ((c = malloc(sizeof(struct community))) == NULL) { 2233122394Sharti syslog(LOG_ERR, "comm_define: %m"); 2234122394Sharti return (0); 2235122394Sharti } 2236122394Sharti c->owner = owner; 2237122394Sharti c->value = ncomm; 2238122394Sharti c->descr = descr; 2239122394Sharti c->string = NULL; 2240122394Sharti c->private = priv; 2241122394Sharti 2242122394Sharti if (str != NULL) { 2243122394Sharti if((c->string = malloc(strlen(str)+1)) == NULL) { 2244122394Sharti free(c); 2245122394Sharti return (0); 2246122394Sharti } 2247122394Sharti strcpy(c->string, str); 2248122394Sharti } 2249122394Sharti 2250122394Sharti /* make index */ 2251122394Sharti if (c->owner == NULL) { 2252122394Sharti c->index.len = 1; 2253122394Sharti c->index.subs[0] = 0; 2254122394Sharti } else { 2255122394Sharti c->index = c->owner->index; 2256122394Sharti } 2257122394Sharti c->index.subs[c->index.len++] = c->private; 2258122394Sharti 2259122394Sharti /* 2260122394Sharti * Insert ordered 2261122394Sharti */ 2262122394Sharti TAILQ_FOREACH(p, &community_list, link) { 2263122394Sharti if (asn_compare_oid(&p->index, &c->index) > 0) { 2264122394Sharti TAILQ_INSERT_BEFORE(p, c, link); 2265122394Sharti break; 2266122394Sharti } 2267122394Sharti } 2268122394Sharti if (p == NULL) 2269122394Sharti TAILQ_INSERT_TAIL(&community_list, c, link); 2270122394Sharti return (c->value); 2271122394Sharti} 2272122394Sharti 2273122394Sharticonst char * 2274122394Sharticomm_string(u_int ncomm) 2275122394Sharti{ 2276122394Sharti struct community *p; 2277122394Sharti 2278122394Sharti TAILQ_FOREACH(p, &community_list, link) 2279122394Sharti if (p->value == ncomm) 2280122394Sharti return (p->string); 2281122394Sharti return (NULL); 2282122394Sharti} 2283122394Sharti 2284122394Sharti/* 2285122394Sharti * Delete all communities allocated by a module 2286122394Sharti */ 2287122394Shartistatic void 2288122394Sharticomm_flush(struct lmodule *mod) 2289122394Sharti{ 2290122394Sharti struct community *p, *p1; 2291122394Sharti 2292122394Sharti p = TAILQ_FIRST(&community_list); 2293122394Sharti while (p != NULL) { 2294122394Sharti p1 = TAILQ_NEXT(p, link); 2295122394Sharti if (p->owner == mod) { 2296122394Sharti free(p->string); 2297122394Sharti TAILQ_REMOVE(&community_list, p, link); 2298122394Sharti free(p); 2299122394Sharti } 2300122394Sharti p = p1; 2301122394Sharti } 2302122394Sharti} 2303122394Sharti 2304122394Sharti/* 2305122394Sharti * Request ID handling. 2306122394Sharti * 2307122394Sharti * Allocate a new range of request ids. Use a first fit algorithm. 2308122394Sharti */ 2309122394Shartiu_int 2310122394Shartireqid_allocate(int size, struct lmodule *mod) 2311122394Sharti{ 2312122394Sharti u_int type; 2313122394Sharti struct idrange *r, *r1; 2314122394Sharti 2315122394Sharti if (size <= 0 || size > INT32_MAX) { 2316122394Sharti syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2317122394Sharti return (0); 2318122394Sharti } 2319122394Sharti /* allocate a type id */ 2320122394Sharti do { 2321122394Sharti if ((type = next_idrange++) == UINT_MAX) 2322122394Sharti next_idrange = 1; 2323122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2324122394Sharti if (r->type == type) 2325122394Sharti break; 2326122394Sharti } while(r != NULL); 2327122394Sharti 2328122394Sharti /* find a range */ 2329122394Sharti if (TAILQ_EMPTY(&idrange_list)) 2330122394Sharti r = NULL; 2331122394Sharti else { 2332122394Sharti r = TAILQ_FIRST(&idrange_list); 2333122394Sharti if (r->base < size) { 2334122394Sharti while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2335122394Sharti if (r1->base - (r->base + r->size) >= size) 2336122394Sharti break; 2337122394Sharti r = r1; 2338122394Sharti } 2339122394Sharti r = r1; 2340122394Sharti } 2341122394Sharti if (r == NULL) { 2342122394Sharti r1 = TAILQ_LAST(&idrange_list, idrange_list); 2343122394Sharti if (INT32_MAX - size + 1 < r1->base + r1->size) { 2344122394Sharti syslog(LOG_ERR, "out of id ranges (%u)", size); 2345122394Sharti return (0); 2346122394Sharti } 2347122394Sharti } 2348122394Sharti } 2349122394Sharti 2350122394Sharti /* allocate structure */ 2351122394Sharti if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2352122394Sharti syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2353122394Sharti return (0); 2354122394Sharti } 2355122394Sharti 2356122394Sharti r1->type = type; 2357122394Sharti r1->size = size; 2358122394Sharti r1->owner = mod; 2359122394Sharti if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2360122394Sharti r1->base = 0; 2361122394Sharti TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2362122394Sharti } else if (r == NULL) { 2363122394Sharti r = TAILQ_LAST(&idrange_list, idrange_list); 2364122394Sharti r1->base = r->base + r->size; 2365122394Sharti TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2366122394Sharti } else { 2367122394Sharti r = TAILQ_PREV(r, idrange_list, link); 2368122394Sharti r1->base = r->base + r->size; 2369122394Sharti TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2370122394Sharti } 2371122394Sharti r1->next = r1->base; 2372122394Sharti 2373122394Sharti return (type); 2374122394Sharti} 2375122394Sharti 2376122394Shartiint32_t 2377122394Shartireqid_next(u_int type) 2378122394Sharti{ 2379122394Sharti struct idrange *r; 2380122394Sharti int32_t id; 2381122394Sharti 2382122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2383122394Sharti if (r->type == type) 2384122394Sharti break; 2385122394Sharti if (r == NULL) { 2386122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2387122394Sharti abort(); 2388122394Sharti } 2389122394Sharti if ((id = r->next++) == r->base + (r->size - 1)) 2390122394Sharti r->next = r->base; 2391122394Sharti return (id); 2392122394Sharti} 2393122394Sharti 2394122394Shartiint32_t 2395122394Shartireqid_base(u_int type) 2396122394Sharti{ 2397122394Sharti struct idrange *r; 2398122394Sharti 2399122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2400122394Sharti if (r->type == type) 2401122394Sharti return (r->base); 2402122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2403122394Sharti abort(); 2404122394Sharti} 2405122394Sharti 2406122394Shartiu_int 2407122394Shartireqid_type(int32_t reqid) 2408122394Sharti{ 2409122394Sharti struct idrange *r; 2410122394Sharti 2411122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2412122394Sharti if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2413122394Sharti return (r->type); 2414122394Sharti return (0); 2415122394Sharti} 2416122394Sharti 2417122394Shartiint 2418122394Shartireqid_istype(int32_t reqid, u_int type) 2419122394Sharti{ 2420122394Sharti return (reqid_type(reqid) == type); 2421122394Sharti} 2422122394Sharti 2423122394Sharti/* 2424122394Sharti * Delete all communities allocated by a module 2425122394Sharti */ 2426122394Shartistatic void 2427122394Shartireqid_flush(struct lmodule *mod) 2428122394Sharti{ 2429122394Sharti struct idrange *p, *p1; 2430122394Sharti 2431122394Sharti p = TAILQ_FIRST(&idrange_list); 2432122394Sharti while (p != NULL) { 2433122394Sharti p1 = TAILQ_NEXT(p, link); 2434122394Sharti if (p->owner == mod) { 2435122394Sharti TAILQ_REMOVE(&idrange_list, p, link); 2436122394Sharti free(p); 2437122394Sharti } 2438122394Sharti p = p1; 2439122394Sharti } 2440122394Sharti} 2441122394Sharti 2442122394Sharti/* 2443122394Sharti * Merge the given tree for the given module into the main tree. 2444122394Sharti */ 2445122394Shartistatic int 2446122394Sharticompare_node(const void *v1, const void *v2) 2447122394Sharti{ 2448122394Sharti const struct snmp_node *n1 = v1; 2449122394Sharti const struct snmp_node *n2 = v2; 2450122394Sharti 2451122394Sharti return (asn_compare_oid(&n1->oid, &n2->oid)); 2452122394Sharti} 2453122394Shartistatic int 2454122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2455122394Sharti{ 2456122394Sharti struct snmp_node *xtree; 2457122394Sharti u_int i; 2458122394Sharti 2459122394Sharti xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2460122394Sharti if (xtree == NULL) { 2461128237Sharti syslog(LOG_ERR, "tree_merge: %m"); 2462122394Sharti return (-1); 2463122394Sharti } 2464122394Sharti tree = xtree; 2465122394Sharti memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2466122394Sharti 2467122394Sharti for (i = 0; i < nsize; i++) 2468128237Sharti tree[tree_size + i].tree_data = mod; 2469122394Sharti 2470122394Sharti tree_size += nsize; 2471122394Sharti 2472122394Sharti qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2473122394Sharti 2474122394Sharti return (0); 2475122394Sharti} 2476122394Sharti 2477122394Sharti/* 2478122394Sharti * Remove all nodes belonging to the loadable module 2479122394Sharti */ 2480122394Shartistatic void 2481122394Shartitree_unmerge(struct lmodule *mod) 2482122394Sharti{ 2483122394Sharti u_int s, d; 2484122394Sharti 2485122394Sharti for(s = d = 0; s < tree_size; s++) 2486128237Sharti if (tree[s].tree_data != mod) { 2487122394Sharti if (s != d) 2488122394Sharti tree[d] = tree[s]; 2489122394Sharti d++; 2490122394Sharti } 2491122394Sharti tree_size = d; 2492122394Sharti} 2493122394Sharti 2494122394Sharti/* 2495122394Sharti * Loadable modules 2496122394Sharti */ 2497122394Shartistruct lmodule * 2498122394Shartilm_load(const char *path, const char *section) 2499122394Sharti{ 2500122394Sharti struct lmodule *m; 2501122394Sharti int err; 2502122394Sharti int i; 2503122394Sharti char *av[MAX_MOD_ARGS + 1]; 2504122394Sharti int ac; 2505122394Sharti u_int u; 2506122394Sharti 2507122394Sharti if ((m = malloc(sizeof(*m))) == NULL) { 2508122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2509122394Sharti return (NULL); 2510122394Sharti } 2511122394Sharti m->handle = NULL; 2512122394Sharti m->flags = 0; 2513122394Sharti strcpy(m->section, section); 2514122394Sharti 2515122394Sharti if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2516122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2517122394Sharti goto err; 2518122394Sharti } 2519122394Sharti strcpy(m->path, path); 2520122394Sharti 2521122394Sharti /* 2522122394Sharti * Make index 2523122394Sharti */ 2524122394Sharti m->index.subs[0] = strlen(section); 2525122394Sharti m->index.len = m->index.subs[0] + 1; 2526122394Sharti for (u = 0; u < m->index.subs[0]; u++) 2527122394Sharti m->index.subs[u + 1] = section[u]; 2528122394Sharti 2529122394Sharti /* 2530122394Sharti * Load the object file and locate the config structure 2531122394Sharti */ 2532122394Sharti if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2533122394Sharti syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2534122394Sharti goto err; 2535122394Sharti } 2536122394Sharti 2537122394Sharti if ((m->config = dlsym(m->handle, "config")) == NULL) { 2538122394Sharti syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2539122394Sharti goto err; 2540122394Sharti } 2541122394Sharti 2542122394Sharti /* 2543122394Sharti * Insert it into the right place 2544122394Sharti */ 2545122394Sharti INSERT_OBJECT_OID(m, &lmodules); 2546122394Sharti 2547122394Sharti /* preserve order */ 2548122394Sharti if (community == COMM_INITIALIZE) { 2549122394Sharti m->flags |= LM_ONSTARTLIST; 2550122394Sharti TAILQ_INSERT_TAIL(&modules_start, m, start); 2551122394Sharti } 2552122394Sharti 2553122394Sharti /* 2554122394Sharti * make the argument vector. 2555122394Sharti */ 2556122394Sharti ac = 0; 2557122394Sharti for (i = 0; i < nprogargs; i++) { 2558122394Sharti if (strlen(progargs[i]) >= strlen(section) + 1 && 2559122394Sharti strncmp(progargs[i], section, strlen(section)) == 0 && 2560122394Sharti progargs[i][strlen(section)] == ':') { 2561122394Sharti if (ac == MAX_MOD_ARGS) { 2562122394Sharti syslog(LOG_WARNING, "too many arguments for " 2563122394Sharti "module '%s", section); 2564122394Sharti break; 2565122394Sharti } 2566122394Sharti av[ac++] = &progargs[i][strlen(section)+1]; 2567122394Sharti } 2568122394Sharti } 2569122394Sharti av[ac] = NULL; 2570122394Sharti 2571122394Sharti /* 2572150920Sharti * Run the initialization function 2573122394Sharti */ 2574122394Sharti if ((err = (*m->config->init)(m, ac, av)) != 0) { 2575122394Sharti syslog(LOG_ERR, "lm_load: init failed: %d", err); 2576122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2577122394Sharti goto err; 2578122394Sharti } 2579122394Sharti 2580122394Sharti return (m); 2581122394Sharti 2582122394Sharti err: 2583176892Ssyrinx if ((m->flags & LM_ONSTARTLIST) != 0) 2584176892Ssyrinx TAILQ_REMOVE(&modules_start, m, start); 2585122394Sharti if (m->handle) 2586122394Sharti dlclose(m->handle); 2587122394Sharti free(m->path); 2588122394Sharti free(m); 2589122394Sharti return (NULL); 2590122394Sharti} 2591122394Sharti 2592122394Sharti/* 2593122394Sharti * Start a module 2594122394Sharti */ 2595122394Shartivoid 2596122394Shartilm_start(struct lmodule *mod) 2597122394Sharti{ 2598122394Sharti const struct lmodule *m; 2599122394Sharti 2600122394Sharti /* 2601122394Sharti * Merge tree. If this fails, unload the module. 2602122394Sharti */ 2603122394Sharti if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2604122394Sharti lm_unload(mod); 2605122394Sharti return; 2606122394Sharti } 2607122394Sharti 2608122394Sharti /* 2609122394Sharti * Read configuration 2610122394Sharti */ 2611122394Sharti if (read_config(config_file, mod)) { 2612122394Sharti syslog(LOG_ERR, "error in config file"); 2613122394Sharti lm_unload(mod); 2614122394Sharti return; 2615122394Sharti } 2616122394Sharti if (mod->config->start) 2617122394Sharti (*mod->config->start)(); 2618122394Sharti 2619122394Sharti mod->flags |= LM_STARTED; 2620122394Sharti 2621122394Sharti /* 2622122394Sharti * Inform other modules 2623122394Sharti */ 2624122394Sharti TAILQ_FOREACH(m, &lmodules, link) 2625122394Sharti if (m->config->loading) 2626122394Sharti (*m->config->loading)(mod, 1); 2627122394Sharti} 2628122394Sharti 2629122394Sharti 2630122394Sharti/* 2631122394Sharti * Unload a module. 2632122394Sharti */ 2633122394Shartivoid 2634122394Shartilm_unload(struct lmodule *m) 2635122394Sharti{ 2636122394Sharti int err; 2637122394Sharti const struct lmodule *mod; 2638122394Sharti 2639122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2640122394Sharti if (m->flags & LM_ONSTARTLIST) 2641122394Sharti TAILQ_REMOVE(&modules_start, m, start); 2642122394Sharti tree_unmerge(m); 2643122394Sharti 2644122394Sharti if ((m->flags & LM_STARTED) && m->config->fini && 2645122394Sharti (err = (*m->config->fini)()) != 0) 2646122394Sharti syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2647122394Sharti 2648122394Sharti comm_flush(m); 2649122394Sharti reqid_flush(m); 2650122394Sharti timer_flush(m); 2651122394Sharti fd_flush(m); 2652122394Sharti 2653122394Sharti dlclose(m->handle); 2654122394Sharti free(m->path); 2655122394Sharti 2656122394Sharti /* 2657122394Sharti * Inform other modules 2658122394Sharti */ 2659122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 2660122394Sharti if (mod->config->loading) 2661122394Sharti (*mod->config->loading)(m, 0); 2662122394Sharti 2663122394Sharti free(m); 2664122394Sharti} 2665122394Sharti 2666122394Sharti/* 2667122394Sharti * Register an object resource and return the index (or 0 on failures) 2668122394Sharti */ 2669122394Shartiu_int 2670122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2671122394Sharti{ 2672122394Sharti struct objres *objres, *or1; 2673122394Sharti u_int idx; 2674122394Sharti 2675122394Sharti /* find a free index */ 2676122394Sharti idx = 1; 2677122394Sharti for (objres = TAILQ_FIRST(&objres_list); 2678122394Sharti objres != NULL; 2679122394Sharti objres = TAILQ_NEXT(objres, link)) { 2680122394Sharti if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2681122394Sharti or1->index > objres->index + 1) { 2682122394Sharti idx = objres->index + 1; 2683122394Sharti break; 2684122394Sharti } 2685122394Sharti } 2686122394Sharti 2687122394Sharti if ((objres = malloc(sizeof(*objres))) == NULL) 2688122394Sharti return (0); 2689122394Sharti 2690122394Sharti objres->index = idx; 2691122394Sharti objres->oid = *or; 2692122394Sharti strlcpy(objres->descr, descr, sizeof(objres->descr)); 2693146525Sharti objres->uptime = (uint32_t)(get_ticks() - start_tick); 2694122394Sharti objres->module = mod; 2695122394Sharti 2696122394Sharti INSERT_OBJECT_INT(objres, &objres_list); 2697122394Sharti 2698122394Sharti systemg.or_last_change = objres->uptime; 2699122394Sharti 2700122394Sharti return (idx); 2701122394Sharti} 2702122394Sharti 2703122394Shartivoid 2704122394Shartior_unregister(u_int idx) 2705122394Sharti{ 2706122394Sharti struct objres *objres; 2707122394Sharti 2708122394Sharti TAILQ_FOREACH(objres, &objres_list, link) 2709122394Sharti if (objres->index == idx) { 2710122394Sharti TAILQ_REMOVE(&objres_list, objres, link); 2711122394Sharti free(objres); 2712122394Sharti return; 2713122394Sharti } 2714122394Sharti} 2715216294Ssyrinx 2716216294Ssyrinx/* 2717216294Ssyrinx * RFC 3414 User-based Security Model support 2718216294Ssyrinx */ 2719216294Ssyrinx 2720216294Ssyrinxstruct snmpd_usmstat * 2721216294Ssyrinxbsnmpd_get_usm_stats(void) 2722216294Ssyrinx{ 2723216294Ssyrinx return (&snmpd_usmstats); 2724216294Ssyrinx} 2725216294Ssyrinx 2726216294Ssyrinxvoid 2727216294Ssyrinxbsnmpd_reset_usm_stats(void) 2728216294Ssyrinx{ 2729233128Sharti memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); 2730216294Ssyrinx} 2731216294Ssyrinx 2732216294Ssyrinxstruct usm_user * 2733216294Ssyrinxusm_first_user(void) 2734216294Ssyrinx{ 2735216294Ssyrinx return (SLIST_FIRST(&usm_userlist)); 2736216294Ssyrinx} 2737216294Ssyrinx 2738216294Ssyrinxstruct usm_user * 2739216294Ssyrinxusm_next_user(struct usm_user *uuser) 2740216294Ssyrinx{ 2741216294Ssyrinx if (uuser == NULL) 2742216294Ssyrinx return (NULL); 2743216294Ssyrinx 2744216294Ssyrinx return (SLIST_NEXT(uuser, up)); 2745216294Ssyrinx} 2746216294Ssyrinx 2747216294Ssyrinxstruct usm_user * 2748216294Ssyrinxusm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2749216294Ssyrinx{ 2750216294Ssyrinx struct usm_user *uuser; 2751216294Ssyrinx 2752216294Ssyrinx SLIST_FOREACH(uuser, &usm_userlist, up) 2753216294Ssyrinx if (uuser->user_engine_len == elen && 2754216294Ssyrinx memcmp(uuser->user_engine_id, engine, elen) == 0 && 2755216294Ssyrinx strlen(uuser->suser.sec_name) == strlen(uname) && 2756216294Ssyrinx strcmp(uuser->suser.sec_name, uname) == 0) 2757216294Ssyrinx break; 2758216294Ssyrinx 2759216294Ssyrinx return (uuser); 2760216294Ssyrinx} 2761216294Ssyrinx 2762216294Ssyrinxstatic int 2763216294Ssyrinxusm_compare_user(struct usm_user *u1, struct usm_user *u2) 2764216294Ssyrinx{ 2765216294Ssyrinx uint32_t i; 2766216294Ssyrinx 2767216294Ssyrinx if (u1->user_engine_len < u2->user_engine_len) 2768216294Ssyrinx return (-1); 2769216294Ssyrinx if (u1->user_engine_len > u2->user_engine_len) 2770216294Ssyrinx return (1); 2771216294Ssyrinx 2772216294Ssyrinx for (i = 0; i < u1->user_engine_len; i++) { 2773216294Ssyrinx if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2774216294Ssyrinx return (-1); 2775216294Ssyrinx if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2776216294Ssyrinx return (1); 2777216294Ssyrinx } 2778216294Ssyrinx 2779216294Ssyrinx if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2780216294Ssyrinx return (-1); 2781216294Ssyrinx if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2782216294Ssyrinx return (1); 2783216294Ssyrinx 2784216294Ssyrinx for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2785216294Ssyrinx if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2786216294Ssyrinx return (-1); 2787216294Ssyrinx if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2788216294Ssyrinx return (1); 2789216294Ssyrinx } 2790216294Ssyrinx 2791216294Ssyrinx return (0); 2792216294Ssyrinx} 2793216294Ssyrinx 2794216294Ssyrinxstruct usm_user * 2795216294Ssyrinxusm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2796216294Ssyrinx{ 2797216294Ssyrinx int cmp; 2798216294Ssyrinx struct usm_user *uuser, *temp, *prev; 2799216294Ssyrinx 2800216294Ssyrinx for (uuser = usm_first_user(); uuser != NULL; 2801216294Ssyrinx (uuser = usm_next_user(uuser))) { 2802216294Ssyrinx if (uuser->user_engine_len == elen && 2803216294Ssyrinx strlen(uname) == strlen(uuser->suser.sec_name) && 2804216294Ssyrinx strcmp(uname, uuser->suser.sec_name) == 0 && 2805216294Ssyrinx memcmp(eid, uuser->user_engine_id, elen) == 0) 2806216294Ssyrinx return (NULL); 2807216294Ssyrinx } 2808216294Ssyrinx 2809216294Ssyrinx if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2810216294Ssyrinx return (NULL); 2811216294Ssyrinx 2812216294Ssyrinx memset(uuser, 0, sizeof(struct usm_user)); 2813216294Ssyrinx strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2814216294Ssyrinx memcpy(uuser->user_engine_id, eid, elen); 2815216294Ssyrinx uuser->user_engine_len = elen; 2816216294Ssyrinx 2817216294Ssyrinx if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2818216294Ssyrinx usm_compare_user(uuser, prev) < 0) { 2819216294Ssyrinx SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2820216294Ssyrinx return (uuser); 2821216294Ssyrinx } 2822216294Ssyrinx 2823216294Ssyrinx SLIST_FOREACH(temp, &usm_userlist, up) { 2824216294Ssyrinx if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2825216294Ssyrinx break; 2826216294Ssyrinx prev = temp; 2827216294Ssyrinx } 2828216294Ssyrinx 2829216294Ssyrinx if (temp == NULL || cmp < 0) 2830216294Ssyrinx SLIST_INSERT_AFTER(prev, uuser, up); 2831216294Ssyrinx else if (cmp > 0) 2832216294Ssyrinx SLIST_INSERT_AFTER(temp, uuser, up); 2833216294Ssyrinx else { 2834216294Ssyrinx syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2835216294Ssyrinx free(uuser); 2836216294Ssyrinx return (NULL); 2837216294Ssyrinx } 2838216294Ssyrinx 2839216294Ssyrinx return (uuser); 2840216294Ssyrinx} 2841216294Ssyrinx 2842216294Ssyrinxvoid 2843216294Ssyrinxusm_delete_user(struct usm_user *uuser) 2844216294Ssyrinx{ 2845216294Ssyrinx SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2846216294Ssyrinx free(uuser); 2847216294Ssyrinx} 2848216294Ssyrinx 2849216294Ssyrinxvoid 2850216294Ssyrinxusm_flush_users(void) 2851216294Ssyrinx{ 2852216294Ssyrinx struct usm_user *uuser; 2853216294Ssyrinx 2854216294Ssyrinx while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2855216294Ssyrinx SLIST_REMOVE_HEAD(&usm_userlist, up); 2856216294Ssyrinx free(uuser); 2857216294Ssyrinx } 2858216294Ssyrinx 2859216294Ssyrinx SLIST_INIT(&usm_userlist); 2860216294Ssyrinx} 2861216294Ssyrinx 2862216294Ssyrinx/* 2863216294Ssyrinx * RFC 3415 View-based Access Control Model support 2864216294Ssyrinx */ 2865216294Ssyrinxstruct vacm_user * 2866216294Ssyrinxvacm_first_user(void) 2867216294Ssyrinx{ 2868216294Ssyrinx return (SLIST_FIRST(&vacm_userlist)); 2869216294Ssyrinx} 2870216294Ssyrinx 2871216294Ssyrinxstruct vacm_user * 2872216294Ssyrinxvacm_next_user(struct vacm_user *vuser) 2873216294Ssyrinx{ 2874216294Ssyrinx if (vuser == NULL) 2875216294Ssyrinx return (NULL); 2876216294Ssyrinx 2877216294Ssyrinx return (SLIST_NEXT(vuser, vvu)); 2878216294Ssyrinx} 2879216294Ssyrinx 2880216294Ssyrinxstatic int 2881216294Ssyrinxvacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2882216294Ssyrinx{ 2883216294Ssyrinx uint32_t i; 2884216294Ssyrinx 2885216294Ssyrinx if (v1->sec_model < v2->sec_model) 2886216294Ssyrinx return (-1); 2887216294Ssyrinx if (v1->sec_model > v2->sec_model) 2888216294Ssyrinx return (1); 2889216294Ssyrinx 2890216294Ssyrinx if (strlen(v1->secname) < strlen(v2->secname)) 2891216294Ssyrinx return (-1); 2892216294Ssyrinx if (strlen(v1->secname) > strlen(v2->secname)) 2893216294Ssyrinx return (1); 2894216294Ssyrinx 2895216294Ssyrinx for (i = 0; i < strlen(v1->secname); i++) { 2896216294Ssyrinx if (v1->secname[i] < v2->secname[i]) 2897216294Ssyrinx return (-1); 2898216294Ssyrinx if (v1->secname[i] > v2->secname[i]) 2899216294Ssyrinx return (1); 2900216294Ssyrinx } 2901216294Ssyrinx 2902216294Ssyrinx return (0); 2903216294Ssyrinx} 2904216294Ssyrinx 2905216294Ssyrinxstruct vacm_user * 2906216294Ssyrinxvacm_new_user(int32_t smodel, char *uname) 2907216294Ssyrinx{ 2908216294Ssyrinx int cmp; 2909216294Ssyrinx struct vacm_user *user, *temp, *prev; 2910216294Ssyrinx 2911216294Ssyrinx SLIST_FOREACH(user, &vacm_userlist, vvu) 2912216294Ssyrinx if (strcmp(uname, user->secname) == 0 && 2913216294Ssyrinx smodel == user->sec_model) 2914216294Ssyrinx return (NULL); 2915216294Ssyrinx 2916216294Ssyrinx if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2917216294Ssyrinx return (NULL); 2918216294Ssyrinx 2919216294Ssyrinx memset(user, 0, sizeof(*user)); 2920216294Ssyrinx user->group = &vacm_default_group; 2921216294Ssyrinx SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2922216294Ssyrinx user->sec_model = smodel; 2923216294Ssyrinx strlcpy(user->secname, uname, sizeof(user->secname)); 2924216294Ssyrinx 2925216294Ssyrinx if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2926216294Ssyrinx vacm_compare_user(user, prev) < 0) { 2927216294Ssyrinx SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2928216294Ssyrinx return (user); 2929216294Ssyrinx } 2930216294Ssyrinx 2931216294Ssyrinx SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2932216294Ssyrinx if ((cmp = vacm_compare_user(user, temp)) <= 0) 2933216294Ssyrinx break; 2934216294Ssyrinx prev = temp; 2935216294Ssyrinx } 2936216294Ssyrinx 2937216294Ssyrinx if (temp == NULL || cmp < 0) 2938216294Ssyrinx SLIST_INSERT_AFTER(prev, user, vvu); 2939216294Ssyrinx else if (cmp > 0) 2940216294Ssyrinx SLIST_INSERT_AFTER(temp, user, vvu); 2941216294Ssyrinx else { 2942216294Ssyrinx syslog(LOG_ERR, "User %s exists", user->secname); 2943216294Ssyrinx free(user); 2944216294Ssyrinx return (NULL); 2945216294Ssyrinx } 2946216294Ssyrinx 2947216294Ssyrinx return (user); 2948216294Ssyrinx} 2949216294Ssyrinx 2950216294Ssyrinxint 2951216294Ssyrinxvacm_delete_user(struct vacm_user *user) 2952216294Ssyrinx{ 2953216294Ssyrinx if (user->group != NULL && user->group != &vacm_default_group) { 2954216294Ssyrinx SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2955216294Ssyrinx if (SLIST_EMPTY(&user->group->group_users)) { 2956216294Ssyrinx SLIST_REMOVE(&vacm_grouplist, user->group, 2957216294Ssyrinx vacm_group, vge); 2958216294Ssyrinx free(user->group); 2959216294Ssyrinx } 2960216294Ssyrinx } 2961216294Ssyrinx 2962216294Ssyrinx SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2963216294Ssyrinx free(user); 2964216294Ssyrinx 2965216294Ssyrinx return (0); 2966216294Ssyrinx} 2967216294Ssyrinx 2968216294Ssyrinxint 2969216294Ssyrinxvacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2970216294Ssyrinx{ 2971216294Ssyrinx struct vacm_group *group; 2972216294Ssyrinx 2973216294Ssyrinx if (len >= SNMP_ADM_STR32_SIZ) 2974216294Ssyrinx return (-1); 2975216294Ssyrinx 2976216294Ssyrinx SLIST_FOREACH(group, &vacm_grouplist, vge) 2977216294Ssyrinx if (strlen(group->groupname) == len && 2978216294Ssyrinx memcmp(octets, group->groupname, len) == 0) 2979216294Ssyrinx break; 2980216294Ssyrinx 2981216294Ssyrinx if (group == NULL) { 2982216294Ssyrinx if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2983216294Ssyrinx return (-1); 2984216294Ssyrinx memset(group, 0, sizeof(*group)); 2985216294Ssyrinx memcpy(group->groupname, octets, len); 2986216294Ssyrinx group->groupname[len] = '\0'; 2987216294Ssyrinx SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2988216294Ssyrinx } 2989216294Ssyrinx 2990216294Ssyrinx SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2991216294Ssyrinx SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2992216294Ssyrinx user->group = group; 2993216294Ssyrinx 2994216294Ssyrinx return (0); 2995216294Ssyrinx} 2996216294Ssyrinx 2997216294Ssyrinxvoid 2998216294Ssyrinxvacm_groups_init(void) 2999216294Ssyrinx{ 3000216294Ssyrinx SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 3001216294Ssyrinx} 3002216294Ssyrinx 3003216294Ssyrinxstruct vacm_access * 3004216294Ssyrinxvacm_first_access_rule(void) 3005216294Ssyrinx{ 3006216294Ssyrinx return (TAILQ_FIRST(&vacm_accesslist)); 3007216294Ssyrinx} 3008216294Ssyrinx 3009216294Ssyrinxstruct vacm_access * 3010216294Ssyrinxvacm_next_access_rule(struct vacm_access *acl) 3011216294Ssyrinx{ 3012216294Ssyrinx if (acl == NULL) 3013216294Ssyrinx return (NULL); 3014216294Ssyrinx 3015216294Ssyrinx return (TAILQ_NEXT(acl, vva)); 3016216294Ssyrinx} 3017216294Ssyrinx 3018216294Ssyrinxstatic int 3019216294Ssyrinxvacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 3020216294Ssyrinx{ 3021216294Ssyrinx uint32_t i; 3022216294Ssyrinx 3023216294Ssyrinx if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 3024216294Ssyrinx return (-1); 3025216294Ssyrinx if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 3026216294Ssyrinx return (1); 3027216294Ssyrinx 3028216294Ssyrinx for (i = 0; i < strlen(v1->group->groupname); i++) { 3029216294Ssyrinx if (v1->group->groupname[i] < v2->group->groupname[i]) 3030216294Ssyrinx return (-1); 3031216294Ssyrinx if (v1->group->groupname[i] > v2->group->groupname[i]) 3032216294Ssyrinx return (1); 3033216294Ssyrinx } 3034216294Ssyrinx 3035216294Ssyrinx if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 3036216294Ssyrinx return (-1); 3037216294Ssyrinx if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 3038216294Ssyrinx return (1); 3039216294Ssyrinx 3040216294Ssyrinx for (i = 0; i < strlen(v1->ctx_prefix); i++) { 3041216294Ssyrinx if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 3042216294Ssyrinx return (-1); 3043216294Ssyrinx if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 3044216294Ssyrinx return (1); 3045216294Ssyrinx } 3046216294Ssyrinx 3047216294Ssyrinx if (v1->sec_model < v2->sec_model) 3048216294Ssyrinx return (-1); 3049216294Ssyrinx if (v1->sec_model > v2->sec_model) 3050216294Ssyrinx return (1); 3051216294Ssyrinx 3052216294Ssyrinx if (v1->sec_level < v2->sec_level) 3053216294Ssyrinx return (-1); 3054216294Ssyrinx if (v1->sec_level > v2->sec_level) 3055216294Ssyrinx return (1); 3056216294Ssyrinx 3057216294Ssyrinx return (0); 3058216294Ssyrinx} 3059216294Ssyrinx 3060216294Ssyrinxstruct vacm_access * 3061216294Ssyrinxvacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 3062216294Ssyrinx{ 3063216294Ssyrinx struct vacm_group *group; 3064216294Ssyrinx struct vacm_access *acl, *temp; 3065216294Ssyrinx 3066216294Ssyrinx TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 3067216294Ssyrinx if (acl->group == NULL) 3068216294Ssyrinx continue; 3069216294Ssyrinx if (strcmp(gname, acl->group->groupname) == 0 && 3070216294Ssyrinx strcmp(cprefix, acl->ctx_prefix) == 0 && 3071216294Ssyrinx acl->sec_model == smodel && acl->sec_level == slevel) 3072216294Ssyrinx return (NULL); 3073216294Ssyrinx } 3074216294Ssyrinx 3075216294Ssyrinx /* Make sure the group exists */ 3076216294Ssyrinx SLIST_FOREACH(group, &vacm_grouplist, vge) 3077216294Ssyrinx if (strcmp(gname, group->groupname) == 0) 3078216294Ssyrinx break; 3079216294Ssyrinx 3080216294Ssyrinx if (group == NULL) 3081216294Ssyrinx return (NULL); 3082216294Ssyrinx 3083216294Ssyrinx if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 3084216294Ssyrinx return (NULL); 3085216294Ssyrinx 3086216294Ssyrinx memset(acl, 0, sizeof(*acl)); 3087216294Ssyrinx acl->group = group; 3088216294Ssyrinx strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 3089216294Ssyrinx acl->sec_model = smodel; 3090216294Ssyrinx acl->sec_level = slevel; 3091216294Ssyrinx 3092216294Ssyrinx if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 3093216294Ssyrinx vacm_compare_access_rule(acl, temp) < 0) { 3094216294Ssyrinx TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 3095216294Ssyrinx return (acl); 3096216294Ssyrinx } 3097216294Ssyrinx 3098216294Ssyrinx TAILQ_FOREACH(temp, &vacm_accesslist, vva) 3099216294Ssyrinx if (vacm_compare_access_rule(acl, temp) < 0) { 3100216294Ssyrinx TAILQ_INSERT_BEFORE(temp, acl, vva); 3101216294Ssyrinx return (acl); 3102216294Ssyrinx } 3103216294Ssyrinx 3104216294Ssyrinx TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 3105216294Ssyrinx 3106216294Ssyrinx return (acl); 3107216294Ssyrinx} 3108216294Ssyrinx 3109216294Ssyrinxint 3110216294Ssyrinxvacm_delete_access_rule(struct vacm_access *acl) 3111216294Ssyrinx{ 3112216294Ssyrinx TAILQ_REMOVE(&vacm_accesslist, acl, vva); 3113216294Ssyrinx free(acl); 3114216294Ssyrinx 3115216294Ssyrinx return (0); 3116216294Ssyrinx} 3117216294Ssyrinx 3118216294Ssyrinxstruct vacm_view * 3119216294Ssyrinxvacm_first_view(void) 3120216294Ssyrinx{ 3121216294Ssyrinx return (SLIST_FIRST(&vacm_viewlist)); 3122216294Ssyrinx} 3123216294Ssyrinx 3124216294Ssyrinxstruct vacm_view * 3125216294Ssyrinxvacm_next_view(struct vacm_view *view) 3126216294Ssyrinx{ 3127216294Ssyrinx if (view == NULL) 3128216294Ssyrinx return (NULL); 3129216294Ssyrinx 3130216294Ssyrinx return (SLIST_NEXT(view, vvl)); 3131216294Ssyrinx} 3132216294Ssyrinx 3133216294Ssyrinxstatic int 3134216294Ssyrinxvacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3135216294Ssyrinx{ 3136216294Ssyrinx uint32_t i; 3137216294Ssyrinx 3138216294Ssyrinx if (strlen(v1->viewname) < strlen(v2->viewname)) 3139216294Ssyrinx return (-1); 3140216294Ssyrinx if (strlen(v1->viewname) > strlen(v2->viewname)) 3141216294Ssyrinx return (1); 3142216294Ssyrinx 3143216294Ssyrinx for (i = 0; i < strlen(v1->viewname); i++) { 3144216294Ssyrinx if (v1->viewname[i] < v2->viewname[i]) 3145216294Ssyrinx return (-1); 3146216294Ssyrinx if (v1->viewname[i] > v2->viewname[i]) 3147216294Ssyrinx return (1); 3148216294Ssyrinx } 3149216294Ssyrinx 3150216294Ssyrinx return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3151216294Ssyrinx} 3152216294Ssyrinx 3153216294Ssyrinxstruct vacm_view * 3154216294Ssyrinxvacm_new_view(char *vname, struct asn_oid *oid) 3155216294Ssyrinx{ 3156216294Ssyrinx int cmp; 3157216294Ssyrinx struct vacm_view *view, *temp, *prev; 3158216294Ssyrinx 3159216294Ssyrinx SLIST_FOREACH(view, &vacm_viewlist, vvl) 3160216294Ssyrinx if (strcmp(vname, view->viewname) == 0) 3161216294Ssyrinx return (NULL); 3162216294Ssyrinx 3163216294Ssyrinx if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3164216294Ssyrinx return (NULL); 3165216294Ssyrinx 3166216294Ssyrinx memset(view, 0, sizeof(*view)); 3167216294Ssyrinx strlcpy(view->viewname, vname, sizeof(view->viewname)); 3168216294Ssyrinx asn_append_oid(&view->subtree, oid); 3169216294Ssyrinx 3170216294Ssyrinx if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3171216294Ssyrinx vacm_compare_view(view, prev) < 0) { 3172216294Ssyrinx SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3173216294Ssyrinx return (view); 3174216294Ssyrinx } 3175216294Ssyrinx 3176216294Ssyrinx SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3177216294Ssyrinx if ((cmp = vacm_compare_view(view, temp)) <= 0) 3178216294Ssyrinx break; 3179216294Ssyrinx prev = temp; 3180216294Ssyrinx } 3181216294Ssyrinx 3182216294Ssyrinx if (temp == NULL || cmp < 0) 3183216294Ssyrinx SLIST_INSERT_AFTER(prev, view, vvl); 3184216294Ssyrinx else if (cmp > 0) 3185216294Ssyrinx SLIST_INSERT_AFTER(temp, view, vvl); 3186216294Ssyrinx else { 3187216294Ssyrinx syslog(LOG_ERR, "View %s exists", view->viewname); 3188216294Ssyrinx free(view); 3189216294Ssyrinx return (NULL); 3190216294Ssyrinx } 3191216294Ssyrinx 3192216294Ssyrinx return (view); 3193216294Ssyrinx} 3194216294Ssyrinx 3195216294Ssyrinxint 3196216294Ssyrinxvacm_delete_view(struct vacm_view *view) 3197216294Ssyrinx{ 3198216294Ssyrinx SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3199216294Ssyrinx free(view); 3200216294Ssyrinx 3201216294Ssyrinx return (0); 3202216294Ssyrinx} 3203216294Ssyrinx 3204216294Ssyrinxstruct vacm_context * 3205216294Ssyrinxvacm_first_context(void) 3206216294Ssyrinx{ 3207216294Ssyrinx return (SLIST_FIRST(&vacm_contextlist)); 3208216294Ssyrinx} 3209216294Ssyrinx 3210216294Ssyrinxstruct vacm_context * 3211216294Ssyrinxvacm_next_context(struct vacm_context *vacmctx) 3212216294Ssyrinx{ 3213216294Ssyrinx if (vacmctx == NULL) 3214216294Ssyrinx return (NULL); 3215216294Ssyrinx 3216216294Ssyrinx return (SLIST_NEXT(vacmctx, vcl)); 3217216294Ssyrinx} 3218216294Ssyrinx 3219216294Ssyrinxstruct vacm_context * 3220216294Ssyrinxvacm_add_context(char *ctxname, int regid) 3221216294Ssyrinx{ 3222216294Ssyrinx int cmp; 3223216294Ssyrinx struct vacm_context *ctx, *temp, *prev; 3224216294Ssyrinx 3225216294Ssyrinx SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3226216294Ssyrinx if (strcmp(ctxname, ctx->ctxname) == 0) { 3227216294Ssyrinx syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3228216294Ssyrinx return (NULL); 3229216294Ssyrinx } 3230216294Ssyrinx 3231216294Ssyrinx if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3232216294Ssyrinx return (NULL); 3233216294Ssyrinx 3234216294Ssyrinx memset(ctx, 0, sizeof(*ctx)); 3235216294Ssyrinx strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3236216294Ssyrinx ctx->regid = regid; 3237216294Ssyrinx 3238216294Ssyrinx if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3239216294Ssyrinx strlen(ctx->ctxname) < strlen(prev->ctxname) || 3240216294Ssyrinx strcmp(ctx->ctxname, prev->ctxname) < 0) { 3241216294Ssyrinx SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3242216294Ssyrinx return (ctx); 3243216294Ssyrinx } 3244216294Ssyrinx 3245216294Ssyrinx SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3246216294Ssyrinx if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3247216294Ssyrinx strcmp(ctx->ctxname, temp->ctxname) < 0) { 3248216294Ssyrinx cmp = -1; 3249216294Ssyrinx break; 3250216294Ssyrinx } 3251216294Ssyrinx prev = temp; 3252216294Ssyrinx } 3253216294Ssyrinx 3254216294Ssyrinx if (temp == NULL || cmp < 0) 3255216294Ssyrinx SLIST_INSERT_AFTER(prev, ctx, vcl); 3256216294Ssyrinx else if (cmp > 0) 3257216294Ssyrinx SLIST_INSERT_AFTER(temp, ctx, vcl); 3258216294Ssyrinx else { 3259216294Ssyrinx syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3260216294Ssyrinx free(ctx); 3261216294Ssyrinx return (NULL); 3262216294Ssyrinx } 3263216294Ssyrinx 3264216294Ssyrinx return (ctx); 3265216294Ssyrinx} 3266216294Ssyrinx 3267216294Ssyrinxvoid 3268216294Ssyrinxvacm_flush_contexts(int regid) 3269216294Ssyrinx{ 3270216294Ssyrinx struct vacm_context *ctx, *temp; 3271216294Ssyrinx 3272216294Ssyrinx SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3273216294Ssyrinx if (ctx->regid == regid) { 3274216294Ssyrinx SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3275216294Ssyrinx free(ctx); 3276216294Ssyrinx } 3277216294Ssyrinx} 3278