main.c revision 216294
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 * 8133211Sharti * Redistribution and use in source and binary forms, with or without 9133211Sharti * modification, are permitted provided that the following conditions 10133211Sharti * are met: 11133211Sharti * 1. Redistributions of source code must retain the above copyright 12133211Sharti * notice, this list of conditions and the following disclaimer. 13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 14122394Sharti * notice, this list of conditions and the following disclaimer in the 15122394Sharti * documentation and/or other materials provided with the distribution. 16133211Sharti * 17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27133211Sharti * SUCH DAMAGE. 28122394Sharti * 29156066Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ 30122394Sharti * 31122394Sharti * SNMPd main stuff. 32122394Sharti */ 33216294Ssyrinx 34216294Ssyrinx#include <sys/queue.h> 35122394Sharti#include <sys/param.h> 36122394Sharti#include <sys/un.h> 37124861Sharti#include <sys/ucred.h> 38150920Sharti#include <sys/uio.h> 39122394Sharti#include <stdio.h> 40122394Sharti#include <stdlib.h> 41122394Sharti#include <stddef.h> 42122394Sharti#include <string.h> 43122394Sharti#include <stdarg.h> 44122394Sharti#include <ctype.h> 45122394Sharti#include <errno.h> 46122394Sharti#include <syslog.h> 47122394Sharti#include <unistd.h> 48122394Sharti#include <signal.h> 49122394Sharti#include <dlfcn.h> 50122394Sharti#include <inttypes.h> 51122394Sharti 52145557Sharti#ifdef USE_TCPWRAPPERS 53145557Sharti#include <arpa/inet.h> 54145557Sharti#include <tcpd.h> 55145557Sharti#endif 56145557Sharti 57156066Sharti#include "support.h" 58122394Sharti#include "snmpmod.h" 59122394Sharti#include "snmpd.h" 60122394Sharti#include "tree.h" 61122394Sharti#include "oid.h" 62122394Sharti 63122394Sharti#define PATH_PID "/var/run/%s.pid" 64122394Sharti#define PATH_CONFIG "/etc/%s.config" 65216294Ssyrinx#define PATH_ENGINE "/var/%s.engine" 66122394Sharti 67146525Shartiuint64_t this_tick; /* start of processing of current packet (absolute) */ 68146525Shartiuint64_t start_tick; /* start of processing */ 69122394Sharti 70122394Shartistruct systemg systemg = { 71122394Sharti NULL, 72122394Sharti { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, 73122394Sharti NULL, NULL, NULL, 74122394Sharti 64 + 8 + 4, 75122394Sharti 0 76122394Sharti}; 77122394Shartistruct debug debug = { 78122394Sharti 0, /* dump_pdus */ 79122394Sharti LOG_DEBUG, /* log_pri */ 80122394Sharti 0, /* evdebug */ 81122394Sharti}; 82122394Sharti 83122394Shartistruct snmpd snmpd = { 84122394Sharti 2048, /* txbuf */ 85122394Sharti 2048, /* rxbuf */ 86122394Sharti 0, /* comm_dis */ 87122394Sharti 0, /* auth_traps */ 88122394Sharti {0, 0, 0, 0}, /* trap1addr */ 89124861Sharti VERS_ENABLE_ALL,/* version_enable */ 90122394Sharti}; 91122394Shartistruct snmpd_stats snmpd_stats; 92122394Sharti 93216294Ssyrinxstruct snmpd_usmstat snmpd_usmstats; 94216294Ssyrinx 95216294Ssyrinx/* snmpEngine */ 96216294Ssyrinxstruct snmp_engine snmpd_engine; 97216294Ssyrinx 98122394Sharti/* snmpSerialNo */ 99122394Shartiint32_t snmp_serial_no; 100122394Sharti 101122394Sharti/* search path for config files */ 102122394Sharticonst char *syspath = PATH_SYSCONFIG; 103122394Sharti 104122394Sharti/* list of all loaded modules */ 105122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); 106122394Sharti 107122394Sharti/* list of loaded modules during start-up in the order they were loaded */ 108122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); 109122394Sharti 110122394Sharti/* list of all known communities */ 111122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); 112122394Sharti 113216294Ssyrinx/* list of all known USM users */ 114216294Ssyrinxstruct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); 115216294Ssyrinx 116216294Ssyrinx/* A list of all VACM users configured, including v1, v2c and v3 */ 117216294Ssyrinxstruct vacm_userlist vacm_userlist = SLIST_HEAD_INITIALIZER(vacm_userlist); 118216294Ssyrinx 119216294Ssyrinx/* A list of all VACM groups */ 120216294Ssyrinxstruct vacm_grouplist vacm_grouplist = SLIST_HEAD_INITIALIZER(vacm_grouplist); 121216294Ssyrinx 122216294Ssyrinxstatic struct vacm_group vacm_default_group = { 123216294Ssyrinx .groupname = "", 124216294Ssyrinx}; 125216294Ssyrinx 126216294Ssyrinx/* The list of configured access entries */ 127216294Ssyrinxstruct vacm_accesslist vacm_accesslist = TAILQ_HEAD_INITIALIZER(vacm_accesslist); 128216294Ssyrinx 129216294Ssyrinx/* The list of configured views */ 130216294Ssyrinxstruct vacm_viewlist vacm_viewlist = SLIST_HEAD_INITIALIZER(vacm_viewlist); 131216294Ssyrinx 132216294Ssyrinx/* The list of configured contexts */ 133216294Ssyrinxstruct vacm_contextlist vacm_contextlist = 134216294Ssyrinx SLIST_HEAD_INITIALIZER(vacm_contextlist); 135216294Ssyrinx 136122394Sharti/* list of all installed object resources */ 137122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); 138122394Sharti 139122394Sharti/* community value generator */ 140122394Shartistatic u_int next_community_index = 1; 141122394Sharti 142122394Sharti/* list of all known ranges */ 143122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); 144122394Sharti 145122394Sharti/* identifier generator */ 146122394Shartiu_int next_idrange = 1; 147122394Sharti 148122394Sharti/* list of all current timers */ 149122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); 150122394Sharti 151122394Sharti/* list of file descriptors */ 152122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); 153122394Sharti 154122394Sharti/* program arguments */ 155122394Shartistatic char **progargs; 156122394Shartistatic int nprogargs; 157122394Sharti 158122394Sharti/* current community */ 159122394Shartiu_int community; 160122394Shartistatic struct community *comm; 161122394Sharti 162216294Ssyrinx/* current USM user */ 163216294Ssyrinxstruct usm_user *usm_user; 164216294Ssyrinx 165122394Sharti/* file names */ 166122394Shartistatic char config_file[MAXPATHLEN + 1]; 167122394Shartistatic char pid_file[MAXPATHLEN + 1]; 168216294Ssyrinxchar engine_file[MAXPATHLEN + 1]; 169122394Sharti 170124861Sharti#ifndef USE_LIBBEGEMOT 171122394Sharti/* event context */ 172122394Shartistatic evContext evctx; 173124861Sharti#endif 174122394Sharti 175122394Sharti/* signal mask */ 176122394Shartistatic sigset_t blocked_sigs; 177122394Sharti 178122394Sharti/* signal handling */ 179122394Shartistatic int work; 180122394Sharti#define WORK_DOINFO 0x0001 181122394Sharti#define WORK_RECONFIG 0x0002 182122394Sharti 183122394Sharti/* oids */ 184122394Shartistatic const struct asn_oid 185122394Sharti oid_snmpMIB = OIDX_snmpMIB, 186122394Sharti oid_begemotSnmpd = OIDX_begemotSnmpd, 187122394Sharti oid_coldStart = OIDX_coldStart, 188122394Sharti oid_authenticationFailure = OIDX_authenticationFailure; 189122394Sharti 190122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; 191122394Sharti 192216294Ssyrinxconst struct asn_oid oid_usmUnknownEngineIDs = 193216294Ssyrinx { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; 194216294Ssyrinx 195216294Ssyrinxconst struct asn_oid oid_usmNotInTimeWindows = 196216294Ssyrinx { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; 197216294Ssyrinx 198122394Sharti/* request id generator for traps */ 199122394Shartiu_int trap_reqid; 200122394Sharti 201122394Sharti/* help text */ 202122394Shartistatic const char usgtxt[] = "\ 203122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ 204122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\ 205216294SsyrinxCopyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ 206216294Ssyrinxusage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ 207216294Ssyrinx [-l prefix] [-m variable=value] [-p file]\n\ 208122394Shartioptions:\n\ 209122394Sharti -d don't daemonize\n\ 210122394Sharti -h print this info\n\ 211122394Sharti -c file specify configuration file\n\ 212122394Sharti -D options debugging options\n\ 213216294Ssyrinx -e file specify engine id file\n\ 214122394Sharti -I path system include path\n\ 215122394Sharti -l prefix default basename for pid and config file\n\ 216122394Sharti -m var=val define variable\n\ 217122394Sharti -p file specify pid file\n\ 218122394Sharti"; 219122394Sharti 220145557Sharti/* hosts_access(3) request */ 221145557Sharti#ifdef USE_TCPWRAPPERS 222145557Shartistatic struct request_info req; 223145557Sharti#endif 224145557Sharti 225124861Sharti/* transports */ 226124861Shartiextern const struct transport_def udp_trans; 227124861Shartiextern const struct transport_def lsock_trans; 228124861Sharti 229124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); 230124861Sharti 231122394Sharti/* forward declarations */ 232122394Shartistatic void snmp_printf_func(const char *fmt, ...); 233122394Shartistatic void snmp_error_func(const char *err, ...); 234122394Shartistatic void snmp_debug_func(const char *err, ...); 235122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...); 236122394Sharti 237122394Sharti/* 238122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx. 239122394Sharti */ 240122394Shartivoid * 241122394Shartibuf_alloc(int tx) 242122394Sharti{ 243122394Sharti void *buf; 244122394Sharti 245124861Sharti if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { 246122394Sharti syslog(LOG_CRIT, "cannot allocate buffer"); 247122394Sharti if (tx) 248122394Sharti snmpd_stats.noTxbuf++; 249122394Sharti else 250122394Sharti snmpd_stats.noRxbuf++; 251122394Sharti return (NULL); 252122394Sharti } 253122394Sharti return (buf); 254122394Sharti} 255122394Sharti 256122394Sharti/* 257124861Sharti * Return the buffer size. 258122394Sharti */ 259122394Shartisize_t 260122394Shartibuf_size(int tx) 261122394Sharti{ 262124861Sharti return (tx ? snmpd.txbuf : snmpd.rxbuf); 263122394Sharti} 264122394Sharti 265122394Sharti/* 266122394Sharti * Prepare a PDU for output 267122394Sharti */ 268122394Shartivoid 269124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, 270122394Sharti const char *dest) 271122394Sharti{ 272122394Sharti struct asn_buf resp_b; 273122394Sharti 274122394Sharti resp_b.asn_ptr = sndbuf; 275122394Sharti resp_b.asn_len = snmpd.txbuf; 276122394Sharti 277122394Sharti if (snmp_pdu_encode(pdu, &resp_b) != 0) { 278122394Sharti syslog(LOG_ERR, "cannot encode message"); 279122394Sharti abort(); 280122394Sharti } 281122394Sharti if (debug.dump_pdus) { 282122394Sharti snmp_printf("%s <- ", dest); 283122394Sharti snmp_pdu_dump(pdu); 284122394Sharti } 285122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 286122394Sharti} 287122394Sharti 288122394Sharti/* 289216294Ssyrinx * Check USM PDU header credentials against local SNMP Engine & users. 290122394Sharti */ 291216294Ssyrinxstatic enum snmp_code 292216294Ssyrinxsnmp_pdu_auth_user(struct snmp_pdu *pdu) 293216294Ssyrinx{ 294216294Ssyrinx uint64_t etime; 295216294Ssyrinx usm_user = NULL; 296216294Ssyrinx 297216294Ssyrinx /* un-authenticated snmpEngineId discovery */ 298216294Ssyrinx if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { 299216294Ssyrinx pdu->engine.engine_len = snmpd_engine.engine_len; 300216294Ssyrinx memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 301216294Ssyrinx snmpd_engine.engine_len); 302216294Ssyrinx pdu->engine.engine_boots = snmpd_engine.engine_boots; 303216294Ssyrinx pdu->engine.engine_time = snmpd_engine.engine_time; 304216294Ssyrinx pdu->flags |= SNMP_MSG_AUTODISCOVER; 305216294Ssyrinx return (SNMP_CODE_OK); 306216294Ssyrinx } 307216294Ssyrinx 308216294Ssyrinx if ((usm_user = usm_find_user(pdu->engine.engine_id, 309216294Ssyrinx pdu->engine.engine_len, pdu->user.sec_name)) == NULL || 310216294Ssyrinx usm_user->status != 1 /* active */) 311216294Ssyrinx return (SNMP_CODE_BADUSER); 312216294Ssyrinx 313216294Ssyrinx if (usm_user->user_engine_len != snmpd_engine.engine_len || 314216294Ssyrinx memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, 315216294Ssyrinx snmpd_engine.engine_len) != 0) 316216294Ssyrinx return (SNMP_CODE_BADENGINE); 317216294Ssyrinx 318216294Ssyrinx pdu->user.priv_proto = usm_user->suser.priv_proto; 319216294Ssyrinx memcpy(pdu->user.priv_key, usm_user->suser.priv_key, 320216294Ssyrinx sizeof(pdu->user.priv_key)); 321216294Ssyrinx 322216294Ssyrinx /* authenticated snmpEngineId discovery */ 323216294Ssyrinx if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 324216294Ssyrinx etime = (get_ticks() - start_tick) / 100ULL; 325216294Ssyrinx if (etime < INT32_MAX) 326216294Ssyrinx snmpd_engine.engine_time = etime; 327216294Ssyrinx else { 328216294Ssyrinx start_tick = get_ticks(); 329216294Ssyrinx set_snmpd_engine(); 330216294Ssyrinx snmpd_engine.engine_time = start_tick; 331216294Ssyrinx } 332216294Ssyrinx 333216294Ssyrinx pdu->user.auth_proto = usm_user->suser.auth_proto; 334216294Ssyrinx memcpy(pdu->user.auth_key, usm_user->suser.auth_key, 335216294Ssyrinx sizeof(pdu->user.auth_key)); 336216294Ssyrinx 337216294Ssyrinx if (pdu->engine.engine_boots == 0 && 338216294Ssyrinx pdu->engine.engine_time == 0) { 339216294Ssyrinx pdu->flags |= SNMP_MSG_AUTODISCOVER; 340216294Ssyrinx return (SNMP_CODE_OK); 341216294Ssyrinx } 342216294Ssyrinx 343216294Ssyrinx if (pdu->engine.engine_boots != snmpd_engine.engine_boots || 344216294Ssyrinx abs(pdu->engine.engine_time - snmpd_engine.engine_time) > 345216294Ssyrinx SNMP_TIME_WINDOW) 346216294Ssyrinx return (SNMP_CODE_NOTINTIME); 347216294Ssyrinx } 348216294Ssyrinx 349216294Ssyrinx if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 350216294Ssyrinx (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || 351216294Ssyrinx ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && 352216294Ssyrinx usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || 353216294Ssyrinx ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && 354216294Ssyrinx usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) 355216294Ssyrinx return (SNMP_CODE_BADSECLEVEL); 356216294Ssyrinx 357216294Ssyrinx return (SNMP_CODE_OK); 358216294Ssyrinx} 359216294Ssyrinx 360216294Ssyrinx/* 361216294Ssyrinx * Check whether access to each of var bindings in the PDU is allowed based 362216294Ssyrinx * on the user credentials against the configured User groups & VACM views. 363216294Ssyrinx */ 364216294Ssyrinxstatic enum snmp_code 365216294Ssyrinxsnmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) 366216294Ssyrinx{ 367216294Ssyrinx const char *uname; 368216294Ssyrinx int32_t suboid, smodel; 369216294Ssyrinx uint32_t i; 370216294Ssyrinx struct vacm_user *vuser; 371216294Ssyrinx struct vacm_access *acl; 372216294Ssyrinx struct vacm_context *vacmctx; 373216294Ssyrinx struct vacm_view *view; 374216294Ssyrinx 375216294Ssyrinx /* 376216294Ssyrinx * At least a default context exists if the snmpd_vacm(3) module is 377216294Ssyrinx * running. 378216294Ssyrinx */ 379216294Ssyrinx if (SLIST_EMPTY(&vacm_contextlist) || 380216294Ssyrinx (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) 381216294Ssyrinx return (SNMP_CODE_OK); 382216294Ssyrinx 383216294Ssyrinx switch (pdu->version) { 384216294Ssyrinx case SNMP_V1: 385216294Ssyrinx if ((uname = comm_string(community)) == NULL) 386216294Ssyrinx return (SNMP_CODE_FAILED); 387216294Ssyrinx smodel = SNMP_SECMODEL_SNMPv1; 388216294Ssyrinx break; 389216294Ssyrinx 390216294Ssyrinx case SNMP_V2c: 391216294Ssyrinx if ((uname = comm_string(community)) == NULL) 392216294Ssyrinx return (SNMP_CODE_FAILED); 393216294Ssyrinx smodel = SNMP_SECMODEL_SNMPv2c; 394216294Ssyrinx break; 395216294Ssyrinx 396216294Ssyrinx case SNMP_V3: 397216294Ssyrinx uname = pdu->user.sec_name; 398216294Ssyrinx if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) 399216294Ssyrinx return (SNMP_CODE_FAILED); 400216294Ssyrinx /* Compare the PDU context engine id against the agent's */ 401216294Ssyrinx if (pdu->context_engine_len != snmpd_engine.engine_len || 402216294Ssyrinx memcmp(pdu->context_engine, snmpd_engine.engine_id, 403216294Ssyrinx snmpd_engine.engine_len) != 0) 404216294Ssyrinx return (SNMP_CODE_FAILED); 405216294Ssyrinx break; 406216294Ssyrinx 407216294Ssyrinx default: 408216294Ssyrinx abort(); 409216294Ssyrinx } 410216294Ssyrinx 411216294Ssyrinx SLIST_FOREACH(vuser, &vacm_userlist, vvu) 412216294Ssyrinx if (strcmp(uname, vuser->secname) == 0 && 413216294Ssyrinx vuser->sec_model == smodel) 414216294Ssyrinx break; 415216294Ssyrinx 416216294Ssyrinx if (vuser == NULL || vuser->group == NULL) 417216294Ssyrinx return (SNMP_CODE_FAILED); 418216294Ssyrinx 419216294Ssyrinx /* XXX: shteryana - recheck */ 420216294Ssyrinx TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { 421216294Ssyrinx if (acl->group != vuser->group) 422216294Ssyrinx continue; 423216294Ssyrinx SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) 424216294Ssyrinx if (memcmp(vacmctx->ctxname, acl->ctx_prefix, 425216294Ssyrinx acl->ctx_match) == 0) 426216294Ssyrinx goto match; 427216294Ssyrinx } 428216294Ssyrinx 429216294Ssyrinx return (SNMP_CODE_FAILED); 430216294Ssyrinx 431216294Ssyrinxmatch: 432216294Ssyrinx 433216294Ssyrinx switch (pdu->type) { 434216294Ssyrinx case SNMP_PDU_GET: 435216294Ssyrinx case SNMP_PDU_GETNEXT: 436216294Ssyrinx case SNMP_PDU_GETBULK: 437216294Ssyrinx if ((view = acl->read_view) == NULL) 438216294Ssyrinx return (SNMP_CODE_FAILED); 439216294Ssyrinx break; 440216294Ssyrinx 441216294Ssyrinx case SNMP_PDU_SET: 442216294Ssyrinx if ((view = acl->write_view) == NULL) 443216294Ssyrinx return (SNMP_CODE_FAILED); 444216294Ssyrinx break; 445216294Ssyrinx 446216294Ssyrinx case SNMP_PDU_TRAP: 447216294Ssyrinx case SNMP_PDU_INFORM: 448216294Ssyrinx case SNMP_PDU_TRAP2: 449216294Ssyrinx case SNMP_PDU_REPORT: 450216294Ssyrinx if ((view = acl->notify_view) == NULL) 451216294Ssyrinx return (SNMP_CODE_FAILED); 452216294Ssyrinx break; 453216294Ssyrinx case SNMP_PDU_RESPONSE: 454216294Ssyrinx /* NOTREACHED */ 455216294Ssyrinx return (SNMP_CODE_FAILED); 456216294Ssyrinx default: 457216294Ssyrinx abort(); 458216294Ssyrinx } 459216294Ssyrinx 460216294Ssyrinx for (i = 0; i < pdu->nbindings; i++) { 461216294Ssyrinx /* XXX - view->mask*/ 462216294Ssyrinx suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); 463216294Ssyrinx if ((!suboid && !view->exclude) || (suboid && view->exclude)) { 464216294Ssyrinx *ip = i + 1; 465216294Ssyrinx return (SNMP_CODE_FAILED); 466216294Ssyrinx } 467216294Ssyrinx } 468216294Ssyrinx 469216294Ssyrinx return (SNMP_CODE_OK); 470216294Ssyrinx} 471216294Ssyrinx 472216294Ssyrinx/* 473216294Ssyrinx * SNMP input. Start: decode the PDU, find the user or community. 474216294Ssyrinx */ 475122394Shartienum snmpd_input_err 476122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source, 477124861Sharti struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) 478122394Sharti{ 479122394Sharti struct asn_buf b; 480122394Sharti enum snmp_code code; 481122394Sharti enum snmpd_input_err ret; 482124861Sharti int sret; 483122394Sharti 484216294Ssyrinx /* update uptime */ 485216294Ssyrinx this_tick = get_ticks(); 486216294Ssyrinx 487122394Sharti b.asn_cptr = buf; 488122394Sharti b.asn_len = len; 489124861Sharti 490124861Sharti /* look whether we have enough bytes for the entire PDU. */ 491124861Sharti switch (sret = snmp_pdu_snoop(&b)) { 492124861Sharti 493124861Sharti case 0: 494124861Sharti return (SNMPD_INPUT_TRUNC); 495124861Sharti 496124861Sharti case -1: 497124861Sharti snmpd_stats.inASNParseErrs++; 498124861Sharti return (SNMPD_INPUT_FAILED); 499124861Sharti } 500124861Sharti b.asn_len = *pdulen = (size_t)sret; 501124861Sharti 502216294Ssyrinx memset(pdu, 0, sizeof(*pdu)); 503216294Ssyrinx if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) 504216294Ssyrinx goto decoded; 505122394Sharti 506216294Ssyrinx if (pdu->version == SNMP_V3) { 507216294Ssyrinx if (pdu->security_model != SNMP_SECMODEL_USM) { 508216294Ssyrinx code = SNMP_CODE_FAILED; 509216294Ssyrinx goto decoded; 510216294Ssyrinx } 511216294Ssyrinx if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) 512216294Ssyrinx goto decoded; 513216294Ssyrinx if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) 514216294Ssyrinx goto decoded; 515216294Ssyrinx } 516216294Ssyrinx code = snmp_pdu_decode_scoped(&b, pdu, ip); 517216294Ssyrinx 518216294Ssyrinx ret = SNMPD_INPUT_OK; 519216294Ssyrinx 520216294Ssyrinxdecoded: 521124861Sharti snmpd_stats.inPkts++; 522124861Sharti 523122394Sharti switch (code) { 524122394Sharti 525122394Sharti case SNMP_CODE_FAILED: 526122394Sharti snmpd_stats.inASNParseErrs++; 527122394Sharti return (SNMPD_INPUT_FAILED); 528122394Sharti 529122394Sharti case SNMP_CODE_BADVERS: 530124861Sharti bad_vers: 531122394Sharti snmpd_stats.inBadVersions++; 532122394Sharti return (SNMPD_INPUT_FAILED); 533122394Sharti 534122394Sharti case SNMP_CODE_BADLEN: 535122394Sharti if (pdu->type == SNMP_OP_SET) 536122394Sharti ret = SNMPD_INPUT_VALBADLEN; 537122394Sharti break; 538122394Sharti 539122394Sharti case SNMP_CODE_OORANGE: 540122394Sharti if (pdu->type == SNMP_OP_SET) 541122394Sharti ret = SNMPD_INPUT_VALRANGE; 542122394Sharti break; 543122394Sharti 544122394Sharti case SNMP_CODE_BADENC: 545122394Sharti if (pdu->type == SNMP_OP_SET) 546122394Sharti ret = SNMPD_INPUT_VALBADENC; 547122394Sharti break; 548122394Sharti 549216294Ssyrinx case SNMP_CODE_BADSECLEVEL: 550216294Ssyrinx snmpd_usmstats.unsupported_seclevels++; 551216294Ssyrinx return (SNMPD_INPUT_FAILED); 552216294Ssyrinx 553216294Ssyrinx case SNMP_CODE_NOTINTIME: 554216294Ssyrinx snmpd_usmstats.not_in_time_windows++; 555216294Ssyrinx return (SNMPD_INPUT_FAILED); 556216294Ssyrinx 557216294Ssyrinx case SNMP_CODE_BADUSER: 558216294Ssyrinx snmpd_usmstats.unknown_users++; 559216294Ssyrinx return (SNMPD_INPUT_FAILED); 560216294Ssyrinx 561216294Ssyrinx case SNMP_CODE_BADENGINE: 562216294Ssyrinx snmpd_usmstats.unknown_engine_ids++; 563216294Ssyrinx return (SNMPD_INPUT_FAILED); 564216294Ssyrinx 565216294Ssyrinx case SNMP_CODE_BADDIGEST: 566216294Ssyrinx snmpd_usmstats.wrong_digests++; 567216294Ssyrinx return (SNMPD_INPUT_FAILED); 568216294Ssyrinx 569216294Ssyrinx case SNMP_CODE_EDECRYPT: 570216294Ssyrinx snmpd_usmstats.decrypt_errors++; 571216294Ssyrinx return (SNMPD_INPUT_FAILED); 572216294Ssyrinx 573122394Sharti case SNMP_CODE_OK: 574124861Sharti switch (pdu->version) { 575124861Sharti 576124861Sharti case SNMP_V1: 577124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V1)) 578124861Sharti goto bad_vers; 579124861Sharti break; 580124861Sharti 581124861Sharti case SNMP_V2c: 582124861Sharti if (!(snmpd.version_enable & VERS_ENABLE_V2C)) 583124861Sharti goto bad_vers; 584124861Sharti break; 585124861Sharti 586216294Ssyrinx case SNMP_V3: 587216294Ssyrinx if (!(snmpd.version_enable & VERS_ENABLE_V3)) 588216294Ssyrinx goto bad_vers; 589216294Ssyrinx break; 590216294Ssyrinx 591124861Sharti case SNMP_Verr: 592124861Sharti goto bad_vers; 593124861Sharti } 594122394Sharti break; 595122394Sharti } 596122394Sharti 597122394Sharti if (debug.dump_pdus) { 598122394Sharti snmp_printf("%s -> ", source); 599122394Sharti snmp_pdu_dump(pdu); 600122394Sharti } 601122394Sharti 602122394Sharti /* 603216294Ssyrinx * Look, whether we know the community or user 604122394Sharti */ 605122394Sharti 606216294Ssyrinx if (pdu->version != SNMP_V3) { 607216294Ssyrinx TAILQ_FOREACH(comm, &community_list, link) 608216294Ssyrinx if (comm->string != NULL && 609216294Ssyrinx strcmp(comm->string, pdu->community) == 0) 610216294Ssyrinx break; 611122394Sharti 612216294Ssyrinx if (comm == NULL) { 613216294Ssyrinx snmpd_stats.inBadCommunityNames++; 614216294Ssyrinx snmp_pdu_free(pdu); 615216294Ssyrinx if (snmpd.auth_traps) 616216294Ssyrinx snmp_send_trap(&oid_authenticationFailure, 617216294Ssyrinx (struct snmp_value *)NULL); 618216294Ssyrinx ret = SNMPD_INPUT_BAD_COMM; 619216294Ssyrinx } else 620216294Ssyrinx community = comm->value; 621216294Ssyrinx } else if (pdu->nbindings == 0) { 622216294Ssyrinx /* RFC 3414 - snmpEngineID Discovery */ 623216294Ssyrinx if (strlen(pdu->user.sec_name) == 0) { 624216294Ssyrinx asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 625216294Ssyrinx &oid_usmUnknownEngineIDs); 626216294Ssyrinx pdu->context_engine_len = snmpd_engine.engine_len; 627216294Ssyrinx memcpy(pdu->context_engine, snmpd_engine.engine_id, 628216294Ssyrinx snmpd_engine.engine_len); 629216294Ssyrinx } else if (pdu->engine.engine_boots == 0 && 630216294Ssyrinx pdu->engine.engine_time == 0) { 631216294Ssyrinx asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), 632216294Ssyrinx &oid_usmNotInTimeWindows); 633216294Ssyrinx pdu->engine.engine_boots = snmpd_engine.engine_boots; 634216294Ssyrinx pdu->engine.engine_time = snmpd_engine.engine_time; 635216294Ssyrinx } 636216294Ssyrinx } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && 637216294Ssyrinx (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { 638216294Ssyrinx snmpd_usmstats.not_in_time_windows++; 639216294Ssyrinx ret = SNMP_CODE_FAILED; 640216294Ssyrinx } 641122394Sharti 642216294Ssyrinx if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) 643216294Ssyrinx ret = SNMP_CODE_FAILED; 644216294Ssyrinx 645122394Sharti return (ret); 646122394Sharti} 647122394Sharti 648122394Sharti/* 649122394Sharti * Will return only _OK or _FAILED 650122394Sharti */ 651122394Shartienum snmpd_input_err 652122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, 653122394Sharti u_char *sndbuf, size_t *sndlen, const char *source, 654122394Sharti enum snmpd_input_err ierr, int32_t ivar, void *data) 655122394Sharti{ 656122394Sharti struct snmp_pdu resp; 657122394Sharti struct asn_buf resp_b, pdu_b; 658122394Sharti enum snmp_ret ret; 659122394Sharti 660122394Sharti resp_b.asn_ptr = sndbuf; 661122394Sharti resp_b.asn_len = snmpd.txbuf; 662122394Sharti 663122394Sharti pdu_b.asn_cptr = rcvbuf; 664122394Sharti pdu_b.asn_len = rcvlen; 665122394Sharti 666122394Sharti if (ierr != SNMPD_INPUT_OK) { 667122394Sharti /* error decoding the input of a SET */ 668122394Sharti if (pdu->version == SNMP_V1) 669122394Sharti pdu->error_status = SNMP_ERR_BADVALUE; 670122394Sharti else if (ierr == SNMPD_INPUT_VALBADLEN) 671122394Sharti pdu->error_status = SNMP_ERR_WRONG_LENGTH; 672122394Sharti else if (ierr == SNMPD_INPUT_VALRANGE) 673122394Sharti pdu->error_status = SNMP_ERR_WRONG_VALUE; 674122394Sharti else 675122394Sharti pdu->error_status = SNMP_ERR_WRONG_ENCODING; 676122394Sharti 677122394Sharti pdu->error_index = ivar; 678122394Sharti 679122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 680122394Sharti syslog(LOG_WARNING, "could not encode error response"); 681122394Sharti snmpd_stats.silentDrops++; 682122394Sharti return (SNMPD_INPUT_FAILED); 683122394Sharti } 684122394Sharti 685122394Sharti if (debug.dump_pdus) { 686122394Sharti snmp_printf("%s <- ", source); 687122394Sharti snmp_pdu_dump(pdu); 688122394Sharti } 689122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 690122394Sharti return (SNMPD_INPUT_OK); 691122394Sharti } 692122394Sharti 693122394Sharti switch (pdu->type) { 694122394Sharti 695122394Sharti case SNMP_PDU_GET: 696122394Sharti ret = snmp_get(pdu, &resp_b, &resp, data); 697122394Sharti break; 698122394Sharti 699122394Sharti case SNMP_PDU_GETNEXT: 700122394Sharti ret = snmp_getnext(pdu, &resp_b, &resp, data); 701122394Sharti break; 702122394Sharti 703122394Sharti case SNMP_PDU_SET: 704122394Sharti ret = snmp_set(pdu, &resp_b, &resp, data); 705122394Sharti break; 706122394Sharti 707122394Sharti case SNMP_PDU_GETBULK: 708122394Sharti ret = snmp_getbulk(pdu, &resp_b, &resp, data); 709122394Sharti break; 710122394Sharti 711122394Sharti default: 712122394Sharti ret = SNMP_RET_IGN; 713122394Sharti break; 714122394Sharti } 715122394Sharti 716122394Sharti switch (ret) { 717122394Sharti 718122394Sharti case SNMP_RET_OK: 719122394Sharti /* normal return - send a response */ 720122394Sharti if (debug.dump_pdus) { 721122394Sharti snmp_printf("%s <- ", source); 722122394Sharti snmp_pdu_dump(&resp); 723122394Sharti } 724122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 725122394Sharti snmp_pdu_free(&resp); 726122394Sharti return (SNMPD_INPUT_OK); 727122394Sharti 728122394Sharti case SNMP_RET_IGN: 729122394Sharti /* error - send nothing */ 730122394Sharti snmpd_stats.silentDrops++; 731122394Sharti return (SNMPD_INPUT_FAILED); 732122394Sharti 733122394Sharti case SNMP_RET_ERR: 734122394Sharti /* error - send error response. The snmp routine has 735122394Sharti * changed the error fields in the original message. */ 736122394Sharti resp_b.asn_ptr = sndbuf; 737122394Sharti resp_b.asn_len = snmpd.txbuf; 738122394Sharti if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { 739122394Sharti syslog(LOG_WARNING, "could not encode error response"); 740122394Sharti snmpd_stats.silentDrops++; 741122394Sharti return (SNMPD_INPUT_FAILED); 742122394Sharti } else { 743122394Sharti if (debug.dump_pdus) { 744122394Sharti snmp_printf("%s <- ", source); 745122394Sharti snmp_pdu_dump(pdu); 746122394Sharti } 747122394Sharti *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); 748122394Sharti return (SNMPD_INPUT_OK); 749122394Sharti } 750122394Sharti } 751122394Sharti abort(); 752122394Sharti} 753122394Sharti 754124861Sharti/* 755124861Sharti * Insert a port into the right place in the transport's table of ports 756124861Sharti */ 757124861Shartivoid 758124861Shartitrans_insert_port(struct transport *t, struct tport *port) 759124861Sharti{ 760124861Sharti struct tport *p; 761122394Sharti 762124861Sharti TAILQ_FOREACH(p, &t->table, link) { 763124861Sharti if (asn_compare_oid(&p->index, &port->index) > 0) { 764124861Sharti TAILQ_INSERT_BEFORE(p, port, link); 765124861Sharti return; 766124861Sharti } 767124861Sharti } 768124861Sharti port->transport = t; 769124861Sharti TAILQ_INSERT_TAIL(&t->table, port, link); 770124861Sharti} 771122394Sharti 772122394Sharti/* 773124861Sharti * Remove a port from a transport's list 774124861Sharti */ 775124861Shartivoid 776124861Shartitrans_remove_port(struct tport *port) 777124861Sharti{ 778124861Sharti 779124861Sharti TAILQ_REMOVE(&port->transport->table, port, link); 780124861Sharti} 781124861Sharti 782124861Sharti/* 783124861Sharti * Find a port on a transport's list 784124861Sharti */ 785124861Shartistruct tport * 786124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) 787124861Sharti{ 788124861Sharti 789124861Sharti return (FIND_OBJECT_OID(&t->table, idx, sub)); 790124861Sharti} 791124861Sharti 792124861Sharti/* 793124861Sharti * Find next port on a transport's list 794124861Sharti */ 795124861Shartistruct tport * 796124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) 797124861Sharti{ 798124861Sharti 799124861Sharti return (NEXT_OBJECT_OID(&t->table, idx, sub)); 800124861Sharti} 801124861Sharti 802124861Sharti/* 803124861Sharti * Return first port 804124861Sharti */ 805124861Shartistruct tport * 806124861Shartitrans_first_port(struct transport *t) 807124861Sharti{ 808124861Sharti 809124861Sharti return (TAILQ_FIRST(&t->table)); 810124861Sharti} 811124861Sharti 812124861Sharti/* 813124861Sharti * Iterate through all ports until a function returns a 0. 814124861Sharti */ 815124861Shartistruct tport * 816124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), 817124861Sharti intptr_t arg) 818124861Sharti{ 819124861Sharti struct tport *p; 820124861Sharti 821124861Sharti TAILQ_FOREACH(p, &t->table, link) 822124861Sharti if (func(p, arg) == 0) 823124861Sharti return (p); 824124861Sharti return (NULL); 825124861Sharti} 826124861Sharti 827124861Sharti/* 828124861Sharti * Register a transport 829124861Sharti */ 830124861Shartiint 831124861Shartitrans_register(const struct transport_def *def, struct transport **pp) 832124861Sharti{ 833124861Sharti u_int i; 834124861Sharti char or_descr[256]; 835124861Sharti 836124861Sharti if ((*pp = malloc(sizeof(**pp))) == NULL) 837124861Sharti return (SNMP_ERR_GENERR); 838124861Sharti 839124861Sharti /* construct index */ 840124861Sharti (*pp)->index.len = strlen(def->name) + 1; 841124861Sharti (*pp)->index.subs[0] = strlen(def->name); 842124861Sharti for (i = 0; i < (*pp)->index.subs[0]; i++) 843124861Sharti (*pp)->index.subs[i + 1] = def->name[i]; 844124861Sharti 845124861Sharti (*pp)->vtab = def; 846124861Sharti 847124861Sharti if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { 848124861Sharti free(*pp); 849124861Sharti return (SNMP_ERR_INCONS_VALUE); 850124861Sharti } 851124861Sharti 852124861Sharti /* register module */ 853124861Sharti snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); 854124861Sharti if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { 855124861Sharti free(*pp); 856124861Sharti return (SNMP_ERR_GENERR); 857124861Sharti } 858124861Sharti 859124861Sharti INSERT_OBJECT_OID((*pp), &transport_list); 860124861Sharti 861124861Sharti TAILQ_INIT(&(*pp)->table); 862124861Sharti 863124861Sharti return (SNMP_ERR_NOERROR); 864124861Sharti} 865124861Sharti 866124861Sharti/* 867124861Sharti * Unregister transport 868124861Sharti */ 869124861Shartiint 870124861Shartitrans_unregister(struct transport *t) 871124861Sharti{ 872124861Sharti if (!TAILQ_EMPTY(&t->table)) 873124861Sharti return (SNMP_ERR_INCONS_VALUE); 874124861Sharti 875124861Sharti or_unregister(t->or_index); 876124861Sharti TAILQ_REMOVE(&transport_list, t, link); 877124861Sharti 878124861Sharti return (SNMP_ERR_NOERROR); 879124861Sharti} 880124861Sharti 881124861Sharti/* 882122394Sharti * File descriptor support 883122394Sharti */ 884124861Sharti#ifdef USE_LIBBEGEMOT 885122394Shartistatic void 886124861Shartiinput(int fd, int mask __unused, void *uap) 887124861Sharti#else 888124861Shartistatic void 889122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused) 890124861Sharti#endif 891122394Sharti{ 892122394Sharti struct fdesc *f = uap; 893122394Sharti 894122394Sharti (*f->func)(fd, f->udata); 895122394Sharti} 896122394Sharti 897122394Shartivoid 898122394Shartifd_suspend(void *p) 899122394Sharti{ 900122394Sharti struct fdesc *f = p; 901122394Sharti 902124861Sharti#ifdef USE_LIBBEGEMOT 903124861Sharti if (f->id >= 0) { 904124861Sharti poll_unregister(f->id); 905124861Sharti f->id = -1; 906124861Sharti } 907124861Sharti#else 908122394Sharti if (evTestID(f->id)) { 909122394Sharti (void)evDeselectFD(evctx, f->id); 910122394Sharti evInitID(&f->id); 911122394Sharti } 912124861Sharti#endif 913122394Sharti} 914122394Sharti 915122394Shartiint 916122394Shartifd_resume(void *p) 917122394Sharti{ 918122394Sharti struct fdesc *f = p; 919122394Sharti int err; 920122394Sharti 921124861Sharti#ifdef USE_LIBBEGEMOT 922124861Sharti if (f->id >= 0) 923124861Sharti return (0); 924142810Sharti if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) { 925124861Sharti err = errno; 926124861Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 927124861Sharti errno = err; 928124861Sharti return (-1); 929124861Sharti } 930124861Sharti#else 931122394Sharti if (evTestID(f->id)) 932122394Sharti return (0); 933122394Sharti if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { 934122394Sharti err = errno; 935122394Sharti syslog(LOG_ERR, "select fd %d: %m", f->fd); 936122394Sharti errno = err; 937122394Sharti return (-1); 938122394Sharti } 939124861Sharti#endif 940122394Sharti return (0); 941122394Sharti} 942122394Sharti 943122394Shartivoid * 944122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) 945122394Sharti{ 946122394Sharti struct fdesc *f; 947122394Sharti int err; 948122394Sharti 949122394Sharti if ((f = malloc(sizeof(struct fdesc))) == NULL) { 950122394Sharti err = errno; 951122394Sharti syslog(LOG_ERR, "fd_select: %m"); 952122394Sharti errno = err; 953122394Sharti return (NULL); 954122394Sharti } 955122394Sharti f->fd = fd; 956122394Sharti f->func = func; 957122394Sharti f->udata = udata; 958122394Sharti f->owner = mod; 959124861Sharti#ifdef USE_LIBBEGEMOT 960124861Sharti f->id = -1; 961124861Sharti#else 962122394Sharti evInitID(&f->id); 963124861Sharti#endif 964122394Sharti 965122394Sharti if (fd_resume(f)) { 966122394Sharti err = errno; 967122394Sharti free(f); 968122394Sharti errno = err; 969122394Sharti return (NULL); 970122394Sharti } 971122394Sharti 972122394Sharti LIST_INSERT_HEAD(&fdesc_list, f, link); 973122394Sharti 974122394Sharti return (f); 975122394Sharti} 976122394Sharti 977122394Shartivoid 978122394Shartifd_deselect(void *p) 979122394Sharti{ 980122394Sharti struct fdesc *f = p; 981122394Sharti 982122394Sharti LIST_REMOVE(f, link); 983122394Sharti fd_suspend(f); 984122394Sharti free(f); 985122394Sharti} 986122394Sharti 987122394Shartistatic void 988122394Shartifd_flush(struct lmodule *mod) 989122394Sharti{ 990122394Sharti struct fdesc *t, *t1; 991122394Sharti 992122394Sharti t = LIST_FIRST(&fdesc_list); 993122394Sharti while (t != NULL) { 994122394Sharti t1 = LIST_NEXT(t, link); 995122394Sharti if (t->owner == mod) 996122394Sharti fd_deselect(t); 997122394Sharti t = t1; 998122394Sharti } 999122394Sharti} 1000122394Sharti 1001122394Sharti/* 1002124861Sharti * Consume a message from the input buffer 1003122394Sharti */ 1004122394Shartistatic void 1005124861Shartisnmp_input_consume(struct port_input *pi) 1006122394Sharti{ 1007124861Sharti if (!pi->stream) { 1008124861Sharti /* always consume everything */ 1009124861Sharti pi->length = 0; 1010122394Sharti return; 1011122394Sharti } 1012124861Sharti if (pi->consumed >= pi->length) { 1013124861Sharti /* all bytes consumed */ 1014124861Sharti pi->length = 0; 1015122394Sharti return; 1016122394Sharti } 1017124861Sharti memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); 1018124861Sharti pi->length -= pi->consumed; 1019124861Sharti} 1020124861Sharti 1021124861Shartistruct credmsg { 1022124861Sharti struct cmsghdr hdr; 1023124861Sharti struct cmsgcred cred; 1024124861Sharti}; 1025124861Sharti 1026124861Shartistatic void 1027124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg) 1028124861Sharti{ 1029124861Sharti struct credmsg *cmsg; 1030124861Sharti struct xucred ucred; 1031124861Sharti socklen_t ucredlen; 1032124861Sharti 1033124861Sharti pi->priv = 0; 1034124861Sharti 1035124861Sharti if (msg->msg_controllen == sizeof(*cmsg)) { 1036150920Sharti /* process explicitly sends credentials */ 1037124861Sharti 1038124861Sharti cmsg = (struct credmsg *)msg->msg_control; 1039124861Sharti pi->priv = (cmsg->cred.cmcred_euid == 0); 1040122394Sharti return; 1041122394Sharti } 1042124861Sharti 1043124861Sharti /* ok, obtain the accept time credentials */ 1044124861Sharti ucredlen = sizeof(ucred); 1045124861Sharti 1046124861Sharti if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && 1047124861Sharti ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) 1048124861Sharti pi->priv = (ucred.cr_uid == 0); 1049124861Sharti} 1050124861Sharti 1051124861Sharti/* 1052124861Sharti * Input from a stream socket. 1053124861Sharti */ 1054124861Shartistatic int 1055124861Shartirecv_stream(struct port_input *pi) 1056124861Sharti{ 1057124861Sharti struct msghdr msg; 1058124861Sharti struct iovec iov[1]; 1059124861Sharti ssize_t len; 1060124861Sharti struct credmsg cmsg; 1061124861Sharti 1062124861Sharti if (pi->buf == NULL) { 1063124861Sharti /* no buffer yet - allocate one */ 1064124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 1065124861Sharti /* ups - could not get buffer. Return an error 1066124861Sharti * the caller must close the transport. */ 1067124861Sharti return (-1); 1068124861Sharti } 1069124861Sharti pi->buflen = buf_size(0); 1070124861Sharti pi->consumed = 0; 1071124861Sharti pi->length = 0; 1072124861Sharti } 1073124861Sharti 1074124861Sharti /* try to get a message */ 1075124861Sharti msg.msg_name = pi->peer; 1076124861Sharti msg.msg_namelen = pi->peerlen; 1077124861Sharti msg.msg_iov = iov; 1078124861Sharti msg.msg_iovlen = 1; 1079124861Sharti if (pi->cred) { 1080124861Sharti msg.msg_control = &cmsg; 1081124861Sharti msg.msg_controllen = sizeof(cmsg); 1082124861Sharti 1083124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 1084124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 1085124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 1086124861Sharti } else { 1087124861Sharti msg.msg_control = NULL; 1088124861Sharti msg.msg_controllen = 0; 1089124861Sharti } 1090124861Sharti msg.msg_flags = 0; 1091124861Sharti 1092124861Sharti iov[0].iov_base = pi->buf + pi->length; 1093124861Sharti iov[0].iov_len = pi->buflen - pi->length; 1094124861Sharti 1095124861Sharti len = recvmsg(pi->fd, &msg, 0); 1096124861Sharti 1097124861Sharti if (len == -1 || len == 0) 1098124861Sharti /* receive error */ 1099124861Sharti return (-1); 1100124861Sharti 1101124861Sharti pi->length += len; 1102124861Sharti 1103124861Sharti if (pi->cred) 1104124861Sharti check_priv(pi, &msg); 1105124861Sharti 1106124861Sharti return (0); 1107124861Sharti} 1108124861Sharti 1109124861Sharti/* 1110124861Sharti * Input from a datagram socket. 1111124861Sharti * Each receive should return one datagram. 1112124861Sharti */ 1113124861Shartistatic int 1114124861Shartirecv_dgram(struct port_input *pi) 1115124861Sharti{ 1116124861Sharti u_char embuf[1000]; 1117124861Sharti struct msghdr msg; 1118124861Sharti struct iovec iov[1]; 1119124861Sharti ssize_t len; 1120124861Sharti struct credmsg cmsg; 1121124861Sharti 1122124861Sharti if (pi->buf == NULL) { 1123124861Sharti /* no buffer yet - allocate one */ 1124124861Sharti if ((pi->buf = buf_alloc(0)) == NULL) { 1125124861Sharti /* ups - could not get buffer. Read away input 1126124861Sharti * and drop it */ 1127124861Sharti (void)recvfrom(pi->fd, embuf, sizeof(embuf), 1128124861Sharti 0, NULL, NULL); 1129124861Sharti /* return error */ 1130124861Sharti return (-1); 1131124861Sharti } 1132124861Sharti pi->buflen = buf_size(0); 1133124861Sharti } 1134124861Sharti 1135124861Sharti /* try to get a message */ 1136124861Sharti msg.msg_name = pi->peer; 1137124861Sharti msg.msg_namelen = pi->peerlen; 1138124861Sharti msg.msg_iov = iov; 1139124861Sharti msg.msg_iovlen = 1; 1140124861Sharti if (pi->cred) { 1141124861Sharti msg.msg_control = &cmsg; 1142124861Sharti msg.msg_controllen = sizeof(cmsg); 1143124861Sharti 1144124861Sharti cmsg.hdr.cmsg_len = sizeof(cmsg); 1145124861Sharti cmsg.hdr.cmsg_level = SOL_SOCKET; 1146124861Sharti cmsg.hdr.cmsg_type = SCM_CREDS; 1147124861Sharti } else { 1148124861Sharti msg.msg_control = NULL; 1149128237Sharti msg.msg_controllen = 0; 1150124861Sharti } 1151124861Sharti msg.msg_flags = 0; 1152124861Sharti 1153124861Sharti iov[0].iov_base = pi->buf; 1154124861Sharti iov[0].iov_len = pi->buflen; 1155124861Sharti 1156124861Sharti len = recvmsg(pi->fd, &msg, 0); 1157124861Sharti 1158124861Sharti if (len == -1 || len == 0) 1159124861Sharti /* receive error */ 1160124861Sharti return (-1); 1161124861Sharti 1162124861Sharti if (msg.msg_flags & MSG_TRUNC) { 1163124861Sharti /* truncated - drop */ 1164122394Sharti snmpd_stats.silentDrops++; 1165122394Sharti snmpd_stats.inTooLong++; 1166124861Sharti return (-1); 1167122394Sharti } 1168122394Sharti 1169124861Sharti pi->length = (size_t)len; 1170124861Sharti 1171124861Sharti if (pi->cred) 1172124861Sharti check_priv(pi, &msg); 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 1194124861Sharti 1195124861Sharti /* get input depending on the transport */ 1196124861Sharti if (pi->stream) { 1197124861Sharti ret = recv_stream(pi); 1198124861Sharti } else { 1199124861Sharti ret = recv_dgram(pi); 1200124861Sharti } 1201124861Sharti 1202124861Sharti if (ret == -1) 1203124861Sharti return (-1); 1204124861Sharti 1205145557Sharti#ifdef USE_TCPWRAPPERS 1206122394Sharti /* 1207145557Sharti * In case of AF_INET{6} peer, do hosts_access(5) check. 1208145557Sharti */ 1209145557Sharti if (inet_ntop(pi->peer->sa_family, 1210146525Sharti &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, 1211146525Sharti client, sizeof(client)) != NULL) { 1212145557Sharti request_set(&req, RQ_CLIENT_ADDR, client, 0); 1213145557Sharti if (hosts_access(&req) == 0) { 1214145557Sharti syslog(LOG_ERR, "refused connection from %.500s", 1215145557Sharti eval_client(&req)); 1216145557Sharti return (-1); 1217145557Sharti } 1218145557Sharti } else 1219145557Sharti syslog(LOG_ERR, "inet_ntop(): %m"); 1220145557Sharti#endif 1221145557Sharti 1222145557Sharti /* 1223122394Sharti * Handle input 1224122394Sharti */ 1225124861Sharti ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, 1226124861Sharti &pi->consumed); 1227124861Sharti if (ierr == SNMPD_INPUT_TRUNC) { 1228124861Sharti /* need more bytes. This is ok only for streaming transports. 1229124861Sharti * but only if we have not reached bufsiz yet. */ 1230124861Sharti if (pi->stream) { 1231124861Sharti if (pi->length == buf_size(0)) { 1232124861Sharti snmpd_stats.silentDrops++; 1233124861Sharti return (-1); 1234124861Sharti } 1235124861Sharti return (0); 1236124861Sharti } 1237124861Sharti snmpd_stats.silentDrops++; 1238124861Sharti return (-1); 1239124861Sharti } 1240122394Sharti 1241122394Sharti /* can't check for bad SET pdus here, because a proxy may have to 1242122394Sharti * check the access first. We don't want to return an error response 1243122394Sharti * to a proxy PDU with a wrong community */ 1244122394Sharti if (ierr == SNMPD_INPUT_FAILED) { 1245124861Sharti /* for streaming transports this is fatal */ 1246124861Sharti if (pi->stream) 1247124861Sharti return (-1); 1248124861Sharti snmp_input_consume(pi); 1249124861Sharti return (0); 1250122394Sharti } 1251133211Sharti if (ierr == SNMPD_INPUT_BAD_COMM) { 1252133211Sharti snmp_input_consume(pi); 1253133211Sharti return (0); 1254133211Sharti } 1255122394Sharti 1256122394Sharti /* 1257122394Sharti * If that is a module community and the module has a proxy function, 1258122394Sharti * the hand it over to the module. 1259122394Sharti */ 1260216294Ssyrinx if (comm != NULL && comm->owner != NULL && 1261216294Ssyrinx comm->owner->config->proxy != NULL) { 1262124861Sharti perr = (*comm->owner->config->proxy)(&pdu, tport->transport, 1263133211Sharti &tport->index, pi->peer, pi->peerlen, ierr, vi, 1264133211Sharti !pi->cred || pi->priv); 1265122394Sharti 1266122394Sharti switch (perr) { 1267122394Sharti 1268122394Sharti case SNMPD_PROXY_OK: 1269124861Sharti snmp_input_consume(pi); 1270124861Sharti return (0); 1271122394Sharti 1272122394Sharti case SNMPD_PROXY_REJ: 1273122394Sharti break; 1274122394Sharti 1275122394Sharti case SNMPD_PROXY_DROP: 1276124861Sharti snmp_input_consume(pi); 1277122394Sharti snmp_pdu_free(&pdu); 1278122394Sharti snmpd_stats.proxyDrops++; 1279124861Sharti return (0); 1280122394Sharti 1281122394Sharti case SNMPD_PROXY_BADCOMM: 1282124861Sharti snmp_input_consume(pi); 1283122394Sharti snmp_pdu_free(&pdu); 1284122394Sharti snmpd_stats.inBadCommunityNames++; 1285122394Sharti if (snmpd.auth_traps) 1286122394Sharti snmp_send_trap(&oid_authenticationFailure, 1287133211Sharti (struct snmp_value *)NULL); 1288124861Sharti return (0); 1289122394Sharti 1290122394Sharti case SNMPD_PROXY_BADCOMMUSE: 1291124861Sharti snmp_input_consume(pi); 1292122394Sharti snmp_pdu_free(&pdu); 1293122394Sharti snmpd_stats.inBadCommunityUses++; 1294122394Sharti if (snmpd.auth_traps) 1295122394Sharti snmp_send_trap(&oid_authenticationFailure, 1296133211Sharti (struct snmp_value *)NULL); 1297124861Sharti return (0); 1298122394Sharti } 1299122394Sharti } 1300122394Sharti 1301122394Sharti /* 1302122394Sharti * Check type 1303122394Sharti */ 1304122394Sharti if (pdu.type == SNMP_PDU_RESPONSE || 1305122394Sharti pdu.type == SNMP_PDU_TRAP || 1306122394Sharti pdu.type == SNMP_PDU_TRAP2) { 1307122394Sharti snmpd_stats.silentDrops++; 1308122394Sharti snmpd_stats.inBadPduTypes++; 1309122394Sharti snmp_pdu_free(&pdu); 1310124861Sharti snmp_input_consume(pi); 1311124861Sharti return (0); 1312122394Sharti } 1313122394Sharti 1314122394Sharti /* 1315122394Sharti * Check community 1316122394Sharti */ 1317216294Ssyrinx if (pdu.version < SNMP_V3 && 1318216294Ssyrinx ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || 1319124861Sharti (community != COMM_WRITE && 1320216294Ssyrinx (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { 1321122394Sharti snmpd_stats.inBadCommunityUses++; 1322122394Sharti snmp_pdu_free(&pdu); 1323124861Sharti snmp_input_consume(pi); 1324122394Sharti if (snmpd.auth_traps) 1325133211Sharti snmp_send_trap(&oid_authenticationFailure, 1326133211Sharti (struct snmp_value *)NULL); 1327124861Sharti return (0); 1328122394Sharti } 1329122394Sharti 1330122394Sharti /* 1331122394Sharti * Execute it. 1332122394Sharti */ 1333122394Sharti if ((sndbuf = buf_alloc(1)) == NULL) { 1334122394Sharti snmpd_stats.silentDrops++; 1335122394Sharti snmp_pdu_free(&pdu); 1336124861Sharti snmp_input_consume(pi); 1337124861Sharti return (0); 1338122394Sharti } 1339124861Sharti ferr = snmp_input_finish(&pdu, pi->buf, pi->length, 1340124861Sharti sndbuf, &sndlen, "SNMP", ierr, vi, NULL); 1341122394Sharti 1342122394Sharti if (ferr == SNMPD_INPUT_OK) { 1343124861Sharti slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen); 1344124861Sharti if (slen == -1) 1345122394Sharti syslog(LOG_ERR, "sendto: %m"); 1346124861Sharti else if ((size_t)slen != sndlen) 1347122394Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1348124861Sharti sndlen, (size_t)slen); 1349122394Sharti } 1350122394Sharti snmp_pdu_free(&pdu); 1351122394Sharti free(sndbuf); 1352124861Sharti snmp_input_consume(pi); 1353122394Sharti 1354124861Sharti return (0); 1355122394Sharti} 1356122394Sharti 1357122394Sharti/* 1358124861Sharti * Send a PDU to a given port 1359122394Sharti */ 1360124861Shartivoid 1361124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, 1362124861Sharti const struct sockaddr *addr, socklen_t addrlen) 1363122394Sharti{ 1364124861Sharti struct transport *trans = targ; 1365124861Sharti struct tport *tp; 1366124861Sharti u_char *sndbuf; 1367124861Sharti size_t sndlen; 1368124861Sharti ssize_t len; 1369122394Sharti 1370124861Sharti TAILQ_FOREACH(tp, &trans->table, link) 1371124861Sharti if (asn_compare_oid(port, &tp->index) == 0) 1372122394Sharti break; 1373124861Sharti if (tp == 0) 1374124861Sharti return; 1375122394Sharti 1376124861Sharti if ((sndbuf = buf_alloc(1)) == NULL) 1377124861Sharti return; 1378122394Sharti 1379124861Sharti snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); 1380122394Sharti 1381124861Sharti len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); 1382122394Sharti 1383124861Sharti if (len == -1) 1384124861Sharti syslog(LOG_ERR, "sendto: %m"); 1385124861Sharti else if ((size_t)len != sndlen) 1386124861Sharti syslog(LOG_ERR, "sendto: short write %zu/%zu", 1387124861Sharti sndlen, (size_t)len); 1388122394Sharti 1389124861Sharti free(sndbuf); 1390122394Sharti} 1391122394Sharti 1392122394Sharti 1393122394Sharti/* 1394124861Sharti * Close an input source 1395122394Sharti */ 1396122394Shartivoid 1397124861Shartisnmpd_input_close(struct port_input *pi) 1398122394Sharti{ 1399124861Sharti if (pi->id != NULL) 1400124861Sharti fd_deselect(pi->id); 1401124861Sharti if (pi->fd >= 0) 1402124861Sharti (void)close(pi->fd); 1403124861Sharti if (pi->buf != NULL) 1404124861Sharti free(pi->buf); 1405122394Sharti} 1406122394Sharti 1407122394Sharti/* 1408122394Sharti * Dump internal state. 1409122394Sharti */ 1410124861Sharti#ifdef USE_LIBBEGEMOT 1411122394Shartistatic void 1412124861Shartiinfo_func(void) 1413124861Sharti#else 1414124861Shartistatic void 1415122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) 1416124861Sharti#endif 1417122394Sharti{ 1418122394Sharti struct lmodule *m; 1419122394Sharti u_int i; 1420122394Sharti char buf[10000]; 1421122394Sharti 1422122394Sharti syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); 1423122394Sharti for (i = 0; i < tree_size; i++) { 1424122394Sharti switch (tree[i].type) { 1425122394Sharti 1426122394Sharti case SNMP_NODE_LEAF: 1427122394Sharti sprintf(buf, "LEAF: %s %s", tree[i].name, 1428122394Sharti asn_oid2str(&tree[i].oid)); 1429122394Sharti break; 1430122394Sharti 1431122394Sharti case SNMP_NODE_COLUMN: 1432122394Sharti sprintf(buf, "COL: %s %s", tree[i].name, 1433122394Sharti asn_oid2str(&tree[i].oid)); 1434122394Sharti break; 1435122394Sharti } 1436122394Sharti syslog(LOG_DEBUG, "%s", buf); 1437122394Sharti } 1438122394Sharti 1439122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1440122394Sharti if (m->config->dump) 1441122394Sharti (*m->config->dump)(); 1442122394Sharti} 1443122394Sharti 1444122394Sharti/* 1445122394Sharti * Re-read configuration 1446122394Sharti */ 1447124861Sharti#ifdef USE_LIBBEGEMOT 1448122394Shartistatic void 1449124861Sharticonfig_func(void) 1450124861Sharti#else 1451124861Shartistatic void 1452122394Sharticonfig_func(evContext ctx __unused, void *uap __unused, 1453122394Sharti const void *tag __unused) 1454124861Sharti#endif 1455122394Sharti{ 1456122394Sharti struct lmodule *m; 1457122394Sharti 1458122394Sharti if (read_config(config_file, NULL)) { 1459122394Sharti syslog(LOG_ERR, "error reading config file '%s'", config_file); 1460122394Sharti return; 1461122394Sharti } 1462122394Sharti TAILQ_FOREACH(m, &lmodules, link) 1463122394Sharti if (m->config->config) 1464122394Sharti (*m->config->config)(); 1465122394Sharti} 1466122394Sharti 1467122394Sharti/* 1468122394Sharti * On USR1 dump actual configuration. 1469122394Sharti */ 1470122394Shartistatic void 1471122394Shartionusr1(int s __unused) 1472122394Sharti{ 1473124861Sharti 1474122394Sharti work |= WORK_DOINFO; 1475122394Sharti} 1476122394Shartistatic void 1477122394Shartionhup(int s __unused) 1478122394Sharti{ 1479124861Sharti 1480122394Sharti work |= WORK_RECONFIG; 1481122394Sharti} 1482122394Sharti 1483122394Shartistatic void 1484122394Shartionterm(int s __unused) 1485122394Sharti{ 1486122394Sharti 1487124861Sharti /* allow clean-up */ 1488122394Sharti exit(0); 1489122394Sharti} 1490122394Sharti 1491122394Shartistatic void 1492122394Shartiinit_sigs(void) 1493122394Sharti{ 1494122394Sharti struct sigaction sa; 1495122394Sharti 1496122394Sharti sa.sa_handler = onusr1; 1497122394Sharti sa.sa_flags = SA_RESTART; 1498122394Sharti sigemptyset(&sa.sa_mask); 1499122394Sharti if (sigaction(SIGUSR1, &sa, NULL)) { 1500122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1501122394Sharti exit(1); 1502122394Sharti } 1503122394Sharti 1504122394Sharti sa.sa_handler = onhup; 1505122394Sharti if (sigaction(SIGHUP, &sa, NULL)) { 1506122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1507122394Sharti exit(1); 1508122394Sharti } 1509122394Sharti 1510122394Sharti sa.sa_handler = onterm; 1511122394Sharti sa.sa_flags = 0; 1512122394Sharti sigemptyset(&sa.sa_mask); 1513122394Sharti if (sigaction(SIGTERM, &sa, NULL)) { 1514122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1515122394Sharti exit(1); 1516122394Sharti } 1517122394Sharti if (sigaction(SIGINT, &sa, NULL)) { 1518122394Sharti syslog(LOG_ERR, "sigaction: %m"); 1519122394Sharti exit(1); 1520122394Sharti } 1521122394Sharti} 1522122394Sharti 1523122394Shartistatic void 1524122394Shartiblock_sigs(void) 1525122394Sharti{ 1526122394Sharti sigset_t set; 1527122394Sharti 1528122394Sharti sigfillset(&set); 1529122394Sharti if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { 1530122394Sharti syslog(LOG_ERR, "SIG_BLOCK: %m"); 1531122394Sharti exit(1); 1532122394Sharti } 1533122394Sharti} 1534122394Shartistatic void 1535122394Shartiunblock_sigs(void) 1536122394Sharti{ 1537122394Sharti if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { 1538122394Sharti syslog(LOG_ERR, "SIG_SETMASK: %m"); 1539122394Sharti exit(1); 1540122394Sharti } 1541122394Sharti} 1542122394Sharti 1543122394Sharti/* 1544122394Sharti * Shut down 1545122394Sharti */ 1546122394Shartistatic void 1547122394Shartiterm(void) 1548122394Sharti{ 1549122394Sharti (void)unlink(pid_file); 1550122394Sharti} 1551122394Sharti 1552124861Shartistatic void 1553124861Shartitrans_stop(void) 1554124861Sharti{ 1555124861Sharti struct transport *t; 1556124861Sharti 1557124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1558124861Sharti (void)t->vtab->stop(1); 1559124861Sharti} 1560124861Sharti 1561122394Sharti/* 1562122394Sharti * Define a macro from the command line 1563122394Sharti */ 1564122394Shartistatic void 1565122394Shartido_macro(char *arg) 1566122394Sharti{ 1567122394Sharti char *eq; 1568122394Sharti int err; 1569122394Sharti 1570122394Sharti if ((eq = strchr(arg, '=')) == NULL) 1571122394Sharti err = define_macro(arg, ""); 1572122394Sharti else { 1573122394Sharti *eq++ = '\0'; 1574122394Sharti err = define_macro(arg, eq); 1575122394Sharti } 1576122394Sharti if (err == -1) { 1577122394Sharti syslog(LOG_ERR, "cannot save macro: %m"); 1578122394Sharti exit(1); 1579122394Sharti } 1580122394Sharti} 1581122394Sharti 1582122394Sharti/* 1583122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken 1584122394Sharti * and will not compile with WARNS=5. 1585122394Sharti */ 1586122394Shartistatic int 1587122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp) 1588122394Sharti{ 1589122394Sharti static const char *const delim = ",\t "; 1590122394Sharti u_int i; 1591122394Sharti char *ptr; 1592122394Sharti 1593122394Sharti *optp = NULL; 1594122394Sharti 1595122394Sharti /* skip leading junk */ 1596122394Sharti for (ptr = *arg; *ptr != '\0'; ptr++) 1597122394Sharti if (strchr(delim, *ptr) == NULL) 1598122394Sharti break; 1599122394Sharti if (*ptr == '\0') { 1600122394Sharti *arg = ptr; 1601122394Sharti return (-1); 1602122394Sharti } 1603122394Sharti *optp = ptr; 1604122394Sharti 1605122394Sharti /* find the end of the option */ 1606122394Sharti while (*++ptr != '\0') 1607122394Sharti if (strchr(delim, *ptr) != NULL || *ptr == '=') 1608122394Sharti break; 1609122394Sharti 1610122394Sharti if (*ptr != '\0') { 1611122394Sharti if (*ptr == '=') { 1612122394Sharti *ptr++ = '\0'; 1613122394Sharti *valp = ptr; 1614122394Sharti while (*ptr != '\0' && strchr(delim, *ptr) == NULL) 1615122394Sharti ptr++; 1616122394Sharti if (*ptr != '\0') 1617122394Sharti *ptr++ = '\0'; 1618122394Sharti } else 1619122394Sharti *ptr++ = '\0'; 1620122394Sharti } 1621122394Sharti 1622122394Sharti *arg = ptr; 1623122394Sharti 1624122394Sharti for (i = 0; *options != NULL; options++, i++) 1625124861Sharti if (strcmp(*optp, *options) == 0) 1626122394Sharti return (i); 1627122394Sharti return (-1); 1628122394Sharti} 1629122394Sharti 1630122394Shartiint 1631122394Shartimain(int argc, char *argv[]) 1632122394Sharti{ 1633122394Sharti int opt; 1634122394Sharti FILE *fp; 1635122394Sharti int background = 1; 1636124861Sharti struct tport *p; 1637122394Sharti const char *prefix = "snmpd"; 1638122394Sharti struct lmodule *m; 1639216294Ssyrinx char *value = NULL, *option; /* XXX */ 1640124861Sharti struct transport *t; 1641122394Sharti 1642122394Sharti#define DBG_DUMP 0 1643122394Sharti#define DBG_EVENTS 1 1644122394Sharti#define DBG_TRACE 2 1645122394Sharti static const char *const debug_opts[] = { 1646122394Sharti "dump", 1647122394Sharti "events", 1648122394Sharti "trace", 1649122394Sharti NULL 1650122394Sharti }; 1651122394Sharti 1652122394Sharti snmp_printf = snmp_printf_func; 1653122394Sharti snmp_error = snmp_error_func; 1654122394Sharti snmp_debug = snmp_debug_func; 1655122394Sharti asn_error = asn_error_func; 1656122394Sharti 1657216294Ssyrinx while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) 1658122394Sharti switch (opt) { 1659122394Sharti 1660122394Sharti case 'c': 1661122394Sharti strlcpy(config_file, optarg, sizeof(config_file)); 1662122394Sharti break; 1663122394Sharti 1664122394Sharti case 'd': 1665122394Sharti background = 0; 1666122394Sharti break; 1667122394Sharti 1668122394Sharti case 'D': 1669122394Sharti while (*optarg) { 1670122394Sharti switch (getsubopt1(&optarg, debug_opts, 1671122394Sharti &value, &option)) { 1672122394Sharti 1673122394Sharti case DBG_DUMP: 1674122394Sharti debug.dump_pdus = 1; 1675122394Sharti break; 1676122394Sharti 1677122394Sharti case DBG_EVENTS: 1678122394Sharti debug.evdebug++; 1679122394Sharti break; 1680122394Sharti 1681122394Sharti case DBG_TRACE: 1682122394Sharti if (value == NULL) 1683122394Sharti syslog(LOG_ERR, 1684122394Sharti "no value for 'trace'"); 1685155094Sharti else 1686156066Sharti snmp_trace = strtoul(value, 1687156066Sharti NULL, 0); 1688122394Sharti break; 1689122394Sharti 1690122394Sharti case -1: 1691122394Sharti if (suboptarg) 1692122394Sharti syslog(LOG_ERR, 1693122394Sharti "unknown debug flag '%s'", 1694122394Sharti option); 1695122394Sharti else 1696122394Sharti syslog(LOG_ERR, 1697122394Sharti "missing debug flag"); 1698122394Sharti break; 1699122394Sharti } 1700122394Sharti } 1701122394Sharti break; 1702122394Sharti 1703216294Ssyrinx case 'e': 1704216294Ssyrinx strlcpy(engine_file, optarg, sizeof(engine_file)); 1705216294Ssyrinx break; 1706122394Sharti case 'h': 1707122394Sharti fprintf(stderr, "%s", usgtxt); 1708122394Sharti exit(0); 1709122394Sharti 1710122394Sharti case 'I': 1711122394Sharti syspath = optarg; 1712122394Sharti break; 1713122394Sharti 1714122394Sharti case 'l': 1715122394Sharti prefix = optarg; 1716122394Sharti break; 1717122394Sharti 1718122394Sharti case 'm': 1719122394Sharti do_macro(optarg); 1720122394Sharti break; 1721122394Sharti 1722122394Sharti case 'p': 1723122394Sharti strlcpy(pid_file, optarg, sizeof(pid_file)); 1724122394Sharti break; 1725122394Sharti } 1726122394Sharti 1727122394Sharti openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); 1728122394Sharti setlogmask(LOG_UPTO(debug.logpri - 1)); 1729122394Sharti 1730122394Sharti if (background && daemon(0, 0) < 0) { 1731122394Sharti syslog(LOG_ERR, "daemon: %m"); 1732122394Sharti exit(1); 1733122394Sharti } 1734122394Sharti 1735122394Sharti argc -= optind; 1736122394Sharti argv += optind; 1737122394Sharti 1738122394Sharti progargs = argv; 1739122394Sharti nprogargs = argc; 1740122394Sharti 1741122394Sharti srandomdev(); 1742122394Sharti 1743122394Sharti snmp_serial_no = random(); 1744122394Sharti 1745145557Sharti#ifdef USE_TCPWRAPPERS 1746122394Sharti /* 1747145557Sharti * Initialize hosts_access(3) handler. 1748145557Sharti */ 1749145557Sharti request_init(&req, RQ_DAEMON, "snmpd", 0); 1750145557Sharti sock_methods(&req); 1751145557Sharti#endif 1752145557Sharti 1753145557Sharti /* 1754122394Sharti * Initialize the tree. 1755122394Sharti */ 1756122394Sharti if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { 1757122394Sharti syslog(LOG_ERR, "%m"); 1758122394Sharti exit(1); 1759122394Sharti } 1760122394Sharti memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); 1761122394Sharti tree_size = CTREE_SIZE; 1762122394Sharti 1763122394Sharti /* 1764122394Sharti * Get standard communities 1765122394Sharti */ 1766154180Sharti (void)comm_define(1, "SNMP read", NULL, NULL); 1767154180Sharti (void)comm_define(2, "SNMP write", NULL, NULL); 1768122394Sharti community = COMM_INITIALIZE; 1769122394Sharti 1770122394Sharti trap_reqid = reqid_allocate(512, NULL); 1771122394Sharti 1772122394Sharti if (config_file[0] == '\0') 1773122394Sharti snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); 1774122394Sharti 1775122394Sharti init_actvals(); 1776216294Ssyrinx init_snmpd_engine(); 1777124861Sharti 1778124861Sharti this_tick = get_ticks(); 1779146525Sharti start_tick = this_tick; 1780124861Sharti 1781124861Sharti /* start transports */ 1782124861Sharti if (atexit(trans_stop) == -1) { 1783124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1784124861Sharti exit(1); 1785124861Sharti } 1786124861Sharti if (udp_trans.start() != SNMP_ERR_NOERROR) 1787124861Sharti syslog(LOG_WARNING, "cannot start UDP transport"); 1788124861Sharti if (lsock_trans.start() != SNMP_ERR_NOERROR) 1789124861Sharti syslog(LOG_WARNING, "cannot start LSOCK transport"); 1790124861Sharti 1791124861Sharti#ifdef USE_LIBBEGEMOT 1792124861Sharti if (debug.evdebug > 0) 1793124861Sharti rpoll_trace = 1; 1794124861Sharti#else 1795122394Sharti if (evCreate(&evctx)) { 1796122394Sharti syslog(LOG_ERR, "evCreate: %m"); 1797122394Sharti exit(1); 1798122394Sharti } 1799122394Sharti if (debug.evdebug > 0) 1800122394Sharti evSetDebug(evctx, 10, stderr); 1801124861Sharti#endif 1802122394Sharti 1803216294Ssyrinx if (engine_file[0] == '\0') 1804216294Ssyrinx snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); 1805216294Ssyrinx 1806133211Sharti if (read_config(config_file, NULL)) { 1807133211Sharti syslog(LOG_ERR, "error in config file"); 1808133211Sharti exit(1); 1809133211Sharti } 1810133211Sharti 1811124861Sharti TAILQ_FOREACH(t, &transport_list, link) 1812124861Sharti TAILQ_FOREACH(p, &t->table, link) 1813124861Sharti t->vtab->init_port(p); 1814122394Sharti 1815122394Sharti init_sigs(); 1816122394Sharti 1817122394Sharti if (pid_file[0] == '\0') 1818122394Sharti snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); 1819122394Sharti 1820122394Sharti if ((fp = fopen(pid_file, "w")) != NULL) { 1821122394Sharti fprintf(fp, "%u", getpid()); 1822122394Sharti fclose(fp); 1823124861Sharti if (atexit(term) == -1) { 1824124861Sharti syslog(LOG_ERR, "atexit failed: %m"); 1825124861Sharti (void)remove(pid_file); 1826124861Sharti exit(0); 1827124861Sharti } 1828122394Sharti } 1829122394Sharti 1830122394Sharti if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", 1831122394Sharti NULL) == 0) { 1832122394Sharti syslog(LOG_ERR, "cannot register SNMPv2 MIB"); 1833122394Sharti exit(1); 1834122394Sharti } 1835122394Sharti if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", 1836122394Sharti NULL) == 0) { 1837122394Sharti syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); 1838122394Sharti exit(1); 1839122394Sharti } 1840122394Sharti 1841133211Sharti snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); 1842122394Sharti 1843122394Sharti while ((m = TAILQ_FIRST(&modules_start)) != NULL) { 1844122394Sharti m->flags &= ~LM_ONSTARTLIST; 1845122394Sharti TAILQ_REMOVE(&modules_start, m, start); 1846122394Sharti lm_start(m); 1847122394Sharti } 1848122394Sharti 1849122394Sharti for (;;) { 1850124861Sharti#ifndef USE_LIBBEGEMOT 1851122394Sharti evEvent event; 1852124861Sharti#endif 1853122394Sharti struct lmodule *mod; 1854122394Sharti 1855122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 1856122394Sharti if (mod->config->idle != NULL) 1857122394Sharti (*mod->config->idle)(); 1858122394Sharti 1859124861Sharti#ifndef USE_LIBBEGEMOT 1860122394Sharti if (evGetNext(evctx, &event, EV_WAIT) == 0) { 1861122394Sharti if (evDispatch(evctx, event)) 1862122394Sharti syslog(LOG_ERR, "evDispatch: %m"); 1863122394Sharti } else if (errno != EINTR) { 1864122394Sharti syslog(LOG_ERR, "evGetNext: %m"); 1865122394Sharti exit(1); 1866122394Sharti } 1867124861Sharti#else 1868124861Sharti poll_dispatch(1); 1869124861Sharti#endif 1870122394Sharti 1871122394Sharti if (work != 0) { 1872122394Sharti block_sigs(); 1873122394Sharti if (work & WORK_DOINFO) { 1874124861Sharti#ifdef USE_LIBBEGEMOT 1875124861Sharti info_func(); 1876124861Sharti#else 1877122394Sharti if (evWaitFor(evctx, &work, info_func, 1878122394Sharti NULL, NULL) == -1) { 1879122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1880122394Sharti exit(1); 1881122394Sharti } 1882124861Sharti#endif 1883122394Sharti } 1884122394Sharti if (work & WORK_RECONFIG) { 1885124861Sharti#ifdef USE_LIBBEGEMOT 1886124861Sharti config_func(); 1887124861Sharti#else 1888122394Sharti if (evWaitFor(evctx, &work, config_func, 1889122394Sharti NULL, NULL) == -1) { 1890122394Sharti syslog(LOG_ERR, "evWaitFor: %m"); 1891122394Sharti exit(1); 1892122394Sharti } 1893124861Sharti#endif 1894122394Sharti } 1895122394Sharti work = 0; 1896122394Sharti unblock_sigs(); 1897124861Sharti#ifndef USE_LIBBEGEMOT 1898122394Sharti if (evDo(evctx, &work) == -1) { 1899122394Sharti syslog(LOG_ERR, "evDo: %m"); 1900122394Sharti exit(1); 1901122394Sharti } 1902124861Sharti#endif 1903122394Sharti } 1904122394Sharti } 1905122394Sharti 1906122394Sharti return (0); 1907122394Sharti} 1908122394Sharti 1909146525Shartiuint64_t 1910216294Ssyrinxget_ticks(void) 1911122394Sharti{ 1912122394Sharti struct timeval tv; 1913146525Sharti uint64_t ret; 1914122394Sharti 1915122394Sharti if (gettimeofday(&tv, NULL)) 1916122394Sharti abort(); 1917146525Sharti ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; 1918122394Sharti return (ret); 1919122394Sharti} 1920146525Sharti 1921122394Sharti/* 1922122394Sharti * Timer support 1923122394Sharti */ 1924150920Sharti 1925150920Sharti/* 1926150920Sharti * Trampoline for the non-repeatable timers. 1927150920Sharti */ 1928124861Sharti#ifdef USE_LIBBEGEMOT 1929122394Shartistatic void 1930124861Shartitfunc(int tid __unused, void *uap) 1931124861Sharti#else 1932124861Shartistatic void 1933122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1934122394Sharti struct timespec inter __unused) 1935124861Sharti#endif 1936122394Sharti{ 1937122394Sharti struct timer *tp = uap; 1938122394Sharti 1939122394Sharti LIST_REMOVE(tp, link); 1940122394Sharti tp->func(tp->udata); 1941122394Sharti free(tp); 1942122394Sharti} 1943122394Sharti 1944122394Sharti/* 1945150920Sharti * Trampoline for the repeatable timers. 1946122394Sharti */ 1947150920Sharti#ifdef USE_LIBBEGEMOT 1948150920Shartistatic void 1949150920Shartitrfunc(int tid __unused, void *uap) 1950150920Sharti#else 1951150920Shartistatic void 1952150920Shartitrfunc(evContext ctx __unused, void *uap, struct timespec due __unused, 1953150920Sharti struct timespec inter __unused) 1954150920Sharti#endif 1955150920Sharti{ 1956150920Sharti struct timer *tp = uap; 1957150920Sharti 1958150920Sharti tp->func(tp->udata); 1959150920Sharti} 1960150920Sharti 1961150920Sharti/* 1962150920Sharti * Start a one-shot timer 1963150920Sharti */ 1964122394Shartivoid * 1965122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) 1966122394Sharti{ 1967122394Sharti struct timer *tp; 1968145673Sharti#ifndef USE_LIBBEGEMOT 1969122394Sharti struct timespec due; 1970124861Sharti#endif 1971122394Sharti 1972122394Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 1973122394Sharti syslog(LOG_CRIT, "out of memory for timer"); 1974122394Sharti exit(1); 1975122394Sharti } 1976145673Sharti 1977145673Sharti#ifndef USE_LIBBEGEMOT 1978122394Sharti due = evAddTime(evNowTime(), 1979124861Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 1980124861Sharti#endif 1981122394Sharti 1982122394Sharti tp->udata = udata; 1983122394Sharti tp->owner = mod; 1984122394Sharti tp->func = func; 1985122394Sharti 1986122394Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 1987122394Sharti 1988124861Sharti#ifdef USE_LIBBEGEMOT 1989145673Sharti if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { 1990124861Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1991124861Sharti exit(1); 1992124861Sharti } 1993124861Sharti#else 1994122394Sharti if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) 1995122394Sharti == -1) { 1996122394Sharti syslog(LOG_ERR, "cannot set timer: %m"); 1997122394Sharti exit(1); 1998122394Sharti } 1999124861Sharti#endif 2000122394Sharti return (tp); 2001122394Sharti} 2002122394Sharti 2003150920Sharti/* 2004150920Sharti * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument 2005150920Sharti * is currently ignored and the initial number of ticks is set to the 2006150920Sharti * repeat number of ticks. 2007150920Sharti */ 2008150920Shartivoid * 2009150920Shartitimer_start_repeat(u_int ticks __unused, u_int repeat_ticks, 2010150920Sharti void (*func)(void *), void *udata, struct lmodule *mod) 2011150920Sharti{ 2012150920Sharti struct timer *tp; 2013150920Sharti#ifndef USE_LIBBEGEMOT 2014150920Sharti struct timespec due; 2015150920Sharti struct timespec inter; 2016150920Sharti#endif 2017150920Sharti 2018150920Sharti if ((tp = malloc(sizeof(struct timer))) == NULL) { 2019150920Sharti syslog(LOG_CRIT, "out of memory for timer"); 2020150920Sharti exit(1); 2021150920Sharti } 2022150920Sharti 2023150920Sharti#ifndef USE_LIBBEGEMOT 2024150920Sharti due = evAddTime(evNowTime(), 2025150920Sharti evConsTime(ticks / 100, (ticks % 100) * 10000)); 2026150920Sharti inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); 2027150920Sharti#endif 2028150920Sharti 2029150920Sharti tp->udata = udata; 2030150920Sharti tp->owner = mod; 2031150920Sharti tp->func = func; 2032150920Sharti 2033150920Sharti LIST_INSERT_HEAD(&timer_list, tp, link); 2034150920Sharti 2035150920Sharti#ifdef USE_LIBBEGEMOT 2036150920Sharti if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { 2037150920Sharti syslog(LOG_ERR, "cannot set timer: %m"); 2038150920Sharti exit(1); 2039150920Sharti } 2040150920Sharti#else 2041150920Sharti if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { 2042150920Sharti syslog(LOG_ERR, "cannot set timer: %m"); 2043150920Sharti exit(1); 2044150920Sharti } 2045150920Sharti#endif 2046150920Sharti return (tp); 2047150920Sharti} 2048150920Sharti 2049150920Sharti/* 2050150920Sharti * Stop a timer. 2051150920Sharti */ 2052122394Shartivoid 2053122394Shartitimer_stop(void *p) 2054122394Sharti{ 2055122394Sharti struct timer *tp = p; 2056122394Sharti 2057122394Sharti LIST_REMOVE(tp, link); 2058124861Sharti#ifdef USE_LIBBEGEMOT 2059124861Sharti poll_stop_timer(tp->id); 2060124861Sharti#else 2061122394Sharti if (evClearTimer(evctx, tp->id) == -1) { 2062122394Sharti syslog(LOG_ERR, "cannot stop timer: %m"); 2063122394Sharti exit(1); 2064122394Sharti } 2065124861Sharti#endif 2066122394Sharti free(p); 2067122394Sharti} 2068122394Sharti 2069122394Shartistatic void 2070122394Shartitimer_flush(struct lmodule *mod) 2071122394Sharti{ 2072122394Sharti struct timer *t, *t1; 2073122394Sharti 2074122394Sharti t = LIST_FIRST(&timer_list); 2075122394Sharti while (t != NULL) { 2076122394Sharti t1 = LIST_NEXT(t, link); 2077122394Sharti if (t->owner == mod) 2078122394Sharti timer_stop(t); 2079122394Sharti t = t1; 2080122394Sharti } 2081122394Sharti} 2082122394Sharti 2083122394Shartistatic void 2084122394Shartisnmp_printf_func(const char *fmt, ...) 2085122394Sharti{ 2086122394Sharti va_list ap; 2087122394Sharti static char *pend = NULL; 2088122394Sharti char *ret, *new; 2089122394Sharti 2090122394Sharti va_start(ap, fmt); 2091122394Sharti vasprintf(&ret, fmt, ap); 2092122394Sharti va_end(ap); 2093122394Sharti 2094122394Sharti if (ret == NULL) 2095122394Sharti return; 2096122394Sharti if (pend != NULL) { 2097122394Sharti if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) 2098122394Sharti == NULL) { 2099122394Sharti free(ret); 2100122394Sharti return; 2101122394Sharti } 2102122394Sharti pend = new; 2103122394Sharti strcat(pend, ret); 2104122394Sharti free(ret); 2105122394Sharti } else 2106122394Sharti pend = ret; 2107122394Sharti 2108122394Sharti while ((ret = strchr(pend, '\n')) != NULL) { 2109122394Sharti *ret = '\0'; 2110122394Sharti syslog(LOG_DEBUG, "%s", pend); 2111122394Sharti if (strlen(ret + 1) == 0) { 2112122394Sharti free(pend); 2113122394Sharti pend = NULL; 2114122394Sharti break; 2115122394Sharti } 2116122394Sharti strcpy(pend, ret + 1); 2117122394Sharti } 2118122394Sharti} 2119122394Sharti 2120122394Shartistatic void 2121122394Shartisnmp_error_func(const char *err, ...) 2122122394Sharti{ 2123122394Sharti char errbuf[1000]; 2124122394Sharti va_list ap; 2125122394Sharti 2126124861Sharti if (!(snmp_trace & LOG_SNMP_ERRORS)) 2127124861Sharti return; 2128124861Sharti 2129122394Sharti va_start(ap, err); 2130122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2131124861Sharti vsnprintf(errbuf + strlen(errbuf), 2132124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 2133122394Sharti va_end(ap); 2134122394Sharti 2135122394Sharti syslog(LOG_ERR, "%s", errbuf); 2136122394Sharti} 2137122394Sharti 2138122394Shartistatic void 2139122394Shartisnmp_debug_func(const char *err, ...) 2140122394Sharti{ 2141122394Sharti char errbuf[1000]; 2142122394Sharti va_list ap; 2143122394Sharti 2144122394Sharti va_start(ap, err); 2145122394Sharti snprintf(errbuf, sizeof(errbuf), "SNMP: "); 2146122394Sharti vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), 2147122394Sharti err, ap); 2148122394Sharti va_end(ap); 2149122394Sharti 2150122394Sharti syslog(LOG_DEBUG, "%s", errbuf); 2151122394Sharti} 2152122394Sharti 2153122394Shartistatic void 2154122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...) 2155122394Sharti{ 2156122394Sharti char errbuf[1000]; 2157122394Sharti va_list ap; 2158122394Sharti u_int i; 2159122394Sharti 2160124861Sharti if (!(snmp_trace & LOG_ASN1_ERRORS)) 2161124861Sharti return; 2162124861Sharti 2163122394Sharti va_start(ap, err); 2164122394Sharti snprintf(errbuf, sizeof(errbuf), "ASN.1: "); 2165124861Sharti vsnprintf(errbuf + strlen(errbuf), 2166124861Sharti sizeof(errbuf) - strlen(errbuf), err, ap); 2167122394Sharti va_end(ap); 2168122394Sharti 2169122394Sharti if (b != NULL) { 2170124861Sharti snprintf(errbuf + strlen(errbuf), 2171124861Sharti sizeof(errbuf) - strlen(errbuf), " at"); 2172122394Sharti for (i = 0; b->asn_len > i; i++) 2173124861Sharti snprintf(errbuf + strlen(errbuf), 2174124861Sharti sizeof(errbuf) - strlen(errbuf), 2175124861Sharti " %02x", b->asn_cptr[i]); 2176122394Sharti } 2177122394Sharti 2178122394Sharti syslog(LOG_ERR, "%s", errbuf); 2179122394Sharti} 2180122394Sharti 2181122394Sharti/* 2182122394Sharti * Create a new community 2183122394Sharti */ 2184122394Shartiu_int 2185122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner, 2186122394Sharti const char *str) 2187122394Sharti{ 2188122394Sharti struct community *c, *p; 2189122394Sharti u_int ncomm; 2190122394Sharti 2191122394Sharti /* generate an identifier */ 2192122394Sharti do { 2193122394Sharti if ((ncomm = next_community_index++) == UINT_MAX) 2194122394Sharti next_community_index = 1; 2195122394Sharti TAILQ_FOREACH(c, &community_list, link) 2196122394Sharti if (c->value == ncomm) 2197122394Sharti break; 2198122394Sharti } while (c != NULL); 2199122394Sharti 2200122394Sharti if ((c = malloc(sizeof(struct community))) == NULL) { 2201122394Sharti syslog(LOG_ERR, "comm_define: %m"); 2202122394Sharti return (0); 2203122394Sharti } 2204122394Sharti c->owner = owner; 2205122394Sharti c->value = ncomm; 2206122394Sharti c->descr = descr; 2207122394Sharti c->string = NULL; 2208122394Sharti c->private = priv; 2209122394Sharti 2210122394Sharti if (str != NULL) { 2211122394Sharti if((c->string = malloc(strlen(str)+1)) == NULL) { 2212122394Sharti free(c); 2213122394Sharti return (0); 2214122394Sharti } 2215122394Sharti strcpy(c->string, str); 2216122394Sharti } 2217122394Sharti 2218122394Sharti /* make index */ 2219122394Sharti if (c->owner == NULL) { 2220122394Sharti c->index.len = 1; 2221122394Sharti c->index.subs[0] = 0; 2222122394Sharti } else { 2223122394Sharti c->index = c->owner->index; 2224122394Sharti } 2225122394Sharti c->index.subs[c->index.len++] = c->private; 2226122394Sharti 2227122394Sharti /* 2228122394Sharti * Insert ordered 2229122394Sharti */ 2230122394Sharti TAILQ_FOREACH(p, &community_list, link) { 2231122394Sharti if (asn_compare_oid(&p->index, &c->index) > 0) { 2232122394Sharti TAILQ_INSERT_BEFORE(p, c, link); 2233122394Sharti break; 2234122394Sharti } 2235122394Sharti } 2236122394Sharti if (p == NULL) 2237122394Sharti TAILQ_INSERT_TAIL(&community_list, c, link); 2238122394Sharti return (c->value); 2239122394Sharti} 2240122394Sharti 2241122394Sharticonst char * 2242122394Sharticomm_string(u_int ncomm) 2243122394Sharti{ 2244122394Sharti struct community *p; 2245122394Sharti 2246122394Sharti TAILQ_FOREACH(p, &community_list, link) 2247122394Sharti if (p->value == ncomm) 2248122394Sharti return (p->string); 2249122394Sharti return (NULL); 2250122394Sharti} 2251122394Sharti 2252122394Sharti/* 2253122394Sharti * Delete all communities allocated by a module 2254122394Sharti */ 2255122394Shartistatic void 2256122394Sharticomm_flush(struct lmodule *mod) 2257122394Sharti{ 2258122394Sharti struct community *p, *p1; 2259122394Sharti 2260122394Sharti p = TAILQ_FIRST(&community_list); 2261122394Sharti while (p != NULL) { 2262122394Sharti p1 = TAILQ_NEXT(p, link); 2263122394Sharti if (p->owner == mod) { 2264122394Sharti free(p->string); 2265122394Sharti TAILQ_REMOVE(&community_list, p, link); 2266122394Sharti free(p); 2267122394Sharti } 2268122394Sharti p = p1; 2269122394Sharti } 2270122394Sharti} 2271122394Sharti 2272122394Sharti/* 2273122394Sharti * Request ID handling. 2274122394Sharti * 2275122394Sharti * Allocate a new range of request ids. Use a first fit algorithm. 2276122394Sharti */ 2277122394Shartiu_int 2278122394Shartireqid_allocate(int size, struct lmodule *mod) 2279122394Sharti{ 2280122394Sharti u_int type; 2281122394Sharti struct idrange *r, *r1; 2282122394Sharti 2283122394Sharti if (size <= 0 || size > INT32_MAX) { 2284122394Sharti syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); 2285122394Sharti return (0); 2286122394Sharti } 2287122394Sharti /* allocate a type id */ 2288122394Sharti do { 2289122394Sharti if ((type = next_idrange++) == UINT_MAX) 2290122394Sharti next_idrange = 1; 2291122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2292122394Sharti if (r->type == type) 2293122394Sharti break; 2294122394Sharti } while(r != NULL); 2295122394Sharti 2296122394Sharti /* find a range */ 2297122394Sharti if (TAILQ_EMPTY(&idrange_list)) 2298122394Sharti r = NULL; 2299122394Sharti else { 2300122394Sharti r = TAILQ_FIRST(&idrange_list); 2301122394Sharti if (r->base < size) { 2302122394Sharti while((r1 = TAILQ_NEXT(r, link)) != NULL) { 2303122394Sharti if (r1->base - (r->base + r->size) >= size) 2304122394Sharti break; 2305122394Sharti r = r1; 2306122394Sharti } 2307122394Sharti r = r1; 2308122394Sharti } 2309122394Sharti if (r == NULL) { 2310122394Sharti r1 = TAILQ_LAST(&idrange_list, idrange_list); 2311122394Sharti if (INT32_MAX - size + 1 < r1->base + r1->size) { 2312122394Sharti syslog(LOG_ERR, "out of id ranges (%u)", size); 2313122394Sharti return (0); 2314122394Sharti } 2315122394Sharti } 2316122394Sharti } 2317122394Sharti 2318122394Sharti /* allocate structure */ 2319122394Sharti if ((r1 = malloc(sizeof(struct idrange))) == NULL) { 2320122394Sharti syslog(LOG_ERR, "%s: %m", __FUNCTION__); 2321122394Sharti return (0); 2322122394Sharti } 2323122394Sharti 2324122394Sharti r1->type = type; 2325122394Sharti r1->size = size; 2326122394Sharti r1->owner = mod; 2327122394Sharti if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { 2328122394Sharti r1->base = 0; 2329122394Sharti TAILQ_INSERT_HEAD(&idrange_list, r1, link); 2330122394Sharti } else if (r == NULL) { 2331122394Sharti r = TAILQ_LAST(&idrange_list, idrange_list); 2332122394Sharti r1->base = r->base + r->size; 2333122394Sharti TAILQ_INSERT_TAIL(&idrange_list, r1, link); 2334122394Sharti } else { 2335122394Sharti r = TAILQ_PREV(r, idrange_list, link); 2336122394Sharti r1->base = r->base + r->size; 2337122394Sharti TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); 2338122394Sharti } 2339122394Sharti r1->next = r1->base; 2340122394Sharti 2341122394Sharti return (type); 2342122394Sharti} 2343122394Sharti 2344122394Shartiint32_t 2345122394Shartireqid_next(u_int type) 2346122394Sharti{ 2347122394Sharti struct idrange *r; 2348122394Sharti int32_t id; 2349122394Sharti 2350122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2351122394Sharti if (r->type == type) 2352122394Sharti break; 2353122394Sharti if (r == NULL) { 2354122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2355122394Sharti abort(); 2356122394Sharti } 2357122394Sharti if ((id = r->next++) == r->base + (r->size - 1)) 2358122394Sharti r->next = r->base; 2359122394Sharti return (id); 2360122394Sharti} 2361122394Sharti 2362122394Shartiint32_t 2363122394Shartireqid_base(u_int type) 2364122394Sharti{ 2365122394Sharti struct idrange *r; 2366122394Sharti 2367122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2368122394Sharti if (r->type == type) 2369122394Sharti return (r->base); 2370122394Sharti syslog(LOG_CRIT, "wrong idrange type"); 2371122394Sharti abort(); 2372122394Sharti} 2373122394Sharti 2374122394Shartiu_int 2375122394Shartireqid_type(int32_t reqid) 2376122394Sharti{ 2377122394Sharti struct idrange *r; 2378122394Sharti 2379122394Sharti TAILQ_FOREACH(r, &idrange_list, link) 2380122394Sharti if (reqid >= r->base && reqid <= r->base + (r->size - 1)) 2381122394Sharti return (r->type); 2382122394Sharti return (0); 2383122394Sharti} 2384122394Sharti 2385122394Shartiint 2386122394Shartireqid_istype(int32_t reqid, u_int type) 2387122394Sharti{ 2388122394Sharti return (reqid_type(reqid) == type); 2389122394Sharti} 2390122394Sharti 2391122394Sharti/* 2392122394Sharti * Delete all communities allocated by a module 2393122394Sharti */ 2394122394Shartistatic void 2395122394Shartireqid_flush(struct lmodule *mod) 2396122394Sharti{ 2397122394Sharti struct idrange *p, *p1; 2398122394Sharti 2399122394Sharti p = TAILQ_FIRST(&idrange_list); 2400122394Sharti while (p != NULL) { 2401122394Sharti p1 = TAILQ_NEXT(p, link); 2402122394Sharti if (p->owner == mod) { 2403122394Sharti TAILQ_REMOVE(&idrange_list, p, link); 2404122394Sharti free(p); 2405122394Sharti } 2406122394Sharti p = p1; 2407122394Sharti } 2408122394Sharti} 2409122394Sharti 2410122394Sharti/* 2411122394Sharti * Merge the given tree for the given module into the main tree. 2412122394Sharti */ 2413122394Shartistatic int 2414122394Sharticompare_node(const void *v1, const void *v2) 2415122394Sharti{ 2416122394Sharti const struct snmp_node *n1 = v1; 2417122394Sharti const struct snmp_node *n2 = v2; 2418122394Sharti 2419122394Sharti return (asn_compare_oid(&n1->oid, &n2->oid)); 2420122394Sharti} 2421122394Shartistatic int 2422122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) 2423122394Sharti{ 2424122394Sharti struct snmp_node *xtree; 2425122394Sharti u_int i; 2426122394Sharti 2427122394Sharti xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); 2428122394Sharti if (xtree == NULL) { 2429128237Sharti syslog(LOG_ERR, "tree_merge: %m"); 2430122394Sharti return (-1); 2431122394Sharti } 2432122394Sharti tree = xtree; 2433122394Sharti memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); 2434122394Sharti 2435122394Sharti for (i = 0; i < nsize; i++) 2436128237Sharti tree[tree_size + i].tree_data = mod; 2437122394Sharti 2438122394Sharti tree_size += nsize; 2439122394Sharti 2440122394Sharti qsort(tree, tree_size, sizeof(tree[0]), compare_node); 2441122394Sharti 2442122394Sharti return (0); 2443122394Sharti} 2444122394Sharti 2445122394Sharti/* 2446122394Sharti * Remove all nodes belonging to the loadable module 2447122394Sharti */ 2448122394Shartistatic void 2449122394Shartitree_unmerge(struct lmodule *mod) 2450122394Sharti{ 2451122394Sharti u_int s, d; 2452122394Sharti 2453122394Sharti for(s = d = 0; s < tree_size; s++) 2454128237Sharti if (tree[s].tree_data != mod) { 2455122394Sharti if (s != d) 2456122394Sharti tree[d] = tree[s]; 2457122394Sharti d++; 2458122394Sharti } 2459122394Sharti tree_size = d; 2460122394Sharti} 2461122394Sharti 2462122394Sharti/* 2463122394Sharti * Loadable modules 2464122394Sharti */ 2465122394Shartistruct lmodule * 2466122394Shartilm_load(const char *path, const char *section) 2467122394Sharti{ 2468122394Sharti struct lmodule *m; 2469122394Sharti int err; 2470122394Sharti int i; 2471122394Sharti char *av[MAX_MOD_ARGS + 1]; 2472122394Sharti int ac; 2473122394Sharti u_int u; 2474122394Sharti 2475122394Sharti if ((m = malloc(sizeof(*m))) == NULL) { 2476122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2477122394Sharti return (NULL); 2478122394Sharti } 2479122394Sharti m->handle = NULL; 2480122394Sharti m->flags = 0; 2481122394Sharti strcpy(m->section, section); 2482122394Sharti 2483122394Sharti if ((m->path = malloc(strlen(path) + 1)) == NULL) { 2484122394Sharti syslog(LOG_ERR, "lm_load: %m"); 2485122394Sharti goto err; 2486122394Sharti } 2487122394Sharti strcpy(m->path, path); 2488122394Sharti 2489122394Sharti /* 2490122394Sharti * Make index 2491122394Sharti */ 2492122394Sharti m->index.subs[0] = strlen(section); 2493122394Sharti m->index.len = m->index.subs[0] + 1; 2494122394Sharti for (u = 0; u < m->index.subs[0]; u++) 2495122394Sharti m->index.subs[u + 1] = section[u]; 2496122394Sharti 2497122394Sharti /* 2498122394Sharti * Load the object file and locate the config structure 2499122394Sharti */ 2500122394Sharti if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { 2501122394Sharti syslog(LOG_ERR, "lm_load: open %s", dlerror()); 2502122394Sharti goto err; 2503122394Sharti } 2504122394Sharti 2505122394Sharti if ((m->config = dlsym(m->handle, "config")) == NULL) { 2506122394Sharti syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); 2507122394Sharti goto err; 2508122394Sharti } 2509122394Sharti 2510122394Sharti /* 2511122394Sharti * Insert it into the right place 2512122394Sharti */ 2513122394Sharti INSERT_OBJECT_OID(m, &lmodules); 2514122394Sharti 2515122394Sharti /* preserve order */ 2516122394Sharti if (community == COMM_INITIALIZE) { 2517122394Sharti m->flags |= LM_ONSTARTLIST; 2518122394Sharti TAILQ_INSERT_TAIL(&modules_start, m, start); 2519122394Sharti } 2520122394Sharti 2521122394Sharti /* 2522122394Sharti * make the argument vector. 2523122394Sharti */ 2524122394Sharti ac = 0; 2525122394Sharti for (i = 0; i < nprogargs; i++) { 2526122394Sharti if (strlen(progargs[i]) >= strlen(section) + 1 && 2527122394Sharti strncmp(progargs[i], section, strlen(section)) == 0 && 2528122394Sharti progargs[i][strlen(section)] == ':') { 2529122394Sharti if (ac == MAX_MOD_ARGS) { 2530122394Sharti syslog(LOG_WARNING, "too many arguments for " 2531122394Sharti "module '%s", section); 2532122394Sharti break; 2533122394Sharti } 2534122394Sharti av[ac++] = &progargs[i][strlen(section)+1]; 2535122394Sharti } 2536122394Sharti } 2537122394Sharti av[ac] = NULL; 2538122394Sharti 2539122394Sharti /* 2540150920Sharti * Run the initialization function 2541122394Sharti */ 2542122394Sharti if ((err = (*m->config->init)(m, ac, av)) != 0) { 2543122394Sharti syslog(LOG_ERR, "lm_load: init failed: %d", err); 2544122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2545122394Sharti goto err; 2546122394Sharti } 2547122394Sharti 2548122394Sharti return (m); 2549122394Sharti 2550122394Sharti err: 2551176892Ssyrinx if ((m->flags & LM_ONSTARTLIST) != 0) 2552176892Ssyrinx TAILQ_REMOVE(&modules_start, m, start); 2553122394Sharti if (m->handle) 2554122394Sharti dlclose(m->handle); 2555122394Sharti free(m->path); 2556122394Sharti free(m); 2557122394Sharti return (NULL); 2558122394Sharti} 2559122394Sharti 2560122394Sharti/* 2561122394Sharti * Start a module 2562122394Sharti */ 2563122394Shartivoid 2564122394Shartilm_start(struct lmodule *mod) 2565122394Sharti{ 2566122394Sharti const struct lmodule *m; 2567122394Sharti 2568122394Sharti /* 2569122394Sharti * Merge tree. If this fails, unload the module. 2570122394Sharti */ 2571122394Sharti if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { 2572122394Sharti lm_unload(mod); 2573122394Sharti return; 2574122394Sharti } 2575122394Sharti 2576122394Sharti /* 2577122394Sharti * Read configuration 2578122394Sharti */ 2579122394Sharti if (read_config(config_file, mod)) { 2580122394Sharti syslog(LOG_ERR, "error in config file"); 2581122394Sharti lm_unload(mod); 2582122394Sharti return; 2583122394Sharti } 2584122394Sharti if (mod->config->start) 2585122394Sharti (*mod->config->start)(); 2586122394Sharti 2587122394Sharti mod->flags |= LM_STARTED; 2588122394Sharti 2589122394Sharti /* 2590122394Sharti * Inform other modules 2591122394Sharti */ 2592122394Sharti TAILQ_FOREACH(m, &lmodules, link) 2593122394Sharti if (m->config->loading) 2594122394Sharti (*m->config->loading)(mod, 1); 2595122394Sharti} 2596122394Sharti 2597122394Sharti 2598122394Sharti/* 2599122394Sharti * Unload a module. 2600122394Sharti */ 2601122394Shartivoid 2602122394Shartilm_unload(struct lmodule *m) 2603122394Sharti{ 2604122394Sharti int err; 2605122394Sharti const struct lmodule *mod; 2606122394Sharti 2607122394Sharti TAILQ_REMOVE(&lmodules, m, link); 2608122394Sharti if (m->flags & LM_ONSTARTLIST) 2609122394Sharti TAILQ_REMOVE(&modules_start, m, start); 2610122394Sharti tree_unmerge(m); 2611122394Sharti 2612122394Sharti if ((m->flags & LM_STARTED) && m->config->fini && 2613122394Sharti (err = (*m->config->fini)()) != 0) 2614122394Sharti syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); 2615122394Sharti 2616122394Sharti comm_flush(m); 2617122394Sharti reqid_flush(m); 2618122394Sharti timer_flush(m); 2619122394Sharti fd_flush(m); 2620122394Sharti 2621122394Sharti dlclose(m->handle); 2622122394Sharti free(m->path); 2623122394Sharti 2624122394Sharti /* 2625122394Sharti * Inform other modules 2626122394Sharti */ 2627122394Sharti TAILQ_FOREACH(mod, &lmodules, link) 2628122394Sharti if (mod->config->loading) 2629122394Sharti (*mod->config->loading)(m, 0); 2630122394Sharti 2631122394Sharti free(m); 2632122394Sharti} 2633122394Sharti 2634122394Sharti/* 2635122394Sharti * Register an object resource and return the index (or 0 on failures) 2636122394Sharti */ 2637122394Shartiu_int 2638122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) 2639122394Sharti{ 2640122394Sharti struct objres *objres, *or1; 2641122394Sharti u_int idx; 2642122394Sharti 2643122394Sharti /* find a free index */ 2644122394Sharti idx = 1; 2645122394Sharti for (objres = TAILQ_FIRST(&objres_list); 2646122394Sharti objres != NULL; 2647122394Sharti objres = TAILQ_NEXT(objres, link)) { 2648122394Sharti if ((or1 = TAILQ_NEXT(objres, link)) == NULL || 2649122394Sharti or1->index > objres->index + 1) { 2650122394Sharti idx = objres->index + 1; 2651122394Sharti break; 2652122394Sharti } 2653122394Sharti } 2654122394Sharti 2655122394Sharti if ((objres = malloc(sizeof(*objres))) == NULL) 2656122394Sharti return (0); 2657122394Sharti 2658122394Sharti objres->index = idx; 2659122394Sharti objres->oid = *or; 2660122394Sharti strlcpy(objres->descr, descr, sizeof(objres->descr)); 2661146525Sharti objres->uptime = (uint32_t)(get_ticks() - start_tick); 2662122394Sharti objres->module = mod; 2663122394Sharti 2664122394Sharti INSERT_OBJECT_INT(objres, &objres_list); 2665122394Sharti 2666122394Sharti systemg.or_last_change = objres->uptime; 2667122394Sharti 2668122394Sharti return (idx); 2669122394Sharti} 2670122394Sharti 2671122394Shartivoid 2672122394Shartior_unregister(u_int idx) 2673122394Sharti{ 2674122394Sharti struct objres *objres; 2675122394Sharti 2676122394Sharti TAILQ_FOREACH(objres, &objres_list, link) 2677122394Sharti if (objres->index == idx) { 2678122394Sharti TAILQ_REMOVE(&objres_list, objres, link); 2679122394Sharti free(objres); 2680122394Sharti return; 2681122394Sharti } 2682122394Sharti} 2683216294Ssyrinx 2684216294Ssyrinx/* 2685216294Ssyrinx * RFC 3414 User-based Security Model support 2686216294Ssyrinx */ 2687216294Ssyrinx 2688216294Ssyrinxstruct snmpd_usmstat * 2689216294Ssyrinxbsnmpd_get_usm_stats(void) 2690216294Ssyrinx{ 2691216294Ssyrinx return (&snmpd_usmstats); 2692216294Ssyrinx} 2693216294Ssyrinx 2694216294Ssyrinxvoid 2695216294Ssyrinxbsnmpd_reset_usm_stats(void) 2696216294Ssyrinx{ 2697216294Ssyrinx memset(&snmpd_usmstats, 0, sizeof(&snmpd_usmstats)); 2698216294Ssyrinx} 2699216294Ssyrinx 2700216294Ssyrinxstruct usm_user * 2701216294Ssyrinxusm_first_user(void) 2702216294Ssyrinx{ 2703216294Ssyrinx return (SLIST_FIRST(&usm_userlist)); 2704216294Ssyrinx} 2705216294Ssyrinx 2706216294Ssyrinxstruct usm_user * 2707216294Ssyrinxusm_next_user(struct usm_user *uuser) 2708216294Ssyrinx{ 2709216294Ssyrinx if (uuser == NULL) 2710216294Ssyrinx return (NULL); 2711216294Ssyrinx 2712216294Ssyrinx return (SLIST_NEXT(uuser, up)); 2713216294Ssyrinx} 2714216294Ssyrinx 2715216294Ssyrinxstruct usm_user * 2716216294Ssyrinxusm_find_user(uint8_t *engine, uint32_t elen, char *uname) 2717216294Ssyrinx{ 2718216294Ssyrinx struct usm_user *uuser; 2719216294Ssyrinx 2720216294Ssyrinx SLIST_FOREACH(uuser, &usm_userlist, up) 2721216294Ssyrinx if (uuser->user_engine_len == elen && 2722216294Ssyrinx memcmp(uuser->user_engine_id, engine, elen) == 0 && 2723216294Ssyrinx strlen(uuser->suser.sec_name) == strlen(uname) && 2724216294Ssyrinx strcmp(uuser->suser.sec_name, uname) == 0) 2725216294Ssyrinx break; 2726216294Ssyrinx 2727216294Ssyrinx return (uuser); 2728216294Ssyrinx} 2729216294Ssyrinx 2730216294Ssyrinxstatic int 2731216294Ssyrinxusm_compare_user(struct usm_user *u1, struct usm_user *u2) 2732216294Ssyrinx{ 2733216294Ssyrinx uint32_t i; 2734216294Ssyrinx 2735216294Ssyrinx if (u1->user_engine_len < u2->user_engine_len) 2736216294Ssyrinx return (-1); 2737216294Ssyrinx if (u1->user_engine_len > u2->user_engine_len) 2738216294Ssyrinx return (1); 2739216294Ssyrinx 2740216294Ssyrinx for (i = 0; i < u1->user_engine_len; i++) { 2741216294Ssyrinx if (u1->user_engine_id[i] < u2->user_engine_id[i]) 2742216294Ssyrinx return (-1); 2743216294Ssyrinx if (u1->user_engine_id[i] > u2->user_engine_id[i]) 2744216294Ssyrinx return (1); 2745216294Ssyrinx } 2746216294Ssyrinx 2747216294Ssyrinx if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) 2748216294Ssyrinx return (-1); 2749216294Ssyrinx if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) 2750216294Ssyrinx return (1); 2751216294Ssyrinx 2752216294Ssyrinx for (i = 0; i < strlen(u1->suser.sec_name); i++) { 2753216294Ssyrinx if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) 2754216294Ssyrinx return (-1); 2755216294Ssyrinx if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) 2756216294Ssyrinx return (1); 2757216294Ssyrinx } 2758216294Ssyrinx 2759216294Ssyrinx return (0); 2760216294Ssyrinx} 2761216294Ssyrinx 2762216294Ssyrinxstruct usm_user * 2763216294Ssyrinxusm_new_user(uint8_t *eid, uint32_t elen, char *uname) 2764216294Ssyrinx{ 2765216294Ssyrinx int cmp; 2766216294Ssyrinx struct usm_user *uuser, *temp, *prev; 2767216294Ssyrinx 2768216294Ssyrinx for (uuser = usm_first_user(); uuser != NULL; 2769216294Ssyrinx (uuser = usm_next_user(uuser))) { 2770216294Ssyrinx if (uuser->user_engine_len == elen && 2771216294Ssyrinx strlen(uname) == strlen(uuser->suser.sec_name) && 2772216294Ssyrinx strcmp(uname, uuser->suser.sec_name) == 0 && 2773216294Ssyrinx memcmp(eid, uuser->user_engine_id, elen) == 0) 2774216294Ssyrinx return (NULL); 2775216294Ssyrinx } 2776216294Ssyrinx 2777216294Ssyrinx if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) 2778216294Ssyrinx return (NULL); 2779216294Ssyrinx 2780216294Ssyrinx memset(uuser, 0, sizeof(struct usm_user)); 2781216294Ssyrinx strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); 2782216294Ssyrinx memcpy(uuser->user_engine_id, eid, elen); 2783216294Ssyrinx uuser->user_engine_len = elen; 2784216294Ssyrinx 2785216294Ssyrinx if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || 2786216294Ssyrinx usm_compare_user(uuser, prev) < 0) { 2787216294Ssyrinx SLIST_INSERT_HEAD(&usm_userlist, uuser, up); 2788216294Ssyrinx return (uuser); 2789216294Ssyrinx } 2790216294Ssyrinx 2791216294Ssyrinx SLIST_FOREACH(temp, &usm_userlist, up) { 2792216294Ssyrinx if ((cmp = usm_compare_user(uuser, temp)) <= 0) 2793216294Ssyrinx break; 2794216294Ssyrinx prev = temp; 2795216294Ssyrinx } 2796216294Ssyrinx 2797216294Ssyrinx if (temp == NULL || cmp < 0) 2798216294Ssyrinx SLIST_INSERT_AFTER(prev, uuser, up); 2799216294Ssyrinx else if (cmp > 0) 2800216294Ssyrinx SLIST_INSERT_AFTER(temp, uuser, up); 2801216294Ssyrinx else { 2802216294Ssyrinx syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); 2803216294Ssyrinx free(uuser); 2804216294Ssyrinx return (NULL); 2805216294Ssyrinx } 2806216294Ssyrinx 2807216294Ssyrinx return (uuser); 2808216294Ssyrinx} 2809216294Ssyrinx 2810216294Ssyrinxvoid 2811216294Ssyrinxusm_delete_user(struct usm_user *uuser) 2812216294Ssyrinx{ 2813216294Ssyrinx SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); 2814216294Ssyrinx free(uuser); 2815216294Ssyrinx} 2816216294Ssyrinx 2817216294Ssyrinxvoid 2818216294Ssyrinxusm_flush_users(void) 2819216294Ssyrinx{ 2820216294Ssyrinx struct usm_user *uuser; 2821216294Ssyrinx 2822216294Ssyrinx while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { 2823216294Ssyrinx SLIST_REMOVE_HEAD(&usm_userlist, up); 2824216294Ssyrinx free(uuser); 2825216294Ssyrinx } 2826216294Ssyrinx 2827216294Ssyrinx SLIST_INIT(&usm_userlist); 2828216294Ssyrinx} 2829216294Ssyrinx 2830216294Ssyrinx/* 2831216294Ssyrinx * RFC 3415 View-based Access Control Model support 2832216294Ssyrinx */ 2833216294Ssyrinxstruct vacm_user * 2834216294Ssyrinxvacm_first_user(void) 2835216294Ssyrinx{ 2836216294Ssyrinx return (SLIST_FIRST(&vacm_userlist)); 2837216294Ssyrinx} 2838216294Ssyrinx 2839216294Ssyrinxstruct vacm_user * 2840216294Ssyrinxvacm_next_user(struct vacm_user *vuser) 2841216294Ssyrinx{ 2842216294Ssyrinx if (vuser == NULL) 2843216294Ssyrinx return (NULL); 2844216294Ssyrinx 2845216294Ssyrinx return (SLIST_NEXT(vuser, vvu)); 2846216294Ssyrinx} 2847216294Ssyrinx 2848216294Ssyrinxstatic int 2849216294Ssyrinxvacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) 2850216294Ssyrinx{ 2851216294Ssyrinx uint32_t i; 2852216294Ssyrinx 2853216294Ssyrinx if (v1->sec_model < v2->sec_model) 2854216294Ssyrinx return (-1); 2855216294Ssyrinx if (v1->sec_model > v2->sec_model) 2856216294Ssyrinx return (1); 2857216294Ssyrinx 2858216294Ssyrinx if (strlen(v1->secname) < strlen(v2->secname)) 2859216294Ssyrinx return (-1); 2860216294Ssyrinx if (strlen(v1->secname) > strlen(v2->secname)) 2861216294Ssyrinx return (1); 2862216294Ssyrinx 2863216294Ssyrinx for (i = 0; i < strlen(v1->secname); i++) { 2864216294Ssyrinx if (v1->secname[i] < v2->secname[i]) 2865216294Ssyrinx return (-1); 2866216294Ssyrinx if (v1->secname[i] > v2->secname[i]) 2867216294Ssyrinx return (1); 2868216294Ssyrinx } 2869216294Ssyrinx 2870216294Ssyrinx return (0); 2871216294Ssyrinx} 2872216294Ssyrinx 2873216294Ssyrinxstruct vacm_user * 2874216294Ssyrinxvacm_new_user(int32_t smodel, char *uname) 2875216294Ssyrinx{ 2876216294Ssyrinx int cmp; 2877216294Ssyrinx struct vacm_user *user, *temp, *prev; 2878216294Ssyrinx 2879216294Ssyrinx SLIST_FOREACH(user, &vacm_userlist, vvu) 2880216294Ssyrinx if (strcmp(uname, user->secname) == 0 && 2881216294Ssyrinx smodel == user->sec_model) 2882216294Ssyrinx return (NULL); 2883216294Ssyrinx 2884216294Ssyrinx if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) 2885216294Ssyrinx return (NULL); 2886216294Ssyrinx 2887216294Ssyrinx memset(user, 0, sizeof(*user)); 2888216294Ssyrinx user->group = &vacm_default_group; 2889216294Ssyrinx SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); 2890216294Ssyrinx user->sec_model = smodel; 2891216294Ssyrinx strlcpy(user->secname, uname, sizeof(user->secname)); 2892216294Ssyrinx 2893216294Ssyrinx if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || 2894216294Ssyrinx vacm_compare_user(user, prev) < 0) { 2895216294Ssyrinx SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); 2896216294Ssyrinx return (user); 2897216294Ssyrinx } 2898216294Ssyrinx 2899216294Ssyrinx SLIST_FOREACH(temp, &vacm_userlist, vvu) { 2900216294Ssyrinx if ((cmp = vacm_compare_user(user, temp)) <= 0) 2901216294Ssyrinx break; 2902216294Ssyrinx prev = temp; 2903216294Ssyrinx } 2904216294Ssyrinx 2905216294Ssyrinx if (temp == NULL || cmp < 0) 2906216294Ssyrinx SLIST_INSERT_AFTER(prev, user, vvu); 2907216294Ssyrinx else if (cmp > 0) 2908216294Ssyrinx SLIST_INSERT_AFTER(temp, user, vvu); 2909216294Ssyrinx else { 2910216294Ssyrinx syslog(LOG_ERR, "User %s exists", user->secname); 2911216294Ssyrinx free(user); 2912216294Ssyrinx return (NULL); 2913216294Ssyrinx } 2914216294Ssyrinx 2915216294Ssyrinx return (user); 2916216294Ssyrinx} 2917216294Ssyrinx 2918216294Ssyrinxint 2919216294Ssyrinxvacm_delete_user(struct vacm_user *user) 2920216294Ssyrinx{ 2921216294Ssyrinx if (user->group != NULL && user->group != &vacm_default_group) { 2922216294Ssyrinx SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2923216294Ssyrinx if (SLIST_EMPTY(&user->group->group_users)) { 2924216294Ssyrinx SLIST_REMOVE(&vacm_grouplist, user->group, 2925216294Ssyrinx vacm_group, vge); 2926216294Ssyrinx free(user->group); 2927216294Ssyrinx } 2928216294Ssyrinx } 2929216294Ssyrinx 2930216294Ssyrinx SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); 2931216294Ssyrinx free(user); 2932216294Ssyrinx 2933216294Ssyrinx return (0); 2934216294Ssyrinx} 2935216294Ssyrinx 2936216294Ssyrinxint 2937216294Ssyrinxvacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) 2938216294Ssyrinx{ 2939216294Ssyrinx struct vacm_group *group; 2940216294Ssyrinx 2941216294Ssyrinx if (len >= SNMP_ADM_STR32_SIZ) 2942216294Ssyrinx return (-1); 2943216294Ssyrinx 2944216294Ssyrinx SLIST_FOREACH(group, &vacm_grouplist, vge) 2945216294Ssyrinx if (strlen(group->groupname) == len && 2946216294Ssyrinx memcmp(octets, group->groupname, len) == 0) 2947216294Ssyrinx break; 2948216294Ssyrinx 2949216294Ssyrinx if (group == NULL) { 2950216294Ssyrinx if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) 2951216294Ssyrinx return (-1); 2952216294Ssyrinx memset(group, 0, sizeof(*group)); 2953216294Ssyrinx memcpy(group->groupname, octets, len); 2954216294Ssyrinx group->groupname[len] = '\0'; 2955216294Ssyrinx SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); 2956216294Ssyrinx } 2957216294Ssyrinx 2958216294Ssyrinx SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); 2959216294Ssyrinx SLIST_INSERT_HEAD(&group->group_users, user, vvg); 2960216294Ssyrinx user->group = group; 2961216294Ssyrinx 2962216294Ssyrinx return (0); 2963216294Ssyrinx} 2964216294Ssyrinx 2965216294Ssyrinxvoid 2966216294Ssyrinxvacm_groups_init(void) 2967216294Ssyrinx{ 2968216294Ssyrinx SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); 2969216294Ssyrinx} 2970216294Ssyrinx 2971216294Ssyrinxstruct vacm_access * 2972216294Ssyrinxvacm_first_access_rule(void) 2973216294Ssyrinx{ 2974216294Ssyrinx return (TAILQ_FIRST(&vacm_accesslist)); 2975216294Ssyrinx} 2976216294Ssyrinx 2977216294Ssyrinxstruct vacm_access * 2978216294Ssyrinxvacm_next_access_rule(struct vacm_access *acl) 2979216294Ssyrinx{ 2980216294Ssyrinx if (acl == NULL) 2981216294Ssyrinx return (NULL); 2982216294Ssyrinx 2983216294Ssyrinx return (TAILQ_NEXT(acl, vva)); 2984216294Ssyrinx} 2985216294Ssyrinx 2986216294Ssyrinxstatic int 2987216294Ssyrinxvacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) 2988216294Ssyrinx{ 2989216294Ssyrinx uint32_t i; 2990216294Ssyrinx 2991216294Ssyrinx if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) 2992216294Ssyrinx return (-1); 2993216294Ssyrinx if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) 2994216294Ssyrinx return (1); 2995216294Ssyrinx 2996216294Ssyrinx for (i = 0; i < strlen(v1->group->groupname); i++) { 2997216294Ssyrinx if (v1->group->groupname[i] < v2->group->groupname[i]) 2998216294Ssyrinx return (-1); 2999216294Ssyrinx if (v1->group->groupname[i] > v2->group->groupname[i]) 3000216294Ssyrinx return (1); 3001216294Ssyrinx } 3002216294Ssyrinx 3003216294Ssyrinx if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) 3004216294Ssyrinx return (-1); 3005216294Ssyrinx if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) 3006216294Ssyrinx return (1); 3007216294Ssyrinx 3008216294Ssyrinx for (i = 0; i < strlen(v1->ctx_prefix); i++) { 3009216294Ssyrinx if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) 3010216294Ssyrinx return (-1); 3011216294Ssyrinx if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) 3012216294Ssyrinx return (1); 3013216294Ssyrinx } 3014216294Ssyrinx 3015216294Ssyrinx if (v1->sec_model < v2->sec_model) 3016216294Ssyrinx return (-1); 3017216294Ssyrinx if (v1->sec_model > v2->sec_model) 3018216294Ssyrinx return (1); 3019216294Ssyrinx 3020216294Ssyrinx if (v1->sec_level < v2->sec_level) 3021216294Ssyrinx return (-1); 3022216294Ssyrinx if (v1->sec_level > v2->sec_level) 3023216294Ssyrinx return (1); 3024216294Ssyrinx 3025216294Ssyrinx return (0); 3026216294Ssyrinx} 3027216294Ssyrinx 3028216294Ssyrinxstruct vacm_access * 3029216294Ssyrinxvacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) 3030216294Ssyrinx{ 3031216294Ssyrinx struct vacm_group *group; 3032216294Ssyrinx struct vacm_access *acl, *temp; 3033216294Ssyrinx 3034216294Ssyrinx TAILQ_FOREACH(acl, &vacm_accesslist, vva) { 3035216294Ssyrinx if (acl->group == NULL) 3036216294Ssyrinx continue; 3037216294Ssyrinx if (strcmp(gname, acl->group->groupname) == 0 && 3038216294Ssyrinx strcmp(cprefix, acl->ctx_prefix) == 0 && 3039216294Ssyrinx acl->sec_model == smodel && acl->sec_level == slevel) 3040216294Ssyrinx return (NULL); 3041216294Ssyrinx } 3042216294Ssyrinx 3043216294Ssyrinx /* Make sure the group exists */ 3044216294Ssyrinx SLIST_FOREACH(group, &vacm_grouplist, vge) 3045216294Ssyrinx if (strcmp(gname, group->groupname) == 0) 3046216294Ssyrinx break; 3047216294Ssyrinx 3048216294Ssyrinx if (group == NULL) 3049216294Ssyrinx return (NULL); 3050216294Ssyrinx 3051216294Ssyrinx if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) 3052216294Ssyrinx return (NULL); 3053216294Ssyrinx 3054216294Ssyrinx memset(acl, 0, sizeof(*acl)); 3055216294Ssyrinx acl->group = group; 3056216294Ssyrinx strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); 3057216294Ssyrinx acl->sec_model = smodel; 3058216294Ssyrinx acl->sec_level = slevel; 3059216294Ssyrinx 3060216294Ssyrinx if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || 3061216294Ssyrinx vacm_compare_access_rule(acl, temp) < 0) { 3062216294Ssyrinx TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); 3063216294Ssyrinx return (acl); 3064216294Ssyrinx } 3065216294Ssyrinx 3066216294Ssyrinx TAILQ_FOREACH(temp, &vacm_accesslist, vva) 3067216294Ssyrinx if (vacm_compare_access_rule(acl, temp) < 0) { 3068216294Ssyrinx TAILQ_INSERT_BEFORE(temp, acl, vva); 3069216294Ssyrinx return (acl); 3070216294Ssyrinx } 3071216294Ssyrinx 3072216294Ssyrinx TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); 3073216294Ssyrinx 3074216294Ssyrinx return (acl); 3075216294Ssyrinx} 3076216294Ssyrinx 3077216294Ssyrinxint 3078216294Ssyrinxvacm_delete_access_rule(struct vacm_access *acl) 3079216294Ssyrinx{ 3080216294Ssyrinx TAILQ_REMOVE(&vacm_accesslist, acl, vva); 3081216294Ssyrinx free(acl); 3082216294Ssyrinx 3083216294Ssyrinx return (0); 3084216294Ssyrinx} 3085216294Ssyrinx 3086216294Ssyrinxstruct vacm_view * 3087216294Ssyrinxvacm_first_view(void) 3088216294Ssyrinx{ 3089216294Ssyrinx return (SLIST_FIRST(&vacm_viewlist)); 3090216294Ssyrinx} 3091216294Ssyrinx 3092216294Ssyrinxstruct vacm_view * 3093216294Ssyrinxvacm_next_view(struct vacm_view *view) 3094216294Ssyrinx{ 3095216294Ssyrinx if (view == NULL) 3096216294Ssyrinx return (NULL); 3097216294Ssyrinx 3098216294Ssyrinx return (SLIST_NEXT(view, vvl)); 3099216294Ssyrinx} 3100216294Ssyrinx 3101216294Ssyrinxstatic int 3102216294Ssyrinxvacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) 3103216294Ssyrinx{ 3104216294Ssyrinx uint32_t i; 3105216294Ssyrinx 3106216294Ssyrinx if (strlen(v1->viewname) < strlen(v2->viewname)) 3107216294Ssyrinx return (-1); 3108216294Ssyrinx if (strlen(v1->viewname) > strlen(v2->viewname)) 3109216294Ssyrinx return (1); 3110216294Ssyrinx 3111216294Ssyrinx for (i = 0; i < strlen(v1->viewname); i++) { 3112216294Ssyrinx if (v1->viewname[i] < v2->viewname[i]) 3113216294Ssyrinx return (-1); 3114216294Ssyrinx if (v1->viewname[i] > v2->viewname[i]) 3115216294Ssyrinx return (1); 3116216294Ssyrinx } 3117216294Ssyrinx 3118216294Ssyrinx return (asn_compare_oid(&v1->subtree, &v2->subtree)); 3119216294Ssyrinx} 3120216294Ssyrinx 3121216294Ssyrinxstruct vacm_view * 3122216294Ssyrinxvacm_new_view(char *vname, struct asn_oid *oid) 3123216294Ssyrinx{ 3124216294Ssyrinx int cmp; 3125216294Ssyrinx struct vacm_view *view, *temp, *prev; 3126216294Ssyrinx 3127216294Ssyrinx SLIST_FOREACH(view, &vacm_viewlist, vvl) 3128216294Ssyrinx if (strcmp(vname, view->viewname) == 0) 3129216294Ssyrinx return (NULL); 3130216294Ssyrinx 3131216294Ssyrinx if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) 3132216294Ssyrinx return (NULL); 3133216294Ssyrinx 3134216294Ssyrinx memset(view, 0, sizeof(*view)); 3135216294Ssyrinx strlcpy(view->viewname, vname, sizeof(view->viewname)); 3136216294Ssyrinx asn_append_oid(&view->subtree, oid); 3137216294Ssyrinx 3138216294Ssyrinx if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || 3139216294Ssyrinx vacm_compare_view(view, prev) < 0) { 3140216294Ssyrinx SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); 3141216294Ssyrinx return (view); 3142216294Ssyrinx } 3143216294Ssyrinx 3144216294Ssyrinx SLIST_FOREACH(temp, &vacm_viewlist, vvl) { 3145216294Ssyrinx if ((cmp = vacm_compare_view(view, temp)) <= 0) 3146216294Ssyrinx break; 3147216294Ssyrinx prev = temp; 3148216294Ssyrinx } 3149216294Ssyrinx 3150216294Ssyrinx if (temp == NULL || cmp < 0) 3151216294Ssyrinx SLIST_INSERT_AFTER(prev, view, vvl); 3152216294Ssyrinx else if (cmp > 0) 3153216294Ssyrinx SLIST_INSERT_AFTER(temp, view, vvl); 3154216294Ssyrinx else { 3155216294Ssyrinx syslog(LOG_ERR, "View %s exists", view->viewname); 3156216294Ssyrinx free(view); 3157216294Ssyrinx return (NULL); 3158216294Ssyrinx } 3159216294Ssyrinx 3160216294Ssyrinx return (view); 3161216294Ssyrinx} 3162216294Ssyrinx 3163216294Ssyrinxint 3164216294Ssyrinxvacm_delete_view(struct vacm_view *view) 3165216294Ssyrinx{ 3166216294Ssyrinx SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); 3167216294Ssyrinx free(view); 3168216294Ssyrinx 3169216294Ssyrinx return (0); 3170216294Ssyrinx} 3171216294Ssyrinx 3172216294Ssyrinxstruct vacm_context * 3173216294Ssyrinxvacm_first_context(void) 3174216294Ssyrinx{ 3175216294Ssyrinx return (SLIST_FIRST(&vacm_contextlist)); 3176216294Ssyrinx} 3177216294Ssyrinx 3178216294Ssyrinxstruct vacm_context * 3179216294Ssyrinxvacm_next_context(struct vacm_context *vacmctx) 3180216294Ssyrinx{ 3181216294Ssyrinx if (vacmctx == NULL) 3182216294Ssyrinx return (NULL); 3183216294Ssyrinx 3184216294Ssyrinx return (SLIST_NEXT(vacmctx, vcl)); 3185216294Ssyrinx} 3186216294Ssyrinx 3187216294Ssyrinxstruct vacm_context * 3188216294Ssyrinxvacm_add_context(char *ctxname, int regid) 3189216294Ssyrinx{ 3190216294Ssyrinx int cmp; 3191216294Ssyrinx struct vacm_context *ctx, *temp, *prev; 3192216294Ssyrinx 3193216294Ssyrinx SLIST_FOREACH(ctx, &vacm_contextlist, vcl) 3194216294Ssyrinx if (strcmp(ctxname, ctx->ctxname) == 0) { 3195216294Ssyrinx syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3196216294Ssyrinx return (NULL); 3197216294Ssyrinx } 3198216294Ssyrinx 3199216294Ssyrinx if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) 3200216294Ssyrinx return (NULL); 3201216294Ssyrinx 3202216294Ssyrinx memset(ctx, 0, sizeof(*ctx)); 3203216294Ssyrinx strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); 3204216294Ssyrinx ctx->regid = regid; 3205216294Ssyrinx 3206216294Ssyrinx if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || 3207216294Ssyrinx strlen(ctx->ctxname) < strlen(prev->ctxname) || 3208216294Ssyrinx strcmp(ctx->ctxname, prev->ctxname) < 0) { 3209216294Ssyrinx SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); 3210216294Ssyrinx return (ctx); 3211216294Ssyrinx } 3212216294Ssyrinx 3213216294Ssyrinx SLIST_FOREACH(temp, &vacm_contextlist, vcl) { 3214216294Ssyrinx if (strlen(ctx->ctxname) < strlen(temp->ctxname) || 3215216294Ssyrinx strcmp(ctx->ctxname, temp->ctxname) < 0) { 3216216294Ssyrinx cmp = -1; 3217216294Ssyrinx break; 3218216294Ssyrinx } 3219216294Ssyrinx prev = temp; 3220216294Ssyrinx } 3221216294Ssyrinx 3222216294Ssyrinx if (temp == NULL || cmp < 0) 3223216294Ssyrinx SLIST_INSERT_AFTER(prev, ctx, vcl); 3224216294Ssyrinx else if (cmp > 0) 3225216294Ssyrinx SLIST_INSERT_AFTER(temp, ctx, vcl); 3226216294Ssyrinx else { 3227216294Ssyrinx syslog(LOG_ERR, "Context %s exists", ctx->ctxname); 3228216294Ssyrinx free(ctx); 3229216294Ssyrinx return (NULL); 3230216294Ssyrinx } 3231216294Ssyrinx 3232216294Ssyrinx return (ctx); 3233216294Ssyrinx} 3234216294Ssyrinx 3235216294Ssyrinxvoid 3236216294Ssyrinxvacm_flush_contexts(int regid) 3237216294Ssyrinx{ 3238216294Ssyrinx struct vacm_context *ctx, *temp; 3239216294Ssyrinx 3240216294Ssyrinx SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) 3241216294Ssyrinx if (ctx->regid == regid) { 3242216294Ssyrinx SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); 3243216294Ssyrinx free(ctx); 3244216294Ssyrinx } 3245216294Ssyrinx} 3246