main.c revision 128237
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>
7122394Sharti *
8122394Sharti * Redistribution of this software and documentation and use in source and
9122394Sharti * binary forms, with or without modification, are permitted provided that
10122394Sharti * the following conditions are met:
11122394Sharti *
12122394Sharti * 1. Redistributions of source code or documentation must retain the above
13122394Sharti *    copyright notice, this list of conditions and the following disclaimer.
14122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
15122394Sharti *    notice, this list of conditions and the following disclaimer in the
16122394Sharti *    documentation and/or other materials provided with the distribution.
17122394Sharti * 3. Neither the name of the Institute nor the names of its contributors
18122394Sharti *    may be used to endorse or promote products derived from this software
19122394Sharti *    without specific prior written permission.
20122394Sharti *
21122394Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22122394Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23122394Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24122394Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25122394Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26122394Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27122394Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28122394Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29122394Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30122394Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31122394Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32122394Sharti *
33128237Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.85 2004/04/14 15:39:14 novo Exp $
34122394Sharti *
35122394Sharti * SNMPd main stuff.
36122394Sharti */
37122394Sharti#include <sys/param.h>
38122394Sharti#include <sys/un.h>
39124861Sharti#include <sys/ucred.h>
40122394Sharti#include <stdio.h>
41122394Sharti#include <stdlib.h>
42122394Sharti#include <stddef.h>
43122394Sharti#include <string.h>
44122394Sharti#include <stdarg.h>
45122394Sharti#include <ctype.h>
46122394Sharti#include <errno.h>
47122394Sharti#include <syslog.h>
48122394Sharti#include <unistd.h>
49122394Sharti#include <signal.h>
50122394Sharti#include <dlfcn.h>
51122394Sharti#include <inttypes.h>
52122394Sharti
53122394Sharti#include "snmpmod.h"
54122394Sharti#include "snmpd.h"
55122394Sharti#include "tree.h"
56122394Sharti#include "oid.h"
57122394Sharti
58122394Sharti#define	PATH_PID	"/var/run/%s.pid"
59122394Sharti#define PATH_CONFIG	"/etc/%s.config"
60122394Sharti
61122394Shartiu_int32_t this_tick;	/* start of processing of current packet */
62122394Shartiu_int32_t start_tick;	/* start of processing */
63122394Sharti
64122394Shartistruct systemg systemg = {
65122394Sharti	NULL,
66122394Sharti	{ 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }},
67122394Sharti	NULL, NULL, NULL,
68122394Sharti	64 + 8 + 4,
69122394Sharti	0
70122394Sharti};
71122394Shartistruct debug debug = {
72122394Sharti	0,		/* dump_pdus */
73122394Sharti	LOG_DEBUG,	/* log_pri */
74122394Sharti	0,		/* evdebug */
75122394Sharti};
76122394Sharti
77122394Shartistruct snmpd snmpd = {
78122394Sharti	2048,		/* txbuf */
79122394Sharti	2048,		/* rxbuf */
80122394Sharti	0,		/* comm_dis */
81122394Sharti	0,		/* auth_traps */
82122394Sharti	{0, 0, 0, 0},	/* trap1addr */
83124861Sharti	VERS_ENABLE_ALL,/* version_enable */
84122394Sharti};
85122394Shartistruct snmpd_stats snmpd_stats;
86122394Sharti
87122394Sharti/* snmpSerialNo */
88122394Shartiint32_t snmp_serial_no;
89122394Sharti
90122394Sharti/* search path for config files */
91122394Sharticonst char *syspath = PATH_SYSCONFIG;
92122394Sharti
93122394Sharti/* list of all loaded modules */
94122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules);
95122394Sharti
96122394Sharti/* list of loaded modules during start-up in the order they were loaded */
97122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start);
98122394Sharti
99122394Sharti/* list of all known communities */
100122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list);
101122394Sharti
102122394Sharti/* list of all installed object resources */
103122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list);
104122394Sharti
105122394Sharti/* community value generator */
106122394Shartistatic u_int next_community_index = 1;
107122394Sharti
108122394Sharti/* list of all known ranges */
109122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list);
110122394Sharti
111122394Sharti/* identifier generator */
112122394Shartiu_int next_idrange = 1;
113122394Sharti
114122394Sharti/* list of all current timers */
115122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list);
116122394Sharti
117122394Sharti/* list of file descriptors */
118122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list);
119122394Sharti
120122394Sharti/* program arguments */
121122394Shartistatic char **progargs;
122122394Shartistatic int nprogargs;
123122394Sharti
124122394Sharti/* current community */
125122394Shartiu_int	community;
126122394Shartistatic struct community *comm;
127122394Sharti
128122394Sharti/* file names */
129122394Shartistatic char config_file[MAXPATHLEN + 1];
130122394Shartistatic char pid_file[MAXPATHLEN + 1];
131122394Sharti
132124861Sharti#ifndef USE_LIBBEGEMOT
133122394Sharti/* event context */
134122394Shartistatic evContext evctx;
135124861Sharti#endif
136122394Sharti
137122394Sharti/* signal mask */
138122394Shartistatic sigset_t blocked_sigs;
139122394Sharti
140122394Sharti/* signal handling */
141122394Shartistatic int work;
142122394Sharti#define	WORK_DOINFO	0x0001
143122394Sharti#define	WORK_RECONFIG	0x0002
144122394Sharti
145122394Sharti/* oids */
146122394Shartistatic const struct asn_oid
147122394Sharti	oid_snmpMIB = OIDX_snmpMIB,
148122394Sharti	oid_begemotSnmpd = OIDX_begemotSnmpd,
149122394Sharti	oid_coldStart = OIDX_coldStart,
150122394Sharti	oid_authenticationFailure = OIDX_authenticationFailure;
151122394Sharti
152122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }};
153122394Sharti
154122394Sharti/* request id generator for traps */
155122394Shartiu_int trap_reqid;
156122394Sharti
157122394Sharti/* help text */
158122394Shartistatic const char usgtxt[] = "\
159122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
160122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\
161122394Shartiusage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\
162122394Sharti             [-m variable=value] [-p file]\n\
163122394Shartioptions:\n\
164122394Sharti  -d		don't daemonize\n\
165122394Sharti  -h		print this info\n\
166122394Sharti  -c file	specify configuration file\n\
167122394Sharti  -D options	debugging options\n\
168122394Sharti  -I path	system include path\n\
169122394Sharti  -l prefix	default basename for pid and config file\n\
170122394Sharti  -m var=val	define variable\n\
171122394Sharti  -p file	specify pid file\n\
172122394Sharti";
173122394Sharti
174124861Sharti/* transports */
175124861Shartiextern const struct transport_def udp_trans;
176124861Shartiextern const struct transport_def lsock_trans;
177124861Sharti
178124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
179124861Sharti
180122394Sharti/* forward declarations */
181122394Shartistatic void snmp_printf_func(const char *fmt, ...);
182122394Shartistatic void snmp_error_func(const char *err, ...);
183122394Shartistatic void snmp_debug_func(const char *err, ...);
184122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...);
185122394Sharti
186122394Sharti/*
187122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx.
188122394Sharti */
189122394Shartivoid *
190122394Shartibuf_alloc(int tx)
191122394Sharti{
192122394Sharti	void *buf;
193122394Sharti
194124861Sharti	if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) {
195122394Sharti		syslog(LOG_CRIT, "cannot allocate buffer");
196122394Sharti		if (tx)
197122394Sharti			snmpd_stats.noTxbuf++;
198122394Sharti		else
199122394Sharti			snmpd_stats.noRxbuf++;
200122394Sharti		return (NULL);
201122394Sharti	}
202122394Sharti	return (buf);
203122394Sharti}
204122394Sharti
205122394Sharti/*
206124861Sharti * Return the buffer size.
207122394Sharti */
208122394Shartisize_t
209122394Shartibuf_size(int tx)
210122394Sharti{
211124861Sharti	return (tx ? snmpd.txbuf : snmpd.rxbuf);
212122394Sharti}
213122394Sharti
214122394Sharti/*
215122394Sharti * Prepare a PDU for output
216122394Sharti */
217122394Shartivoid
218124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen,
219122394Sharti    const char *dest)
220122394Sharti{
221122394Sharti	struct asn_buf resp_b;
222122394Sharti
223122394Sharti	resp_b.asn_ptr = sndbuf;
224122394Sharti	resp_b.asn_len = snmpd.txbuf;
225122394Sharti
226122394Sharti	if (snmp_pdu_encode(pdu, &resp_b) != 0) {
227122394Sharti		syslog(LOG_ERR, "cannot encode message");
228122394Sharti		abort();
229122394Sharti	}
230122394Sharti	if (debug.dump_pdus) {
231122394Sharti		snmp_printf("%s <- ", dest);
232122394Sharti		snmp_pdu_dump(pdu);
233122394Sharti	}
234122394Sharti	*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
235122394Sharti}
236122394Sharti
237122394Sharti/*
238122394Sharti * SNMP input. Start: decode the PDU, find the community.
239122394Sharti */
240122394Shartienum snmpd_input_err
241122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source,
242124861Sharti    struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen)
243122394Sharti{
244122394Sharti	struct asn_buf b;
245122394Sharti	enum snmp_code code;
246122394Sharti	enum snmpd_input_err ret;
247124861Sharti	int sret;
248122394Sharti
249122394Sharti	b.asn_cptr = buf;
250122394Sharti	b.asn_len = len;
251124861Sharti
252124861Sharti	/* look whether we have enough bytes for the entire PDU. */
253124861Sharti	switch (sret = snmp_pdu_snoop(&b)) {
254124861Sharti
255124861Sharti	  case 0:
256124861Sharti		return (SNMPD_INPUT_TRUNC);
257124861Sharti
258124861Sharti	  case -1:
259124861Sharti		snmpd_stats.inASNParseErrs++;
260124861Sharti		return (SNMPD_INPUT_FAILED);
261124861Sharti	}
262124861Sharti	b.asn_len = *pdulen = (size_t)sret;
263124861Sharti
264122394Sharti	code = snmp_pdu_decode(&b, pdu, ip);
265122394Sharti
266124861Sharti	snmpd_stats.inPkts++;
267124861Sharti
268122394Sharti	ret = SNMPD_INPUT_OK;
269122394Sharti	switch (code) {
270122394Sharti
271122394Sharti	  case SNMP_CODE_FAILED:
272122394Sharti		snmpd_stats.inASNParseErrs++;
273122394Sharti		return (SNMPD_INPUT_FAILED);
274122394Sharti
275122394Sharti	  case SNMP_CODE_BADVERS:
276124861Sharti	  bad_vers:
277122394Sharti		snmpd_stats.inBadVersions++;
278122394Sharti		return (SNMPD_INPUT_FAILED);
279122394Sharti
280122394Sharti	  case SNMP_CODE_BADLEN:
281122394Sharti		if (pdu->type == SNMP_OP_SET)
282122394Sharti			ret = SNMPD_INPUT_VALBADLEN;
283122394Sharti		break;
284122394Sharti
285122394Sharti	  case SNMP_CODE_OORANGE:
286122394Sharti		if (pdu->type == SNMP_OP_SET)
287122394Sharti			ret = SNMPD_INPUT_VALRANGE;
288122394Sharti		break;
289122394Sharti
290122394Sharti	  case SNMP_CODE_BADENC:
291122394Sharti		if (pdu->type == SNMP_OP_SET)
292122394Sharti			ret = SNMPD_INPUT_VALBADENC;
293122394Sharti		break;
294122394Sharti
295122394Sharti	  case SNMP_CODE_OK:
296124861Sharti		switch (pdu->version) {
297124861Sharti
298124861Sharti		  case SNMP_V1:
299124861Sharti			if (!(snmpd.version_enable & VERS_ENABLE_V1))
300124861Sharti				goto bad_vers;
301124861Sharti			break;
302124861Sharti
303124861Sharti		  case SNMP_V2c:
304124861Sharti			if (!(snmpd.version_enable & VERS_ENABLE_V2C))
305124861Sharti				goto bad_vers;
306124861Sharti			break;
307124861Sharti
308124861Sharti		  case SNMP_Verr:
309124861Sharti			goto bad_vers;
310124861Sharti		}
311122394Sharti		break;
312122394Sharti	}
313122394Sharti
314122394Sharti	if (debug.dump_pdus) {
315122394Sharti		snmp_printf("%s -> ", source);
316122394Sharti		snmp_pdu_dump(pdu);
317122394Sharti	}
318122394Sharti
319122394Sharti	/*
320122394Sharti	 * Look, whether we know the community
321122394Sharti	 */
322122394Sharti	TAILQ_FOREACH(comm, &community_list, link)
323122394Sharti		if (comm->string != NULL &&
324122394Sharti		    strcmp(comm->string, pdu->community) == 0)
325122394Sharti			break;
326122394Sharti
327122394Sharti	if (comm == NULL) {
328122394Sharti		snmpd_stats.inBadCommunityNames++;
329122394Sharti		snmp_pdu_free(pdu);
330122394Sharti		if (snmpd.auth_traps)
331122394Sharti			snmp_send_trap(&oid_authenticationFailure, NULL);
332122394Sharti		return (SNMPD_INPUT_FAILED);
333122394Sharti	}
334122394Sharti	community = comm->value;
335122394Sharti
336122394Sharti	/* update uptime */
337122394Sharti	this_tick = get_ticks();
338122394Sharti
339122394Sharti	return (ret);
340122394Sharti}
341122394Sharti
342122394Sharti/*
343122394Sharti * Will return only _OK or _FAILED
344122394Sharti */
345122394Shartienum snmpd_input_err
346122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen,
347122394Sharti    u_char *sndbuf, size_t *sndlen, const char *source,
348122394Sharti    enum snmpd_input_err ierr, int32_t ivar, void *data)
349122394Sharti{
350122394Sharti	struct snmp_pdu resp;
351122394Sharti	struct asn_buf resp_b, pdu_b;
352122394Sharti	enum snmp_ret ret;
353122394Sharti
354122394Sharti	resp_b.asn_ptr = sndbuf;
355122394Sharti	resp_b.asn_len = snmpd.txbuf;
356122394Sharti
357122394Sharti	pdu_b.asn_cptr = rcvbuf;
358122394Sharti	pdu_b.asn_len = rcvlen;
359122394Sharti
360122394Sharti	if (ierr != SNMPD_INPUT_OK) {
361122394Sharti		/* error decoding the input of a SET */
362122394Sharti		if (pdu->version == SNMP_V1)
363122394Sharti			pdu->error_status = SNMP_ERR_BADVALUE;
364122394Sharti		else if (ierr == SNMPD_INPUT_VALBADLEN)
365122394Sharti			pdu->error_status = SNMP_ERR_WRONG_LENGTH;
366122394Sharti		else if (ierr == SNMPD_INPUT_VALRANGE)
367122394Sharti			pdu->error_status = SNMP_ERR_WRONG_VALUE;
368122394Sharti		else
369122394Sharti			pdu->error_status = SNMP_ERR_WRONG_ENCODING;
370122394Sharti
371122394Sharti		pdu->error_index = ivar;
372122394Sharti
373122394Sharti		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
374122394Sharti			syslog(LOG_WARNING, "could not encode error response");
375122394Sharti			snmpd_stats.silentDrops++;
376122394Sharti			return (SNMPD_INPUT_FAILED);
377122394Sharti		}
378122394Sharti
379122394Sharti		if (debug.dump_pdus) {
380122394Sharti			snmp_printf("%s <- ", source);
381122394Sharti			snmp_pdu_dump(pdu);
382122394Sharti		}
383122394Sharti		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
384122394Sharti		return (SNMPD_INPUT_OK);
385122394Sharti	}
386122394Sharti
387122394Sharti	switch (pdu->type) {
388122394Sharti
389122394Sharti	  case SNMP_PDU_GET:
390122394Sharti		ret = snmp_get(pdu, &resp_b, &resp, data);
391122394Sharti		break;
392122394Sharti
393122394Sharti	  case SNMP_PDU_GETNEXT:
394122394Sharti		ret = snmp_getnext(pdu, &resp_b, &resp, data);
395122394Sharti		break;
396122394Sharti
397122394Sharti	  case SNMP_PDU_SET:
398122394Sharti		ret = snmp_set(pdu, &resp_b, &resp, data);
399122394Sharti		break;
400122394Sharti
401122394Sharti	  case SNMP_PDU_GETBULK:
402122394Sharti		ret = snmp_getbulk(pdu, &resp_b, &resp, data);
403122394Sharti		break;
404122394Sharti
405122394Sharti	  default:
406122394Sharti		ret = SNMP_RET_IGN;
407122394Sharti		break;
408122394Sharti	}
409122394Sharti
410122394Sharti	switch (ret) {
411122394Sharti
412122394Sharti	  case SNMP_RET_OK:
413122394Sharti		/* normal return - send a response */
414122394Sharti		if (debug.dump_pdus) {
415122394Sharti			snmp_printf("%s <- ", source);
416122394Sharti			snmp_pdu_dump(&resp);
417122394Sharti		}
418122394Sharti		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
419122394Sharti		snmp_pdu_free(&resp);
420122394Sharti		return (SNMPD_INPUT_OK);
421122394Sharti
422122394Sharti	  case SNMP_RET_IGN:
423122394Sharti		/* error - send nothing */
424122394Sharti		snmpd_stats.silentDrops++;
425122394Sharti		return (SNMPD_INPUT_FAILED);
426122394Sharti
427122394Sharti	  case SNMP_RET_ERR:
428122394Sharti		/* error - send error response. The snmp routine has
429122394Sharti		 * changed the error fields in the original message. */
430122394Sharti		resp_b.asn_ptr = sndbuf;
431122394Sharti		resp_b.asn_len = snmpd.txbuf;
432122394Sharti		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
433122394Sharti			syslog(LOG_WARNING, "could not encode error response");
434122394Sharti			snmpd_stats.silentDrops++;
435122394Sharti			return (SNMPD_INPUT_FAILED);
436122394Sharti		} else {
437122394Sharti			if (debug.dump_pdus) {
438122394Sharti				snmp_printf("%s <- ", source);
439122394Sharti				snmp_pdu_dump(pdu);
440122394Sharti			}
441122394Sharti			*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
442122394Sharti			return (SNMPD_INPUT_OK);
443122394Sharti		}
444122394Sharti	}
445122394Sharti	abort();
446122394Sharti}
447122394Sharti
448124861Sharti/*
449124861Sharti * Insert a port into the right place in the transport's table of ports
450124861Sharti */
451124861Shartivoid
452124861Shartitrans_insert_port(struct transport *t, struct tport *port)
453124861Sharti{
454124861Sharti	struct tport *p;
455122394Sharti
456124861Sharti	TAILQ_FOREACH(p, &t->table, link) {
457124861Sharti		if (asn_compare_oid(&p->index, &port->index) > 0) {
458124861Sharti			TAILQ_INSERT_BEFORE(p, port, link);
459124861Sharti			return;
460124861Sharti		}
461124861Sharti	}
462124861Sharti	port->transport = t;
463124861Sharti	TAILQ_INSERT_TAIL(&t->table, port, link);
464124861Sharti}
465122394Sharti
466122394Sharti/*
467124861Sharti * Remove a port from a transport's list
468124861Sharti */
469124861Shartivoid
470124861Shartitrans_remove_port(struct tport *port)
471124861Sharti{
472124861Sharti
473124861Sharti	TAILQ_REMOVE(&port->transport->table, port, link);
474124861Sharti}
475124861Sharti
476124861Sharti/*
477124861Sharti * Find a port on a transport's list
478124861Sharti */
479124861Shartistruct tport *
480124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub)
481124861Sharti{
482124861Sharti
483124861Sharti	return (FIND_OBJECT_OID(&t->table, idx, sub));
484124861Sharti}
485124861Sharti
486124861Sharti/*
487124861Sharti * Find next port on a transport's list
488124861Sharti */
489124861Shartistruct tport *
490124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub)
491124861Sharti{
492124861Sharti
493124861Sharti	return (NEXT_OBJECT_OID(&t->table, idx, sub));
494124861Sharti}
495124861Sharti
496124861Sharti/*
497124861Sharti * Return first port
498124861Sharti */
499124861Shartistruct tport *
500124861Shartitrans_first_port(struct transport *t)
501124861Sharti{
502124861Sharti
503124861Sharti	return (TAILQ_FIRST(&t->table));
504124861Sharti}
505124861Sharti
506124861Sharti/*
507124861Sharti * Iterate through all ports until a function returns a 0.
508124861Sharti */
509124861Shartistruct tport *
510124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t),
511124861Sharti    intptr_t arg)
512124861Sharti{
513124861Sharti	struct tport *p;
514124861Sharti
515124861Sharti	TAILQ_FOREACH(p, &t->table, link)
516124861Sharti		if (func(p, arg) == 0)
517124861Sharti			return (p);
518124861Sharti	return (NULL);
519124861Sharti}
520124861Sharti
521124861Sharti/*
522124861Sharti * Register a transport
523124861Sharti */
524124861Shartiint
525124861Shartitrans_register(const struct transport_def *def, struct transport **pp)
526124861Sharti{
527124861Sharti	u_int i;
528124861Sharti	char or_descr[256];
529124861Sharti
530124861Sharti	if ((*pp = malloc(sizeof(**pp))) == NULL)
531124861Sharti		return (SNMP_ERR_GENERR);
532124861Sharti
533124861Sharti	/* construct index */
534124861Sharti	(*pp)->index.len = strlen(def->name) + 1;
535124861Sharti	(*pp)->index.subs[0] = strlen(def->name);
536124861Sharti	for (i = 0; i < (*pp)->index.subs[0]; i++)
537124861Sharti		(*pp)->index.subs[i + 1] = def->name[i];
538124861Sharti
539124861Sharti	(*pp)->vtab = def;
540124861Sharti
541124861Sharti	if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) {
542124861Sharti		free(*pp);
543124861Sharti		return (SNMP_ERR_INCONS_VALUE);
544124861Sharti	}
545124861Sharti
546124861Sharti	/* register module */
547124861Sharti	snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name);
548124861Sharti	if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) {
549124861Sharti		free(*pp);
550124861Sharti		return (SNMP_ERR_GENERR);
551124861Sharti	}
552124861Sharti
553124861Sharti	INSERT_OBJECT_OID((*pp), &transport_list);
554124861Sharti
555124861Sharti	TAILQ_INIT(&(*pp)->table);
556124861Sharti
557124861Sharti	return (SNMP_ERR_NOERROR);
558124861Sharti}
559124861Sharti
560124861Sharti/*
561124861Sharti * Unregister transport
562124861Sharti */
563124861Shartiint
564124861Shartitrans_unregister(struct transport *t)
565124861Sharti{
566124861Sharti	if (!TAILQ_EMPTY(&t->table))
567124861Sharti		return (SNMP_ERR_INCONS_VALUE);
568124861Sharti
569124861Sharti	or_unregister(t->or_index);
570124861Sharti	TAILQ_REMOVE(&transport_list, t, link);
571124861Sharti
572124861Sharti	return (SNMP_ERR_NOERROR);
573124861Sharti}
574124861Sharti
575124861Sharti/*
576122394Sharti * File descriptor support
577122394Sharti */
578124861Sharti#ifdef USE_LIBBEGEMOT
579122394Shartistatic void
580124861Shartiinput(int fd, int mask __unused, void *uap)
581124861Sharti#else
582124861Shartistatic void
583122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused)
584124861Sharti#endif
585122394Sharti{
586122394Sharti	struct fdesc *f = uap;
587122394Sharti
588122394Sharti	(*f->func)(fd, f->udata);
589122394Sharti}
590122394Sharti
591122394Shartivoid
592122394Shartifd_suspend(void *p)
593122394Sharti{
594122394Sharti	struct fdesc *f = p;
595122394Sharti
596124861Sharti#ifdef USE_LIBBEGEMOT
597124861Sharti	if (f->id >= 0) {
598124861Sharti		poll_unregister(f->id);
599124861Sharti		f->id = -1;
600124861Sharti	}
601124861Sharti#else
602122394Sharti	if (evTestID(f->id)) {
603122394Sharti		(void)evDeselectFD(evctx, f->id);
604122394Sharti		evInitID(&f->id);
605122394Sharti	}
606124861Sharti#endif
607122394Sharti}
608122394Sharti
609122394Shartiint
610122394Shartifd_resume(void *p)
611122394Sharti{
612122394Sharti	struct fdesc *f = p;
613122394Sharti	int err;
614122394Sharti
615124861Sharti#ifdef USE_LIBBEGEMOT
616124861Sharti	if (f->id >= 0)
617124861Sharti		return (0);
618124861Sharti	if ((f->fd = poll_register(f->fd, input, f, POLL_IN)) < 0) {
619124861Sharti		err = errno;
620124861Sharti		syslog(LOG_ERR, "select fd %d: %m", f->fd);
621124861Sharti		errno = err;
622124861Sharti		return (-1);
623124861Sharti	}
624124861Sharti#else
625122394Sharti	if (evTestID(f->id))
626122394Sharti		return (0);
627122394Sharti	if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) {
628122394Sharti		err = errno;
629122394Sharti		syslog(LOG_ERR, "select fd %d: %m", f->fd);
630122394Sharti		errno = err;
631122394Sharti		return (-1);
632122394Sharti	}
633124861Sharti#endif
634122394Sharti	return (0);
635122394Sharti}
636122394Sharti
637122394Shartivoid *
638122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod)
639122394Sharti{
640122394Sharti	struct fdesc *f;
641122394Sharti	int err;
642122394Sharti
643122394Sharti	if ((f = malloc(sizeof(struct fdesc))) == NULL) {
644122394Sharti		err = errno;
645122394Sharti		syslog(LOG_ERR, "fd_select: %m");
646122394Sharti		errno = err;
647122394Sharti		return (NULL);
648122394Sharti	}
649122394Sharti	f->fd = fd;
650122394Sharti	f->func = func;
651122394Sharti	f->udata = udata;
652122394Sharti	f->owner = mod;
653124861Sharti#ifdef USE_LIBBEGEMOT
654124861Sharti	f->id = -1;
655124861Sharti#else
656122394Sharti	evInitID(&f->id);
657124861Sharti#endif
658122394Sharti
659122394Sharti	if (fd_resume(f)) {
660122394Sharti		err = errno;
661122394Sharti		free(f);
662122394Sharti		errno = err;
663122394Sharti		return (NULL);
664122394Sharti	}
665122394Sharti
666122394Sharti	LIST_INSERT_HEAD(&fdesc_list, f, link);
667122394Sharti
668122394Sharti	return (f);
669122394Sharti}
670122394Sharti
671122394Shartivoid
672122394Shartifd_deselect(void *p)
673122394Sharti{
674122394Sharti	struct fdesc *f = p;
675122394Sharti
676122394Sharti	LIST_REMOVE(f, link);
677122394Sharti	fd_suspend(f);
678122394Sharti	free(f);
679122394Sharti}
680122394Sharti
681122394Shartistatic void
682122394Shartifd_flush(struct lmodule *mod)
683122394Sharti{
684122394Sharti	struct fdesc *t, *t1;
685122394Sharti
686122394Sharti	t = LIST_FIRST(&fdesc_list);
687122394Sharti	while (t != NULL) {
688122394Sharti		t1 = LIST_NEXT(t, link);
689122394Sharti		if (t->owner == mod)
690122394Sharti			fd_deselect(t);
691122394Sharti		t = t1;
692122394Sharti	}
693122394Sharti}
694122394Sharti
695122394Sharti/*
696124861Sharti * Consume a message from the input buffer
697122394Sharti */
698122394Shartistatic void
699124861Shartisnmp_input_consume(struct port_input *pi)
700122394Sharti{
701124861Sharti	if (!pi->stream) {
702124861Sharti		/* always consume everything */
703124861Sharti		pi->length = 0;
704122394Sharti		return;
705122394Sharti	}
706124861Sharti	if (pi->consumed >= pi->length) {
707124861Sharti		/* all bytes consumed */
708124861Sharti		pi->length = 0;
709122394Sharti		return;
710122394Sharti	}
711124861Sharti	memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed);
712124861Sharti	pi->length -= pi->consumed;
713124861Sharti}
714124861Sharti
715124861Shartistruct credmsg {
716124861Sharti	struct cmsghdr hdr;
717124861Sharti	struct cmsgcred cred;
718124861Sharti};
719124861Sharti
720124861Shartistatic void
721124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg)
722124861Sharti{
723124861Sharti	struct credmsg *cmsg;
724124861Sharti	struct xucred ucred;
725124861Sharti	socklen_t ucredlen;
726124861Sharti
727124861Sharti	pi->priv = 0;
728124861Sharti
729124861Sharti	if (msg->msg_controllen == sizeof(*cmsg)) {
730124861Sharti		/* process explicitely sends credentials */
731124861Sharti
732124861Sharti		cmsg = (struct credmsg *)msg->msg_control;
733124861Sharti		pi->priv = (cmsg->cred.cmcred_euid == 0);
734122394Sharti		return;
735122394Sharti	}
736124861Sharti
737124861Sharti	/* ok, obtain the accept time credentials */
738124861Sharti	ucredlen = sizeof(ucred);
739124861Sharti
740124861Sharti	if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 &&
741124861Sharti	    ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION)
742124861Sharti		pi->priv = (ucred.cr_uid == 0);
743124861Sharti}
744124861Sharti
745124861Sharti/*
746124861Sharti * Input from a stream socket.
747124861Sharti */
748124861Shartistatic int
749124861Shartirecv_stream(struct port_input *pi)
750124861Sharti{
751124861Sharti	struct msghdr msg;
752124861Sharti	struct iovec iov[1];
753124861Sharti	ssize_t len;
754124861Sharti	struct credmsg cmsg;
755124861Sharti
756124861Sharti	if (pi->buf == NULL) {
757124861Sharti		/* no buffer yet - allocate one */
758124861Sharti		if ((pi->buf = buf_alloc(0)) == NULL) {
759124861Sharti			/* ups - could not get buffer. Return an error
760124861Sharti			 * the caller must close the transport. */
761124861Sharti			return (-1);
762124861Sharti		}
763124861Sharti		pi->buflen = buf_size(0);
764124861Sharti		pi->consumed = 0;
765124861Sharti		pi->length = 0;
766124861Sharti	}
767124861Sharti
768124861Sharti	/* try to get a message */
769124861Sharti	msg.msg_name = pi->peer;
770124861Sharti	msg.msg_namelen = pi->peerlen;
771124861Sharti	msg.msg_iov = iov;
772124861Sharti	msg.msg_iovlen = 1;
773124861Sharti	if (pi->cred) {
774124861Sharti		msg.msg_control = &cmsg;
775124861Sharti		msg.msg_controllen = sizeof(cmsg);
776124861Sharti
777124861Sharti		cmsg.hdr.cmsg_len = sizeof(cmsg);
778124861Sharti		cmsg.hdr.cmsg_level = SOL_SOCKET;
779124861Sharti		cmsg.hdr.cmsg_type = SCM_CREDS;
780124861Sharti	} else {
781124861Sharti		msg.msg_control = NULL;
782124861Sharti		msg.msg_controllen = 0;
783124861Sharti	}
784124861Sharti	msg.msg_flags = 0;
785124861Sharti
786124861Sharti	iov[0].iov_base = pi->buf + pi->length;
787124861Sharti	iov[0].iov_len = pi->buflen - pi->length;
788124861Sharti
789124861Sharti	len = recvmsg(pi->fd, &msg, 0);
790124861Sharti
791124861Sharti	if (len == -1 || len == 0)
792124861Sharti		/* receive error */
793124861Sharti		return (-1);
794124861Sharti
795124861Sharti	pi->length += len;
796124861Sharti
797124861Sharti	if (pi->cred)
798124861Sharti		check_priv(pi, &msg);
799124861Sharti
800124861Sharti	return (0);
801124861Sharti}
802124861Sharti
803124861Sharti/*
804124861Sharti * Input from a datagram socket.
805124861Sharti * Each receive should return one datagram.
806124861Sharti */
807124861Shartistatic int
808124861Shartirecv_dgram(struct port_input *pi)
809124861Sharti{
810124861Sharti	u_char embuf[1000];
811124861Sharti	struct msghdr msg;
812124861Sharti	struct iovec iov[1];
813124861Sharti	ssize_t len;
814124861Sharti	struct credmsg cmsg;
815124861Sharti
816124861Sharti	if (pi->buf == NULL) {
817124861Sharti		/* no buffer yet - allocate one */
818124861Sharti		if ((pi->buf = buf_alloc(0)) == NULL) {
819124861Sharti			/* ups - could not get buffer. Read away input
820124861Sharti			 * and drop it */
821124861Sharti			(void)recvfrom(pi->fd, embuf, sizeof(embuf),
822124861Sharti			    0, NULL, NULL);
823124861Sharti			/* return error */
824124861Sharti			return (-1);
825124861Sharti		}
826124861Sharti		pi->buflen = buf_size(0);
827124861Sharti	}
828124861Sharti
829124861Sharti	/* try to get a message */
830124861Sharti	msg.msg_name = pi->peer;
831124861Sharti	msg.msg_namelen = pi->peerlen;
832124861Sharti	msg.msg_iov = iov;
833124861Sharti	msg.msg_iovlen = 1;
834124861Sharti	if (pi->cred) {
835124861Sharti		msg.msg_control = &cmsg;
836124861Sharti		msg.msg_controllen = sizeof(cmsg);
837124861Sharti
838124861Sharti		cmsg.hdr.cmsg_len = sizeof(cmsg);
839124861Sharti		cmsg.hdr.cmsg_level = SOL_SOCKET;
840124861Sharti		cmsg.hdr.cmsg_type = SCM_CREDS;
841124861Sharti	} else {
842124861Sharti		msg.msg_control = NULL;
843128237Sharti		msg.msg_controllen = 0;
844124861Sharti	}
845124861Sharti	msg.msg_flags = 0;
846124861Sharti
847124861Sharti	iov[0].iov_base = pi->buf;
848124861Sharti	iov[0].iov_len = pi->buflen;
849124861Sharti
850124861Sharti	len = recvmsg(pi->fd, &msg, 0);
851124861Sharti
852124861Sharti	if (len == -1 || len == 0)
853124861Sharti		/* receive error */
854124861Sharti		return (-1);
855124861Sharti
856124861Sharti	if (msg.msg_flags & MSG_TRUNC) {
857124861Sharti		/* truncated - drop */
858122394Sharti		snmpd_stats.silentDrops++;
859122394Sharti		snmpd_stats.inTooLong++;
860124861Sharti		return (-1);
861122394Sharti	}
862122394Sharti
863124861Sharti	pi->length = (size_t)len;
864124861Sharti
865124861Sharti	if (pi->cred)
866124861Sharti		check_priv(pi, &msg);
867124861Sharti
868124861Sharti	return (0);
869124861Sharti}
870124861Sharti
871124861Sharti/*
872124861Sharti * Input from a socket
873124861Sharti */
874124861Shartiint
875124861Shartisnmpd_input(struct port_input *pi, struct tport *tport)
876124861Sharti{
877124861Sharti	u_char *sndbuf;
878124861Sharti	size_t sndlen;
879124861Sharti	struct snmp_pdu pdu;
880124861Sharti	enum snmpd_input_err ierr, ferr;
881124861Sharti	enum snmpd_proxy_err perr;
882124861Sharti	int32_t vi;
883124861Sharti	int ret;
884124861Sharti	ssize_t slen;
885124861Sharti
886124861Sharti	/* get input depending on the transport */
887124861Sharti	if (pi->stream) {
888124861Sharti		ret = recv_stream(pi);
889124861Sharti	} else {
890124861Sharti		ret = recv_dgram(pi);
891124861Sharti	}
892124861Sharti
893124861Sharti	if (ret == -1)
894124861Sharti		return (-1);
895124861Sharti
896122394Sharti	/*
897122394Sharti	 * Handle input
898122394Sharti	 */
899124861Sharti	ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi,
900124861Sharti	    &pi->consumed);
901124861Sharti	if (ierr == SNMPD_INPUT_TRUNC) {
902124861Sharti		/* need more bytes. This is ok only for streaming transports.
903124861Sharti		 * but only if we have not reached bufsiz yet. */
904124861Sharti		if (pi->stream) {
905124861Sharti			if (pi->length == buf_size(0)) {
906124861Sharti				snmpd_stats.silentDrops++;
907124861Sharti				return (-1);
908124861Sharti			}
909124861Sharti			return (0);
910124861Sharti		}
911124861Sharti		snmpd_stats.silentDrops++;
912124861Sharti		return (-1);
913124861Sharti	}
914122394Sharti
915122394Sharti	/* can't check for bad SET pdus here, because a proxy may have to
916122394Sharti	 * check the access first. We don't want to return an error response
917122394Sharti	 * to a proxy PDU with a wrong community */
918122394Sharti	if (ierr == SNMPD_INPUT_FAILED) {
919124861Sharti		/* for streaming transports this is fatal */
920124861Sharti		if (pi->stream)
921124861Sharti			return (-1);
922124861Sharti		snmp_input_consume(pi);
923124861Sharti		return (0);
924122394Sharti	}
925122394Sharti
926122394Sharti	/*
927122394Sharti	 * If that is a module community and the module has a proxy function,
928122394Sharti	 * the hand it over to the module.
929122394Sharti	 */
930122394Sharti	if (comm->owner != NULL && comm->owner->config->proxy != NULL) {
931124861Sharti		perr = (*comm->owner->config->proxy)(&pdu, tport->transport,
932124861Sharti		    &tport->index, pi->peer, pi->peerlen, ierr, vi, pi->priv);
933122394Sharti
934122394Sharti		switch (perr) {
935122394Sharti
936122394Sharti		  case SNMPD_PROXY_OK:
937124861Sharti			snmp_input_consume(pi);
938124861Sharti			return (0);
939122394Sharti
940122394Sharti		  case SNMPD_PROXY_REJ:
941122394Sharti			break;
942122394Sharti
943122394Sharti		  case SNMPD_PROXY_DROP:
944124861Sharti			snmp_input_consume(pi);
945122394Sharti			snmp_pdu_free(&pdu);
946122394Sharti			snmpd_stats.proxyDrops++;
947124861Sharti			return (0);
948122394Sharti
949122394Sharti		  case SNMPD_PROXY_BADCOMM:
950124861Sharti			snmp_input_consume(pi);
951122394Sharti			snmp_pdu_free(&pdu);
952122394Sharti			snmpd_stats.inBadCommunityNames++;
953122394Sharti			if (snmpd.auth_traps)
954122394Sharti				snmp_send_trap(&oid_authenticationFailure,
955122394Sharti				    NULL);
956124861Sharti			return (0);
957122394Sharti
958122394Sharti		  case SNMPD_PROXY_BADCOMMUSE:
959124861Sharti			snmp_input_consume(pi);
960122394Sharti			snmp_pdu_free(&pdu);
961122394Sharti			snmpd_stats.inBadCommunityUses++;
962122394Sharti			if (snmpd.auth_traps)
963122394Sharti				snmp_send_trap(&oid_authenticationFailure,
964122394Sharti				    NULL);
965124861Sharti			return (0);
966122394Sharti		}
967122394Sharti	}
968122394Sharti
969122394Sharti	/*
970122394Sharti	 * Check type
971122394Sharti	 */
972122394Sharti	if (pdu.type == SNMP_PDU_RESPONSE ||
973122394Sharti	    pdu.type == SNMP_PDU_TRAP ||
974122394Sharti	    pdu.type == SNMP_PDU_TRAP2) {
975122394Sharti		snmpd_stats.silentDrops++;
976122394Sharti		snmpd_stats.inBadPduTypes++;
977122394Sharti		snmp_pdu_free(&pdu);
978124861Sharti		snmp_input_consume(pi);
979124861Sharti		return (0);
980122394Sharti	}
981122394Sharti
982122394Sharti	/*
983122394Sharti	 * Check community
984122394Sharti	 */
985124861Sharti	if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) ||
986124861Sharti	    (community != COMM_WRITE &&
987124861Sharti            (pdu.type == SNMP_PDU_SET || community != COMM_READ))) {
988122394Sharti		snmpd_stats.inBadCommunityUses++;
989122394Sharti		snmp_pdu_free(&pdu);
990124861Sharti		snmp_input_consume(pi);
991122394Sharti		if (snmpd.auth_traps)
992122394Sharti			snmp_send_trap(&oid_authenticationFailure, NULL);
993124861Sharti		return (0);
994122394Sharti	}
995122394Sharti
996122394Sharti	/*
997122394Sharti	 * Execute it.
998122394Sharti	 */
999122394Sharti	if ((sndbuf = buf_alloc(1)) == NULL) {
1000122394Sharti		snmpd_stats.silentDrops++;
1001122394Sharti		snmp_pdu_free(&pdu);
1002124861Sharti		snmp_input_consume(pi);
1003124861Sharti		return (0);
1004122394Sharti	}
1005124861Sharti	ferr = snmp_input_finish(&pdu, pi->buf, pi->length,
1006124861Sharti	    sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
1007122394Sharti
1008122394Sharti	if (ferr == SNMPD_INPUT_OK) {
1009124861Sharti		slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen);
1010124861Sharti		if (slen == -1)
1011122394Sharti			syslog(LOG_ERR, "sendto: %m");
1012124861Sharti		else if ((size_t)slen != sndlen)
1013122394Sharti			syslog(LOG_ERR, "sendto: short write %zu/%zu",
1014124861Sharti			    sndlen, (size_t)slen);
1015122394Sharti	}
1016122394Sharti	snmp_pdu_free(&pdu);
1017122394Sharti	free(sndbuf);
1018124861Sharti	snmp_input_consume(pi);
1019122394Sharti
1020124861Sharti	return (0);
1021122394Sharti}
1022122394Sharti
1023122394Sharti/*
1024124861Sharti * Send a PDU to a given port
1025122394Sharti */
1026124861Shartivoid
1027124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
1028124861Sharti    const struct sockaddr *addr, socklen_t addrlen)
1029122394Sharti{
1030124861Sharti	struct transport *trans = targ;
1031124861Sharti	struct tport *tp;
1032124861Sharti	u_char *sndbuf;
1033124861Sharti	size_t sndlen;
1034124861Sharti	ssize_t len;
1035122394Sharti
1036124861Sharti	TAILQ_FOREACH(tp, &trans->table, link)
1037124861Sharti		if (asn_compare_oid(port, &tp->index) == 0)
1038122394Sharti			break;
1039124861Sharti	if (tp == 0)
1040124861Sharti		return;
1041122394Sharti
1042124861Sharti	if ((sndbuf = buf_alloc(1)) == NULL)
1043124861Sharti		return;
1044122394Sharti
1045124861Sharti	snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
1046122394Sharti
1047124861Sharti	len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
1048122394Sharti
1049124861Sharti	if (len == -1)
1050124861Sharti		syslog(LOG_ERR, "sendto: %m");
1051124861Sharti	else if ((size_t)len != sndlen)
1052124861Sharti		syslog(LOG_ERR, "sendto: short write %zu/%zu",
1053124861Sharti		    sndlen, (size_t)len);
1054122394Sharti
1055124861Sharti	free(sndbuf);
1056122394Sharti}
1057122394Sharti
1058122394Sharti
1059122394Sharti/*
1060124861Sharti * Close an input source
1061122394Sharti */
1062122394Shartivoid
1063124861Shartisnmpd_input_close(struct port_input *pi)
1064122394Sharti{
1065124861Sharti	if (pi->id != NULL)
1066124861Sharti		fd_deselect(pi->id);
1067124861Sharti	if (pi->fd >= 0)
1068124861Sharti		(void)close(pi->fd);
1069124861Sharti	if (pi->buf != NULL)
1070124861Sharti		free(pi->buf);
1071122394Sharti}
1072122394Sharti
1073122394Sharti/*
1074122394Sharti * Dump internal state.
1075122394Sharti */
1076124861Sharti#ifdef USE_LIBBEGEMOT
1077122394Shartistatic void
1078124861Shartiinfo_func(void)
1079124861Sharti#else
1080124861Shartistatic void
1081122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused)
1082124861Sharti#endif
1083122394Sharti{
1084122394Sharti	struct lmodule *m;
1085122394Sharti	u_int i;
1086122394Sharti	char buf[10000];
1087122394Sharti
1088122394Sharti	syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());
1089122394Sharti	for (i = 0; i < tree_size; i++) {
1090122394Sharti		switch (tree[i].type) {
1091122394Sharti
1092122394Sharti		  case SNMP_NODE_LEAF:
1093122394Sharti			sprintf(buf, "LEAF: %s %s", tree[i].name,
1094122394Sharti			    asn_oid2str(&tree[i].oid));
1095122394Sharti			break;
1096122394Sharti
1097122394Sharti		  case SNMP_NODE_COLUMN:
1098122394Sharti			sprintf(buf, "COL: %s %s", tree[i].name,
1099122394Sharti			    asn_oid2str(&tree[i].oid));
1100122394Sharti			break;
1101122394Sharti		}
1102122394Sharti		syslog(LOG_DEBUG, "%s", buf);
1103122394Sharti	}
1104122394Sharti
1105122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
1106122394Sharti		if (m->config->dump)
1107122394Sharti			(*m->config->dump)();
1108122394Sharti}
1109122394Sharti
1110122394Sharti/*
1111122394Sharti * Re-read configuration
1112122394Sharti */
1113124861Sharti#ifdef USE_LIBBEGEMOT
1114122394Shartistatic void
1115124861Sharticonfig_func(void)
1116124861Sharti#else
1117124861Shartistatic void
1118122394Sharticonfig_func(evContext ctx __unused, void *uap __unused,
1119122394Sharti    const void *tag __unused)
1120124861Sharti#endif
1121122394Sharti{
1122122394Sharti	struct lmodule *m;
1123122394Sharti
1124122394Sharti	if (read_config(config_file, NULL)) {
1125122394Sharti		syslog(LOG_ERR, "error reading config file '%s'", config_file);
1126122394Sharti		return;
1127122394Sharti	}
1128122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
1129122394Sharti		if (m->config->config)
1130122394Sharti			(*m->config->config)();
1131122394Sharti}
1132122394Sharti
1133122394Sharti/*
1134122394Sharti * On USR1 dump actual configuration.
1135122394Sharti */
1136122394Shartistatic void
1137122394Shartionusr1(int s __unused)
1138122394Sharti{
1139124861Sharti
1140122394Sharti	work |= WORK_DOINFO;
1141122394Sharti}
1142122394Shartistatic void
1143122394Shartionhup(int s __unused)
1144122394Sharti{
1145124861Sharti
1146122394Sharti	work |= WORK_RECONFIG;
1147122394Sharti}
1148122394Sharti
1149122394Shartistatic void
1150122394Shartionterm(int s __unused)
1151122394Sharti{
1152122394Sharti
1153124861Sharti	/* allow clean-up */
1154122394Sharti	exit(0);
1155122394Sharti}
1156122394Sharti
1157122394Shartistatic void
1158122394Shartiinit_sigs(void)
1159122394Sharti{
1160122394Sharti	struct sigaction sa;
1161122394Sharti
1162122394Sharti	sa.sa_handler = onusr1;
1163122394Sharti	sa.sa_flags = SA_RESTART;
1164122394Sharti	sigemptyset(&sa.sa_mask);
1165122394Sharti	if (sigaction(SIGUSR1, &sa, NULL)) {
1166122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1167122394Sharti		exit(1);
1168122394Sharti	}
1169122394Sharti
1170122394Sharti	sa.sa_handler = onhup;
1171122394Sharti	if (sigaction(SIGHUP, &sa, NULL)) {
1172122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1173122394Sharti		exit(1);
1174122394Sharti	}
1175122394Sharti
1176122394Sharti	sa.sa_handler = onterm;
1177122394Sharti	sa.sa_flags = 0;
1178122394Sharti	sigemptyset(&sa.sa_mask);
1179122394Sharti	if (sigaction(SIGTERM, &sa, NULL)) {
1180122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1181122394Sharti		exit(1);
1182122394Sharti	}
1183122394Sharti	if (sigaction(SIGINT, &sa, NULL)) {
1184122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1185122394Sharti		exit(1);
1186122394Sharti	}
1187122394Sharti}
1188122394Sharti
1189122394Shartistatic void
1190122394Shartiblock_sigs(void)
1191122394Sharti{
1192122394Sharti	sigset_t set;
1193122394Sharti
1194122394Sharti	sigfillset(&set);
1195122394Sharti	if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) {
1196122394Sharti		syslog(LOG_ERR, "SIG_BLOCK: %m");
1197122394Sharti		exit(1);
1198122394Sharti	}
1199122394Sharti}
1200122394Shartistatic void
1201122394Shartiunblock_sigs(void)
1202122394Sharti{
1203122394Sharti	if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) {
1204122394Sharti		syslog(LOG_ERR, "SIG_SETMASK: %m");
1205122394Sharti		exit(1);
1206122394Sharti	}
1207122394Sharti}
1208122394Sharti
1209122394Sharti/*
1210122394Sharti * Shut down
1211122394Sharti */
1212122394Shartistatic void
1213122394Shartiterm(void)
1214122394Sharti{
1215122394Sharti	(void)unlink(pid_file);
1216122394Sharti}
1217122394Sharti
1218124861Shartistatic void
1219124861Shartitrans_stop(void)
1220124861Sharti{
1221124861Sharti	struct transport *t;
1222124861Sharti
1223124861Sharti	TAILQ_FOREACH(t, &transport_list, link)
1224124861Sharti		(void)t->vtab->stop(1);
1225124861Sharti}
1226124861Sharti
1227122394Sharti/*
1228122394Sharti * Define a macro from the command line
1229122394Sharti */
1230122394Shartistatic void
1231122394Shartido_macro(char *arg)
1232122394Sharti{
1233122394Sharti	char *eq;
1234122394Sharti	int err;
1235122394Sharti
1236122394Sharti	if ((eq = strchr(arg, '=')) == NULL)
1237122394Sharti		err = define_macro(arg, "");
1238122394Sharti	else {
1239122394Sharti		*eq++ = '\0';
1240122394Sharti		err = define_macro(arg, eq);
1241122394Sharti	}
1242122394Sharti	if (err == -1) {
1243122394Sharti		syslog(LOG_ERR, "cannot save macro: %m");
1244122394Sharti		exit(1);
1245122394Sharti	}
1246122394Sharti}
1247122394Sharti
1248122394Sharti/*
1249122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken
1250122394Sharti * and will not compile with WARNS=5.
1251122394Sharti */
1252122394Shartistatic int
1253122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp)
1254122394Sharti{
1255122394Sharti	static const char *const delim = ",\t ";
1256122394Sharti	u_int i;
1257122394Sharti	char *ptr;
1258122394Sharti
1259122394Sharti	*optp = NULL;
1260122394Sharti
1261122394Sharti	/* skip leading junk */
1262122394Sharti	for (ptr = *arg; *ptr != '\0'; ptr++)
1263122394Sharti		if (strchr(delim, *ptr) == NULL)
1264122394Sharti			break;
1265122394Sharti	if (*ptr == '\0') {
1266122394Sharti		*arg = ptr;
1267122394Sharti		return (-1);
1268122394Sharti	}
1269122394Sharti	*optp = ptr;
1270122394Sharti
1271122394Sharti	/* find the end of the option */
1272122394Sharti	while (*++ptr != '\0')
1273122394Sharti		if (strchr(delim, *ptr) != NULL || *ptr == '=')
1274122394Sharti			break;
1275122394Sharti
1276122394Sharti	if (*ptr != '\0') {
1277122394Sharti		if (*ptr == '=') {
1278122394Sharti			*ptr++ = '\0';
1279122394Sharti			*valp = ptr;
1280122394Sharti			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
1281122394Sharti				ptr++;
1282122394Sharti			if (*ptr != '\0')
1283122394Sharti				*ptr++ = '\0';
1284122394Sharti		} else
1285122394Sharti			*ptr++ = '\0';
1286122394Sharti	}
1287122394Sharti
1288122394Sharti	*arg = ptr;
1289122394Sharti
1290122394Sharti	for (i = 0; *options != NULL; options++, i++)
1291124861Sharti		if (strcmp(*optp, *options) == 0)
1292122394Sharti			return (i);
1293122394Sharti	return (-1);
1294122394Sharti}
1295122394Sharti
1296122394Shartiint
1297122394Shartimain(int argc, char *argv[])
1298122394Sharti{
1299122394Sharti	int opt;
1300122394Sharti	FILE *fp;
1301122394Sharti	int background = 1;
1302124861Sharti	struct tport *p;
1303122394Sharti	const char *prefix = "snmpd";
1304122394Sharti	struct lmodule *m;
1305122394Sharti	char *value, *option;
1306124861Sharti	struct transport *t;
1307122394Sharti
1308122394Sharti#define DBG_DUMP	0
1309122394Sharti#define DBG_EVENTS	1
1310122394Sharti#define DBG_TRACE	2
1311122394Sharti	static const char *const debug_opts[] = {
1312122394Sharti		"dump",
1313122394Sharti		"events",
1314122394Sharti		"trace",
1315122394Sharti		NULL
1316122394Sharti	};
1317122394Sharti
1318122394Sharti	snmp_printf = snmp_printf_func;
1319122394Sharti	snmp_error = snmp_error_func;
1320122394Sharti	snmp_debug = snmp_debug_func;
1321122394Sharti	asn_error = asn_error_func;
1322122394Sharti
1323122394Sharti	while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF)
1324122394Sharti		switch (opt) {
1325122394Sharti
1326122394Sharti		  case 'c':
1327122394Sharti			strlcpy(config_file, optarg, sizeof(config_file));
1328122394Sharti			break;
1329122394Sharti
1330122394Sharti		  case 'd':
1331122394Sharti			background = 0;
1332122394Sharti			break;
1333122394Sharti
1334122394Sharti		  case 'D':
1335122394Sharti			while (*optarg) {
1336122394Sharti				switch (getsubopt1(&optarg, debug_opts,
1337122394Sharti				    &value, &option)) {
1338122394Sharti
1339122394Sharti				  case DBG_DUMP:
1340122394Sharti					debug.dump_pdus = 1;
1341122394Sharti					break;
1342122394Sharti
1343122394Sharti				  case DBG_EVENTS:
1344122394Sharti					debug.evdebug++;
1345122394Sharti					break;
1346122394Sharti
1347122394Sharti				  case DBG_TRACE:
1348122394Sharti					if (value == NULL)
1349122394Sharti						syslog(LOG_ERR,
1350122394Sharti						    "no value for 'trace'");
1351122394Sharti					snmp_trace = strtoul(value, NULL, 0);
1352122394Sharti					break;
1353122394Sharti
1354122394Sharti				  case -1:
1355122394Sharti					if (suboptarg)
1356122394Sharti						syslog(LOG_ERR,
1357122394Sharti						    "unknown debug flag '%s'",
1358122394Sharti						    option);
1359122394Sharti					else
1360122394Sharti						syslog(LOG_ERR,
1361122394Sharti						    "missing debug flag");
1362122394Sharti					break;
1363122394Sharti				}
1364122394Sharti			}
1365122394Sharti			break;
1366122394Sharti
1367122394Sharti		  case 'h':
1368122394Sharti			fprintf(stderr, "%s", usgtxt);
1369122394Sharti			exit(0);
1370122394Sharti
1371122394Sharti		  case 'I':
1372122394Sharti			syspath = optarg;
1373122394Sharti			break;
1374122394Sharti
1375122394Sharti		  case 'l':
1376122394Sharti			prefix = optarg;
1377122394Sharti			break;
1378122394Sharti
1379122394Sharti		  case 'm':
1380122394Sharti			do_macro(optarg);
1381122394Sharti			break;
1382122394Sharti
1383122394Sharti		  case 'p':
1384122394Sharti			strlcpy(pid_file, optarg, sizeof(pid_file));
1385122394Sharti			break;
1386122394Sharti		}
1387122394Sharti
1388122394Sharti	openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
1389122394Sharti	setlogmask(LOG_UPTO(debug.logpri - 1));
1390122394Sharti
1391122394Sharti	if (background && daemon(0, 0) < 0) {
1392122394Sharti		syslog(LOG_ERR, "daemon: %m");
1393122394Sharti		exit(1);
1394122394Sharti	}
1395122394Sharti
1396122394Sharti	argc -= optind;
1397122394Sharti	argv += optind;
1398122394Sharti
1399122394Sharti	progargs = argv;
1400122394Sharti	nprogargs = argc;
1401122394Sharti
1402122394Sharti	srandomdev();
1403122394Sharti
1404122394Sharti	snmp_serial_no = random();
1405122394Sharti
1406122394Sharti	/*
1407122394Sharti	 * Initialize the tree.
1408122394Sharti	 */
1409122394Sharti	if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) {
1410122394Sharti		syslog(LOG_ERR, "%m");
1411122394Sharti		exit(1);
1412122394Sharti	}
1413122394Sharti	memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE);
1414122394Sharti	tree_size = CTREE_SIZE;
1415122394Sharti
1416122394Sharti	/*
1417122394Sharti	 * Get standard communities
1418122394Sharti	 */
1419122394Sharti	(void)comm_define(1, "SNMP read", NULL, "public");
1420122394Sharti	(void)comm_define(2, "SNMP write", NULL, "public");
1421122394Sharti	community = COMM_INITIALIZE;
1422122394Sharti
1423122394Sharti	trap_reqid = reqid_allocate(512, NULL);
1424122394Sharti
1425122394Sharti	if (config_file[0] == '\0')
1426122394Sharti		snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix);
1427122394Sharti
1428122394Sharti	init_actvals();
1429124861Sharti
1430124861Sharti	start_tick = get_ticks();
1431124861Sharti	this_tick = get_ticks();
1432124861Sharti
1433124861Sharti	/* start transports */
1434124861Sharti	if (atexit(trans_stop) == -1) {
1435124861Sharti		syslog(LOG_ERR, "atexit failed: %m");
1436124861Sharti		exit(1);
1437124861Sharti	}
1438124861Sharti	if (udp_trans.start() != SNMP_ERR_NOERROR)
1439124861Sharti		syslog(LOG_WARNING, "cannot start UDP transport");
1440124861Sharti	if (lsock_trans.start() != SNMP_ERR_NOERROR)
1441124861Sharti		syslog(LOG_WARNING, "cannot start LSOCK transport");
1442124861Sharti
1443122394Sharti	if (read_config(config_file, NULL)) {
1444122394Sharti		syslog(LOG_ERR, "error in config file");
1445122394Sharti		exit(1);
1446122394Sharti	}
1447122394Sharti
1448124861Sharti#ifdef USE_LIBBEGEMOT
1449124861Sharti	if (debug.evdebug > 0)
1450124861Sharti		rpoll_trace = 1;
1451124861Sharti#else
1452122394Sharti	if (evCreate(&evctx)) {
1453122394Sharti		syslog(LOG_ERR, "evCreate: %m");
1454122394Sharti		exit(1);
1455122394Sharti	}
1456122394Sharti	if (debug.evdebug > 0)
1457122394Sharti		evSetDebug(evctx, 10, stderr);
1458124861Sharti#endif
1459122394Sharti
1460124861Sharti	TAILQ_FOREACH(t, &transport_list, link)
1461124861Sharti		TAILQ_FOREACH(p, &t->table, link)
1462124861Sharti			t->vtab->init_port(p);
1463122394Sharti
1464122394Sharti	init_sigs();
1465122394Sharti
1466122394Sharti	if (pid_file[0] == '\0')
1467122394Sharti		snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix);
1468122394Sharti
1469122394Sharti	if ((fp = fopen(pid_file, "w")) != NULL) {
1470122394Sharti		fprintf(fp, "%u", getpid());
1471122394Sharti		fclose(fp);
1472124861Sharti		if (atexit(term) == -1) {
1473124861Sharti			syslog(LOG_ERR, "atexit failed: %m");
1474124861Sharti			(void)remove(pid_file);
1475124861Sharti			exit(0);
1476124861Sharti		}
1477122394Sharti	}
1478122394Sharti
1479122394Sharti	if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.",
1480122394Sharti	    NULL) == 0) {
1481122394Sharti		syslog(LOG_ERR, "cannot register SNMPv2 MIB");
1482122394Sharti		exit(1);
1483122394Sharti	}
1484122394Sharti	if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.",
1485122394Sharti	    NULL) == 0) {
1486122394Sharti		syslog(LOG_ERR, "cannot register begemotSnmpd MIB");
1487122394Sharti		exit(1);
1488122394Sharti	}
1489122394Sharti
1490122394Sharti	snmp_send_trap(&oid_coldStart, NULL);
1491122394Sharti
1492122394Sharti	while ((m = TAILQ_FIRST(&modules_start)) != NULL) {
1493122394Sharti		m->flags &= ~LM_ONSTARTLIST;
1494122394Sharti		TAILQ_REMOVE(&modules_start, m, start);
1495122394Sharti		lm_start(m);
1496122394Sharti	}
1497122394Sharti
1498122394Sharti	for (;;) {
1499124861Sharti#ifndef USE_LIBBEGEMOT
1500122394Sharti		evEvent event;
1501124861Sharti#endif
1502122394Sharti		struct lmodule *mod;
1503122394Sharti
1504122394Sharti		TAILQ_FOREACH(mod, &lmodules, link)
1505122394Sharti			if (mod->config->idle != NULL)
1506122394Sharti				(*mod->config->idle)();
1507122394Sharti
1508124861Sharti#ifndef USE_LIBBEGEMOT
1509122394Sharti		if (evGetNext(evctx, &event, EV_WAIT) == 0) {
1510122394Sharti			if (evDispatch(evctx, event))
1511122394Sharti				syslog(LOG_ERR, "evDispatch: %m");
1512122394Sharti		} else if (errno != EINTR) {
1513122394Sharti			syslog(LOG_ERR, "evGetNext: %m");
1514122394Sharti			exit(1);
1515122394Sharti		}
1516124861Sharti#else
1517124861Sharti		poll_dispatch(1);
1518124861Sharti#endif
1519122394Sharti
1520122394Sharti		if (work != 0) {
1521122394Sharti			block_sigs();
1522122394Sharti			if (work & WORK_DOINFO) {
1523124861Sharti#ifdef USE_LIBBEGEMOT
1524124861Sharti				info_func();
1525124861Sharti#else
1526122394Sharti				if (evWaitFor(evctx, &work, info_func,
1527122394Sharti				    NULL, NULL) == -1) {
1528122394Sharti					syslog(LOG_ERR, "evWaitFor: %m");
1529122394Sharti					exit(1);
1530122394Sharti				}
1531124861Sharti#endif
1532122394Sharti			}
1533122394Sharti			if (work & WORK_RECONFIG) {
1534124861Sharti#ifdef USE_LIBBEGEMOT
1535124861Sharti				config_func();
1536124861Sharti#else
1537122394Sharti				if (evWaitFor(evctx, &work, config_func,
1538122394Sharti				    NULL, NULL) == -1) {
1539122394Sharti					syslog(LOG_ERR, "evWaitFor: %m");
1540122394Sharti					exit(1);
1541122394Sharti				}
1542124861Sharti#endif
1543122394Sharti			}
1544122394Sharti			work = 0;
1545122394Sharti			unblock_sigs();
1546124861Sharti#ifndef USE_LIBBEGEMOT
1547122394Sharti			if (evDo(evctx, &work) == -1) {
1548122394Sharti				syslog(LOG_ERR, "evDo: %m");
1549122394Sharti				exit(1);
1550122394Sharti			}
1551124861Sharti#endif
1552122394Sharti		}
1553122394Sharti	}
1554122394Sharti
1555122394Sharti	return (0);
1556122394Sharti}
1557122394Sharti
1558122394Sharti
1559122394Shartiu_int32_t
1560122394Shartiget_ticks()
1561122394Sharti{
1562122394Sharti	struct timeval tv;
1563122394Sharti	u_int32_t ret;
1564122394Sharti
1565122394Sharti	if (gettimeofday(&tv, NULL))
1566122394Sharti		abort();
1567122394Sharti	ret = tv.tv_sec * 100 + tv.tv_usec / 10000;
1568122394Sharti	return (ret);
1569122394Sharti}
1570122394Sharti/*
1571122394Sharti * Timer support
1572122394Sharti */
1573124861Sharti#ifdef USE_LIBBEGEMOT
1574122394Shartistatic void
1575124861Shartitfunc(int tid __unused, void *uap)
1576124861Sharti#else
1577124861Shartistatic void
1578122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1579122394Sharti	struct timespec inter __unused)
1580124861Sharti#endif
1581122394Sharti{
1582122394Sharti	struct timer *tp = uap;
1583122394Sharti
1584122394Sharti	LIST_REMOVE(tp, link);
1585122394Sharti	tp->func(tp->udata);
1586122394Sharti	free(tp);
1587122394Sharti}
1588122394Sharti
1589122394Sharti/*
1590122394Sharti * Start a timer
1591122394Sharti */
1592122394Shartivoid *
1593122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
1594122394Sharti{
1595122394Sharti	struct timer *tp;
1596124861Sharti#ifdef USE_LIBBEGEMOT
1597124861Sharti	struct timeval due;
1598124861Sharti#else
1599122394Sharti	struct timespec due;
1600124861Sharti#endif
1601122394Sharti
1602122394Sharti	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1603122394Sharti		syslog(LOG_CRIT, "out of memory for timer");
1604122394Sharti		exit(1);
1605122394Sharti	}
1606124861Sharti#ifdef USE_LIBBEGEMOT
1607124861Sharti	(void)gettimeofday(&due, NULL);
1608124861Sharti	due.tv_sec += ticks / 100;
1609124861Sharti	due.tv_usec += (ticks % 100) * 10000;
1610124861Sharti	if (due.tv_usec >= 1000000) {
1611124861Sharti		due.tv_sec++;
1612124861Sharti		due.tv_usec -= 1000000;
1613124861Sharti	}
1614124861Sharti#else
1615122394Sharti	due = evAddTime(evNowTime(),
1616124861Sharti	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1617124861Sharti#endif
1618122394Sharti
1619122394Sharti	tp->udata = udata;
1620122394Sharti	tp->owner = mod;
1621122394Sharti	tp->func = func;
1622122394Sharti
1623122394Sharti	LIST_INSERT_HEAD(&timer_list, tp, link);
1624122394Sharti
1625124861Sharti#ifdef USE_LIBBEGEMOT
1626124861Sharti	if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000,
1627124861Sharti	    0, tfunc, tp)) < 0) {
1628124861Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1629124861Sharti		exit(1);
1630124861Sharti	}
1631124861Sharti#else
1632122394Sharti	if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
1633122394Sharti	    == -1) {
1634122394Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1635122394Sharti		exit(1);
1636122394Sharti	}
1637124861Sharti#endif
1638122394Sharti	return (tp);
1639122394Sharti}
1640122394Sharti
1641122394Shartivoid
1642122394Shartitimer_stop(void *p)
1643122394Sharti{
1644122394Sharti	struct timer *tp = p;
1645122394Sharti
1646122394Sharti	LIST_REMOVE(tp, link);
1647124861Sharti#ifdef USE_LIBBEGEMOT
1648124861Sharti	poll_stop_timer(tp->id);
1649124861Sharti#else
1650122394Sharti	if (evClearTimer(evctx, tp->id) == -1) {
1651122394Sharti		syslog(LOG_ERR, "cannot stop timer: %m");
1652122394Sharti		exit(1);
1653122394Sharti	}
1654124861Sharti#endif
1655122394Sharti	free(p);
1656122394Sharti}
1657122394Sharti
1658122394Shartistatic void
1659122394Shartitimer_flush(struct lmodule *mod)
1660122394Sharti{
1661122394Sharti	struct timer *t, *t1;
1662122394Sharti
1663122394Sharti	t = LIST_FIRST(&timer_list);
1664122394Sharti	while (t != NULL) {
1665122394Sharti		t1 = LIST_NEXT(t, link);
1666122394Sharti		if (t->owner == mod)
1667122394Sharti			timer_stop(t);
1668122394Sharti		t = t1;
1669122394Sharti	}
1670122394Sharti}
1671122394Sharti
1672122394Shartistatic void
1673122394Shartisnmp_printf_func(const char *fmt, ...)
1674122394Sharti{
1675122394Sharti	va_list ap;
1676122394Sharti	static char *pend = NULL;
1677122394Sharti	char *ret, *new;
1678122394Sharti
1679122394Sharti	va_start(ap, fmt);
1680122394Sharti	vasprintf(&ret, fmt, ap);
1681122394Sharti	va_end(ap);
1682122394Sharti
1683122394Sharti	if (ret == NULL)
1684122394Sharti		return;
1685122394Sharti	if (pend != NULL) {
1686122394Sharti		if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1))
1687122394Sharti		    == NULL) {
1688122394Sharti			free(ret);
1689122394Sharti			return;
1690122394Sharti		}
1691122394Sharti		pend = new;
1692122394Sharti		strcat(pend, ret);
1693122394Sharti		free(ret);
1694122394Sharti	} else
1695122394Sharti		pend = ret;
1696122394Sharti
1697122394Sharti	while ((ret = strchr(pend, '\n')) != NULL) {
1698122394Sharti		*ret = '\0';
1699122394Sharti		syslog(LOG_DEBUG, "%s", pend);
1700122394Sharti		if (strlen(ret + 1) == 0) {
1701122394Sharti			free(pend);
1702122394Sharti			pend = NULL;
1703122394Sharti			break;
1704122394Sharti		}
1705122394Sharti		strcpy(pend, ret + 1);
1706122394Sharti	}
1707122394Sharti}
1708122394Sharti
1709122394Shartistatic void
1710122394Shartisnmp_error_func(const char *err, ...)
1711122394Sharti{
1712122394Sharti	char errbuf[1000];
1713122394Sharti	va_list ap;
1714122394Sharti
1715124861Sharti	if (!(snmp_trace & LOG_SNMP_ERRORS))
1716124861Sharti		return;
1717124861Sharti
1718122394Sharti	va_start(ap, err);
1719122394Sharti	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1720124861Sharti	vsnprintf(errbuf + strlen(errbuf),
1721124861Sharti	    sizeof(errbuf) - strlen(errbuf), err, ap);
1722122394Sharti	va_end(ap);
1723122394Sharti
1724122394Sharti	syslog(LOG_ERR, "%s", errbuf);
1725122394Sharti}
1726122394Sharti
1727122394Shartistatic void
1728122394Shartisnmp_debug_func(const char *err, ...)
1729122394Sharti{
1730122394Sharti	char errbuf[1000];
1731122394Sharti	va_list ap;
1732122394Sharti
1733122394Sharti	va_start(ap, err);
1734122394Sharti	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1735122394Sharti	vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf),
1736122394Sharti	    err, ap);
1737122394Sharti	va_end(ap);
1738122394Sharti
1739122394Sharti	syslog(LOG_DEBUG, "%s", errbuf);
1740122394Sharti}
1741122394Sharti
1742122394Shartistatic void
1743122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...)
1744122394Sharti{
1745122394Sharti	char errbuf[1000];
1746122394Sharti	va_list ap;
1747122394Sharti	u_int i;
1748122394Sharti
1749124861Sharti	if (!(snmp_trace & LOG_ASN1_ERRORS))
1750124861Sharti		return;
1751124861Sharti
1752122394Sharti	va_start(ap, err);
1753122394Sharti	snprintf(errbuf, sizeof(errbuf), "ASN.1: ");
1754124861Sharti	vsnprintf(errbuf + strlen(errbuf),
1755124861Sharti	    sizeof(errbuf) - strlen(errbuf), err, ap);
1756122394Sharti	va_end(ap);
1757122394Sharti
1758122394Sharti	if (b != NULL) {
1759124861Sharti		snprintf(errbuf + strlen(errbuf),
1760124861Sharti		    sizeof(errbuf) - strlen(errbuf), " at");
1761122394Sharti		for (i = 0; b->asn_len > i; i++)
1762124861Sharti			snprintf(errbuf + strlen(errbuf),
1763124861Sharti			    sizeof(errbuf) - strlen(errbuf),
1764124861Sharti			    " %02x", b->asn_cptr[i]);
1765122394Sharti	}
1766122394Sharti
1767122394Sharti	syslog(LOG_ERR, "%s", errbuf);
1768122394Sharti}
1769122394Sharti
1770122394Sharti/*
1771122394Sharti * Create a new community
1772122394Sharti */
1773122394Shartiu_int
1774122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner,
1775122394Sharti    const char *str)
1776122394Sharti{
1777122394Sharti	struct community *c, *p;
1778122394Sharti	u_int ncomm;
1779122394Sharti
1780122394Sharti	/* generate an identifier */
1781122394Sharti	do {
1782122394Sharti		if ((ncomm = next_community_index++) == UINT_MAX)
1783122394Sharti			next_community_index = 1;
1784122394Sharti		TAILQ_FOREACH(c, &community_list, link)
1785122394Sharti			if (c->value == ncomm)
1786122394Sharti				break;
1787122394Sharti	} while (c != NULL);
1788122394Sharti
1789122394Sharti	if ((c = malloc(sizeof(struct community))) == NULL) {
1790122394Sharti		syslog(LOG_ERR, "comm_define: %m");
1791122394Sharti		return (0);
1792122394Sharti	}
1793122394Sharti	c->owner = owner;
1794122394Sharti	c->value = ncomm;
1795122394Sharti	c->descr = descr;
1796122394Sharti	c->string = NULL;
1797122394Sharti	c->private = priv;
1798122394Sharti
1799122394Sharti	if (str != NULL) {
1800122394Sharti		if((c->string = malloc(strlen(str)+1)) == NULL) {
1801122394Sharti			free(c);
1802122394Sharti			return (0);
1803122394Sharti		}
1804122394Sharti		strcpy(c->string, str);
1805122394Sharti	}
1806122394Sharti
1807122394Sharti	/* make index */
1808122394Sharti	if (c->owner == NULL) {
1809122394Sharti		c->index.len = 1;
1810122394Sharti		c->index.subs[0] = 0;
1811122394Sharti	} else {
1812122394Sharti		c->index = c->owner->index;
1813122394Sharti	}
1814122394Sharti	c->index.subs[c->index.len++] = c->private;
1815122394Sharti
1816122394Sharti	/*
1817122394Sharti	 * Insert ordered
1818122394Sharti	 */
1819122394Sharti	TAILQ_FOREACH(p, &community_list, link) {
1820122394Sharti		if (asn_compare_oid(&p->index, &c->index) > 0) {
1821122394Sharti			TAILQ_INSERT_BEFORE(p, c, link);
1822122394Sharti			break;
1823122394Sharti		}
1824122394Sharti	}
1825122394Sharti	if (p == NULL)
1826122394Sharti		TAILQ_INSERT_TAIL(&community_list, c, link);
1827122394Sharti	return (c->value);
1828122394Sharti}
1829122394Sharti
1830122394Sharticonst char *
1831122394Sharticomm_string(u_int ncomm)
1832122394Sharti{
1833122394Sharti	struct community *p;
1834122394Sharti
1835122394Sharti	TAILQ_FOREACH(p, &community_list, link)
1836122394Sharti		if (p->value == ncomm)
1837122394Sharti			return (p->string);
1838122394Sharti	return (NULL);
1839122394Sharti}
1840122394Sharti
1841122394Sharti/*
1842122394Sharti * Delete all communities allocated by a module
1843122394Sharti */
1844122394Shartistatic void
1845122394Sharticomm_flush(struct lmodule *mod)
1846122394Sharti{
1847122394Sharti	struct community *p, *p1;
1848122394Sharti
1849122394Sharti	p = TAILQ_FIRST(&community_list);
1850122394Sharti	while (p != NULL) {
1851122394Sharti		p1 = TAILQ_NEXT(p, link);
1852122394Sharti		if (p->owner == mod) {
1853122394Sharti			free(p->string);
1854122394Sharti			TAILQ_REMOVE(&community_list, p, link);
1855122394Sharti			free(p);
1856122394Sharti		}
1857122394Sharti		p = p1;
1858122394Sharti	}
1859122394Sharti}
1860122394Sharti
1861122394Sharti/*
1862122394Sharti * Request ID handling.
1863122394Sharti *
1864122394Sharti * Allocate a new range of request ids. Use a first fit algorithm.
1865122394Sharti */
1866122394Shartiu_int
1867122394Shartireqid_allocate(int size, struct lmodule *mod)
1868122394Sharti{
1869122394Sharti	u_int type;
1870122394Sharti	struct idrange *r, *r1;
1871122394Sharti
1872122394Sharti	if (size <= 0 || size > INT32_MAX) {
1873122394Sharti		syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size);
1874122394Sharti		return (0);
1875122394Sharti	}
1876122394Sharti	/* allocate a type id */
1877122394Sharti	do {
1878122394Sharti		if ((type = next_idrange++) == UINT_MAX)
1879122394Sharti			next_idrange = 1;
1880122394Sharti		TAILQ_FOREACH(r, &idrange_list, link)
1881122394Sharti			if (r->type == type)
1882122394Sharti				break;
1883122394Sharti	} while(r != NULL);
1884122394Sharti
1885122394Sharti	/* find a range */
1886122394Sharti	if (TAILQ_EMPTY(&idrange_list))
1887122394Sharti		r = NULL;
1888122394Sharti	else {
1889122394Sharti		r = TAILQ_FIRST(&idrange_list);
1890122394Sharti		if (r->base < size) {
1891122394Sharti			while((r1 = TAILQ_NEXT(r, link)) != NULL) {
1892122394Sharti				if (r1->base - (r->base + r->size) >= size)
1893122394Sharti					break;
1894122394Sharti				r = r1;
1895122394Sharti			}
1896122394Sharti			r = r1;
1897122394Sharti		}
1898122394Sharti		if (r == NULL) {
1899122394Sharti			r1 = TAILQ_LAST(&idrange_list, idrange_list);
1900122394Sharti			if (INT32_MAX - size + 1 < r1->base + r1->size) {
1901122394Sharti				syslog(LOG_ERR, "out of id ranges (%u)", size);
1902122394Sharti				return (0);
1903122394Sharti			}
1904122394Sharti		}
1905122394Sharti	}
1906122394Sharti
1907122394Sharti	/* allocate structure */
1908122394Sharti	if ((r1 = malloc(sizeof(struct idrange))) == NULL) {
1909122394Sharti		syslog(LOG_ERR, "%s: %m", __FUNCTION__);
1910122394Sharti		return (0);
1911122394Sharti	}
1912122394Sharti
1913122394Sharti	r1->type = type;
1914122394Sharti	r1->size = size;
1915122394Sharti	r1->owner = mod;
1916122394Sharti	if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) {
1917122394Sharti		r1->base = 0;
1918122394Sharti		TAILQ_INSERT_HEAD(&idrange_list, r1, link);
1919122394Sharti	} else if (r == NULL) {
1920122394Sharti		r = TAILQ_LAST(&idrange_list, idrange_list);
1921122394Sharti		r1->base = r->base + r->size;
1922122394Sharti		TAILQ_INSERT_TAIL(&idrange_list, r1, link);
1923122394Sharti	} else {
1924122394Sharti		r = TAILQ_PREV(r, idrange_list, link);
1925122394Sharti		r1->base = r->base + r->size;
1926122394Sharti		TAILQ_INSERT_AFTER(&idrange_list, r, r1, link);
1927122394Sharti	}
1928122394Sharti	r1->next = r1->base;
1929122394Sharti
1930122394Sharti	return (type);
1931122394Sharti}
1932122394Sharti
1933122394Shartiint32_t
1934122394Shartireqid_next(u_int type)
1935122394Sharti{
1936122394Sharti	struct idrange *r;
1937122394Sharti	int32_t id;
1938122394Sharti
1939122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
1940122394Sharti		if (r->type == type)
1941122394Sharti			break;
1942122394Sharti	if (r == NULL) {
1943122394Sharti		syslog(LOG_CRIT, "wrong idrange type");
1944122394Sharti		abort();
1945122394Sharti	}
1946122394Sharti	if ((id = r->next++) == r->base + (r->size - 1))
1947122394Sharti		r->next = r->base;
1948122394Sharti	return (id);
1949122394Sharti}
1950122394Sharti
1951122394Shartiint32_t
1952122394Shartireqid_base(u_int type)
1953122394Sharti{
1954122394Sharti	struct idrange *r;
1955122394Sharti
1956122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
1957122394Sharti		if (r->type == type)
1958122394Sharti			return (r->base);
1959122394Sharti	syslog(LOG_CRIT, "wrong idrange type");
1960122394Sharti	abort();
1961122394Sharti}
1962122394Sharti
1963122394Shartiu_int
1964122394Shartireqid_type(int32_t reqid)
1965122394Sharti{
1966122394Sharti	struct idrange *r;
1967122394Sharti
1968122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
1969122394Sharti		if (reqid >= r->base && reqid <= r->base + (r->size - 1))
1970122394Sharti			return (r->type);
1971122394Sharti	return (0);
1972122394Sharti}
1973122394Sharti
1974122394Shartiint
1975122394Shartireqid_istype(int32_t reqid, u_int type)
1976122394Sharti{
1977122394Sharti	return (reqid_type(reqid) == type);
1978122394Sharti}
1979122394Sharti
1980122394Sharti/*
1981122394Sharti * Delete all communities allocated by a module
1982122394Sharti */
1983122394Shartistatic void
1984122394Shartireqid_flush(struct lmodule *mod)
1985122394Sharti{
1986122394Sharti	struct idrange *p, *p1;
1987122394Sharti
1988122394Sharti	p = TAILQ_FIRST(&idrange_list);
1989122394Sharti	while (p != NULL) {
1990122394Sharti		p1 = TAILQ_NEXT(p, link);
1991122394Sharti		if (p->owner == mod) {
1992122394Sharti			TAILQ_REMOVE(&idrange_list, p, link);
1993122394Sharti			free(p);
1994122394Sharti		}
1995122394Sharti		p = p1;
1996122394Sharti	}
1997122394Sharti}
1998122394Sharti
1999122394Sharti/*
2000122394Sharti * Merge the given tree for the given module into the main tree.
2001122394Sharti */
2002122394Shartistatic int
2003122394Sharticompare_node(const void *v1, const void *v2)
2004122394Sharti{
2005122394Sharti	const struct snmp_node *n1 = v1;
2006122394Sharti	const struct snmp_node *n2 = v2;
2007122394Sharti
2008122394Sharti	return (asn_compare_oid(&n1->oid, &n2->oid));
2009122394Sharti}
2010122394Shartistatic int
2011122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod)
2012122394Sharti{
2013122394Sharti	struct snmp_node *xtree;
2014122394Sharti	u_int i;
2015122394Sharti
2016122394Sharti	xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize));
2017122394Sharti	if (xtree == NULL) {
2018128237Sharti		syslog(LOG_ERR, "tree_merge: %m");
2019122394Sharti		return (-1);
2020122394Sharti	}
2021122394Sharti	tree = xtree;
2022122394Sharti	memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize);
2023122394Sharti
2024122394Sharti	for (i = 0; i < nsize; i++)
2025128237Sharti		tree[tree_size + i].tree_data = mod;
2026122394Sharti
2027122394Sharti	tree_size += nsize;
2028122394Sharti
2029122394Sharti	qsort(tree, tree_size, sizeof(tree[0]), compare_node);
2030122394Sharti
2031122394Sharti	return (0);
2032122394Sharti}
2033122394Sharti
2034122394Sharti/*
2035122394Sharti * Remove all nodes belonging to the loadable module
2036122394Sharti */
2037122394Shartistatic void
2038122394Shartitree_unmerge(struct lmodule *mod)
2039122394Sharti{
2040122394Sharti	u_int s, d;
2041122394Sharti
2042122394Sharti	for(s = d = 0; s < tree_size; s++)
2043128237Sharti		if (tree[s].tree_data != mod) {
2044122394Sharti			if (s != d)
2045122394Sharti				tree[d] = tree[s];
2046122394Sharti			d++;
2047122394Sharti		}
2048122394Sharti	tree_size = d;
2049122394Sharti}
2050122394Sharti
2051122394Sharti/*
2052122394Sharti * Loadable modules
2053122394Sharti */
2054122394Shartistruct lmodule *
2055122394Shartilm_load(const char *path, const char *section)
2056122394Sharti{
2057122394Sharti	struct lmodule *m;
2058122394Sharti	int err;
2059122394Sharti	int i;
2060122394Sharti	char *av[MAX_MOD_ARGS + 1];
2061122394Sharti	int ac;
2062122394Sharti	u_int u;
2063122394Sharti
2064122394Sharti	if ((m = malloc(sizeof(*m))) == NULL) {
2065122394Sharti		syslog(LOG_ERR, "lm_load: %m");
2066122394Sharti		return (NULL);
2067122394Sharti	}
2068122394Sharti	m->handle = NULL;
2069122394Sharti	m->flags = 0;
2070122394Sharti	strcpy(m->section, section);
2071122394Sharti
2072122394Sharti	if ((m->path = malloc(strlen(path) + 1)) == NULL) {
2073122394Sharti		syslog(LOG_ERR, "lm_load: %m");
2074122394Sharti		goto err;
2075122394Sharti	}
2076122394Sharti	strcpy(m->path, path);
2077122394Sharti
2078122394Sharti	/*
2079122394Sharti	 * Make index
2080122394Sharti	 */
2081122394Sharti	m->index.subs[0] = strlen(section);
2082122394Sharti	m->index.len = m->index.subs[0] + 1;
2083122394Sharti	for (u = 0; u < m->index.subs[0]; u++)
2084122394Sharti		m->index.subs[u + 1] = section[u];
2085122394Sharti
2086122394Sharti	/*
2087122394Sharti	 * Load the object file and locate the config structure
2088122394Sharti	 */
2089122394Sharti	if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
2090122394Sharti		syslog(LOG_ERR, "lm_load: open %s", dlerror());
2091122394Sharti		goto err;
2092122394Sharti	}
2093122394Sharti
2094122394Sharti	if ((m->config = dlsym(m->handle, "config")) == NULL) {
2095122394Sharti		syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror());
2096122394Sharti		goto err;
2097122394Sharti	}
2098122394Sharti
2099122394Sharti	/*
2100122394Sharti	 * Insert it into the right place
2101122394Sharti	 */
2102122394Sharti	INSERT_OBJECT_OID(m, &lmodules);
2103122394Sharti
2104122394Sharti	/* preserve order */
2105122394Sharti	if (community == COMM_INITIALIZE) {
2106122394Sharti		m->flags |= LM_ONSTARTLIST;
2107122394Sharti		TAILQ_INSERT_TAIL(&modules_start, m, start);
2108122394Sharti	}
2109122394Sharti
2110122394Sharti	/*
2111122394Sharti	 * make the argument vector.
2112122394Sharti	 */
2113122394Sharti	ac = 0;
2114122394Sharti	for (i = 0; i < nprogargs; i++) {
2115122394Sharti		if (strlen(progargs[i]) >= strlen(section) + 1 &&
2116122394Sharti		    strncmp(progargs[i], section, strlen(section)) == 0 &&
2117122394Sharti		    progargs[i][strlen(section)] == ':') {
2118122394Sharti			if (ac == MAX_MOD_ARGS) {
2119122394Sharti				syslog(LOG_WARNING, "too many arguments for "
2120122394Sharti				    "module '%s", section);
2121122394Sharti				break;
2122122394Sharti			}
2123122394Sharti			av[ac++] = &progargs[i][strlen(section)+1];
2124122394Sharti		}
2125122394Sharti	}
2126122394Sharti	av[ac] = NULL;
2127122394Sharti
2128122394Sharti	/*
2129122394Sharti	 * Run the initialisation function
2130122394Sharti	 */
2131122394Sharti	if ((err = (*m->config->init)(m, ac, av)) != 0) {
2132122394Sharti		syslog(LOG_ERR, "lm_load: init failed: %d", err);
2133122394Sharti		TAILQ_REMOVE(&lmodules, m, link);
2134122394Sharti		goto err;
2135122394Sharti	}
2136122394Sharti
2137122394Sharti	return (m);
2138122394Sharti
2139122394Sharti  err:
2140122394Sharti	if (m->handle)
2141122394Sharti		dlclose(m->handle);
2142122394Sharti	free(m->path);
2143122394Sharti	free(m);
2144122394Sharti	return (NULL);
2145122394Sharti}
2146122394Sharti
2147122394Sharti/*
2148122394Sharti * Start a module
2149122394Sharti */
2150122394Shartivoid
2151122394Shartilm_start(struct lmodule *mod)
2152122394Sharti{
2153122394Sharti	const struct lmodule *m;
2154122394Sharti
2155122394Sharti	/*
2156122394Sharti	 * Merge tree. If this fails, unload the module.
2157122394Sharti	 */
2158122394Sharti	if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) {
2159122394Sharti		lm_unload(mod);
2160122394Sharti		return;
2161122394Sharti	}
2162122394Sharti
2163122394Sharti	/*
2164122394Sharti	 * Read configuration
2165122394Sharti	 */
2166122394Sharti	if (read_config(config_file, mod)) {
2167122394Sharti		syslog(LOG_ERR, "error in config file");
2168122394Sharti		lm_unload(mod);
2169122394Sharti		return;
2170122394Sharti	}
2171122394Sharti	if (mod->config->start)
2172122394Sharti		(*mod->config->start)();
2173122394Sharti
2174122394Sharti	mod->flags |= LM_STARTED;
2175122394Sharti
2176122394Sharti	/*
2177122394Sharti	 * Inform other modules
2178122394Sharti	 */
2179122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
2180122394Sharti		if (m->config->loading)
2181122394Sharti			(*m->config->loading)(mod, 1);
2182122394Sharti}
2183122394Sharti
2184122394Sharti
2185122394Sharti/*
2186122394Sharti * Unload a module.
2187122394Sharti */
2188122394Shartivoid
2189122394Shartilm_unload(struct lmodule *m)
2190122394Sharti{
2191122394Sharti	int err;
2192122394Sharti	const struct lmodule *mod;
2193122394Sharti
2194122394Sharti	TAILQ_REMOVE(&lmodules, m, link);
2195122394Sharti	if (m->flags & LM_ONSTARTLIST)
2196122394Sharti		TAILQ_REMOVE(&modules_start, m, start);
2197122394Sharti	tree_unmerge(m);
2198122394Sharti
2199122394Sharti	if ((m->flags & LM_STARTED) && m->config->fini &&
2200122394Sharti	    (err = (*m->config->fini)()) != 0)
2201122394Sharti		syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err);
2202122394Sharti
2203122394Sharti	comm_flush(m);
2204122394Sharti	reqid_flush(m);
2205122394Sharti	timer_flush(m);
2206122394Sharti	fd_flush(m);
2207122394Sharti
2208122394Sharti	dlclose(m->handle);
2209122394Sharti	free(m->path);
2210122394Sharti
2211122394Sharti	/*
2212122394Sharti	 * Inform other modules
2213122394Sharti	 */
2214122394Sharti	TAILQ_FOREACH(mod, &lmodules, link)
2215122394Sharti		if (mod->config->loading)
2216122394Sharti			(*mod->config->loading)(m, 0);
2217122394Sharti
2218122394Sharti	free(m);
2219122394Sharti}
2220122394Sharti
2221122394Sharti/*
2222122394Sharti * Register an object resource and return the index (or 0 on failures)
2223122394Sharti */
2224122394Shartiu_int
2225122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod)
2226122394Sharti{
2227122394Sharti	struct objres *objres, *or1;
2228122394Sharti	u_int idx;
2229122394Sharti
2230122394Sharti	/* find a free index */
2231122394Sharti	idx = 1;
2232122394Sharti	for (objres = TAILQ_FIRST(&objres_list);
2233122394Sharti	     objres != NULL;
2234122394Sharti	     objres = TAILQ_NEXT(objres, link)) {
2235122394Sharti		if ((or1 = TAILQ_NEXT(objres, link)) == NULL ||
2236122394Sharti		    or1->index > objres->index + 1) {
2237122394Sharti			idx = objres->index + 1;
2238122394Sharti			break;
2239122394Sharti		}
2240122394Sharti	}
2241122394Sharti
2242122394Sharti	if ((objres = malloc(sizeof(*objres))) == NULL)
2243122394Sharti		return (0);
2244122394Sharti
2245122394Sharti	objres->index = idx;
2246122394Sharti	objres->oid = *or;
2247122394Sharti	strlcpy(objres->descr, descr, sizeof(objres->descr));
2248122394Sharti	objres->uptime = get_ticks() - start_tick;
2249122394Sharti	objres->module = mod;
2250122394Sharti
2251122394Sharti	INSERT_OBJECT_INT(objres, &objres_list);
2252122394Sharti
2253122394Sharti	systemg.or_last_change = objres->uptime;
2254122394Sharti
2255122394Sharti	return (idx);
2256122394Sharti}
2257122394Sharti
2258122394Shartivoid
2259122394Shartior_unregister(u_int idx)
2260122394Sharti{
2261122394Sharti	struct objres *objres;
2262122394Sharti
2263122394Sharti	TAILQ_FOREACH(objres, &objres_list, link)
2264122394Sharti		if (objres->index == idx) {
2265122394Sharti			TAILQ_REMOVE(&objres_list, objres, link);
2266122394Sharti			free(objres);
2267122394Sharti			return;
2268122394Sharti		}
2269122394Sharti}
2270