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