main.c revision 128237
1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 *	All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution of this software and documentation and use in source and
9 * binary forms, with or without modification, are permitted provided that
10 * the following conditions are met:
11 *
12 * 1. Redistributions of source code or documentation must retain the above
13 *    copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Begemot: bsnmp/snmpd/main.c,v 1.85 2004/04/14 15:39:14 novo Exp $
34 *
35 * SNMPd main stuff.
36 */
37#include <sys/param.h>
38#include <sys/un.h>
39#include <sys/ucred.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <stddef.h>
43#include <string.h>
44#include <stdarg.h>
45#include <ctype.h>
46#include <errno.h>
47#include <syslog.h>
48#include <unistd.h>
49#include <signal.h>
50#include <dlfcn.h>
51#include <inttypes.h>
52
53#include "snmpmod.h"
54#include "snmpd.h"
55#include "tree.h"
56#include "oid.h"
57
58#define	PATH_PID	"/var/run/%s.pid"
59#define PATH_CONFIG	"/etc/%s.config"
60
61u_int32_t this_tick;	/* start of processing of current packet */
62u_int32_t start_tick;	/* start of processing */
63
64struct systemg systemg = {
65	NULL,
66	{ 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }},
67	NULL, NULL, NULL,
68	64 + 8 + 4,
69	0
70};
71struct debug debug = {
72	0,		/* dump_pdus */
73	LOG_DEBUG,	/* log_pri */
74	0,		/* evdebug */
75};
76
77struct snmpd snmpd = {
78	2048,		/* txbuf */
79	2048,		/* rxbuf */
80	0,		/* comm_dis */
81	0,		/* auth_traps */
82	{0, 0, 0, 0},	/* trap1addr */
83	VERS_ENABLE_ALL,/* version_enable */
84};
85struct snmpd_stats snmpd_stats;
86
87/* snmpSerialNo */
88int32_t snmp_serial_no;
89
90/* search path for config files */
91const char *syspath = PATH_SYSCONFIG;
92
93/* list of all loaded modules */
94struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules);
95
96/* list of loaded modules during start-up in the order they were loaded */
97static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start);
98
99/* list of all known communities */
100struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list);
101
102/* list of all installed object resources */
103struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list);
104
105/* community value generator */
106static u_int next_community_index = 1;
107
108/* list of all known ranges */
109struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list);
110
111/* identifier generator */
112u_int next_idrange = 1;
113
114/* list of all current timers */
115struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list);
116
117/* list of file descriptors */
118struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list);
119
120/* program arguments */
121static char **progargs;
122static int nprogargs;
123
124/* current community */
125u_int	community;
126static struct community *comm;
127
128/* file names */
129static char config_file[MAXPATHLEN + 1];
130static char pid_file[MAXPATHLEN + 1];
131
132#ifndef USE_LIBBEGEMOT
133/* event context */
134static evContext evctx;
135#endif
136
137/* signal mask */
138static sigset_t blocked_sigs;
139
140/* signal handling */
141static int work;
142#define	WORK_DOINFO	0x0001
143#define	WORK_RECONFIG	0x0002
144
145/* oids */
146static const struct asn_oid
147	oid_snmpMIB = OIDX_snmpMIB,
148	oid_begemotSnmpd = OIDX_begemotSnmpd,
149	oid_coldStart = OIDX_coldStart,
150	oid_authenticationFailure = OIDX_authenticationFailure;
151
152const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }};
153
154/* request id generator for traps */
155u_int trap_reqid;
156
157/* help text */
158static const char usgtxt[] = "\
159Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
160Open Communication Systems (FhG Fokus). All rights reserved.\n\
161usage: snmpd [-dh] [-c file] [-D options] [-I path] [-l prefix]\n\
162             [-m variable=value] [-p file]\n\
163options:\n\
164  -d		don't daemonize\n\
165  -h		print this info\n\
166  -c file	specify configuration file\n\
167  -D options	debugging options\n\
168  -I path	system include path\n\
169  -l prefix	default basename for pid and config file\n\
170  -m var=val	define variable\n\
171  -p file	specify pid file\n\
172";
173
174/* transports */
175extern const struct transport_def udp_trans;
176extern const struct transport_def lsock_trans;
177
178struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
179
180/* forward declarations */
181static void snmp_printf_func(const char *fmt, ...);
182static void snmp_error_func(const char *err, ...);
183static void snmp_debug_func(const char *err, ...);
184static void asn_error_func(const struct asn_buf *b, const char *err, ...);
185
186/*
187 * Allocate rx/tx buffer. We allocate one byte more for rx.
188 */
189void *
190buf_alloc(int tx)
191{
192	void *buf;
193
194	if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) {
195		syslog(LOG_CRIT, "cannot allocate buffer");
196		if (tx)
197			snmpd_stats.noTxbuf++;
198		else
199			snmpd_stats.noRxbuf++;
200		return (NULL);
201	}
202	return (buf);
203}
204
205/*
206 * Return the buffer size.
207 */
208size_t
209buf_size(int tx)
210{
211	return (tx ? snmpd.txbuf : snmpd.rxbuf);
212}
213
214/*
215 * Prepare a PDU for output
216 */
217void
218snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen,
219    const char *dest)
220{
221	struct asn_buf resp_b;
222
223	resp_b.asn_ptr = sndbuf;
224	resp_b.asn_len = snmpd.txbuf;
225
226	if (snmp_pdu_encode(pdu, &resp_b) != 0) {
227		syslog(LOG_ERR, "cannot encode message");
228		abort();
229	}
230	if (debug.dump_pdus) {
231		snmp_printf("%s <- ", dest);
232		snmp_pdu_dump(pdu);
233	}
234	*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
235}
236
237/*
238 * SNMP input. Start: decode the PDU, find the community.
239 */
240enum snmpd_input_err
241snmp_input_start(const u_char *buf, size_t len, const char *source,
242    struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen)
243{
244	struct asn_buf b;
245	enum snmp_code code;
246	enum snmpd_input_err ret;
247	int sret;
248
249	b.asn_cptr = buf;
250	b.asn_len = len;
251
252	/* look whether we have enough bytes for the entire PDU. */
253	switch (sret = snmp_pdu_snoop(&b)) {
254
255	  case 0:
256		return (SNMPD_INPUT_TRUNC);
257
258	  case -1:
259		snmpd_stats.inASNParseErrs++;
260		return (SNMPD_INPUT_FAILED);
261	}
262	b.asn_len = *pdulen = (size_t)sret;
263
264	code = snmp_pdu_decode(&b, pdu, ip);
265
266	snmpd_stats.inPkts++;
267
268	ret = SNMPD_INPUT_OK;
269	switch (code) {
270
271	  case SNMP_CODE_FAILED:
272		snmpd_stats.inASNParseErrs++;
273		return (SNMPD_INPUT_FAILED);
274
275	  case SNMP_CODE_BADVERS:
276	  bad_vers:
277		snmpd_stats.inBadVersions++;
278		return (SNMPD_INPUT_FAILED);
279
280	  case SNMP_CODE_BADLEN:
281		if (pdu->type == SNMP_OP_SET)
282			ret = SNMPD_INPUT_VALBADLEN;
283		break;
284
285	  case SNMP_CODE_OORANGE:
286		if (pdu->type == SNMP_OP_SET)
287			ret = SNMPD_INPUT_VALRANGE;
288		break;
289
290	  case SNMP_CODE_BADENC:
291		if (pdu->type == SNMP_OP_SET)
292			ret = SNMPD_INPUT_VALBADENC;
293		break;
294
295	  case SNMP_CODE_OK:
296		switch (pdu->version) {
297
298		  case SNMP_V1:
299			if (!(snmpd.version_enable & VERS_ENABLE_V1))
300				goto bad_vers;
301			break;
302
303		  case SNMP_V2c:
304			if (!(snmpd.version_enable & VERS_ENABLE_V2C))
305				goto bad_vers;
306			break;
307
308		  case SNMP_Verr:
309			goto bad_vers;
310		}
311		break;
312	}
313
314	if (debug.dump_pdus) {
315		snmp_printf("%s -> ", source);
316		snmp_pdu_dump(pdu);
317	}
318
319	/*
320	 * Look, whether we know the community
321	 */
322	TAILQ_FOREACH(comm, &community_list, link)
323		if (comm->string != NULL &&
324		    strcmp(comm->string, pdu->community) == 0)
325			break;
326
327	if (comm == NULL) {
328		snmpd_stats.inBadCommunityNames++;
329		snmp_pdu_free(pdu);
330		if (snmpd.auth_traps)
331			snmp_send_trap(&oid_authenticationFailure, NULL);
332		return (SNMPD_INPUT_FAILED);
333	}
334	community = comm->value;
335
336	/* update uptime */
337	this_tick = get_ticks();
338
339	return (ret);
340}
341
342/*
343 * Will return only _OK or _FAILED
344 */
345enum snmpd_input_err
346snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen,
347    u_char *sndbuf, size_t *sndlen, const char *source,
348    enum snmpd_input_err ierr, int32_t ivar, void *data)
349{
350	struct snmp_pdu resp;
351	struct asn_buf resp_b, pdu_b;
352	enum snmp_ret ret;
353
354	resp_b.asn_ptr = sndbuf;
355	resp_b.asn_len = snmpd.txbuf;
356
357	pdu_b.asn_cptr = rcvbuf;
358	pdu_b.asn_len = rcvlen;
359
360	if (ierr != SNMPD_INPUT_OK) {
361		/* error decoding the input of a SET */
362		if (pdu->version == SNMP_V1)
363			pdu->error_status = SNMP_ERR_BADVALUE;
364		else if (ierr == SNMPD_INPUT_VALBADLEN)
365			pdu->error_status = SNMP_ERR_WRONG_LENGTH;
366		else if (ierr == SNMPD_INPUT_VALRANGE)
367			pdu->error_status = SNMP_ERR_WRONG_VALUE;
368		else
369			pdu->error_status = SNMP_ERR_WRONG_ENCODING;
370
371		pdu->error_index = ivar;
372
373		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
374			syslog(LOG_WARNING, "could not encode error response");
375			snmpd_stats.silentDrops++;
376			return (SNMPD_INPUT_FAILED);
377		}
378
379		if (debug.dump_pdus) {
380			snmp_printf("%s <- ", source);
381			snmp_pdu_dump(pdu);
382		}
383		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
384		return (SNMPD_INPUT_OK);
385	}
386
387	switch (pdu->type) {
388
389	  case SNMP_PDU_GET:
390		ret = snmp_get(pdu, &resp_b, &resp, data);
391		break;
392
393	  case SNMP_PDU_GETNEXT:
394		ret = snmp_getnext(pdu, &resp_b, &resp, data);
395		break;
396
397	  case SNMP_PDU_SET:
398		ret = snmp_set(pdu, &resp_b, &resp, data);
399		break;
400
401	  case SNMP_PDU_GETBULK:
402		ret = snmp_getbulk(pdu, &resp_b, &resp, data);
403		break;
404
405	  default:
406		ret = SNMP_RET_IGN;
407		break;
408	}
409
410	switch (ret) {
411
412	  case SNMP_RET_OK:
413		/* normal return - send a response */
414		if (debug.dump_pdus) {
415			snmp_printf("%s <- ", source);
416			snmp_pdu_dump(&resp);
417		}
418		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
419		snmp_pdu_free(&resp);
420		return (SNMPD_INPUT_OK);
421
422	  case SNMP_RET_IGN:
423		/* error - send nothing */
424		snmpd_stats.silentDrops++;
425		return (SNMPD_INPUT_FAILED);
426
427	  case SNMP_RET_ERR:
428		/* error - send error response. The snmp routine has
429		 * changed the error fields in the original message. */
430		resp_b.asn_ptr = sndbuf;
431		resp_b.asn_len = snmpd.txbuf;
432		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
433			syslog(LOG_WARNING, "could not encode error response");
434			snmpd_stats.silentDrops++;
435			return (SNMPD_INPUT_FAILED);
436		} else {
437			if (debug.dump_pdus) {
438				snmp_printf("%s <- ", source);
439				snmp_pdu_dump(pdu);
440			}
441			*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
442			return (SNMPD_INPUT_OK);
443		}
444	}
445	abort();
446}
447
448/*
449 * Insert a port into the right place in the transport's table of ports
450 */
451void
452trans_insert_port(struct transport *t, struct tport *port)
453{
454	struct tport *p;
455
456	TAILQ_FOREACH(p, &t->table, link) {
457		if (asn_compare_oid(&p->index, &port->index) > 0) {
458			TAILQ_INSERT_BEFORE(p, port, link);
459			return;
460		}
461	}
462	port->transport = t;
463	TAILQ_INSERT_TAIL(&t->table, port, link);
464}
465
466/*
467 * Remove a port from a transport's list
468 */
469void
470trans_remove_port(struct tport *port)
471{
472
473	TAILQ_REMOVE(&port->transport->table, port, link);
474}
475
476/*
477 * Find a port on a transport's list
478 */
479struct tport *
480trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub)
481{
482
483	return (FIND_OBJECT_OID(&t->table, idx, sub));
484}
485
486/*
487 * Find next port on a transport's list
488 */
489struct tport *
490trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub)
491{
492
493	return (NEXT_OBJECT_OID(&t->table, idx, sub));
494}
495
496/*
497 * Return first port
498 */
499struct tport *
500trans_first_port(struct transport *t)
501{
502
503	return (TAILQ_FIRST(&t->table));
504}
505
506/*
507 * Iterate through all ports until a function returns a 0.
508 */
509struct tport *
510trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t),
511    intptr_t arg)
512{
513	struct tport *p;
514
515	TAILQ_FOREACH(p, &t->table, link)
516		if (func(p, arg) == 0)
517			return (p);
518	return (NULL);
519}
520
521/*
522 * Register a transport
523 */
524int
525trans_register(const struct transport_def *def, struct transport **pp)
526{
527	u_int i;
528	char or_descr[256];
529
530	if ((*pp = malloc(sizeof(**pp))) == NULL)
531		return (SNMP_ERR_GENERR);
532
533	/* construct index */
534	(*pp)->index.len = strlen(def->name) + 1;
535	(*pp)->index.subs[0] = strlen(def->name);
536	for (i = 0; i < (*pp)->index.subs[0]; i++)
537		(*pp)->index.subs[i + 1] = def->name[i];
538
539	(*pp)->vtab = def;
540
541	if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) {
542		free(*pp);
543		return (SNMP_ERR_INCONS_VALUE);
544	}
545
546	/* register module */
547	snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name);
548	if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) {
549		free(*pp);
550		return (SNMP_ERR_GENERR);
551	}
552
553	INSERT_OBJECT_OID((*pp), &transport_list);
554
555	TAILQ_INIT(&(*pp)->table);
556
557	return (SNMP_ERR_NOERROR);
558}
559
560/*
561 * Unregister transport
562 */
563int
564trans_unregister(struct transport *t)
565{
566	if (!TAILQ_EMPTY(&t->table))
567		return (SNMP_ERR_INCONS_VALUE);
568
569	or_unregister(t->or_index);
570	TAILQ_REMOVE(&transport_list, t, link);
571
572	return (SNMP_ERR_NOERROR);
573}
574
575/*
576 * File descriptor support
577 */
578#ifdef USE_LIBBEGEMOT
579static void
580input(int fd, int mask __unused, void *uap)
581#else
582static void
583input(evContext ctx __unused, void *uap, int fd, int mask __unused)
584#endif
585{
586	struct fdesc *f = uap;
587
588	(*f->func)(fd, f->udata);
589}
590
591void
592fd_suspend(void *p)
593{
594	struct fdesc *f = p;
595
596#ifdef USE_LIBBEGEMOT
597	if (f->id >= 0) {
598		poll_unregister(f->id);
599		f->id = -1;
600	}
601#else
602	if (evTestID(f->id)) {
603		(void)evDeselectFD(evctx, f->id);
604		evInitID(&f->id);
605	}
606#endif
607}
608
609int
610fd_resume(void *p)
611{
612	struct fdesc *f = p;
613	int err;
614
615#ifdef USE_LIBBEGEMOT
616	if (f->id >= 0)
617		return (0);
618	if ((f->fd = poll_register(f->fd, input, f, POLL_IN)) < 0) {
619		err = errno;
620		syslog(LOG_ERR, "select fd %d: %m", f->fd);
621		errno = err;
622		return (-1);
623	}
624#else
625	if (evTestID(f->id))
626		return (0);
627	if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) {
628		err = errno;
629		syslog(LOG_ERR, "select fd %d: %m", f->fd);
630		errno = err;
631		return (-1);
632	}
633#endif
634	return (0);
635}
636
637void *
638fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod)
639{
640	struct fdesc *f;
641	int err;
642
643	if ((f = malloc(sizeof(struct fdesc))) == NULL) {
644		err = errno;
645		syslog(LOG_ERR, "fd_select: %m");
646		errno = err;
647		return (NULL);
648	}
649	f->fd = fd;
650	f->func = func;
651	f->udata = udata;
652	f->owner = mod;
653#ifdef USE_LIBBEGEMOT
654	f->id = -1;
655#else
656	evInitID(&f->id);
657#endif
658
659	if (fd_resume(f)) {
660		err = errno;
661		free(f);
662		errno = err;
663		return (NULL);
664	}
665
666	LIST_INSERT_HEAD(&fdesc_list, f, link);
667
668	return (f);
669}
670
671void
672fd_deselect(void *p)
673{
674	struct fdesc *f = p;
675
676	LIST_REMOVE(f, link);
677	fd_suspend(f);
678	free(f);
679}
680
681static void
682fd_flush(struct lmodule *mod)
683{
684	struct fdesc *t, *t1;
685
686	t = LIST_FIRST(&fdesc_list);
687	while (t != NULL) {
688		t1 = LIST_NEXT(t, link);
689		if (t->owner == mod)
690			fd_deselect(t);
691		t = t1;
692	}
693}
694
695/*
696 * Consume a message from the input buffer
697 */
698static void
699snmp_input_consume(struct port_input *pi)
700{
701	if (!pi->stream) {
702		/* always consume everything */
703		pi->length = 0;
704		return;
705	}
706	if (pi->consumed >= pi->length) {
707		/* all bytes consumed */
708		pi->length = 0;
709		return;
710	}
711	memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed);
712	pi->length -= pi->consumed;
713}
714
715struct credmsg {
716	struct cmsghdr hdr;
717	struct cmsgcred cred;
718};
719
720static void
721check_priv(struct port_input *pi, struct msghdr *msg)
722{
723	struct credmsg *cmsg;
724	struct xucred ucred;
725	socklen_t ucredlen;
726
727	pi->priv = 0;
728
729	if (msg->msg_controllen == sizeof(*cmsg)) {
730		/* process explicitely sends credentials */
731
732		cmsg = (struct credmsg *)msg->msg_control;
733		pi->priv = (cmsg->cred.cmcred_euid == 0);
734		return;
735	}
736
737	/* ok, obtain the accept time credentials */
738	ucredlen = sizeof(ucred);
739
740	if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 &&
741	    ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION)
742		pi->priv = (ucred.cr_uid == 0);
743}
744
745/*
746 * Input from a stream socket.
747 */
748static int
749recv_stream(struct port_input *pi)
750{
751	struct msghdr msg;
752	struct iovec iov[1];
753	ssize_t len;
754	struct credmsg cmsg;
755
756	if (pi->buf == NULL) {
757		/* no buffer yet - allocate one */
758		if ((pi->buf = buf_alloc(0)) == NULL) {
759			/* ups - could not get buffer. Return an error
760			 * the caller must close the transport. */
761			return (-1);
762		}
763		pi->buflen = buf_size(0);
764		pi->consumed = 0;
765		pi->length = 0;
766	}
767
768	/* try to get a message */
769	msg.msg_name = pi->peer;
770	msg.msg_namelen = pi->peerlen;
771	msg.msg_iov = iov;
772	msg.msg_iovlen = 1;
773	if (pi->cred) {
774		msg.msg_control = &cmsg;
775		msg.msg_controllen = sizeof(cmsg);
776
777		cmsg.hdr.cmsg_len = sizeof(cmsg);
778		cmsg.hdr.cmsg_level = SOL_SOCKET;
779		cmsg.hdr.cmsg_type = SCM_CREDS;
780	} else {
781		msg.msg_control = NULL;
782		msg.msg_controllen = 0;
783	}
784	msg.msg_flags = 0;
785
786	iov[0].iov_base = pi->buf + pi->length;
787	iov[0].iov_len = pi->buflen - pi->length;
788
789	len = recvmsg(pi->fd, &msg, 0);
790
791	if (len == -1 || len == 0)
792		/* receive error */
793		return (-1);
794
795	pi->length += len;
796
797	if (pi->cred)
798		check_priv(pi, &msg);
799
800	return (0);
801}
802
803/*
804 * Input from a datagram socket.
805 * Each receive should return one datagram.
806 */
807static int
808recv_dgram(struct port_input *pi)
809{
810	u_char embuf[1000];
811	struct msghdr msg;
812	struct iovec iov[1];
813	ssize_t len;
814	struct credmsg cmsg;
815
816	if (pi->buf == NULL) {
817		/* no buffer yet - allocate one */
818		if ((pi->buf = buf_alloc(0)) == NULL) {
819			/* ups - could not get buffer. Read away input
820			 * and drop it */
821			(void)recvfrom(pi->fd, embuf, sizeof(embuf),
822			    0, NULL, NULL);
823			/* return error */
824			return (-1);
825		}
826		pi->buflen = buf_size(0);
827	}
828
829	/* try to get a message */
830	msg.msg_name = pi->peer;
831	msg.msg_namelen = pi->peerlen;
832	msg.msg_iov = iov;
833	msg.msg_iovlen = 1;
834	if (pi->cred) {
835		msg.msg_control = &cmsg;
836		msg.msg_controllen = sizeof(cmsg);
837
838		cmsg.hdr.cmsg_len = sizeof(cmsg);
839		cmsg.hdr.cmsg_level = SOL_SOCKET;
840		cmsg.hdr.cmsg_type = SCM_CREDS;
841	} else {
842		msg.msg_control = NULL;
843		msg.msg_controllen = 0;
844	}
845	msg.msg_flags = 0;
846
847	iov[0].iov_base = pi->buf;
848	iov[0].iov_len = pi->buflen;
849
850	len = recvmsg(pi->fd, &msg, 0);
851
852	if (len == -1 || len == 0)
853		/* receive error */
854		return (-1);
855
856	if (msg.msg_flags & MSG_TRUNC) {
857		/* truncated - drop */
858		snmpd_stats.silentDrops++;
859		snmpd_stats.inTooLong++;
860		return (-1);
861	}
862
863	pi->length = (size_t)len;
864
865	if (pi->cred)
866		check_priv(pi, &msg);
867
868	return (0);
869}
870
871/*
872 * Input from a socket
873 */
874int
875snmpd_input(struct port_input *pi, struct tport *tport)
876{
877	u_char *sndbuf;
878	size_t sndlen;
879	struct snmp_pdu pdu;
880	enum snmpd_input_err ierr, ferr;
881	enum snmpd_proxy_err perr;
882	int32_t vi;
883	int ret;
884	ssize_t slen;
885
886	/* get input depending on the transport */
887	if (pi->stream) {
888		ret = recv_stream(pi);
889	} else {
890		ret = recv_dgram(pi);
891	}
892
893	if (ret == -1)
894		return (-1);
895
896	/*
897	 * Handle input
898	 */
899	ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi,
900	    &pi->consumed);
901	if (ierr == SNMPD_INPUT_TRUNC) {
902		/* need more bytes. This is ok only for streaming transports.
903		 * but only if we have not reached bufsiz yet. */
904		if (pi->stream) {
905			if (pi->length == buf_size(0)) {
906				snmpd_stats.silentDrops++;
907				return (-1);
908			}
909			return (0);
910		}
911		snmpd_stats.silentDrops++;
912		return (-1);
913	}
914
915	/* can't check for bad SET pdus here, because a proxy may have to
916	 * check the access first. We don't want to return an error response
917	 * to a proxy PDU with a wrong community */
918	if (ierr == SNMPD_INPUT_FAILED) {
919		/* for streaming transports this is fatal */
920		if (pi->stream)
921			return (-1);
922		snmp_input_consume(pi);
923		return (0);
924	}
925
926	/*
927	 * If that is a module community and the module has a proxy function,
928	 * the hand it over to the module.
929	 */
930	if (comm->owner != NULL && comm->owner->config->proxy != NULL) {
931		perr = (*comm->owner->config->proxy)(&pdu, tport->transport,
932		    &tport->index, pi->peer, pi->peerlen, ierr, vi, pi->priv);
933
934		switch (perr) {
935
936		  case SNMPD_PROXY_OK:
937			snmp_input_consume(pi);
938			return (0);
939
940		  case SNMPD_PROXY_REJ:
941			break;
942
943		  case SNMPD_PROXY_DROP:
944			snmp_input_consume(pi);
945			snmp_pdu_free(&pdu);
946			snmpd_stats.proxyDrops++;
947			return (0);
948
949		  case SNMPD_PROXY_BADCOMM:
950			snmp_input_consume(pi);
951			snmp_pdu_free(&pdu);
952			snmpd_stats.inBadCommunityNames++;
953			if (snmpd.auth_traps)
954				snmp_send_trap(&oid_authenticationFailure,
955				    NULL);
956			return (0);
957
958		  case SNMPD_PROXY_BADCOMMUSE:
959			snmp_input_consume(pi);
960			snmp_pdu_free(&pdu);
961			snmpd_stats.inBadCommunityUses++;
962			if (snmpd.auth_traps)
963				snmp_send_trap(&oid_authenticationFailure,
964				    NULL);
965			return (0);
966		}
967	}
968
969	/*
970	 * Check type
971	 */
972	if (pdu.type == SNMP_PDU_RESPONSE ||
973	    pdu.type == SNMP_PDU_TRAP ||
974	    pdu.type == SNMP_PDU_TRAP2) {
975		snmpd_stats.silentDrops++;
976		snmpd_stats.inBadPduTypes++;
977		snmp_pdu_free(&pdu);
978		snmp_input_consume(pi);
979		return (0);
980	}
981
982	/*
983	 * Check community
984	 */
985	if ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) ||
986	    (community != COMM_WRITE &&
987            (pdu.type == SNMP_PDU_SET || community != COMM_READ))) {
988		snmpd_stats.inBadCommunityUses++;
989		snmp_pdu_free(&pdu);
990		snmp_input_consume(pi);
991		if (snmpd.auth_traps)
992			snmp_send_trap(&oid_authenticationFailure, NULL);
993		return (0);
994	}
995
996	/*
997	 * Execute it.
998	 */
999	if ((sndbuf = buf_alloc(1)) == NULL) {
1000		snmpd_stats.silentDrops++;
1001		snmp_pdu_free(&pdu);
1002		snmp_input_consume(pi);
1003		return (0);
1004	}
1005	ferr = snmp_input_finish(&pdu, pi->buf, pi->length,
1006	    sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
1007
1008	if (ferr == SNMPD_INPUT_OK) {
1009		slen = sendto(pi->fd, sndbuf, sndlen, 0, pi->peer, pi->peerlen);
1010		if (slen == -1)
1011			syslog(LOG_ERR, "sendto: %m");
1012		else if ((size_t)slen != sndlen)
1013			syslog(LOG_ERR, "sendto: short write %zu/%zu",
1014			    sndlen, (size_t)slen);
1015	}
1016	snmp_pdu_free(&pdu);
1017	free(sndbuf);
1018	snmp_input_consume(pi);
1019
1020	return (0);
1021}
1022
1023/*
1024 * Send a PDU to a given port
1025 */
1026void
1027snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
1028    const struct sockaddr *addr, socklen_t addrlen)
1029{
1030	struct transport *trans = targ;
1031	struct tport *tp;
1032	u_char *sndbuf;
1033	size_t sndlen;
1034	ssize_t len;
1035
1036	TAILQ_FOREACH(tp, &trans->table, link)
1037		if (asn_compare_oid(port, &tp->index) == 0)
1038			break;
1039	if (tp == 0)
1040		return;
1041
1042	if ((sndbuf = buf_alloc(1)) == NULL)
1043		return;
1044
1045	snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
1046
1047	len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
1048
1049	if (len == -1)
1050		syslog(LOG_ERR, "sendto: %m");
1051	else if ((size_t)len != sndlen)
1052		syslog(LOG_ERR, "sendto: short write %zu/%zu",
1053		    sndlen, (size_t)len);
1054
1055	free(sndbuf);
1056}
1057
1058
1059/*
1060 * Close an input source
1061 */
1062void
1063snmpd_input_close(struct port_input *pi)
1064{
1065	if (pi->id != NULL)
1066		fd_deselect(pi->id);
1067	if (pi->fd >= 0)
1068		(void)close(pi->fd);
1069	if (pi->buf != NULL)
1070		free(pi->buf);
1071}
1072
1073/*
1074 * Dump internal state.
1075 */
1076#ifdef USE_LIBBEGEMOT
1077static void
1078info_func(void)
1079#else
1080static void
1081info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused)
1082#endif
1083{
1084	struct lmodule *m;
1085	u_int i;
1086	char buf[10000];
1087
1088	syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());
1089	for (i = 0; i < tree_size; i++) {
1090		switch (tree[i].type) {
1091
1092		  case SNMP_NODE_LEAF:
1093			sprintf(buf, "LEAF: %s %s", tree[i].name,
1094			    asn_oid2str(&tree[i].oid));
1095			break;
1096
1097		  case SNMP_NODE_COLUMN:
1098			sprintf(buf, "COL: %s %s", tree[i].name,
1099			    asn_oid2str(&tree[i].oid));
1100			break;
1101		}
1102		syslog(LOG_DEBUG, "%s", buf);
1103	}
1104
1105	TAILQ_FOREACH(m, &lmodules, link)
1106		if (m->config->dump)
1107			(*m->config->dump)();
1108}
1109
1110/*
1111 * Re-read configuration
1112 */
1113#ifdef USE_LIBBEGEMOT
1114static void
1115config_func(void)
1116#else
1117static void
1118config_func(evContext ctx __unused, void *uap __unused,
1119    const void *tag __unused)
1120#endif
1121{
1122	struct lmodule *m;
1123
1124	if (read_config(config_file, NULL)) {
1125		syslog(LOG_ERR, "error reading config file '%s'", config_file);
1126		return;
1127	}
1128	TAILQ_FOREACH(m, &lmodules, link)
1129		if (m->config->config)
1130			(*m->config->config)();
1131}
1132
1133/*
1134 * On USR1 dump actual configuration.
1135 */
1136static void
1137onusr1(int s __unused)
1138{
1139
1140	work |= WORK_DOINFO;
1141}
1142static void
1143onhup(int s __unused)
1144{
1145
1146	work |= WORK_RECONFIG;
1147}
1148
1149static void
1150onterm(int s __unused)
1151{
1152
1153	/* allow clean-up */
1154	exit(0);
1155}
1156
1157static void
1158init_sigs(void)
1159{
1160	struct sigaction sa;
1161
1162	sa.sa_handler = onusr1;
1163	sa.sa_flags = SA_RESTART;
1164	sigemptyset(&sa.sa_mask);
1165	if (sigaction(SIGUSR1, &sa, NULL)) {
1166		syslog(LOG_ERR, "sigaction: %m");
1167		exit(1);
1168	}
1169
1170	sa.sa_handler = onhup;
1171	if (sigaction(SIGHUP, &sa, NULL)) {
1172		syslog(LOG_ERR, "sigaction: %m");
1173		exit(1);
1174	}
1175
1176	sa.sa_handler = onterm;
1177	sa.sa_flags = 0;
1178	sigemptyset(&sa.sa_mask);
1179	if (sigaction(SIGTERM, &sa, NULL)) {
1180		syslog(LOG_ERR, "sigaction: %m");
1181		exit(1);
1182	}
1183	if (sigaction(SIGINT, &sa, NULL)) {
1184		syslog(LOG_ERR, "sigaction: %m");
1185		exit(1);
1186	}
1187}
1188
1189static void
1190block_sigs(void)
1191{
1192	sigset_t set;
1193
1194	sigfillset(&set);
1195	if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) {
1196		syslog(LOG_ERR, "SIG_BLOCK: %m");
1197		exit(1);
1198	}
1199}
1200static void
1201unblock_sigs(void)
1202{
1203	if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) {
1204		syslog(LOG_ERR, "SIG_SETMASK: %m");
1205		exit(1);
1206	}
1207}
1208
1209/*
1210 * Shut down
1211 */
1212static void
1213term(void)
1214{
1215	(void)unlink(pid_file);
1216}
1217
1218static void
1219trans_stop(void)
1220{
1221	struct transport *t;
1222
1223	TAILQ_FOREACH(t, &transport_list, link)
1224		(void)t->vtab->stop(1);
1225}
1226
1227/*
1228 * Define a macro from the command line
1229 */
1230static void
1231do_macro(char *arg)
1232{
1233	char *eq;
1234	int err;
1235
1236	if ((eq = strchr(arg, '=')) == NULL)
1237		err = define_macro(arg, "");
1238	else {
1239		*eq++ = '\0';
1240		err = define_macro(arg, eq);
1241	}
1242	if (err == -1) {
1243		syslog(LOG_ERR, "cannot save macro: %m");
1244		exit(1);
1245	}
1246}
1247
1248/*
1249 * Re-implement getsubopt from scratch, because the second argument is broken
1250 * and will not compile with WARNS=5.
1251 */
1252static int
1253getsubopt1(char **arg, const char *const *options, char **valp, char **optp)
1254{
1255	static const char *const delim = ",\t ";
1256	u_int i;
1257	char *ptr;
1258
1259	*optp = NULL;
1260
1261	/* skip leading junk */
1262	for (ptr = *arg; *ptr != '\0'; ptr++)
1263		if (strchr(delim, *ptr) == NULL)
1264			break;
1265	if (*ptr == '\0') {
1266		*arg = ptr;
1267		return (-1);
1268	}
1269	*optp = ptr;
1270
1271	/* find the end of the option */
1272	while (*++ptr != '\0')
1273		if (strchr(delim, *ptr) != NULL || *ptr == '=')
1274			break;
1275
1276	if (*ptr != '\0') {
1277		if (*ptr == '=') {
1278			*ptr++ = '\0';
1279			*valp = ptr;
1280			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
1281				ptr++;
1282			if (*ptr != '\0')
1283				*ptr++ = '\0';
1284		} else
1285			*ptr++ = '\0';
1286	}
1287
1288	*arg = ptr;
1289
1290	for (i = 0; *options != NULL; options++, i++)
1291		if (strcmp(*optp, *options) == 0)
1292			return (i);
1293	return (-1);
1294}
1295
1296int
1297main(int argc, char *argv[])
1298{
1299	int opt;
1300	FILE *fp;
1301	int background = 1;
1302	struct tport *p;
1303	const char *prefix = "snmpd";
1304	struct lmodule *m;
1305	char *value, *option;
1306	struct transport *t;
1307
1308#define DBG_DUMP	0
1309#define DBG_EVENTS	1
1310#define DBG_TRACE	2
1311	static const char *const debug_opts[] = {
1312		"dump",
1313		"events",
1314		"trace",
1315		NULL
1316	};
1317
1318	snmp_printf = snmp_printf_func;
1319	snmp_error = snmp_error_func;
1320	snmp_debug = snmp_debug_func;
1321	asn_error = asn_error_func;
1322
1323	while ((opt = getopt(argc, argv, "c:dD:hI:l:m:p:")) != EOF)
1324		switch (opt) {
1325
1326		  case 'c':
1327			strlcpy(config_file, optarg, sizeof(config_file));
1328			break;
1329
1330		  case 'd':
1331			background = 0;
1332			break;
1333
1334		  case 'D':
1335			while (*optarg) {
1336				switch (getsubopt1(&optarg, debug_opts,
1337				    &value, &option)) {
1338
1339				  case DBG_DUMP:
1340					debug.dump_pdus = 1;
1341					break;
1342
1343				  case DBG_EVENTS:
1344					debug.evdebug++;
1345					break;
1346
1347				  case DBG_TRACE:
1348					if (value == NULL)
1349						syslog(LOG_ERR,
1350						    "no value for 'trace'");
1351					snmp_trace = strtoul(value, NULL, 0);
1352					break;
1353
1354				  case -1:
1355					if (suboptarg)
1356						syslog(LOG_ERR,
1357						    "unknown debug flag '%s'",
1358						    option);
1359					else
1360						syslog(LOG_ERR,
1361						    "missing debug flag");
1362					break;
1363				}
1364			}
1365			break;
1366
1367		  case 'h':
1368			fprintf(stderr, "%s", usgtxt);
1369			exit(0);
1370
1371		  case 'I':
1372			syspath = optarg;
1373			break;
1374
1375		  case 'l':
1376			prefix = optarg;
1377			break;
1378
1379		  case 'm':
1380			do_macro(optarg);
1381			break;
1382
1383		  case 'p':
1384			strlcpy(pid_file, optarg, sizeof(pid_file));
1385			break;
1386		}
1387
1388	openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
1389	setlogmask(LOG_UPTO(debug.logpri - 1));
1390
1391	if (background && daemon(0, 0) < 0) {
1392		syslog(LOG_ERR, "daemon: %m");
1393		exit(1);
1394	}
1395
1396	argc -= optind;
1397	argv += optind;
1398
1399	progargs = argv;
1400	nprogargs = argc;
1401
1402	srandomdev();
1403
1404	snmp_serial_no = random();
1405
1406	/*
1407	 * Initialize the tree.
1408	 */
1409	if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) {
1410		syslog(LOG_ERR, "%m");
1411		exit(1);
1412	}
1413	memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE);
1414	tree_size = CTREE_SIZE;
1415
1416	/*
1417	 * Get standard communities
1418	 */
1419	(void)comm_define(1, "SNMP read", NULL, "public");
1420	(void)comm_define(2, "SNMP write", NULL, "public");
1421	community = COMM_INITIALIZE;
1422
1423	trap_reqid = reqid_allocate(512, NULL);
1424
1425	if (config_file[0] == '\0')
1426		snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix);
1427
1428	init_actvals();
1429
1430	start_tick = get_ticks();
1431	this_tick = get_ticks();
1432
1433	/* start transports */
1434	if (atexit(trans_stop) == -1) {
1435		syslog(LOG_ERR, "atexit failed: %m");
1436		exit(1);
1437	}
1438	if (udp_trans.start() != SNMP_ERR_NOERROR)
1439		syslog(LOG_WARNING, "cannot start UDP transport");
1440	if (lsock_trans.start() != SNMP_ERR_NOERROR)
1441		syslog(LOG_WARNING, "cannot start LSOCK transport");
1442
1443	if (read_config(config_file, NULL)) {
1444		syslog(LOG_ERR, "error in config file");
1445		exit(1);
1446	}
1447
1448#ifdef USE_LIBBEGEMOT
1449	if (debug.evdebug > 0)
1450		rpoll_trace = 1;
1451#else
1452	if (evCreate(&evctx)) {
1453		syslog(LOG_ERR, "evCreate: %m");
1454		exit(1);
1455	}
1456	if (debug.evdebug > 0)
1457		evSetDebug(evctx, 10, stderr);
1458#endif
1459
1460	TAILQ_FOREACH(t, &transport_list, link)
1461		TAILQ_FOREACH(p, &t->table, link)
1462			t->vtab->init_port(p);
1463
1464	init_sigs();
1465
1466	if (pid_file[0] == '\0')
1467		snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix);
1468
1469	if ((fp = fopen(pid_file, "w")) != NULL) {
1470		fprintf(fp, "%u", getpid());
1471		fclose(fp);
1472		if (atexit(term) == -1) {
1473			syslog(LOG_ERR, "atexit failed: %m");
1474			(void)remove(pid_file);
1475			exit(0);
1476		}
1477	}
1478
1479	if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.",
1480	    NULL) == 0) {
1481		syslog(LOG_ERR, "cannot register SNMPv2 MIB");
1482		exit(1);
1483	}
1484	if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.",
1485	    NULL) == 0) {
1486		syslog(LOG_ERR, "cannot register begemotSnmpd MIB");
1487		exit(1);
1488	}
1489
1490	snmp_send_trap(&oid_coldStart, NULL);
1491
1492	while ((m = TAILQ_FIRST(&modules_start)) != NULL) {
1493		m->flags &= ~LM_ONSTARTLIST;
1494		TAILQ_REMOVE(&modules_start, m, start);
1495		lm_start(m);
1496	}
1497
1498	for (;;) {
1499#ifndef USE_LIBBEGEMOT
1500		evEvent event;
1501#endif
1502		struct lmodule *mod;
1503
1504		TAILQ_FOREACH(mod, &lmodules, link)
1505			if (mod->config->idle != NULL)
1506				(*mod->config->idle)();
1507
1508#ifndef USE_LIBBEGEMOT
1509		if (evGetNext(evctx, &event, EV_WAIT) == 0) {
1510			if (evDispatch(evctx, event))
1511				syslog(LOG_ERR, "evDispatch: %m");
1512		} else if (errno != EINTR) {
1513			syslog(LOG_ERR, "evGetNext: %m");
1514			exit(1);
1515		}
1516#else
1517		poll_dispatch(1);
1518#endif
1519
1520		if (work != 0) {
1521			block_sigs();
1522			if (work & WORK_DOINFO) {
1523#ifdef USE_LIBBEGEMOT
1524				info_func();
1525#else
1526				if (evWaitFor(evctx, &work, info_func,
1527				    NULL, NULL) == -1) {
1528					syslog(LOG_ERR, "evWaitFor: %m");
1529					exit(1);
1530				}
1531#endif
1532			}
1533			if (work & WORK_RECONFIG) {
1534#ifdef USE_LIBBEGEMOT
1535				config_func();
1536#else
1537				if (evWaitFor(evctx, &work, config_func,
1538				    NULL, NULL) == -1) {
1539					syslog(LOG_ERR, "evWaitFor: %m");
1540					exit(1);
1541				}
1542#endif
1543			}
1544			work = 0;
1545			unblock_sigs();
1546#ifndef USE_LIBBEGEMOT
1547			if (evDo(evctx, &work) == -1) {
1548				syslog(LOG_ERR, "evDo: %m");
1549				exit(1);
1550			}
1551#endif
1552		}
1553	}
1554
1555	return (0);
1556}
1557
1558
1559u_int32_t
1560get_ticks()
1561{
1562	struct timeval tv;
1563	u_int32_t ret;
1564
1565	if (gettimeofday(&tv, NULL))
1566		abort();
1567	ret = tv.tv_sec * 100 + tv.tv_usec / 10000;
1568	return (ret);
1569}
1570/*
1571 * Timer support
1572 */
1573#ifdef USE_LIBBEGEMOT
1574static void
1575tfunc(int tid __unused, void *uap)
1576#else
1577static void
1578tfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1579	struct timespec inter __unused)
1580#endif
1581{
1582	struct timer *tp = uap;
1583
1584	LIST_REMOVE(tp, link);
1585	tp->func(tp->udata);
1586	free(tp);
1587}
1588
1589/*
1590 * Start a timer
1591 */
1592void *
1593timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
1594{
1595	struct timer *tp;
1596#ifdef USE_LIBBEGEMOT
1597	struct timeval due;
1598#else
1599	struct timespec due;
1600#endif
1601
1602	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1603		syslog(LOG_CRIT, "out of memory for timer");
1604		exit(1);
1605	}
1606#ifdef USE_LIBBEGEMOT
1607	(void)gettimeofday(&due, NULL);
1608	due.tv_sec += ticks / 100;
1609	due.tv_usec += (ticks % 100) * 10000;
1610	if (due.tv_usec >= 1000000) {
1611		due.tv_sec++;
1612		due.tv_usec -= 1000000;
1613	}
1614#else
1615	due = evAddTime(evNowTime(),
1616	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1617#endif
1618
1619	tp->udata = udata;
1620	tp->owner = mod;
1621	tp->func = func;
1622
1623	LIST_INSERT_HEAD(&timer_list, tp, link);
1624
1625#ifdef USE_LIBBEGEMOT
1626	if ((tp->id = poll_start_timer(due.tv_sec * 1000 + due.tv_usec / 1000,
1627	    0, tfunc, tp)) < 0) {
1628		syslog(LOG_ERR, "cannot set timer: %m");
1629		exit(1);
1630	}
1631#else
1632	if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
1633	    == -1) {
1634		syslog(LOG_ERR, "cannot set timer: %m");
1635		exit(1);
1636	}
1637#endif
1638	return (tp);
1639}
1640
1641void
1642timer_stop(void *p)
1643{
1644	struct timer *tp = p;
1645
1646	LIST_REMOVE(tp, link);
1647#ifdef USE_LIBBEGEMOT
1648	poll_stop_timer(tp->id);
1649#else
1650	if (evClearTimer(evctx, tp->id) == -1) {
1651		syslog(LOG_ERR, "cannot stop timer: %m");
1652		exit(1);
1653	}
1654#endif
1655	free(p);
1656}
1657
1658static void
1659timer_flush(struct lmodule *mod)
1660{
1661	struct timer *t, *t1;
1662
1663	t = LIST_FIRST(&timer_list);
1664	while (t != NULL) {
1665		t1 = LIST_NEXT(t, link);
1666		if (t->owner == mod)
1667			timer_stop(t);
1668		t = t1;
1669	}
1670}
1671
1672static void
1673snmp_printf_func(const char *fmt, ...)
1674{
1675	va_list ap;
1676	static char *pend = NULL;
1677	char *ret, *new;
1678
1679	va_start(ap, fmt);
1680	vasprintf(&ret, fmt, ap);
1681	va_end(ap);
1682
1683	if (ret == NULL)
1684		return;
1685	if (pend != NULL) {
1686		if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1))
1687		    == NULL) {
1688			free(ret);
1689			return;
1690		}
1691		pend = new;
1692		strcat(pend, ret);
1693		free(ret);
1694	} else
1695		pend = ret;
1696
1697	while ((ret = strchr(pend, '\n')) != NULL) {
1698		*ret = '\0';
1699		syslog(LOG_DEBUG, "%s", pend);
1700		if (strlen(ret + 1) == 0) {
1701			free(pend);
1702			pend = NULL;
1703			break;
1704		}
1705		strcpy(pend, ret + 1);
1706	}
1707}
1708
1709static void
1710snmp_error_func(const char *err, ...)
1711{
1712	char errbuf[1000];
1713	va_list ap;
1714
1715	if (!(snmp_trace & LOG_SNMP_ERRORS))
1716		return;
1717
1718	va_start(ap, err);
1719	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1720	vsnprintf(errbuf + strlen(errbuf),
1721	    sizeof(errbuf) - strlen(errbuf), err, ap);
1722	va_end(ap);
1723
1724	syslog(LOG_ERR, "%s", errbuf);
1725}
1726
1727static void
1728snmp_debug_func(const char *err, ...)
1729{
1730	char errbuf[1000];
1731	va_list ap;
1732
1733	va_start(ap, err);
1734	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
1735	vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf),
1736	    err, ap);
1737	va_end(ap);
1738
1739	syslog(LOG_DEBUG, "%s", errbuf);
1740}
1741
1742static void
1743asn_error_func(const struct asn_buf *b, const char *err, ...)
1744{
1745	char errbuf[1000];
1746	va_list ap;
1747	u_int i;
1748
1749	if (!(snmp_trace & LOG_ASN1_ERRORS))
1750		return;
1751
1752	va_start(ap, err);
1753	snprintf(errbuf, sizeof(errbuf), "ASN.1: ");
1754	vsnprintf(errbuf + strlen(errbuf),
1755	    sizeof(errbuf) - strlen(errbuf), err, ap);
1756	va_end(ap);
1757
1758	if (b != NULL) {
1759		snprintf(errbuf + strlen(errbuf),
1760		    sizeof(errbuf) - strlen(errbuf), " at");
1761		for (i = 0; b->asn_len > i; i++)
1762			snprintf(errbuf + strlen(errbuf),
1763			    sizeof(errbuf) - strlen(errbuf),
1764			    " %02x", b->asn_cptr[i]);
1765	}
1766
1767	syslog(LOG_ERR, "%s", errbuf);
1768}
1769
1770/*
1771 * Create a new community
1772 */
1773u_int
1774comm_define(u_int priv, const char *descr, struct lmodule *owner,
1775    const char *str)
1776{
1777	struct community *c, *p;
1778	u_int ncomm;
1779
1780	/* generate an identifier */
1781	do {
1782		if ((ncomm = next_community_index++) == UINT_MAX)
1783			next_community_index = 1;
1784		TAILQ_FOREACH(c, &community_list, link)
1785			if (c->value == ncomm)
1786				break;
1787	} while (c != NULL);
1788
1789	if ((c = malloc(sizeof(struct community))) == NULL) {
1790		syslog(LOG_ERR, "comm_define: %m");
1791		return (0);
1792	}
1793	c->owner = owner;
1794	c->value = ncomm;
1795	c->descr = descr;
1796	c->string = NULL;
1797	c->private = priv;
1798
1799	if (str != NULL) {
1800		if((c->string = malloc(strlen(str)+1)) == NULL) {
1801			free(c);
1802			return (0);
1803		}
1804		strcpy(c->string, str);
1805	}
1806
1807	/* make index */
1808	if (c->owner == NULL) {
1809		c->index.len = 1;
1810		c->index.subs[0] = 0;
1811	} else {
1812		c->index = c->owner->index;
1813	}
1814	c->index.subs[c->index.len++] = c->private;
1815
1816	/*
1817	 * Insert ordered
1818	 */
1819	TAILQ_FOREACH(p, &community_list, link) {
1820		if (asn_compare_oid(&p->index, &c->index) > 0) {
1821			TAILQ_INSERT_BEFORE(p, c, link);
1822			break;
1823		}
1824	}
1825	if (p == NULL)
1826		TAILQ_INSERT_TAIL(&community_list, c, link);
1827	return (c->value);
1828}
1829
1830const char *
1831comm_string(u_int ncomm)
1832{
1833	struct community *p;
1834
1835	TAILQ_FOREACH(p, &community_list, link)
1836		if (p->value == ncomm)
1837			return (p->string);
1838	return (NULL);
1839}
1840
1841/*
1842 * Delete all communities allocated by a module
1843 */
1844static void
1845comm_flush(struct lmodule *mod)
1846{
1847	struct community *p, *p1;
1848
1849	p = TAILQ_FIRST(&community_list);
1850	while (p != NULL) {
1851		p1 = TAILQ_NEXT(p, link);
1852		if (p->owner == mod) {
1853			free(p->string);
1854			TAILQ_REMOVE(&community_list, p, link);
1855			free(p);
1856		}
1857		p = p1;
1858	}
1859}
1860
1861/*
1862 * Request ID handling.
1863 *
1864 * Allocate a new range of request ids. Use a first fit algorithm.
1865 */
1866u_int
1867reqid_allocate(int size, struct lmodule *mod)
1868{
1869	u_int type;
1870	struct idrange *r, *r1;
1871
1872	if (size <= 0 || size > INT32_MAX) {
1873		syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size);
1874		return (0);
1875	}
1876	/* allocate a type id */
1877	do {
1878		if ((type = next_idrange++) == UINT_MAX)
1879			next_idrange = 1;
1880		TAILQ_FOREACH(r, &idrange_list, link)
1881			if (r->type == type)
1882				break;
1883	} while(r != NULL);
1884
1885	/* find a range */
1886	if (TAILQ_EMPTY(&idrange_list))
1887		r = NULL;
1888	else {
1889		r = TAILQ_FIRST(&idrange_list);
1890		if (r->base < size) {
1891			while((r1 = TAILQ_NEXT(r, link)) != NULL) {
1892				if (r1->base - (r->base + r->size) >= size)
1893					break;
1894				r = r1;
1895			}
1896			r = r1;
1897		}
1898		if (r == NULL) {
1899			r1 = TAILQ_LAST(&idrange_list, idrange_list);
1900			if (INT32_MAX - size + 1 < r1->base + r1->size) {
1901				syslog(LOG_ERR, "out of id ranges (%u)", size);
1902				return (0);
1903			}
1904		}
1905	}
1906
1907	/* allocate structure */
1908	if ((r1 = malloc(sizeof(struct idrange))) == NULL) {
1909		syslog(LOG_ERR, "%s: %m", __FUNCTION__);
1910		return (0);
1911	}
1912
1913	r1->type = type;
1914	r1->size = size;
1915	r1->owner = mod;
1916	if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) {
1917		r1->base = 0;
1918		TAILQ_INSERT_HEAD(&idrange_list, r1, link);
1919	} else if (r == NULL) {
1920		r = TAILQ_LAST(&idrange_list, idrange_list);
1921		r1->base = r->base + r->size;
1922		TAILQ_INSERT_TAIL(&idrange_list, r1, link);
1923	} else {
1924		r = TAILQ_PREV(r, idrange_list, link);
1925		r1->base = r->base + r->size;
1926		TAILQ_INSERT_AFTER(&idrange_list, r, r1, link);
1927	}
1928	r1->next = r1->base;
1929
1930	return (type);
1931}
1932
1933int32_t
1934reqid_next(u_int type)
1935{
1936	struct idrange *r;
1937	int32_t id;
1938
1939	TAILQ_FOREACH(r, &idrange_list, link)
1940		if (r->type == type)
1941			break;
1942	if (r == NULL) {
1943		syslog(LOG_CRIT, "wrong idrange type");
1944		abort();
1945	}
1946	if ((id = r->next++) == r->base + (r->size - 1))
1947		r->next = r->base;
1948	return (id);
1949}
1950
1951int32_t
1952reqid_base(u_int type)
1953{
1954	struct idrange *r;
1955
1956	TAILQ_FOREACH(r, &idrange_list, link)
1957		if (r->type == type)
1958			return (r->base);
1959	syslog(LOG_CRIT, "wrong idrange type");
1960	abort();
1961}
1962
1963u_int
1964reqid_type(int32_t reqid)
1965{
1966	struct idrange *r;
1967
1968	TAILQ_FOREACH(r, &idrange_list, link)
1969		if (reqid >= r->base && reqid <= r->base + (r->size - 1))
1970			return (r->type);
1971	return (0);
1972}
1973
1974int
1975reqid_istype(int32_t reqid, u_int type)
1976{
1977	return (reqid_type(reqid) == type);
1978}
1979
1980/*
1981 * Delete all communities allocated by a module
1982 */
1983static void
1984reqid_flush(struct lmodule *mod)
1985{
1986	struct idrange *p, *p1;
1987
1988	p = TAILQ_FIRST(&idrange_list);
1989	while (p != NULL) {
1990		p1 = TAILQ_NEXT(p, link);
1991		if (p->owner == mod) {
1992			TAILQ_REMOVE(&idrange_list, p, link);
1993			free(p);
1994		}
1995		p = p1;
1996	}
1997}
1998
1999/*
2000 * Merge the given tree for the given module into the main tree.
2001 */
2002static int
2003compare_node(const void *v1, const void *v2)
2004{
2005	const struct snmp_node *n1 = v1;
2006	const struct snmp_node *n2 = v2;
2007
2008	return (asn_compare_oid(&n1->oid, &n2->oid));
2009}
2010static int
2011tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod)
2012{
2013	struct snmp_node *xtree;
2014	u_int i;
2015
2016	xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize));
2017	if (xtree == NULL) {
2018		syslog(LOG_ERR, "tree_merge: %m");
2019		return (-1);
2020	}
2021	tree = xtree;
2022	memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize);
2023
2024	for (i = 0; i < nsize; i++)
2025		tree[tree_size + i].tree_data = mod;
2026
2027	tree_size += nsize;
2028
2029	qsort(tree, tree_size, sizeof(tree[0]), compare_node);
2030
2031	return (0);
2032}
2033
2034/*
2035 * Remove all nodes belonging to the loadable module
2036 */
2037static void
2038tree_unmerge(struct lmodule *mod)
2039{
2040	u_int s, d;
2041
2042	for(s = d = 0; s < tree_size; s++)
2043		if (tree[s].tree_data != mod) {
2044			if (s != d)
2045				tree[d] = tree[s];
2046			d++;
2047		}
2048	tree_size = d;
2049}
2050
2051/*
2052 * Loadable modules
2053 */
2054struct lmodule *
2055lm_load(const char *path, const char *section)
2056{
2057	struct lmodule *m;
2058	int err;
2059	int i;
2060	char *av[MAX_MOD_ARGS + 1];
2061	int ac;
2062	u_int u;
2063
2064	if ((m = malloc(sizeof(*m))) == NULL) {
2065		syslog(LOG_ERR, "lm_load: %m");
2066		return (NULL);
2067	}
2068	m->handle = NULL;
2069	m->flags = 0;
2070	strcpy(m->section, section);
2071
2072	if ((m->path = malloc(strlen(path) + 1)) == NULL) {
2073		syslog(LOG_ERR, "lm_load: %m");
2074		goto err;
2075	}
2076	strcpy(m->path, path);
2077
2078	/*
2079	 * Make index
2080	 */
2081	m->index.subs[0] = strlen(section);
2082	m->index.len = m->index.subs[0] + 1;
2083	for (u = 0; u < m->index.subs[0]; u++)
2084		m->index.subs[u + 1] = section[u];
2085
2086	/*
2087	 * Load the object file and locate the config structure
2088	 */
2089	if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
2090		syslog(LOG_ERR, "lm_load: open %s", dlerror());
2091		goto err;
2092	}
2093
2094	if ((m->config = dlsym(m->handle, "config")) == NULL) {
2095		syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror());
2096		goto err;
2097	}
2098
2099	/*
2100	 * Insert it into the right place
2101	 */
2102	INSERT_OBJECT_OID(m, &lmodules);
2103
2104	/* preserve order */
2105	if (community == COMM_INITIALIZE) {
2106		m->flags |= LM_ONSTARTLIST;
2107		TAILQ_INSERT_TAIL(&modules_start, m, start);
2108	}
2109
2110	/*
2111	 * make the argument vector.
2112	 */
2113	ac = 0;
2114	for (i = 0; i < nprogargs; i++) {
2115		if (strlen(progargs[i]) >= strlen(section) + 1 &&
2116		    strncmp(progargs[i], section, strlen(section)) == 0 &&
2117		    progargs[i][strlen(section)] == ':') {
2118			if (ac == MAX_MOD_ARGS) {
2119				syslog(LOG_WARNING, "too many arguments for "
2120				    "module '%s", section);
2121				break;
2122			}
2123			av[ac++] = &progargs[i][strlen(section)+1];
2124		}
2125	}
2126	av[ac] = NULL;
2127
2128	/*
2129	 * Run the initialisation function
2130	 */
2131	if ((err = (*m->config->init)(m, ac, av)) != 0) {
2132		syslog(LOG_ERR, "lm_load: init failed: %d", err);
2133		TAILQ_REMOVE(&lmodules, m, link);
2134		goto err;
2135	}
2136
2137	return (m);
2138
2139  err:
2140	if (m->handle)
2141		dlclose(m->handle);
2142	free(m->path);
2143	free(m);
2144	return (NULL);
2145}
2146
2147/*
2148 * Start a module
2149 */
2150void
2151lm_start(struct lmodule *mod)
2152{
2153	const struct lmodule *m;
2154
2155	/*
2156	 * Merge tree. If this fails, unload the module.
2157	 */
2158	if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) {
2159		lm_unload(mod);
2160		return;
2161	}
2162
2163	/*
2164	 * Read configuration
2165	 */
2166	if (read_config(config_file, mod)) {
2167		syslog(LOG_ERR, "error in config file");
2168		lm_unload(mod);
2169		return;
2170	}
2171	if (mod->config->start)
2172		(*mod->config->start)();
2173
2174	mod->flags |= LM_STARTED;
2175
2176	/*
2177	 * Inform other modules
2178	 */
2179	TAILQ_FOREACH(m, &lmodules, link)
2180		if (m->config->loading)
2181			(*m->config->loading)(mod, 1);
2182}
2183
2184
2185/*
2186 * Unload a module.
2187 */
2188void
2189lm_unload(struct lmodule *m)
2190{
2191	int err;
2192	const struct lmodule *mod;
2193
2194	TAILQ_REMOVE(&lmodules, m, link);
2195	if (m->flags & LM_ONSTARTLIST)
2196		TAILQ_REMOVE(&modules_start, m, start);
2197	tree_unmerge(m);
2198
2199	if ((m->flags & LM_STARTED) && m->config->fini &&
2200	    (err = (*m->config->fini)()) != 0)
2201		syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err);
2202
2203	comm_flush(m);
2204	reqid_flush(m);
2205	timer_flush(m);
2206	fd_flush(m);
2207
2208	dlclose(m->handle);
2209	free(m->path);
2210
2211	/*
2212	 * Inform other modules
2213	 */
2214	TAILQ_FOREACH(mod, &lmodules, link)
2215		if (mod->config->loading)
2216			(*mod->config->loading)(m, 0);
2217
2218	free(m);
2219}
2220
2221/*
2222 * Register an object resource and return the index (or 0 on failures)
2223 */
2224u_int
2225or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod)
2226{
2227	struct objres *objres, *or1;
2228	u_int idx;
2229
2230	/* find a free index */
2231	idx = 1;
2232	for (objres = TAILQ_FIRST(&objres_list);
2233	     objres != NULL;
2234	     objres = TAILQ_NEXT(objres, link)) {
2235		if ((or1 = TAILQ_NEXT(objres, link)) == NULL ||
2236		    or1->index > objres->index + 1) {
2237			idx = objres->index + 1;
2238			break;
2239		}
2240	}
2241
2242	if ((objres = malloc(sizeof(*objres))) == NULL)
2243		return (0);
2244
2245	objres->index = idx;
2246	objres->oid = *or;
2247	strlcpy(objres->descr, descr, sizeof(objres->descr));
2248	objres->uptime = get_ticks() - start_tick;
2249	objres->module = mod;
2250
2251	INSERT_OBJECT_INT(objres, &objres_list);
2252
2253	systemg.or_last_change = objres->uptime;
2254
2255	return (idx);
2256}
2257
2258void
2259or_unregister(u_int idx)
2260{
2261	struct objres *objres;
2262
2263	TAILQ_FOREACH(objres, &objres_list, link)
2264		if (objres->index == idx) {
2265			TAILQ_REMOVE(&objres_list, objres, link);
2266			free(objres);
2267			return;
2268		}
2269}
2270