xref: /freebsd/contrib/bsnmp/snmpd/main.c (revision 8b959dd6a3921c35395bef4a6d7ad2426a3bd88e)
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   * Copyright (c) 2010 The FreeBSD Foundation
9   * All rights reserved.
10   *
11   * Portions of this software were developed by Shteryana Sotirova Shopova
12   * under sponsorship from the FreeBSD Foundation.
13   *
14   * Redistribution and use in source and binary forms, with or without
15   * modification, are permitted provided that the following conditions
16   * are met:
17   * 1. Redistributions of source code must retain the above copyright
18   *    notice, this list of conditions and the following disclaimer.
19   * 2. Redistributions in binary form must reproduce the above copyright
20   *    notice, this list of conditions and the following disclaimer in the
21   *    documentation and/or other materials provided with the distribution.
22   *
23   * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26   * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33   * SUCH DAMAGE.
34   *
35   * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $
36   *
37   * SNMPd main stuff.
38   */
39  
40  #include <sys/queue.h>
41  #include <sys/param.h>
42  #include <sys/un.h>
43  #include <sys/ucred.h>
44  #include <sys/uio.h>
45  #include <stdio.h>
46  #include <stdlib.h>
47  #include <stddef.h>
48  #include <string.h>
49  #include <stdarg.h>
50  #include <ctype.h>
51  #include <errno.h>
52  #include <syslog.h>
53  #include <unistd.h>
54  #include <signal.h>
55  #include <dlfcn.h>
56  
57  #ifdef USE_TCPWRAPPERS
58  #include <arpa/inet.h>
59  #include <tcpd.h>
60  #endif
61  
62  #include "support.h"
63  #include "snmpmod.h"
64  #include "snmpd.h"
65  #include "tree.h"
66  #include "oid.h"
67  
68  #include "trans_inet.h"
69  
70  #define	PATH_PID	"/var/run/%s.pid"
71  #define PATH_CONFIG	"/etc/%s.config"
72  #define	PATH_ENGINE	"/var/%s.engine"
73  
74  uint64_t this_tick;	/* start of processing of current packet (absolute) */
75  uint64_t start_tick;	/* start of processing */
76  
77  struct systemg systemg = {
78  	NULL,
79  	{ 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }},
80  	NULL, NULL, NULL,
81  	64 + 8 + 4,
82  	0
83  };
84  struct debug debug = {
85  	0,		/* dump_pdus */
86  	LOG_DEBUG,	/* log_pri */
87  	0,		/* evdebug */
88  };
89  
90  struct snmpd snmpd = {
91  	2048,		/* txbuf */
92  	2048,		/* rxbuf */
93  	0,		/* comm_dis */
94  	0,		/* auth_traps */
95  	{0, 0, 0, 0},	/* trap1addr */
96  	VERS_ENABLE_ALL,/* version_enable */
97  };
98  struct snmpd_stats snmpd_stats;
99  
100  struct snmpd_usmstat snmpd_usmstats;
101  
102  /* snmpEngine */
103  struct snmp_engine snmpd_engine;
104  
105  /* snmpSerialNo */
106  int32_t snmp_serial_no;
107  
108  struct snmpd_target_stats snmpd_target_stats;
109  
110  /* search path for config files */
111  const char *syspath = PATH_SYSCONFIG;
112  
113  /* list of all loaded modules */
114  struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules);
115  
116  /* list of loaded modules during start-up in the order they were loaded */
117  static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start);
118  
119  /* list of all known communities */
120  struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list);
121  
122  /* list of all known USM users */
123  static struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist);
124  
125  /* A list of all VACM users configured, including v1, v2c and v3 */
126  static struct vacm_userlist vacm_userlist =
127      SLIST_HEAD_INITIALIZER(vacm_userlist);
128  
129  /* A list of all VACM groups */
130  static struct vacm_grouplist vacm_grouplist =
131      SLIST_HEAD_INITIALIZER(vacm_grouplist);
132  
133  static struct vacm_group vacm_default_group = {
134  	.groupname = "",
135  };
136  
137  /* The list of configured access entries */
138  static struct vacm_accesslist vacm_accesslist =
139      TAILQ_HEAD_INITIALIZER(vacm_accesslist);
140  
141  /* The list of configured views */
142  static struct vacm_viewlist vacm_viewlist =
143      SLIST_HEAD_INITIALIZER(vacm_viewlist);
144  
145  /* The list of configured contexts */
146  static struct vacm_contextlist vacm_contextlist =
147      SLIST_HEAD_INITIALIZER(vacm_contextlist);
148  
149  /* list of all installed object resources */
150  struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list);
151  
152  /* community value generator */
153  static u_int next_community_index = 1;
154  
155  /* list of all known ranges */
156  struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list);
157  
158  /* identifier generator */
159  u_int next_idrange = 1;
160  
161  /* list of all current timers */
162  struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list);
163  
164  /* list of file descriptors */
165  struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list);
166  
167  /* program arguments */
168  static char **progargs;
169  static int nprogargs;
170  
171  /* current community */
172  u_int	community;
173  static struct community *comm;
174  
175  /* current USM user */
176  struct usm_user *usm_user;
177  
178  /* file names */
179  static char config_file[MAXPATHLEN + 1];
180  static char pid_file[MAXPATHLEN + 1];
181  char engine_file[MAXPATHLEN + 1];
182  
183  #ifndef USE_LIBBEGEMOT
184  /* event context */
185  static evContext evctx;
186  #endif
187  
188  /* signal mask */
189  static sigset_t blocked_sigs;
190  
191  /* signal handling */
192  static int work;
193  #define	WORK_DOINFO	0x0001
194  #define	WORK_RECONFIG	0x0002
195  
196  /* oids */
197  static const struct asn_oid
198  	oid_snmpMIB = OIDX_snmpMIB,
199  	oid_begemotSnmpd = OIDX_begemotSnmpd,
200  	oid_coldStart = OIDX_coldStart,
201  	oid_authenticationFailure = OIDX_authenticationFailure;
202  
203  const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }};
204  
205  const struct asn_oid oid_usmUnknownEngineIDs =
206  	{ 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}};
207  
208  const struct asn_oid oid_usmNotInTimeWindows =
209  	{ 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}};
210  
211  /* request id generator for traps */
212  u_int trap_reqid;
213  
214  /* help text */
215  static const char usgtxt[] = "\
216  Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\
217  Open Communication Systems (FhG Fokus). All rights reserved.\n\
218  Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\
219  usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\
220               [-l prefix] [-m variable=value] [-p file]\n\
221  options:\n\
222    -d		don't daemonize\n\
223    -h		print this info\n\
224    -c file	specify configuration file\n\
225    -D options	debugging options\n\
226    -e file	specify engine id file\n\
227    -I path	system include path\n\
228    -l prefix	default basename for pid and config file\n\
229    -m var=val	define variable\n\
230    -p file	specify pid file\n\
231  ";
232  
233  /* hosts_access(3) request */
234  #ifdef USE_TCPWRAPPERS
235  static struct request_info req;
236  #endif
237  
238  /* transports */
239  extern const struct transport_def udp_trans;
240  extern const struct transport_def lsock_trans;
241  
242  struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
243  
244  /* forward declarations */
245  static void snmp_printf_func(const char *fmt, ...);
246  static void snmp_error_func(const char *err, ...);
247  static void snmp_debug_func(const char *err, ...);
248  static void asn_error_func(const struct asn_buf *b, const char *err, ...);
249  
250  /*
251   * Allocate rx/tx buffer. We allocate one byte more for rx.
252   */
253  void *
buf_alloc(int tx)254  buf_alloc(int tx)
255  {
256  	void *buf;
257  
258  	if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) {
259  		syslog(LOG_CRIT, "cannot allocate buffer");
260  		if (tx)
261  			snmpd_stats.noTxbuf++;
262  		else
263  			snmpd_stats.noRxbuf++;
264  		return (NULL);
265  	}
266  	return (buf);
267  }
268  
269  /*
270   * Return the buffer size.
271   */
272  size_t
buf_size(int tx)273  buf_size(int tx)
274  {
275  	return (tx ? snmpd.txbuf : snmpd.rxbuf);
276  }
277  
278  /*
279   * Prepare a PDU for output
280   */
281  void
snmp_output(struct snmp_pdu * pdu,u_char * sndbuf,size_t * sndlen,const char * dest)282  snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen,
283      const char *dest)
284  {
285  	struct asn_buf resp_b;
286  	enum snmp_code code;
287  
288  	resp_b.asn_ptr = sndbuf;
289  	resp_b.asn_len = snmpd.txbuf;
290  
291  	if ((code = snmp_pdu_encode(pdu, &resp_b)) != SNMP_CODE_OK) {
292  		syslog(LOG_ERR, "cannot encode message (code=%d)", code);
293  		abort();
294  	}
295  	if (debug.dump_pdus) {
296  		snmp_printf("%s <- ", dest);
297  		snmp_pdu_dump(pdu);
298  	}
299  	*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
300  }
301  
302  /*
303   * Check USM PDU header credentials against local SNMP Engine & users.
304   */
305  static enum snmp_code
snmp_pdu_auth_user(struct snmp_pdu * pdu)306  snmp_pdu_auth_user(struct snmp_pdu *pdu)
307  {
308  	usm_user = NULL;
309  
310  	/* un-authenticated snmpEngineId discovery */
311  	if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) {
312  		pdu->engine.engine_len = snmpd_engine.engine_len;
313  		memcpy(pdu->engine.engine_id, snmpd_engine.engine_id,
314  		    snmpd_engine.engine_len);
315  		update_snmpd_engine_time();
316  		pdu->engine.engine_boots = snmpd_engine.engine_boots;
317  		pdu->engine.engine_time = snmpd_engine.engine_time;
318  		pdu->flags |= SNMP_MSG_AUTODISCOVER;
319  		return (SNMP_CODE_OK);
320  	}
321  
322  	if ((usm_user = usm_find_user(pdu->engine.engine_id,
323  	    pdu->engine.engine_len, pdu->user.sec_name)) == NULL ||
324  	    usm_user->status != 1 /* active */)
325  		return (SNMP_CODE_BADUSER);
326  
327  	if (usm_user->user_engine_len != snmpd_engine.engine_len ||
328  	    memcmp(usm_user->user_engine_id, snmpd_engine.engine_id,
329  	    snmpd_engine.engine_len) != 0)
330  		return (SNMP_CODE_BADENGINE);
331  
332  	pdu->user.priv_proto = usm_user->suser.priv_proto;
333  	memcpy(pdu->user.priv_key, usm_user->suser.priv_key,
334  	    sizeof(pdu->user.priv_key));
335  
336  	/* authenticated snmpEngineId discovery */
337  	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
338  		update_snmpd_engine_time();
339  		pdu->user.auth_proto = usm_user->suser.auth_proto;
340  		memcpy(pdu->user.auth_key, usm_user->suser.auth_key,
341  		    sizeof(pdu->user.auth_key));
342  
343  		if (pdu->engine.engine_boots == 0 &&
344  		    pdu->engine.engine_time == 0) {
345  			update_snmpd_engine_time();
346  		    	pdu->flags |= SNMP_MSG_AUTODISCOVER;
347  			return (SNMP_CODE_OK);
348  		}
349  
350  		if (pdu->engine.engine_boots != snmpd_engine.engine_boots ||
351  		    abs(pdu->engine.engine_time - snmpd_engine.engine_time) >
352  		    SNMP_TIME_WINDOW)
353  			return (SNMP_CODE_NOTINTIME);
354  	}
355  
356  	if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
357  	    (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) ||
358  	    ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 &&
359  	    usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) ||
360  	    ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 &&
361  	    usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV))
362  		return (SNMP_CODE_BADSECLEVEL);
363  
364  	return (SNMP_CODE_OK);
365  }
366  
367  /*
368   * Check whether access to each of var bindings in the PDU is allowed based
369   * on the user credentials against the configured User groups & VACM views.
370   */
371  enum snmp_code
snmp_pdu_auth_access(struct snmp_pdu * pdu,int32_t * ip)372  snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip)
373  {
374  	const char *uname;
375  	int32_t suboid, smodel;
376  	uint32_t i;
377  	struct vacm_user *vuser;
378  	struct vacm_access *acl;
379  	struct vacm_context *vacmctx;
380  	struct vacm_view *view;
381  
382  	/*
383  	 * At least a default context exists if the snmpd_vacm(3) module is
384  	 * running.
385  	 */
386  	if (SLIST_EMPTY(&vacm_contextlist) ||
387  	    (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0)
388  		return (SNMP_CODE_OK);
389  
390  	switch (pdu->version) {
391  	case SNMP_V1:
392  		if ((uname = comm_string(community)) == NULL)
393  			return (SNMP_CODE_FAILED);
394  		smodel = SNMP_SECMODEL_SNMPv1;
395  		break;
396  
397  	case SNMP_V2c:
398  		if ((uname = comm_string(community)) == NULL)
399  			return (SNMP_CODE_FAILED);
400  		smodel = SNMP_SECMODEL_SNMPv2c;
401  		break;
402  
403  	case SNMP_V3:
404  		uname = pdu->user.sec_name;
405  		if ((smodel = pdu->security_model) !=  SNMP_SECMODEL_USM)
406  			return (SNMP_CODE_FAILED);
407  		/* Compare the PDU context engine id against the agent's */
408  		if (pdu->context_engine_len != snmpd_engine.engine_len ||
409  		    memcmp(pdu->context_engine, snmpd_engine.engine_id,
410  		    snmpd_engine.engine_len) != 0)
411  			return (SNMP_CODE_FAILED);
412  		break;
413  
414  	default:
415  		abort();
416  	}
417  
418  	SLIST_FOREACH(vuser, &vacm_userlist, vvu)
419  		if (strcmp(uname, vuser->secname) == 0 &&
420  		    vuser->sec_model == smodel)
421  			break;
422  
423  	if (vuser == NULL || vuser->group == NULL)
424  		return (SNMP_CODE_FAILED);
425  
426  	/* XXX: shteryana - recheck */
427  	TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) {
428  		if (acl->group != vuser->group)
429  			continue;
430  		SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl)
431  			if (memcmp(vacmctx->ctxname, acl->ctx_prefix,
432  			    acl->ctx_match) == 0)
433  				goto match;
434  	}
435  
436  	return (SNMP_CODE_FAILED);
437  
438  match:
439  
440  	switch (pdu->type) {
441  	case SNMP_PDU_GET:
442  	case SNMP_PDU_GETNEXT:
443  	case SNMP_PDU_GETBULK:
444  		if ((view = acl->read_view) == NULL)
445  			return (SNMP_CODE_FAILED);
446  		break;
447  
448  	case SNMP_PDU_SET:
449  		if ((view = acl->write_view) == NULL)
450  			return (SNMP_CODE_FAILED);
451  		break;
452  
453  	case SNMP_PDU_TRAP:
454  	case SNMP_PDU_INFORM:
455  	case SNMP_PDU_TRAP2:
456  	case SNMP_PDU_REPORT:
457  		if ((view = acl->notify_view) == NULL)
458  			return (SNMP_CODE_FAILED);
459  		break;
460  	case SNMP_PDU_RESPONSE:
461  		/* NOTREACHED */
462  			return (SNMP_CODE_FAILED);
463  	default:
464  		abort();
465  	}
466  
467  	for (i = 0; i < pdu->nbindings; i++) {
468  		/* XXX - view->mask*/
469  		suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var);
470  		if ((!suboid && !view->exclude) || (suboid && view->exclude)) {
471  			*ip = i + 1;
472  			return (SNMP_CODE_FAILED);
473  		}
474  	}
475  
476  	return (SNMP_CODE_OK);
477  }
478  
479  /*
480   * SNMP input. Start: decode the PDU, find the user or community.
481   */
482  enum snmpd_input_err
snmp_input_start(const u_char * buf,size_t len,const char * source,struct snmp_pdu * pdu,int32_t * ip,size_t * pdulen)483  snmp_input_start(const u_char *buf, size_t len, const char *source,
484      struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen)
485  {
486  	struct asn_buf b;
487  	enum snmp_code code;
488  	enum snmpd_input_err ret;
489  	int sret;
490  
491  	/* update uptime */
492  	this_tick = get_ticks();
493  
494  	b.asn_cptr = buf;
495  	b.asn_len = len;
496  
497  	ret = SNMPD_INPUT_OK;
498  
499  	/* look whether we have enough bytes for the entire PDU. */
500  	switch (sret = snmp_pdu_snoop(&b)) {
501  
502  	  case 0:
503  		return (SNMPD_INPUT_TRUNC);
504  
505  	  case -1:
506  		snmpd_stats.inASNParseErrs++;
507  		return (SNMPD_INPUT_FAILED);
508  	}
509  	b.asn_len = *pdulen = (size_t)sret;
510  
511  	memset(pdu, 0, sizeof(*pdu));
512  	if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK)
513  		goto decoded;
514  
515  	if (pdu->version == SNMP_V3) {
516  		if (pdu->security_model != SNMP_SECMODEL_USM) {
517  			code = SNMP_CODE_FAILED;
518  			goto decoded;
519  		}
520  		if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK)
521  		    	goto decoded;
522  		if ((code =  snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK)
523  			goto decoded;
524  	}
525  	code = snmp_pdu_decode_scoped(&b, pdu, ip);
526  
527  decoded:
528  	snmpd_stats.inPkts++;
529  
530  	switch (code) {
531  
532  	  case SNMP_CODE_FAILED:
533  		snmpd_stats.inASNParseErrs++;
534  		return (SNMPD_INPUT_FAILED);
535  
536  	  case SNMP_CODE_BADVERS:
537  	  bad_vers:
538  		snmpd_stats.inBadVersions++;
539  		return (SNMPD_INPUT_FAILED);
540  
541  	  case SNMP_CODE_BADLEN:
542  		if (pdu->type == SNMP_OP_SET)
543  			ret = SNMPD_INPUT_VALBADLEN;
544  		break;
545  
546  	  case SNMP_CODE_OORANGE:
547  		if (pdu->type == SNMP_OP_SET)
548  			ret = SNMPD_INPUT_VALRANGE;
549  		break;
550  
551  	  case SNMP_CODE_BADENC:
552  		if (pdu->type == SNMP_OP_SET)
553  			ret = SNMPD_INPUT_VALBADENC;
554  		break;
555  
556  	  case SNMP_CODE_BADSECLEVEL:
557  		snmpd_usmstats.unsupported_seclevels++;
558  		return (SNMPD_INPUT_FAILED);
559  
560  	  case SNMP_CODE_NOTINTIME:
561  		snmpd_usmstats.not_in_time_windows++;
562  		return (SNMPD_INPUT_FAILED);
563  
564  	  case SNMP_CODE_BADUSER:
565  		snmpd_usmstats.unknown_users++;
566  		return (SNMPD_INPUT_FAILED);
567  
568  	  case SNMP_CODE_BADENGINE:
569  		snmpd_usmstats.unknown_engine_ids++;
570  		return (SNMPD_INPUT_FAILED);
571  
572  	  case SNMP_CODE_BADDIGEST:
573  		snmpd_usmstats.wrong_digests++;
574  		return (SNMPD_INPUT_FAILED);
575  
576  	  case SNMP_CODE_EDECRYPT:
577  		snmpd_usmstats.decrypt_errors++;
578  		return (SNMPD_INPUT_FAILED);
579  
580  	  case SNMP_CODE_OK:
581  		switch (pdu->version) {
582  
583  		  case SNMP_V1:
584  			if (!(snmpd.version_enable & VERS_ENABLE_V1))
585  				goto bad_vers;
586  			break;
587  
588  		  case SNMP_V2c:
589  			if (!(snmpd.version_enable & VERS_ENABLE_V2C))
590  				goto bad_vers;
591  			break;
592  
593  		  case SNMP_V3:
594  		  	if (!(snmpd.version_enable & VERS_ENABLE_V3))
595  				goto bad_vers;
596  			break;
597  
598  		  case SNMP_Verr:
599  			goto bad_vers;
600  		}
601  		break;
602  	}
603  
604  	if (debug.dump_pdus) {
605  		snmp_printf("%s -> ", source);
606  		snmp_pdu_dump(pdu);
607  	}
608  
609  	/*
610  	 * Look, whether we know the community or user
611  	 */
612  
613  	if (pdu->version != SNMP_V3) {
614  		TAILQ_FOREACH(comm, &community_list, link)
615  			if (comm->string != NULL &&
616  			    strcmp(comm->string, pdu->community) == 0)
617  				break;
618  
619  		if (comm == NULL) {
620  			snmpd_stats.inBadCommunityNames++;
621  			snmp_pdu_free(pdu);
622  			if (snmpd.auth_traps)
623  				snmp_send_trap(&oid_authenticationFailure,
624  				    (struct snmp_value *)NULL);
625  			ret = SNMPD_INPUT_BAD_COMM;
626  		} else
627  			community = comm->value;
628  	} else if (pdu->nbindings == 0) {
629  		/* RFC 3414 - snmpEngineID Discovery */
630  		if (strlen(pdu->user.sec_name) == 0) {
631  			asn_append_oid(&(pdu->bindings[pdu->nbindings++].var),
632  			    &oid_usmUnknownEngineIDs);
633  			pdu->context_engine_len = snmpd_engine.engine_len;
634  			memcpy(pdu->context_engine, snmpd_engine.engine_id,
635  			    snmpd_engine.engine_len);
636  		} else if (pdu->engine.engine_boots == 0 &&
637  		    pdu->engine.engine_time == 0) {
638  			asn_append_oid(&(pdu->bindings[pdu->nbindings++].var),
639  			    &oid_usmNotInTimeWindows);
640  			update_snmpd_engine_time();
641  			pdu->engine.engine_boots = snmpd_engine.engine_boots;
642  			pdu->engine.engine_time = snmpd_engine.engine_time;
643  		}
644  	} else if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
645  	     (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) {
646  		snmpd_usmstats.not_in_time_windows++;
647  		ret = SNMPD_INPUT_FAILED;
648  	}
649  
650  	if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK)
651  		ret = SNMPD_INPUT_FAILED;
652  
653  	return (ret);
654  }
655  
656  /*
657   * Will return only _OK or _FAILED
658   */
659  enum snmpd_input_err
snmp_input_finish(struct snmp_pdu * pdu,const u_char * rcvbuf,size_t rcvlen,u_char * sndbuf,size_t * sndlen,const char * source,enum snmpd_input_err ierr,int32_t ivar,void * data)660  snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen,
661      u_char *sndbuf, size_t *sndlen, const char *source,
662      enum snmpd_input_err ierr, int32_t ivar, void *data)
663  {
664  	struct snmp_pdu resp;
665  	struct asn_buf resp_b, pdu_b;
666  	enum snmp_ret ret;
667  
668  	resp_b.asn_ptr = sndbuf;
669  	resp_b.asn_len = snmpd.txbuf;
670  
671  	pdu_b.asn_cptr = rcvbuf;
672  	pdu_b.asn_len = rcvlen;
673  
674  	if (ierr != SNMPD_INPUT_OK) {
675  		/* error decoding the input of a SET */
676  		if (pdu->version == SNMP_V1)
677  			pdu->error_status = SNMP_ERR_BADVALUE;
678  		else if (ierr == SNMPD_INPUT_VALBADLEN)
679  			pdu->error_status = SNMP_ERR_WRONG_LENGTH;
680  		else if (ierr == SNMPD_INPUT_VALRANGE)
681  			pdu->error_status = SNMP_ERR_WRONG_VALUE;
682  		else
683  			pdu->error_status = SNMP_ERR_WRONG_ENCODING;
684  
685  		pdu->error_index = ivar;
686  
687  		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
688  			syslog(LOG_WARNING, "could not encode error response");
689  			snmpd_stats.silentDrops++;
690  			return (SNMPD_INPUT_FAILED);
691  		}
692  
693  		if (debug.dump_pdus) {
694  			snmp_printf("%s <- ", source);
695  			snmp_pdu_dump(pdu);
696  		}
697  		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
698  		return (SNMPD_INPUT_OK);
699  	}
700  
701  	switch (pdu->type) {
702  
703  	  case SNMP_PDU_GET:
704  		ret = snmp_get(pdu, &resp_b, &resp, data);
705  		break;
706  
707  	  case SNMP_PDU_GETNEXT:
708  		ret = snmp_getnext(pdu, &resp_b, &resp, data);
709  		break;
710  
711  	  case SNMP_PDU_SET:
712  		ret = snmp_set(pdu, &resp_b, &resp, data);
713  		break;
714  
715  	  case SNMP_PDU_GETBULK:
716  		ret = snmp_getbulk(pdu, &resp_b, &resp, data);
717  		break;
718  
719  	  default:
720  		ret = SNMP_RET_IGN;
721  		break;
722  	}
723  
724  	switch (ret) {
725  
726  	  case SNMP_RET_OK:
727  		/* normal return - send a response */
728  		if (debug.dump_pdus) {
729  			snmp_printf("%s <- ", source);
730  			snmp_pdu_dump(&resp);
731  		}
732  		*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
733  		snmp_pdu_free(&resp);
734  		return (SNMPD_INPUT_OK);
735  
736  	  case SNMP_RET_IGN:
737  		/* error - send nothing */
738  		snmpd_stats.silentDrops++;
739  		return (SNMPD_INPUT_FAILED);
740  
741  	  case SNMP_RET_ERR:
742  		/* error - send error response. The snmp routine has
743  		 * changed the error fields in the original message. */
744  		resp_b.asn_ptr = sndbuf;
745  		resp_b.asn_len = snmpd.txbuf;
746  		if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) {
747  			syslog(LOG_WARNING, "could not encode error response");
748  			snmpd_stats.silentDrops++;
749  			return (SNMPD_INPUT_FAILED);
750  		} else {
751  			if (debug.dump_pdus) {
752  				snmp_printf("%s <- ", source);
753  				snmp_pdu_dump(pdu);
754  			}
755  			*sndlen = (size_t)(resp_b.asn_ptr - sndbuf);
756  			return (SNMPD_INPUT_OK);
757  		}
758  	}
759  	abort();
760  }
761  
762  /*
763   * Insert a port into the right place in the transport's table of ports
764   */
765  void
trans_insert_port(struct transport * t,struct tport * port)766  trans_insert_port(struct transport *t, struct tport *port)
767  {
768  	struct tport *p;
769  
770  	port->transport = t;
771  	TAILQ_FOREACH(p, &t->table, link) {
772  		if (asn_compare_oid(&p->index, &port->index) > 0) {
773  			TAILQ_INSERT_BEFORE(p, port, link);
774  			return;
775  		}
776  	}
777  	TAILQ_INSERT_TAIL(&t->table, port, link);
778  }
779  
780  /*
781   * Remove a port from a transport's list
782   */
783  void
trans_remove_port(struct tport * port)784  trans_remove_port(struct tport *port)
785  {
786  
787  	TAILQ_REMOVE(&port->transport->table, port, link);
788  }
789  
790  /*
791   * Find a port on a transport's list
792   */
793  struct tport *
trans_find_port(struct transport * t,const struct asn_oid * idx,u_int sub)794  trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub)
795  {
796  
797  	return (FIND_OBJECT_OID(&t->table, idx, sub));
798  }
799  
800  /*
801   * Find next port on a transport's list
802   */
803  struct tport *
trans_next_port(struct transport * t,const struct asn_oid * idx,u_int sub)804  trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub)
805  {
806  
807  	return (NEXT_OBJECT_OID(&t->table, idx, sub));
808  }
809  
810  /*
811   * Return first port
812   */
813  struct tport *
trans_first_port(struct transport * t)814  trans_first_port(struct transport *t)
815  {
816  
817  	return (TAILQ_FIRST(&t->table));
818  }
819  
820  /*
821   * Iterate through all ports until a function returns a 0.
822   */
823  struct tport *
trans_iter_port(struct transport * t,int (* func)(struct tport *,intptr_t),intptr_t arg)824  trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t),
825      intptr_t arg)
826  {
827  	struct tport *p;
828  
829  	TAILQ_FOREACH(p, &t->table, link)
830  		if (func(p, arg) == 0)
831  			return (p);
832  	return (NULL);
833  }
834  
835  /*
836   * Register a transport
837   */
838  int
trans_register(const struct transport_def * def,struct transport ** pp)839  trans_register(const struct transport_def *def, struct transport **pp)
840  {
841  	u_int i;
842  	char or_descr[256];
843  
844  	if ((*pp = malloc(sizeof(**pp))) == NULL)
845  		return (SNMP_ERR_GENERR);
846  
847  	/* construct index */
848  	(*pp)->index.len = strlen(def->name) + 1;
849  	(*pp)->index.subs[0] = strlen(def->name);
850  	for (i = 0; i < (*pp)->index.subs[0]; i++)
851  		(*pp)->index.subs[i + 1] = def->name[i];
852  
853  	(*pp)->vtab = def;
854  
855  	if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) {
856  		free(*pp);
857  		return (SNMP_ERR_INCONS_VALUE);
858  	}
859  
860  	/* register module */
861  	snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name);
862  	if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) {
863  		free(*pp);
864  		return (SNMP_ERR_GENERR);
865  	}
866  
867  	INSERT_OBJECT_OID((*pp), &transport_list);
868  
869  	TAILQ_INIT(&(*pp)->table);
870  
871  	return (SNMP_ERR_NOERROR);
872  }
873  
874  /*
875   * Unregister transport
876   */
877  int
trans_unregister(struct transport * t)878  trans_unregister(struct transport *t)
879  {
880  	if (!TAILQ_EMPTY(&t->table))
881  		return (SNMP_ERR_INCONS_VALUE);
882  
883  	or_unregister(t->or_index);
884  	TAILQ_REMOVE(&transport_list, t, link);
885  
886  	return (SNMP_ERR_NOERROR);
887  }
888  
889  /*
890   * File descriptor support
891   */
892  #ifdef USE_LIBBEGEMOT
893  static void
input(int fd,int mask __unused,void * uap)894  input(int fd, int mask __unused, void *uap)
895  #else
896  static void
897  input(evContext ctx __unused, void *uap, int fd, int mask __unused)
898  #endif
899  {
900  	struct fdesc *f = uap;
901  
902  	(*f->func)(fd, f->udata);
903  }
904  
905  void
fd_suspend(void * p)906  fd_suspend(void *p)
907  {
908  	struct fdesc *f = p;
909  
910  #ifdef USE_LIBBEGEMOT
911  	if (f->id >= 0) {
912  		poll_unregister(f->id);
913  		f->id = -1;
914  	}
915  #else
916  	if (evTestID(f->id)) {
917  		(void)evDeselectFD(evctx, f->id);
918  		evInitID(&f->id);
919  	}
920  #endif
921  }
922  
923  int
fd_resume(void * p)924  fd_resume(void *p)
925  {
926  	struct fdesc *f = p;
927  	int err;
928  
929  #ifdef USE_LIBBEGEMOT
930  	if (f->id >= 0)
931  		return (0);
932  	if ((f->id = poll_register(f->fd, input, f, RPOLL_IN)) < 0) {
933  		err = errno;
934  		syslog(LOG_ERR, "select fd %d: %m", f->fd);
935  		errno = err;
936  		return (-1);
937  	}
938  #else
939  	if (evTestID(f->id))
940  		return (0);
941  	if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) {
942  		err = errno;
943  		syslog(LOG_ERR, "select fd %d: %m", f->fd);
944  		errno = err;
945  		return (-1);
946  	}
947  #endif
948  	return (0);
949  }
950  
951  void *
fd_select(int fd,void (* func)(int,void *),void * udata,struct lmodule * mod)952  fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod)
953  {
954  	struct fdesc *f;
955  	int err;
956  
957  	if ((f = malloc(sizeof(struct fdesc))) == NULL) {
958  		err = errno;
959  		syslog(LOG_ERR, "fd_select: %m");
960  		errno = err;
961  		return (NULL);
962  	}
963  	f->fd = fd;
964  	f->func = func;
965  	f->udata = udata;
966  	f->owner = mod;
967  #ifdef USE_LIBBEGEMOT
968  	f->id = -1;
969  #else
970  	evInitID(&f->id);
971  #endif
972  
973  	if (fd_resume(f)) {
974  		err = errno;
975  		free(f);
976  		errno = err;
977  		return (NULL);
978  	}
979  
980  	LIST_INSERT_HEAD(&fdesc_list, f, link);
981  
982  	return (f);
983  }
984  
985  void
fd_deselect(void * p)986  fd_deselect(void *p)
987  {
988  	struct fdesc *f = p;
989  
990  	LIST_REMOVE(f, link);
991  	fd_suspend(f);
992  	free(f);
993  }
994  
995  static void
fd_flush(struct lmodule * mod)996  fd_flush(struct lmodule *mod)
997  {
998  	struct fdesc *t, *t1;
999  
1000  	t = LIST_FIRST(&fdesc_list);
1001  	while (t != NULL) {
1002  		t1 = LIST_NEXT(t, link);
1003  		if (t->owner == mod)
1004  			fd_deselect(t);
1005  		t = t1;
1006  	}
1007  }
1008  
1009  /*
1010   * Consume a message from the input buffer
1011   */
1012  static void
snmp_input_consume(struct port_input * pi)1013  snmp_input_consume(struct port_input *pi)
1014  {
1015  	if (!pi->stream) {
1016  		/* always consume everything */
1017  		pi->length = 0;
1018  		return;
1019  	}
1020  	if (pi->consumed >= pi->length) {
1021  		/* all bytes consumed */
1022  		pi->length = 0;
1023  		return;
1024  	}
1025  	memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed);
1026  	pi->length -= pi->consumed;
1027  }
1028  
1029  /*
1030   * Input from a socket
1031   */
1032  int
snmpd_input(struct port_input * pi,struct tport * tport)1033  snmpd_input(struct port_input *pi, struct tport *tport)
1034  {
1035  	u_char *sndbuf;
1036  	size_t sndlen;
1037  	struct snmp_pdu pdu;
1038  	enum snmpd_input_err ierr, ferr;
1039  	enum snmpd_proxy_err perr;
1040  	ssize_t ret, slen;
1041  	int32_t vi;
1042  #ifdef USE_TCPWRAPPERS
1043  	char client[INET6_ADDRSTRLEN];
1044  #endif
1045  
1046  	ret = tport->transport->vtab->recv(tport, pi);
1047  	if (ret == -1)
1048  		return (-1);
1049  
1050  #ifdef USE_TCPWRAPPERS
1051  	/*
1052  	 * In case of AF_INET{6} peer, do hosts_access(5) check.
1053  	 */
1054  	if (pi->peer->sa_family != AF_LOCAL &&
1055  	    inet_ntop(pi->peer->sa_family,
1056  	    &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr,
1057  	    client, sizeof(client)) != NULL) {
1058  		request_set(&req, RQ_CLIENT_ADDR, client, 0);
1059  		if (hosts_access(&req) == 0) {
1060  			syslog(LOG_ERR, "refused connection from %.500s",
1061  			    eval_client(&req));
1062  			return (-1);
1063  		}
1064  	} else if (pi->peer->sa_family != AF_LOCAL)
1065  		syslog(LOG_ERR, "inet_ntop(): %m");
1066  #endif
1067  
1068  	/*
1069  	 * Handle input
1070  	 */
1071  	ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi,
1072  	    &pi->consumed);
1073  	if (ierr == SNMPD_INPUT_TRUNC) {
1074  		/* need more bytes. This is ok only for streaming transports.
1075  		 * but only if we have not reached bufsiz yet. */
1076  		if (pi->stream) {
1077  			if (pi->length == buf_size(0)) {
1078  				snmpd_stats.silentDrops++;
1079  				return (-1);
1080  			}
1081  			return (0);
1082  		}
1083  		snmpd_stats.silentDrops++;
1084  		return (-1);
1085  	}
1086  
1087  	/* can't check for bad SET pdus here, because a proxy may have to
1088  	 * check the access first. We don't want to return an error response
1089  	 * to a proxy PDU with a wrong community */
1090  	if (ierr == SNMPD_INPUT_FAILED) {
1091  		/* for streaming transports this is fatal */
1092  		if (pi->stream)
1093  			return (-1);
1094  		snmp_input_consume(pi);
1095  		return (0);
1096  	}
1097  	if (ierr == SNMPD_INPUT_BAD_COMM) {
1098  		snmp_input_consume(pi);
1099  		return (0);
1100  	}
1101  
1102  	/*
1103  	 * If that is a module community and the module has a proxy function,
1104  	 * the hand it over to the module.
1105  	 */
1106  	if (comm != NULL && comm->owner != NULL &&
1107  	    comm->owner->config->proxy != NULL) {
1108  		perr = (*comm->owner->config->proxy)(&pdu, tport->transport,
1109  		    &tport->index, pi->peer, pi->peerlen, ierr, vi,
1110  		    !pi->cred || pi->priv);
1111  
1112  		switch (perr) {
1113  
1114  		  case SNMPD_PROXY_OK:
1115  			snmp_input_consume(pi);
1116  			return (0);
1117  
1118  		  case SNMPD_PROXY_REJ:
1119  			break;
1120  
1121  		  case SNMPD_PROXY_DROP:
1122  			snmp_input_consume(pi);
1123  			snmp_pdu_free(&pdu);
1124  			snmpd_stats.proxyDrops++;
1125  			return (0);
1126  
1127  		  case SNMPD_PROXY_BADCOMM:
1128  			snmp_input_consume(pi);
1129  			snmp_pdu_free(&pdu);
1130  			snmpd_stats.inBadCommunityNames++;
1131  			if (snmpd.auth_traps)
1132  				snmp_send_trap(&oid_authenticationFailure,
1133  				    (struct snmp_value *)NULL);
1134  			return (0);
1135  
1136  		  case SNMPD_PROXY_BADCOMMUSE:
1137  			snmp_input_consume(pi);
1138  			snmp_pdu_free(&pdu);
1139  			snmpd_stats.inBadCommunityUses++;
1140  			if (snmpd.auth_traps)
1141  				snmp_send_trap(&oid_authenticationFailure,
1142  				    (struct snmp_value *)NULL);
1143  			return (0);
1144  		}
1145  	}
1146  
1147  	/*
1148  	 * Check type
1149  	 */
1150  	if (pdu.type == SNMP_PDU_RESPONSE ||
1151  	    pdu.type == SNMP_PDU_TRAP ||
1152  	    pdu.type == SNMP_PDU_TRAP2) {
1153  		snmpd_stats.silentDrops++;
1154  		snmpd_stats.inBadPduTypes++;
1155  		snmp_pdu_free(&pdu);
1156  		snmp_input_consume(pi);
1157  		return (0);
1158  	}
1159  
1160  	/*
1161  	 * Check community
1162  	 */
1163  	if (pdu.version < SNMP_V3 &&
1164  	    ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) ||
1165  	    (comm != NULL && comm->private != COMM_WRITE &&
1166              (pdu.type == SNMP_PDU_SET || comm->private != COMM_READ)))) {
1167  		snmpd_stats.inBadCommunityUses++;
1168  		snmp_pdu_free(&pdu);
1169  		snmp_input_consume(pi);
1170  		if (snmpd.auth_traps)
1171  			snmp_send_trap(&oid_authenticationFailure,
1172  			    (struct snmp_value *)NULL);
1173  		return (0);
1174  	}
1175  
1176  	/*
1177  	 * Execute it.
1178  	 */
1179  	if ((sndbuf = buf_alloc(1)) == NULL) {
1180  		snmpd_stats.silentDrops++;
1181  		snmp_pdu_free(&pdu);
1182  		snmp_input_consume(pi);
1183  		return (0);
1184  	}
1185  	ferr = snmp_input_finish(&pdu, pi->buf, pi->length,
1186  	    sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
1187  
1188  	if (ferr == SNMPD_INPUT_OK) {
1189  		if (tport->transport->vtab->send != NULL)
1190  			slen = tport->transport->vtab->send(tport, sndbuf,
1191  			    sndlen, pi->peer, pi->peerlen);
1192  		else
1193  			slen = tport->transport->vtab->send2(tport, sndbuf,
1194  			    sndlen, pi);
1195  		if (slen == -1)
1196  			syslog(LOG_ERR, "send*: %m");
1197  		else if ((size_t)slen != sndlen)
1198  			syslog(LOG_ERR, "send*: short write %zu/%zu", sndlen,
1199  			    (size_t)slen);
1200  	}
1201  
1202  	snmp_pdu_free(&pdu);
1203  	free(sndbuf);
1204  	snmp_input_consume(pi);
1205  
1206  	return (0);
1207  }
1208  
1209  /*
1210   * Send a PDU to a given port. If this is a multi-socket port, use the
1211   * first socket.
1212   */
1213  void
snmp_send_port(void * targ,const struct asn_oid * port,struct snmp_pdu * pdu,const struct sockaddr * addr,socklen_t addrlen)1214  snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
1215      const struct sockaddr *addr, socklen_t addrlen)
1216  {
1217  	struct transport *trans = targ;
1218  	struct tport *tp;
1219  	u_char *sndbuf;
1220  	size_t sndlen;
1221  	ssize_t len;
1222  
1223  	TAILQ_FOREACH(tp, &trans->table, link)
1224  		if (asn_compare_oid(port, &tp->index) == 0)
1225  			break;
1226  	if (tp == 0)
1227  		return;
1228  
1229  	if ((sndbuf = buf_alloc(1)) == NULL)
1230  		return;
1231  
1232  	snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
1233  
1234  	if (trans->vtab->send != NULL)
1235  		len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
1236  	else
1237  		len = trans->vtab->send2(tp, sndbuf, sndlen, NULL);
1238  
1239  	if (len == -1)
1240  		syslog(LOG_ERR, "sendto: %m");
1241  	else if ((size_t)len != sndlen)
1242  		syslog(LOG_ERR, "sendto: short write %zu/%zu",
1243  		    sndlen, (size_t)len);
1244  
1245  	free(sndbuf);
1246  }
1247  
1248  
1249  /*
1250   * Close an input source
1251   *
1252   * \param pi	input instance
1253   */
1254  void
snmpd_input_close(struct port_input * pi)1255  snmpd_input_close(struct port_input *pi)
1256  {
1257  	if (pi->id != NULL) {
1258  		fd_deselect(pi->id);
1259  		pi->id = NULL;
1260  	}
1261  	if (pi->fd >= 0) {
1262  		(void)close(pi->fd);
1263  		pi->fd = -1;
1264  	}
1265  	if (pi->buf != NULL) {
1266  		free(pi->buf);
1267  		pi->buf = NULL;
1268  	}
1269  }
1270  
1271  /*
1272   * Initialize an input source.
1273   *
1274   * \param pi	input instance
1275   */
1276  void
snmpd_input_init(struct port_input * pi)1277  snmpd_input_init(struct port_input *pi)
1278  {
1279  	pi->id = NULL;
1280  	pi->fd = -1;
1281  	pi->buf = NULL;
1282  }
1283  
1284  /*
1285   * Dump internal state.
1286   */
1287  #ifdef USE_LIBBEGEMOT
1288  static void
info_func(void)1289  info_func(void)
1290  #else
1291  static void
1292  info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused)
1293  #endif
1294  {
1295  	struct lmodule *m;
1296  	u_int i;
1297  	char buf[10000];
1298  
1299  	syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());
1300  	for (i = 0; i < tree_size; i++) {
1301  		switch (tree[i].type) {
1302  
1303  		  case SNMP_NODE_LEAF:
1304  			sprintf(buf, "LEAF: %s %s", tree[i].name,
1305  			    asn_oid2str(&tree[i].oid));
1306  			break;
1307  
1308  		  case SNMP_NODE_COLUMN:
1309  			sprintf(buf, "COL: %s %s", tree[i].name,
1310  			    asn_oid2str(&tree[i].oid));
1311  			break;
1312  		}
1313  		syslog(LOG_DEBUG, "%s", buf);
1314  	}
1315  
1316  	TAILQ_FOREACH(m, &lmodules, link)
1317  		if (m->config->dump)
1318  			(*m->config->dump)();
1319  }
1320  
1321  /*
1322   * Re-read configuration
1323   */
1324  #ifdef USE_LIBBEGEMOT
1325  static void
config_func(void)1326  config_func(void)
1327  #else
1328  static void
1329  config_func(evContext ctx __unused, void *uap __unused,
1330      const void *tag __unused)
1331  #endif
1332  {
1333  	struct lmodule *m;
1334  
1335  	if (read_config(config_file, NULL)) {
1336  		syslog(LOG_ERR, "error reading config file '%s'", config_file);
1337  		return;
1338  	}
1339  	TAILQ_FOREACH(m, &lmodules, link)
1340  		if (m->config->config)
1341  			(*m->config->config)();
1342  }
1343  
1344  /*
1345   * On USR1 dump actual configuration.
1346   */
1347  static void
onusr1(int s __unused)1348  onusr1(int s __unused)
1349  {
1350  
1351  	work |= WORK_DOINFO;
1352  }
1353  static void
onhup(int s __unused)1354  onhup(int s __unused)
1355  {
1356  
1357  	work |= WORK_RECONFIG;
1358  }
1359  
1360  static void
onterm(int s __unused)1361  onterm(int s __unused)
1362  {
1363  
1364  	/* allow clean-up */
1365  	exit(0);
1366  }
1367  
1368  static void
init_sigs(void)1369  init_sigs(void)
1370  {
1371  	struct sigaction sa;
1372  
1373  	sa.sa_handler = onusr1;
1374  	sa.sa_flags = SA_RESTART;
1375  	sigemptyset(&sa.sa_mask);
1376  	if (sigaction(SIGUSR1, &sa, NULL)) {
1377  		syslog(LOG_ERR, "sigaction: %m");
1378  		exit(1);
1379  	}
1380  
1381  	sa.sa_handler = onhup;
1382  	if (sigaction(SIGHUP, &sa, NULL)) {
1383  		syslog(LOG_ERR, "sigaction: %m");
1384  		exit(1);
1385  	}
1386  
1387  	sa.sa_handler = onterm;
1388  	sa.sa_flags = 0;
1389  	sigemptyset(&sa.sa_mask);
1390  	if (sigaction(SIGTERM, &sa, NULL)) {
1391  		syslog(LOG_ERR, "sigaction: %m");
1392  		exit(1);
1393  	}
1394  	if (sigaction(SIGINT, &sa, NULL)) {
1395  		syslog(LOG_ERR, "sigaction: %m");
1396  		exit(1);
1397  	}
1398  }
1399  
1400  static void
block_sigs(void)1401  block_sigs(void)
1402  {
1403  	sigset_t set;
1404  
1405  	sigfillset(&set);
1406  	if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) {
1407  		syslog(LOG_ERR, "SIG_BLOCK: %m");
1408  		exit(1);
1409  	}
1410  }
1411  static void
unblock_sigs(void)1412  unblock_sigs(void)
1413  {
1414  	if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) {
1415  		syslog(LOG_ERR, "SIG_SETMASK: %m");
1416  		exit(1);
1417  	}
1418  }
1419  
1420  /*
1421   * Shut down
1422   */
1423  static void
term(void)1424  term(void)
1425  {
1426  	(void)unlink(pid_file);
1427  }
1428  
1429  static void
trans_stop(void)1430  trans_stop(void)
1431  {
1432  	struct transport *t;
1433  
1434  	TAILQ_FOREACH(t, &transport_list, link)
1435  		(void)t->vtab->stop(1);
1436  }
1437  
1438  /*
1439   * Define a macro from the command line
1440   */
1441  static void
do_macro(char * arg)1442  do_macro(char *arg)
1443  {
1444  	char *eq;
1445  	int err;
1446  
1447  	if ((eq = strchr(arg, '=')) == NULL)
1448  		err = define_macro(arg, "");
1449  	else {
1450  		*eq++ = '\0';
1451  		err = define_macro(arg, eq);
1452  	}
1453  	if (err == -1) {
1454  		syslog(LOG_ERR, "cannot save macro: %m");
1455  		exit(1);
1456  	}
1457  }
1458  
1459  /*
1460   * Re-implement getsubopt from scratch, because the second argument is broken
1461   * and will not compile with WARNS=5.
1462   */
1463  static int
getsubopt1(char ** arg,const char * const * options,char ** valp,char ** optp)1464  getsubopt1(char **arg, const char *const *options, char **valp, char **optp)
1465  {
1466  	static const char *const delim = ",\t ";
1467  	u_int i;
1468  	char *ptr;
1469  
1470  	*optp = NULL;
1471  
1472  	/* skip leading junk */
1473  	for (ptr = *arg; *ptr != '\0'; ptr++)
1474  		if (strchr(delim, *ptr) == NULL)
1475  			break;
1476  	if (*ptr == '\0') {
1477  		*arg = ptr;
1478  		return (-1);
1479  	}
1480  	*optp = ptr;
1481  
1482  	/* find the end of the option */
1483  	while (*++ptr != '\0')
1484  		if (strchr(delim, *ptr) != NULL || *ptr == '=')
1485  			break;
1486  
1487  	if (*ptr != '\0') {
1488  		if (*ptr == '=') {
1489  			*ptr++ = '\0';
1490  			*valp = ptr;
1491  			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
1492  				ptr++;
1493  			if (*ptr != '\0')
1494  				*ptr++ = '\0';
1495  		} else
1496  			*ptr++ = '\0';
1497  	}
1498  
1499  	*arg = ptr;
1500  
1501  	for (i = 0; *options != NULL; options++, i++)
1502  		if (strcmp(*optp, *options) == 0)
1503  			return (i);
1504  	return (-1);
1505  }
1506  
1507  int
main(int argc,char * argv[])1508  main(int argc, char *argv[])
1509  {
1510  	int opt;
1511  	FILE *fp;
1512  	int background = 1;
1513  	struct tport *p;
1514  	const char *prefix = "snmpd";
1515  	struct lmodule *m;
1516  	char *value = NULL, *option; /* XXX */
1517  	struct transport *t;
1518  
1519  #define DBG_DUMP	0
1520  #define DBG_EVENTS	1
1521  #define DBG_TRACE	2
1522  	static const char *const debug_opts[] = {
1523  		"dump",
1524  		"events",
1525  		"trace",
1526  		NULL
1527  	};
1528  
1529  	snmp_printf = snmp_printf_func;
1530  	snmp_error = snmp_error_func;
1531  	snmp_debug = snmp_debug_func;
1532  	asn_error = asn_error_func;
1533  
1534  	while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF)
1535  		switch (opt) {
1536  
1537  		  case 'c':
1538  			strlcpy(config_file, optarg, sizeof(config_file));
1539  			break;
1540  
1541  		  case 'd':
1542  			background = 0;
1543  			break;
1544  
1545  		  case 'D':
1546  			while (*optarg) {
1547  				switch (getsubopt1(&optarg, debug_opts,
1548  				    &value, &option)) {
1549  
1550  				  case DBG_DUMP:
1551  					debug.dump_pdus = 1;
1552  					break;
1553  
1554  				  case DBG_EVENTS:
1555  					debug.evdebug++;
1556  					break;
1557  
1558  				  case DBG_TRACE:
1559  					if (value == NULL)
1560  						syslog(LOG_ERR,
1561  						    "no value for 'trace'");
1562  					else
1563  						snmp_trace = strtoul(value,
1564  						    NULL, 0);
1565  					break;
1566  
1567  				  case -1:
1568  					if (suboptarg)
1569  						syslog(LOG_ERR,
1570  						    "unknown debug flag '%s'",
1571  						    option);
1572  					else
1573  						syslog(LOG_ERR,
1574  						    "missing debug flag");
1575  					break;
1576  				}
1577  			}
1578  			break;
1579  
1580  		  case 'e':
1581  			strlcpy(engine_file, optarg, sizeof(engine_file));
1582  			break;
1583  		  case 'h':
1584  			fprintf(stderr, "%s", usgtxt);
1585  			exit(0);
1586  
1587  		  case 'I':
1588  			syspath = optarg;
1589  			break;
1590  
1591  		  case 'l':
1592  			prefix = optarg;
1593  			break;
1594  
1595  		  case 'm':
1596  			do_macro(optarg);
1597  			break;
1598  
1599  		  case 'p':
1600  			strlcpy(pid_file, optarg, sizeof(pid_file));
1601  			break;
1602  		}
1603  
1604  	openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
1605  	setlogmask(LOG_UPTO(debug.logpri - 1));
1606  
1607  	if (background && daemon(0, 0) < 0) {
1608  		syslog(LOG_ERR, "daemon: %m");
1609  		exit(1);
1610  	}
1611  
1612  	argc -= optind;
1613  	argv += optind;
1614  
1615  	progargs = argv;
1616  	nprogargs = argc;
1617  
1618  	snmp_serial_no = arc4random();
1619  
1620  #ifdef USE_TCPWRAPPERS
1621  	/*
1622  	 * Initialize hosts_access(3) handler.
1623  	 */
1624  	request_init(&req, RQ_DAEMON, "snmpd", 0);
1625  	sock_methods(&req);
1626  #endif
1627  
1628  	/*
1629  	 * Initialize the tree.
1630  	 */
1631  	if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) {
1632  		syslog(LOG_ERR, "%m");
1633  		exit(1);
1634  	}
1635  	memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE);
1636  	tree_size = CTREE_SIZE;
1637  
1638  	/*
1639  	 * Get standard communities
1640  	 */
1641  	comm_define(COMM_READ, "SNMP read", NULL, NULL);
1642  	comm_define(COMM_WRITE, "SNMP write", NULL, NULL);
1643  	community = COMM_INITIALIZE;
1644  
1645  	trap_reqid = reqid_allocate(512, NULL);
1646  
1647  	if (config_file[0] == '\0')
1648  		snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix);
1649  
1650  	init_actvals();
1651  	init_snmpd_engine();
1652  
1653  	this_tick = get_ticks();
1654  	start_tick = this_tick;
1655  
1656  	/* start transports */
1657  	if (atexit(trans_stop) == -1) {
1658  		syslog(LOG_ERR, "atexit failed: %m");
1659  		exit(1);
1660  	}
1661  	if (udp_trans.start() != SNMP_ERR_NOERROR)
1662  		syslog(LOG_WARNING, "cannot start UDP transport");
1663  	if (lsock_trans.start() != SNMP_ERR_NOERROR)
1664  		syslog(LOG_WARNING, "cannot start LSOCK transport");
1665  	if (inet_trans.start() != SNMP_ERR_NOERROR)
1666  		syslog(LOG_WARNING, "cannot start INET transport");
1667  
1668  #ifdef USE_LIBBEGEMOT
1669  	if (debug.evdebug > 0)
1670  		rpoll_trace = 1;
1671  #else
1672  	if (evCreate(&evctx)) {
1673  		syslog(LOG_ERR, "evCreate: %m");
1674  		exit(1);
1675  	}
1676  	if (debug.evdebug > 0)
1677  		evSetDebug(evctx, 10, stderr);
1678  #endif
1679  
1680  	if (engine_file[0] == '\0')
1681  		snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix);
1682  
1683  	if (read_config(config_file, NULL)) {
1684  		syslog(LOG_ERR, "error in config file");
1685  		exit(1);
1686  	}
1687  
1688  	TAILQ_FOREACH(t, &transport_list, link)
1689  		TAILQ_FOREACH(p, &t->table, link)
1690  			t->vtab->init_port(p);
1691  
1692  	init_sigs();
1693  
1694  	if (pid_file[0] == '\0')
1695  		snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix);
1696  
1697  	if ((fp = fopen(pid_file, "w")) != NULL) {
1698  		fprintf(fp, "%u", getpid());
1699  		fclose(fp);
1700  		if (atexit(term) == -1) {
1701  			syslog(LOG_ERR, "atexit failed: %m");
1702  			(void)remove(pid_file);
1703  			exit(0);
1704  		}
1705  	}
1706  
1707  	if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.",
1708  	    NULL) == 0) {
1709  		syslog(LOG_ERR, "cannot register SNMPv2 MIB");
1710  		exit(1);
1711  	}
1712  	if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.",
1713  	    NULL) == 0) {
1714  		syslog(LOG_ERR, "cannot register begemotSnmpd MIB");
1715  		exit(1);
1716  	}
1717  
1718  	while ((m = TAILQ_FIRST(&modules_start)) != NULL) {
1719  		m->flags &= ~LM_ONSTARTLIST;
1720  		TAILQ_REMOVE(&modules_start, m, start);
1721  		lm_start(m);
1722  	}
1723  
1724  	snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL);
1725  
1726  	for (;;) {
1727  #ifndef USE_LIBBEGEMOT
1728  		evEvent event;
1729  #endif
1730  		struct lmodule *mod;
1731  
1732  		TAILQ_FOREACH(mod, &lmodules, link)
1733  			if (mod->config->idle != NULL)
1734  				(*mod->config->idle)();
1735  
1736  #ifndef USE_LIBBEGEMOT
1737  		if (evGetNext(evctx, &event, EV_WAIT) == 0) {
1738  			if (evDispatch(evctx, event))
1739  				syslog(LOG_ERR, "evDispatch: %m");
1740  		} else if (errno != EINTR) {
1741  			syslog(LOG_ERR, "evGetNext: %m");
1742  			exit(1);
1743  		}
1744  #else
1745  		poll_dispatch(1);
1746  #endif
1747  
1748  		if (work != 0) {
1749  			block_sigs();
1750  			if (work & WORK_DOINFO) {
1751  #ifdef USE_LIBBEGEMOT
1752  				info_func();
1753  #else
1754  				if (evWaitFor(evctx, &work, info_func,
1755  				    NULL, NULL) == -1) {
1756  					syslog(LOG_ERR, "evWaitFor: %m");
1757  					exit(1);
1758  				}
1759  #endif
1760  			}
1761  			if (work & WORK_RECONFIG) {
1762  #ifdef USE_LIBBEGEMOT
1763  				config_func();
1764  #else
1765  				if (evWaitFor(evctx, &work, config_func,
1766  				    NULL, NULL) == -1) {
1767  					syslog(LOG_ERR, "evWaitFor: %m");
1768  					exit(1);
1769  				}
1770  #endif
1771  			}
1772  			work = 0;
1773  			unblock_sigs();
1774  #ifndef USE_LIBBEGEMOT
1775  			if (evDo(evctx, &work) == -1) {
1776  				syslog(LOG_ERR, "evDo: %m");
1777  				exit(1);
1778  			}
1779  #endif
1780  		}
1781  	}
1782  
1783  	return (0);
1784  }
1785  
1786  uint64_t
get_ticks(void)1787  get_ticks(void)
1788  {
1789  	struct timeval tv;
1790  	uint64_t ret;
1791  
1792  	if (gettimeofday(&tv, NULL))
1793  		abort();
1794  	ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL;
1795  	return (ret);
1796  }
1797  
1798  /*
1799   * Timer support
1800   */
1801  
1802  /*
1803   * Trampoline for the non-repeatable timers.
1804   */
1805  #ifdef USE_LIBBEGEMOT
1806  static void
tfunc(int tid __unused,void * uap)1807  tfunc(int tid __unused, void *uap)
1808  #else
1809  static void
1810  tfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1811  	struct timespec inter __unused)
1812  #endif
1813  {
1814  	struct timer *tp = uap;
1815  
1816  	LIST_REMOVE(tp, link);
1817  	tp->func(tp->udata);
1818  	free(tp);
1819  }
1820  
1821  /*
1822   * Trampoline for the repeatable timers.
1823   */
1824  #ifdef USE_LIBBEGEMOT
1825  static void
trfunc(int tid __unused,void * uap)1826  trfunc(int tid __unused, void *uap)
1827  #else
1828  static void
1829  trfunc(evContext ctx __unused, void *uap, struct timespec due __unused,
1830  	struct timespec inter __unused)
1831  #endif
1832  {
1833  	struct timer *tp = uap;
1834  
1835  	tp->func(tp->udata);
1836  }
1837  
1838  /*
1839   * Start a one-shot timer
1840   */
1841  void *
timer_start(u_int ticks,void (* func)(void *),void * udata,struct lmodule * mod)1842  timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod)
1843  {
1844  	struct timer *tp;
1845  #ifndef USE_LIBBEGEMOT
1846  	struct timespec due;
1847  #endif
1848  
1849  	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1850  		syslog(LOG_CRIT, "out of memory for timer");
1851  		exit(1);
1852  	}
1853  
1854  #ifndef USE_LIBBEGEMOT
1855  	due = evAddTime(evNowTime(),
1856  	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1857  #endif
1858  
1859  	tp->udata = udata;
1860  	tp->owner = mod;
1861  	tp->func = func;
1862  
1863  	LIST_INSERT_HEAD(&timer_list, tp, link);
1864  
1865  #ifdef USE_LIBBEGEMOT
1866  	if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) {
1867  		syslog(LOG_ERR, "cannot set timer: %m");
1868  		exit(1);
1869  	}
1870  #else
1871  	if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id)
1872  	    == -1) {
1873  		syslog(LOG_ERR, "cannot set timer: %m");
1874  		exit(1);
1875  	}
1876  #endif
1877  	return (tp);
1878  }
1879  
1880  /*
1881   * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument
1882   * is currently ignored and the initial number of ticks is set to the
1883   * repeat number of ticks.
1884   */
1885  void *
timer_start_repeat(u_int ticks __unused,u_int repeat_ticks,void (* func)(void *),void * udata,struct lmodule * mod)1886  timer_start_repeat(u_int ticks __unused, u_int repeat_ticks,
1887      void (*func)(void *), void *udata, struct lmodule *mod)
1888  {
1889  	struct timer *tp;
1890  #ifndef USE_LIBBEGEMOT
1891  	struct timespec due;
1892  	struct timespec inter;
1893  #endif
1894  
1895  	if ((tp = malloc(sizeof(struct timer))) == NULL) {
1896  		syslog(LOG_CRIT, "out of memory for timer");
1897  		exit(1);
1898  	}
1899  
1900  #ifndef USE_LIBBEGEMOT
1901  	due = evAddTime(evNowTime(),
1902  	    evConsTime(ticks / 100, (ticks % 100) * 10000));
1903  	inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000);
1904  #endif
1905  
1906  	tp->udata = udata;
1907  	tp->owner = mod;
1908  	tp->func = func;
1909  
1910  	LIST_INSERT_HEAD(&timer_list, tp, link);
1911  
1912  #ifdef USE_LIBBEGEMOT
1913  	if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) {
1914  		syslog(LOG_ERR, "cannot set timer: %m");
1915  		exit(1);
1916  	}
1917  #else
1918  	if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) {
1919  		syslog(LOG_ERR, "cannot set timer: %m");
1920  		exit(1);
1921  	}
1922  #endif
1923  	return (tp);
1924  }
1925  
1926  /*
1927   * Stop a timer.
1928   */
1929  void
timer_stop(void * p)1930  timer_stop(void *p)
1931  {
1932  	struct timer *tp = p;
1933  
1934  	LIST_REMOVE(tp, link);
1935  #ifdef USE_LIBBEGEMOT
1936  	poll_stop_timer(tp->id);
1937  #else
1938  	if (evClearTimer(evctx, tp->id) == -1) {
1939  		syslog(LOG_ERR, "cannot stop timer: %m");
1940  		exit(1);
1941  	}
1942  #endif
1943  	free(p);
1944  }
1945  
1946  static void
timer_flush(struct lmodule * mod)1947  timer_flush(struct lmodule *mod)
1948  {
1949  	struct timer *t, *t1;
1950  
1951  	t = LIST_FIRST(&timer_list);
1952  	while (t != NULL) {
1953  		t1 = LIST_NEXT(t, link);
1954  		if (t->owner == mod)
1955  			timer_stop(t);
1956  		t = t1;
1957  	}
1958  }
1959  
1960  static void
snmp_printf_func(const char * fmt,...)1961  snmp_printf_func(const char *fmt, ...)
1962  {
1963  	va_list ap;
1964  	static char *pend = NULL;
1965  	char *ret, *new;
1966  
1967  	va_start(ap, fmt);
1968  	vasprintf(&ret, fmt, ap);
1969  	va_end(ap);
1970  
1971  	if (ret == NULL)
1972  		return;
1973  	if (pend != NULL) {
1974  		if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1))
1975  		    == NULL) {
1976  			free(ret);
1977  			return;
1978  		}
1979  		pend = new;
1980  		strcat(pend, ret);
1981  		free(ret);
1982  	} else
1983  		pend = ret;
1984  
1985  	while ((ret = strchr(pend, '\n')) != NULL) {
1986  		*ret = '\0';
1987  		syslog(LOG_DEBUG, "%s", pend);
1988  		if (strlen(ret + 1) == 0) {
1989  			free(pend);
1990  			pend = NULL;
1991  			break;
1992  		}
1993  		strcpy(pend, ret + 1);
1994  	}
1995  }
1996  
1997  static void
snmp_error_func(const char * err,...)1998  snmp_error_func(const char *err, ...)
1999  {
2000  	char errbuf[1000];
2001  	va_list ap;
2002  
2003  	if (!(snmp_trace & LOG_SNMP_ERRORS))
2004  		return;
2005  
2006  	va_start(ap, err);
2007  	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
2008  	vsnprintf(errbuf + strlen(errbuf),
2009  	    sizeof(errbuf) - strlen(errbuf), err, ap);
2010  	va_end(ap);
2011  
2012  	syslog(LOG_ERR, "%s", errbuf);
2013  }
2014  
2015  static void
snmp_debug_func(const char * err,...)2016  snmp_debug_func(const char *err, ...)
2017  {
2018  	char errbuf[1000];
2019  	va_list ap;
2020  
2021  	va_start(ap, err);
2022  	snprintf(errbuf, sizeof(errbuf), "SNMP: ");
2023  	vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf),
2024  	    err, ap);
2025  	va_end(ap);
2026  
2027  	syslog(LOG_DEBUG, "%s", errbuf);
2028  }
2029  
2030  static void
asn_error_func(const struct asn_buf * b,const char * err,...)2031  asn_error_func(const struct asn_buf *b, const char *err, ...)
2032  {
2033  	char errbuf[1000];
2034  	va_list ap;
2035  	u_int i;
2036  
2037  	if (!(snmp_trace & LOG_ASN1_ERRORS))
2038  		return;
2039  
2040  	va_start(ap, err);
2041  	snprintf(errbuf, sizeof(errbuf), "ASN.1: ");
2042  	vsnprintf(errbuf + strlen(errbuf),
2043  	    sizeof(errbuf) - strlen(errbuf), err, ap);
2044  	va_end(ap);
2045  
2046  	if (b != NULL) {
2047  		snprintf(errbuf + strlen(errbuf),
2048  		    sizeof(errbuf) - strlen(errbuf), " at");
2049  		for (i = 0; b->asn_len > i; i++)
2050  			snprintf(errbuf + strlen(errbuf),
2051  			    sizeof(errbuf) - strlen(errbuf),
2052  			    " %02x", b->asn_cptr[i]);
2053  	}
2054  
2055  	syslog(LOG_ERR, "%s", errbuf);
2056  }
2057  
2058  /*
2059   * Create a new community
2060   */
2061  struct community*
comm_define_ordered(u_int priv,const char * descr,struct asn_oid * idx,struct lmodule * owner,const char * str)2062  comm_define_ordered(u_int priv, const char *descr, struct asn_oid *idx,
2063      struct lmodule *owner, const char *str)
2064  {
2065  	struct community *c, *p;
2066  	u_int ncomm;
2067  
2068  	ncomm = idx->subs[idx->len - 1];
2069  
2070  	/* check that community doesn't already exist */
2071  	TAILQ_FOREACH(c, &community_list, link)
2072  		if (c->value == ncomm)
2073  			return (c);
2074  
2075  	if ((c = malloc(sizeof(struct community))) == NULL) {
2076  		syslog(LOG_ERR, "%s: %m", __func__);
2077  		return (NULL);
2078  	}
2079  	c->owner = owner;
2080  	c->value = ncomm;
2081  	c->descr = descr;
2082  	c->string = NULL;
2083  	c->private = priv;
2084  
2085  	if (str != NULL) {
2086  		if((c->string = malloc(strlen(str)+1)) == NULL) {
2087  			free(c);
2088  			return (NULL);
2089  		}
2090  		strcpy(c->string, str);
2091  	}
2092  	/*
2093  	 * Insert ordered
2094  	 */
2095  	c->index = *idx;
2096  	TAILQ_FOREACH(p, &community_list, link) {
2097  		if (asn_compare_oid(&p->index, &c->index) > 0) {
2098  			TAILQ_INSERT_BEFORE(p, c, link);
2099  			break;
2100  		}
2101  	}
2102  	if (p == NULL)
2103  		TAILQ_INSERT_TAIL(&community_list, c, link);
2104  	return (c);
2105  }
2106  
2107  u_int
comm_define(u_int priv,const char * descr,struct lmodule * owner,const char * str)2108  comm_define(u_int priv, const char *descr, struct lmodule *owner,
2109      const char *str)
2110  {
2111  	struct asn_oid idx, *p;
2112  	struct community *c;
2113  	u_int ncomm;
2114  
2115  	/* generate an identifier */
2116  	do {
2117  		if ((ncomm = next_community_index++) == UINT_MAX)
2118  			next_community_index = 1;
2119  		TAILQ_FOREACH(c, &community_list, link)
2120  			if (c->value == ncomm)
2121  				break;
2122  	} while (c != NULL);
2123  
2124  	/* make index */
2125  	if (owner != NULL)
2126  		p = &owner->index;
2127  	else {
2128  		p = &idx;
2129  		p->len = 1;
2130  		p->subs[0] = 0;
2131  	}
2132  	p->subs[p->len++] = ncomm;
2133  	c = comm_define_ordered(priv, descr, p, owner, str);
2134  	if (c == NULL)
2135  		return (0);
2136  	return (c->value);
2137  }
2138  
2139  const char *
comm_string(u_int ncomm)2140  comm_string(u_int ncomm)
2141  {
2142  	struct community *p;
2143  
2144  	TAILQ_FOREACH(p, &community_list, link)
2145  		if (p->value == ncomm)
2146  			return (p->string);
2147  	return (NULL);
2148  }
2149  
2150  /*
2151   * Delete all communities allocated by a module
2152   */
2153  static void
comm_flush(struct lmodule * mod)2154  comm_flush(struct lmodule *mod)
2155  {
2156  	struct community *p, *p1;
2157  
2158  	p = TAILQ_FIRST(&community_list);
2159  	while (p != NULL) {
2160  		p1 = TAILQ_NEXT(p, link);
2161  		if (p->owner == mod) {
2162  			free(p->string);
2163  			TAILQ_REMOVE(&community_list, p, link);
2164  			free(p);
2165  		}
2166  		p = p1;
2167  	}
2168  }
2169  
2170  /*
2171   * Request ID handling.
2172   *
2173   * Allocate a new range of request ids. Use a first fit algorithm.
2174   */
2175  u_int
reqid_allocate(int size,struct lmodule * mod)2176  reqid_allocate(int size, struct lmodule *mod)
2177  {
2178  	u_int type;
2179  	struct idrange *r, *r1;
2180  
2181  	if (size <= 0 || size > INT32_MAX) {
2182  		syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size);
2183  		return (0);
2184  	}
2185  	/* allocate a type id */
2186  	do {
2187  		if ((type = next_idrange++) == UINT_MAX)
2188  			next_idrange = 1;
2189  		TAILQ_FOREACH(r, &idrange_list, link)
2190  			if (r->type == type)
2191  				break;
2192  	} while(r != NULL);
2193  
2194  	/* find a range */
2195  	if (TAILQ_EMPTY(&idrange_list))
2196  		r = NULL;
2197  	else {
2198  		r = TAILQ_FIRST(&idrange_list);
2199  		if (r->base < size) {
2200  			while((r1 = TAILQ_NEXT(r, link)) != NULL) {
2201  				if (r1->base - (r->base + r->size) >= size)
2202  					break;
2203  				r = r1;
2204  			}
2205  			r = r1;
2206  		}
2207  		if (r == NULL) {
2208  			r1 = TAILQ_LAST(&idrange_list, idrange_list);
2209  			if (INT32_MAX - size + 1 < r1->base + r1->size) {
2210  				syslog(LOG_ERR, "out of id ranges (%u)", size);
2211  				return (0);
2212  			}
2213  		}
2214  	}
2215  
2216  	/* allocate structure */
2217  	if ((r1 = malloc(sizeof(struct idrange))) == NULL) {
2218  		syslog(LOG_ERR, "%s: %m", __FUNCTION__);
2219  		return (0);
2220  	}
2221  
2222  	r1->type = type;
2223  	r1->size = size;
2224  	r1->owner = mod;
2225  	if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) {
2226  		r1->base = 0;
2227  		TAILQ_INSERT_HEAD(&idrange_list, r1, link);
2228  	} else if (r == NULL) {
2229  		r = TAILQ_LAST(&idrange_list, idrange_list);
2230  		r1->base = r->base + r->size;
2231  		TAILQ_INSERT_TAIL(&idrange_list, r1, link);
2232  	} else {
2233  		r = TAILQ_PREV(r, idrange_list, link);
2234  		r1->base = r->base + r->size;
2235  		TAILQ_INSERT_AFTER(&idrange_list, r, r1, link);
2236  	}
2237  	r1->next = r1->base;
2238  
2239  	return (type);
2240  }
2241  
2242  int32_t
reqid_next(u_int type)2243  reqid_next(u_int type)
2244  {
2245  	struct idrange *r;
2246  	int32_t id;
2247  
2248  	TAILQ_FOREACH(r, &idrange_list, link)
2249  		if (r->type == type)
2250  			break;
2251  	if (r == NULL) {
2252  		syslog(LOG_CRIT, "wrong idrange type");
2253  		abort();
2254  	}
2255  	if ((id = r->next++) == r->base + (r->size - 1))
2256  		r->next = r->base;
2257  	return (id);
2258  }
2259  
2260  int32_t
reqid_base(u_int type)2261  reqid_base(u_int type)
2262  {
2263  	struct idrange *r;
2264  
2265  	TAILQ_FOREACH(r, &idrange_list, link)
2266  		if (r->type == type)
2267  			return (r->base);
2268  	syslog(LOG_CRIT, "wrong idrange type");
2269  	abort();
2270  }
2271  
2272  u_int
reqid_type(int32_t reqid)2273  reqid_type(int32_t reqid)
2274  {
2275  	struct idrange *r;
2276  
2277  	TAILQ_FOREACH(r, &idrange_list, link)
2278  		if (reqid >= r->base && reqid <= r->base + (r->size - 1))
2279  			return (r->type);
2280  	return (0);
2281  }
2282  
2283  int
reqid_istype(int32_t reqid,u_int type)2284  reqid_istype(int32_t reqid, u_int type)
2285  {
2286  	return (reqid_type(reqid) == type);
2287  }
2288  
2289  /*
2290   * Delete all communities allocated by a module
2291   */
2292  static void
reqid_flush(struct lmodule * mod)2293  reqid_flush(struct lmodule *mod)
2294  {
2295  	struct idrange *p, *p1;
2296  
2297  	p = TAILQ_FIRST(&idrange_list);
2298  	while (p != NULL) {
2299  		p1 = TAILQ_NEXT(p, link);
2300  		if (p->owner == mod) {
2301  			TAILQ_REMOVE(&idrange_list, p, link);
2302  			free(p);
2303  		}
2304  		p = p1;
2305  	}
2306  }
2307  
2308  /*
2309   * Merge the given tree for the given module into the main tree.
2310   */
2311  static int
compare_node(const void * v1,const void * v2)2312  compare_node(const void *v1, const void *v2)
2313  {
2314  	const struct snmp_node *n1 = v1;
2315  	const struct snmp_node *n2 = v2;
2316  
2317  	return (asn_compare_oid(&n1->oid, &n2->oid));
2318  }
2319  static int
tree_merge(const struct snmp_node * ntree,u_int nsize,struct lmodule * mod)2320  tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod)
2321  {
2322  	struct snmp_node *xtree;
2323  	u_int i;
2324  
2325  	xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize));
2326  	if (xtree == NULL) {
2327  		syslog(LOG_ERR, "tree_merge: %m");
2328  		return (-1);
2329  	}
2330  	tree = xtree;
2331  	memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize);
2332  
2333  	for (i = 0; i < nsize; i++)
2334  		tree[tree_size + i].tree_data = mod;
2335  
2336  	tree_size += nsize;
2337  
2338  	qsort(tree, tree_size, sizeof(tree[0]), compare_node);
2339  
2340  	return (0);
2341  }
2342  
2343  /*
2344   * Remove all nodes belonging to the loadable module
2345   */
2346  static void
tree_unmerge(struct lmodule * mod)2347  tree_unmerge(struct lmodule *mod)
2348  {
2349  	u_int s, d;
2350  
2351  	for(s = d = 0; s < tree_size; s++)
2352  		if (tree[s].tree_data != mod) {
2353  			if (s != d)
2354  				tree[d] = tree[s];
2355  			d++;
2356  		}
2357  	tree_size = d;
2358  }
2359  
2360  /*
2361   * Loadable modules
2362   */
2363  struct lmodule *
lm_load(const char * path,const char * section)2364  lm_load(const char *path, const char *section)
2365  {
2366  	struct lmodule *m;
2367  	int err;
2368  	int i;
2369  	char *av[MAX_MOD_ARGS + 1];
2370  	int ac;
2371  	u_int u;
2372  
2373  	if ((m = malloc(sizeof(*m))) == NULL) {
2374  		syslog(LOG_ERR, "lm_load: %m");
2375  		return (NULL);
2376  	}
2377  	m->handle = NULL;
2378  	m->flags = 0;
2379  	strlcpy(m->section, section, sizeof(m->section));
2380  
2381  	if ((m->path = strdup(path)) == NULL) {
2382  		syslog(LOG_ERR, "lm_load: %m");
2383  		goto err;
2384  	}
2385  
2386  	/*
2387  	 * Make index
2388  	 */
2389  	m->index.subs[0] = strlen(section);
2390  	m->index.len = m->index.subs[0] + 1;
2391  	for (u = 0; u < m->index.subs[0]; u++)
2392  		m->index.subs[u + 1] = section[u];
2393  
2394  	/*
2395  	 * Load the object file and locate the config structure
2396  	 */
2397  	if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) {
2398  		syslog(LOG_ERR, "lm_load: open %s", dlerror());
2399  		goto err;
2400  	}
2401  
2402  	if ((m->config = dlsym(m->handle, "config")) == NULL) {
2403  		syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror());
2404  		goto err;
2405  	}
2406  
2407  	/*
2408  	 * Insert it into the right place
2409  	 */
2410  	INSERT_OBJECT_OID(m, &lmodules);
2411  
2412  	/* preserve order */
2413  	if (community == COMM_INITIALIZE) {
2414  		m->flags |= LM_ONSTARTLIST;
2415  		TAILQ_INSERT_TAIL(&modules_start, m, start);
2416  	}
2417  
2418  	/*
2419  	 * make the argument vector.
2420  	 */
2421  	ac = 0;
2422  	for (i = 0; i < nprogargs; i++) {
2423  		if (strlen(progargs[i]) >= strlen(section) + 1 &&
2424  		    strncmp(progargs[i], section, strlen(section)) == 0 &&
2425  		    progargs[i][strlen(section)] == ':') {
2426  			if (ac == MAX_MOD_ARGS) {
2427  				syslog(LOG_WARNING, "too many arguments for "
2428  				    "module '%s", section);
2429  				break;
2430  			}
2431  			av[ac++] = &progargs[i][strlen(section)+1];
2432  		}
2433  	}
2434  	av[ac] = NULL;
2435  
2436  	/*
2437  	 * Run the initialization function
2438  	 */
2439  	if ((err = (*m->config->init)(m, ac, av)) != 0) {
2440  		syslog(LOG_ERR, "lm_load: init failed: %d", err);
2441  		TAILQ_REMOVE(&lmodules, m, link);
2442  		goto err;
2443  	}
2444  
2445  	return (m);
2446  
2447    err:
2448  	if ((m->flags & LM_ONSTARTLIST) != 0)
2449  		TAILQ_REMOVE(&modules_start, m, start);
2450  	if (m->handle)
2451  		dlclose(m->handle);
2452  	free(m->path);
2453  	free(m);
2454  	return (NULL);
2455  }
2456  
2457  /*
2458   * Start a module
2459   */
2460  void
lm_start(struct lmodule * mod)2461  lm_start(struct lmodule *mod)
2462  {
2463  	const struct lmodule *m;
2464  
2465  	/*
2466  	 * Merge tree. If this fails, unload the module.
2467  	 */
2468  	if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) {
2469  		lm_unload(mod);
2470  		return;
2471  	}
2472  
2473  	/*
2474  	 * Read configuration
2475  	 */
2476  	if (read_config(config_file, mod)) {
2477  		syslog(LOG_ERR, "error in config file");
2478  		lm_unload(mod);
2479  		return;
2480  	}
2481  	if (mod->config->start)
2482  		(*mod->config->start)();
2483  
2484  	mod->flags |= LM_STARTED;
2485  
2486  	/*
2487  	 * Inform other modules
2488  	 */
2489  	TAILQ_FOREACH(m, &lmodules, link)
2490  		if (m->config->loading)
2491  			(*m->config->loading)(mod, 1);
2492  }
2493  
2494  
2495  /*
2496   * Unload a module.
2497   */
2498  void
lm_unload(struct lmodule * m)2499  lm_unload(struct lmodule *m)
2500  {
2501  	int err;
2502  	const struct lmodule *mod;
2503  
2504  	TAILQ_REMOVE(&lmodules, m, link);
2505  	if (m->flags & LM_ONSTARTLIST)
2506  		TAILQ_REMOVE(&modules_start, m, start);
2507  	tree_unmerge(m);
2508  
2509  	if ((m->flags & LM_STARTED) && m->config->fini &&
2510  	    (err = (*m->config->fini)()) != 0)
2511  		syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err);
2512  
2513  	comm_flush(m);
2514  	reqid_flush(m);
2515  	timer_flush(m);
2516  	fd_flush(m);
2517  
2518  	dlclose(m->handle);
2519  	free(m->path);
2520  
2521  	/*
2522  	 * Inform other modules
2523  	 */
2524  	TAILQ_FOREACH(mod, &lmodules, link)
2525  		if (mod->config->loading)
2526  			(*mod->config->loading)(m, 0);
2527  
2528  	free(m);
2529  }
2530  
2531  /*
2532   * Register an object resource and return the index (or 0 on failures)
2533   */
2534  u_int
or_register(const struct asn_oid * or,const char * descr,struct lmodule * mod)2535  or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod)
2536  {
2537  	struct objres *objres, *or1;
2538  	u_int idx;
2539  
2540  	/* find a free index */
2541  	idx = 1;
2542  	for (objres = TAILQ_FIRST(&objres_list);
2543  	     objres != NULL;
2544  	     objres = TAILQ_NEXT(objres, link)) {
2545  		if ((or1 = TAILQ_NEXT(objres, link)) == NULL ||
2546  		    or1->index > objres->index + 1) {
2547  			idx = objres->index + 1;
2548  			break;
2549  		}
2550  	}
2551  
2552  	if ((objres = malloc(sizeof(*objres))) == NULL)
2553  		return (0);
2554  
2555  	objres->index = idx;
2556  	objres->oid = *or;
2557  	strlcpy(objres->descr, descr, sizeof(objres->descr));
2558  	objres->uptime = (uint32_t)(get_ticks() - start_tick);
2559  	objres->module = mod;
2560  
2561  	INSERT_OBJECT_INT(objres, &objres_list);
2562  
2563  	systemg.or_last_change = objres->uptime;
2564  
2565  	return (idx);
2566  }
2567  
2568  void
or_unregister(u_int idx)2569  or_unregister(u_int idx)
2570  {
2571  	struct objres *objres;
2572  
2573  	TAILQ_FOREACH(objres, &objres_list, link)
2574  		if (objres->index == idx) {
2575  			TAILQ_REMOVE(&objres_list, objres, link);
2576  			free(objres);
2577  			return;
2578  		}
2579  }
2580  
2581  /*
2582   * RFC 3414 User-based Security Model support
2583   */
2584  
2585  struct snmpd_usmstat *
bsnmpd_get_usm_stats(void)2586  bsnmpd_get_usm_stats(void)
2587  {
2588  	return (&snmpd_usmstats);
2589  }
2590  
2591  void
bsnmpd_reset_usm_stats(void)2592  bsnmpd_reset_usm_stats(void)
2593  {
2594  	memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats));
2595  }
2596  
2597  struct usm_user *
usm_first_user(void)2598  usm_first_user(void)
2599  {
2600  	return (SLIST_FIRST(&usm_userlist));
2601  }
2602  
2603  struct usm_user *
usm_next_user(struct usm_user * uuser)2604  usm_next_user(struct usm_user *uuser)
2605  {
2606  	if (uuser == NULL)
2607  		return (NULL);
2608  
2609  	return (SLIST_NEXT(uuser, up));
2610  }
2611  
2612  struct usm_user *
usm_find_user(uint8_t * engine,uint32_t elen,char * uname)2613  usm_find_user(uint8_t *engine, uint32_t elen, char *uname)
2614  {
2615  	struct usm_user *uuser;
2616  
2617  	SLIST_FOREACH(uuser, &usm_userlist, up)
2618  		if (uuser->user_engine_len == elen &&
2619  		    memcmp(uuser->user_engine_id, engine, elen) == 0 &&
2620  		    strlen(uuser->suser.sec_name) == strlen(uname) &&
2621  		    strcmp(uuser->suser.sec_name, uname) == 0)
2622  			break;
2623  
2624  	return (uuser);
2625  }
2626  
2627  static int
usm_compare_user(struct usm_user * u1,struct usm_user * u2)2628  usm_compare_user(struct usm_user *u1, struct usm_user *u2)
2629  {
2630  	uint32_t i;
2631  
2632  	if (u1->user_engine_len < u2->user_engine_len)
2633  		return (-1);
2634  	if (u1->user_engine_len > u2->user_engine_len)
2635  		return (1);
2636  
2637  	for (i = 0; i < u1->user_engine_len; i++) {
2638  		if (u1->user_engine_id[i] < u2->user_engine_id[i])
2639  			return (-1);
2640  		if (u1->user_engine_id[i] > u2->user_engine_id[i])
2641  			return (1);
2642  	}
2643  
2644  	if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name))
2645  		return (-1);
2646  	if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name))
2647  		return (1);
2648  
2649  	for (i = 0; i < strlen(u1->suser.sec_name); i++) {
2650  		if (u1->suser.sec_name[i] < u2->suser.sec_name[i])
2651  			return (-1);
2652  		if (u1->suser.sec_name[i] > u2->suser.sec_name[i])
2653  			return (1);
2654  	}
2655  
2656  	return (0);
2657  }
2658  
2659  struct usm_user *
usm_new_user(uint8_t * eid,uint32_t elen,char * uname)2660  usm_new_user(uint8_t *eid, uint32_t elen, char *uname)
2661  {
2662  	int cmp;
2663  	struct usm_user *uuser, *temp, *prev;
2664  
2665  	for (uuser = usm_first_user(); uuser != NULL;
2666  	    (uuser = usm_next_user(uuser))) {
2667  		if (uuser->user_engine_len == elen &&
2668  		    strlen(uname) == strlen(uuser->suser.sec_name) &&
2669  		    strcmp(uname, uuser->suser.sec_name) == 0 &&
2670  		    memcmp(eid, uuser->user_engine_id, elen) == 0)
2671  			return (NULL);
2672  	}
2673  
2674  	if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL)
2675  		return (NULL);
2676  
2677  	memset(uuser, 0, sizeof(*uuser));
2678  	strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ);
2679  	memcpy(uuser->user_engine_id, eid, elen);
2680  	uuser->user_engine_len = elen;
2681  
2682  	if ((prev = SLIST_FIRST(&usm_userlist)) == NULL ||
2683  	    usm_compare_user(uuser, prev) < 0) {
2684  		SLIST_INSERT_HEAD(&usm_userlist, uuser, up);
2685  		return (uuser);
2686  	}
2687  
2688  	SLIST_FOREACH(temp, &usm_userlist, up) {
2689  		if ((cmp = usm_compare_user(uuser, temp)) <= 0)
2690  			break;
2691  		prev = temp;
2692  	}
2693  
2694  	if (temp == NULL || cmp < 0)
2695  		SLIST_INSERT_AFTER(prev, uuser, up);
2696  	else if (cmp > 0)
2697  		SLIST_INSERT_AFTER(temp, uuser, up);
2698  	else {
2699  		syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name);
2700  		free(uuser);
2701  		return (NULL);
2702  	}
2703  
2704  	return (uuser);
2705  }
2706  
2707  void
usm_delete_user(struct usm_user * uuser)2708  usm_delete_user(struct usm_user *uuser)
2709  {
2710  	SLIST_REMOVE(&usm_userlist, uuser, usm_user, up);
2711  	free(uuser);
2712  }
2713  
2714  void
usm_flush_users(void)2715  usm_flush_users(void)
2716  {
2717  	struct usm_user *uuser;
2718  
2719  	while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) {
2720  		SLIST_REMOVE_HEAD(&usm_userlist, up);
2721  		free(uuser);
2722  	}
2723  
2724  	SLIST_INIT(&usm_userlist);
2725  }
2726  
2727  /*
2728   * RFC 3415 View-based Access Control Model support
2729   */
2730  struct vacm_user *
vacm_first_user(void)2731  vacm_first_user(void)
2732  {
2733  	return (SLIST_FIRST(&vacm_userlist));
2734  }
2735  
2736  struct vacm_user *
vacm_next_user(struct vacm_user * vuser)2737  vacm_next_user(struct vacm_user *vuser)
2738  {
2739  	if (vuser == NULL)
2740  		return (NULL);
2741  
2742  	return (SLIST_NEXT(vuser, vvu));
2743  }
2744  
2745  static int
vacm_compare_user(struct vacm_user * v1,struct vacm_user * v2)2746  vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2)
2747  {
2748  	uint32_t i;
2749  
2750  	if (v1->sec_model < v2->sec_model)
2751  		return (-1);
2752  	if (v1->sec_model > v2->sec_model)
2753  		return (1);
2754  
2755  	if (strlen(v1->secname) < strlen(v2->secname))
2756  		return (-1);
2757  	if (strlen(v1->secname) > strlen(v2->secname))
2758  		return (1);
2759  
2760  	for (i = 0; i < strlen(v1->secname); i++) {
2761  		if (v1->secname[i] < v2->secname[i])
2762  			return (-1);
2763  		if (v1->secname[i] > v2->secname[i])
2764  			return (1);
2765  	}
2766  
2767  	return (0);
2768  }
2769  
2770  struct vacm_user *
vacm_new_user(int32_t smodel,char * uname)2771  vacm_new_user(int32_t smodel, char *uname)
2772  {
2773  	int cmp;
2774  	struct vacm_user *user, *temp, *prev;
2775  
2776  	SLIST_FOREACH(user, &vacm_userlist, vvu)
2777  		if (strcmp(uname, user->secname) == 0 &&
2778  		    smodel == user->sec_model)
2779  			return (NULL);
2780  
2781  	if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL)
2782  		return (NULL);
2783  
2784  	memset(user, 0, sizeof(*user));
2785  	user->group = &vacm_default_group;
2786  	SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg);
2787  	user->sec_model = smodel;
2788  	strlcpy(user->secname, uname, sizeof(user->secname));
2789  
2790  	if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL ||
2791  	    vacm_compare_user(user, prev) < 0) {
2792  		SLIST_INSERT_HEAD(&vacm_userlist, user, vvu);
2793  		return (user);
2794  	}
2795  
2796  	SLIST_FOREACH(temp, &vacm_userlist, vvu) {
2797  		if ((cmp = vacm_compare_user(user, temp)) <= 0)
2798  			break;
2799  		prev = temp;
2800  	}
2801  
2802  	if (temp == NULL || cmp < 0)
2803  		SLIST_INSERT_AFTER(prev, user, vvu);
2804  	else if (cmp > 0)
2805  		SLIST_INSERT_AFTER(temp, user, vvu);
2806  	else {
2807  		syslog(LOG_ERR, "User %s exists", user->secname);
2808  		free(user);
2809  		return (NULL);
2810  	}
2811  
2812  	return (user);
2813  }
2814  
2815  int
vacm_delete_user(struct vacm_user * user)2816  vacm_delete_user(struct vacm_user *user)
2817  {
2818  	if (user->group != NULL && user->group != &vacm_default_group) {
2819  		SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg);
2820  		if (SLIST_EMPTY(&user->group->group_users)) {
2821  			SLIST_REMOVE(&vacm_grouplist, user->group,
2822  			    vacm_group, vge);
2823  			free(user->group);
2824  		}
2825  	}
2826  
2827  	SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu);
2828  	free(user);
2829  
2830  	return (0);
2831  }
2832  
2833  int
vacm_user_set_group(struct vacm_user * user,u_char * octets,u_int len)2834  vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len)
2835  {
2836  	struct vacm_group *group;
2837  
2838  	if (len >= SNMP_ADM_STR32_SIZ)
2839  		return (-1);
2840  
2841  	SLIST_FOREACH(group, &vacm_grouplist, vge)
2842  		if (strlen(group->groupname) == len &&
2843  		    memcmp(octets, group->groupname, len) == 0)
2844  			break;
2845  
2846  	if (group == NULL) {
2847  		if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL)
2848  			return (-1);
2849  		memset(group, 0, sizeof(*group));
2850  		memcpy(group->groupname, octets, len);
2851  		group->groupname[len] = '\0';
2852  		SLIST_INSERT_HEAD(&vacm_grouplist, group, vge);
2853  	}
2854  
2855  	SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg);
2856  	SLIST_INSERT_HEAD(&group->group_users, user, vvg);
2857  	user->group = group;
2858  
2859  	return (0);
2860  }
2861  
2862  void
vacm_groups_init(void)2863  vacm_groups_init(void)
2864  {
2865  	SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge);
2866  }
2867  
2868  struct vacm_access *
vacm_first_access_rule(void)2869  vacm_first_access_rule(void)
2870  {
2871  	return (TAILQ_FIRST(&vacm_accesslist));
2872  }
2873  
2874  struct vacm_access *
vacm_next_access_rule(struct vacm_access * acl)2875  vacm_next_access_rule(struct vacm_access *acl)
2876  {
2877  	if (acl == NULL)
2878  		return (NULL);
2879  
2880  	return (TAILQ_NEXT(acl, vva));
2881  }
2882  
2883  static int
vacm_compare_access_rule(struct vacm_access * v1,struct vacm_access * v2)2884  vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2)
2885  {
2886  	uint32_t i;
2887  
2888  	if (strlen(v1->group->groupname) < strlen(v2->group->groupname))
2889  		return (-1);
2890  	if (strlen(v1->group->groupname) > strlen(v2->group->groupname))
2891  		return (1);
2892  
2893  	for (i = 0; i < strlen(v1->group->groupname); i++) {
2894  		if (v1->group->groupname[i] < v2->group->groupname[i])
2895  			return (-1);
2896  		if (v1->group->groupname[i] > v2->group->groupname[i])
2897  			return (1);
2898  	}
2899  
2900  	if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix))
2901  		return (-1);
2902  	if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix))
2903  		return (1);
2904  
2905  	for (i = 0; i < strlen(v1->ctx_prefix); i++) {
2906  		if (v1->ctx_prefix[i] < v2->ctx_prefix[i])
2907  			return (-1);
2908  		if (v1->ctx_prefix[i] > v2->ctx_prefix[i])
2909  			return (1);
2910  	}
2911  
2912  	if (v1->sec_model < v2->sec_model)
2913  		return (-1);
2914  	if (v1->sec_model > v2->sec_model)
2915  		return (1);
2916  
2917  	if (v1->sec_level < v2->sec_level)
2918  		return (-1);
2919  	if (v1->sec_level > v2->sec_level)
2920  		return (1);
2921  
2922  	return (0);
2923  }
2924  
2925  struct vacm_access *
vacm_new_access_rule(char * gname,char * cprefix,int32_t smodel,int32_t slevel)2926  vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel)
2927  {
2928  	struct vacm_group *group;
2929  	struct vacm_access *acl, *temp;
2930  
2931  	TAILQ_FOREACH(acl, &vacm_accesslist, vva) {
2932  		if (acl->group == NULL)
2933  			continue;
2934  		if (strcmp(gname, acl->group->groupname) == 0 &&
2935  		    strcmp(cprefix, acl->ctx_prefix) == 0 &&
2936  		    acl->sec_model == smodel && acl->sec_level == slevel)
2937  			return (NULL);
2938  	}
2939  
2940  	/* Make sure the group exists */
2941  	SLIST_FOREACH(group, &vacm_grouplist, vge)
2942  		if (strcmp(gname, group->groupname) == 0)
2943  			break;
2944  
2945  	if (group == NULL)
2946  		return (NULL);
2947  
2948  	if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL)
2949  		return (NULL);
2950  
2951  	memset(acl, 0, sizeof(*acl));
2952  	acl->group = group;
2953  	strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix));
2954  	acl->sec_model = smodel;
2955  	acl->sec_level = slevel;
2956  
2957  	if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL ||
2958  	    vacm_compare_access_rule(acl, temp) < 0) {
2959  		TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva);
2960  		return (acl);
2961  	}
2962  
2963  	TAILQ_FOREACH(temp, &vacm_accesslist, vva)
2964  		if (vacm_compare_access_rule(acl, temp) < 0) {
2965  		    	TAILQ_INSERT_BEFORE(temp, acl, vva);
2966  			return (acl);
2967  		}
2968  
2969  	TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva);
2970  
2971  	return (acl);
2972  }
2973  
2974  int
vacm_delete_access_rule(struct vacm_access * acl)2975  vacm_delete_access_rule(struct vacm_access *acl)
2976  {
2977  	TAILQ_REMOVE(&vacm_accesslist, acl, vva);
2978  	free(acl);
2979  
2980  	return (0);
2981  }
2982  
2983  struct vacm_view *
vacm_first_view(void)2984  vacm_first_view(void)
2985  {
2986  	return (SLIST_FIRST(&vacm_viewlist));
2987  }
2988  
2989  struct vacm_view *
vacm_next_view(struct vacm_view * view)2990  vacm_next_view(struct vacm_view *view)
2991  {
2992  	if (view == NULL)
2993  		return (NULL);
2994  
2995  	return (SLIST_NEXT(view, vvl));
2996  }
2997  
2998  static int
vacm_compare_view(struct vacm_view * v1,struct vacm_view * v2)2999  vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2)
3000  {
3001  	uint32_t i;
3002  
3003  	if (strlen(v1->viewname) < strlen(v2->viewname))
3004  		return (-1);
3005  	if (strlen(v1->viewname) > strlen(v2->viewname))
3006  		return (1);
3007  
3008  	for (i = 0; i < strlen(v1->viewname); i++) {
3009  		if (v1->viewname[i] < v2->viewname[i])
3010  			return (-1);
3011  		if (v1->viewname[i] > v2->viewname[i])
3012  			return (1);
3013  	}
3014  
3015  	return (asn_compare_oid(&v1->subtree, &v2->subtree));
3016  }
3017  
3018  struct vacm_view *
vacm_new_view(char * vname,struct asn_oid * oid)3019  vacm_new_view(char *vname, struct asn_oid *oid)
3020  {
3021  	int cmp;
3022  	struct vacm_view *view, *temp, *prev;
3023  
3024  	SLIST_FOREACH(view, &vacm_viewlist, vvl)
3025  		if (strcmp(vname, view->viewname) == 0)
3026  			return (NULL);
3027  
3028  	if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL)
3029  		return (NULL);
3030  
3031  	memset(view, 0, sizeof(*view));
3032  	strlcpy(view->viewname, vname, sizeof(view->viewname));
3033  	asn_append_oid(&view->subtree, oid);
3034  
3035  	if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL ||
3036  	    vacm_compare_view(view, prev) < 0) {
3037  		SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl);
3038  		return (view);
3039  	}
3040  
3041  	SLIST_FOREACH(temp, &vacm_viewlist, vvl) {
3042  		if ((cmp = vacm_compare_view(view, temp)) <= 0)
3043  			break;
3044  		prev = temp;
3045  	}
3046  
3047  	if (temp == NULL || cmp < 0)
3048  		SLIST_INSERT_AFTER(prev, view, vvl);
3049  	else if (cmp > 0)
3050  		SLIST_INSERT_AFTER(temp, view, vvl);
3051  	else {
3052  		syslog(LOG_ERR, "View %s exists", view->viewname);
3053  		free(view);
3054  		return (NULL);
3055  	}
3056  
3057  	return (view);
3058  }
3059  
3060  int
vacm_delete_view(struct vacm_view * view)3061  vacm_delete_view(struct vacm_view *view)
3062  {
3063  	SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl);
3064  	free(view);
3065  
3066  	return (0);
3067  }
3068  
3069  struct vacm_context *
vacm_first_context(void)3070  vacm_first_context(void)
3071  {
3072  	return (SLIST_FIRST(&vacm_contextlist));
3073  }
3074  
3075  struct vacm_context *
vacm_next_context(struct vacm_context * vacmctx)3076  vacm_next_context(struct vacm_context *vacmctx)
3077  {
3078  	if (vacmctx == NULL)
3079  		return (NULL);
3080  
3081  	return (SLIST_NEXT(vacmctx, vcl));
3082  }
3083  
3084  struct vacm_context *
vacm_add_context(char * ctxname,int regid)3085  vacm_add_context(char *ctxname, int regid)
3086  {
3087  	int cmp;
3088  	struct vacm_context *ctx, *temp, *prev;
3089  
3090  	SLIST_FOREACH(ctx, &vacm_contextlist, vcl)
3091  		if (strcmp(ctxname, ctx->ctxname) == 0) {
3092  			syslog(LOG_ERR, "Context %s exists", ctx->ctxname);
3093  			return (NULL);
3094  		}
3095  
3096  	if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL)
3097  		return (NULL);
3098  
3099  	memset(ctx, 0, sizeof(*ctx));
3100  	strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname));
3101  	ctx->regid = regid;
3102  
3103  	if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL ||
3104  	    strlen(ctx->ctxname) < strlen(prev->ctxname) ||
3105  	    strcmp(ctx->ctxname, prev->ctxname) < 0) {
3106  		SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl);
3107  		return (ctx);
3108  	}
3109  
3110  	SLIST_FOREACH(temp, &vacm_contextlist, vcl) {
3111  		if (strlen(ctx->ctxname) < strlen(temp->ctxname) ||
3112  		    strcmp(ctx->ctxname, temp->ctxname) < 0) {
3113  		    	cmp = -1;
3114  			break;
3115  		}
3116  		prev = temp;
3117  	}
3118  
3119  	if (temp == NULL || cmp < 0)
3120  		SLIST_INSERT_AFTER(prev, ctx, vcl);
3121  	else if (cmp > 0)
3122  		SLIST_INSERT_AFTER(temp, ctx, vcl);
3123  	else {
3124  		syslog(LOG_ERR, "Context %s exists", ctx->ctxname);
3125  		free(ctx);
3126  		return (NULL);
3127  	}
3128  
3129  	return (ctx);
3130  }
3131  
3132  void
vacm_flush_contexts(int regid)3133  vacm_flush_contexts(int regid)
3134  {
3135  	struct vacm_context *ctx, *temp;
3136  
3137  	SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp)
3138  		if (ctx->regid == regid) {
3139  			SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl);
3140  			free(ctx);
3141  		}
3142  }
3143