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