main.c revision 156066
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 */
33122394Sharti#include <sys/param.h>
34122394Sharti#include <sys/un.h>
35124861Sharti#include <sys/ucred.h>
36150920Sharti#include <sys/uio.h>
37122394Sharti#include <stdio.h>
38122394Sharti#include <stdlib.h>
39122394Sharti#include <stddef.h>
40122394Sharti#include <string.h>
41122394Sharti#include <stdarg.h>
42122394Sharti#include <ctype.h>
43122394Sharti#include <errno.h>
44122394Sharti#include <syslog.h>
45122394Sharti#include <unistd.h>
46122394Sharti#include <signal.h>
47122394Sharti#include <dlfcn.h>
48122394Sharti#include <inttypes.h>
49122394Sharti
50145557Sharti#ifdef USE_TCPWRAPPERS
51145557Sharti#include <arpa/inet.h>
52145557Sharti#include <tcpd.h>
53145557Sharti#endif
54145557Sharti
55156066Sharti#include "support.h"
56122394Sharti#include "snmpmod.h"
57122394Sharti#include "snmpd.h"
58122394Sharti#include "tree.h"
59122394Sharti#include "oid.h"
60122394Sharti
61122394Sharti#define	PATH_PID	"/var/run/%s.pid"
62122394Sharti#define PATH_CONFIG	"/etc/%s.config"
63122394Sharti
64146525Shartiuint64_t this_tick;	/* start of processing of current packet (absolute) */
65146525Shartiuint64_t start_tick;	/* start of processing */
66122394Sharti
67122394Shartistruct systemg systemg = {
68122394Sharti	NULL,
69122394Sharti	{ 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }},
70122394Sharti	NULL, NULL, NULL,
71122394Sharti	64 + 8 + 4,
72122394Sharti	0
73122394Sharti};
74122394Shartistruct debug debug = {
75122394Sharti	0,		/* dump_pdus */
76122394Sharti	LOG_DEBUG,	/* log_pri */
77122394Sharti	0,		/* evdebug */
78122394Sharti};
79122394Sharti
80122394Shartistruct snmpd snmpd = {
81122394Sharti	2048,		/* txbuf */
82122394Sharti	2048,		/* rxbuf */
83122394Sharti	0,		/* comm_dis */
84122394Sharti	0,		/* auth_traps */
85122394Sharti	{0, 0, 0, 0},	/* trap1addr */
86124861Sharti	VERS_ENABLE_ALL,/* version_enable */
87122394Sharti};
88122394Shartistruct snmpd_stats snmpd_stats;
89122394Sharti
90122394Sharti/* snmpSerialNo */
91122394Shartiint32_t snmp_serial_no;
92122394Sharti
93122394Sharti/* search path for config files */
94122394Sharticonst char *syspath = PATH_SYSCONFIG;
95122394Sharti
96122394Sharti/* list of all loaded modules */
97122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules);
98122394Sharti
99122394Sharti/* list of loaded modules during start-up in the order they were loaded */
100122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start);
101122394Sharti
102122394Sharti/* list of all known communities */
103122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list);
104122394Sharti
105122394Sharti/* list of all installed object resources */
106122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list);
107122394Sharti
108122394Sharti/* community value generator */
109122394Shartistatic u_int next_community_index = 1;
110122394Sharti
111122394Sharti/* list of all known ranges */
112122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list);
113122394Sharti
114122394Sharti/* identifier generator */
115122394Shartiu_int next_idrange = 1;
116122394Sharti
117122394Sharti/* list of all current timers */
118122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list);
119122394Sharti
120122394Sharti/* list of file descriptors */
121122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list);
122122394Sharti
123122394Sharti/* program arguments */
124122394Shartistatic char **progargs;
125122394Shartistatic int nprogargs;
126122394Sharti
127122394Sharti/* current community */
128122394Shartiu_int	community;
129122394Shartistatic struct community *comm;
130122394Sharti
131122394Sharti/* file names */
132122394Shartistatic char config_file[MAXPATHLEN + 1];
133122394Shartistatic char pid_file[MAXPATHLEN + 1];
134122394Sharti
135124861Sharti#ifndef USE_LIBBEGEMOT
136122394Sharti/* event context */
137122394Shartistatic evContext evctx;
138124861Sharti#endif
139122394Sharti
140122394Sharti/* signal mask */
141122394Shartistatic sigset_t blocked_sigs;
142122394Sharti
143122394Sharti/* signal handling */
144122394Shartistatic int work;
145122394Sharti#define	WORK_DOINFO	0x0001
146122394Sharti#define	WORK_RECONFIG	0x0002
147122394Sharti
148122394Sharti/* oids */
149122394Shartistatic const struct asn_oid
150122394Sharti	oid_snmpMIB = OIDX_snmpMIB,
151122394Sharti	oid_begemotSnmpd = OIDX_begemotSnmpd,
152122394Sharti	oid_coldStart = OIDX_coldStart,
153122394Sharti	oid_authenticationFailure = OIDX_authenticationFailure;
154122394Sharti
155122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }};
156122394Sharti
157122394Sharti/* request id generator for traps */
158122394Shartiu_int trap_reqid;
159122394Sharti
160122394Sharti/* help text */
161122394Shartistatic const char usgtxt[] = "\
162122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
163122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\
164122394Shartiusage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\
165122394Sharti             [-m variable=value] [-p file]\n\
166122394Shartioptions:\n\
167122394Sharti  -d		don't daemonize\n\
168122394Sharti  -h		print this info\n\
169122394Sharti  -c file	specify configuration file\n\
170122394Sharti  -D options	debugging options\n\
171122394Sharti  -I path	system include path\n\
172122394Sharti  -l prefix	default basename for pid and config file\n\
173122394Sharti  -m var=val	define variable\n\
174122394Sharti  -p file	specify pid file\n\
175122394Sharti";
176122394Sharti
177145557Sharti/* hosts_access(3) request */
178145557Sharti#ifdef USE_TCPWRAPPERS
179145557Shartistatic struct request_info req;
180145557Sharti#endif
181145557Sharti
182124861Sharti/* transports */
183124861Shartiextern const struct transport_def udp_trans;
184124861Shartiextern const struct transport_def lsock_trans;
185124861Sharti
186124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
187124861Sharti
188122394Sharti/* forward declarations */
189122394Shartistatic void snmp_printf_func(const char *fmt, ...);
190122394Shartistatic void snmp_error_func(const char *err, ...);
191122394Shartistatic void snmp_debug_func(const char *err, ...);
192122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...);
193122394Sharti
194122394Sharti/*
195122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx.
196122394Sharti */
197122394Shartivoid *
198122394Shartibuf_alloc(int tx)
199122394Sharti{
200122394Sharti	void *buf;
201122394Sharti
202124861Sharti	if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) {
203122394Sharti		syslog(LOG_CRIT, "cannot allocate buffer");
204122394Sharti		if (tx)
205122394Sharti			snmpd_stats.noTxbuf++;
206122394Sharti		else
207122394Sharti			snmpd_stats.noRxbuf++;
208122394Sharti		return (NULL);
209122394Sharti	}
210122394Sharti	return (buf);
211122394Sharti}
212122394Sharti
213122394Sharti/*
214124861Sharti * Return the buffer size.
215122394Sharti */
216122394Shartisize_t
217122394Shartibuf_size(int tx)
218122394Sharti{
219124861Sharti	return (tx ? snmpd.txbuf : snmpd.rxbuf);
220122394Sharti}
221122394Sharti
222122394Sharti/*
223122394Sharti * Prepare a PDU for output
224122394Sharti */
225122394Shartivoid
226124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen,
227122394Sharti    const char *dest)
228122394Sharti{
229122394Sharti	struct asn_buf resp_b;
230122394Sharti
231122394Sharti	resp_b.asn_ptr = sndbuf;
232122394Sharti	resp_b.asn_len = snmpd.txbuf;
233122394Sharti
234122394Sharti	if (snmp_pdu_encode(pdu, &resp_b) != 0) {
235122394Sharti		syslog(LOG_ERR, "cannot encode message");
236122394Sharti		abort();
237122394Sharti	}
238122394Sharti	if (debug.dump_pdus) {
239122394Sharti		snmp_printf("%s <- ", dest);
240122394Sharti		snmp_pdu_dump(pdu);
241122394Sharti	}
242122394Sharti	*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
243122394Sharti}
244122394Sharti
245122394Sharti/*
246122394Sharti * SNMP input. Start: decode the PDU, find the community.
247122394Sharti */
248122394Shartienum snmpd_input_err
249122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source,
250124861Sharti    struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen)
251122394Sharti{
252122394Sharti	struct asn_buf b;
253122394Sharti	enum snmp_code code;
254122394Sharti	enum snmpd_input_err ret;
255124861Sharti	int sret;
256122394Sharti
257122394Sharti	b.asn_cptr = buf;
258122394Sharti	b.asn_len = len;
259124861Sharti
260124861Sharti	/* look whether we have enough bytes for the entire PDU. */
261124861Sharti	switch (sret = snmp_pdu_snoop(&b)) {
262124861Sharti
263124861Sharti	  case 0:
264124861Sharti		return (SNMPD_INPUT_TRUNC);
265124861Sharti
266124861Sharti	  case -1:
267124861Sharti		snmpd_stats.inASNParseErrs++;
268124861Sharti		return (SNMPD_INPUT_FAILED);
269124861Sharti	}
270124861Sharti	b.asn_len = *pdulen = (size_t)sret;
271124861Sharti
272122394Sharti	code = snmp_pdu_decode(&b, pdu, ip);
273122394Sharti
274124861Sharti	snmpd_stats.inPkts++;
275124861Sharti
276122394Sharti	ret = SNMPD_INPUT_OK;
277122394Sharti	switch (code) {
278122394Sharti
279122394Sharti	  case SNMP_CODE_FAILED:
280122394Sharti		snmpd_stats.inASNParseErrs++;
281122394Sharti		return (SNMPD_INPUT_FAILED);
282122394Sharti
283122394Sharti	  case SNMP_CODE_BADVERS:
284124861Sharti	  bad_vers:
285122394Sharti		snmpd_stats.inBadVersions++;
286122394Sharti		return (SNMPD_INPUT_FAILED);
287122394Sharti
288122394Sharti	  case SNMP_CODE_BADLEN:
289122394Sharti		if (pdu->type == SNMP_OP_SET)
290122394Sharti			ret = SNMPD_INPUT_VALBADLEN;
291122394Sharti		break;
292122394Sharti
293122394Sharti	  case SNMP_CODE_OORANGE:
294122394Sharti		if (pdu->type == SNMP_OP_SET)
295122394Sharti			ret = SNMPD_INPUT_VALRANGE;
296122394Sharti		break;
297122394Sharti
298122394Sharti	  case SNMP_CODE_BADENC:
299122394Sharti		if (pdu->type == SNMP_OP_SET)
300122394Sharti			ret = SNMPD_INPUT_VALBADENC;
301122394Sharti		break;
302122394Sharti
303122394Sharti	  case SNMP_CODE_OK:
304124861Sharti		switch (pdu->version) {
305124861Sharti
306124861Sharti		  case SNMP_V1:
307124861Sharti			if (!(snmpd.version_enable & VERS_ENABLE_V1))
308124861Sharti				goto bad_vers;
309124861Sharti			break;
310124861Sharti
311124861Sharti		  case SNMP_V2c:
312124861Sharti			if (!(snmpd.version_enable & VERS_ENABLE_V2C))
313124861Sharti				goto bad_vers;
314124861Sharti			break;
315124861Sharti
316124861Sharti		  case SNMP_Verr:
317124861Sharti			goto bad_vers;
318124861Sharti		}
319122394Sharti		break;
320122394Sharti	}
321122394Sharti
322122394Sharti	if (debug.dump_pdus) {
323122394Sharti		snmp_printf("%s -> ", source);
324122394Sharti		snmp_pdu_dump(pdu);
325122394Sharti	}
326122394Sharti
327122394Sharti	/*
328122394Sharti	 * Look, whether we know the community
329122394Sharti	 */
330122394Sharti	TAILQ_FOREACH(comm, &community_list, link)
331122394Sharti		if (comm->string != NULL &&
332122394Sharti		    strcmp(comm->string, pdu->community) == 0)
333122394Sharti			break;
334122394Sharti
335122394Sharti	if (comm == NULL) {
336122394Sharti		snmpd_stats.inBadCommunityNames++;
337122394Sharti		snmp_pdu_free(pdu);
338122394Sharti		if (snmpd.auth_traps)
339133211Sharti			snmp_send_trap(&oid_authenticationFailure,
340133211Sharti			    (struct snmp_value *)NULL);
341133211Sharti		ret = SNMPD_INPUT_BAD_COMM;
342133211Sharti	} else
343133211Sharti		community = comm->value;
344122394Sharti
345122394Sharti	/* update uptime */
346122394Sharti	this_tick = get_ticks();
347122394Sharti
348122394Sharti	return (ret);
349122394Sharti}
350122394Sharti
351122394Sharti/*
352122394Sharti * Will return only _OK or _FAILED
353122394Sharti */
354122394Shartienum snmpd_input_err
355122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen,
356122394Sharti    u_char *sndbuf, size_t *sndlen, const char *source,
357122394Sharti    enum snmpd_input_err ierr, int32_t ivar, void *data)
358122394Sharti{
359122394Sharti	struct snmp_pdu resp;
360122394Sharti	struct asn_buf resp_b, pdu_b;
361122394Sharti	enum snmp_ret ret;
362122394Sharti
363122394Sharti	resp_b.asn_ptr = sndbuf;
364122394Sharti	resp_b.asn_len = snmpd.txbuf;
365122394Sharti
366122394Sharti	pdu_b.asn_cptr = rcvbuf;
367122394Sharti	pdu_b.asn_len = rcvlen;
368122394Sharti
369122394Sharti	if (ierr != SNMPD_INPUT_OK) {
370122394Sharti		/* error decoding the input of a SET */
371122394Sharti		if (pdu->version == SNMP_V1)
372122394Sharti			pdu->error_status = SNMP_ERR_BADVALUE;
373122394Sharti		else if (ierr == SNMPD_INPUT_VALBADLEN)
374122394Sharti			pdu->error_status = SNMP_ERR_WRONG_LENGTH;
375122394Sharti		else if (ierr == SNMPD_INPUT_VALRANGE)
376122394Sharti			pdu->error_status = SNMP_ERR_WRONG_VALUE;
377122394Sharti		else
378122394Sharti			pdu->error_status = SNMP_ERR_WRONG_ENCODING;
379122394Sharti
380122394Sharti		pdu->error_index = ivar;
381122394Sharti
382122394Sharti		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
383122394Sharti			syslog(LOG_WARNING, "could not encode error response");
384122394Sharti			snmpd_stats.silentDrops++;
385122394Sharti			return (SNMPD_INPUT_FAILED);
386122394Sharti		}
387122394Sharti
388122394Sharti		if (debug.dump_pdus) {
389122394Sharti			snmp_printf("%s <- ", source);
390122394Sharti			snmp_pdu_dump(pdu);
391122394Sharti		}
392122394Sharti		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
393122394Sharti		return (SNMPD_INPUT_OK);
394122394Sharti	}
395122394Sharti
396122394Sharti	switch (pdu->type) {
397122394Sharti
398122394Sharti	  case SNMP_PDU_GET:
399122394Sharti		ret = snmp_get(pdu, &resp_b, &resp, data);
400122394Sharti		break;
401122394Sharti
402122394Sharti	  case SNMP_PDU_GETNEXT:
403122394Sharti		ret = snmp_getnext(pdu, &resp_b, &resp, data);
404122394Sharti		break;
405122394Sharti
406122394Sharti	  case SNMP_PDU_SET:
407122394Sharti		ret = snmp_set(pdu, &resp_b, &resp, data);
408122394Sharti		break;
409122394Sharti
410122394Sharti	  case SNMP_PDU_GETBULK:
411122394Sharti		ret = snmp_getbulk(pdu, &resp_b, &resp, data);
412122394Sharti		break;
413122394Sharti
414122394Sharti	  default:
415122394Sharti		ret = SNMP_RET_IGN;
416122394Sharti		break;
417122394Sharti	}
418122394Sharti
419122394Sharti	switch (ret) {
420122394Sharti
421122394Sharti	  case SNMP_RET_OK:
422122394Sharti		/* normal return - send a response */
423122394Sharti		if (debug.dump_pdus) {
424122394Sharti			snmp_printf("%s <- ", source);
425122394Sharti			snmp_pdu_dump(&resp);
426122394Sharti		}
427122394Sharti		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
428122394Sharti		snmp_pdu_free(&resp);
429122394Sharti		return (SNMPD_INPUT_OK);
430122394Sharti
431122394Sharti	  case SNMP_RET_IGN:
432122394Sharti		/* error - send nothing */
433122394Sharti		snmpd_stats.silentDrops++;
434122394Sharti		return (SNMPD_INPUT_FAILED);
435122394Sharti
436122394Sharti	  case SNMP_RET_ERR:
437122394Sharti		/* error - send error response. The snmp routine has
438122394Sharti		 * changed the error fields in the original message. */
439122394Sharti		resp_b.asn_ptr = sndbuf;
440122394Sharti		resp_b.asn_len = snmpd.txbuf;
441122394Sharti		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
442122394Sharti			syslog(LOG_WARNING, "could not encode error response");
443122394Sharti			snmpd_stats.silentDrops++;
444122394Sharti			return (SNMPD_INPUT_FAILED);
445122394Sharti		} else {
446122394Sharti			if (debug.dump_pdus) {
447122394Sharti				snmp_printf("%s <- ", source);
448122394Sharti				snmp_pdu_dump(pdu);
449122394Sharti			}
450122394Sharti			*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
451122394Sharti			return (SNMPD_INPUT_OK);
452122394Sharti		}
453122394Sharti	}
454122394Sharti	abort();
455122394Sharti}
456122394Sharti
457124861Sharti/*
458124861Sharti * Insert a port into the right place in the transport's table of ports
459124861Sharti */
460124861Shartivoid
461124861Shartitrans_insert_port(struct transport *t, struct tport *port)
462124861Sharti{
463124861Sharti	struct tport *p;
464122394Sharti
465124861Sharti	TAILQ_FOREACH(p, &t->table, link) {
466124861Sharti		if (asn_compare_oid(&p->index, &port->index) > 0) {
467124861Sharti			TAILQ_INSERT_BEFORE(p, port, link);
468124861Sharti			return;
469124861Sharti		}
470124861Sharti	}
471124861Sharti	port->transport = t;
472124861Sharti	TAILQ_INSERT_TAIL(&t->table, port, link);
473124861Sharti}
474122394Sharti
475122394Sharti/*
476124861Sharti * Remove a port from a transport's list
477124861Sharti */
478124861Shartivoid
479124861Shartitrans_remove_port(struct tport *port)
480124861Sharti{
481124861Sharti
482124861Sharti	TAILQ_REMOVE(&port->transport->table, port, link);
483124861Sharti}
484124861Sharti
485124861Sharti/*
486124861Sharti * Find a port on a transport's list
487124861Sharti */
488124861Shartistruct tport *
489124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub)
490124861Sharti{
491124861Sharti
492124861Sharti	return (FIND_OBJECT_OID(&t->table, idx, sub));
493124861Sharti}
494124861Sharti
495124861Sharti/*
496124861Sharti * Find next port on a transport's list
497124861Sharti */
498124861Shartistruct tport *
499124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub)
500124861Sharti{
501124861Sharti
502124861Sharti	return (NEXT_OBJECT_OID(&t->table, idx, sub));
503124861Sharti}
504124861Sharti
505124861Sharti/*
506124861Sharti * Return first port
507124861Sharti */
508124861Shartistruct tport *
509124861Shartitrans_first_port(struct transport *t)
510124861Sharti{
511124861Sharti
512124861Sharti	return (TAILQ_FIRST(&t->table));
513124861Sharti}
514124861Sharti
515124861Sharti/*
516124861Sharti * Iterate through all ports until a function returns a 0.
517124861Sharti */
518124861Shartistruct tport *
519124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t),
520124861Sharti    intptr_t arg)
521124861Sharti{
522124861Sharti	struct tport *p;
523124861Sharti
524124861Sharti	TAILQ_FOREACH(p, &t->table, link)
525124861Sharti		if (func(p, arg) == 0)
526124861Sharti			return (p);
527124861Sharti	return (NULL);
528124861Sharti}
529124861Sharti
530124861Sharti/*
531124861Sharti * Register a transport
532124861Sharti */
533124861Shartiint
534124861Shartitrans_register(const struct transport_def *def, struct transport **pp)
535124861Sharti{
536124861Sharti	u_int i;
537124861Sharti	char or_descr[256];
538124861Sharti
539124861Sharti	if ((*pp = malloc(sizeof(**pp))) == NULL)
540124861Sharti		return (SNMP_ERR_GENERR);
541124861Sharti
542124861Sharti	/* construct index */
543124861Sharti	(*pp)->index.len = strlen(def->name) + 1;
544124861Sharti	(*pp)->index.subs[0] = strlen(def->name);
545124861Sharti	for (i = 0; i < (*pp)->index.subs[0]; i++)
546124861Sharti		(*pp)->index.subs[i + 1] = def->name[i];
547124861Sharti
548124861Sharti	(*pp)->vtab = def;
549124861Sharti
550124861Sharti	if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) {
551124861Sharti		free(*pp);
552124861Sharti		return (SNMP_ERR_INCONS_VALUE);
553124861Sharti	}
554124861Sharti
555124861Sharti	/* register module */
556124861Sharti	snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name);
557124861Sharti	if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) {
558124861Sharti		free(*pp);
559124861Sharti		return (SNMP_ERR_GENERR);
560124861Sharti	}
561124861Sharti
562124861Sharti	INSERT_OBJECT_OID((*pp), &transport_list);
563124861Sharti
564124861Sharti	TAILQ_INIT(&(*pp)->table);
565124861Sharti
566124861Sharti	return (SNMP_ERR_NOERROR);
567124861Sharti}
568124861Sharti
569124861Sharti/*
570124861Sharti * Unregister transport
571124861Sharti */
572124861Shartiint
573124861Shartitrans_unregister(struct transport *t)
574124861Sharti{
575124861Sharti	if (!TAILQ_EMPTY(&t->table))
576124861Sharti		return (SNMP_ERR_INCONS_VALUE);
577124861Sharti
578124861Sharti	or_unregister(t->or_index);
579124861Sharti	TAILQ_REMOVE(&transport_list, t, link);
580124861Sharti
581124861Sharti	return (SNMP_ERR_NOERROR);
582124861Sharti}
583124861Sharti
584124861Sharti/*
585122394Sharti * File descriptor support
586122394Sharti */
587124861Sharti#ifdef USE_LIBBEGEMOT
588122394Shartistatic void
589124861Shartiinput(int fd, int mask __unused, void *uap)
590124861Sharti#else
591124861Shartistatic void
592122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused)
593124861Sharti#endif
594122394Sharti{
595122394Sharti	struct fdesc *f = uap;
596122394Sharti
597122394Sharti	(*f->func)(fd, f->udata);
598122394Sharti}
599122394Sharti
600122394Shartivoid
601122394Shartifd_suspend(void *p)
602122394Sharti{
603122394Sharti	struct fdesc *f = p;
604122394Sharti
605124861Sharti#ifdef USE_LIBBEGEMOT
606124861Sharti	if (f->id >= 0) {
607124861Sharti		poll_unregister(f->id);
608124861Sharti		f->id = -1;
609124861Sharti	}
610124861Sharti#else
611122394Sharti	if (evTestID(f->id)) {
612122394Sharti		(void)evDeselectFD(evctx, f->id);
613122394Sharti		evInitID(&f->id);
614122394Sharti	}
615124861Sharti#endif
616122394Sharti}
617122394Sharti
618122394Shartiint
619122394Shartifd_resume(void *p)
620122394Sharti{
621122394Sharti	struct fdesc *f = p;
622122394Sharti	int err;
623122394Sharti
624124861Sharti#ifdef USE_LIBBEGEMOT
625124861Sharti	if (f->id >= 0)
626124861Sharti		return (0);
627142810Sharti	if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) {
628124861Sharti		err = errno;
629124861Sharti		syslog(LOG_ERR, "select fd %d: %m", f->fd);
630124861Sharti		errno = err;
631124861Sharti		return (-1);
632124861Sharti	}
633124861Sharti#else
634122394Sharti	if (evTestID(f->id))
635122394Sharti		return (0);
636122394Sharti	if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) {
637122394Sharti		err = errno;
638122394Sharti		syslog(LOG_ERR, "select fd %d: %m", f->fd);
639122394Sharti		errno = err;
640122394Sharti		return (-1);
641122394Sharti	}
642124861Sharti#endif
643122394Sharti	return (0);
644122394Sharti}
645122394Sharti
646122394Shartivoid *
647122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod)
648122394Sharti{
649122394Sharti	struct fdesc *f;
650122394Sharti	int err;
651122394Sharti
652122394Sharti	if ((f = malloc(sizeof(struct fdesc))) == NULL) {
653122394Sharti		err = errno;
654122394Sharti		syslog(LOG_ERR, "fd_select: %m");
655122394Sharti		errno = err;
656122394Sharti		return (NULL);
657122394Sharti	}
658122394Sharti	f->fd = fd;
659122394Sharti	f->func = func;
660122394Sharti	f->udata = udata;
661122394Sharti	f->owner = mod;
662124861Sharti#ifdef USE_LIBBEGEMOT
663124861Sharti	f->id = -1;
664124861Sharti#else
665122394Sharti	evInitID(&f->id);
666124861Sharti#endif
667122394Sharti
668122394Sharti	if (fd_resume(f)) {
669122394Sharti		err = errno;
670122394Sharti		free(f);
671122394Sharti		errno = err;
672122394Sharti		return (NULL);
673122394Sharti	}
674122394Sharti
675122394Sharti	LIST_INSERT_HEAD(&fdesc_list, f, link);
676122394Sharti
677122394Sharti	return (f);
678122394Sharti}
679122394Sharti
680122394Shartivoid
681122394Shartifd_deselect(void *p)
682122394Sharti{
683122394Sharti	struct fdesc *f = p;
684122394Sharti
685122394Sharti	LIST_REMOVE(f, link);
686122394Sharti	fd_suspend(f);
687122394Sharti	free(f);
688122394Sharti}
689122394Sharti
690122394Shartistatic void
691122394Shartifd_flush(struct lmodule *mod)
692122394Sharti{
693122394Sharti	struct fdesc *t, *t1;
694122394Sharti
695122394Sharti	t = LIST_FIRST(&fdesc_list);
696122394Sharti	while (t != NULL) {
697122394Sharti		t1 = LIST_NEXT(t, link);
698122394Sharti		if (t->owner == mod)
699122394Sharti			fd_deselect(t);
700122394Sharti		t = t1;
701122394Sharti	}
702122394Sharti}
703122394Sharti
704122394Sharti/*
705124861Sharti * Consume a message from the input buffer
706122394Sharti */
707122394Shartistatic void
708124861Shartisnmp_input_consume(struct port_input *pi)
709122394Sharti{
710124861Sharti	if (!pi->stream) {
711124861Sharti		/* always consume everything */
712124861Sharti		pi->length = 0;
713122394Sharti		return;
714122394Sharti	}
715124861Sharti	if (pi->consumed >= pi->length) {
716124861Sharti		/* all bytes consumed */
717124861Sharti		pi->length = 0;
718122394Sharti		return;
719122394Sharti	}
720124861Sharti	memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed);
721124861Sharti	pi->length -= pi->consumed;
722124861Sharti}
723124861Sharti
724124861Shartistruct credmsg {
725124861Sharti	struct cmsghdr hdr;
726124861Sharti	struct cmsgcred cred;
727124861Sharti};
728124861Sharti
729124861Shartistatic void
730124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg)
731124861Sharti{
732124861Sharti	struct credmsg *cmsg;
733124861Sharti	struct xucred ucred;
734124861Sharti	socklen_t ucredlen;
735124861Sharti
736124861Sharti	pi->priv = 0;
737124861Sharti
738124861Sharti	if (msg->msg_controllen == sizeof(*cmsg)) {
739150920Sharti		/* process explicitly sends credentials */
740124861Sharti
741124861Sharti		cmsg = (struct credmsg *)msg->msg_control;
742124861Sharti		pi->priv = (cmsg->cred.cmcred_euid == 0);
743122394Sharti		return;
744122394Sharti	}
745124861Sharti
746124861Sharti	/* ok, obtain the accept time credentials */
747124861Sharti	ucredlen = sizeof(ucred);
748124861Sharti
749124861Sharti	if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 &&
750124861Sharti	    ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION)
751124861Sharti		pi->priv = (ucred.cr_uid == 0);
752124861Sharti}
753124861Sharti
754124861Sharti/*
755124861Sharti * Input from a stream socket.
756124861Sharti */
757124861Shartistatic int
758124861Shartirecv_stream(struct port_input *pi)
759124861Sharti{
760124861Sharti	struct msghdr msg;
761124861Sharti	struct iovec iov[1];
762124861Sharti	ssize_t len;
763124861Sharti	struct credmsg cmsg;
764124861Sharti
765124861Sharti	if (pi->buf == NULL) {
766124861Sharti		/* no buffer yet - allocate one */
767124861Sharti		if ((pi->buf = buf_alloc(0)) == NULL) {
768124861Sharti			/* ups - could not get buffer. Return an error
769124861Sharti			 * the caller must close the transport. */
770124861Sharti			return (-1);
771124861Sharti		}
772124861Sharti		pi->buflen = buf_size(0);
773124861Sharti		pi->consumed = 0;
774124861Sharti		pi->length = 0;
775124861Sharti	}
776124861Sharti
777124861Sharti	/* try to get a message */
778124861Sharti	msg.msg_name = pi->peer;
779124861Sharti	msg.msg_namelen = pi->peerlen;
780124861Sharti	msg.msg_iov = iov;
781124861Sharti	msg.msg_iovlen = 1;
782124861Sharti	if (pi->cred) {
783124861Sharti		msg.msg_control = &cmsg;
784124861Sharti		msg.msg_controllen = sizeof(cmsg);
785124861Sharti
786124861Sharti		cmsg.hdr.cmsg_len = sizeof(cmsg);
787124861Sharti		cmsg.hdr.cmsg_level = SOL_SOCKET;
788124861Sharti		cmsg.hdr.cmsg_type = SCM_CREDS;
789124861Sharti	} else {
790124861Sharti		msg.msg_control = NULL;
791124861Sharti		msg.msg_controllen = 0;
792124861Sharti	}
793124861Sharti	msg.msg_flags = 0;
794124861Sharti
795124861Sharti	iov[0].iov_base = pi->buf + pi->length;
796124861Sharti	iov[0].iov_len = pi->buflen - pi->length;
797124861Sharti
798124861Sharti	len = recvmsg(pi->fd, &msg, 0);
799124861Sharti
800124861Sharti	if (len == -1 || len == 0)
801124861Sharti		/* receive error */
802124861Sharti		return (-1);
803124861Sharti
804124861Sharti	pi->length += len;
805124861Sharti
806124861Sharti	if (pi->cred)
807124861Sharti		check_priv(pi, &msg);
808124861Sharti
809124861Sharti	return (0);
810124861Sharti}
811124861Sharti
812124861Sharti/*
813124861Sharti * Input from a datagram socket.
814124861Sharti * Each receive should return one datagram.
815124861Sharti */
816124861Shartistatic int
817124861Shartirecv_dgram(struct port_input *pi)
818124861Sharti{
819124861Sharti	u_char embuf[1000];
820124861Sharti	struct msghdr msg;
821124861Sharti	struct iovec iov[1];
822124861Sharti	ssize_t len;
823124861Sharti	struct credmsg cmsg;
824124861Sharti
825124861Sharti	if (pi->buf == NULL) {
826124861Sharti		/* no buffer yet - allocate one */
827124861Sharti		if ((pi->buf = buf_alloc(0)) == NULL) {
828124861Sharti			/* ups - could not get buffer. Read away input
829124861Sharti			 * and drop it */
830124861Sharti			(void)recvfrom(pi->fd, embuf, sizeof(embuf),
831124861Sharti			    0, NULL, NULL);
832124861Sharti			/* return error */
833124861Sharti			return (-1);
834124861Sharti		}
835124861Sharti		pi->buflen = buf_size(0);
836124861Sharti	}
837124861Sharti
838124861Sharti	/* try to get a message */
839124861Sharti	msg.msg_name = pi->peer;
840124861Sharti	msg.msg_namelen = pi->peerlen;
841124861Sharti	msg.msg_iov = iov;
842124861Sharti	msg.msg_iovlen = 1;
843124861Sharti	if (pi->cred) {
844124861Sharti		msg.msg_control = &cmsg;
845124861Sharti		msg.msg_controllen = sizeof(cmsg);
846124861Sharti
847124861Sharti		cmsg.hdr.cmsg_len = sizeof(cmsg);
848124861Sharti		cmsg.hdr.cmsg_level = SOL_SOCKET;
849124861Sharti		cmsg.hdr.cmsg_type = SCM_CREDS;
850124861Sharti	} else {
851124861Sharti		msg.msg_control = NULL;
852128237Sharti		msg.msg_controllen = 0;
853124861Sharti	}
854124861Sharti	msg.msg_flags = 0;
855124861Sharti
856124861Sharti	iov[0].iov_base = pi->buf;
857124861Sharti	iov[0].iov_len = pi->buflen;
858124861Sharti
859124861Sharti	len = recvmsg(pi->fd, &msg, 0);
860124861Sharti
861124861Sharti	if (len == -1 || len == 0)
862124861Sharti		/* receive error */
863124861Sharti		return (-1);
864124861Sharti
865124861Sharti	if (msg.msg_flags & MSG_TRUNC) {
866124861Sharti		/* truncated - drop */
867122394Sharti		snmpd_stats.silentDrops++;
868122394Sharti		snmpd_stats.inTooLong++;
869124861Sharti		return (-1);
870122394Sharti	}
871122394Sharti
872124861Sharti	pi->length = (size_t)len;
873124861Sharti
874124861Sharti	if (pi->cred)
875124861Sharti		check_priv(pi, &msg);
876124861Sharti
877124861Sharti	return (0);
878124861Sharti}
879124861Sharti
880124861Sharti/*
881124861Sharti * Input from a socket
882124861Sharti */
883124861Shartiint
884124861Shartisnmpd_input(struct port_input *pi, struct tport *tport)
885124861Sharti{
886124861Sharti	u_char *sndbuf;
887124861Sharti	size_t sndlen;
888124861Sharti	struct snmp_pdu pdu;
889124861Sharti	enum snmpd_input_err ierr, ferr;
890124861Sharti	enum snmpd_proxy_err perr;
891124861Sharti	int32_t vi;
892124861Sharti	int ret;
893124861Sharti	ssize_t slen;
894145557Sharti#ifdef USE_TCPWRAPPERS
895145557Sharti	char client[16];
896145557Sharti#endif
897124861Sharti
898124861Sharti	/* get input depending on the transport */
899124861Sharti	if (pi->stream) {
900124861Sharti		ret = recv_stream(pi);
901124861Sharti	} else {
902124861Sharti		ret = recv_dgram(pi);
903124861Sharti	}
904124861Sharti
905124861Sharti	if (ret == -1)
906124861Sharti		return (-1);
907124861Sharti
908145557Sharti#ifdef USE_TCPWRAPPERS
909122394Sharti	/*
910145557Sharti	 * In case of AF_INET{6} peer, do hosts_access(5) check.
911145557Sharti	 */
912145557Sharti	if (inet_ntop(pi->peer->sa_family,
913146525Sharti	    &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr,
914146525Sharti	    client, sizeof(client)) != NULL) {
915145557Sharti		request_set(&req, RQ_CLIENT_ADDR, client, 0);
916145557Sharti		if (hosts_access(&req) == 0) {
917145557Sharti			syslog(LOG_ERR, "refused connection from %.500s",
918145557Sharti			    eval_client(&req));
919145557Sharti			return (-1);
920145557Sharti		}
921145557Sharti	} else
922145557Sharti		syslog(LOG_ERR, "inet_ntop(): %m");
923145557Sharti#endif
924145557Sharti
925145557Sharti	/*
926122394Sharti	 * Handle input
927122394Sharti	 */
928124861Sharti	ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi,
929124861Sharti	    &pi->consumed);
930124861Sharti	if (ierr == SNMPD_INPUT_TRUNC) {
931124861Sharti		/* need more bytes. This is ok only for streaming transports.
932124861Sharti		 * but only if we have not reached bufsiz yet. */
933124861Sharti		if (pi->stream) {
934124861Sharti			if (pi->length == buf_size(0)) {
935124861Sharti				snmpd_stats.silentDrops++;
936124861Sharti				return (-1);
937124861Sharti			}
938124861Sharti			return (0);
939124861Sharti		}
940124861Sharti		snmpd_stats.silentDrops++;
941124861Sharti		return (-1);
942124861Sharti	}
943122394Sharti
944122394Sharti	/* can't check for bad SET pdus here, because a proxy may have to
945122394Sharti	 * check the access first. We don't want to return an error response
946122394Sharti	 * to a proxy PDU with a wrong community */
947122394Sharti	if (ierr == SNMPD_INPUT_FAILED) {
948124861Sharti		/* for streaming transports this is fatal */
949124861Sharti		if (pi->stream)
950124861Sharti			return (-1);
951124861Sharti		snmp_input_consume(pi);
952124861Sharti		return (0);
953122394Sharti	}
954133211Sharti	if (ierr == SNMPD_INPUT_BAD_COMM) {
955133211Sharti		snmp_input_consume(pi);
956133211Sharti		return (0);
957133211Sharti	}
958122394Sharti
959122394Sharti	/*
960122394Sharti	 * If that is a module community and the module has a proxy function,
961122394Sharti	 * the hand it over to the module.
962122394Sharti	 */
963122394Sharti	if (comm->owner != NULL && comm->owner->config->proxy != NULL) {
964124861Sharti		perr = (*comm->owner->config->proxy)(&pdu, tport->transport,
965133211Sharti		    &tport->index, pi->peer, pi->peerlen, ierr, vi,
966133211Sharti		    !pi->cred || pi->priv);
967122394Sharti
968122394Sharti		switch (perr) {
969122394Sharti
970122394Sharti		  case SNMPD_PROXY_OK:
971124861Sharti			snmp_input_consume(pi);
972124861Sharti			return (0);
973122394Sharti
974122394Sharti		  case SNMPD_PROXY_REJ:
975122394Sharti			break;
976122394Sharti
977122394Sharti		  case SNMPD_PROXY_DROP:
978124861Sharti			snmp_input_consume(pi);
979122394Sharti			snmp_pdu_free(&pdu);
980122394Sharti			snmpd_stats.proxyDrops++;
981124861Sharti			return (0);
982122394Sharti
983122394Sharti		  case SNMPD_PROXY_BADCOMM:
984124861Sharti			snmp_input_consume(pi);
985122394Sharti			snmp_pdu_free(&pdu);
986122394Sharti			snmpd_stats.inBadCommunityNames++;
987122394Sharti			if (snmpd.auth_traps)
988122394Sharti				snmp_send_trap(&oid_authenticationFailure,
989133211Sharti				    (struct snmp_value *)NULL);
990124861Sharti			return (0);
991122394Sharti
992122394Sharti		  case SNMPD_PROXY_BADCOMMUSE:
993124861Sharti			snmp_input_consume(pi);
994122394Sharti			snmp_pdu_free(&pdu);
995122394Sharti			snmpd_stats.inBadCommunityUses++;
996122394Sharti			if (snmpd.auth_traps)
997122394Sharti				snmp_send_trap(&oid_authenticationFailure,
998133211Sharti				    (struct snmp_value *)NULL);
999124861Sharti			return (0);
1000122394Sharti		}
1001122394Sharti	}
1002122394Sharti
1003122394Sharti	/*
1004122394Sharti	 * Check type
1005122394Sharti	 */
1006122394Sharti	if (pdu.type == SNMP_PDU_RESPONSE ||
1007122394Sharti	    pdu.type == SNMP_PDU_TRAP ||
1008122394Sharti	    pdu.type == SNMP_PDU_TRAP2) {
1009122394Sharti		snmpd_stats.silentDrops++;
1010122394Sharti		snmpd_stats.inBadPduTypes++;
1011122394Sharti		snmp_pdu_free(&pdu);
1012124861Sharti		snmp_input_consume(pi);
1013124861Sharti		return (0);
1014122394Sharti	}
1015122394Sharti
1016122394Sharti	/*
1017122394Sharti	 * Check community
1018122394Sharti	 */
1019124861Sharti	if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) ||
1020124861Sharti	    (community != COMM_WRITE &&
1021124861Sharti            (pdu.type == SNMP_PDU_SET || community != COMM_READ))) {
1022122394Sharti		snmpd_stats.inBadCommunityUses++;
1023122394Sharti		snmp_pdu_free(&pdu);
1024124861Sharti		snmp_input_consume(pi);
1025122394Sharti		if (snmpd.auth_traps)
1026133211Sharti			snmp_send_trap(&oid_authenticationFailure,
1027133211Sharti			    (struct snmp_value *)NULL);
1028124861Sharti		return (0);
1029122394Sharti	}
1030122394Sharti
1031122394Sharti	/*
1032122394Sharti	 * Execute it.
1033122394Sharti	 */
1034122394Sharti	if ((sndbuf = buf_alloc(1)) == NULL) {
1035122394Sharti		snmpd_stats.silentDrops++;
1036122394Sharti		snmp_pdu_free(&pdu);
1037124861Sharti		snmp_input_consume(pi);
1038124861Sharti		return (0);
1039122394Sharti	}
1040124861Sharti	ferr = snmp_input_finish(&pdu, pi->buf, pi->length,
1041124861Sharti	    sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
1042122394Sharti
1043122394Sharti	if (ferr == SNMPD_INPUT_OK) {
1044124861Sharti		slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen);
1045124861Sharti		if (slen == -1)
1046122394Sharti			syslog(LOG_ERR, "sendto: %m");
1047124861Sharti		else if ((size_t)slen != sndlen)
1048122394Sharti			syslog(LOG_ERR, "sendto: short write %zu/%zu",
1049124861Sharti			    sndlen, (size_t)slen);
1050122394Sharti	}
1051122394Sharti	snmp_pdu_free(&pdu);
1052122394Sharti	free(sndbuf);
1053124861Sharti	snmp_input_consume(pi);
1054122394Sharti
1055124861Sharti	return (0);
1056122394Sharti}
1057122394Sharti
1058122394Sharti/*
1059124861Sharti * Send a PDU to a given port
1060122394Sharti */
1061124861Shartivoid
1062124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
1063124861Sharti    const struct sockaddr *addr, socklen_t addrlen)
1064122394Sharti{
1065124861Sharti	struct transport *trans = targ;
1066124861Sharti	struct tport *tp;
1067124861Sharti	u_char *sndbuf;
1068124861Sharti	size_t sndlen;
1069124861Sharti	ssize_t len;
1070122394Sharti
1071124861Sharti	TAILQ_FOREACH(tp, &trans->table, link)
1072124861Sharti		if (asn_compare_oid(port, &tp->index) == 0)
1073122394Sharti			break;
1074124861Sharti	if (tp == 0)
1075124861Sharti		return;
1076122394Sharti
1077124861Sharti	if ((sndbuf = buf_alloc(1)) == NULL)
1078124861Sharti		return;
1079122394Sharti
1080124861Sharti	snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
1081122394Sharti
1082124861Sharti	len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
1083122394Sharti
1084124861Sharti	if (len == -1)
1085124861Sharti		syslog(LOG_ERR, "sendto: %m");
1086124861Sharti	else if ((size_t)len != sndlen)
1087124861Sharti		syslog(LOG_ERR, "sendto: short write %zu/%zu",
1088124861Sharti		    sndlen, (size_t)len);
1089122394Sharti
1090124861Sharti	free(sndbuf);
1091122394Sharti}
1092122394Sharti
1093122394Sharti
1094122394Sharti/*
1095124861Sharti * Close an input source
1096122394Sharti */
1097122394Shartivoid
1098124861Shartisnmpd_input_close(struct port_input *pi)
1099122394Sharti{
1100124861Sharti	if (pi->id != NULL)
1101124861Sharti		fd_deselect(pi->id);
1102124861Sharti	if (pi->fd >= 0)
1103124861Sharti		(void)close(pi->fd);
1104124861Sharti	if (pi->buf != NULL)
1105124861Sharti		free(pi->buf);
1106122394Sharti}
1107122394Sharti
1108122394Sharti/*
1109122394Sharti * Dump internal state.
1110122394Sharti */
1111124861Sharti#ifdef USE_LIBBEGEMOT
1112122394Shartistatic void
1113124861Shartiinfo_func(void)
1114124861Sharti#else
1115124861Shartistatic void
1116122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused)
1117124861Sharti#endif
1118122394Sharti{
1119122394Sharti	struct lmodule *m;
1120122394Sharti	u_int i;
1121122394Sharti	char buf[10000];
1122122394Sharti
1123122394Sharti	syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());
1124122394Sharti	for (i = 0; i < tree_size; i++) {
1125122394Sharti		switch (tree[i].type) {
1126122394Sharti
1127122394Sharti		  case SNMP_NODE_LEAF:
1128122394Sharti			sprintf(buf, "LEAF: %s %s", tree[i].name,
1129122394Sharti			    asn_oid2str(&tree[i].oid));
1130122394Sharti			break;
1131122394Sharti
1132122394Sharti		  case SNMP_NODE_COLUMN:
1133122394Sharti			sprintf(buf, "COL: %s %s", tree[i].name,
1134122394Sharti			    asn_oid2str(&tree[i].oid));
1135122394Sharti			break;
1136122394Sharti		}
1137122394Sharti		syslog(LOG_DEBUG, "%s", buf);
1138122394Sharti	}
1139122394Sharti
1140122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
1141122394Sharti		if (m->config->dump)
1142122394Sharti			(*m->config->dump)();
1143122394Sharti}
1144122394Sharti
1145122394Sharti/*
1146122394Sharti * Re-read configuration
1147122394Sharti */
1148124861Sharti#ifdef USE_LIBBEGEMOT
1149122394Shartistatic void
1150124861Sharticonfig_func(void)
1151124861Sharti#else
1152124861Shartistatic void
1153122394Sharticonfig_func(evContext ctx __unused, void *uap __unused,
1154122394Sharti    const void *tag __unused)
1155124861Sharti#endif
1156122394Sharti{
1157122394Sharti	struct lmodule *m;
1158122394Sharti
1159122394Sharti	if (read_config(config_file, NULL)) {
1160122394Sharti		syslog(LOG_ERR, "error reading config file '%s'", config_file);
1161122394Sharti		return;
1162122394Sharti	}
1163122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
1164122394Sharti		if (m->config->config)
1165122394Sharti			(*m->config->config)();
1166122394Sharti}
1167122394Sharti
1168122394Sharti/*
1169122394Sharti * On USR1 dump actual configuration.
1170122394Sharti */
1171122394Shartistatic void
1172122394Shartionusr1(int s __unused)
1173122394Sharti{
1174124861Sharti
1175122394Sharti	work |= WORK_DOINFO;
1176122394Sharti}
1177122394Shartistatic void
1178122394Shartionhup(int s __unused)
1179122394Sharti{
1180124861Sharti
1181122394Sharti	work |= WORK_RECONFIG;
1182122394Sharti}
1183122394Sharti
1184122394Shartistatic void
1185122394Shartionterm(int s __unused)
1186122394Sharti{
1187122394Sharti
1188124861Sharti	/* allow clean-up */
1189122394Sharti	exit(0);
1190122394Sharti}
1191122394Sharti
1192122394Shartistatic void
1193122394Shartiinit_sigs(void)
1194122394Sharti{
1195122394Sharti	struct sigaction sa;
1196122394Sharti
1197122394Sharti	sa.sa_handler = onusr1;
1198122394Sharti	sa.sa_flags = SA_RESTART;
1199122394Sharti	sigemptyset(&sa.sa_mask);
1200122394Sharti	if (sigaction(SIGUSR1, &sa, NULL)) {
1201122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1202122394Sharti		exit(1);
1203122394Sharti	}
1204122394Sharti
1205122394Sharti	sa.sa_handler = onhup;
1206122394Sharti	if (sigaction(SIGHUP, &sa, NULL)) {
1207122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1208122394Sharti		exit(1);
1209122394Sharti	}
1210122394Sharti
1211122394Sharti	sa.sa_handler = onterm;
1212122394Sharti	sa.sa_flags = 0;
1213122394Sharti	sigemptyset(&sa.sa_mask);
1214122394Sharti	if (sigaction(SIGTERM, &sa, NULL)) {
1215122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1216122394Sharti		exit(1);
1217122394Sharti	}
1218122394Sharti	if (sigaction(SIGINT, &sa, NULL)) {
1219122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1220122394Sharti		exit(1);
1221122394Sharti	}
1222122394Sharti}
1223122394Sharti
1224122394Shartistatic void
1225122394Shartiblock_sigs(void)
1226122394Sharti{
1227122394Sharti	sigset_t set;
1228122394Sharti
1229122394Sharti	sigfillset(&set);
1230122394Sharti	if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) {
1231122394Sharti		syslog(LOG_ERR, "SIG_BLOCK: %m");
1232122394Sharti		exit(1);
1233122394Sharti	}
1234122394Sharti}
1235122394Shartistatic void
1236122394Shartiunblock_sigs(void)
1237122394Sharti{
1238122394Sharti	if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) {
1239122394Sharti		syslog(LOG_ERR, "SIG_SETMASK: %m");
1240122394Sharti		exit(1);
1241122394Sharti	}
1242122394Sharti}
1243122394Sharti
1244122394Sharti/*
1245122394Sharti * Shut down
1246122394Sharti */
1247122394Shartistatic void
1248122394Shartiterm(void)
1249122394Sharti{
1250122394Sharti	(void)unlink(pid_file);
1251122394Sharti}
1252122394Sharti
1253124861Shartistatic void
1254124861Shartitrans_stop(void)
1255124861Sharti{
1256124861Sharti	struct transport *t;
1257124861Sharti
1258124861Sharti	TAILQ_FOREACH(t, &transport_list, link)
1259124861Sharti		(void)t->vtab->stop(1);
1260124861Sharti}
1261124861Sharti
1262122394Sharti/*
1263122394Sharti * Define a macro from the command line
1264122394Sharti */
1265122394Shartistatic void
1266122394Shartido_macro(char *arg)
1267122394Sharti{
1268122394Sharti	char *eq;
1269122394Sharti	int err;
1270122394Sharti
1271122394Sharti	if ((eq = strchr(arg, '=')) == NULL)
1272122394Sharti		err = define_macro(arg, "");
1273122394Sharti	else {
1274122394Sharti		*eq++ = '\0';
1275122394Sharti		err = define_macro(arg, eq);
1276122394Sharti	}
1277122394Sharti	if (err == -1) {
1278122394Sharti		syslog(LOG_ERR, "cannot save macro: %m");
1279122394Sharti		exit(1);
1280122394Sharti	}
1281122394Sharti}
1282122394Sharti
1283122394Sharti/*
1284122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken
1285122394Sharti * and will not compile with WARNS=5.
1286122394Sharti */
1287122394Shartistatic int
1288122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp)
1289122394Sharti{
1290122394Sharti	static const char *const delim = ",\t ";
1291122394Sharti	u_int i;
1292122394Sharti	char *ptr;
1293122394Sharti
1294122394Sharti	*optp = NULL;
1295122394Sharti
1296122394Sharti	/* skip leading junk */
1297122394Sharti	for (ptr = *arg; *ptr != '\0'; ptr++)
1298122394Sharti		if (strchr(delim, *ptr) == NULL)
1299122394Sharti			break;
1300122394Sharti	if (*ptr == '\0') {
1301122394Sharti		*arg = ptr;
1302122394Sharti		return (-1);
1303122394Sharti	}
1304122394Sharti	*optp = ptr;
1305122394Sharti
1306122394Sharti	/* find the end of the option */
1307122394Sharti	while (*++ptr != '\0')
1308122394Sharti		if (strchr(delim, *ptr) != NULL || *ptr == '=')
1309122394Sharti			break;
1310122394Sharti
1311122394Sharti	if (*ptr != '\0') {
1312122394Sharti		if (*ptr == '=') {
1313122394Sharti			*ptr++ = '\0';
1314122394Sharti			*valp = ptr;
1315122394Sharti			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
1316122394Sharti				ptr++;
1317122394Sharti			if (*ptr != '\0')
1318122394Sharti				*ptr++ = '\0';
1319122394Sharti		} else
1320122394Sharti			*ptr++ = '\0';
1321122394Sharti	}
1322122394Sharti
1323122394Sharti	*arg = ptr;
1324122394Sharti
1325122394Sharti	for (i = 0; *options != NULL; options++, i++)
1326124861Sharti		if (strcmp(*optp, *options) == 0)
1327122394Sharti			return (i);
1328122394Sharti	return (-1);
1329122394Sharti}
1330122394Sharti
1331122394Shartiint
1332122394Shartimain(int argc, char *argv[])
1333122394Sharti{
1334122394Sharti	int opt;
1335122394Sharti	FILE *fp;
1336122394Sharti	int background = 1;
1337124861Sharti	struct tport *p;
1338122394Sharti	const char *prefix = "snmpd";
1339122394Sharti	struct lmodule *m;
1340122394Sharti	char *value, *option;
1341124861Sharti	struct transport *t;
1342122394Sharti
1343122394Sharti#define DBG_DUMP	0
1344122394Sharti#define DBG_EVENTS	1
1345122394Sharti#define DBG_TRACE	2
1346122394Sharti	static const char *const debug_opts[] = {
1347122394Sharti		"dump",
1348122394Sharti		"events",
1349122394Sharti		"trace",
1350122394Sharti		NULL
1351122394Sharti	};
1352122394Sharti
1353122394Sharti	snmp_printf = snmp_printf_func;
1354122394Sharti	snmp_error = snmp_error_func;
1355122394Sharti	snmp_debug = snmp_debug_func;
1356122394Sharti	asn_error = asn_error_func;
1357122394Sharti
1358122394Sharti	while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF)
1359122394Sharti		switch (opt) {
1360122394Sharti
1361122394Sharti		  case 'c':
1362122394Sharti			strlcpy(config_file, optarg, sizeof(config_file));
1363122394Sharti			break;
1364122394Sharti
1365122394Sharti		  case 'd':
1366122394Sharti			background = 0;
1367122394Sharti			break;
1368122394Sharti
1369122394Sharti		  case 'D':
1370122394Sharti			while (*optarg) {
1371122394Sharti				switch (getsubopt1(&optarg, debug_opts,
1372122394Sharti				    &value, &option)) {
1373122394Sharti
1374122394Sharti				  case DBG_DUMP:
1375122394Sharti					debug.dump_pdus = 1;
1376122394Sharti					break;
1377122394Sharti
1378122394Sharti				  case DBG_EVENTS:
1379122394Sharti					debug.evdebug++;
1380122394Sharti					break;
1381122394Sharti
1382122394Sharti				  case DBG_TRACE:
1383122394Sharti					if (value == NULL)
1384122394Sharti						syslog(LOG_ERR,
1385122394Sharti						    "no value for 'trace'");
1386155094Sharti					else
1387156066Sharti						snmp_trace = strtoul(value,
1388156066Sharti						    NULL, 0);
1389122394Sharti					break;
1390122394Sharti
1391122394Sharti				  case -1:
1392122394Sharti					if (suboptarg)
1393122394Sharti						syslog(LOG_ERR,
1394122394Sharti						    "unknown debug flag '%s'",
1395122394Sharti						    option);
1396122394Sharti					else
1397122394Sharti						syslog(LOG_ERR,
1398122394Sharti						    "missing debug flag");
1399122394Sharti					break;
1400122394Sharti				}
1401122394Sharti			}
1402122394Sharti			break;
1403122394Sharti
1404122394Sharti		  case 'h':
1405122394Sharti			fprintf(stderr, "%s", usgtxt);
1406122394Sharti			exit(0);
1407122394Sharti
1408122394Sharti		  case 'I':
1409122394Sharti			syspath = optarg;
1410122394Sharti			break;
1411122394Sharti
1412122394Sharti		  case 'l':
1413122394Sharti			prefix = optarg;
1414122394Sharti			break;
1415122394Sharti
1416122394Sharti		  case 'm':
1417122394Sharti			do_macro(optarg);
1418122394Sharti			break;
1419122394Sharti
1420122394Sharti		  case 'p':
1421122394Sharti			strlcpy(pid_file, optarg, sizeof(pid_file));
1422122394Sharti			break;
1423122394Sharti		}
1424122394Sharti
1425122394Sharti	openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
1426122394Sharti	setlogmask(LOG_UPTO(debug.logpri - 1));
1427122394Sharti
1428122394Sharti	if (background && daemon(0, 0) < 0) {
1429122394Sharti		syslog(LOG_ERR, "daemon: %m");
1430122394Sharti		exit(1);
1431122394Sharti	}
1432122394Sharti
1433122394Sharti	argc -= optind;
1434122394Sharti	argv += optind;
1435122394Sharti
1436122394Sharti	progargs = argv;
1437122394Sharti	nprogargs = argc;
1438122394Sharti
1439122394Sharti	srandomdev();
1440122394Sharti
1441122394Sharti	snmp_serial_no = random();
1442122394Sharti
1443145557Sharti#ifdef USE_TCPWRAPPERS
1444122394Sharti	/*
1445145557Sharti	 * Initialize hosts_access(3) handler.
1446145557Sharti	 */
1447145557Sharti	request_init(&req, RQ_DAEMON, "snmpd", 0);
1448145557Sharti	sock_methods(&req);
1449145557Sharti#endif
1450145557Sharti
1451145557Sharti	/*
1452122394Sharti	 * Initialize the tree.
1453122394Sharti	 */
1454122394Sharti	if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) {
1455122394Sharti		syslog(LOG_ERR, "%m");
1456122394Sharti		exit(1);
1457122394Sharti	}
1458122394Sharti	memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE);
1459122394Sharti	tree_size = CTREE_SIZE;
1460122394Sharti
1461122394Sharti	/*
1462122394Sharti	 * Get standard communities
1463122394Sharti	 */
1464154180Sharti	(void)comm_define(1, "SNMP read", NULL, NULL);
1465154180Sharti	(void)comm_define(2, "SNMP write", NULL, NULL);
1466122394Sharti	community = COMM_INITIALIZE;
1467122394Sharti
1468122394Sharti	trap_reqid = reqid_allocate(512, NULL);
1469122394Sharti
1470122394Sharti	if (config_file[0] == '\0')
1471122394Sharti		snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix);
1472122394Sharti
1473122394Sharti	init_actvals();
1474124861Sharti
1475124861Sharti	this_tick = get_ticks();
1476146525Sharti	start_tick = this_tick;
1477124861Sharti
1478124861Sharti	/* start transports */
1479124861Sharti	if (atexit(trans_stop) == -1) {
1480124861Sharti		syslog(LOG_ERR, "atexit failed: %m");
1481124861Sharti		exit(1);
1482124861Sharti	}
1483124861Sharti	if (udp_trans.start() != SNMP_ERR_NOERROR)
1484124861Sharti		syslog(LOG_WARNING, "cannot start UDP transport");
1485124861Sharti	if (lsock_trans.start() != SNMP_ERR_NOERROR)
1486124861Sharti		syslog(LOG_WARNING, "cannot start LSOCK transport");
1487124861Sharti
1488124861Sharti#ifdef USE_LIBBEGEMOT
1489124861Sharti	if (debug.evdebug > 0)
1490124861Sharti		rpoll_trace = 1;
1491124861Sharti#else
1492122394Sharti	if (evCreate(&evctx)) {
1493122394Sharti		syslog(LOG_ERR, "evCreate: %m");
1494122394Sharti		exit(1);
1495122394Sharti	}
1496122394Sharti	if (debug.evdebug > 0)
1497122394Sharti		evSetDebug(evctx, 10, stderr);
1498124861Sharti#endif
1499122394Sharti
1500133211Sharti	if (read_config(config_file, NULL)) {
1501133211Sharti		syslog(LOG_ERR, "error in config file");
1502133211Sharti		exit(1);
1503133211Sharti	}
1504133211Sharti
1505124861Sharti	TAILQ_FOREACH(t, &transport_list, link)
1506124861Sharti		TAILQ_FOREACH(p, &t->table, link)
1507124861Sharti			t->vtab->init_port(p);
1508122394Sharti
1509122394Sharti	init_sigs();
1510122394Sharti
1511122394Sharti	if (pid_file[0] == '\0')
1512122394Sharti		snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix);
1513122394Sharti
1514122394Sharti	if ((fp = fopen(pid_file, "w")) != NULL) {
1515122394Sharti		fprintf(fp, "%u", getpid());
1516122394Sharti		fclose(fp);
1517124861Sharti		if (atexit(term) == -1) {
1518124861Sharti			syslog(LOG_ERR, "atexit failed: %m");
1519124861Sharti			(void)remove(pid_file);
1520124861Sharti			exit(0);
1521124861Sharti		}
1522122394Sharti	}
1523122394Sharti
1524122394Sharti	if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.",
1525122394Sharti	    NULL) == 0) {
1526122394Sharti		syslog(LOG_ERR, "cannot register SNMPv2 MIB");
1527122394Sharti		exit(1);
1528122394Sharti	}
1529122394Sharti	if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.",
1530122394Sharti	    NULL) == 0) {
1531122394Sharti		syslog(LOG_ERR, "cannot register begemotSnmpd MIB");
1532122394Sharti		exit(1);
1533122394Sharti	}
1534122394Sharti
1535133211Sharti	snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL);
1536122394Sharti
1537122394Sharti	while ((m = TAILQ_FIRST(&modules_start)) != NULL) {
1538122394Sharti		m->flags &= ~LM_ONSTARTLIST;
1539122394Sharti		TAILQ_REMOVE(&modules_start, m, start);
1540122394Sharti		lm_start(m);
1541122394Sharti	}
1542122394Sharti
1543122394Sharti	for (;;) {
1544124861Sharti#ifndef USE_LIBBEGEMOT
1545122394Sharti		evEvent event;
1546124861Sharti#endif
1547122394Sharti		struct lmodule *mod;
1548122394Sharti
1549122394Sharti		TAILQ_FOREACH(mod, &lmodules, link)
1550122394Sharti			if (mod->config->idle != NULL)
1551122394Sharti				(*mod->config->idle)();
1552122394Sharti
1553124861Sharti#ifndef USE_LIBBEGEMOT
1554122394Sharti		if (evGetNext(evctx, &event, EV_WAIT) == 0) {
1555122394Sharti			if (evDispatch(evctx, event))
1556122394Sharti				syslog(LOG_ERR, "evDispatch: %m");
1557122394Sharti		} else if (errno != EINTR) {
1558122394Sharti			syslog(LOG_ERR, "evGetNext: %m");
1559122394Sharti			exit(1);
1560122394Sharti		}
1561124861Sharti#else
1562124861Sharti		poll_dispatch(1);
1563124861Sharti#endif
1564122394Sharti
1565122394Sharti		if (work != 0) {
1566122394Sharti			block_sigs();
1567122394Sharti			if (work & WORK_DOINFO) {
1568124861Sharti#ifdef USE_LIBBEGEMOT
1569124861Sharti				info_func();
1570124861Sharti#else
1571122394Sharti				if (evWaitFor(evctx, &work, info_func,
1572122394Sharti				    NULL, NULL) == -1) {
1573122394Sharti					syslog(LOG_ERR, "evWaitFor: %m");
1574122394Sharti					exit(1);
1575122394Sharti				}
1576124861Sharti#endif
1577122394Sharti			}
1578122394Sharti			if (work & WORK_RECONFIG) {
1579124861Sharti#ifdef USE_LIBBEGEMOT
1580124861Sharti				config_func();
1581124861Sharti#else
1582122394Sharti				if (evWaitFor(evctx, &work, config_func,
1583122394Sharti				    NULL, NULL) == -1) {
1584122394Sharti					syslog(LOG_ERR, "evWaitFor: %m");
1585122394Sharti					exit(1);
1586122394Sharti				}
1587124861Sharti#endif
1588122394Sharti			}
1589122394Sharti			work = 0;
1590122394Sharti			unblock_sigs();
1591124861Sharti#ifndef USE_LIBBEGEMOT
1592122394Sharti			if (evDo(evctx, &work) == -1) {
1593122394Sharti				syslog(LOG_ERR, "evDo: %m");
1594122394Sharti				exit(1);
1595122394Sharti			}
1596124861Sharti#endif
1597122394Sharti		}
1598122394Sharti	}
1599122394Sharti
1600122394Sharti	return (0);
1601122394Sharti}
1602122394Sharti
1603146525Shartiuint64_t
1604122394Shartiget_ticks()
1605122394Sharti{
1606122394Sharti	struct timeval tv;
1607146525Sharti	uint64_t ret;
1608122394Sharti
1609122394Sharti	if (gettimeofday(&tv, NULL))
1610122394Sharti		abort();
1611146525Sharti	ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL;
1612122394Sharti	return (ret);
1613122394Sharti}
1614146525Sharti
1615122394Sharti/*
1616122394Sharti * Timer support
1617122394Sharti */
1618150920Sharti
1619150920Sharti/*
1620150920Sharti * Trampoline for the non-repeatable timers.
1621150920Sharti */
1622124861Sharti#ifdef USE_LIBBEGEMOT
1623122394Shartistatic void
1624124861Shartitfunc(int tid __unused, void *uap)
1625124861Sharti#else
1626124861Shartistatic void
1627122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1628122394Sharti	struct timespec inter __unused)
1629124861Sharti#endif
1630122394Sharti{
1631122394Sharti	struct timer *tp = uap;
1632122394Sharti
1633122394Sharti	LIST_REMOVE(tp, link);
1634122394Sharti	tp->func(tp->udata);
1635122394Sharti	free(tp);
1636122394Sharti}
1637122394Sharti
1638122394Sharti/*
1639150920Sharti * Trampoline for the repeatable timers.
1640122394Sharti */
1641150920Sharti#ifdef USE_LIBBEGEMOT
1642150920Shartistatic void
1643150920Shartitrfunc(int tid __unused, void *uap)
1644150920Sharti#else
1645150920Shartistatic void
1646150920Shartitrfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1647150920Sharti	struct timespec inter __unused)
1648150920Sharti#endif
1649150920Sharti{
1650150920Sharti	struct timer *tp = uap;
1651150920Sharti
1652150920Sharti	tp->func(tp->udata);
1653150920Sharti}
1654150920Sharti
1655150920Sharti/*
1656150920Sharti * Start a one-shot timer
1657150920Sharti */
1658122394Shartivoid *
1659122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
1660122394Sharti{
1661122394Sharti	struct timer *tp;
1662145673Sharti#ifndef USE_LIBBEGEMOT
1663122394Sharti	struct timespec due;
1664124861Sharti#endif
1665122394Sharti
1666122394Sharti	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1667122394Sharti		syslog(LOG_CRIT, "out of memory for timer");
1668122394Sharti		exit(1);
1669122394Sharti	}
1670145673Sharti
1671145673Sharti#ifndef USE_LIBBEGEMOT
1672122394Sharti	due = evAddTime(evNowTime(),
1673124861Sharti	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1674124861Sharti#endif
1675122394Sharti
1676122394Sharti	tp->udata = udata;
1677122394Sharti	tp->owner = mod;
1678122394Sharti	tp->func = func;
1679122394Sharti
1680122394Sharti	LIST_INSERT_HEAD(&timer_list, tp, link);
1681122394Sharti
1682124861Sharti#ifdef USE_LIBBEGEMOT
1683145673Sharti	if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) {
1684124861Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1685124861Sharti		exit(1);
1686124861Sharti	}
1687124861Sharti#else
1688122394Sharti	if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
1689122394Sharti	    == -1) {
1690122394Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1691122394Sharti		exit(1);
1692122394Sharti	}
1693124861Sharti#endif
1694122394Sharti	return (tp);
1695122394Sharti}
1696122394Sharti
1697150920Sharti/*
1698150920Sharti * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument
1699150920Sharti * is currently ignored and the initial number of ticks is set to the
1700150920Sharti * repeat number of ticks.
1701150920Sharti */
1702150920Shartivoid *
1703150920Shartitimer_start_repeat(u_int ticks __unused, u_int repeat_ticks,
1704150920Sharti    void (*func)(void *), void *udata, struct lmodule *mod)
1705150920Sharti{
1706150920Sharti	struct timer *tp;
1707150920Sharti#ifndef USE_LIBBEGEMOT
1708150920Sharti	struct timespec due;
1709150920Sharti	struct timespec inter;
1710150920Sharti#endif
1711150920Sharti
1712150920Sharti	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1713150920Sharti		syslog(LOG_CRIT, "out of memory for timer");
1714150920Sharti		exit(1);
1715150920Sharti	}
1716150920Sharti
1717150920Sharti#ifndef USE_LIBBEGEMOT
1718150920Sharti	due = evAddTime(evNowTime(),
1719150920Sharti	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1720150920Sharti	inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000);
1721150920Sharti#endif
1722150920Sharti
1723150920Sharti	tp->udata = udata;
1724150920Sharti	tp->owner = mod;
1725150920Sharti	tp->func = func;
1726150920Sharti
1727150920Sharti	LIST_INSERT_HEAD(&timer_list, tp, link);
1728150920Sharti
1729150920Sharti#ifdef USE_LIBBEGEMOT
1730150920Sharti	if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) {
1731150920Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1732150920Sharti		exit(1);
1733150920Sharti	}
1734150920Sharti#else
1735150920Sharti	if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) {
1736150920Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1737150920Sharti		exit(1);
1738150920Sharti	}
1739150920Sharti#endif
1740150920Sharti	return (tp);
1741150920Sharti}
1742150920Sharti
1743150920Sharti/*
1744150920Sharti * Stop a timer.
1745150920Sharti */
1746122394Shartivoid
1747122394Shartitimer_stop(void *p)
1748122394Sharti{
1749122394Sharti	struct timer *tp = p;
1750122394Sharti
1751122394Sharti	LIST_REMOVE(tp, link);
1752124861Sharti#ifdef USE_LIBBEGEMOT
1753124861Sharti	poll_stop_timer(tp->id);
1754124861Sharti#else
1755122394Sharti	if (evClearTimer(evctx, tp->id) == -1) {
1756122394Sharti		syslog(LOG_ERR, "cannot stop timer: %m");
1757122394Sharti		exit(1);
1758122394Sharti	}
1759124861Sharti#endif
1760122394Sharti	free(p);
1761122394Sharti}
1762122394Sharti
1763122394Shartistatic void
1764122394Shartitimer_flush(struct lmodule *mod)
1765122394Sharti{
1766122394Sharti	struct timer *t, *t1;
1767122394Sharti
1768122394Sharti	t = LIST_FIRST(&timer_list);
1769122394Sharti	while (t != NULL) {
1770122394Sharti		t1 = LIST_NEXT(t, link);
1771122394Sharti		if (t->owner == mod)
1772122394Sharti			timer_stop(t);
1773122394Sharti		t = t1;
1774122394Sharti	}
1775122394Sharti}
1776122394Sharti
1777122394Shartistatic void
1778122394Shartisnmp_printf_func(const char *fmt, ...)
1779122394Sharti{
1780122394Sharti	va_list ap;
1781122394Sharti	static char *pend = NULL;
1782122394Sharti	char *ret, *new;
1783122394Sharti
1784122394Sharti	va_start(ap, fmt);
1785122394Sharti	vasprintf(&ret, fmt, ap);
1786122394Sharti	va_end(ap);
1787122394Sharti
1788122394Sharti	if (ret == NULL)
1789122394Sharti		return;
1790122394Sharti	if (pend != NULL) {
1791122394Sharti		if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1))
1792122394Sharti		    == NULL) {
1793122394Sharti			free(ret);
1794122394Sharti			return;
1795122394Sharti		}
1796122394Sharti		pend = new;
1797122394Sharti		strcat(pend, ret);
1798122394Sharti		free(ret);
1799122394Sharti	} else
1800122394Sharti		pend = ret;
1801122394Sharti
1802122394Sharti	while ((ret = strchr(pend, '\n')) != NULL) {
1803122394Sharti		*ret = '\0';
1804122394Sharti		syslog(LOG_DEBUG, "%s", pend);
1805122394Sharti		if (strlen(ret + 1) == 0) {
1806122394Sharti			free(pend);
1807122394Sharti			pend = NULL;
1808122394Sharti			break;
1809122394Sharti		}
1810122394Sharti		strcpy(pend, ret + 1);
1811122394Sharti	}
1812122394Sharti}
1813122394Sharti
1814122394Shartistatic void
1815122394Shartisnmp_error_func(const char *err, ...)
1816122394Sharti{
1817122394Sharti	char errbuf[1000];
1818122394Sharti	va_list ap;
1819122394Sharti
1820124861Sharti	if (!(snmp_trace & LOG_SNMP_ERRORS))
1821124861Sharti		return;
1822124861Sharti
1823122394Sharti	va_start(ap, err);
1824122394Sharti	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1825124861Sharti	vsnprintf(errbuf + strlen(errbuf),
1826124861Sharti	    sizeof(errbuf) - strlen(errbuf), err, ap);
1827122394Sharti	va_end(ap);
1828122394Sharti
1829122394Sharti	syslog(LOG_ERR, "%s", errbuf);
1830122394Sharti}
1831122394Sharti
1832122394Shartistatic void
1833122394Shartisnmp_debug_func(const char *err, ...)
1834122394Sharti{
1835122394Sharti	char errbuf[1000];
1836122394Sharti	va_list ap;
1837122394Sharti
1838122394Sharti	va_start(ap, err);
1839122394Sharti	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1840122394Sharti	vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf),
1841122394Sharti	    err, ap);
1842122394Sharti	va_end(ap);
1843122394Sharti
1844122394Sharti	syslog(LOG_DEBUG, "%s", errbuf);
1845122394Sharti}
1846122394Sharti
1847122394Shartistatic void
1848122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...)
1849122394Sharti{
1850122394Sharti	char errbuf[1000];
1851122394Sharti	va_list ap;
1852122394Sharti	u_int i;
1853122394Sharti
1854124861Sharti	if (!(snmp_trace & LOG_ASN1_ERRORS))
1855124861Sharti		return;
1856124861Sharti
1857122394Sharti	va_start(ap, err);
1858122394Sharti	snprintf(errbuf, sizeof(errbuf), "ASN.1: ");
1859124861Sharti	vsnprintf(errbuf + strlen(errbuf),
1860124861Sharti	    sizeof(errbuf) - strlen(errbuf), err, ap);
1861122394Sharti	va_end(ap);
1862122394Sharti
1863122394Sharti	if (b != NULL) {
1864124861Sharti		snprintf(errbuf + strlen(errbuf),
1865124861Sharti		    sizeof(errbuf) - strlen(errbuf), " at");
1866122394Sharti		for (i = 0; b->asn_len > i; i++)
1867124861Sharti			snprintf(errbuf + strlen(errbuf),
1868124861Sharti			    sizeof(errbuf) - strlen(errbuf),
1869124861Sharti			    " %02x", b->asn_cptr[i]);
1870122394Sharti	}
1871122394Sharti
1872122394Sharti	syslog(LOG_ERR, "%s", errbuf);
1873122394Sharti}
1874122394Sharti
1875122394Sharti/*
1876122394Sharti * Create a new community
1877122394Sharti */
1878122394Shartiu_int
1879122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner,
1880122394Sharti    const char *str)
1881122394Sharti{
1882122394Sharti	struct community *c, *p;
1883122394Sharti	u_int ncomm;
1884122394Sharti
1885122394Sharti	/* generate an identifier */
1886122394Sharti	do {
1887122394Sharti		if ((ncomm = next_community_index++) == UINT_MAX)
1888122394Sharti			next_community_index = 1;
1889122394Sharti		TAILQ_FOREACH(c, &community_list, link)
1890122394Sharti			if (c->value == ncomm)
1891122394Sharti				break;
1892122394Sharti	} while (c != NULL);
1893122394Sharti
1894122394Sharti	if ((c = malloc(sizeof(struct community))) == NULL) {
1895122394Sharti		syslog(LOG_ERR, "comm_define: %m");
1896122394Sharti		return (0);
1897122394Sharti	}
1898122394Sharti	c->owner = owner;
1899122394Sharti	c->value = ncomm;
1900122394Sharti	c->descr = descr;
1901122394Sharti	c->string = NULL;
1902122394Sharti	c->private = priv;
1903122394Sharti
1904122394Sharti	if (str != NULL) {
1905122394Sharti		if((c->string = malloc(strlen(str)+1)) == NULL) {
1906122394Sharti			free(c);
1907122394Sharti			return (0);
1908122394Sharti		}
1909122394Sharti		strcpy(c->string, str);
1910122394Sharti	}
1911122394Sharti
1912122394Sharti	/* make index */
1913122394Sharti	if (c->owner == NULL) {
1914122394Sharti		c->index.len = 1;
1915122394Sharti		c->index.subs[0] = 0;
1916122394Sharti	} else {
1917122394Sharti		c->index = c->owner->index;
1918122394Sharti	}
1919122394Sharti	c->index.subs[c->index.len++] = c->private;
1920122394Sharti
1921122394Sharti	/*
1922122394Sharti	 * Insert ordered
1923122394Sharti	 */
1924122394Sharti	TAILQ_FOREACH(p, &community_list, link) {
1925122394Sharti		if (asn_compare_oid(&p->index, &c->index) > 0) {
1926122394Sharti			TAILQ_INSERT_BEFORE(p, c, link);
1927122394Sharti			break;
1928122394Sharti		}
1929122394Sharti	}
1930122394Sharti	if (p == NULL)
1931122394Sharti		TAILQ_INSERT_TAIL(&community_list, c, link);
1932122394Sharti	return (c->value);
1933122394Sharti}
1934122394Sharti
1935122394Sharticonst char *
1936122394Sharticomm_string(u_int ncomm)
1937122394Sharti{
1938122394Sharti	struct community *p;
1939122394Sharti
1940122394Sharti	TAILQ_FOREACH(p, &community_list, link)
1941122394Sharti		if (p->value == ncomm)
1942122394Sharti			return (p->string);
1943122394Sharti	return (NULL);
1944122394Sharti}
1945122394Sharti
1946122394Sharti/*
1947122394Sharti * Delete all communities allocated by a module
1948122394Sharti */
1949122394Shartistatic void
1950122394Sharticomm_flush(struct lmodule *mod)
1951122394Sharti{
1952122394Sharti	struct community *p, *p1;
1953122394Sharti
1954122394Sharti	p = TAILQ_FIRST(&community_list);
1955122394Sharti	while (p != NULL) {
1956122394Sharti		p1 = TAILQ_NEXT(p, link);
1957122394Sharti		if (p->owner == mod) {
1958122394Sharti			free(p->string);
1959122394Sharti			TAILQ_REMOVE(&community_list, p, link);
1960122394Sharti			free(p);
1961122394Sharti		}
1962122394Sharti		p = p1;
1963122394Sharti	}
1964122394Sharti}
1965122394Sharti
1966122394Sharti/*
1967122394Sharti * Request ID handling.
1968122394Sharti *
1969122394Sharti * Allocate a new range of request ids. Use a first fit algorithm.
1970122394Sharti */
1971122394Shartiu_int
1972122394Shartireqid_allocate(int size, struct lmodule *mod)
1973122394Sharti{
1974122394Sharti	u_int type;
1975122394Sharti	struct idrange *r, *r1;
1976122394Sharti
1977122394Sharti	if (size <= 0 || size > INT32_MAX) {
1978122394Sharti		syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size);
1979122394Sharti		return (0);
1980122394Sharti	}
1981122394Sharti	/* allocate a type id */
1982122394Sharti	do {
1983122394Sharti		if ((type = next_idrange++) == UINT_MAX)
1984122394Sharti			next_idrange = 1;
1985122394Sharti		TAILQ_FOREACH(r, &idrange_list, link)
1986122394Sharti			if (r->type == type)
1987122394Sharti				break;
1988122394Sharti	} while(r != NULL);
1989122394Sharti
1990122394Sharti	/* find a range */
1991122394Sharti	if (TAILQ_EMPTY(&idrange_list))
1992122394Sharti		r = NULL;
1993122394Sharti	else {
1994122394Sharti		r = TAILQ_FIRST(&idrange_list);
1995122394Sharti		if (r->base < size) {
1996122394Sharti			while((r1 = TAILQ_NEXT(r, link)) != NULL) {
1997122394Sharti				if (r1->base - (r->base + r->size) >= size)
1998122394Sharti					break;
1999122394Sharti				r = r1;
2000122394Sharti			}
2001122394Sharti			r = r1;
2002122394Sharti		}
2003122394Sharti		if (r == NULL) {
2004122394Sharti			r1 = TAILQ_LAST(&idrange_list, idrange_list);
2005122394Sharti			if (INT32_MAX - size + 1 < r1->base + r1->size) {
2006122394Sharti				syslog(LOG_ERR, "out of id ranges (%u)", size);
2007122394Sharti				return (0);
2008122394Sharti			}
2009122394Sharti		}
2010122394Sharti	}
2011122394Sharti
2012122394Sharti	/* allocate structure */
2013122394Sharti	if ((r1 = malloc(sizeof(struct idrange))) == NULL) {
2014122394Sharti		syslog(LOG_ERR, "%s: %m", __FUNCTION__);
2015122394Sharti		return (0);
2016122394Sharti	}
2017122394Sharti
2018122394Sharti	r1->type = type;
2019122394Sharti	r1->size = size;
2020122394Sharti	r1->owner = mod;
2021122394Sharti	if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) {
2022122394Sharti		r1->base = 0;
2023122394Sharti		TAILQ_INSERT_HEAD(&idrange_list, r1, link);
2024122394Sharti	} else if (r == NULL) {
2025122394Sharti		r = TAILQ_LAST(&idrange_list, idrange_list);
2026122394Sharti		r1->base = r->base + r->size;
2027122394Sharti		TAILQ_INSERT_TAIL(&idrange_list, r1, link);
2028122394Sharti	} else {
2029122394Sharti		r = TAILQ_PREV(r, idrange_list, link);
2030122394Sharti		r1->base = r->base + r->size;
2031122394Sharti		TAILQ_INSERT_AFTER(&idrange_list, r, r1, link);
2032122394Sharti	}
2033122394Sharti	r1->next = r1->base;
2034122394Sharti
2035122394Sharti	return (type);
2036122394Sharti}
2037122394Sharti
2038122394Shartiint32_t
2039122394Shartireqid_next(u_int type)
2040122394Sharti{
2041122394Sharti	struct idrange *r;
2042122394Sharti	int32_t id;
2043122394Sharti
2044122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
2045122394Sharti		if (r->type == type)
2046122394Sharti			break;
2047122394Sharti	if (r == NULL) {
2048122394Sharti		syslog(LOG_CRIT, "wrong idrange type");
2049122394Sharti		abort();
2050122394Sharti	}
2051122394Sharti	if ((id = r->next++) == r->base + (r->size - 1))
2052122394Sharti		r->next = r->base;
2053122394Sharti	return (id);
2054122394Sharti}
2055122394Sharti
2056122394Shartiint32_t
2057122394Shartireqid_base(u_int type)
2058122394Sharti{
2059122394Sharti	struct idrange *r;
2060122394Sharti
2061122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
2062122394Sharti		if (r->type == type)
2063122394Sharti			return (r->base);
2064122394Sharti	syslog(LOG_CRIT, "wrong idrange type");
2065122394Sharti	abort();
2066122394Sharti}
2067122394Sharti
2068122394Shartiu_int
2069122394Shartireqid_type(int32_t reqid)
2070122394Sharti{
2071122394Sharti	struct idrange *r;
2072122394Sharti
2073122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
2074122394Sharti		if (reqid >= r->base && reqid <= r->base + (r->size - 1))
2075122394Sharti			return (r->type);
2076122394Sharti	return (0);
2077122394Sharti}
2078122394Sharti
2079122394Shartiint
2080122394Shartireqid_istype(int32_t reqid, u_int type)
2081122394Sharti{
2082122394Sharti	return (reqid_type(reqid) == type);
2083122394Sharti}
2084122394Sharti
2085122394Sharti/*
2086122394Sharti * Delete all communities allocated by a module
2087122394Sharti */
2088122394Shartistatic void
2089122394Shartireqid_flush(struct lmodule *mod)
2090122394Sharti{
2091122394Sharti	struct idrange *p, *p1;
2092122394Sharti
2093122394Sharti	p = TAILQ_FIRST(&idrange_list);
2094122394Sharti	while (p != NULL) {
2095122394Sharti		p1 = TAILQ_NEXT(p, link);
2096122394Sharti		if (p->owner == mod) {
2097122394Sharti			TAILQ_REMOVE(&idrange_list, p, link);
2098122394Sharti			free(p);
2099122394Sharti		}
2100122394Sharti		p = p1;
2101122394Sharti	}
2102122394Sharti}
2103122394Sharti
2104122394Sharti/*
2105122394Sharti * Merge the given tree for the given module into the main tree.
2106122394Sharti */
2107122394Shartistatic int
2108122394Sharticompare_node(const void *v1, const void *v2)
2109122394Sharti{
2110122394Sharti	const struct snmp_node *n1 = v1;
2111122394Sharti	const struct snmp_node *n2 = v2;
2112122394Sharti
2113122394Sharti	return (asn_compare_oid(&n1->oid, &n2->oid));
2114122394Sharti}
2115122394Shartistatic int
2116122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod)
2117122394Sharti{
2118122394Sharti	struct snmp_node *xtree;
2119122394Sharti	u_int i;
2120122394Sharti
2121122394Sharti	xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize));
2122122394Sharti	if (xtree == NULL) {
2123128237Sharti		syslog(LOG_ERR, "tree_merge: %m");
2124122394Sharti		return (-1);
2125122394Sharti	}
2126122394Sharti	tree = xtree;
2127122394Sharti	memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize);
2128122394Sharti
2129122394Sharti	for (i = 0; i < nsize; i++)
2130128237Sharti		tree[tree_size + i].tree_data = mod;
2131122394Sharti
2132122394Sharti	tree_size += nsize;
2133122394Sharti
2134122394Sharti	qsort(tree, tree_size, sizeof(tree[0]), compare_node);
2135122394Sharti
2136122394Sharti	return (0);
2137122394Sharti}
2138122394Sharti
2139122394Sharti/*
2140122394Sharti * Remove all nodes belonging to the loadable module
2141122394Sharti */
2142122394Shartistatic void
2143122394Shartitree_unmerge(struct lmodule *mod)
2144122394Sharti{
2145122394Sharti	u_int s, d;
2146122394Sharti
2147122394Sharti	for(s = d = 0; s < tree_size; s++)
2148128237Sharti		if (tree[s].tree_data != mod) {
2149122394Sharti			if (s != d)
2150122394Sharti				tree[d] = tree[s];
2151122394Sharti			d++;
2152122394Sharti		}
2153122394Sharti	tree_size = d;
2154122394Sharti}
2155122394Sharti
2156122394Sharti/*
2157122394Sharti * Loadable modules
2158122394Sharti */
2159122394Shartistruct lmodule *
2160122394Shartilm_load(const char *path, const char *section)
2161122394Sharti{
2162122394Sharti	struct lmodule *m;
2163122394Sharti	int err;
2164122394Sharti	int i;
2165122394Sharti	char *av[MAX_MOD_ARGS + 1];
2166122394Sharti	int ac;
2167122394Sharti	u_int u;
2168122394Sharti
2169122394Sharti	if ((m = malloc(sizeof(*m))) == NULL) {
2170122394Sharti		syslog(LOG_ERR, "lm_load: %m");
2171122394Sharti		return (NULL);
2172122394Sharti	}
2173122394Sharti	m->handle = NULL;
2174122394Sharti	m->flags = 0;
2175122394Sharti	strcpy(m->section, section);
2176122394Sharti
2177122394Sharti	if ((m->path = malloc(strlen(path) + 1)) == NULL) {
2178122394Sharti		syslog(LOG_ERR, "lm_load: %m");
2179122394Sharti		goto err;
2180122394Sharti	}
2181122394Sharti	strcpy(m->path, path);
2182122394Sharti
2183122394Sharti	/*
2184122394Sharti	 * Make index
2185122394Sharti	 */
2186122394Sharti	m->index.subs[0] = strlen(section);
2187122394Sharti	m->index.len = m->index.subs[0] + 1;
2188122394Sharti	for (u = 0; u < m->index.subs[0]; u++)
2189122394Sharti		m->index.subs[u + 1] = section[u];
2190122394Sharti
2191122394Sharti	/*
2192122394Sharti	 * Load the object file and locate the config structure
2193122394Sharti	 */
2194122394Sharti	if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
2195122394Sharti		syslog(LOG_ERR, "lm_load: open %s", dlerror());
2196122394Sharti		goto err;
2197122394Sharti	}
2198122394Sharti
2199122394Sharti	if ((m->config = dlsym(m->handle, "config")) == NULL) {
2200122394Sharti		syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror());
2201122394Sharti		goto err;
2202122394Sharti	}
2203122394Sharti
2204122394Sharti	/*
2205122394Sharti	 * Insert it into the right place
2206122394Sharti	 */
2207122394Sharti	INSERT_OBJECT_OID(m, &lmodules);
2208122394Sharti
2209122394Sharti	/* preserve order */
2210122394Sharti	if (community == COMM_INITIALIZE) {
2211122394Sharti		m->flags |= LM_ONSTARTLIST;
2212122394Sharti		TAILQ_INSERT_TAIL(&modules_start, m, start);
2213122394Sharti	}
2214122394Sharti
2215122394Sharti	/*
2216122394Sharti	 * make the argument vector.
2217122394Sharti	 */
2218122394Sharti	ac = 0;
2219122394Sharti	for (i = 0; i < nprogargs; i++) {
2220122394Sharti		if (strlen(progargs[i]) >= strlen(section) + 1 &&
2221122394Sharti		    strncmp(progargs[i], section, strlen(section)) == 0 &&
2222122394Sharti		    progargs[i][strlen(section)] == ':') {
2223122394Sharti			if (ac == MAX_MOD_ARGS) {
2224122394Sharti				syslog(LOG_WARNING, "too many arguments for "
2225122394Sharti				    "module '%s", section);
2226122394Sharti				break;
2227122394Sharti			}
2228122394Sharti			av[ac++] = &progargs[i][strlen(section)+1];
2229122394Sharti		}
2230122394Sharti	}
2231122394Sharti	av[ac] = NULL;
2232122394Sharti
2233122394Sharti	/*
2234150920Sharti	 * Run the initialization function
2235122394Sharti	 */
2236122394Sharti	if ((err = (*m->config->init)(m, ac, av)) != 0) {
2237122394Sharti		syslog(LOG_ERR, "lm_load: init failed: %d", err);
2238122394Sharti		TAILQ_REMOVE(&lmodules, m, link);
2239122394Sharti		goto err;
2240122394Sharti	}
2241122394Sharti
2242122394Sharti	return (m);
2243122394Sharti
2244122394Sharti  err:
2245122394Sharti	if (m->handle)
2246122394Sharti		dlclose(m->handle);
2247122394Sharti	free(m->path);
2248122394Sharti	free(m);
2249122394Sharti	return (NULL);
2250122394Sharti}
2251122394Sharti
2252122394Sharti/*
2253122394Sharti * Start a module
2254122394Sharti */
2255122394Shartivoid
2256122394Shartilm_start(struct lmodule *mod)
2257122394Sharti{
2258122394Sharti	const struct lmodule *m;
2259122394Sharti
2260122394Sharti	/*
2261122394Sharti	 * Merge tree. If this fails, unload the module.
2262122394Sharti	 */
2263122394Sharti	if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) {
2264122394Sharti		lm_unload(mod);
2265122394Sharti		return;
2266122394Sharti	}
2267122394Sharti
2268122394Sharti	/*
2269122394Sharti	 * Read configuration
2270122394Sharti	 */
2271122394Sharti	if (read_config(config_file, mod)) {
2272122394Sharti		syslog(LOG_ERR, "error in config file");
2273122394Sharti		lm_unload(mod);
2274122394Sharti		return;
2275122394Sharti	}
2276122394Sharti	if (mod->config->start)
2277122394Sharti		(*mod->config->start)();
2278122394Sharti
2279122394Sharti	mod->flags |= LM_STARTED;
2280122394Sharti
2281122394Sharti	/*
2282122394Sharti	 * Inform other modules
2283122394Sharti	 */
2284122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
2285122394Sharti		if (m->config->loading)
2286122394Sharti			(*m->config->loading)(mod, 1);
2287122394Sharti}
2288122394Sharti
2289122394Sharti
2290122394Sharti/*
2291122394Sharti * Unload a module.
2292122394Sharti */
2293122394Shartivoid
2294122394Shartilm_unload(struct lmodule *m)
2295122394Sharti{
2296122394Sharti	int err;
2297122394Sharti	const struct lmodule *mod;
2298122394Sharti
2299122394Sharti	TAILQ_REMOVE(&lmodules, m, link);
2300122394Sharti	if (m->flags & LM_ONSTARTLIST)
2301122394Sharti		TAILQ_REMOVE(&modules_start, m, start);
2302122394Sharti	tree_unmerge(m);
2303122394Sharti
2304122394Sharti	if ((m->flags & LM_STARTED) && m->config->fini &&
2305122394Sharti	    (err = (*m->config->fini)()) != 0)
2306122394Sharti		syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err);
2307122394Sharti
2308122394Sharti	comm_flush(m);
2309122394Sharti	reqid_flush(m);
2310122394Sharti	timer_flush(m);
2311122394Sharti	fd_flush(m);
2312122394Sharti
2313122394Sharti	dlclose(m->handle);
2314122394Sharti	free(m->path);
2315122394Sharti
2316122394Sharti	/*
2317122394Sharti	 * Inform other modules
2318122394Sharti	 */
2319122394Sharti	TAILQ_FOREACH(mod, &lmodules, link)
2320122394Sharti		if (mod->config->loading)
2321122394Sharti			(*mod->config->loading)(m, 0);
2322122394Sharti
2323122394Sharti	free(m);
2324122394Sharti}
2325122394Sharti
2326122394Sharti/*
2327122394Sharti * Register an object resource and return the index (or 0 on failures)
2328122394Sharti */
2329122394Shartiu_int
2330122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod)
2331122394Sharti{
2332122394Sharti	struct objres *objres, *or1;
2333122394Sharti	u_int idx;
2334122394Sharti
2335122394Sharti	/* find a free index */
2336122394Sharti	idx = 1;
2337122394Sharti	for (objres = TAILQ_FIRST(&objres_list);
2338122394Sharti	     objres != NULL;
2339122394Sharti	     objres = TAILQ_NEXT(objres, link)) {
2340122394Sharti		if ((or1 = TAILQ_NEXT(objres, link)) == NULL ||
2341122394Sharti		    or1->index > objres->index + 1) {
2342122394Sharti			idx = objres->index + 1;
2343122394Sharti			break;
2344122394Sharti		}
2345122394Sharti	}
2346122394Sharti
2347122394Sharti	if ((objres = malloc(sizeof(*objres))) == NULL)
2348122394Sharti		return (0);
2349122394Sharti
2350122394Sharti	objres->index = idx;
2351122394Sharti	objres->oid = *or;
2352122394Sharti	strlcpy(objres->descr, descr, sizeof(objres->descr));
2353146525Sharti	objres->uptime = (uint32_t)(get_ticks() - start_tick);
2354122394Sharti	objres->module = mod;
2355122394Sharti
2356122394Sharti	INSERT_OBJECT_INT(objres, &objres_list);
2357122394Sharti
2358122394Sharti	systemg.or_last_change = objres->uptime;
2359122394Sharti
2360122394Sharti	return (idx);
2361122394Sharti}
2362122394Sharti
2363122394Shartivoid
2364122394Shartior_unregister(u_int idx)
2365122394Sharti{
2366122394Sharti	struct objres *objres;
2367122394Sharti
2368122394Sharti	TAILQ_FOREACH(objres, &objres_list, link)
2369122394Sharti		if (objres->index == idx) {
2370122394Sharti			TAILQ_REMOVE(&objres_list, objres, link);
2371122394Sharti			free(objres);
2372122394Sharti			return;
2373122394Sharti		}
2374122394Sharti}
2375