main.c revision 145557
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 *
29145557Sharti * $Begemot: bsnmp/snmpd/main.c,v 1.91 2005/04/22 12:18:14 brandt_h Exp $
30122394Sharti *
31122394Sharti * SNMPd main stuff.
32122394Sharti */
33122394Sharti#include <sys/param.h>
34122394Sharti#include <sys/un.h>
35124861Sharti#include <sys/ucred.h>
36122394Sharti#include <stdio.h>
37122394Sharti#include <stdlib.h>
38122394Sharti#include <stddef.h>
39122394Sharti#include <string.h>
40122394Sharti#include <stdarg.h>
41122394Sharti#include <ctype.h>
42122394Sharti#include <errno.h>
43122394Sharti#include <syslog.h>
44122394Sharti#include <unistd.h>
45122394Sharti#include <signal.h>
46122394Sharti#include <dlfcn.h>
47122394Sharti#include <inttypes.h>
48122394Sharti
49145557Sharti#ifdef USE_TCPWRAPPERS
50145557Sharti#include <arpa/inet.h>
51145557Sharti#include <tcpd.h>
52145557Sharti#endif
53145557Sharti
54122394Sharti#include "snmpmod.h"
55122394Sharti#include "snmpd.h"
56122394Sharti#include "tree.h"
57122394Sharti#include "oid.h"
58122394Sharti
59122394Sharti#define	PATH_PID	"/var/run/%s.pid"
60122394Sharti#define PATH_CONFIG	"/etc/%s.config"
61122394Sharti
62122394Shartiu_int32_t this_tick;	/* start of processing of current packet */
63122394Shartiu_int32_t start_tick;	/* start of processing */
64122394Sharti
65122394Shartistruct systemg systemg = {
66122394Sharti	NULL,
67122394Sharti	{ 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }},
68122394Sharti	NULL, NULL, NULL,
69122394Sharti	64 + 8 + 4,
70122394Sharti	0
71122394Sharti};
72122394Shartistruct debug debug = {
73122394Sharti	0,		/* dump_pdus */
74122394Sharti	LOG_DEBUG,	/* log_pri */
75122394Sharti	0,		/* evdebug */
76122394Sharti};
77122394Sharti
78122394Shartistruct snmpd snmpd = {
79122394Sharti	2048,		/* txbuf */
80122394Sharti	2048,		/* rxbuf */
81122394Sharti	0,		/* comm_dis */
82122394Sharti	0,		/* auth_traps */
83122394Sharti	{0, 0, 0, 0},	/* trap1addr */
84124861Sharti	VERS_ENABLE_ALL,/* version_enable */
85122394Sharti};
86122394Shartistruct snmpd_stats snmpd_stats;
87122394Sharti
88122394Sharti/* snmpSerialNo */
89122394Shartiint32_t snmp_serial_no;
90122394Sharti
91122394Sharti/* search path for config files */
92122394Sharticonst char *syspath = PATH_SYSCONFIG;
93122394Sharti
94122394Sharti/* list of all loaded modules */
95122394Shartistruct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules);
96122394Sharti
97122394Sharti/* list of loaded modules during start-up in the order they were loaded */
98122394Shartistatic struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start);
99122394Sharti
100122394Sharti/* list of all known communities */
101122394Shartistruct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list);
102122394Sharti
103122394Sharti/* list of all installed object resources */
104122394Shartistruct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list);
105122394Sharti
106122394Sharti/* community value generator */
107122394Shartistatic u_int next_community_index = 1;
108122394Sharti
109122394Sharti/* list of all known ranges */
110122394Shartistruct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list);
111122394Sharti
112122394Sharti/* identifier generator */
113122394Shartiu_int next_idrange = 1;
114122394Sharti
115122394Sharti/* list of all current timers */
116122394Shartistruct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list);
117122394Sharti
118122394Sharti/* list of file descriptors */
119122394Shartistruct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list);
120122394Sharti
121122394Sharti/* program arguments */
122122394Shartistatic char **progargs;
123122394Shartistatic int nprogargs;
124122394Sharti
125122394Sharti/* current community */
126122394Shartiu_int	community;
127122394Shartistatic struct community *comm;
128122394Sharti
129122394Sharti/* file names */
130122394Shartistatic char config_file[MAXPATHLEN + 1];
131122394Shartistatic char pid_file[MAXPATHLEN + 1];
132122394Sharti
133124861Sharti#ifndef USE_LIBBEGEMOT
134122394Sharti/* event context */
135122394Shartistatic evContext evctx;
136124861Sharti#endif
137122394Sharti
138122394Sharti/* signal mask */
139122394Shartistatic sigset_t blocked_sigs;
140122394Sharti
141122394Sharti/* signal handling */
142122394Shartistatic int work;
143122394Sharti#define	WORK_DOINFO	0x0001
144122394Sharti#define	WORK_RECONFIG	0x0002
145122394Sharti
146122394Sharti/* oids */
147122394Shartistatic const struct asn_oid
148122394Sharti	oid_snmpMIB = OIDX_snmpMIB,
149122394Sharti	oid_begemotSnmpd = OIDX_begemotSnmpd,
150122394Sharti	oid_coldStart = OIDX_coldStart,
151122394Sharti	oid_authenticationFailure = OIDX_authenticationFailure;
152122394Sharti
153122394Sharticonst struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }};
154122394Sharti
155122394Sharti/* request id generator for traps */
156122394Shartiu_int trap_reqid;
157122394Sharti
158122394Sharti/* help text */
159122394Shartistatic const char usgtxt[] = "\
160122394ShartiBegemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
161122394ShartiOpen Communication Systems (FhG Fokus). All rights reserved.\n\
162122394Shartiusage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\
163122394Sharti             [-m variable=value] [-p file]\n\
164122394Shartioptions:\n\
165122394Sharti  -d		don't daemonize\n\
166122394Sharti  -h		print this info\n\
167122394Sharti  -c file	specify configuration file\n\
168122394Sharti  -D options	debugging options\n\
169122394Sharti  -I path	system include path\n\
170122394Sharti  -l prefix	default basename for pid and config file\n\
171122394Sharti  -m var=val	define variable\n\
172122394Sharti  -p file	specify pid file\n\
173122394Sharti";
174122394Sharti
175145557Sharti/* hosts_access(3) request */
176145557Sharti#ifdef USE_TCPWRAPPERS
177145557Shartistatic struct request_info req;
178145557Sharti#endif
179145557Sharti
180124861Sharti/* transports */
181124861Shartiextern const struct transport_def udp_trans;
182124861Shartiextern const struct transport_def lsock_trans;
183124861Sharti
184124861Shartistruct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
185124861Sharti
186122394Sharti/* forward declarations */
187122394Shartistatic void snmp_printf_func(const char *fmt, ...);
188122394Shartistatic void snmp_error_func(const char *err, ...);
189122394Shartistatic void snmp_debug_func(const char *err, ...);
190122394Shartistatic void asn_error_func(const struct asn_buf *b, const char *err, ...);
191122394Sharti
192122394Sharti/*
193122394Sharti * Allocate rx/tx buffer. We allocate one byte more for rx.
194122394Sharti */
195122394Shartivoid *
196122394Shartibuf_alloc(int tx)
197122394Sharti{
198122394Sharti	void *buf;
199122394Sharti
200124861Sharti	if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) {
201122394Sharti		syslog(LOG_CRIT, "cannot allocate buffer");
202122394Sharti		if (tx)
203122394Sharti			snmpd_stats.noTxbuf++;
204122394Sharti		else
205122394Sharti			snmpd_stats.noRxbuf++;
206122394Sharti		return (NULL);
207122394Sharti	}
208122394Sharti	return (buf);
209122394Sharti}
210122394Sharti
211122394Sharti/*
212124861Sharti * Return the buffer size.
213122394Sharti */
214122394Shartisize_t
215122394Shartibuf_size(int tx)
216122394Sharti{
217124861Sharti	return (tx ? snmpd.txbuf : snmpd.rxbuf);
218122394Sharti}
219122394Sharti
220122394Sharti/*
221122394Sharti * Prepare a PDU for output
222122394Sharti */
223122394Shartivoid
224124861Shartisnmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen,
225122394Sharti    const char *dest)
226122394Sharti{
227122394Sharti	struct asn_buf resp_b;
228122394Sharti
229122394Sharti	resp_b.asn_ptr = sndbuf;
230122394Sharti	resp_b.asn_len = snmpd.txbuf;
231122394Sharti
232122394Sharti	if (snmp_pdu_encode(pdu, &resp_b) != 0) {
233122394Sharti		syslog(LOG_ERR, "cannot encode message");
234122394Sharti		abort();
235122394Sharti	}
236122394Sharti	if (debug.dump_pdus) {
237122394Sharti		snmp_printf("%s <- ", dest);
238122394Sharti		snmp_pdu_dump(pdu);
239122394Sharti	}
240122394Sharti	*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
241122394Sharti}
242122394Sharti
243122394Sharti/*
244122394Sharti * SNMP input. Start: decode the PDU, find the community.
245122394Sharti */
246122394Shartienum snmpd_input_err
247122394Shartisnmp_input_start(const u_char *buf, size_t len, const char *source,
248124861Sharti    struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen)
249122394Sharti{
250122394Sharti	struct asn_buf b;
251122394Sharti	enum snmp_code code;
252122394Sharti	enum snmpd_input_err ret;
253124861Sharti	int sret;
254122394Sharti
255122394Sharti	b.asn_cptr = buf;
256122394Sharti	b.asn_len = len;
257124861Sharti
258124861Sharti	/* look whether we have enough bytes for the entire PDU. */
259124861Sharti	switch (sret = snmp_pdu_snoop(&b)) {
260124861Sharti
261124861Sharti	  case 0:
262124861Sharti		return (SNMPD_INPUT_TRUNC);
263124861Sharti
264124861Sharti	  case -1:
265124861Sharti		snmpd_stats.inASNParseErrs++;
266124861Sharti		return (SNMPD_INPUT_FAILED);
267124861Sharti	}
268124861Sharti	b.asn_len = *pdulen = (size_t)sret;
269124861Sharti
270122394Sharti	code = snmp_pdu_decode(&b, pdu, ip);
271122394Sharti
272124861Sharti	snmpd_stats.inPkts++;
273124861Sharti
274122394Sharti	ret = SNMPD_INPUT_OK;
275122394Sharti	switch (code) {
276122394Sharti
277122394Sharti	  case SNMP_CODE_FAILED:
278122394Sharti		snmpd_stats.inASNParseErrs++;
279122394Sharti		return (SNMPD_INPUT_FAILED);
280122394Sharti
281122394Sharti	  case SNMP_CODE_BADVERS:
282124861Sharti	  bad_vers:
283122394Sharti		snmpd_stats.inBadVersions++;
284122394Sharti		return (SNMPD_INPUT_FAILED);
285122394Sharti
286122394Sharti	  case SNMP_CODE_BADLEN:
287122394Sharti		if (pdu->type == SNMP_OP_SET)
288122394Sharti			ret = SNMPD_INPUT_VALBADLEN;
289122394Sharti		break;
290122394Sharti
291122394Sharti	  case SNMP_CODE_OORANGE:
292122394Sharti		if (pdu->type == SNMP_OP_SET)
293122394Sharti			ret = SNMPD_INPUT_VALRANGE;
294122394Sharti		break;
295122394Sharti
296122394Sharti	  case SNMP_CODE_BADENC:
297122394Sharti		if (pdu->type == SNMP_OP_SET)
298122394Sharti			ret = SNMPD_INPUT_VALBADENC;
299122394Sharti		break;
300122394Sharti
301122394Sharti	  case SNMP_CODE_OK:
302124861Sharti		switch (pdu->version) {
303124861Sharti
304124861Sharti		  case SNMP_V1:
305124861Sharti			if (!(snmpd.version_enable & VERS_ENABLE_V1))
306124861Sharti				goto bad_vers;
307124861Sharti			break;
308124861Sharti
309124861Sharti		  case SNMP_V2c:
310124861Sharti			if (!(snmpd.version_enable & VERS_ENABLE_V2C))
311124861Sharti				goto bad_vers;
312124861Sharti			break;
313124861Sharti
314124861Sharti		  case SNMP_Verr:
315124861Sharti			goto bad_vers;
316124861Sharti		}
317122394Sharti		break;
318122394Sharti	}
319122394Sharti
320122394Sharti	if (debug.dump_pdus) {
321122394Sharti		snmp_printf("%s -> ", source);
322122394Sharti		snmp_pdu_dump(pdu);
323122394Sharti	}
324122394Sharti
325122394Sharti	/*
326122394Sharti	 * Look, whether we know the community
327122394Sharti	 */
328122394Sharti	TAILQ_FOREACH(comm, &community_list, link)
329122394Sharti		if (comm->string != NULL &&
330122394Sharti		    strcmp(comm->string, pdu->community) == 0)
331122394Sharti			break;
332122394Sharti
333122394Sharti	if (comm == NULL) {
334122394Sharti		snmpd_stats.inBadCommunityNames++;
335122394Sharti		snmp_pdu_free(pdu);
336122394Sharti		if (snmpd.auth_traps)
337133211Sharti			snmp_send_trap(&oid_authenticationFailure,
338133211Sharti			    (struct snmp_value *)NULL);
339133211Sharti		ret = SNMPD_INPUT_BAD_COMM;
340133211Sharti	} else
341133211Sharti		community = comm->value;
342122394Sharti
343122394Sharti	/* update uptime */
344122394Sharti	this_tick = get_ticks();
345122394Sharti
346122394Sharti	return (ret);
347122394Sharti}
348122394Sharti
349122394Sharti/*
350122394Sharti * Will return only _OK or _FAILED
351122394Sharti */
352122394Shartienum snmpd_input_err
353122394Shartisnmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen,
354122394Sharti    u_char *sndbuf, size_t *sndlen, const char *source,
355122394Sharti    enum snmpd_input_err ierr, int32_t ivar, void *data)
356122394Sharti{
357122394Sharti	struct snmp_pdu resp;
358122394Sharti	struct asn_buf resp_b, pdu_b;
359122394Sharti	enum snmp_ret ret;
360122394Sharti
361122394Sharti	resp_b.asn_ptr = sndbuf;
362122394Sharti	resp_b.asn_len = snmpd.txbuf;
363122394Sharti
364122394Sharti	pdu_b.asn_cptr = rcvbuf;
365122394Sharti	pdu_b.asn_len = rcvlen;
366122394Sharti
367122394Sharti	if (ierr != SNMPD_INPUT_OK) {
368122394Sharti		/* error decoding the input of a SET */
369122394Sharti		if (pdu->version == SNMP_V1)
370122394Sharti			pdu->error_status = SNMP_ERR_BADVALUE;
371122394Sharti		else if (ierr == SNMPD_INPUT_VALBADLEN)
372122394Sharti			pdu->error_status = SNMP_ERR_WRONG_LENGTH;
373122394Sharti		else if (ierr == SNMPD_INPUT_VALRANGE)
374122394Sharti			pdu->error_status = SNMP_ERR_WRONG_VALUE;
375122394Sharti		else
376122394Sharti			pdu->error_status = SNMP_ERR_WRONG_ENCODING;
377122394Sharti
378122394Sharti		pdu->error_index = ivar;
379122394Sharti
380122394Sharti		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
381122394Sharti			syslog(LOG_WARNING, "could not encode error response");
382122394Sharti			snmpd_stats.silentDrops++;
383122394Sharti			return (SNMPD_INPUT_FAILED);
384122394Sharti		}
385122394Sharti
386122394Sharti		if (debug.dump_pdus) {
387122394Sharti			snmp_printf("%s <- ", source);
388122394Sharti			snmp_pdu_dump(pdu);
389122394Sharti		}
390122394Sharti		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
391122394Sharti		return (SNMPD_INPUT_OK);
392122394Sharti	}
393122394Sharti
394122394Sharti	switch (pdu->type) {
395122394Sharti
396122394Sharti	  case SNMP_PDU_GET:
397122394Sharti		ret = snmp_get(pdu, &resp_b, &resp, data);
398122394Sharti		break;
399122394Sharti
400122394Sharti	  case SNMP_PDU_GETNEXT:
401122394Sharti		ret = snmp_getnext(pdu, &resp_b, &resp, data);
402122394Sharti		break;
403122394Sharti
404122394Sharti	  case SNMP_PDU_SET:
405122394Sharti		ret = snmp_set(pdu, &resp_b, &resp, data);
406122394Sharti		break;
407122394Sharti
408122394Sharti	  case SNMP_PDU_GETBULK:
409122394Sharti		ret = snmp_getbulk(pdu, &resp_b, &resp, data);
410122394Sharti		break;
411122394Sharti
412122394Sharti	  default:
413122394Sharti		ret = SNMP_RET_IGN;
414122394Sharti		break;
415122394Sharti	}
416122394Sharti
417122394Sharti	switch (ret) {
418122394Sharti
419122394Sharti	  case SNMP_RET_OK:
420122394Sharti		/* normal return - send a response */
421122394Sharti		if (debug.dump_pdus) {
422122394Sharti			snmp_printf("%s <- ", source);
423122394Sharti			snmp_pdu_dump(&resp);
424122394Sharti		}
425122394Sharti		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
426122394Sharti		snmp_pdu_free(&resp);
427122394Sharti		return (SNMPD_INPUT_OK);
428122394Sharti
429122394Sharti	  case SNMP_RET_IGN:
430122394Sharti		/* error - send nothing */
431122394Sharti		snmpd_stats.silentDrops++;
432122394Sharti		return (SNMPD_INPUT_FAILED);
433122394Sharti
434122394Sharti	  case SNMP_RET_ERR:
435122394Sharti		/* error - send error response. The snmp routine has
436122394Sharti		 * changed the error fields in the original message. */
437122394Sharti		resp_b.asn_ptr = sndbuf;
438122394Sharti		resp_b.asn_len = snmpd.txbuf;
439122394Sharti		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
440122394Sharti			syslog(LOG_WARNING, "could not encode error response");
441122394Sharti			snmpd_stats.silentDrops++;
442122394Sharti			return (SNMPD_INPUT_FAILED);
443122394Sharti		} else {
444122394Sharti			if (debug.dump_pdus) {
445122394Sharti				snmp_printf("%s <- ", source);
446122394Sharti				snmp_pdu_dump(pdu);
447122394Sharti			}
448122394Sharti			*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
449122394Sharti			return (SNMPD_INPUT_OK);
450122394Sharti		}
451122394Sharti	}
452122394Sharti	abort();
453122394Sharti}
454122394Sharti
455124861Sharti/*
456124861Sharti * Insert a port into the right place in the transport's table of ports
457124861Sharti */
458124861Shartivoid
459124861Shartitrans_insert_port(struct transport *t, struct tport *port)
460124861Sharti{
461124861Sharti	struct tport *p;
462122394Sharti
463124861Sharti	TAILQ_FOREACH(p, &t->table, link) {
464124861Sharti		if (asn_compare_oid(&p->index, &port->index) > 0) {
465124861Sharti			TAILQ_INSERT_BEFORE(p, port, link);
466124861Sharti			return;
467124861Sharti		}
468124861Sharti	}
469124861Sharti	port->transport = t;
470124861Sharti	TAILQ_INSERT_TAIL(&t->table, port, link);
471124861Sharti}
472122394Sharti
473122394Sharti/*
474124861Sharti * Remove a port from a transport's list
475124861Sharti */
476124861Shartivoid
477124861Shartitrans_remove_port(struct tport *port)
478124861Sharti{
479124861Sharti
480124861Sharti	TAILQ_REMOVE(&port->transport->table, port, link);
481124861Sharti}
482124861Sharti
483124861Sharti/*
484124861Sharti * Find a port on a transport's list
485124861Sharti */
486124861Shartistruct tport *
487124861Shartitrans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub)
488124861Sharti{
489124861Sharti
490124861Sharti	return (FIND_OBJECT_OID(&t->table, idx, sub));
491124861Sharti}
492124861Sharti
493124861Sharti/*
494124861Sharti * Find next port on a transport's list
495124861Sharti */
496124861Shartistruct tport *
497124861Shartitrans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub)
498124861Sharti{
499124861Sharti
500124861Sharti	return (NEXT_OBJECT_OID(&t->table, idx, sub));
501124861Sharti}
502124861Sharti
503124861Sharti/*
504124861Sharti * Return first port
505124861Sharti */
506124861Shartistruct tport *
507124861Shartitrans_first_port(struct transport *t)
508124861Sharti{
509124861Sharti
510124861Sharti	return (TAILQ_FIRST(&t->table));
511124861Sharti}
512124861Sharti
513124861Sharti/*
514124861Sharti * Iterate through all ports until a function returns a 0.
515124861Sharti */
516124861Shartistruct tport *
517124861Shartitrans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t),
518124861Sharti    intptr_t arg)
519124861Sharti{
520124861Sharti	struct tport *p;
521124861Sharti
522124861Sharti	TAILQ_FOREACH(p, &t->table, link)
523124861Sharti		if (func(p, arg) == 0)
524124861Sharti			return (p);
525124861Sharti	return (NULL);
526124861Sharti}
527124861Sharti
528124861Sharti/*
529124861Sharti * Register a transport
530124861Sharti */
531124861Shartiint
532124861Shartitrans_register(const struct transport_def *def, struct transport **pp)
533124861Sharti{
534124861Sharti	u_int i;
535124861Sharti	char or_descr[256];
536124861Sharti
537124861Sharti	if ((*pp = malloc(sizeof(**pp))) == NULL)
538124861Sharti		return (SNMP_ERR_GENERR);
539124861Sharti
540124861Sharti	/* construct index */
541124861Sharti	(*pp)->index.len = strlen(def->name) + 1;
542124861Sharti	(*pp)->index.subs[0] = strlen(def->name);
543124861Sharti	for (i = 0; i < (*pp)->index.subs[0]; i++)
544124861Sharti		(*pp)->index.subs[i + 1] = def->name[i];
545124861Sharti
546124861Sharti	(*pp)->vtab = def;
547124861Sharti
548124861Sharti	if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) {
549124861Sharti		free(*pp);
550124861Sharti		return (SNMP_ERR_INCONS_VALUE);
551124861Sharti	}
552124861Sharti
553124861Sharti	/* register module */
554124861Sharti	snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name);
555124861Sharti	if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) {
556124861Sharti		free(*pp);
557124861Sharti		return (SNMP_ERR_GENERR);
558124861Sharti	}
559124861Sharti
560124861Sharti	INSERT_OBJECT_OID((*pp), &transport_list);
561124861Sharti
562124861Sharti	TAILQ_INIT(&(*pp)->table);
563124861Sharti
564124861Sharti	return (SNMP_ERR_NOERROR);
565124861Sharti}
566124861Sharti
567124861Sharti/*
568124861Sharti * Unregister transport
569124861Sharti */
570124861Shartiint
571124861Shartitrans_unregister(struct transport *t)
572124861Sharti{
573124861Sharti	if (!TAILQ_EMPTY(&t->table))
574124861Sharti		return (SNMP_ERR_INCONS_VALUE);
575124861Sharti
576124861Sharti	or_unregister(t->or_index);
577124861Sharti	TAILQ_REMOVE(&transport_list, t, link);
578124861Sharti
579124861Sharti	return (SNMP_ERR_NOERROR);
580124861Sharti}
581124861Sharti
582124861Sharti/*
583122394Sharti * File descriptor support
584122394Sharti */
585124861Sharti#ifdef USE_LIBBEGEMOT
586122394Shartistatic void
587124861Shartiinput(int fd, int mask __unused, void *uap)
588124861Sharti#else
589124861Shartistatic void
590122394Shartiinput(evContext ctx __unused, void *uap, int fd, int mask __unused)
591124861Sharti#endif
592122394Sharti{
593122394Sharti	struct fdesc *f = uap;
594122394Sharti
595122394Sharti	(*f->func)(fd, f->udata);
596122394Sharti}
597122394Sharti
598122394Shartivoid
599122394Shartifd_suspend(void *p)
600122394Sharti{
601122394Sharti	struct fdesc *f = p;
602122394Sharti
603124861Sharti#ifdef USE_LIBBEGEMOT
604124861Sharti	if (f->id >= 0) {
605124861Sharti		poll_unregister(f->id);
606124861Sharti		f->id = -1;
607124861Sharti	}
608124861Sharti#else
609122394Sharti	if (evTestID(f->id)) {
610122394Sharti		(void)evDeselectFD(evctx, f->id);
611122394Sharti		evInitID(&f->id);
612122394Sharti	}
613124861Sharti#endif
614122394Sharti}
615122394Sharti
616122394Shartiint
617122394Shartifd_resume(void *p)
618122394Sharti{
619122394Sharti	struct fdesc *f = p;
620122394Sharti	int err;
621122394Sharti
622124861Sharti#ifdef USE_LIBBEGEMOT
623124861Sharti	if (f->id >= 0)
624124861Sharti		return (0);
625142810Sharti	if ((f->id = poll_register(f->fd, input, f, POLL_IN)) < 0) {
626124861Sharti		err = errno;
627124861Sharti		syslog(LOG_ERR, "select fd %d: %m", f->fd);
628124861Sharti		errno = err;
629124861Sharti		return (-1);
630124861Sharti	}
631124861Sharti#else
632122394Sharti	if (evTestID(f->id))
633122394Sharti		return (0);
634122394Sharti	if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) {
635122394Sharti		err = errno;
636122394Sharti		syslog(LOG_ERR, "select fd %d: %m", f->fd);
637122394Sharti		errno = err;
638122394Sharti		return (-1);
639122394Sharti	}
640124861Sharti#endif
641122394Sharti	return (0);
642122394Sharti}
643122394Sharti
644122394Shartivoid *
645122394Shartifd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod)
646122394Sharti{
647122394Sharti	struct fdesc *f;
648122394Sharti	int err;
649122394Sharti
650122394Sharti	if ((f = malloc(sizeof(struct fdesc))) == NULL) {
651122394Sharti		err = errno;
652122394Sharti		syslog(LOG_ERR, "fd_select: %m");
653122394Sharti		errno = err;
654122394Sharti		return (NULL);
655122394Sharti	}
656122394Sharti	f->fd = fd;
657122394Sharti	f->func = func;
658122394Sharti	f->udata = udata;
659122394Sharti	f->owner = mod;
660124861Sharti#ifdef USE_LIBBEGEMOT
661124861Sharti	f->id = -1;
662124861Sharti#else
663122394Sharti	evInitID(&f->id);
664124861Sharti#endif
665122394Sharti
666122394Sharti	if (fd_resume(f)) {
667122394Sharti		err = errno;
668122394Sharti		free(f);
669122394Sharti		errno = err;
670122394Sharti		return (NULL);
671122394Sharti	}
672122394Sharti
673122394Sharti	LIST_INSERT_HEAD(&fdesc_list, f, link);
674122394Sharti
675122394Sharti	return (f);
676122394Sharti}
677122394Sharti
678122394Shartivoid
679122394Shartifd_deselect(void *p)
680122394Sharti{
681122394Sharti	struct fdesc *f = p;
682122394Sharti
683122394Sharti	LIST_REMOVE(f, link);
684122394Sharti	fd_suspend(f);
685122394Sharti	free(f);
686122394Sharti}
687122394Sharti
688122394Shartistatic void
689122394Shartifd_flush(struct lmodule *mod)
690122394Sharti{
691122394Sharti	struct fdesc *t, *t1;
692122394Sharti
693122394Sharti	t = LIST_FIRST(&fdesc_list);
694122394Sharti	while (t != NULL) {
695122394Sharti		t1 = LIST_NEXT(t, link);
696122394Sharti		if (t->owner == mod)
697122394Sharti			fd_deselect(t);
698122394Sharti		t = t1;
699122394Sharti	}
700122394Sharti}
701122394Sharti
702122394Sharti/*
703124861Sharti * Consume a message from the input buffer
704122394Sharti */
705122394Shartistatic void
706124861Shartisnmp_input_consume(struct port_input *pi)
707122394Sharti{
708124861Sharti	if (!pi->stream) {
709124861Sharti		/* always consume everything */
710124861Sharti		pi->length = 0;
711122394Sharti		return;
712122394Sharti	}
713124861Sharti	if (pi->consumed >= pi->length) {
714124861Sharti		/* all bytes consumed */
715124861Sharti		pi->length = 0;
716122394Sharti		return;
717122394Sharti	}
718124861Sharti	memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed);
719124861Sharti	pi->length -= pi->consumed;
720124861Sharti}
721124861Sharti
722124861Shartistruct credmsg {
723124861Sharti	struct cmsghdr hdr;
724124861Sharti	struct cmsgcred cred;
725124861Sharti};
726124861Sharti
727124861Shartistatic void
728124861Sharticheck_priv(struct port_input *pi, struct msghdr *msg)
729124861Sharti{
730124861Sharti	struct credmsg *cmsg;
731124861Sharti	struct xucred ucred;
732124861Sharti	socklen_t ucredlen;
733124861Sharti
734124861Sharti	pi->priv = 0;
735124861Sharti
736124861Sharti	if (msg->msg_controllen == sizeof(*cmsg)) {
737124861Sharti		/* process explicitely sends credentials */
738124861Sharti
739124861Sharti		cmsg = (struct credmsg *)msg->msg_control;
740124861Sharti		pi->priv = (cmsg->cred.cmcred_euid == 0);
741122394Sharti		return;
742122394Sharti	}
743124861Sharti
744124861Sharti	/* ok, obtain the accept time credentials */
745124861Sharti	ucredlen = sizeof(ucred);
746124861Sharti
747124861Sharti	if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 &&
748124861Sharti	    ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION)
749124861Sharti		pi->priv = (ucred.cr_uid == 0);
750124861Sharti}
751124861Sharti
752124861Sharti/*
753124861Sharti * Input from a stream socket.
754124861Sharti */
755124861Shartistatic int
756124861Shartirecv_stream(struct port_input *pi)
757124861Sharti{
758124861Sharti	struct msghdr msg;
759124861Sharti	struct iovec iov[1];
760124861Sharti	ssize_t len;
761124861Sharti	struct credmsg cmsg;
762124861Sharti
763124861Sharti	if (pi->buf == NULL) {
764124861Sharti		/* no buffer yet - allocate one */
765124861Sharti		if ((pi->buf = buf_alloc(0)) == NULL) {
766124861Sharti			/* ups - could not get buffer. Return an error
767124861Sharti			 * the caller must close the transport. */
768124861Sharti			return (-1);
769124861Sharti		}
770124861Sharti		pi->buflen = buf_size(0);
771124861Sharti		pi->consumed = 0;
772124861Sharti		pi->length = 0;
773124861Sharti	}
774124861Sharti
775124861Sharti	/* try to get a message */
776124861Sharti	msg.msg_name = pi->peer;
777124861Sharti	msg.msg_namelen = pi->peerlen;
778124861Sharti	msg.msg_iov = iov;
779124861Sharti	msg.msg_iovlen = 1;
780124861Sharti	if (pi->cred) {
781124861Sharti		msg.msg_control = &cmsg;
782124861Sharti		msg.msg_controllen = sizeof(cmsg);
783124861Sharti
784124861Sharti		cmsg.hdr.cmsg_len = sizeof(cmsg);
785124861Sharti		cmsg.hdr.cmsg_level = SOL_SOCKET;
786124861Sharti		cmsg.hdr.cmsg_type = SCM_CREDS;
787124861Sharti	} else {
788124861Sharti		msg.msg_control = NULL;
789124861Sharti		msg.msg_controllen = 0;
790124861Sharti	}
791124861Sharti	msg.msg_flags = 0;
792124861Sharti
793124861Sharti	iov[0].iov_base = pi->buf + pi->length;
794124861Sharti	iov[0].iov_len = pi->buflen - pi->length;
795124861Sharti
796124861Sharti	len = recvmsg(pi->fd, &msg, 0);
797124861Sharti
798124861Sharti	if (len == -1 || len == 0)
799124861Sharti		/* receive error */
800124861Sharti		return (-1);
801124861Sharti
802124861Sharti	pi->length += len;
803124861Sharti
804124861Sharti	if (pi->cred)
805124861Sharti		check_priv(pi, &msg);
806124861Sharti
807124861Sharti	return (0);
808124861Sharti}
809124861Sharti
810124861Sharti/*
811124861Sharti * Input from a datagram socket.
812124861Sharti * Each receive should return one datagram.
813124861Sharti */
814124861Shartistatic int
815124861Shartirecv_dgram(struct port_input *pi)
816124861Sharti{
817124861Sharti	u_char embuf[1000];
818124861Sharti	struct msghdr msg;
819124861Sharti	struct iovec iov[1];
820124861Sharti	ssize_t len;
821124861Sharti	struct credmsg cmsg;
822124861Sharti
823124861Sharti	if (pi->buf == NULL) {
824124861Sharti		/* no buffer yet - allocate one */
825124861Sharti		if ((pi->buf = buf_alloc(0)) == NULL) {
826124861Sharti			/* ups - could not get buffer. Read away input
827124861Sharti			 * and drop it */
828124861Sharti			(void)recvfrom(pi->fd, embuf, sizeof(embuf),
829124861Sharti			    0, NULL, NULL);
830124861Sharti			/* return error */
831124861Sharti			return (-1);
832124861Sharti		}
833124861Sharti		pi->buflen = buf_size(0);
834124861Sharti	}
835124861Sharti
836124861Sharti	/* try to get a message */
837124861Sharti	msg.msg_name = pi->peer;
838124861Sharti	msg.msg_namelen = pi->peerlen;
839124861Sharti	msg.msg_iov = iov;
840124861Sharti	msg.msg_iovlen = 1;
841124861Sharti	if (pi->cred) {
842124861Sharti		msg.msg_control = &cmsg;
843124861Sharti		msg.msg_controllen = sizeof(cmsg);
844124861Sharti
845124861Sharti		cmsg.hdr.cmsg_len = sizeof(cmsg);
846124861Sharti		cmsg.hdr.cmsg_level = SOL_SOCKET;
847124861Sharti		cmsg.hdr.cmsg_type = SCM_CREDS;
848124861Sharti	} else {
849124861Sharti		msg.msg_control = NULL;
850128237Sharti		msg.msg_controllen = 0;
851124861Sharti	}
852124861Sharti	msg.msg_flags = 0;
853124861Sharti
854124861Sharti	iov[0].iov_base = pi->buf;
855124861Sharti	iov[0].iov_len = pi->buflen;
856124861Sharti
857124861Sharti	len = recvmsg(pi->fd, &msg, 0);
858124861Sharti
859124861Sharti	if (len == -1 || len == 0)
860124861Sharti		/* receive error */
861124861Sharti		return (-1);
862124861Sharti
863124861Sharti	if (msg.msg_flags & MSG_TRUNC) {
864124861Sharti		/* truncated - drop */
865122394Sharti		snmpd_stats.silentDrops++;
866122394Sharti		snmpd_stats.inTooLong++;
867124861Sharti		return (-1);
868122394Sharti	}
869122394Sharti
870124861Sharti	pi->length = (size_t)len;
871124861Sharti
872124861Sharti	if (pi->cred)
873124861Sharti		check_priv(pi, &msg);
874124861Sharti
875124861Sharti	return (0);
876124861Sharti}
877124861Sharti
878124861Sharti/*
879124861Sharti * Input from a socket
880124861Sharti */
881124861Shartiint
882124861Shartisnmpd_input(struct port_input *pi, struct tport *tport)
883124861Sharti{
884124861Sharti	u_char *sndbuf;
885124861Sharti	size_t sndlen;
886124861Sharti	struct snmp_pdu pdu;
887124861Sharti	enum snmpd_input_err ierr, ferr;
888124861Sharti	enum snmpd_proxy_err perr;
889124861Sharti	int32_t vi;
890124861Sharti	int ret;
891124861Sharti	ssize_t slen;
892145557Sharti#ifdef USE_TCPWRAPPERS
893145557Sharti	char client[16];
894145557Sharti#endif
895124861Sharti
896124861Sharti	/* get input depending on the transport */
897124861Sharti	if (pi->stream) {
898124861Sharti		ret = recv_stream(pi);
899124861Sharti	} else {
900124861Sharti		ret = recv_dgram(pi);
901124861Sharti	}
902124861Sharti
903124861Sharti	if (ret == -1)
904124861Sharti		return (-1);
905124861Sharti
906145557Sharti#ifdef USE_TCPWRAPPERS
907122394Sharti	/*
908145557Sharti	 * In case of AF_INET{6} peer, do hosts_access(5) check.
909145557Sharti	 */
910145557Sharti	if (inet_ntop(pi->peer->sa_family,
911145557Sharti	    &((struct sockaddr_in *)pi->peer)->sin_addr, client,
912145557Sharti	    sizeof(client)) != NULL) {
913145557Sharti		request_set(&req, RQ_CLIENT_ADDR, client, 0);
914145557Sharti		if (hosts_access(&req) == 0) {
915145557Sharti			syslog(LOG_ERR, "refused connection from %.500s",
916145557Sharti			    eval_client(&req));
917145557Sharti			return (-1);
918145557Sharti		}
919145557Sharti	} else
920145557Sharti		syslog(LOG_ERR, "inet_ntop(): %m");
921145557Sharti#endif
922145557Sharti
923145557Sharti	/*
924122394Sharti	 * Handle input
925122394Sharti	 */
926124861Sharti	ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi,
927124861Sharti	    &pi->consumed);
928124861Sharti	if (ierr == SNMPD_INPUT_TRUNC) {
929124861Sharti		/* need more bytes. This is ok only for streaming transports.
930124861Sharti		 * but only if we have not reached bufsiz yet. */
931124861Sharti		if (pi->stream) {
932124861Sharti			if (pi->length == buf_size(0)) {
933124861Sharti				snmpd_stats.silentDrops++;
934124861Sharti				return (-1);
935124861Sharti			}
936124861Sharti			return (0);
937124861Sharti		}
938124861Sharti		snmpd_stats.silentDrops++;
939124861Sharti		return (-1);
940124861Sharti	}
941122394Sharti
942122394Sharti	/* can't check for bad SET pdus here, because a proxy may have to
943122394Sharti	 * check the access first. We don't want to return an error response
944122394Sharti	 * to a proxy PDU with a wrong community */
945122394Sharti	if (ierr == SNMPD_INPUT_FAILED) {
946124861Sharti		/* for streaming transports this is fatal */
947124861Sharti		if (pi->stream)
948124861Sharti			return (-1);
949124861Sharti		snmp_input_consume(pi);
950124861Sharti		return (0);
951122394Sharti	}
952133211Sharti	if (ierr == SNMPD_INPUT_BAD_COMM) {
953133211Sharti		snmp_input_consume(pi);
954133211Sharti		return (0);
955133211Sharti	}
956122394Sharti
957122394Sharti	/*
958122394Sharti	 * If that is a module community and the module has a proxy function,
959122394Sharti	 * the hand it over to the module.
960122394Sharti	 */
961122394Sharti	if (comm->owner != NULL && comm->owner->config->proxy != NULL) {
962124861Sharti		perr = (*comm->owner->config->proxy)(&pdu, tport->transport,
963133211Sharti		    &tport->index, pi->peer, pi->peerlen, ierr, vi,
964133211Sharti		    !pi->cred || pi->priv);
965122394Sharti
966122394Sharti		switch (perr) {
967122394Sharti
968122394Sharti		  case SNMPD_PROXY_OK:
969124861Sharti			snmp_input_consume(pi);
970124861Sharti			return (0);
971122394Sharti
972122394Sharti		  case SNMPD_PROXY_REJ:
973122394Sharti			break;
974122394Sharti
975122394Sharti		  case SNMPD_PROXY_DROP:
976124861Sharti			snmp_input_consume(pi);
977122394Sharti			snmp_pdu_free(&pdu);
978122394Sharti			snmpd_stats.proxyDrops++;
979124861Sharti			return (0);
980122394Sharti
981122394Sharti		  case SNMPD_PROXY_BADCOMM:
982124861Sharti			snmp_input_consume(pi);
983122394Sharti			snmp_pdu_free(&pdu);
984122394Sharti			snmpd_stats.inBadCommunityNames++;
985122394Sharti			if (snmpd.auth_traps)
986122394Sharti				snmp_send_trap(&oid_authenticationFailure,
987133211Sharti				    (struct snmp_value *)NULL);
988124861Sharti			return (0);
989122394Sharti
990122394Sharti		  case SNMPD_PROXY_BADCOMMUSE:
991124861Sharti			snmp_input_consume(pi);
992122394Sharti			snmp_pdu_free(&pdu);
993122394Sharti			snmpd_stats.inBadCommunityUses++;
994122394Sharti			if (snmpd.auth_traps)
995122394Sharti				snmp_send_trap(&oid_authenticationFailure,
996133211Sharti				    (struct snmp_value *)NULL);
997124861Sharti			return (0);
998122394Sharti		}
999122394Sharti	}
1000122394Sharti
1001122394Sharti	/*
1002122394Sharti	 * Check type
1003122394Sharti	 */
1004122394Sharti	if (pdu.type == SNMP_PDU_RESPONSE ||
1005122394Sharti	    pdu.type == SNMP_PDU_TRAP ||
1006122394Sharti	    pdu.type == SNMP_PDU_TRAP2) {
1007122394Sharti		snmpd_stats.silentDrops++;
1008122394Sharti		snmpd_stats.inBadPduTypes++;
1009122394Sharti		snmp_pdu_free(&pdu);
1010124861Sharti		snmp_input_consume(pi);
1011124861Sharti		return (0);
1012122394Sharti	}
1013122394Sharti
1014122394Sharti	/*
1015122394Sharti	 * Check community
1016122394Sharti	 */
1017124861Sharti	if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) ||
1018124861Sharti	    (community != COMM_WRITE &&
1019124861Sharti            (pdu.type == SNMP_PDU_SET || community != COMM_READ))) {
1020122394Sharti		snmpd_stats.inBadCommunityUses++;
1021122394Sharti		snmp_pdu_free(&pdu);
1022124861Sharti		snmp_input_consume(pi);
1023122394Sharti		if (snmpd.auth_traps)
1024133211Sharti			snmp_send_trap(&oid_authenticationFailure,
1025133211Sharti			    (struct snmp_value *)NULL);
1026124861Sharti		return (0);
1027122394Sharti	}
1028122394Sharti
1029122394Sharti	/*
1030122394Sharti	 * Execute it.
1031122394Sharti	 */
1032122394Sharti	if ((sndbuf = buf_alloc(1)) == NULL) {
1033122394Sharti		snmpd_stats.silentDrops++;
1034122394Sharti		snmp_pdu_free(&pdu);
1035124861Sharti		snmp_input_consume(pi);
1036124861Sharti		return (0);
1037122394Sharti	}
1038124861Sharti	ferr = snmp_input_finish(&pdu, pi->buf, pi->length,
1039124861Sharti	    sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
1040122394Sharti
1041122394Sharti	if (ferr == SNMPD_INPUT_OK) {
1042124861Sharti		slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen);
1043124861Sharti		if (slen == -1)
1044122394Sharti			syslog(LOG_ERR, "sendto: %m");
1045124861Sharti		else if ((size_t)slen != sndlen)
1046122394Sharti			syslog(LOG_ERR, "sendto: short write %zu/%zu",
1047124861Sharti			    sndlen, (size_t)slen);
1048122394Sharti	}
1049122394Sharti	snmp_pdu_free(&pdu);
1050122394Sharti	free(sndbuf);
1051124861Sharti	snmp_input_consume(pi);
1052122394Sharti
1053124861Sharti	return (0);
1054122394Sharti}
1055122394Sharti
1056122394Sharti/*
1057124861Sharti * Send a PDU to a given port
1058122394Sharti */
1059124861Shartivoid
1060124861Shartisnmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
1061124861Sharti    const struct sockaddr *addr, socklen_t addrlen)
1062122394Sharti{
1063124861Sharti	struct transport *trans = targ;
1064124861Sharti	struct tport *tp;
1065124861Sharti	u_char *sndbuf;
1066124861Sharti	size_t sndlen;
1067124861Sharti	ssize_t len;
1068122394Sharti
1069124861Sharti	TAILQ_FOREACH(tp, &trans->table, link)
1070124861Sharti		if (asn_compare_oid(port, &tp->index) == 0)
1071122394Sharti			break;
1072124861Sharti	if (tp == 0)
1073124861Sharti		return;
1074122394Sharti
1075124861Sharti	if ((sndbuf = buf_alloc(1)) == NULL)
1076124861Sharti		return;
1077122394Sharti
1078124861Sharti	snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
1079122394Sharti
1080124861Sharti	len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
1081122394Sharti
1082124861Sharti	if (len == -1)
1083124861Sharti		syslog(LOG_ERR, "sendto: %m");
1084124861Sharti	else if ((size_t)len != sndlen)
1085124861Sharti		syslog(LOG_ERR, "sendto: short write %zu/%zu",
1086124861Sharti		    sndlen, (size_t)len);
1087122394Sharti
1088124861Sharti	free(sndbuf);
1089122394Sharti}
1090122394Sharti
1091122394Sharti
1092122394Sharti/*
1093124861Sharti * Close an input source
1094122394Sharti */
1095122394Shartivoid
1096124861Shartisnmpd_input_close(struct port_input *pi)
1097122394Sharti{
1098124861Sharti	if (pi->id != NULL)
1099124861Sharti		fd_deselect(pi->id);
1100124861Sharti	if (pi->fd >= 0)
1101124861Sharti		(void)close(pi->fd);
1102124861Sharti	if (pi->buf != NULL)
1103124861Sharti		free(pi->buf);
1104122394Sharti}
1105122394Sharti
1106122394Sharti/*
1107122394Sharti * Dump internal state.
1108122394Sharti */
1109124861Sharti#ifdef USE_LIBBEGEMOT
1110122394Shartistatic void
1111124861Shartiinfo_func(void)
1112124861Sharti#else
1113124861Shartistatic void
1114122394Shartiinfo_func(evContext ctx __unused, void *uap __unused, const void *tag __unused)
1115124861Sharti#endif
1116122394Sharti{
1117122394Sharti	struct lmodule *m;
1118122394Sharti	u_int i;
1119122394Sharti	char buf[10000];
1120122394Sharti
1121122394Sharti	syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());
1122122394Sharti	for (i = 0; i < tree_size; i++) {
1123122394Sharti		switch (tree[i].type) {
1124122394Sharti
1125122394Sharti		  case SNMP_NODE_LEAF:
1126122394Sharti			sprintf(buf, "LEAF: %s %s", tree[i].name,
1127122394Sharti			    asn_oid2str(&tree[i].oid));
1128122394Sharti			break;
1129122394Sharti
1130122394Sharti		  case SNMP_NODE_COLUMN:
1131122394Sharti			sprintf(buf, "COL: %s %s", tree[i].name,
1132122394Sharti			    asn_oid2str(&tree[i].oid));
1133122394Sharti			break;
1134122394Sharti		}
1135122394Sharti		syslog(LOG_DEBUG, "%s", buf);
1136122394Sharti	}
1137122394Sharti
1138122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
1139122394Sharti		if (m->config->dump)
1140122394Sharti			(*m->config->dump)();
1141122394Sharti}
1142122394Sharti
1143122394Sharti/*
1144122394Sharti * Re-read configuration
1145122394Sharti */
1146124861Sharti#ifdef USE_LIBBEGEMOT
1147122394Shartistatic void
1148124861Sharticonfig_func(void)
1149124861Sharti#else
1150124861Shartistatic void
1151122394Sharticonfig_func(evContext ctx __unused, void *uap __unused,
1152122394Sharti    const void *tag __unused)
1153124861Sharti#endif
1154122394Sharti{
1155122394Sharti	struct lmodule *m;
1156122394Sharti
1157122394Sharti	if (read_config(config_file, NULL)) {
1158122394Sharti		syslog(LOG_ERR, "error reading config file '%s'", config_file);
1159122394Sharti		return;
1160122394Sharti	}
1161122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
1162122394Sharti		if (m->config->config)
1163122394Sharti			(*m->config->config)();
1164122394Sharti}
1165122394Sharti
1166122394Sharti/*
1167122394Sharti * On USR1 dump actual configuration.
1168122394Sharti */
1169122394Shartistatic void
1170122394Shartionusr1(int s __unused)
1171122394Sharti{
1172124861Sharti
1173122394Sharti	work |= WORK_DOINFO;
1174122394Sharti}
1175122394Shartistatic void
1176122394Shartionhup(int s __unused)
1177122394Sharti{
1178124861Sharti
1179122394Sharti	work |= WORK_RECONFIG;
1180122394Sharti}
1181122394Sharti
1182122394Shartistatic void
1183122394Shartionterm(int s __unused)
1184122394Sharti{
1185122394Sharti
1186124861Sharti	/* allow clean-up */
1187122394Sharti	exit(0);
1188122394Sharti}
1189122394Sharti
1190122394Shartistatic void
1191122394Shartiinit_sigs(void)
1192122394Sharti{
1193122394Sharti	struct sigaction sa;
1194122394Sharti
1195122394Sharti	sa.sa_handler = onusr1;
1196122394Sharti	sa.sa_flags = SA_RESTART;
1197122394Sharti	sigemptyset(&sa.sa_mask);
1198122394Sharti	if (sigaction(SIGUSR1, &sa, NULL)) {
1199122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1200122394Sharti		exit(1);
1201122394Sharti	}
1202122394Sharti
1203122394Sharti	sa.sa_handler = onhup;
1204122394Sharti	if (sigaction(SIGHUP, &sa, NULL)) {
1205122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1206122394Sharti		exit(1);
1207122394Sharti	}
1208122394Sharti
1209122394Sharti	sa.sa_handler = onterm;
1210122394Sharti	sa.sa_flags = 0;
1211122394Sharti	sigemptyset(&sa.sa_mask);
1212122394Sharti	if (sigaction(SIGTERM, &sa, NULL)) {
1213122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1214122394Sharti		exit(1);
1215122394Sharti	}
1216122394Sharti	if (sigaction(SIGINT, &sa, NULL)) {
1217122394Sharti		syslog(LOG_ERR, "sigaction: %m");
1218122394Sharti		exit(1);
1219122394Sharti	}
1220122394Sharti}
1221122394Sharti
1222122394Shartistatic void
1223122394Shartiblock_sigs(void)
1224122394Sharti{
1225122394Sharti	sigset_t set;
1226122394Sharti
1227122394Sharti	sigfillset(&set);
1228122394Sharti	if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) {
1229122394Sharti		syslog(LOG_ERR, "SIG_BLOCK: %m");
1230122394Sharti		exit(1);
1231122394Sharti	}
1232122394Sharti}
1233122394Shartistatic void
1234122394Shartiunblock_sigs(void)
1235122394Sharti{
1236122394Sharti	if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) {
1237122394Sharti		syslog(LOG_ERR, "SIG_SETMASK: %m");
1238122394Sharti		exit(1);
1239122394Sharti	}
1240122394Sharti}
1241122394Sharti
1242122394Sharti/*
1243122394Sharti * Shut down
1244122394Sharti */
1245122394Shartistatic void
1246122394Shartiterm(void)
1247122394Sharti{
1248122394Sharti	(void)unlink(pid_file);
1249122394Sharti}
1250122394Sharti
1251124861Shartistatic void
1252124861Shartitrans_stop(void)
1253124861Sharti{
1254124861Sharti	struct transport *t;
1255124861Sharti
1256124861Sharti	TAILQ_FOREACH(t, &transport_list, link)
1257124861Sharti		(void)t->vtab->stop(1);
1258124861Sharti}
1259124861Sharti
1260122394Sharti/*
1261122394Sharti * Define a macro from the command line
1262122394Sharti */
1263122394Shartistatic void
1264122394Shartido_macro(char *arg)
1265122394Sharti{
1266122394Sharti	char *eq;
1267122394Sharti	int err;
1268122394Sharti
1269122394Sharti	if ((eq = strchr(arg, '=')) == NULL)
1270122394Sharti		err = define_macro(arg, "");
1271122394Sharti	else {
1272122394Sharti		*eq++ = '\0';
1273122394Sharti		err = define_macro(arg, eq);
1274122394Sharti	}
1275122394Sharti	if (err == -1) {
1276122394Sharti		syslog(LOG_ERR, "cannot save macro: %m");
1277122394Sharti		exit(1);
1278122394Sharti	}
1279122394Sharti}
1280122394Sharti
1281122394Sharti/*
1282122394Sharti * Re-implement getsubopt from scratch, because the second argument is broken
1283122394Sharti * and will not compile with WARNS=5.
1284122394Sharti */
1285122394Shartistatic int
1286122394Shartigetsubopt1(char **arg, const char *const *options, char **valp, char **optp)
1287122394Sharti{
1288122394Sharti	static const char *const delim = ",\t ";
1289122394Sharti	u_int i;
1290122394Sharti	char *ptr;
1291122394Sharti
1292122394Sharti	*optp = NULL;
1293122394Sharti
1294122394Sharti	/* skip leading junk */
1295122394Sharti	for (ptr = *arg; *ptr != '\0'; ptr++)
1296122394Sharti		if (strchr(delim, *ptr) == NULL)
1297122394Sharti			break;
1298122394Sharti	if (*ptr == '\0') {
1299122394Sharti		*arg = ptr;
1300122394Sharti		return (-1);
1301122394Sharti	}
1302122394Sharti	*optp = ptr;
1303122394Sharti
1304122394Sharti	/* find the end of the option */
1305122394Sharti	while (*++ptr != '\0')
1306122394Sharti		if (strchr(delim, *ptr) != NULL || *ptr == '=')
1307122394Sharti			break;
1308122394Sharti
1309122394Sharti	if (*ptr != '\0') {
1310122394Sharti		if (*ptr == '=') {
1311122394Sharti			*ptr++ = '\0';
1312122394Sharti			*valp = ptr;
1313122394Sharti			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
1314122394Sharti				ptr++;
1315122394Sharti			if (*ptr != '\0')
1316122394Sharti				*ptr++ = '\0';
1317122394Sharti		} else
1318122394Sharti			*ptr++ = '\0';
1319122394Sharti	}
1320122394Sharti
1321122394Sharti	*arg = ptr;
1322122394Sharti
1323122394Sharti	for (i = 0; *options != NULL; options++, i++)
1324124861Sharti		if (strcmp(*optp, *options) == 0)
1325122394Sharti			return (i);
1326122394Sharti	return (-1);
1327122394Sharti}
1328122394Sharti
1329122394Shartiint
1330122394Shartimain(int argc, char *argv[])
1331122394Sharti{
1332122394Sharti	int opt;
1333122394Sharti	FILE *fp;
1334122394Sharti	int background = 1;
1335124861Sharti	struct tport *p;
1336122394Sharti	const char *prefix = "snmpd";
1337122394Sharti	struct lmodule *m;
1338122394Sharti	char *value, *option;
1339124861Sharti	struct transport *t;
1340122394Sharti
1341122394Sharti#define DBG_DUMP	0
1342122394Sharti#define DBG_EVENTS	1
1343122394Sharti#define DBG_TRACE	2
1344122394Sharti	static const char *const debug_opts[] = {
1345122394Sharti		"dump",
1346122394Sharti		"events",
1347122394Sharti		"trace",
1348122394Sharti		NULL
1349122394Sharti	};
1350122394Sharti
1351122394Sharti	snmp_printf = snmp_printf_func;
1352122394Sharti	snmp_error = snmp_error_func;
1353122394Sharti	snmp_debug = snmp_debug_func;
1354122394Sharti	asn_error = asn_error_func;
1355122394Sharti
1356122394Sharti	while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF)
1357122394Sharti		switch (opt) {
1358122394Sharti
1359122394Sharti		  case 'c':
1360122394Sharti			strlcpy(config_file, optarg, sizeof(config_file));
1361122394Sharti			break;
1362122394Sharti
1363122394Sharti		  case 'd':
1364122394Sharti			background = 0;
1365122394Sharti			break;
1366122394Sharti
1367122394Sharti		  case 'D':
1368122394Sharti			while (*optarg) {
1369122394Sharti				switch (getsubopt1(&optarg, debug_opts,
1370122394Sharti				    &value, &option)) {
1371122394Sharti
1372122394Sharti				  case DBG_DUMP:
1373122394Sharti					debug.dump_pdus = 1;
1374122394Sharti					break;
1375122394Sharti
1376122394Sharti				  case DBG_EVENTS:
1377122394Sharti					debug.evdebug++;
1378122394Sharti					break;
1379122394Sharti
1380122394Sharti				  case DBG_TRACE:
1381122394Sharti					if (value == NULL)
1382122394Sharti						syslog(LOG_ERR,
1383122394Sharti						    "no value for 'trace'");
1384122394Sharti					snmp_trace = strtoul(value, NULL, 0);
1385122394Sharti					break;
1386122394Sharti
1387122394Sharti				  case -1:
1388122394Sharti					if (suboptarg)
1389122394Sharti						syslog(LOG_ERR,
1390122394Sharti						    "unknown debug flag '%s'",
1391122394Sharti						    option);
1392122394Sharti					else
1393122394Sharti						syslog(LOG_ERR,
1394122394Sharti						    "missing debug flag");
1395122394Sharti					break;
1396122394Sharti				}
1397122394Sharti			}
1398122394Sharti			break;
1399122394Sharti
1400122394Sharti		  case 'h':
1401122394Sharti			fprintf(stderr, "%s", usgtxt);
1402122394Sharti			exit(0);
1403122394Sharti
1404122394Sharti		  case 'I':
1405122394Sharti			syspath = optarg;
1406122394Sharti			break;
1407122394Sharti
1408122394Sharti		  case 'l':
1409122394Sharti			prefix = optarg;
1410122394Sharti			break;
1411122394Sharti
1412122394Sharti		  case 'm':
1413122394Sharti			do_macro(optarg);
1414122394Sharti			break;
1415122394Sharti
1416122394Sharti		  case 'p':
1417122394Sharti			strlcpy(pid_file, optarg, sizeof(pid_file));
1418122394Sharti			break;
1419122394Sharti		}
1420122394Sharti
1421122394Sharti	openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
1422122394Sharti	setlogmask(LOG_UPTO(debug.logpri - 1));
1423122394Sharti
1424122394Sharti	if (background && daemon(0, 0) < 0) {
1425122394Sharti		syslog(LOG_ERR, "daemon: %m");
1426122394Sharti		exit(1);
1427122394Sharti	}
1428122394Sharti
1429122394Sharti	argc -= optind;
1430122394Sharti	argv += optind;
1431122394Sharti
1432122394Sharti	progargs = argv;
1433122394Sharti	nprogargs = argc;
1434122394Sharti
1435122394Sharti	srandomdev();
1436122394Sharti
1437122394Sharti	snmp_serial_no = random();
1438122394Sharti
1439145557Sharti#ifdef USE_TCPWRAPPERS
1440122394Sharti	/*
1441145557Sharti	 * Initialize hosts_access(3) handler.
1442145557Sharti	 */
1443145557Sharti	request_init(&req, RQ_DAEMON, "snmpd", 0);
1444145557Sharti	sock_methods(&req);
1445145557Sharti#endif
1446145557Sharti
1447145557Sharti	/*
1448122394Sharti	 * Initialize the tree.
1449122394Sharti	 */
1450122394Sharti	if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) {
1451122394Sharti		syslog(LOG_ERR, "%m");
1452122394Sharti		exit(1);
1453122394Sharti	}
1454122394Sharti	memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE);
1455122394Sharti	tree_size = CTREE_SIZE;
1456122394Sharti
1457122394Sharti	/*
1458122394Sharti	 * Get standard communities
1459122394Sharti	 */
1460122394Sharti	(void)comm_define(1, "SNMP read", NULL, "public");
1461122394Sharti	(void)comm_define(2, "SNMP write", NULL, "public");
1462122394Sharti	community = COMM_INITIALIZE;
1463122394Sharti
1464122394Sharti	trap_reqid = reqid_allocate(512, NULL);
1465122394Sharti
1466122394Sharti	if (config_file[0] == '\0')
1467122394Sharti		snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix);
1468122394Sharti
1469122394Sharti	init_actvals();
1470124861Sharti
1471124861Sharti	start_tick = get_ticks();
1472124861Sharti	this_tick = get_ticks();
1473124861Sharti
1474124861Sharti	/* start transports */
1475124861Sharti	if (atexit(trans_stop) == -1) {
1476124861Sharti		syslog(LOG_ERR, "atexit failed: %m");
1477124861Sharti		exit(1);
1478124861Sharti	}
1479124861Sharti	if (udp_trans.start() != SNMP_ERR_NOERROR)
1480124861Sharti		syslog(LOG_WARNING, "cannot start UDP transport");
1481124861Sharti	if (lsock_trans.start() != SNMP_ERR_NOERROR)
1482124861Sharti		syslog(LOG_WARNING, "cannot start LSOCK transport");
1483124861Sharti
1484124861Sharti#ifdef USE_LIBBEGEMOT
1485124861Sharti	if (debug.evdebug > 0)
1486124861Sharti		rpoll_trace = 1;
1487124861Sharti#else
1488122394Sharti	if (evCreate(&evctx)) {
1489122394Sharti		syslog(LOG_ERR, "evCreate: %m");
1490122394Sharti		exit(1);
1491122394Sharti	}
1492122394Sharti	if (debug.evdebug > 0)
1493122394Sharti		evSetDebug(evctx, 10, stderr);
1494124861Sharti#endif
1495122394Sharti
1496133211Sharti	if (read_config(config_file, NULL)) {
1497133211Sharti		syslog(LOG_ERR, "error in config file");
1498133211Sharti		exit(1);
1499133211Sharti	}
1500133211Sharti
1501124861Sharti	TAILQ_FOREACH(t, &transport_list, link)
1502124861Sharti		TAILQ_FOREACH(p, &t->table, link)
1503124861Sharti			t->vtab->init_port(p);
1504122394Sharti
1505122394Sharti	init_sigs();
1506122394Sharti
1507122394Sharti	if (pid_file[0] == '\0')
1508122394Sharti		snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix);
1509122394Sharti
1510122394Sharti	if ((fp = fopen(pid_file, "w")) != NULL) {
1511122394Sharti		fprintf(fp, "%u", getpid());
1512122394Sharti		fclose(fp);
1513124861Sharti		if (atexit(term) == -1) {
1514124861Sharti			syslog(LOG_ERR, "atexit failed: %m");
1515124861Sharti			(void)remove(pid_file);
1516124861Sharti			exit(0);
1517124861Sharti		}
1518122394Sharti	}
1519122394Sharti
1520122394Sharti	if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.",
1521122394Sharti	    NULL) == 0) {
1522122394Sharti		syslog(LOG_ERR, "cannot register SNMPv2 MIB");
1523122394Sharti		exit(1);
1524122394Sharti	}
1525122394Sharti	if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.",
1526122394Sharti	    NULL) == 0) {
1527122394Sharti		syslog(LOG_ERR, "cannot register begemotSnmpd MIB");
1528122394Sharti		exit(1);
1529122394Sharti	}
1530122394Sharti
1531133211Sharti	snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL);
1532122394Sharti
1533122394Sharti	while ((m = TAILQ_FIRST(&modules_start)) != NULL) {
1534122394Sharti		m->flags &= ~LM_ONSTARTLIST;
1535122394Sharti		TAILQ_REMOVE(&modules_start, m, start);
1536122394Sharti		lm_start(m);
1537122394Sharti	}
1538122394Sharti
1539122394Sharti	for (;;) {
1540124861Sharti#ifndef USE_LIBBEGEMOT
1541122394Sharti		evEvent event;
1542124861Sharti#endif
1543122394Sharti		struct lmodule *mod;
1544122394Sharti
1545122394Sharti		TAILQ_FOREACH(mod, &lmodules, link)
1546122394Sharti			if (mod->config->idle != NULL)
1547122394Sharti				(*mod->config->idle)();
1548122394Sharti
1549124861Sharti#ifndef USE_LIBBEGEMOT
1550122394Sharti		if (evGetNext(evctx, &event, EV_WAIT) == 0) {
1551122394Sharti			if (evDispatch(evctx, event))
1552122394Sharti				syslog(LOG_ERR, "evDispatch: %m");
1553122394Sharti		} else if (errno != EINTR) {
1554122394Sharti			syslog(LOG_ERR, "evGetNext: %m");
1555122394Sharti			exit(1);
1556122394Sharti		}
1557124861Sharti#else
1558124861Sharti		poll_dispatch(1);
1559124861Sharti#endif
1560122394Sharti
1561122394Sharti		if (work != 0) {
1562122394Sharti			block_sigs();
1563122394Sharti			if (work & WORK_DOINFO) {
1564124861Sharti#ifdef USE_LIBBEGEMOT
1565124861Sharti				info_func();
1566124861Sharti#else
1567122394Sharti				if (evWaitFor(evctx, &work, info_func,
1568122394Sharti				    NULL, NULL) == -1) {
1569122394Sharti					syslog(LOG_ERR, "evWaitFor: %m");
1570122394Sharti					exit(1);
1571122394Sharti				}
1572124861Sharti#endif
1573122394Sharti			}
1574122394Sharti			if (work & WORK_RECONFIG) {
1575124861Sharti#ifdef USE_LIBBEGEMOT
1576124861Sharti				config_func();
1577124861Sharti#else
1578122394Sharti				if (evWaitFor(evctx, &work, config_func,
1579122394Sharti				    NULL, NULL) == -1) {
1580122394Sharti					syslog(LOG_ERR, "evWaitFor: %m");
1581122394Sharti					exit(1);
1582122394Sharti				}
1583124861Sharti#endif
1584122394Sharti			}
1585122394Sharti			work = 0;
1586122394Sharti			unblock_sigs();
1587124861Sharti#ifndef USE_LIBBEGEMOT
1588122394Sharti			if (evDo(evctx, &work) == -1) {
1589122394Sharti				syslog(LOG_ERR, "evDo: %m");
1590122394Sharti				exit(1);
1591122394Sharti			}
1592124861Sharti#endif
1593122394Sharti		}
1594122394Sharti	}
1595122394Sharti
1596122394Sharti	return (0);
1597122394Sharti}
1598122394Sharti
1599122394Sharti
1600122394Shartiu_int32_t
1601122394Shartiget_ticks()
1602122394Sharti{
1603122394Sharti	struct timeval tv;
1604122394Sharti	u_int32_t ret;
1605122394Sharti
1606122394Sharti	if (gettimeofday(&tv, NULL))
1607122394Sharti		abort();
1608122394Sharti	ret = tv.tv_sec * 100 + tv.tv_usec / 10000;
1609122394Sharti	return (ret);
1610122394Sharti}
1611122394Sharti/*
1612122394Sharti * Timer support
1613122394Sharti */
1614124861Sharti#ifdef USE_LIBBEGEMOT
1615122394Shartistatic void
1616124861Shartitfunc(int tid __unused, void *uap)
1617124861Sharti#else
1618124861Shartistatic void
1619122394Shartitfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1620122394Sharti	struct timespec inter __unused)
1621124861Sharti#endif
1622122394Sharti{
1623122394Sharti	struct timer *tp = uap;
1624122394Sharti
1625122394Sharti	LIST_REMOVE(tp, link);
1626122394Sharti	tp->func(tp->udata);
1627122394Sharti	free(tp);
1628122394Sharti}
1629122394Sharti
1630122394Sharti/*
1631122394Sharti * Start a timer
1632122394Sharti */
1633122394Shartivoid *
1634122394Shartitimer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
1635122394Sharti{
1636122394Sharti	struct timer *tp;
1637124861Sharti#ifdef USE_LIBBEGEMOT
1638124861Sharti	struct timeval due;
1639124861Sharti#else
1640122394Sharti	struct timespec due;
1641124861Sharti#endif
1642122394Sharti
1643122394Sharti	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1644122394Sharti		syslog(LOG_CRIT, "out of memory for timer");
1645122394Sharti		exit(1);
1646122394Sharti	}
1647124861Sharti#ifdef USE_LIBBEGEMOT
1648124861Sharti	(void)gettimeofday(&due, NULL);
1649124861Sharti	due.tv_sec += ticks / 100;
1650124861Sharti	due.tv_usec += (ticks % 100) * 10000;
1651124861Sharti	if (due.tv_usec >= 1000000) {
1652124861Sharti		due.tv_sec++;
1653124861Sharti		due.tv_usec -= 1000000;
1654124861Sharti	}
1655124861Sharti#else
1656122394Sharti	due = evAddTime(evNowTime(),
1657124861Sharti	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1658124861Sharti#endif
1659122394Sharti
1660122394Sharti	tp->udata = udata;
1661122394Sharti	tp->owner = mod;
1662122394Sharti	tp->func = func;
1663122394Sharti
1664122394Sharti	LIST_INSERT_HEAD(&timer_list, tp, link);
1665122394Sharti
1666124861Sharti#ifdef USE_LIBBEGEMOT
1667124861Sharti	if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000,
1668124861Sharti	    0, tfunc, tp)) < 0) {
1669124861Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1670124861Sharti		exit(1);
1671124861Sharti	}
1672124861Sharti#else
1673122394Sharti	if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
1674122394Sharti	    == -1) {
1675122394Sharti		syslog(LOG_ERR, "cannot set timer: %m");
1676122394Sharti		exit(1);
1677122394Sharti	}
1678124861Sharti#endif
1679122394Sharti	return (tp);
1680122394Sharti}
1681122394Sharti
1682122394Shartivoid
1683122394Shartitimer_stop(void *p)
1684122394Sharti{
1685122394Sharti	struct timer *tp = p;
1686122394Sharti
1687122394Sharti	LIST_REMOVE(tp, link);
1688124861Sharti#ifdef USE_LIBBEGEMOT
1689124861Sharti	poll_stop_timer(tp->id);
1690124861Sharti#else
1691122394Sharti	if (evClearTimer(evctx, tp->id) == -1) {
1692122394Sharti		syslog(LOG_ERR, "cannot stop timer: %m");
1693122394Sharti		exit(1);
1694122394Sharti	}
1695124861Sharti#endif
1696122394Sharti	free(p);
1697122394Sharti}
1698122394Sharti
1699122394Shartistatic void
1700122394Shartitimer_flush(struct lmodule *mod)
1701122394Sharti{
1702122394Sharti	struct timer *t, *t1;
1703122394Sharti
1704122394Sharti	t = LIST_FIRST(&timer_list);
1705122394Sharti	while (t != NULL) {
1706122394Sharti		t1 = LIST_NEXT(t, link);
1707122394Sharti		if (t->owner == mod)
1708122394Sharti			timer_stop(t);
1709122394Sharti		t = t1;
1710122394Sharti	}
1711122394Sharti}
1712122394Sharti
1713122394Shartistatic void
1714122394Shartisnmp_printf_func(const char *fmt, ...)
1715122394Sharti{
1716122394Sharti	va_list ap;
1717122394Sharti	static char *pend = NULL;
1718122394Sharti	char *ret, *new;
1719122394Sharti
1720122394Sharti	va_start(ap, fmt);
1721122394Sharti	vasprintf(&ret, fmt, ap);
1722122394Sharti	va_end(ap);
1723122394Sharti
1724122394Sharti	if (ret == NULL)
1725122394Sharti		return;
1726122394Sharti	if (pend != NULL) {
1727122394Sharti		if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1))
1728122394Sharti		    == NULL) {
1729122394Sharti			free(ret);
1730122394Sharti			return;
1731122394Sharti		}
1732122394Sharti		pend = new;
1733122394Sharti		strcat(pend, ret);
1734122394Sharti		free(ret);
1735122394Sharti	} else
1736122394Sharti		pend = ret;
1737122394Sharti
1738122394Sharti	while ((ret = strchr(pend, '\n')) != NULL) {
1739122394Sharti		*ret = '\0';
1740122394Sharti		syslog(LOG_DEBUG, "%s", pend);
1741122394Sharti		if (strlen(ret + 1) == 0) {
1742122394Sharti			free(pend);
1743122394Sharti			pend = NULL;
1744122394Sharti			break;
1745122394Sharti		}
1746122394Sharti		strcpy(pend, ret + 1);
1747122394Sharti	}
1748122394Sharti}
1749122394Sharti
1750122394Shartistatic void
1751122394Shartisnmp_error_func(const char *err, ...)
1752122394Sharti{
1753122394Sharti	char errbuf[1000];
1754122394Sharti	va_list ap;
1755122394Sharti
1756124861Sharti	if (!(snmp_trace & LOG_SNMP_ERRORS))
1757124861Sharti		return;
1758124861Sharti
1759122394Sharti	va_start(ap, err);
1760122394Sharti	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1761124861Sharti	vsnprintf(errbuf + strlen(errbuf),
1762124861Sharti	    sizeof(errbuf) - strlen(errbuf), err, ap);
1763122394Sharti	va_end(ap);
1764122394Sharti
1765122394Sharti	syslog(LOG_ERR, "%s", errbuf);
1766122394Sharti}
1767122394Sharti
1768122394Shartistatic void
1769122394Shartisnmp_debug_func(const char *err, ...)
1770122394Sharti{
1771122394Sharti	char errbuf[1000];
1772122394Sharti	va_list ap;
1773122394Sharti
1774122394Sharti	va_start(ap, err);
1775122394Sharti	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1776122394Sharti	vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf),
1777122394Sharti	    err, ap);
1778122394Sharti	va_end(ap);
1779122394Sharti
1780122394Sharti	syslog(LOG_DEBUG, "%s", errbuf);
1781122394Sharti}
1782122394Sharti
1783122394Shartistatic void
1784122394Shartiasn_error_func(const struct asn_buf *b, const char *err, ...)
1785122394Sharti{
1786122394Sharti	char errbuf[1000];
1787122394Sharti	va_list ap;
1788122394Sharti	u_int i;
1789122394Sharti
1790124861Sharti	if (!(snmp_trace & LOG_ASN1_ERRORS))
1791124861Sharti		return;
1792124861Sharti
1793122394Sharti	va_start(ap, err);
1794122394Sharti	snprintf(errbuf, sizeof(errbuf), "ASN.1: ");
1795124861Sharti	vsnprintf(errbuf + strlen(errbuf),
1796124861Sharti	    sizeof(errbuf) - strlen(errbuf), err, ap);
1797122394Sharti	va_end(ap);
1798122394Sharti
1799122394Sharti	if (b != NULL) {
1800124861Sharti		snprintf(errbuf + strlen(errbuf),
1801124861Sharti		    sizeof(errbuf) - strlen(errbuf), " at");
1802122394Sharti		for (i = 0; b->asn_len > i; i++)
1803124861Sharti			snprintf(errbuf + strlen(errbuf),
1804124861Sharti			    sizeof(errbuf) - strlen(errbuf),
1805124861Sharti			    " %02x", b->asn_cptr[i]);
1806122394Sharti	}
1807122394Sharti
1808122394Sharti	syslog(LOG_ERR, "%s", errbuf);
1809122394Sharti}
1810122394Sharti
1811122394Sharti/*
1812122394Sharti * Create a new community
1813122394Sharti */
1814122394Shartiu_int
1815122394Sharticomm_define(u_int priv, const char *descr, struct lmodule *owner,
1816122394Sharti    const char *str)
1817122394Sharti{
1818122394Sharti	struct community *c, *p;
1819122394Sharti	u_int ncomm;
1820122394Sharti
1821122394Sharti	/* generate an identifier */
1822122394Sharti	do {
1823122394Sharti		if ((ncomm = next_community_index++) == UINT_MAX)
1824122394Sharti			next_community_index = 1;
1825122394Sharti		TAILQ_FOREACH(c, &community_list, link)
1826122394Sharti			if (c->value == ncomm)
1827122394Sharti				break;
1828122394Sharti	} while (c != NULL);
1829122394Sharti
1830122394Sharti	if ((c = malloc(sizeof(struct community))) == NULL) {
1831122394Sharti		syslog(LOG_ERR, "comm_define: %m");
1832122394Sharti		return (0);
1833122394Sharti	}
1834122394Sharti	c->owner = owner;
1835122394Sharti	c->value = ncomm;
1836122394Sharti	c->descr = descr;
1837122394Sharti	c->string = NULL;
1838122394Sharti	c->private = priv;
1839122394Sharti
1840122394Sharti	if (str != NULL) {
1841122394Sharti		if((c->string = malloc(strlen(str)+1)) == NULL) {
1842122394Sharti			free(c);
1843122394Sharti			return (0);
1844122394Sharti		}
1845122394Sharti		strcpy(c->string, str);
1846122394Sharti	}
1847122394Sharti
1848122394Sharti	/* make index */
1849122394Sharti	if (c->owner == NULL) {
1850122394Sharti		c->index.len = 1;
1851122394Sharti		c->index.subs[0] = 0;
1852122394Sharti	} else {
1853122394Sharti		c->index = c->owner->index;
1854122394Sharti	}
1855122394Sharti	c->index.subs[c->index.len++] = c->private;
1856122394Sharti
1857122394Sharti	/*
1858122394Sharti	 * Insert ordered
1859122394Sharti	 */
1860122394Sharti	TAILQ_FOREACH(p, &community_list, link) {
1861122394Sharti		if (asn_compare_oid(&p->index, &c->index) > 0) {
1862122394Sharti			TAILQ_INSERT_BEFORE(p, c, link);
1863122394Sharti			break;
1864122394Sharti		}
1865122394Sharti	}
1866122394Sharti	if (p == NULL)
1867122394Sharti		TAILQ_INSERT_TAIL(&community_list, c, link);
1868122394Sharti	return (c->value);
1869122394Sharti}
1870122394Sharti
1871122394Sharticonst char *
1872122394Sharticomm_string(u_int ncomm)
1873122394Sharti{
1874122394Sharti	struct community *p;
1875122394Sharti
1876122394Sharti	TAILQ_FOREACH(p, &community_list, link)
1877122394Sharti		if (p->value == ncomm)
1878122394Sharti			return (p->string);
1879122394Sharti	return (NULL);
1880122394Sharti}
1881122394Sharti
1882122394Sharti/*
1883122394Sharti * Delete all communities allocated by a module
1884122394Sharti */
1885122394Shartistatic void
1886122394Sharticomm_flush(struct lmodule *mod)
1887122394Sharti{
1888122394Sharti	struct community *p, *p1;
1889122394Sharti
1890122394Sharti	p = TAILQ_FIRST(&community_list);
1891122394Sharti	while (p != NULL) {
1892122394Sharti		p1 = TAILQ_NEXT(p, link);
1893122394Sharti		if (p->owner == mod) {
1894122394Sharti			free(p->string);
1895122394Sharti			TAILQ_REMOVE(&community_list, p, link);
1896122394Sharti			free(p);
1897122394Sharti		}
1898122394Sharti		p = p1;
1899122394Sharti	}
1900122394Sharti}
1901122394Sharti
1902122394Sharti/*
1903122394Sharti * Request ID handling.
1904122394Sharti *
1905122394Sharti * Allocate a new range of request ids. Use a first fit algorithm.
1906122394Sharti */
1907122394Shartiu_int
1908122394Shartireqid_allocate(int size, struct lmodule *mod)
1909122394Sharti{
1910122394Sharti	u_int type;
1911122394Sharti	struct idrange *r, *r1;
1912122394Sharti
1913122394Sharti	if (size <= 0 || size > INT32_MAX) {
1914122394Sharti		syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size);
1915122394Sharti		return (0);
1916122394Sharti	}
1917122394Sharti	/* allocate a type id */
1918122394Sharti	do {
1919122394Sharti		if ((type = next_idrange++) == UINT_MAX)
1920122394Sharti			next_idrange = 1;
1921122394Sharti		TAILQ_FOREACH(r, &idrange_list, link)
1922122394Sharti			if (r->type == type)
1923122394Sharti				break;
1924122394Sharti	} while(r != NULL);
1925122394Sharti
1926122394Sharti	/* find a range */
1927122394Sharti	if (TAILQ_EMPTY(&idrange_list))
1928122394Sharti		r = NULL;
1929122394Sharti	else {
1930122394Sharti		r = TAILQ_FIRST(&idrange_list);
1931122394Sharti		if (r->base < size) {
1932122394Sharti			while((r1 = TAILQ_NEXT(r, link)) != NULL) {
1933122394Sharti				if (r1->base - (r->base + r->size) >= size)
1934122394Sharti					break;
1935122394Sharti				r = r1;
1936122394Sharti			}
1937122394Sharti			r = r1;
1938122394Sharti		}
1939122394Sharti		if (r == NULL) {
1940122394Sharti			r1 = TAILQ_LAST(&idrange_list, idrange_list);
1941122394Sharti			if (INT32_MAX - size + 1 < r1->base + r1->size) {
1942122394Sharti				syslog(LOG_ERR, "out of id ranges (%u)", size);
1943122394Sharti				return (0);
1944122394Sharti			}
1945122394Sharti		}
1946122394Sharti	}
1947122394Sharti
1948122394Sharti	/* allocate structure */
1949122394Sharti	if ((r1 = malloc(sizeof(struct idrange))) == NULL) {
1950122394Sharti		syslog(LOG_ERR, "%s: %m", __FUNCTION__);
1951122394Sharti		return (0);
1952122394Sharti	}
1953122394Sharti
1954122394Sharti	r1->type = type;
1955122394Sharti	r1->size = size;
1956122394Sharti	r1->owner = mod;
1957122394Sharti	if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) {
1958122394Sharti		r1->base = 0;
1959122394Sharti		TAILQ_INSERT_HEAD(&idrange_list, r1, link);
1960122394Sharti	} else if (r == NULL) {
1961122394Sharti		r = TAILQ_LAST(&idrange_list, idrange_list);
1962122394Sharti		r1->base = r->base + r->size;
1963122394Sharti		TAILQ_INSERT_TAIL(&idrange_list, r1, link);
1964122394Sharti	} else {
1965122394Sharti		r = TAILQ_PREV(r, idrange_list, link);
1966122394Sharti		r1->base = r->base + r->size;
1967122394Sharti		TAILQ_INSERT_AFTER(&idrange_list, r, r1, link);
1968122394Sharti	}
1969122394Sharti	r1->next = r1->base;
1970122394Sharti
1971122394Sharti	return (type);
1972122394Sharti}
1973122394Sharti
1974122394Shartiint32_t
1975122394Shartireqid_next(u_int type)
1976122394Sharti{
1977122394Sharti	struct idrange *r;
1978122394Sharti	int32_t id;
1979122394Sharti
1980122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
1981122394Sharti		if (r->type == type)
1982122394Sharti			break;
1983122394Sharti	if (r == NULL) {
1984122394Sharti		syslog(LOG_CRIT, "wrong idrange type");
1985122394Sharti		abort();
1986122394Sharti	}
1987122394Sharti	if ((id = r->next++) == r->base + (r->size - 1))
1988122394Sharti		r->next = r->base;
1989122394Sharti	return (id);
1990122394Sharti}
1991122394Sharti
1992122394Shartiint32_t
1993122394Shartireqid_base(u_int type)
1994122394Sharti{
1995122394Sharti	struct idrange *r;
1996122394Sharti
1997122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
1998122394Sharti		if (r->type == type)
1999122394Sharti			return (r->base);
2000122394Sharti	syslog(LOG_CRIT, "wrong idrange type");
2001122394Sharti	abort();
2002122394Sharti}
2003122394Sharti
2004122394Shartiu_int
2005122394Shartireqid_type(int32_t reqid)
2006122394Sharti{
2007122394Sharti	struct idrange *r;
2008122394Sharti
2009122394Sharti	TAILQ_FOREACH(r, &idrange_list, link)
2010122394Sharti		if (reqid >= r->base && reqid <= r->base + (r->size - 1))
2011122394Sharti			return (r->type);
2012122394Sharti	return (0);
2013122394Sharti}
2014122394Sharti
2015122394Shartiint
2016122394Shartireqid_istype(int32_t reqid, u_int type)
2017122394Sharti{
2018122394Sharti	return (reqid_type(reqid) == type);
2019122394Sharti}
2020122394Sharti
2021122394Sharti/*
2022122394Sharti * Delete all communities allocated by a module
2023122394Sharti */
2024122394Shartistatic void
2025122394Shartireqid_flush(struct lmodule *mod)
2026122394Sharti{
2027122394Sharti	struct idrange *p, *p1;
2028122394Sharti
2029122394Sharti	p = TAILQ_FIRST(&idrange_list);
2030122394Sharti	while (p != NULL) {
2031122394Sharti		p1 = TAILQ_NEXT(p, link);
2032122394Sharti		if (p->owner == mod) {
2033122394Sharti			TAILQ_REMOVE(&idrange_list, p, link);
2034122394Sharti			free(p);
2035122394Sharti		}
2036122394Sharti		p = p1;
2037122394Sharti	}
2038122394Sharti}
2039122394Sharti
2040122394Sharti/*
2041122394Sharti * Merge the given tree for the given module into the main tree.
2042122394Sharti */
2043122394Shartistatic int
2044122394Sharticompare_node(const void *v1, const void *v2)
2045122394Sharti{
2046122394Sharti	const struct snmp_node *n1 = v1;
2047122394Sharti	const struct snmp_node *n2 = v2;
2048122394Sharti
2049122394Sharti	return (asn_compare_oid(&n1->oid, &n2->oid));
2050122394Sharti}
2051122394Shartistatic int
2052122394Shartitree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod)
2053122394Sharti{
2054122394Sharti	struct snmp_node *xtree;
2055122394Sharti	u_int i;
2056122394Sharti
2057122394Sharti	xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize));
2058122394Sharti	if (xtree == NULL) {
2059128237Sharti		syslog(LOG_ERR, "tree_merge: %m");
2060122394Sharti		return (-1);
2061122394Sharti	}
2062122394Sharti	tree = xtree;
2063122394Sharti	memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize);
2064122394Sharti
2065122394Sharti	for (i = 0; i < nsize; i++)
2066128237Sharti		tree[tree_size + i].tree_data = mod;
2067122394Sharti
2068122394Sharti	tree_size += nsize;
2069122394Sharti
2070122394Sharti	qsort(tree, tree_size, sizeof(tree[0]), compare_node);
2071122394Sharti
2072122394Sharti	return (0);
2073122394Sharti}
2074122394Sharti
2075122394Sharti/*
2076122394Sharti * Remove all nodes belonging to the loadable module
2077122394Sharti */
2078122394Shartistatic void
2079122394Shartitree_unmerge(struct lmodule *mod)
2080122394Sharti{
2081122394Sharti	u_int s, d;
2082122394Sharti
2083122394Sharti	for(s = d = 0; s < tree_size; s++)
2084128237Sharti		if (tree[s].tree_data != mod) {
2085122394Sharti			if (s != d)
2086122394Sharti				tree[d] = tree[s];
2087122394Sharti			d++;
2088122394Sharti		}
2089122394Sharti	tree_size = d;
2090122394Sharti}
2091122394Sharti
2092122394Sharti/*
2093122394Sharti * Loadable modules
2094122394Sharti */
2095122394Shartistruct lmodule *
2096122394Shartilm_load(const char *path, const char *section)
2097122394Sharti{
2098122394Sharti	struct lmodule *m;
2099122394Sharti	int err;
2100122394Sharti	int i;
2101122394Sharti	char *av[MAX_MOD_ARGS + 1];
2102122394Sharti	int ac;
2103122394Sharti	u_int u;
2104122394Sharti
2105122394Sharti	if ((m = malloc(sizeof(*m))) == NULL) {
2106122394Sharti		syslog(LOG_ERR, "lm_load: %m");
2107122394Sharti		return (NULL);
2108122394Sharti	}
2109122394Sharti	m->handle = NULL;
2110122394Sharti	m->flags = 0;
2111122394Sharti	strcpy(m->section, section);
2112122394Sharti
2113122394Sharti	if ((m->path = malloc(strlen(path) + 1)) == NULL) {
2114122394Sharti		syslog(LOG_ERR, "lm_load: %m");
2115122394Sharti		goto err;
2116122394Sharti	}
2117122394Sharti	strcpy(m->path, path);
2118122394Sharti
2119122394Sharti	/*
2120122394Sharti	 * Make index
2121122394Sharti	 */
2122122394Sharti	m->index.subs[0] = strlen(section);
2123122394Sharti	m->index.len = m->index.subs[0] + 1;
2124122394Sharti	for (u = 0; u < m->index.subs[0]; u++)
2125122394Sharti		m->index.subs[u + 1] = section[u];
2126122394Sharti
2127122394Sharti	/*
2128122394Sharti	 * Load the object file and locate the config structure
2129122394Sharti	 */
2130122394Sharti	if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
2131122394Sharti		syslog(LOG_ERR, "lm_load: open %s", dlerror());
2132122394Sharti		goto err;
2133122394Sharti	}
2134122394Sharti
2135122394Sharti	if ((m->config = dlsym(m->handle, "config")) == NULL) {
2136122394Sharti		syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror());
2137122394Sharti		goto err;
2138122394Sharti	}
2139122394Sharti
2140122394Sharti	/*
2141122394Sharti	 * Insert it into the right place
2142122394Sharti	 */
2143122394Sharti	INSERT_OBJECT_OID(m, &lmodules);
2144122394Sharti
2145122394Sharti	/* preserve order */
2146122394Sharti	if (community == COMM_INITIALIZE) {
2147122394Sharti		m->flags |= LM_ONSTARTLIST;
2148122394Sharti		TAILQ_INSERT_TAIL(&modules_start, m, start);
2149122394Sharti	}
2150122394Sharti
2151122394Sharti	/*
2152122394Sharti	 * make the argument vector.
2153122394Sharti	 */
2154122394Sharti	ac = 0;
2155122394Sharti	for (i = 0; i < nprogargs; i++) {
2156122394Sharti		if (strlen(progargs[i]) >= strlen(section) + 1 &&
2157122394Sharti		    strncmp(progargs[i], section, strlen(section)) == 0 &&
2158122394Sharti		    progargs[i][strlen(section)] == ':') {
2159122394Sharti			if (ac == MAX_MOD_ARGS) {
2160122394Sharti				syslog(LOG_WARNING, "too many arguments for "
2161122394Sharti				    "module '%s", section);
2162122394Sharti				break;
2163122394Sharti			}
2164122394Sharti			av[ac++] = &progargs[i][strlen(section)+1];
2165122394Sharti		}
2166122394Sharti	}
2167122394Sharti	av[ac] = NULL;
2168122394Sharti
2169122394Sharti	/*
2170122394Sharti	 * Run the initialisation function
2171122394Sharti	 */
2172122394Sharti	if ((err = (*m->config->init)(m, ac, av)) != 0) {
2173122394Sharti		syslog(LOG_ERR, "lm_load: init failed: %d", err);
2174122394Sharti		TAILQ_REMOVE(&lmodules, m, link);
2175122394Sharti		goto err;
2176122394Sharti	}
2177122394Sharti
2178122394Sharti	return (m);
2179122394Sharti
2180122394Sharti  err:
2181122394Sharti	if (m->handle)
2182122394Sharti		dlclose(m->handle);
2183122394Sharti	free(m->path);
2184122394Sharti	free(m);
2185122394Sharti	return (NULL);
2186122394Sharti}
2187122394Sharti
2188122394Sharti/*
2189122394Sharti * Start a module
2190122394Sharti */
2191122394Shartivoid
2192122394Shartilm_start(struct lmodule *mod)
2193122394Sharti{
2194122394Sharti	const struct lmodule *m;
2195122394Sharti
2196122394Sharti	/*
2197122394Sharti	 * Merge tree. If this fails, unload the module.
2198122394Sharti	 */
2199122394Sharti	if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) {
2200122394Sharti		lm_unload(mod);
2201122394Sharti		return;
2202122394Sharti	}
2203122394Sharti
2204122394Sharti	/*
2205122394Sharti	 * Read configuration
2206122394Sharti	 */
2207122394Sharti	if (read_config(config_file, mod)) {
2208122394Sharti		syslog(LOG_ERR, "error in config file");
2209122394Sharti		lm_unload(mod);
2210122394Sharti		return;
2211122394Sharti	}
2212122394Sharti	if (mod->config->start)
2213122394Sharti		(*mod->config->start)();
2214122394Sharti
2215122394Sharti	mod->flags |= LM_STARTED;
2216122394Sharti
2217122394Sharti	/*
2218122394Sharti	 * Inform other modules
2219122394Sharti	 */
2220122394Sharti	TAILQ_FOREACH(m, &lmodules, link)
2221122394Sharti		if (m->config->loading)
2222122394Sharti			(*m->config->loading)(mod, 1);
2223122394Sharti}
2224122394Sharti
2225122394Sharti
2226122394Sharti/*
2227122394Sharti * Unload a module.
2228122394Sharti */
2229122394Shartivoid
2230122394Shartilm_unload(struct lmodule *m)
2231122394Sharti{
2232122394Sharti	int err;
2233122394Sharti	const struct lmodule *mod;
2234122394Sharti
2235122394Sharti	TAILQ_REMOVE(&lmodules, m, link);
2236122394Sharti	if (m->flags & LM_ONSTARTLIST)
2237122394Sharti		TAILQ_REMOVE(&modules_start, m, start);
2238122394Sharti	tree_unmerge(m);
2239122394Sharti
2240122394Sharti	if ((m->flags & LM_STARTED) && m->config->fini &&
2241122394Sharti	    (err = (*m->config->fini)()) != 0)
2242122394Sharti		syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err);
2243122394Sharti
2244122394Sharti	comm_flush(m);
2245122394Sharti	reqid_flush(m);
2246122394Sharti	timer_flush(m);
2247122394Sharti	fd_flush(m);
2248122394Sharti
2249122394Sharti	dlclose(m->handle);
2250122394Sharti	free(m->path);
2251122394Sharti
2252122394Sharti	/*
2253122394Sharti	 * Inform other modules
2254122394Sharti	 */
2255122394Sharti	TAILQ_FOREACH(mod, &lmodules, link)
2256122394Sharti		if (mod->config->loading)
2257122394Sharti			(*mod->config->loading)(m, 0);
2258122394Sharti
2259122394Sharti	free(m);
2260122394Sharti}
2261122394Sharti
2262122394Sharti/*
2263122394Sharti * Register an object resource and return the index (or 0 on failures)
2264122394Sharti */
2265122394Shartiu_int
2266122394Shartior_register(const struct asn_oid *or, const char *descr, struct lmodule *mod)
2267122394Sharti{
2268122394Sharti	struct objres *objres, *or1;
2269122394Sharti	u_int idx;
2270122394Sharti
2271122394Sharti	/* find a free index */
2272122394Sharti	idx = 1;
2273122394Sharti	for (objres = TAILQ_FIRST(&objres_list);
2274122394Sharti	     objres != NULL;
2275122394Sharti	     objres = TAILQ_NEXT(objres, link)) {
2276122394Sharti		if ((or1 = TAILQ_NEXT(objres, link)) == NULL ||
2277122394Sharti		    or1->index > objres->index + 1) {
2278122394Sharti			idx = objres->index + 1;
2279122394Sharti			break;
2280122394Sharti		}
2281122394Sharti	}
2282122394Sharti
2283122394Sharti	if ((objres = malloc(sizeof(*objres))) == NULL)
2284122394Sharti		return (0);
2285122394Sharti
2286122394Sharti	objres->index = idx;
2287122394Sharti	objres->oid = *or;
2288122394Sharti	strlcpy(objres->descr, descr, sizeof(objres->descr));
2289122394Sharti	objres->uptime = get_ticks() - start_tick;
2290122394Sharti	objres->module = mod;
2291122394Sharti
2292122394Sharti	INSERT_OBJECT_INT(objres, &objres_list);
2293122394Sharti
2294122394Sharti	systemg.or_last_change = objres->uptime;
2295122394Sharti
2296122394Sharti	return (idx);
2297122394Sharti}
2298122394Sharti
2299122394Shartivoid
2300122394Shartior_unregister(u_int idx)
2301122394Sharti{
2302122394Sharti	struct objres *objres;
2303122394Sharti
2304122394Sharti	TAILQ_FOREACH(objres, &objres_list, link)
2305122394Sharti		if (objres->index == idx) {
2306122394Sharti			TAILQ_REMOVE(&objres_list, objres, link);
2307122394Sharti			free(objres);
2308122394Sharti			return;
2309122394Sharti		}
2310122394Sharti}
2311