1 /*
2 * snmptrapd.c - receive and log snmp traps
3 *
4 */
5 /*****************************************************************
6 Copyright 1989, 1991, 1992 by Carnegie Mellon University
7
8 All Rights Reserved
9
10 Permission to use, copy, modify, and distribute this software and its
11 documentation for any purpose and without fee is hereby granted,
12 provided that the above copyright notice appear in all copies and that
13 both that copyright notice and this permission notice appear in
14 supporting documentation, and that the name of CMU not be
15 used in advertising or publicity pertaining to distribution of the
16 software without specific, written prior permission.
17
18 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
19 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
21 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
23 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 SOFTWARE.
25 ******************************************************************/
26 #include <net-snmp/net-snmp-config.h>
27
28 #if HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #if HAVE_STRING_H
35 #include <string.h>
36 #else
37 #include <strings.h>
38 #endif
39 #include <sys/types.h>
40 #if HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
43 #if HAVE_SYS_SOCKET_H
44 #include <sys/socket.h>
45 #endif
46 #if HAVE_SYS_SOCKIO_H
47 #include <sys/sockio.h>
48 #endif
49 #if HAVE_NETINET_IN_H
50 #include <netinet/in.h>
51 #endif
52 #include <stdio.h>
53 #if !defined(mingw32) && defined(HAVE_SYS_TIME_H)
54 # include <sys/time.h>
55 # if TIME_WITH_SYS_TIME
56 # include <time.h>
57 # endif
58 #else
59 # include <time.h>
60 #endif
61 #if HAVE_SYS_SELECT_H
62 #include <sys/select.h>
63 #endif
64 #if HAVE_SYS_PARAM_H
65 #include <sys/param.h>
66 #endif
67 #if HAVE_SYSLOG_H
68 #include <syslog.h>
69 #endif
70 #if HAVE_SYS_IOCTL_H
71 #include <sys/ioctl.h>
72 #endif
73 #if HAVE_NET_IF_H
74 #include <net/if.h>
75 #endif
76 #if HAVE_NETDB_H
77 #include <netdb.h>
78 #endif
79 #if HAVE_ARPA_INET_H
80 #include <arpa/inet.h>
81 #endif
82 #if HAVE_FCNTL_H
83 #include <fcntl.h>
84 #endif
85 #if HAVE_PROCESS_H /* Win32-getpid */
86 #include <process.h>
87 #endif
88 #if HAVE_PWD_H
89 #include <pwd.h>
90 #endif
91 #if HAVE_GRP_H
92 #include <grp.h>
93 #endif
94 #include <signal.h>
95 #include <errno.h>
96
97 #include <net-snmp/net-snmp-includes.h>
98 #include <net-snmp/agent/net-snmp-agent-includes.h>
99 #include <net-snmp/library/fd_event_manager.h>
100 #include <net-snmp/agent/netsnmp_close_fds.h>
101 #include "../snmplib/snmp_syslog.h"
102 #include "../agent_global_vars.h"
103 #include "../agent/mibgroup/snmpv3/snmpEngine.h"
104 #include "../agent/mibgroup/snmpv3/usmUser.h"
105 #include "../agent/mibgroup/agent/nsVacmAccessTable.h"
106 #include "../agent/mibgroup/agentx/subagent.h"
107 #include "snmptrapd_handlers.h"
108 #include "snmptrapd_log.h"
109 #include "snmptrapd_auth.h"
110 #include "snmptrapd_sql.h"
111 #include "notification-log-mib/notification_log.h"
112 #include "tlstm-mib/snmpTlstmCertToTSNTable/snmpTlstmCertToTSNTable.h"
113 #include "mibII/vacm_conf.h"
114 #ifdef NETSNMP_EMBEDDED_PERL
115 #include "snmp_perl.h"
116 #endif
117
118 /*
119 * Include winservice.h to support Windows Service
120 */
121 #ifdef WIN32
122 #include <windows.h>
123 #include <tchar.h>
124 #include <net-snmp/library/winservice.h>
125
126 #define WIN32SERVICE
127
128 #endif
129
130 #if NETSNMP_USE_LIBWRAP
131 #include <tcpd.h>
132 #endif
133
134 #include <net-snmp/net-snmp-features.h>
135
136 #ifndef NETSNMP_NO_SYSTEMD
137 #include <net-snmp/library/sd-daemon.h>
138 #endif
139
140 #ifndef BSD4_3
141 #define BSD4_2
142 #endif
143
144 char *logfile = NULL;
145 static int reconfig = 0;
146 char ddefault_port[] = "udp:162"; /* Default default port */
147 char *default_port = ddefault_port;
148 #if HAVE_GETPID
149 FILE *PID;
150 char *pid_file = NULL;
151 #endif
152 char *trap1_fmt_str_remember = NULL;
153 int dofork = 1;
154
155 /*
156 * Include an extra Facility variable to allow command line adjustment of
157 * syslog destination
158 */
159 int Facility = LOG_DAEMON;
160
161 #ifdef WIN32SERVICE
162 /*
163 * SNMP Trap Receiver Status
164 */
165 #define SNMPTRAPD_RUNNING 1
166 #define SNMPTRAPD_STOPPED 0
167 int trapd_status = SNMPTRAPD_STOPPED;
168 /* app_name_long used for SCM, registry etc */
169 LPCTSTR app_name_long = _T("Net-SNMP Trap Handler"); /* Application Name */
170 #endif
171
172 const char *app_name = "snmptrapd";
173
174 void trapd_update_config(void);
175
176 #ifdef WIN32SERVICE
177 static void StopSnmpTrapd(void);
178 #endif
179
180
181 void
usage(void)182 usage(void)
183 {
184 #ifdef WIN32SERVICE
185 fprintf(stderr, "\nUsage: snmptrapd [-register] [-quiet] [OPTIONS] [LISTENING ADDRESSES]");
186 fprintf(stderr, "\n snmptrapd [-unregister] [-quiet]");
187 #else
188 fprintf(stderr, "Usage: snmptrapd [OPTIONS] [LISTENING ADDRESSES]\n");
189 #endif
190 fprintf(stderr, "\n\tNET-SNMP Version: %s\n", netsnmp_get_version());
191 fprintf(stderr, "\tWeb: http://www.net-snmp.org/\n");
192 fprintf(stderr, "\tEmail: net-snmp-coders@lists.sourceforge.net\n");
193 fprintf(stderr, "\n");
194 fprintf(stderr, " -a\t\t\tignore authentication failure traps\n");
195 fprintf(stderr, " -A\t\t\tappend to log file rather than truncating it\n");
196 fprintf(stderr, " -c FILE\t\tread FILE as a configuration file\n");
197 fprintf(stderr,
198 " -C\t\t\tdo not read the default configuration files\n");
199 fprintf(stderr, " -d\t\t\tdump sent and received SNMP packets\n");
200 fprintf(stderr, " -D[TOKEN[,...]]\t\tturn on debugging output for the specified TOKENs\n\t\t\t (ALL gives extremely verbose debugging output)\n");
201 fprintf(stderr, " -f\t\t\tdo not fork from the shell\n");
202 fprintf(stderr,
203 " -F FORMAT\t\tuse specified format for logging to standard error\n");
204 #if HAVE_UNISTD_H
205 fprintf(stderr, " -g GID\t\tchange to this numeric gid after opening\n"
206 "\t\t\t transport endpoints\n");
207 #endif
208 fprintf(stderr, " -h, --help\t\tdisplay this usage message\n");
209 fprintf(stderr,
210 " -H\t\t\tdisplay configuration file directives understood\n");
211 fprintf(stderr,
212 " -m MIBLIST\t\tuse MIBLIST instead of the default MIB list\n");
213 fprintf(stderr,
214 " -M DIRLIST\t\tuse DIRLIST as the list of locations\n\t\t\t to look for MIBs\n");
215 fprintf(stderr,
216 " -n\t\t\tuse numeric addresses instead of attempting\n\t\t\t hostname lookups (no DNS)\n");
217 #if HAVE_GETPID
218 fprintf(stderr, " -p FILE\t\tstore process id in FILE\n");
219 #endif
220 #ifdef WIN32SERVICE
221 fprintf(stderr, " -register\t\tregister as a Windows service\n");
222 fprintf(stderr, " \t\t\t (followed by -quiet to prevent message popups)\n");
223 fprintf(stderr, " \t\t\t (followed by the startup parameter list)\n");
224 fprintf(stderr, " \t\t\t Note that some parameters are not relevant when running as a service\n");
225 #endif
226 fprintf(stderr, " -t\t\t\tPrevent traps from being logged to syslog\n");
227 #if HAVE_UNISTD_H
228 fprintf(stderr, " -u UID\t\tchange to this uid (numeric or textual) after\n"
229 "\t\t\t opening transport endpoints\n");
230 #endif
231 #ifdef WIN32SERVICE
232 fprintf(stderr, " -unregister\t\tunregister as a Windows service\n");
233 fprintf(stderr, " \t\t\t (followed -quiet to prevent message popups)\n");
234 #endif
235 fprintf(stderr, " -v, --version\t\tdisplay version information\n");
236 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
237 fprintf(stderr, " -x ADDRESS\t\tuse ADDRESS as AgentX address\n");
238 fprintf(stderr, " -X\t\t\tdon't become a subagent\n");
239 #endif
240 fprintf(stderr,
241 " -O <OUTOPTS>\t\ttoggle options controlling output display\n");
242 snmp_out_toggle_options_usage("\t\t\t", stderr);
243 fprintf(stderr,
244 " -L <LOGOPTS>\t\ttoggle options controlling where to log to\n");
245 snmp_log_options_usage("\t\t\t", stderr);
246 }
247
248 static void
version(void)249 version(void)
250 {
251 printf("\nNET-SNMP Version: %s\n", netsnmp_get_version());
252 printf("Web: http://www.net-snmp.org/\n");
253 printf("Email: net-snmp-coders@lists.sourceforge.net\n\n");
254 }
255
256 RETSIGTYPE
term_handler(int sig)257 term_handler(int sig)
258 {
259 netsnmp_running = 0;
260
261 #ifdef WIN32SERVICE
262 /*
263 * In case of windows, select() in receive() function will not return
264 * on signal. Thats why following function is called, which closes the
265 * socket descriptors and causes the select() to return
266 */
267 snmp_close(main_session);
268 #endif
269 }
270
271 #ifdef SIGHUP
272 RETSIGTYPE
hup_handler(int sig)273 hup_handler(int sig)
274 {
275 reconfig = 1;
276 signal(SIGHUP, hup_handler);
277 }
278 #endif
279
280 static int
pre_parse(netsnmp_session * session,netsnmp_transport * transport,void * transport_data,int transport_data_length)281 pre_parse(netsnmp_session * session, netsnmp_transport *transport,
282 void *transport_data, int transport_data_length)
283 {
284 #if NETSNMP_USE_LIBWRAP
285 char *addr_string = NULL;
286
287 if (transport != NULL && transport->f_fmtaddr != NULL) {
288 /*
289 * Okay I do know how to format this address for logging.
290 */
291 addr_string = transport->f_fmtaddr(transport, transport_data,
292 transport_data_length);
293 /*
294 * Don't forget to free() it.
295 */
296 }
297
298 if (addr_string != NULL) {
299 /* Catch udp,udp6,tcp,tcp6 transports using "[" */
300 char *tcpudpaddr = strstr(addr_string, "[");
301 if ( tcpudpaddr != 0 ) {
302 char sbuf[64];
303 char *xp;
304
305 strlcpy(sbuf, tcpudpaddr + 1, sizeof(sbuf));
306 xp = strstr(sbuf, "]");
307 if (xp)
308 *xp = '\0';
309
310 if (hosts_ctl("snmptrapd", STRING_UNKNOWN,
311 sbuf, STRING_UNKNOWN) == 0) {
312 DEBUGMSGTL(("snmptrapd:libwrap", "%s rejected", addr_string));
313 SNMP_FREE(addr_string);
314 return 0;
315 }
316 }
317 SNMP_FREE(addr_string);
318 } else {
319 if (hosts_ctl("snmptrapd", STRING_UNKNOWN,
320 STRING_UNKNOWN, STRING_UNKNOWN) == 0) {
321 DEBUGMSGTL(("snmptrapd:libwrap", "[unknown] rejected"));
322 return 0;
323 }
324 }
325 #endif/* NETSNMP_USE_LIBWRAP */
326 return 1;
327 }
328
329 static netsnmp_session *
snmptrapd_add_session(netsnmp_transport * t)330 snmptrapd_add_session(netsnmp_transport *t)
331 {
332 netsnmp_session sess, *session = &sess, *rc = NULL;
333
334 snmp_sess_init(session);
335 session->peername = SNMP_DEFAULT_PEERNAME; /* Original code had NULL here */
336 session->version = SNMP_DEFAULT_VERSION;
337 session->community_len = SNMP_DEFAULT_COMMUNITY_LEN;
338 session->retries = SNMP_DEFAULT_RETRIES;
339 session->timeout = SNMP_DEFAULT_TIMEOUT;
340 session->callback = snmp_input;
341 session->callback_magic = (void *) t;
342 session->authenticator = NULL;
343 sess.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
344
345 rc = snmp_add(session, t, pre_parse, NULL);
346 if (rc == NULL) {
347 snmp_sess_perror("snmptrapd", session);
348 }
349 return rc;
350 }
351
352 static void
snmptrapd_close_sessions(netsnmp_session * sess_list)353 snmptrapd_close_sessions(netsnmp_session * sess_list)
354 {
355 netsnmp_session *s = NULL, *next = NULL;
356
357 for (s = sess_list; s != NULL; s = next) {
358 next = s->next;
359 snmp_close(s);
360 }
361 }
362
363 void
parse_trapd_address(const char * token,char * cptr)364 parse_trapd_address(const char *token, char *cptr)
365 {
366 char buf[BUFSIZ];
367 char *p;
368 cptr = copy_nword(cptr, buf, sizeof(buf));
369
370 if (default_port == ddefault_port) {
371 default_port = strdup(buf);
372 } else {
373 p = malloc(strlen(buf) + 1 + strlen(default_port) + 1);
374 if (p) {
375 strcpy(p, buf);
376 strcat(p, ",");
377 strcat(p, default_port );
378 }
379 free(default_port);
380 default_port = p;
381 }
382 }
383
384 void
free_trapd_address(void)385 free_trapd_address(void)
386 {
387 if (default_port != ddefault_port) {
388 free(default_port);
389 default_port = ddefault_port;
390 }
391 }
392
393 void
parse_config_doNotLogTraps(const char * token,char * cptr)394 parse_config_doNotLogTraps(const char *token, char *cptr)
395 {
396 if (atoi(cptr) > 0)
397 SyslogTrap++;
398 }
399
400 void
free_config_pidFile(void)401 free_config_pidFile(void)
402 {
403 if (pid_file)
404 free(pid_file);
405 pid_file = NULL;
406 }
407
408 void
parse_config_pidFile(const char * token,char * cptr)409 parse_config_pidFile(const char *token, char *cptr)
410 {
411 free_config_pidFile();
412 pid_file = strdup (cptr);
413 }
414
415 void
parse_config_doNotFork(const char * token,char * cptr)416 parse_config_doNotFork(const char *token, char *cptr)
417 {
418 if (netsnmp_ds_parse_boolean(cptr) == 1)
419 dofork = 0;
420 }
421
422 void
parse_config_ignoreAuthFailure(const char * token,char * cptr)423 parse_config_ignoreAuthFailure(const char *token, char *cptr)
424 {
425 if (netsnmp_ds_parse_boolean(cptr) == 1)
426 dropauth = 1;
427 }
428
429 void
parse_config_outputOption(const char * token,char * cptr)430 parse_config_outputOption(const char *token, char *cptr)
431 {
432 char *cp;
433
434 cp = snmp_out_toggle_options(cptr);
435 if (cp != NULL) {
436 fprintf(stderr, "Unknown output option passed to -O: %c\n",
437 *cp);
438 }
439 }
440
441 void
parse_config_addForwarderInfo(const char * token,char * cptr)442 parse_config_addForwarderInfo(const char *token, char *cptr)
443 {
444 if (netsnmp_ds_parse_boolean(cptr) == 1) {
445 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
446 NETSNMP_DS_LIB_ADD_FORWARDER_INFO, 1);
447 }
448 }
449
450 static void
snmptrapd_main_loop(void)451 snmptrapd_main_loop(void)
452 {
453 int count, numfds, block;
454 fd_set readfds,writefds,exceptfds;
455 struct timeval timeout;
456 NETSNMP_SELECT_TIMEVAL timeout2;
457
458 while (netsnmp_running) {
459 if (reconfig) {
460 /*
461 * If we are logging to a file, receipt of SIGHUP also
462 * indicates that the log file should be closed and
463 * re-opened. This is useful for users that want to
464 * rotate logs in a more predictable manner.
465 */
466 netsnmp_logging_restart();
467 snmp_log(LOG_INFO, "NET-SNMP version %s restarted\n",
468 netsnmp_get_version());
469 trapd_update_config();
470 if (trap1_fmt_str_remember) {
471 parse_format( NULL, trap1_fmt_str_remember );
472 }
473 reconfig = 0;
474 }
475 numfds = 0;
476 FD_ZERO(&readfds);
477 FD_ZERO(&writefds);
478 FD_ZERO(&exceptfds);
479 block = 0;
480 timerclear(&timeout);
481 timeout.tv_sec = 5;
482 snmp_select_info(&numfds, &readfds, &timeout, &block);
483 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
484 netsnmp_external_event_info(&numfds, &readfds, &writefds, &exceptfds);
485 #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
486 timeout2.tv_sec = timeout.tv_sec;
487 timeout2.tv_usec = timeout.tv_usec;
488 count = select(numfds, &readfds, &writefds, &exceptfds,
489 !block ? &timeout2 : NULL);
490 if (count > 0) {
491 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
492 netsnmp_dispatch_external_events(&count, &readfds, &writefds,
493 &exceptfds);
494 #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
495 /* If there are any more events after external events, then
496 * try SNMP events. */
497 if (count > 0) {
498 snmp_read(&readfds);
499 }
500 } else {
501 switch (count) {
502 case 0:
503 snmp_timeout();
504 break;
505 case -1:
506 if (errno == EINTR)
507 continue;
508 snmp_log_perror("select");
509 netsnmp_running = 0;
510 break;
511 default:
512 fprintf(stderr, "select returned %d\n", count);
513 netsnmp_running = 0;
514 }
515 }
516 run_alarms();
517 }
518 }
519
520 /*******************************************************************-o-******
521 * main - Non Windows
522 * SnmpTrapdMain - Windows to support windows service
523 *
524 * Parameters:
525 * argc
526 * *argv[]
527 *
528 * Returns:
529 * 0 Always succeeds. (?)
530 *
531 *
532 * Setup and start the trap receiver daemon.
533 *
534 * Also successfully EXITs with zero for some options.
535 */
536 int
537 #ifdef WIN32SERVICE
SnmpTrapdMain(int argc,TCHAR * argv[])538 SnmpTrapdMain(int argc, TCHAR * argv[])
539 #else
540 main(int argc, char *argv[])
541 #endif
542 {
543 static const char options[] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:Ptu:vx:X-:"
544 #if HAVE_GETPID
545 "p:"
546 #endif
547 ;
548 netsnmp_session *sess_list = NULL, *ss = NULL;
549 netsnmp_transport *transport = NULL;
550 int arg, i = 0;
551 int uid = 0, gid = 0;
552 int exit_code = 1;
553 char *cp, *listen_ports = NULL;
554 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
555 int agentx_subagent = 1;
556 #endif
557 netsnmp_trapd_handler *traph;
558 #ifndef WIN32
559 int prepared_sockets = 0;
560 #endif
561
562
563 #ifndef NETSNMP_NO_SYSTEMD
564 /* check if systemd has sockets for us and don't close them */
565 prepared_sockets = netsnmp_sd_listen_fds(0);
566 #endif
567 #ifndef WIN32
568 /*
569 * close all non-standard file descriptors we may have
570 * inherited from the shell.
571 */
572 if (!prepared_sockets)
573 netsnmp_close_fds(2);
574 #endif
575
576 #ifdef SIGTERM
577 signal(SIGTERM, term_handler);
578 #endif
579 #ifdef SIGHUP
580 signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */
581 #endif
582
583 #ifdef SIGINT
584 signal(SIGINT, term_handler);
585 #endif
586 #ifdef SIGPIPE
587 signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */
588 #endif
589
590 /*
591 * register our configuration handlers now so -H properly displays them
592 */
593 snmptrapd_register_configs( );
594 #ifdef NETSNMP_USE_MYSQL
595 snmptrapd_register_sql_configs( );
596 #endif
597 #ifdef NETSNMP_SECMOD_USM
598 init_usm_conf( "snmptrapd" );
599 #endif /* NETSNMP_SECMOD_USM */
600 register_config_handler("snmptrapd", "snmpTrapdAddr",
601 parse_trapd_address, free_trapd_address, "string");
602
603 register_config_handler("snmptrapd", "doNotLogTraps",
604 parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)");
605 #if HAVE_GETPID
606 register_config_handler("snmptrapd", "pidFile",
607 parse_config_pidFile, NULL, "string");
608 #endif
609 #ifdef HAVE_UNISTD_H
610 register_config_handler("snmptrapd", "agentuser",
611 netsnmp_parse_agent_user, NULL, "userid");
612 register_config_handler("snmptrapd", "agentgroup",
613 netsnmp_parse_agent_group, NULL, "groupid");
614 #endif
615
616 register_config_handler("snmptrapd", "doNotFork",
617 parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)");
618
619 register_config_handler("snmptrapd", "ignoreAuthFailure",
620 parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)");
621
622 register_config_handler("snmptrapd", "outputOption",
623 parse_config_outputOption, NULL, "string");
624
625 register_config_handler("snmptrapd", "addForwarderInfo",
626 parse_config_addForwarderInfo, NULL,
627 "(1|yes|true|0|no|false)");
628
629 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
630 #ifdef WIN32
631 snmp_log_syslogname(app_name_long);
632 #else
633 snmp_log_syslogname(app_name);
634 #endif
635 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
636
637 /*
638 * Now process options normally.
639 */
640
641 while ((arg = getopt(argc, argv, options)) != EOF) {
642 switch (arg) {
643 case '-':
644 if (strcasecmp(optarg, "help") == 0 ||
645 strcasecmp(optarg, "version") == 0) {
646 version();
647 exit_code = 0;
648 goto out;
649 }
650
651 handle_long_opt(optarg);
652 break;
653
654 case 'a':
655 dropauth = 1;
656 break;
657
658 case 'A':
659 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
660 NETSNMP_DS_LIB_APPEND_LOGFILES, 1);
661 break;
662
663 case 'c':
664 if (optarg != NULL) {
665 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
666 NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
667 } else {
668 usage();
669 goto out;
670 }
671 break;
672
673 case 'C':
674 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
675 NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
676 break;
677
678 case 'd':
679 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
680 NETSNMP_DS_LIB_DUMP_PACKET, 1);
681 break;
682
683 case 'D':
684 debug_register_tokens(optarg);
685 snmp_set_do_debugging(1);
686 break;
687
688 case 'f':
689 dofork = 0;
690 break;
691
692 case 'F':
693 if (optarg != NULL) {
694 if (( strncmp( optarg, "print", 5 ) == 0 ) ||
695 ( strncmp( optarg, "syslog", 6 ) == 0 ) ||
696 ( strncmp( optarg, "execute", 7 ) == 0 )) {
697 /* New style: "type=format" */
698 trap1_fmt_str_remember = strdup(optarg);
699 cp = strchr( trap1_fmt_str_remember, '=' );
700 if (cp)
701 *cp = ' ';
702 } else {
703 /* Old style: implicitly "print=format" */
704 trap1_fmt_str_remember = malloc(strlen(optarg) + 7);
705 sprintf( trap1_fmt_str_remember, "print %s", optarg );
706 }
707 } else {
708 usage();
709 goto out;
710 }
711 break;
712
713 #if HAVE_UNISTD_H
714 case 'g':
715 if (optarg != NULL) {
716 gid = atoi(optarg);
717 netsnmp_set_agent_group_id(gid);
718 } else {
719 usage();
720 goto out;
721 }
722 break;
723 #endif
724
725 case 'h':
726 usage();
727 exit_code = 0;
728 goto out;
729
730 case 'H':
731 init_agent("snmptrapd");
732 #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE
733 init_notification_log();
734 #endif
735 #ifdef NETSNMP_EMBEDDED_PERL
736 init_perl();
737 #endif
738 init_snmp("snmptrapd");
739 fprintf(stderr, "Configuration directives understood:\n");
740 read_config_print_usage(" ");
741 exit_code = 0;
742 goto out;
743
744 case 'I':
745 if (optarg != NULL) {
746 add_to_init_list(optarg);
747 } else {
748 usage();
749 }
750 break;
751
752 case 'S':
753 fprintf(stderr,
754 "Warning: -S option has been withdrawn; use -Ls <facility> instead\n");
755 goto out;
756
757 case 'm':
758 if (optarg != NULL) {
759 setenv("MIBS", optarg, 1);
760 } else {
761 usage();
762 goto out;
763 }
764 break;
765
766 case 'M':
767 if (optarg != NULL) {
768 setenv("MIBDIRS", optarg, 1);
769 } else {
770 usage();
771 goto out;
772 }
773 break;
774
775 case 'n':
776 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
777 NETSNMP_DS_APP_NUMERIC_IP, 1);
778 break;
779
780 case 'o':
781 fprintf(stderr,
782 "Warning: -o option has been withdrawn; use -Lf <file> instead\n");
783 goto out;
784
785 case 'O':
786 cp = snmp_out_toggle_options(optarg);
787 if (cp != NULL) {
788 fprintf(stderr, "Unknown output option passed to -O: %c\n",
789 *cp);
790 usage();
791 goto out;
792 }
793 break;
794
795 case 'L':
796 if (snmp_log_options( optarg, argc, argv ) < 0 ) {
797 usage();
798 goto out;
799 }
800 break;
801
802 #if HAVE_GETPID
803 case 'p':
804 if (optarg != NULL) {
805 parse_config_pidFile(NULL, optarg);
806 } else {
807 usage();
808 goto out;
809 }
810 break;
811 #endif
812
813 case 'P':
814 fprintf(stderr,
815 "Warning: -P option has been withdrawn; use -f -Le instead\n");
816 goto out;
817
818 case 's':
819 fprintf(stderr,
820 "Warning: -s option has been withdrawn; use -Lsd instead\n");
821 goto out;
822
823 case 't':
824 SyslogTrap++;
825 break;
826
827 #if HAVE_UNISTD_H
828 case 'u':
829 if (optarg != NULL) {
830 char *ecp;
831
832 uid = strtoul(optarg, &ecp, 10);
833 #if HAVE_GETPWNAM && HAVE_PWD_H
834 if (*ecp) {
835 struct passwd *info;
836
837 info = getpwnam(optarg);
838 uid = info ? info->pw_uid : -1;
839 endpwent();
840 }
841 #endif
842 if (uid < 0) {
843 fprintf(stderr, "Bad user id: %s\n", optarg);
844 goto out;
845 }
846 netsnmp_set_agent_user_id(uid);
847 } else {
848 usage();
849 goto out;
850 }
851 break;
852 #endif
853
854 case 'v':
855 version();
856 exit(0);
857 break;
858
859 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
860 case 'x':
861 if (optarg != NULL) {
862 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
863 NETSNMP_DS_AGENT_X_SOCKET, optarg);
864 } else {
865 usage();
866 goto out;
867 }
868 break;
869
870 case 'X':
871 agentx_subagent = 0;
872 break;
873 #endif
874
875 default:
876 fprintf(stderr, "invalid option: -%c\n", arg);
877 usage();
878 goto out;
879 break;
880 }
881 }
882
883 if (optind < argc) {
884 /*
885 * There are optional transport addresses on the command line.
886 */
887 for (i = optind; i < argc; i++) {
888 char *astring;
889 if (listen_ports != NULL) {
890 astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i]));
891 if (astring == NULL) {
892 fprintf(stderr, "malloc failure processing argv[%d]\n", i);
893 goto out;
894 }
895 sprintf(astring, "%s,%s", listen_ports, argv[i]);
896 free(listen_ports);
897 listen_ports = astring;
898 } else {
899 listen_ports = strdup(argv[i]);
900 if (listen_ports == NULL) {
901 fprintf(stderr, "malloc failure processing argv[%d]\n", i);
902 goto out;
903 }
904 }
905 }
906 }
907
908 SOCK_STARTUP;
909
910 /*
911 * I'm being lazy here, and not checking the
912 * return value from these registration calls.
913 * Don't try this at home, children!
914 */
915 if (0 == snmp_get_do_logging()) {
916 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
917 traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
918 syslog_handler);
919 traph->authtypes = TRAP_AUTH_LOG;
920 snmp_enable_syslog();
921 #else /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
922 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
923 traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
924 print_handler);
925 traph->authtypes = TRAP_AUTH_LOG;
926 snmp_enable_stderr();
927 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
928 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
929 } else {
930 traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER,
931 print_handler);
932 traph->authtypes = TRAP_AUTH_LOG;
933 }
934
935 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
936 /*
937 * we're an agentx subagent?
938 */
939 if (agentx_subagent) {
940 /*
941 * make us a agentx client.
942 */
943 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
944 NETSNMP_DS_AGENT_ROLE, 1);
945 }
946 #endif
947
948 /*
949 * don't fail if we can't do agentx (ie, socket not there, or not root)
950 */
951 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
952 NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
953 /*
954 * ignore any warning messages.
955 */
956 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
957 NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS);
958
959 /*
960 * initialize the agent library
961 */
962 init_agent("snmptrapd");
963
964 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
965 #ifdef NETSNMP_FEATURE_CHECKING
966 netsnmp_feature_require(register_snmpEngine_scalars_context)
967 #endif /* NETSNMP_FEATURE_CHECKING */
968 /*
969 * initialize local modules
970 */
971 if (agentx_subagent) {
972 subagent_init();
973 #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE
974 /* register the notification log table */
975 if (should_init("notificationLogMib")) {
976 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
977 NETSNMP_DS_NOTIF_LOG_CTX,
978 "snmptrapd");
979 traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER,
980 notification_handler);
981 traph->authtypes = TRAP_AUTH_LOG;
982 init_notification_log();
983 }
984 #endif
985 #ifdef USING_SNMPV3_SNMPENGINE_MODULE
986 /*
987 * register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group;
988 * allows engineID probes via the master agent under the
989 * snmptrapd context
990 */
991 register_snmpEngine_scalars_context("snmptrapd");
992 #endif
993 }
994 #endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */
995
996 /* register our authorization handler */
997 init_netsnmp_trapd_auth();
998
999 #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX)
1000 if (agentx_subagent) {
1001 #ifdef USING_SNMPV3_USMUSER_MODULE
1002 #ifdef NETSNMP_FEATURE_CHECKING
1003 netsnmp_feature_require(init_register_usmUser_context)
1004 #endif /* NETSNMP_FEATURE_CHECKING */
1005 /* register ourselves as having a USM user database */
1006 init_register_usmUser_context("snmptrapd");
1007 #endif
1008 #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE
1009 /* register net-snmp vacm extensions */
1010 init_register_nsVacm_context("snmptrapd");
1011 #endif
1012 #ifdef USING_TLSTM_MIB_SNMPTLSTMCERTTOTSNTABLE_MODULE
1013 init_snmpTlstmCertToTSNTable_context("snmptrapd");
1014 #endif
1015 }
1016 #endif
1017
1018 #ifdef NETSNMP_EMBEDDED_PERL
1019 init_perl();
1020 {
1021 /* set the default path to load */
1022 char init_file[SNMP_MAXBUF];
1023 snprintf(init_file, sizeof(init_file) - 1,
1024 "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl");
1025 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
1026 NETSNMP_DS_AGENT_PERL_INIT_FILE,
1027 init_file);
1028 }
1029 #endif
1030
1031 /*
1032 * Initialize the world.
1033 */
1034 init_snmp("snmptrapd");
1035
1036 #ifdef SIGHUP
1037 signal(SIGHUP, hup_handler);
1038 #endif
1039
1040 if (trap1_fmt_str_remember) {
1041 parse_format( NULL, trap1_fmt_str_remember );
1042 }
1043
1044 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1045 NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) {
1046 /*
1047 * just starting up to process specific configuration and then
1048 * shutting down immediately.
1049 */
1050 netsnmp_running = 0;
1051 }
1052
1053 /*
1054 * if no logging options on command line or in conf files, use syslog
1055 */
1056 if (0 == snmp_get_do_logging()) {
1057 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
1058 #ifdef WIN32
1059 snmp_enable_syslog_ident(app_name_long, Facility);
1060 #else
1061 snmp_enable_syslog_ident(app_name, Facility);
1062 #endif
1063 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
1064 }
1065
1066 if (listen_ports)
1067 cp = listen_ports;
1068 else
1069 cp = default_port;
1070
1071 while (cp != NULL) {
1072 char *sep = strchr(cp, ',');
1073
1074 if (sep != NULL) {
1075 *sep = 0;
1076 }
1077
1078 transport = netsnmp_transport_open_server("snmptrap", cp);
1079 if (transport == NULL) {
1080 snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n",
1081 cp, errno, strerror(errno));
1082 snmptrapd_close_sessions(sess_list);
1083 goto sock_cleanup;
1084 } else {
1085 ss = snmptrapd_add_session(transport);
1086 if (ss == NULL) {
1087 /*
1088 * Shouldn't happen? We have already opened the transport
1089 * successfully so what could have gone wrong?
1090 */
1091 snmptrapd_close_sessions(sess_list);
1092 snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno));
1093 goto sock_cleanup;
1094 } else {
1095 ss->next = sess_list;
1096 sess_list = ss;
1097 }
1098 }
1099
1100 /*
1101 * Process next listen address, if there is one.
1102 */
1103
1104 if (sep != NULL) {
1105 *sep = ',';
1106 cp = sep + 1;
1107 } else {
1108 cp = NULL;
1109 }
1110 }
1111 SNMP_FREE(listen_ports); /* done with them */
1112
1113 #ifdef NETSNMP_USE_MYSQL
1114 if( netsnmp_mysql_init() ) {
1115 fprintf(stderr, "MySQL initialization failed\n");
1116 goto sock_cleanup;
1117 }
1118 #endif
1119
1120 #ifndef WIN32
1121 /*
1122 * fork the process to the background if we are not printing to stderr
1123 */
1124 if (dofork && netsnmp_running) {
1125 int fd;
1126
1127 #if HAVE_FORKALL
1128 switch (forkall()) {
1129 #else
1130 switch (fork()) {
1131 #endif
1132 case -1:
1133 fprintf(stderr, "bad fork - %s\n", strerror(errno));
1134 goto sock_cleanup;
1135
1136 case 0:
1137 /*
1138 * become process group leader
1139 */
1140 if (setsid() == -1) {
1141 fprintf(stderr, "bad setsid - %s\n", strerror(errno));
1142 goto sock_cleanup;
1143 }
1144
1145 /*
1146 * if we are forked, we don't want to print out to stdout or stderr
1147 */
1148 fd = open("/dev/null", O_RDWR);
1149 if (fd >= 0) {
1150 dup2(fd, STDIN_FILENO);
1151 dup2(fd, STDOUT_FILENO);
1152 dup2(fd, STDERR_FILENO);
1153 close(fd);
1154 }
1155 break;
1156
1157 default:
1158 _exit(0);
1159 }
1160 }
1161 #endif /* WIN32 */
1162 #if HAVE_GETPID
1163 if (pid_file != NULL) {
1164 if ((PID = fopen(pid_file, "w")) == NULL) {
1165 snmp_log_perror("fopen");
1166 goto sock_cleanup;
1167 }
1168 fprintf(PID, "%d\n", (int) getpid());
1169 fclose(PID);
1170 free_config_pidFile();
1171 }
1172 #endif
1173
1174 snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
1175
1176 /*
1177 * ignore early sighup during startup
1178 */
1179 reconfig = 0;
1180
1181 #if HAVE_UNISTD_H
1182 #ifdef HAVE_SETGID
1183 if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
1184 NETSNMP_DS_AGENT_GROUPID)) > 0) {
1185 DEBUGMSGTL(("snmptrapd/main", "Changing gid to %d.\n", gid));
1186 if (setgid(gid) == -1
1187 #ifdef HAVE_SETGROUPS
1188 || setgroups(1, (gid_t *)&gid) == -1
1189 #endif
1190 ) {
1191 snmp_log_perror("setgid failed");
1192 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1193 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
1194 goto sock_cleanup;
1195 }
1196 }
1197 }
1198 #endif
1199 #ifdef HAVE_SETUID
1200 if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
1201 NETSNMP_DS_AGENT_USERID)) > 0) {
1202 DEBUGMSGTL(("snmptrapd/main", "Changing uid to %d.\n", uid));
1203 if (setuid(uid) == -1) {
1204 snmp_log_perror("setuid failed");
1205 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1206 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
1207 goto sock_cleanup;
1208 }
1209 }
1210 }
1211 #endif
1212 #endif
1213
1214 /*
1215 * Let systemd know we're up.
1216 */
1217 #ifndef NETSNMP_NO_SYSTEMD
1218 netsnmp_sd_notify(1, "READY=1\n");
1219 if (prepared_sockets)
1220 /*
1221 * Clear the environment variable, we already processed all the sockets
1222 * by now.
1223 */
1224 netsnmp_sd_listen_fds(1);
1225 #endif
1226
1227 #ifdef WIN32SERVICE
1228 trapd_status = SNMPTRAPD_RUNNING;
1229 #endif
1230
1231 snmptrapd_main_loop();
1232
1233 if (snmp_get_do_logging()) {
1234 struct tm *tm;
1235 time_t timer;
1236 time(&timer);
1237 tm = localtime(&timer);
1238 snmp_log(LOG_INFO,
1239 "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n",
1240 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
1241 tm->tm_min, tm->tm_sec, netsnmp_get_version());
1242 }
1243 snmp_log(LOG_INFO, "Stopping snmptrapd\n");
1244
1245 #ifdef NETSNMP_EMBEDDED_PERL
1246 shutdown_perl();
1247 #endif
1248 snmptrapd_close_sessions(sess_list);
1249 snmp_shutdown("snmptrapd");
1250 #ifdef WIN32SERVICE
1251 trapd_status = SNMPTRAPD_STOPPED;
1252 #endif
1253 snmp_disable_log();
1254
1255 exit_code = 0;
1256
1257 sock_cleanup:
1258 SOCK_CLEANUP;
1259
1260 out:
1261 return exit_code;
1262 }
1263
1264 /*
1265 * Read the configuration files. Implemented as a signal handler so that
1266 * receipt of SIGHUP will cause configuration to be re-read when the
1267 * trap daemon is running detatched from the console.
1268 *
1269 */
1270 void
1271 trapd_update_config(void)
1272 {
1273 free_config();
1274 #ifdef USING_MIBII_VACM_CONF_MODULE
1275 vacm_standard_views(0,0,NULL,NULL);
1276 #endif
1277 read_configs();
1278 }
1279
1280 /*
1281 * Windows Service Related functions
1282 */
1283 #ifdef WIN32SERVICE
1284 /************************************************************
1285 * main function for Windows
1286 * Parse command line arguments for startup options,
1287 * to start as service or console mode application in windows.
1288 * Invokes appropriate startup functions depending on the
1289 * parameters passed
1290 *************************************************************/
1291 int __cdecl
1292 main(int argc, TCHAR * argv[])
1293 {
1294 /*
1295 * Define Service Name and Description, which appears in windows SCM
1296 */
1297 LPCTSTR lpszServiceName = app_name_long; /* Service Registry Name */
1298 LPCTSTR lpszServiceDisplayName = _T("Net-SNMP Trap Handler"); /* Display Name */
1299 LPCTSTR lpszServiceDescription =
1300 #ifdef IFDESCR
1301 _T("SNMPv2c / SNMPv3 trap/inform receiver from Net-SNMP. Supports MIB objects for IP,ICMP,TCP,UDP, and network interface sub-layers.");
1302 #else
1303 _T("SNMPv2c / SNMPv3 trap/inform receiver from Net-SNMP");
1304 #endif
1305 InputParams InputOptions;
1306
1307 enum net_snmp_cmd_line_action nRunType = RUN_AS_CONSOLE;
1308 int quiet = 0;
1309
1310 nRunType = ParseCmdLineForServiceOption(argc, argv, &quiet);
1311
1312 switch (nRunType) {
1313 case REGISTER_SERVICE:
1314 /*
1315 * Register As service
1316 */
1317 InputOptions.Argc = argc;
1318 InputOptions.Argv = argv;
1319 exit (RegisterService(lpszServiceName,
1320 lpszServiceDisplayName,
1321 lpszServiceDescription, &InputOptions, quiet));
1322 break;
1323 case UN_REGISTER_SERVICE:
1324 /*
1325 * Unregister service
1326 */
1327 exit (UnregisterService(lpszServiceName, quiet));
1328 exit(0);
1329 break;
1330 case RUN_AS_SERVICE:
1331 /*
1332 * Run as service
1333 */
1334 /*
1335 * Register Stop Function
1336 */
1337 RegisterStopFunction(StopSnmpTrapd);
1338 return RunAsService(SnmpTrapdMain);
1339 break;
1340 default:
1341 /*
1342 * Run in console mode
1343 */
1344 return SnmpTrapdMain(argc, argv);
1345 break;
1346 }
1347 }
1348
1349 /*
1350 * To stop Snmp Trap Receiver daemon
1351 * This portion is still not working
1352 */
1353 void
1354 StopSnmpTrapd(void)
1355 {
1356 /*
1357 * Shut Down Service
1358 */
1359 term_handler(1);
1360
1361 /*
1362 * Wait till trap receiver is completely stopped
1363 */
1364
1365 while (trapd_status != SNMPTRAPD_STOPPED) {
1366 Sleep(100);
1367 }
1368 }
1369
1370 #endif /*WIN32SERVICE*/
1371