1 /*
2 * snmpd.c
3 */
4 /** @defgroup agent The Net-SNMP agent
5 * The snmp agent responds to SNMP queries from management stations
6 */
7 /* Portions of this file are subject to the following copyrights. See
8 * the Net-SNMP's COPYING file for more details and other copyrights
9 * that may apply:
10 */
11 /*
12 * Copyright 1988, 1989 by Carnegie Mellon University
13 *
14 * All Rights Reserved
15 *
16 * Permission to use, copy, modify, and distribute this software and its
17 * documentation for any purpose and without fee is hereby granted,
18 * provided that the above copyright notice appear in all copies and that
19 * both that copyright notice and this permission notice appear in
20 * supporting documentation, and that the name of CMU not be
21 * used in advertising or publicity pertaining to distribution of the
22 * software without specific, written prior permission.
23 *
24 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
26 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * SOFTWARE.
31 * *****************************************************************
32 */
33 /*
34 * Copyright � 2003 Sun Microsystems, Inc. All rights reserved.
35 * Use is subject to license terms specified in the COPYING file
36 * distributed with the Net-SNMP package.
37 */
38 #include <net-snmp/net-snmp-config.h>
39 #include <net-snmp/net-snmp-features.h>
40 #include <net-snmp/types.h>
41
42 #if HAVE_IO_H
43 #include <io.h>
44 #endif
45 #include <stdio.h>
46 #include <errno.h>
47 #if HAVE_STRING_H
48 #include <string.h>
49 #else
50 #include <strings.h>
51 #endif
52 #if HAVE_STDLIB_H
53 #include <stdlib.h>
54 #endif
55 #if HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58 #include <sys/types.h>
59 #if HAVE_NETINET_IN_H
60 #include <netinet/in.h>
61 #endif
62 #if HAVE_ARPA_INET_H
63 #include <arpa/inet.h>
64 #endif
65 #if TIME_WITH_SYS_TIME
66 # include <sys/time.h>
67 # include <time.h>
68 #else
69 # if HAVE_SYS_TIME_H
70 # include <sys/time.h>
71 # else
72 # include <time.h>
73 # endif
74 #endif
75 #if HAVE_SYS_SELECT_H
76 #include <sys/select.h>
77 #endif
78 #if HAVE_SYS_SOCKET_H
79 #include <sys/socket.h>
80 #endif
81 #if HAVE_NET_IF_H
82 #include <net/if.h>
83 #endif
84 #if HAVE_INET_MIB2_H
85 #include <inet/mib2.h>
86 #endif
87 #if HAVE_SYS_IOCTL_H
88 #include <sys/ioctl.h>
89 #endif
90 #if HAVE_SYS_FILE_H
91 #include <sys/file.h>
92 #endif
93 #ifdef HAVE_FCNTL_H
94 #include <fcntl.h>
95 #endif
96 #if HAVE_SYS_WAIT_H
97 #include <sys/wait.h>
98 #endif
99 #include <signal.h>
100 #ifdef HAVE_SYS_PARAM_H
101 #include <sys/param.h>
102 #endif
103 #if HAVE_PROCESS_H /* Win32-getpid */
104 #include <process.h>
105 #endif
106 #if HAVE_LIMITS_H
107 #include <limits.h>
108 #endif
109 #if HAVE_PWD_H
110 #include <pwd.h>
111 #endif
112 #if HAVE_GRP_H
113 #include <grp.h>
114 #endif
115 #ifdef HAVE_CRTDBG_H
116 #include <crtdbg.h>
117 #endif
118
119 #ifndef PATH_MAX
120 # ifdef _POSIX_PATH_MAX
121 # define PATH_MAX _POSIX_PATH_MAX
122 # else
123 # define PATH_MAX 255
124 # endif
125 #endif
126
127 #include <net-snmp/net-snmp-includes.h>
128 #include <net-snmp/agent/net-snmp-agent-includes.h>
129 #include "agent_global_vars.h"
130
131 #include <net-snmp/library/fd_event_manager.h>
132 #include <net-snmp/library/large_fd_set.h>
133
134 #include "m2m.h"
135 #include <net-snmp/agent/agent_module_config.h>
136 #include <net-snmp/agent/mib_module_config.h>
137
138 #include "snmpd.h"
139
140 #include <net-snmp/agent/mib_modules.h>
141
142 #include <net-snmp/agent/agent_trap.h>
143
144 #include <net-snmp/agent/netsnmp_close_fds.h>
145 #include <net-snmp/agent/table.h>
146 #include <net-snmp/agent/table_iterator.h>
147
148 #include "../snmplib/snmp_syslog.h"
149
150 #include "mibgroup/util_funcs/restart.h"
151
152 /*
153 * Include winservice.h to support Windows Service
154 */
155 #ifdef WIN32
156 #include <windows.h>
157 #include <tchar.h>
158 #include <net-snmp/library/winservice.h>
159
160 #define WIN32SERVICE
161
162 #endif
163
164 #ifndef NETSNMP_NO_SYSTEMD
165 #include <net-snmp/library/sd-daemon.h>
166 #endif
167
168 netsnmp_feature_want(logging_file);
169 netsnmp_feature_want(logging_stdio);
170 netsnmp_feature_want(logging_syslog);
171
172 /*
173 * Globals.
174 */
175 #ifdef NETSNMP_USE_LIBWRAP
176 #include <tcpd.h>
177 #endif /* NETSNMP_USE_LIBWRAP */
178
179 #define TIMETICK 500000L
180
181 int snmp_dump_packet;
182 static int reconfig = 0;
183 int Facility = LOG_DAEMON;
184
185 #ifdef WIN32SERVICE
186 /*
187 * SNMP Agent Status
188 */
189 #define AGENT_RUNNING 1
190 #define AGENT_STOPPED 0
191 int agent_status = AGENT_STOPPED;
192 /* app_name_long used for Event Log (syslog), SCM, registry etc */
193 LPCTSTR app_name_long = _T("Net-SNMP Agent"); /* Application Name */
194 #endif
195
196 const char *app_name = "snmpd";
197
198 #ifdef USING_SMUX_MODULE
199 #include <mibgroup/smux/smux.h>
200 #endif /* USING_SMUX_MODULE */
201
202 /*
203 * Prototypes.
204 */
205 static void usage(char *);
206 static void SnmpTrapNodeDown(void);
207 static int receive(void);
208 #ifdef WIN32SERVICE
209 static void StopSnmpAgent(void);
210 #endif
211
212 static void
usage(char * prog)213 usage(char *prog)
214 {
215 #ifdef WIN32SERVICE
216 printf("\nUsage: %s [-register] [-quiet] [OPTIONS] [LISTENING ADDRESSES]"
217 "\n %s [-unregister] [-quiet]", prog, prog);
218 #else
219 printf("\nUsage: %s [OPTIONS] [LISTENING ADDRESSES]", prog);
220 #endif
221 printf("\n"
222 "\n\tVersion: %s\n%s"
223 "\t\t\t (config search path: %s)\n%s%s",
224 netsnmp_get_version(),
225 "\tWeb: http://www.net-snmp.org/\n"
226 "\tEmail: net-snmp-coders@lists.sourceforge.net\n"
227 "\n -a\t\t\tlog addresses\n"
228 " -A\t\t\tappend to the logfile rather than truncating it\n"
229 " -c FILE[,...]\t\tread FILE(s) as configuration file(s)\n"
230 " -C\t\t\tdo not read the default configuration files\n",
231 get_configuration_directory(),
232 " -d\t\t\tdump sent and received SNMP packets\n"
233 #ifndef NETSNMP_DISABLE_DEBUGGING
234 " -D[TOKEN[,...]]\tturn on debugging output for the given TOKEN(s)\n"
235 "\t\t\t (try ALL for extremely verbose output)\n"
236 "\t\t\t Don't put space(s) between -D and TOKEN(s).\n"
237 #endif
238 " -f\t\t\tdo not fork from the shell\n",
239 #if HAVE_UNISTD_H
240 " -g GID\t\tchange to this numeric gid after opening\n"
241 "\t\t\t transport endpoints\n"
242 #endif
243 " -h, --help\t\tdisplay this usage message\n"
244 " -H\t\t\tdisplay configuration file directives understood\n"
245 " -I [-]INITLIST\tlist of mib modules to initialize (or not)\n"
246 "\t\t\t (run snmpd with -Dmib_init for a list)\n"
247 " -L <LOGOPTS>\t\ttoggle options controlling where to log to\n");
248 snmp_log_options_usage("\t", stdout);
249 printf(" -m MIBLIST\t\tuse MIBLIST instead of the default MIB list\n"
250 " -M DIRLIST\t\tuse DIRLIST as the list of locations to look for MIBs\n"
251 "\t\t\t (default %s)\n%s%s",
252 #ifndef NETSNMP_DISABLE_MIB_LOADING
253 netsnmp_get_mib_directory(),
254 #else
255 "MIBs not loaded",
256 #endif
257 " -p FILE\t\tstore process id in FILE\n"
258 " -q\t\t\tprint information in a more parsable format\n"
259 " -r\t\t\tdo not exit if files only accessible to root\n"
260 "\t\t\t cannot be opened\n"
261 #ifdef WIN32SERVICE
262 " -register\t\tregister as a Windows service\n"
263 " \t\t\t (followed by -quiet to prevent message popups)\n"
264 " \t\t\t (followed by the startup parameter list)\n"
265 " \t\t\t Note that some parameters are not relevant when running as a service\n"
266 #endif
267 #if HAVE_UNISTD_H
268 " -u UID\t\tchange to this uid (numeric or textual) after\n"
269 "\t\t\t opening transport endpoints\n"
270 #endif
271 #ifdef WIN32SERVICE
272 " -unregister\t\tunregister as a Windows service\n"
273 " \t\t\t (followed -quiet to prevent message popups)\n"
274 #endif
275 " -v, --version\t\tdisplay version information\n"
276 " -V\t\t\tverbose display\n"
277 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
278 " -x ADDRESS\t\tuse ADDRESS as AgentX address\n"
279 #endif
280 #ifdef USING_AGENTX_SUBAGENT_MODULE
281 " -X\t\t\trun as an AgentX subagent rather than as an\n"
282 "\t\t\t SNMP master agent\n"
283 #endif
284 ,
285 "\nDeprecated options:\n"
286 " -l FILE\t\tuse -Lf <FILE> instead\n"
287 " -P\t\t\tuse -p instead\n"
288 " -s\t\t\tuse -Lsd instead\n"
289 " -S d|i|0-7\t\tuse -Ls <facility> instead\n"
290 "\n"
291 );
292 }
293
294 static void
version(void)295 version(void)
296 {
297 printf("\nNET-SNMP version: %s\n"
298 "Web: http://www.net-snmp.org/\n"
299 "Email: net-snmp-coders@lists.sourceforge.net\n\n",
300 netsnmp_get_version());
301 }
302
303 RETSIGTYPE
SnmpdShutDown(int a)304 SnmpdShutDown(int a)
305 {
306 netsnmp_running = 0;
307 #ifdef WIN32SERVICE
308 /*
309 * In case of windows, select() in receive() function will not return
310 * on signal. Thats why following function is called, which closes the
311 * socket descriptors and causes the select() to return
312 */
313 snmp_close(main_session);
314 #endif
315 }
316
317 #ifdef SIGHUP
318 RETSIGTYPE
SnmpdReconfig(int a)319 SnmpdReconfig(int a)
320 {
321 reconfig = 1;
322 signal(SIGHUP, SnmpdReconfig);
323 }
324 #endif
325
326 #ifdef SIGUSR1
327 RETSIGTYPE
SnmpdDump(int a)328 SnmpdDump(int a)
329 {
330 dump_registry();
331 signal(SIGUSR1, SnmpdDump);
332 }
333 #endif
334
335 RETSIGTYPE
SnmpdCatchRandomSignal(int a)336 SnmpdCatchRandomSignal(int a)
337 {
338 /* Disable all logs and log the error via syslog */
339 snmp_disable_log();
340 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
341 snmp_enable_syslog();
342 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
343 snmp_log(LOG_ERR, "Exiting on signal %d\n", a);
344 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
345 snmp_disable_syslog();
346 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
347 exit(1);
348 }
349
350 static void
SnmpTrapNodeDown(void)351 SnmpTrapNodeDown(void)
352 {
353 send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 2);
354 /*
355 * XXX 2 - Node Down #define it as NODE_DOWN_TRAP
356 */
357 }
358
359 /*******************************************************************-o-******
360 * main - Non Windows
361 * SnmpDaemonMain - Windows to support windows service
362 *
363 * Parameters:
364 * argc
365 * *argv[]
366 *
367 * Returns:
368 * 0 Always succeeds. (?)
369 *
370 *
371 * Setup and start the agent daemon.
372 *
373 * Also successfully EXITs with zero for some options.
374 */
375 #ifdef WIN32SERVICE
376 static int
SnmpDaemonMain(int argc,TCHAR * argv[])377 SnmpDaemonMain(int argc, TCHAR * argv[])
378 #else
379 int
380 main(int argc, char *argv[])
381 #endif
382 {
383 static const char options[] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:"
384 #if HAVE_UNISTD_H
385 "g:u:"
386 #endif
387 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
388 "x:"
389 #endif
390 #ifdef USING_AGENTX_SUBAGENT_MODULE
391 "X"
392 #endif
393 ;
394 int arg, i, ret, exit_code = 1;
395 int dont_fork = 0, do_help = 0;
396 int log_set = 0;
397 int agent_mode = -1;
398 char *pid_file = NULL;
399 char option_compatability[] = "-Le";
400 #ifndef WIN32
401 int prepared_sockets = 0;
402 #endif
403 #if HAVE_GETPID
404 int fd;
405 FILE *PID;
406 #endif
407
408 SOCK_STARTUP;
409
410 #ifndef NETSNMP_NO_SYSTEMD
411 /* check if systemd has sockets for us and don't close them */
412 prepared_sockets = netsnmp_sd_listen_fds(0);
413 #endif /* NETSNMP_NO_SYSTEMD */
414 #ifndef WIN32
415 /*
416 * close all non-standard file descriptors we may have
417 * inherited from the shell.
418 */
419 if (!prepared_sockets)
420 netsnmp_close_fds(2);
421 #endif
422
423 /*
424 * register signals ASAP to prevent default action (usually core)
425 * for signals during startup...
426 */
427 #ifdef SIGTERM
428 DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n"));
429 signal(SIGTERM, SnmpdShutDown);
430 #endif
431 #ifdef SIGINT
432 DEBUGMSGTL(("signal", "registering SIGINT signal handler\n"));
433 signal(SIGINT, SnmpdShutDown);
434 #endif
435 #ifdef SIGHUP
436 signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */
437 #endif
438 #ifdef SIGUSR1
439 DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n"));
440 signal(SIGUSR1, SnmpdDump);
441 #endif
442 #ifdef SIGPIPE
443 DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n"));
444 signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */
445 #endif
446 #ifdef SIGXFSZ
447 signal(SIGXFSZ, SnmpdCatchRandomSignal);
448 #endif
449
450 #ifdef NETSNMP_NO_ROOT_ACCESS
451 /*
452 * Default to no.
453 */
454 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
455 NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
456 #endif
457 /*
458 * Default to NOT running an AgentX master.
459 */
460 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
461 NETSNMP_DS_AGENT_AGENTX_MASTER, 0);
462 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
463 NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1);
464 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
465 NETSNMP_DS_AGENT_AGENTX_RETRIES, -1);
466
467 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
468 NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5);
469
470 /*
471 * This is incredibly ugly, but it's probably the simplest way
472 * to handle the old '-L' option as well as the new '-Lx' style
473 */
474 for (i=0; i<argc; i++) {
475 if (!strcmp(argv[i], "-L"))
476 argv[i] = option_compatability;
477 }
478
479 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
480 #ifdef WIN32
481 snmp_log_syslogname(app_name_long);
482 #else
483 snmp_log_syslogname(app_name);
484 #endif
485 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
486 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
487 NETSNMP_DS_LIB_APPTYPE, app_name);
488
489 /*
490 * Now process options normally.
491 */
492 while ((arg = getopt(argc, argv, options)) != EOF) {
493 switch (arg) {
494 case '-':
495 if (strcasecmp(optarg, "help") == 0) {
496 usage(argv[0]);
497 goto out;
498 }
499 if (strcasecmp(optarg, "version") == 0) {
500 version();
501 exit_code = 0;
502 goto out;
503 }
504
505 handle_long_opt(optarg);
506 break;
507
508 case 'a':
509 log_addresses++;
510 break;
511
512 case 'A':
513 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
514 NETSNMP_DS_LIB_APPEND_LOGFILES, 1);
515 break;
516
517 case 'c':
518 if (optarg != NULL) {
519 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
520 NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
521 } else {
522 usage(argv[0]);
523 }
524 break;
525
526 case 'C':
527 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
528 NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
529 break;
530
531 case 'd':
532 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
533 NETSNMP_DS_LIB_DUMP_PACKET,
534 ++snmp_dump_packet);
535 break;
536
537 case 'D':
538 #ifdef NETSNMP_DISABLE_DEBUGGING
539 fprintf(stderr, "Debugging not configured\n");
540 goto out;
541 #else
542 debug_register_tokens(optarg);
543 snmp_set_do_debugging(1);
544 #endif
545 break;
546
547 case 'f':
548 dont_fork = 1;
549 break;
550
551 #if HAVE_UNISTD_H
552 case 'g':
553 if (optarg != NULL) {
554 char *ecp;
555 int gid;
556
557 gid = strtoul(optarg, &ecp, 10);
558 #if HAVE_GETGRNAM && HAVE_PWD_H
559 if (*ecp) {
560 struct group *info;
561
562 info = getgrnam(optarg);
563 gid = info ? info->gr_gid : -1;
564 endgrent();
565 }
566 #endif
567 if (gid < 0) {
568 fprintf(stderr, "Bad group id: %s\n", optarg);
569 goto out;
570 }
571 netsnmp_set_agent_group_id(gid);
572 } else {
573 usage(argv[0]);
574 }
575 break;
576 #endif
577
578 case 'h':
579 usage(argv[0]);
580 break;
581
582 case 'H':
583 do_help = 1;
584 break;
585
586 case 'I':
587 if (optarg != NULL) {
588 add_to_init_list(optarg);
589 } else {
590 usage(argv[0]);
591 }
592 break;
593
594 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
595 case 'l':
596 printf("Warning: -l option is deprecated, use -Lf <file> instead\n");
597 if (optarg != NULL) {
598 if (strlen(optarg) > PATH_MAX) {
599 fprintf(stderr,
600 "%s: logfile path too long (limit %d chars)\n",
601 argv[0], PATH_MAX);
602 goto out;
603 }
604 snmp_enable_filelog(optarg,
605 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
606 NETSNMP_DS_LIB_APPEND_LOGFILES));
607 log_set = 1;
608 } else {
609 usage(argv[0]);
610 }
611 break;
612 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
613
614 case 'L':
615 if (snmp_log_options( optarg, argc, argv ) < 0 ) {
616 usage(argv[0]);
617 }
618 log_set = 1;
619 break;
620
621 case 'm':
622 if (optarg != NULL) {
623 setenv("MIBS", optarg, 1);
624 } else {
625 usage(argv[0]);
626 }
627 break;
628
629 case 'M':
630 if (optarg != NULL) {
631 setenv("MIBDIRS", optarg, 1);
632 } else {
633 usage(argv[0]);
634 }
635 break;
636
637 case 'n':
638 if (optarg != NULL) {
639 app_name = optarg;
640 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
641 NETSNMP_DS_LIB_APPTYPE, app_name);
642 } else {
643 usage(argv[0]);
644 }
645 break;
646
647 case 'P':
648 printf("Warning: -P option is deprecated, use -p instead\n");
649 /* FALL THROUGH */
650 case 'p':
651 if (optarg != NULL) {
652 pid_file = optarg;
653 } else {
654 usage(argv[0]);
655 }
656 break;
657
658 case 'q':
659 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
660 NETSNMP_DS_LIB_QUICK_PRINT, 1);
661 break;
662
663 case 'r':
664 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
665 NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
666 break;
667
668 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG
669 case 's':
670 printf("Warning: -s option is deprecated, use -Lsd instead\n");
671 snmp_enable_syslog();
672 log_set = 1;
673 break;
674
675 case 'S':
676 printf("Warning: -S option is deprecated, use -Ls <facility> instead\n");
677 if (optarg != NULL) {
678 switch (*optarg) {
679 case 'd':
680 case 'D':
681 Facility = LOG_DAEMON;
682 break;
683 case 'i':
684 case 'I':
685 Facility = LOG_INFO;
686 break;
687 case '0':
688 Facility = LOG_LOCAL0;
689 break;
690 case '1':
691 Facility = LOG_LOCAL1;
692 break;
693 case '2':
694 Facility = LOG_LOCAL2;
695 break;
696 case '3':
697 Facility = LOG_LOCAL3;
698 break;
699 case '4':
700 Facility = LOG_LOCAL4;
701 break;
702 case '5':
703 Facility = LOG_LOCAL5;
704 break;
705 case '6':
706 Facility = LOG_LOCAL6;
707 break;
708 case '7':
709 Facility = LOG_LOCAL7;
710 break;
711 default:
712 fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
713 usage(argv[0]);
714 }
715 snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility);
716 log_set = 1;
717 } else {
718 fprintf(stderr, "no syslog facility specified\n");
719 usage(argv[0]);
720 }
721 break;
722 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */
723
724 case 'U':
725 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
726 NETSNMP_DS_AGENT_LEAVE_PIDFILE);
727 break;
728
729 #if HAVE_UNISTD_H
730 case 'u':
731 if (optarg != NULL) {
732 char *ecp;
733 int uid;
734
735 uid = strtoul(optarg, &ecp, 10);
736 #if HAVE_GETPWNAM && HAVE_PWD_H
737 if (*ecp) {
738 struct passwd *info;
739
740 info = getpwnam(optarg);
741 uid = info ? info->pw_uid : -1;
742 endpwent();
743 }
744 #endif
745 if (uid < 0) {
746 fprintf(stderr, "Bad user id: %s\n", optarg);
747 goto out;
748 }
749 netsnmp_set_agent_user_id(uid);
750 } else {
751 usage(argv[0]);
752 }
753 break;
754 #endif
755
756 case 'v':
757 version();
758 exit_code = 0;
759 goto out;
760
761 case 'V':
762 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
763 NETSNMP_DS_AGENT_VERBOSE, 1);
764 break;
765
766 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
767 case 'x':
768 if (optarg != NULL) {
769 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
770 NETSNMP_DS_AGENT_X_SOCKET, optarg);
771 } else {
772 usage(argv[0]);
773 }
774 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
775 NETSNMP_DS_AGENT_AGENTX_MASTER, 1);
776 break;
777 #endif
778
779 case 'X':
780 #if defined(USING_AGENTX_SUBAGENT_MODULE)
781 agent_mode = SUB_AGENT;
782 #else
783 fprintf(stderr, "%s: Illegal argument -X:"
784 "AgentX support not compiled in.\n", argv[0]);
785 usage(argv[0]);
786 goto out;
787 #endif
788 break;
789
790 case 'Y':
791 netsnmp_config_remember(optarg);
792 break;
793
794 default:
795 usage(argv[0]);
796 break;
797 }
798 }
799
800 if (do_help) {
801 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
802 NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
803 init_agent(app_name); /* register our .conf handlers */
804 init_mib_modules();
805 init_snmp(app_name);
806 fprintf(stderr, "Configuration directives understood:\n");
807 read_config_print_usage(" ");
808 exit_code = 0;
809 goto out;
810 }
811
812 if (optind < argc) {
813 #ifndef NETSNMP_NO_LISTEN_SUPPORT
814 /*
815 * There are optional transport addresses on the command line.
816 */
817 DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));
818 for (i = optind; i < argc; i++) {
819 char *c, *astring;
820 if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
821 NETSNMP_DS_AGENT_PORTS))) {
822 astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i]));
823 if (astring == NULL) {
824 fprintf(stderr, "malloc failure processing argv[%d]\n", i);
825 goto out;
826 }
827 sprintf(astring, "%s,%s", c, argv[i]);
828 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
829 NETSNMP_DS_AGENT_PORTS, astring);
830 SNMP_FREE(astring);
831 } else {
832 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
833 NETSNMP_DS_AGENT_PORTS, argv[i]);
834 }
835 }
836 DEBUGMSGTL(("snmpd/main", "port spec: %s\n",
837 netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
838 NETSNMP_DS_AGENT_PORTS)));
839 #else /* NETSNMP_NO_LISTEN_SUPPORT */
840 fprintf(stderr, "You specified ports to open; this agent was built to only send notifications\n");
841 goto out;
842 #endif /* NETSNMP_NO_LISTEN_SUPPORT */
843 }
844
845 #if defined(NETSNMP_DAEMONS_DEFAULT_LOG_SYSLOG)
846 if (0 == log_set)
847 snmp_enable_syslog();
848 #else
849 #ifdef NETSNMP_LOGFILE
850 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE
851 if (0 == log_set)
852 snmp_enable_filelog(NETSNMP_LOGFILE,
853 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
854 NETSNMP_DS_LIB_APPEND_LOGFILES));
855 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */
856 #endif /* NETSNMP_LOGFILE */
857 #endif /* ! NETSNMP_DEFAULT_LOG_SYSLOG */
858
859 #ifdef USING_UTIL_FUNCS_RESTART_MODULE
860 {
861 /*
862 * Initialize a argv set to the current for restarting the agent.
863 */
864 char *cptr, **argvptr;
865
866 argvrestartp = (char **)malloc((argc + 2) * sizeof(char *));
867 argvptr = argvrestartp;
868 for (i = 0, ret = 1; i < argc; i++) {
869 ret += strlen(argv[i]) + 1;
870 }
871 argvrestart = (char *) malloc(ret);
872 argvrestartname = (char *) malloc(strlen(argv[0]) + 1);
873 if (!argvrestartp || !argvrestart || !argvrestartname) {
874 fprintf(stderr, "malloc failure processing argvrestart\n");
875 goto out;
876 }
877 strcpy(argvrestartname, argv[0]);
878
879 for (cptr = argvrestart, i = 0; i < argc; i++) {
880 strcpy(cptr, argv[i]);
881 *(argvptr++) = cptr;
882 cptr += strlen(argv[i]) + 1;
883 }
884 }
885 #endif /* USING_UTIL_FUNCS_RESTART_MODULE */
886
887 if (agent_mode == -1) {
888 if (strstr(argv[0], "agentxd") != NULL) {
889 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
890 NETSNMP_DS_AGENT_ROLE, SUB_AGENT);
891 } else {
892 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
893 NETSNMP_DS_AGENT_ROLE, MASTER_AGENT);
894 }
895 } else {
896 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
897 NETSNMP_DS_AGENT_ROLE, agent_mode);
898 }
899
900 if (init_agent(app_name) != 0) {
901 snmp_log(LOG_ERR, "Agent initialization failed\n");
902 goto out;
903 }
904 init_mib_modules();
905
906 /*
907 * start library
908 */
909 init_snmp(app_name);
910
911 if ((ret = init_master_agent()) != 0) {
912 /*
913 * Some error opening one of the specified agent transports.
914 */
915 snmp_log(LOG_ERR, "Server Exiting with code 1\n");
916 goto out;
917 }
918
919 /*
920 * Initialize the world. Detach from the shell. Create initial user.
921 */
922 if(!dont_fork) {
923 int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
924 NETSNMP_DS_AGENT_QUIT_IMMEDIATELY);
925 ret = netsnmp_daemonize(quit,
926 #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO
927 snmp_stderrlog_status()
928 #else /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
929 0
930 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */
931 );
932 /*
933 * xxx-rks: do we care if fork fails? I think we should...
934 */
935 if(ret != 0) {
936 snmp_log(LOG_ERR, "Server Exiting with code 1\n");
937 goto out;
938 }
939 }
940
941 #if HAVE_GETPID
942 if (pid_file != NULL) {
943 /*
944 * unlink the pid_file, if it exists, prior to open. Without
945 * doing this the open will fail if the user specified pid_file
946 * already exists.
947 */
948 unlink(pid_file);
949 fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600);
950 if (fd == -1) {
951 snmp_log_perror(pid_file);
952 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
953 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
954 goto out;
955 }
956 } else {
957 if ((PID = fdopen(fd, "w")) == NULL) {
958 snmp_log_perror(pid_file);
959 goto out;
960 } else {
961 fprintf(PID, "%d\n", (int) getpid());
962 fclose(PID);
963 }
964 #ifndef _MSC_VER
965 /* The sequence open()/fdopen()/fclose()/close() makes MSVC crash,
966 hence skip the close() call when using the MSVC runtime. */
967 close(fd);
968 #endif
969 }
970 }
971 #endif
972
973 #if defined(HAVE_UNISTD_H) && (defined(HAVE_CHOWN) || defined(HAVE_SETGID) || defined(HAVE_SETUID))
974 {
975 const char *persistent_dir;
976 int uid, gid;
977
978 persistent_dir = get_persistent_directory();
979 mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 );
980
981 uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
982 NETSNMP_DS_AGENT_USERID);
983 gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
984 NETSNMP_DS_AGENT_GROUPID);
985
986 #ifdef HAVE_CHOWN
987 if ( uid != 0 || gid != 0 )
988 NETSNMP_IGNORE_RESULT(chown(persistent_dir, uid, gid));
989 #endif
990
991 #ifdef HAVE_SETGID
992 if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
993 NETSNMP_DS_AGENT_GROUPID)) > 0) {
994 DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid));
995 if (setgid(gid) == -1
996 #ifdef HAVE_SETGROUPS
997 || setgroups(1, (gid_t *)&gid) == -1
998 #endif
999 ) {
1000 snmp_log_perror("setgid failed");
1001 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1002 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
1003 goto out;
1004 }
1005 }
1006 }
1007 #endif
1008 #ifdef HAVE_SETUID
1009 if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
1010 NETSNMP_DS_AGENT_USERID)) > 0) {
1011 #if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS
1012 struct passwd *info;
1013
1014 /*
1015 * Set supplementary groups before changing UID
1016 * (which probably involves giving up privileges)
1017 */
1018 info = getpwuid(uid);
1019 if (info) {
1020 DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name));
1021 if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) {
1022 snmp_log_perror("initgroups failed");
1023 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1024 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
1025 goto out;
1026 }
1027 }
1028 }
1029 endpwent();
1030 #endif
1031 DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid));
1032 if (setuid(uid) == -1) {
1033 snmp_log_perror("setuid failed");
1034 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1035 NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
1036 goto out;
1037 }
1038 }
1039 }
1040 #endif
1041 }
1042 #endif
1043
1044 /*
1045 * Store persistent data immediately in case we crash later.
1046 */
1047 snmp_store(app_name);
1048
1049 #ifdef SIGHUP
1050 DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n"));
1051 signal(SIGHUP, SnmpdReconfig);
1052 #endif
1053
1054 /*
1055 * Send coldstart trap if possible.
1056 */
1057 send_easy_trap(0, 0);
1058
1059 /*
1060 * We're up, log our version number.
1061 */
1062 snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
1063 #ifdef WIN32SERVICE
1064 agent_status = AGENT_RUNNING;
1065 #endif
1066 netsnmp_addrcache_initialise();
1067
1068 /*
1069 * Let systemd know we're up.
1070 */
1071 #ifndef NETSNMP_NO_SYSTEMD
1072 netsnmp_sd_notify(1, "READY=1\n");
1073 if (prepared_sockets)
1074 /*
1075 * Clear the environment variable, we already processed all the sockets
1076 * by now.
1077 */
1078 netsnmp_sd_listen_fds(1);
1079 #endif
1080
1081 /*
1082 * Forever monitor the dest_port for incoming PDUs.
1083 */
1084 DEBUGMSGTL(("snmpd/main", "We're up. Starting to process data.\n"));
1085 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1086 NETSNMP_DS_AGENT_QUIT_IMMEDIATELY))
1087 receive();
1088 DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n"));
1089 SnmpTrapNodeDown();
1090 DEBUGMSGTL(("snmpd/main", "Bye...\n"));
1091 snmp_shutdown(app_name);
1092 shutdown_master_agent();
1093 shutdown_agent();
1094
1095 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
1096 NETSNMP_DS_AGENT_LEAVE_PIDFILE) &&
1097 (pid_file != NULL)) {
1098 unlink(pid_file);
1099 }
1100 #ifdef WIN32SERVICE
1101 agent_status = AGENT_STOPPED;
1102 #endif
1103
1104 #ifdef USING_UTIL_FUNCS_RESTART_MODULE
1105 SNMP_FREE(argvrestartname);
1106 SNMP_FREE(argvrestart);
1107 SNMP_FREE(argvrestartp);
1108 #endif /* USING_UTIL_FUNCS_RESTART_MODULE */
1109
1110 exit_code = 0;
1111
1112 out:
1113 SOCK_CLEANUP;
1114 return exit_code;
1115 } /* End main() -- snmpd */
1116
1117 #if defined(WIN32)
1118
1119 #include <process.h>
1120 #include <net-snmp/library/snmp_assert.h>
1121
1122 static unsigned s_threadid;
1123 HANDLE s_thread_handle;
1124
wait_for_stdin(void * arg)1125 static unsigned __stdcall wait_for_stdin(void* arg)
1126 {
1127 if (getc(stdin) != EOF)
1128 netsnmp_running = 0;
1129 return 0;
1130 }
1131
create_stdin_waiter_thread(void)1132 static void create_stdin_waiter_thread(void)
1133 {
1134 netsnmp_assert(s_thread_handle == 0);
1135 #ifdef HAVE__BEGINTHREADEX
1136 s_thread_handle = (HANDLE)_beginthreadex(0, 0, wait_for_stdin, 0, 0,
1137 &s_threadid);
1138 #else
1139 s_thread_handle = (HANDLE)CreateThread(NULL, 0, wait_for_stdin, 0, 0,
1140 &s_threadid);
1141 #endif
1142 netsnmp_assert(s_thread_handle != 0);
1143 }
1144
join_stdin_waiter_thread(void)1145 static void join_stdin_waiter_thread(void)
1146 {
1147 int result;
1148
1149 netsnmp_assert(s_thread_handle != 0);
1150 result = WaitForSingleObject(s_thread_handle, 1000);
1151 netsnmp_assert(result != WAIT_TIMEOUT);
1152 CloseHandle(s_thread_handle);
1153 s_thread_handle = 0;
1154 }
1155 #endif
1156
1157 /*******************************************************************-o-******
1158 * receive
1159 *
1160 * Parameters:
1161 *
1162 * Returns:
1163 * 0 On success.
1164 * -1 System error.
1165 *
1166 * Infinite while-loop which monitors incoming messages for the agent.
1167 * Invoke the established message handlers for incoming messages on a per
1168 * port basis. Handle timeouts.
1169 */
1170 static int
receive(void)1171 receive(void)
1172 {
1173 int numfds;
1174 netsnmp_large_fd_set readfds, writefds, exceptfds;
1175 struct timeval timeout, *tvp = &timeout;
1176 int count, block, i;
1177 #ifdef USING_SMUX_MODULE
1178 int sd;
1179 #endif /* USING_SMUX_MODULE */
1180
1181 netsnmp_large_fd_set_init(&readfds, FD_SETSIZE);
1182 netsnmp_large_fd_set_init(&writefds, FD_SETSIZE);
1183 netsnmp_large_fd_set_init(&exceptfds, FD_SETSIZE);
1184
1185 /*
1186 * ignore early sighup during startup
1187 */
1188 reconfig = 0;
1189
1190 #if defined(WIN32)
1191 create_stdin_waiter_thread();
1192 #endif
1193
1194 /*
1195 * Loop-forever: execute message handlers for sockets with data
1196 */
1197 while (netsnmp_running) {
1198 if (reconfig) {
1199 #if HAVE_SIGHOLD
1200 sighold(SIGHUP);
1201 #endif
1202 reconfig = 0;
1203 snmp_log(LOG_INFO, "Reconfiguring daemon\n");
1204 /* Stop and restart logging. This allows logfiles to be
1205 rotated etc. */
1206 netsnmp_logging_restart();
1207 snmp_log(LOG_INFO, "NET-SNMP version %s restarted\n",
1208 netsnmp_get_version());
1209 update_config();
1210 send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 3);
1211 #if HAVE_SIGHOLD
1212 sigrelse(SIGHUP);
1213 #endif
1214 }
1215
1216 /*
1217 * default to sleeping for a really long time. INT_MAX
1218 * should be sufficient (eg we don't care if time_t is
1219 * a long that's bigger than an int).
1220 */
1221 tvp = &timeout;
1222 tvp->tv_sec = INT_MAX;
1223 tvp->tv_usec = 0;
1224
1225 numfds = 0;
1226 NETSNMP_LARGE_FD_ZERO(&readfds);
1227 NETSNMP_LARGE_FD_ZERO(&writefds);
1228 NETSNMP_LARGE_FD_ZERO(&exceptfds);
1229 block = 0;
1230 snmp_select_info2(&numfds, &readfds, tvp, &block);
1231 if (block == 1) {
1232 tvp = NULL; /* block without timeout */
1233 }
1234
1235 #ifdef USING_SMUX_MODULE
1236 if (smux_listen_sd >= 0) {
1237 NETSNMP_LARGE_FD_SET(smux_listen_sd, &readfds);
1238 numfds =
1239 smux_listen_sd >= numfds ? smux_listen_sd + 1 : numfds;
1240
1241 for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
1242 sd = smux_snmp_select_list_get_SD_from_List(i);
1243 if (sd != 0)
1244 {
1245 NETSNMP_LARGE_FD_SET(sd, &readfds);
1246 numfds = sd >= numfds ? sd + 1 : numfds;
1247 }
1248 }
1249 }
1250 #endif /* USING_SMUX_MODULE */
1251
1252 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
1253 netsnmp_external_event_info2(&numfds, &readfds, &writefds, &exceptfds);
1254 #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
1255
1256 reselect:
1257 #ifndef NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL
1258 for (i = 0; i < NUM_EXTERNAL_SIGS; i++) {
1259 if (external_signal_scheduled[i]) {
1260 external_signal_scheduled[i]--;
1261 external_signal_handler[i](i);
1262 }
1263 }
1264 #endif /* NETSNMP_FEATURE_REMOVE_REGISTER_SIGNAL */
1265
1266 DEBUGMSGTL(("snmpd/select", "select( numfds=%d, ..., tvp=%p)\n",
1267 numfds, tvp));
1268 if (tvp)
1269 DEBUGMSGTL(("timer", "tvp %ld.%ld\n", (long) tvp->tv_sec,
1270 (long) tvp->tv_usec));
1271 count = netsnmp_large_fd_set_select(numfds, &readfds, &writefds, &exceptfds,
1272 tvp);
1273 DEBUGMSGTL(("snmpd/select", "returned, count = %d\n", count));
1274
1275 if (count > 0) {
1276
1277 #ifdef USING_SMUX_MODULE
1278 /*
1279 * handle the SMUX sd's
1280 */
1281 if (smux_listen_sd >= 0) {
1282 for (i = 0; i < smux_snmp_select_list_get_length(); i++) {
1283 sd = smux_snmp_select_list_get_SD_from_List(i);
1284 if (NETSNMP_LARGE_FD_ISSET(sd, &readfds)) {
1285 if (smux_process(sd) < 0) {
1286 smux_snmp_select_list_del(sd);
1287 }
1288 }
1289 }
1290 /*
1291 * new connection
1292 */
1293 if (NETSNMP_LARGE_FD_ISSET(smux_listen_sd, &readfds)) {
1294 if ((sd = smux_accept(smux_listen_sd)) >= 0) {
1295 smux_snmp_select_list_add(sd);
1296 }
1297 }
1298 }
1299
1300 #endif /* USING_SMUX_MODULE */
1301
1302 #ifndef NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER
1303 netsnmp_dispatch_external_events2(&count, &readfds,
1304 &writefds, &exceptfds);
1305 #endif /* NETSNMP_FEATURE_REMOVE_FD_EVENT_MANAGER */
1306
1307 /* If there are still events leftover, process them */
1308 if (count > 0) {
1309 snmp_read2(&readfds);
1310 }
1311 } else
1312 switch (count) {
1313 case 0:
1314 snmp_timeout();
1315 break;
1316 case -1:
1317 DEBUGMSGTL(("snmpd/select", " errno = %d\n", errno));
1318 if (errno == EINTR) {
1319 /*
1320 * likely that we got a signal. Check our special signal
1321 * flags before retrying select.
1322 */
1323 if (netsnmp_running && !reconfig) {
1324 goto reselect;
1325 }
1326 continue;
1327 } else {
1328 snmp_log_perror("select");
1329 }
1330 return -1;
1331 default:
1332 snmp_log(LOG_ERR, "select returned %d\n", count);
1333 return -1;
1334 } /* endif -- count>0 */
1335
1336 /*
1337 * see if persistent store needs to be saved
1338 */
1339 snmp_store_if_needed();
1340
1341 /*
1342 * run requested alarms
1343 */
1344 run_alarms();
1345
1346 netsnmp_check_outstanding_agent_requests();
1347
1348 } /* endwhile */
1349
1350 netsnmp_large_fd_set_cleanup(&readfds);
1351 netsnmp_large_fd_set_cleanup(&writefds);
1352 netsnmp_large_fd_set_cleanup(&exceptfds);
1353
1354 #if defined(WIN32)
1355 join_stdin_waiter_thread();
1356 #endif
1357
1358 snmp_log(LOG_INFO, "Received TERM or STOP signal... shutting down...\n");
1359 return 0;
1360
1361 } /* end receive() */
1362
1363
1364
1365 /*******************************************************************-o-******
1366 * snmp_input
1367 *
1368 * Parameters:
1369 * op
1370 * *session
1371 * requid
1372 * *pdu
1373 * *magic
1374 *
1375 * Returns:
1376 * 1 On success -OR-
1377 * Passes through Return from alarmGetResponse() when
1378 * USING_V2PARTY_ALARM_MODULE is defined.
1379 *
1380 * Call-back function to manage responses to traps (informs) and alarms.
1381 * Not used by the agent to process other Response PDUs.
1382 */
1383 int
snmp_input(int op,netsnmp_session * session,int reqid,netsnmp_pdu * pdu,void * magic)1384 snmp_input(int op,
1385 netsnmp_session * session,
1386 int reqid, netsnmp_pdu *pdu, void *magic)
1387 {
1388 struct get_req_state *state = (struct get_req_state *) magic;
1389
1390 if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
1391 if (pdu->command == SNMP_MSG_GET) {
1392 if (state->type == EVENT_GET_REQ) {
1393 /*
1394 * this is just the ack to our inform pdu
1395 */
1396 return 1;
1397 }
1398 }
1399 } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
1400 if (state->type == ALARM_GET_REQ) {
1401 /*
1402 * Need a mechanism to replace obsolete SNMPv2p alarm
1403 */
1404 }
1405 }
1406 return 1;
1407
1408 } /* end snmp_input() */
1409
1410
1411
1412 /*
1413 * Windows Service Related functions
1414 */
1415 #ifdef WIN32SERVICE
1416 /************************************************************
1417 * main function for Windows
1418 * Parse command line arguments for startup options,
1419 * to start as service or console mode application in windows.
1420 * Invokes appropriate startup functions depending on the
1421 * parameters passed
1422 *************************************************************/
1423 int __cdecl
main(int argc,TCHAR * argv[])1424 main(int argc, TCHAR * argv[])
1425 {
1426 /*
1427 * Define Service Name and Description, which appears in windows SCM
1428 */
1429 LPCTSTR lpszServiceName = app_name_long; /* Service Registry Name */
1430 LPCTSTR lpszServiceDisplayName = _T("Net-SNMP Agent"); /* Display Name */
1431 LPCTSTR lpszServiceDescription =
1432 #ifdef IFDESCR
1433 _T("SNMPv2c / SNMPv3 command responder from Net-SNMP. Supports MIB objects for IP,ICMP,TCP,UDP, and network interface sub-layers.");
1434 #else
1435 _T("SNMPv2c / SNMPv3 command responder from Net-SNMP");
1436 #endif
1437 InputParams InputOptions;
1438
1439
1440 enum net_snmp_cmd_line_action nRunType = RUN_AS_CONSOLE;
1441 int quiet = 0;
1442
1443 #if 0
1444 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF /*| _CRTDBG_CHECK_ALWAYS_DF*/);
1445 #endif
1446
1447 nRunType = ParseCmdLineForServiceOption(argc, argv, &quiet);
1448
1449 switch (nRunType) {
1450 case REGISTER_SERVICE:
1451 /*
1452 * Register As service
1453 */
1454 InputOptions.Argc = argc;
1455 InputOptions.Argv = argv;
1456 return RegisterService(lpszServiceName,
1457 lpszServiceDisplayName,
1458 lpszServiceDescription, &InputOptions, quiet);
1459 case UN_REGISTER_SERVICE:
1460 /*
1461 * Unregister service
1462 */
1463 return UnregisterService(lpszServiceName, quiet);
1464 case RUN_AS_SERVICE:
1465 /*
1466 * Run as service
1467 */
1468 /*
1469 * Register Stop Function
1470 */
1471 RegisterStopFunction(StopSnmpAgent);
1472 return RunAsService(SnmpDaemonMain);
1473 default:
1474 /*
1475 * Run in console mode
1476 */
1477 return SnmpDaemonMain(argc, argv);
1478 }
1479 }
1480
1481 /*
1482 * To stop Snmp Agent daemon
1483 * This portion is still not working
1484 */
1485 void
StopSnmpAgent(void)1486 StopSnmpAgent(void)
1487 {
1488 /*
1489 * Shut Down Agent
1490 */
1491 SnmpdShutDown(1);
1492
1493 /*
1494 * Wait till agent is completely stopped
1495 */
1496
1497 while (agent_status != AGENT_STOPPED) {
1498 Sleep(100);
1499 }
1500 }
1501
1502 #endif /*WIN32SERVICE*/
1503