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