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