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