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