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