and added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / snmpd.c
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 /*
8  * Copyright 1988, 1989 by Carnegie Mellon University
9  *
10  * All Rights Reserved
11  *
12  * Permission to use, copy, modify, and distribute this software and its
13  * documentation for any purpose and without fee is hereby granted,
14  * provided that the above copyright notice appear in all copies and that
15  * both that copyright notice and this permission notice appear in
16  * supporting documentation, and that the name of CMU not be
17  * used in advertising or publicity pertaining to distribution of the
18  * software without specific, written prior permission.
19  *
20  * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22  * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26  * SOFTWARE.
27  * *****************************************************************
28  */
29 #include <net-snmp/net-snmp-config.h>
30
31 #include <stdio.h>
32 #include <errno.h>
33 #if HAVE_STRING_H
34 #include <string.h>
35 #else
36 #include <strings.h>
37 #endif
38 #if HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #if HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #include <sys/types.h>
45 #if HAVE_NETINET_IN_H
46 #include <netinet/in.h>
47 #endif
48 #if HAVE_ARPA_INET_H
49 #include <arpa/inet.h>
50 #endif
51 #if TIME_WITH_SYS_TIME
52 # ifdef WIN32
53 #  include <sys/timeb.h>
54 # else
55 #  include <sys/time.h>
56 # endif
57 # include <time.h>
58 #else
59 # if HAVE_SYS_TIME_H
60 #  include <sys/time.h>
61 # else
62 #  include <time.h>
63 # endif
64 #endif
65 #if HAVE_SYS_SELECT_H
66 #include <sys/select.h>
67 #endif
68 #if HAVE_SYS_SOCKET_H
69 #include <sys/socket.h>
70 #elif HAVE_WINSOCK_H
71 #include <winsock.h>
72 #endif
73 #if HAVE_NET_IF_H
74 #include <net/if.h>
75 #endif
76 #if HAVE_INET_MIB2_H
77 #include <inet/mib2.h>
78 #endif
79 #if HAVE_SYS_IOCTL_H
80 #include <sys/ioctl.h>
81 #endif
82 #if HAVE_SYS_FILE_H
83 #include <sys/file.h>
84 #endif
85 #ifdef HAVE_FCNTL_H
86 #include <fcntl.h>
87 #endif
88 #if HAVE_SYS_WAIT_H
89 #include <sys/wait.h>
90 #endif
91 #include <signal.h>
92 #ifdef HAVE_SYS_PARAM_H
93 #include <sys/param.h>
94 #endif
95 #if HAVE_PROCESS_H              /* Win32-getpid */
96 #include <process.h>
97 #endif
98 #if HAVE_LIMITS_H
99 #include <limits.h>
100 #endif
101 #if HAVE_PWD_H
102 #include <pwd.h>
103 #endif
104 #if HAVE_GRP_H
105 #include <grp.h>
106 #endif
107
108 #ifndef PATH_MAX
109 # ifdef _POSIX_PATH_MAX
110 #  define PATH_MAX _POSIX_PATH_MAX
111 # else
112 #  define PATH_MAX 255
113 # endif
114 #endif
115
116 #ifndef FD_SET
117 typedef long    fd_mask;
118 #define NFDBITS (sizeof(fd_mask) * NBBY)        /* bits per mask */
119 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
120 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
121 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
122 #define FD_ZERO(p)      memset((p), 0, sizeof(*(p)))
123 #endif
124
125 #if HAVE_DMALLOC_H
126 #include <dmalloc.h>
127 #endif
128
129 #include <net-snmp/net-snmp-includes.h>
130 #include <net-snmp/agent/net-snmp-agent-includes.h>
131
132 #include "m2m.h"
133 #include <net-snmp/agent/mib_module_config.h>
134
135 #include "snmpd.h"
136 #include "mibgroup/struct.h"
137 #include <net-snmp/agent/mib_modules.h>
138
139 #include "mibgroup/util_funcs.h"
140
141 #include <net-snmp/agent/agent_trap.h>
142
143 #include <net-snmp/agent/table.h>
144 #include <net-snmp/agent/table_iterator.h>
145 #include "mib_module_includes.h"
146
147 /*
148  * Include winservice.h to support Windows Service
149  */
150 #ifdef WIN32
151 #include <windows.h>
152 #include <tchar.h>
153 #include <net-snmp/library/winservice.h>
154 #endif
155
156 /*
157  * Globals.
158  */
159 #ifdef USE_LIBWRAP
160 #include <tcpd.h>
161 #endif                          /* USE_LIBWRAP */
162
163 #define TIMETICK         500000L
164
165 int             snmp_dump_packet;
166 int             running = 1;
167 int             reconfig = 0;
168 int             Facility = LOG_DAEMON;
169
170 #ifdef WIN32
171 /*
172  * SNMP Agent Status
173  */
174 #define AGENT_RUNNING 1
175 #define AGENT_STOPPED 0
176 int             agent_status = AGENT_STOPPED;
177 LPTSTR          g_szAppName = _T("Net-Snmp Agent");     /* Application Name */
178 #endif
179
180 extern char   **argvrestartp;
181 extern char    *argvrestart;
182 extern char    *argvrestartname;
183
184 #define NUM_SOCKETS     32
185
186 #ifdef USING_SMUX_MODULE
187 static int      sdlist[NUM_SOCKETS], sdlen = 0;
188 #endif                          /* USING_SMUX_MODULE */
189
190 /*
191  * Prototypes.
192  */
193 int             snmp_read_packet(int);
194 int             snmp_input(int, netsnmp_session *, int, netsnmp_pdu *,
195                            void *);
196 static void     usage(char *);
197 static void     SnmpTrapNodeDown(void);
198 static int      receive(void);
199 #ifdef WIN32
200 void            StopSnmpAgent(void);
201 int             SnmpDaemonMain(int argc, TCHAR * argv[]);
202 int __cdecl     _tmain(int argc, TCHAR * argv[]);
203 #else
204 int             SnmpDaemonMain(int, char **);
205 #endif
206
207 /*
208  * These definitions handle 4.2 systems without additional syslog facilities.
209  */
210 #ifndef LOG_CONS
211 #define LOG_CONS        0       /* Don't bother if not defined... */
212 #endif
213 #ifndef LOG_PID
214 #define LOG_PID         0       /* Don't bother if not defined... */
215 #endif
216 #ifndef LOG_LOCAL0
217 #define LOG_LOCAL0      0
218 #endif
219 #ifndef LOG_LOCAL1
220 #define LOG_LOCAL1      0
221 #endif
222 #ifndef LOG_LOCAL2
223 #define LOG_LOCAL2      0
224 #endif
225 #ifndef LOG_LOCAL3
226 #define LOG_LOCAL3      0
227 #endif
228 #ifndef LOG_LOCAL4
229 #define LOG_LOCAL4      0
230 #endif
231 #ifndef LOG_LOCAL5
232 #define LOG_LOCAL5      0
233 #endif
234 #ifndef LOG_LOCAL6
235 #define LOG_LOCAL6      0
236 #endif
237 #ifndef LOG_LOCAL7
238 #define LOG_LOCAL7      0
239 #endif
240 #ifndef LOG_DAEMON
241 #define LOG_DAEMON      0
242 #endif
243
244
245 static void
246 usage(char *prog)
247 {
248 #ifdef WIN32
249     printf("\nUsage:  %s [-register] [OPTIONS] [LISTENING ADDRESSES]",
250            prog);
251     printf("\n        %s -unregister", prog);
252 #else
253     printf("\nUsage:  %s [OPTIONS] [LISTENING ADDRESSES]", prog);
254 #endif
255     printf("\n");
256     printf("\n\tVersion:  %s\n", netsnmp_get_version());
257     printf("\tWeb:      http://www.net-snmp.org/\n");
258     printf("\tEmail:    net-snmp-coders@lists.sourceforge.net\n");
259     printf("\n  -a\t\t\tlog addresses\n");
260     printf("  -A\t\t\tappend to the logfile rather than truncating it\n");
261     printf("  -c FILE\t\tread FILE as a configuration file\n");
262     printf("  -C\t\t\tdo not read the default configuration files\n");
263     printf("  -d\t\t\tdump sent and received SNMP packets\n");
264     printf("  -D\t\t\tturn on debugging output\n");
265     printf("  -f\t\t\tdo not fork from the shell\n");
266 #if HAVE_UNISTD_H
267     printf("  -g GID\t\tchange to this numeric gid after opening\n"
268            "\t\t\t  transport endpoints\n");
269 #endif
270     printf("  -h, --help\t\tdisplay this usage message\n");
271     printf("  -H\t\t\tdisplay configuration file directives understood\n");
272     printf("  -I [-]INITLIST\tlist of mib modules to initialize (or not)\n");
273     printf("\t\t\t  (run snmpd with -Dmib_init for a list)\n");
274     printf("  -l FILE\t\tprint warnings/messages to FILE\n");
275 #ifdef LOGFILE
276     printf("\t\t\t  (by default FILE=%s)\n", LOGFILE);
277 #else
278     printf("\t\t\t  (by default FILE=none)\n");
279 #endif
280     printf("  -L\t\t\tprint warnings/messages to stdout/err\n");
281     printf("  -P FILE\t\tstore process id in FILE\n");
282     printf("  -q\t\t\tprint information in a more parsable format\n");
283     printf("  -r\t\t\tdo not exit if files only accessible to root\n"
284            "\t\t\t  cannot be opened\n");
285 #ifdef WIN32
286     printf("  -register\t\tregister as a Windows service\n");
287     printf("  \t\t\t  (followed by the startup parameter list)\n");
288     printf("  \t\t\t  Note that not all parameters are relevant when running as a service\n");
289 #endif
290     printf("  -s\t\t\tlog warnings/messages to syslog\n");
291     printf("  -S d|i|0-7\t\tset syslog facility to LOG_DAEMON (d), LOG_INFO (i)\n\t\t\t  or LOG_LOCAL[0-7] (default LOG_DAEMON)\n");
292 #if HAVE_UNISTD_H
293     printf("  -u UID\t\tchange to this uid (numeric or textual) after\n"
294            "\t\t\t  opening transport endpoints\n");
295 #endif
296 #ifdef WIN32
297     printf("  -unregister\t\tunregister as a Windows service\n");
298 #endif
299     printf("  -v, --version\t\tdisplay version information\n");
300     printf("  -V\t\t\tverbose display\n");
301 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
302     printf("  -x ADDRESS\t\tuse ADDRESS as AgentX address\n");
303 #endif
304 #ifdef USING_AGENTX_SUBAGENT_MODULE
305     printf("  -X\t\t\trun as an AgentX subagent rather than as an\n"
306            "\t\t\t  SNMP master agent\n");
307 #endif
308
309     printf("\n");
310     exit(1);
311 }
312
313 static void
314 version(void)
315 {
316     printf("\nNET-SNMP version:  %s\n", netsnmp_get_version());
317     printf("Web:               http://www.net-snmp.org/\n");
318     printf("Email:             net-snmp-coders@lists.sourceforge.net\n\n");
319     exit(0);
320 }
321
322 RETSIGTYPE
323 SnmpdShutDown(int a)
324 {
325 #ifdef WIN32
326     extern netsnmp_session *main_session;
327 #endif
328     running = 0;
329 #ifdef WIN32
330     /*
331      * In case of windows, select() in receive() function will not return
332      * on signal. Thats why following function is called, which closes the
333      * socket descriptors and causes the select() to return
334      */
335     snmp_close(main_session);
336 #endif
337 }
338
339 #ifdef SIGHUP
340 RETSIGTYPE
341 SnmpdReconfig(int a)
342 {
343     reconfig = 1;
344     signal(SIGHUP, SnmpdReconfig);
345 }
346 #endif
347
348 #ifdef SIGUSR1
349 #ifdef BRCM_SNMP_DEBUG
350 extern void     dump_registry(void);
351 #endif
352 RETSIGTYPE
353 SnmpdDump(int a)
354 {
355 #ifdef BRCM_SNMP_DEBUG
356     dump_registry();
357 #endif
358     signal(SIGUSR1, SnmpdDump);
359 }
360 #endif
361
362
363 static void
364 SnmpTrapNodeDown(void)
365 {
366 #ifdef BRCM_SNMP_NOT_USED
367     send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 2);
368 #endif
369     /*
370      * XXX  2 - Node Down #define it as NODE_DOWN_TRAP
371      */
372 }
373
374 static void
375 setup_log(int restart, int dont_zero, int stderr_log, int syslog_log, 
376           char *logfile)
377 {
378     static char logfile_s[PATH_MAX + 1] = { 0 };
379     static int dont_zero_s  = 0;
380     static int stderr_log_s = 0;
381     static int syslog_log_s = 0;
382
383     if (restart == 0) {
384         if (logfile != NULL) {
385             strncpy(logfile_s, logfile, PATH_MAX);
386         }
387         dont_zero_s  = dont_zero;
388         stderr_log_s = stderr_log;
389         syslog_log_s = syslog_log;
390     }
391
392     if (stderr_log_s) {
393         snmp_enable_stderrlog();
394     } else {
395         snmp_disable_stderrlog();
396     }
397
398     if (logfile_s[0]) {
399         snmp_enable_filelog(logfile_s, dont_zero_s);
400     }
401
402     if (syslog_log_s) {
403         snmp_enable_syslog_ident("snmpd", Facility);
404     }
405 }
406
407 /*******************************************************************-o-******
408  * SnmpDaemonMain - Non Windows
409  * SnmpDeamonMain - Windows to support windows serivce
410  *
411  * Parameters:
412  *       argc
413  *      *argv[]
414  *
415  * Returns:
416  *      0       Always succeeds.  (?)
417  *
418  *
419  * Setup and start the agent daemon.
420  *
421  * Also successfully EXITs with zero for some options.
422  */
423 int
424 #ifdef WIN32
425 SnmpDaemonMain(int argc, TCHAR * argv[])
426 #else
427 #ifdef BUILD_STATIC
428 snmp_main(int argc, char *argv[])
429 #else
430 main(int argc, char *argv[])
431 #endif
432 #endif
433 {
434     int             isConfigFileProvided;
435     char            options[128] = "aAc:CdD::fhHI:l:LP:qrsS:UvV-:";
436     int             arg, i, ret;
437     int             dont_fork = 0;
438     int             dont_zero_log = 0;
439     int             stderr_log = 0, syslog_log = 0;
440     int             uid = 0, gid = 0;
441     int             agent_mode = -1;
442     char            logfile[PATH_MAX + 1] = { 0 };
443     char           *cptr, **argvptr;
444     char           *pid_file = NULL;
445 #if HAVE_GETPID
446     FILE           *PID;
447 #endif
448
449 #ifdef LOGFILE
450     strncpy(logfile, LOGFILE, PATH_MAX);
451 #endif
452
453 #ifdef NO_ROOT_ACCESS
454     /*
455      * Default to no.
456      */
457     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
458                            NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
459 #endif
460     /*
461      * Default to NOT running an AgentX master.
462      */
463     netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
464                            NETSNMP_DS_AGENT_AGENTX_MASTER, 0);
465     netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
466                        NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1);
467     netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
468                        NETSNMP_DS_AGENT_AGENTX_RETRIES, -1);
469
470     /*
471      * Add some options if they are available.
472      */
473 #if HAVE_UNISTD_H
474     strcat(options, "g:u:");
475 #endif
476 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
477     strcat(options, "x:");
478 #endif
479 #ifdef USING_AGENTX_SUBAGENT_MODULE
480     strcat(options, "X");
481 #endif
482
483    isConfigFileProvided = 0;
484
485     /*
486      * Now process options normally.
487      */
488
489     while ((arg = getopt(argc, argv, options)) != EOF) {
490         switch (arg) {
491         case '-':
492             if (strcasecmp(optarg, "help") == 0) {
493                 usage(argv[0]);
494             }
495             if (strcasecmp(optarg, "version") == 0) {
496                 version();
497             }
498
499             handle_long_opt(optarg);
500             break;
501
502         case 'a':
503             log_addresses++;
504             break;
505
506         case 'A':
507             dont_zero_log = 1;
508             break;
509
510         case 'c':
511             isConfigFileProvided = 1;
512             snmp_log(LOG_WARNING, "optarg = %s\n", optarg);
513             if (optarg != NULL) {
514                 netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
515                                       NETSNMP_DS_LIB_OPTIONALCONFIG, optarg);
516             } else {
517                 usage(argv[0]);
518             }
519             break;
520
521         case 'C':
522             netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
523                                    NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
524             break;
525
526         case 'd':
527             snmp_set_dump_packet(++snmp_dump_packet);
528             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
529                                    NETSNMP_DS_AGENT_VERBOSE, 1);
530             break;
531
532         case 'D':
533             debug_register_tokens(optarg);
534             snmp_set_do_debugging(1);
535             break;
536
537         case 'f':
538             dont_fork = 1;
539             break;
540
541 #if HAVE_UNISTD_H
542         case 'g':
543             if (optarg != NULL) {
544                 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
545                                    NETSNMP_DS_AGENT_GROUPID, atoi(optarg));
546             } else {
547                 usage(argv[0]);
548             }
549             break;
550 #endif
551
552         case 'h':
553             usage(argv[0]);
554             break;
555
556         case 'H':
557             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
558                                    NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
559             init_agent("snmpd");        /* register our .conf handlers */
560             init_mib_modules();
561             init_snmp("snmpd");
562             fprintf(stderr, "Configuration directives understood:\n");
563             read_config_print_usage("  ");
564             exit(0);
565
566         case 'I':
567             if (optarg != NULL) {
568                 add_to_init_list(optarg);
569             } else {
570                 usage(argv[0]);
571             }
572             break;
573
574         case 'l':
575             if (optarg != NULL) {
576                 if (strlen(optarg) > PATH_MAX) {
577                     fprintf(stderr,
578                             "%s: logfile path too long (limit %d chars)\n",
579                             argv[0], PATH_MAX);
580                     exit(1);
581                 }
582                 strncpy(logfile, optarg, PATH_MAX);
583             } else {
584                 usage(argv[0]);
585             }
586             break;
587
588         case 'L':
589             stderr_log = 1;
590             break;
591
592         case 'P':
593             if (optarg != NULL) {
594                 pid_file = optarg;
595             } else {
596                 usage(argv[0]);
597             }
598             break;
599
600         case 'q':
601             snmp_set_quick_print(1);
602             break;
603
604         case 'r':
605             netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID,
606                                       NETSNMP_DS_AGENT_NO_ROOT_ACCESS);
607             break;
608
609         case 's':
610             syslog_log = 1;
611             break;
612
613         case 'S':
614             if (optarg != NULL) {
615                 switch (*optarg) {
616                 case 'd':
617                 case 'D':
618                     Facility = LOG_DAEMON;
619                     break;
620                 case 'i':
621                 case 'I':
622                     Facility = LOG_INFO;
623                     break;
624                 case '0':
625                     Facility = LOG_LOCAL0;
626                     break;
627                 case '1':
628                     Facility = LOG_LOCAL1;
629                     break;
630                 case '2':
631                     Facility = LOG_LOCAL2;
632                     break;
633                 case '3':
634                     Facility = LOG_LOCAL3;
635                     break;
636                 case '4':
637                     Facility = LOG_LOCAL4;
638                     break;
639                 case '5':
640                     Facility = LOG_LOCAL5;
641                     break;
642                 case '6':
643                     Facility = LOG_LOCAL6;
644                     break;
645                 case '7':
646                     Facility = LOG_LOCAL7;
647                     break;
648                 default:
649                     fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg);
650                     usage(argv[0]);
651                 }
652             } else {
653                 fprintf(stderr, "no syslog facility specified\n");
654                 usage(argv[0]);
655             }
656             break;
657
658         case 'U':
659             netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, 
660                                       NETSNMP_DS_AGENT_LEAVE_PIDFILE);
661             break;
662
663 #if HAVE_UNISTD_H
664         case 'u':
665             if (optarg != NULL) {
666                 char           *ecp;
667                 int             uid;
668
669                 uid = strtoul(optarg, &ecp, 10);
670                 if (*ecp) {
671 #if HAVE_GETPWNAM && HAVE_PWD_H
672                     struct passwd  *info;
673                     info = getpwnam(optarg);
674                     if (info) {
675                         uid = info->pw_uid;
676                     } else {
677 #endif
678                         fprintf(stderr, "Bad user id: %s\n", optarg);
679                         exit(1);
680 #if HAVE_GETPWNAM && HAVE_PWD_H
681                     }
682 #endif
683                 }
684                 netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID,
685                                    NETSNMP_DS_AGENT_USERID, uid);
686             } else {
687                 usage(argv[0]);
688             }
689             break;
690 #endif
691
692         case 'v':
693             version();
694
695         case 'V':
696             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
697                                    NETSNMP_DS_AGENT_VERBOSE, 1);
698             break;
699
700 #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE)
701         case 'x':
702             if (optarg != NULL) {
703                 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
704                                       NETSNMP_DS_AGENT_X_SOCKET, optarg);
705             } else {
706                 usage(argv[0]);
707             }
708             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
709                                    NETSNMP_DS_AGENT_AGENTX_MASTER, 1);
710             break;
711 #endif
712
713         case 'X':
714 #if defined(USING_AGENTX_SUBAGENT_MODULE)
715             agent_mode = SUB_AGENT;
716 #else
717             fprintf(stderr, "%s: Illegal argument -X:"
718                             "AgentX support not compiled in.\n", argv[0]);
719             usage(argv[0]);
720             exit(1);
721 #endif
722             break;
723
724         default:
725             usage(argv[0]);
726             break;
727         }
728     }
729
730     if ( isConfigFileProvided == 0 )
731     {
732       /* If the config file was not provided on the
733       ** command line, use the default SNMP configuration file*/
734       netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID,
735                                       NETSNMP_DS_LIB_OPTIONALCONFIG, "/var/snmpd.conf");
736     }
737
738     if (optind < argc) {
739         /*
740          * There are optional transport addresses on the command line.
741          */
742         DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc));
743         for (i = optind; i < argc; i++) {
744             char *c, *astring;
745             if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
746                                            NETSNMP_DS_AGENT_PORTS))) {
747                 astring = malloc(strlen(c) + 2 + strlen(argv[i]));
748                 if (astring == NULL) {
749                     fprintf(stderr, "malloc failure processing argv[%d]\n", i);
750                     exit(1);
751                 }
752                 sprintf(astring, "%s,%s", c, argv[i]);
753                 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
754                                       NETSNMP_DS_AGENT_PORTS, astring);
755                 free(astring);
756             } else {
757                 netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID,
758                                       NETSNMP_DS_AGENT_PORTS, argv[i]);
759             }
760         }
761         DEBUGMSGTL(("snmpd/main", "port spec: %s\n",
762                     netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
763                                           NETSNMP_DS_AGENT_PORTS)));
764     }
765
766     setup_log(0, dont_zero_log, stderr_log, syslog_log, logfile);
767
768     /*
769      * Initialize a argv set to the current for restarting the agent.
770      */
771     argvrestartp = (char **)malloc((argc + 2) * sizeof(char *));
772     argvptr = argvrestartp;
773     for (i = 0, ret = 1; i < argc; i++) {
774         ret += strlen(argv[i]) + 1;
775     }
776     argvrestart = (char *) malloc(ret);
777     argvrestartname = (char *) malloc(strlen(argv[0]) + 1);
778     if (!argvrestartp || !argvrestart || !argvrestartname) {
779         fprintf(stderr, "malloc failure processing argvrestart\n");
780         exit(1);
781     }
782     strcpy(argvrestartname, argv[0]);
783     if (agent_mode == -1) {
784         if (strstr(argvrestartname, "agentxd") != NULL) {
785             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
786                                    NETSNMP_DS_AGENT_ROLE, SUB_AGENT);
787         } else {
788             netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
789                                    NETSNMP_DS_AGENT_ROLE, MASTER_AGENT);
790         }
791     } else {
792         netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
793                                NETSNMP_DS_AGENT_ROLE, agent_mode);
794     }
795
796     for (cptr = argvrestart, i = 0; i < argc; i++) {
797         strcpy(cptr, argv[i]);
798         *(argvptr++) = cptr;
799         cptr += strlen(argv[i]) + 1;
800     }
801     *cptr = 0;
802     *argvptr = NULL;
803
804 #ifdef BUFSIZ
805     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
806 #endif
807     /*
808      * Initialize the world.  Detach from the shell.  Create initial user.
809      */
810 #if HAVE_FORK
811     if (!dont_fork) {
812         /*
813          * Fork to return control to the invoking process and to
814          * guarantee that we aren't a process group leader.
815          */
816         if (fork() != 0) {
817             /* Parent. */
818             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
819                                         NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) {
820                 exit(0);
821             }
822         } else {
823             /* Child. */
824 #ifdef HAVE_SETSID
825             /* Become a process/session group leader. */
826             setsid();
827 #endif
828             /*
829              * Fork to let the process/session group leader exit.
830              */
831             if (fork() != 0) {
832                 /* Parent. */
833                 exit(0);
834             }
835 #ifndef WIN32
836             else {
837                 /* Child. */
838
839                 /* Avoid keeping any directory in use. */
840                 chdir("/");
841
842                 if (!stderr_log) {
843                     /*
844                      * Close inherited file descriptors to avoid
845                      * keeping unnecessary references.
846                      */
847                     close(0);
848                     close(1);
849                     close(2);
850
851                     /*
852                      * Redirect std{in,out,err} to /dev/null, just in
853                      * case.
854                      */
855                     open("/dev/null", O_RDWR);
856                     dup(0);
857                     dup(0);
858                 }
859             }
860 #endif /* !WIN32 */
861         }
862     }
863 #endif /* HAVE_FORK */
864
865     SOCK_STARTUP;
866     init_agent("snmpd");        /* do what we need to do first. */
867     init_mib_modules();
868
869     /*
870      * start library
871      */
872     init_snmp("snmpd");
873
874     if ((ret = init_master_agent()) != 0) {
875         /*
876          * Some error opening one of the specified agent transports.
877          */
878         Exit(1);                /*  Exit logs exit val for us  */
879     }
880 #ifdef SIGTERM
881     DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n"));
882     signal(SIGTERM, SnmpdShutDown);
883 #endif
884 #ifdef SIGINT
885     DEBUGMSGTL(("signal", "registering SIGINT signal handler\n"));
886     signal(SIGINT, SnmpdShutDown);
887 #endif
888 #ifdef SIGHUP
889     DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n"));
890     signal(SIGHUP, SnmpdReconfig);
891 #endif
892 #ifdef SIGUSR1
893     DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n"));
894     signal(SIGUSR1, SnmpdDump);
895 #endif
896 #ifdef SIGPIPE
897     DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n"));
898     signal(SIGPIPE, SIG_IGN);   /* 'Inline' failure of wayward readers */
899 #endif
900
901     /*
902      * Store persistent data immediately in case we crash later.
903      */
904     snmp_store("snmpd");
905
906     /*
907      * Send coldstart trap if possible.
908      */
909     send_easy_trap(0, 0);
910
911 #if HAVE_GETPID
912     if (pid_file != NULL) {
913         if ((PID = fopen(pid_file, "w")) == NULL) {
914             snmp_log_perror(pid_file);
915             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
916                                         NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
917                 exit(1);
918             }
919         } else {
920             fprintf(PID, "%d\n", (int) getpid());
921             fclose(PID);
922         }
923     }
924 #endif
925
926 #if HAVE_UNISTD_H
927 #ifdef HAVE_SETGID
928     if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
929                                   NETSNMP_DS_AGENT_GROUPID)) != 0) {
930         DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid));
931         if (setgid(gid) == -1
932 #ifdef HAVE_SETGROUPS
933             || setgroups(1, (gid_t *)&gid) == -1
934 #endif
935             ) {
936             snmp_log_perror("setgid failed");
937             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
938                                         NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
939                 exit(1);
940             }
941         }
942     }
943 #endif
944 #ifdef HAVE_SETUID
945     if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
946                                   NETSNMP_DS_AGENT_USERID)) != 0) {
947         DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid));
948         if (setuid(uid) == -1) {
949             snmp_log_perror("setuid failed");
950             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
951                                         NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
952                 exit(1);
953             }
954         }
955     }
956 #endif
957 #endif
958
959     /*
960      * We're up, log our version number.
961      */
962     snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version());
963 #ifdef WIN32
964     agent_status = AGENT_RUNNING;
965 #endif
966     netsnmp_addrcache_initialise();
967
968     /*
969      * Forever monitor the dest_port for incoming PDUs.
970      */
971     DEBUGMSGTL(("snmpd/main", "We're up.  Starting to process data.\n"));
972
973 #if 0
974 #ifdef BUILD_ILMI /* testing only */
975     extern int autoconfig_init(char *pvcAddrStr);
976 #ifdef SNMP_TRANSPORT_AAL5PVC_DOMAIN
977     /* defined in \include\net-snmp\net-snmp-config.h */
978     autoconfig_init("pvc:0.0.16");
979 #else
980     autoconfig_init("udp:192.168.1.10:162");
981 #endif
982 #endif /* BUILD_ILMI */
983 #endif /* 0 */
984
985     if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
986                                 NETSNMP_DS_AGENT_QUIT_IMMEDIATELY))
987         receive();
988 #include "mib_module_shutdown.h"
989     DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n"));
990     SnmpTrapNodeDown();
991     DEBUGMSGTL(("snmpd/main", "Bye...\n"));
992     snmp_shutdown("snmpd");
993     if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
994                                 NETSNMP_DS_AGENT_LEAVE_PIDFILE) &&
995         (pid_file != NULL)) {
996         unlink(pid_file);
997     }
998 #ifdef WIN32
999     agent_status = AGENT_STOPPED;
1000 #endif
1001     return 0;
1002 }                               /* End main() -- snmpd */
1003
1004 /*******************************************************************-o-******
1005  * receive
1006  *
1007  * Parameters:
1008  *
1009  * Returns:
1010  *      0       On success.
1011  *      -1      System error.
1012  *
1013  * Infinite while-loop which monitors incoming messges for the agent.
1014  * Invoke the established message handlers for incoming messages on a per
1015  * port basis.  Handle timeouts.
1016  */
1017 static int
1018 receive(void)
1019 {
1020     int             numfds;
1021     fd_set          readfds, writefds, exceptfds;
1022     struct timeval  timeout, *tvp = &timeout;
1023     struct timeval  sched, *svp = &sched, now, *nvp = &now;
1024     int             count, block, i;
1025 #ifdef  USING_SMUX_MODULE
1026     int             sd;
1027 #endif                          /* USING_SMUX_MODULE */
1028
1029
1030     /*
1031      * Set the 'sched'uled timeout to the current time + one TIMETICK.
1032      */
1033     gettimeofday(nvp, (struct timezone *) NULL);
1034     svp->tv_usec = nvp->tv_usec + TIMETICK;
1035     svp->tv_sec = nvp->tv_sec;
1036
1037     while (svp->tv_usec >= ONE_SEC) {
1038         svp->tv_usec -= ONE_SEC;
1039         svp->tv_sec++;
1040     }
1041
1042     /*
1043      * Loop-forever: execute message handlers for sockets with data,
1044      * reset the 'sched'uler.
1045      */
1046     while (running) {
1047         if (reconfig) {
1048             reconfig = 0;
1049             snmp_log(LOG_INFO, "Reconfiguring daemon\n");
1050             /*  Stop and restart logging.  This allows logfiles to be
1051                 rotated etc.  */
1052             snmp_disable_log();
1053             setup_log(1, 0, 0, 0, NULL);
1054             snmp_log(LOG_INFO, "NET-SNMP version %s restarted\n",
1055                      netsnmp_get_version());
1056             update_config();
1057 #ifdef BRCM_SNMP_MIB_SUPPORT
1058             send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 3);
1059 #endif
1060         }
1061
1062         for (i = 0; i < NUM_EXTERNAL_SIGS; i++) {
1063             if (external_signal_scheduled[i]) {
1064                 external_signal_scheduled[i]--;
1065                 external_signal_handler[i](i);
1066             }
1067         }
1068
1069         tvp = &timeout;
1070         tvp->tv_sec = 0;
1071         tvp->tv_usec = TIMETICK;
1072
1073         numfds = 0;
1074         FD_ZERO(&readfds);
1075         FD_ZERO(&writefds);
1076         FD_ZERO(&exceptfds);
1077         block = 0;
1078         snmp_select_info(&numfds, &readfds, tvp, &block);
1079         if (block == 1) {
1080             tvp = NULL;         /* block without timeout */
1081         }
1082
1083 #ifdef  USING_SMUX_MODULE
1084         if (smux_listen_sd >= 0) {
1085             FD_SET(smux_listen_sd, &readfds);
1086             numfds =
1087                 smux_listen_sd >= numfds ? smux_listen_sd + 1 : numfds;
1088             for (i = 0; i < sdlen; i++) {
1089                 FD_SET(sdlist[i], &readfds);
1090                 numfds = sdlist[i] >= numfds ? sdlist[i] + 1 : numfds;
1091             }
1092         }
1093 #endif                          /* USING_SMUX_MODULE */
1094
1095         for (i = 0; i < external_readfdlen; i++) {
1096             FD_SET(external_readfd[i], &readfds);
1097             if (external_readfd[i] >= numfds)
1098                 numfds = external_readfd[i] + 1;
1099         }
1100         for (i = 0; i < external_writefdlen; i++) {
1101             FD_SET(external_writefd[i], &writefds);
1102             if (external_writefd[i] >= numfds)
1103                 numfds = external_writefd[i] + 1;
1104         }
1105         for (i = 0; i < external_exceptfdlen; i++) {
1106             FD_SET(external_exceptfd[i], &exceptfds);
1107             if (external_exceptfd[i] >= numfds)
1108                 numfds = external_exceptfd[i] + 1;
1109         }
1110
1111     reselect:
1112         DEBUGMSGTL(("snmpd/select", "select( numfds=%d, ..., tvp=%p)\n",
1113                     numfds, tvp));
1114         count = select(numfds, &readfds, &writefds, &exceptfds, tvp);
1115         DEBUGMSGTL(("snmpd/select", "returned, count = %d\n", count));
1116
1117         if (count > 0) {
1118
1119 #ifdef USING_SMUX_MODULE
1120             /*
1121              * handle the SMUX sd's
1122              */
1123             if (smux_listen_sd >= 0) {
1124                 for (i = 0; i < sdlen; i++) {
1125                     if (FD_ISSET(sdlist[i], &readfds)) {
1126                         if (smux_process(sdlist[i]) < 0) {
1127                             for (; i < (sdlen - 1); i++) {
1128                                 sdlist[i] = sdlist[i + 1];
1129                             }
1130                             sdlen--;
1131                         }
1132                     }
1133                 }
1134                 /*
1135                  * new connection
1136                  */
1137                 if (FD_ISSET(smux_listen_sd, &readfds)) {
1138                     if ((sd = smux_accept(smux_listen_sd)) >= 0) {
1139                         sdlist[sdlen++] = sd;
1140                     }
1141                 }
1142             }
1143 #endif                          /* USING_SMUX_MODULE */
1144
1145             snmp_read(&readfds);
1146
1147             for (i = 0; count && (i < external_readfdlen); i++) {
1148                 if (FD_ISSET(external_readfd[i], &readfds)) {
1149                     DEBUGMSGTL(("snmpd/select", "readfd[%d] = %d\n",
1150                                 i, external_readfd[i]));
1151                     external_readfdfunc[i] (external_readfd[i],
1152                                             external_readfd_data[i]);
1153                     FD_CLR(external_readfd[i], &readfds);
1154                     count--;
1155                 }
1156             }
1157             for (i = 0; count && (i < external_writefdlen); i++) {
1158                 if (FD_ISSET(external_writefd[i], &writefds)) {
1159                     DEBUGMSGTL(("snmpd/select", "writefd[%d] = %d\n",
1160                                 i, external_writefd[i]));
1161                     external_writefdfunc[i] (external_writefd[i],
1162                                              external_writefd_data[i]);
1163                     FD_CLR(external_writefd[i], &writefds);
1164                     count--;
1165                 }
1166             }
1167             for (i = 0; count && (i < external_exceptfdlen); i++) {
1168                 if (FD_ISSET(external_exceptfd[i], &exceptfds)) {
1169                     DEBUGMSGTL(("snmpd/select", "exceptfd[%d] = %d\n",
1170                                 i, external_exceptfd[i]));
1171                     external_exceptfdfunc[i] (external_exceptfd[i],
1172                                               external_exceptfd_data[i]);
1173                     FD_CLR(external_exceptfd[i], &exceptfds);
1174                     count--;
1175                 }
1176             }
1177
1178         } else
1179             switch (count) {
1180             case 0:
1181                 snmp_timeout();
1182                 break;
1183             case -1:
1184                 if (errno == EINTR) {
1185                     /*
1186                      * likely that we got a signal. Check our special signal
1187                      * flags before retrying select.
1188                      */
1189                     if (running && !reconfig) {
1190                         goto reselect;
1191                     }
1192                     continue;
1193                 } else {
1194                     snmp_log_perror("select");
1195                 }
1196                 return -1;
1197             default:
1198                 snmp_log(LOG_ERR, "select returned %d\n", count);
1199                 return -1;
1200             }                   /* endif -- count>0 */
1201
1202
1203
1204
1205         /*
1206          * If the time 'now' is greater than the 'sched'uled time, then:
1207          *
1208          *    Check alarm and event timers.
1209          *    Reset the 'sched'uled time to current time + one TIMETICK.
1210          *    Age the cache network addresses (from whom messges have
1211          *        been received).
1212          */
1213         gettimeofday(nvp, (struct timezone *)NULL);
1214
1215         if (nvp->tv_sec > svp->tv_sec || (nvp->tv_sec == svp->tv_sec &&
1216                                           nvp->tv_usec > svp->tv_usec)) {
1217             svp->tv_usec = nvp->tv_usec + TIMETICK;
1218             svp->tv_sec = nvp->tv_sec;
1219
1220             while (svp->tv_usec >= ONE_SEC) {
1221                 svp->tv_usec -= ONE_SEC;
1222                 svp->tv_sec++;
1223             }
1224             if (log_addresses && lastAddrAge++ > 600) {
1225                 netsnmp_addrcache_age();
1226             }
1227         }
1228
1229         /*
1230          * endif -- now>sched
1231          */
1232         /*
1233          * run requested alarms
1234          */
1235         run_alarms();
1236
1237         netsnmp_check_outstanding_agent_requests();
1238
1239     }                           /* endwhile */
1240
1241     snmp_log(LOG_INFO, "Received TERM or STOP signal...  shutting down...\n");
1242     return 0;
1243
1244 }                               /* end receive() */
1245
1246
1247
1248 /*******************************************************************-o-******
1249  * snmp_input
1250  *
1251  * Parameters:
1252  *       op
1253  *      *session
1254  *       requid
1255  *      *pdu
1256  *      *magic
1257  *
1258  * Returns:
1259  *      1               On success      -OR-
1260  *      Passes through  Return from alarmGetResponse() when
1261  *                        USING_V2PARTY_ALARM_MODULE is defined.
1262  *
1263  * Call-back function to manage responses to traps (informs) and alarms.
1264  * Not used by the agent to process other Response PDUs.
1265  */
1266 int
1267 snmp_input(int op,
1268            netsnmp_session * session,
1269            int reqid, netsnmp_pdu *pdu, void *magic)
1270 {
1271     struct get_req_state *state = (struct get_req_state *) magic;
1272
1273     if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
1274         if (pdu->command == SNMP_MSG_GET) {
1275             if (state->type == EVENT_GET_REQ) {
1276                 /*
1277                  * this is just the ack to our inform pdu
1278                  */
1279                 return 1;
1280             }
1281         }
1282     } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
1283         if (state->type == ALARM_GET_REQ) {
1284             /*
1285              * Need a mechanism to replace obsolete SNMPv2p alarm
1286              */
1287         }
1288     }
1289     return 1;
1290
1291 }                               /* end snmp_input() */
1292
1293
1294
1295 /*
1296  * Windows Service Related functions
1297  */
1298 #ifdef WIN32
1299 /************************************************************
1300 * main function for Windows
1301 * Parse command line arguments for startup options,
1302 * to start as service or console mode application in windows.
1303 * Invokes appropriate startup funcitons depending on the
1304 * parameters passesd
1305 *************************************************************/
1306 int
1307     __cdecl
1308 _tmain(int argc, TCHAR * argv[])
1309 {
1310
1311     /*
1312      * Define Service Name and Description, which appears in windows SCM
1313      */
1314     LPCTSTR         lpszServiceName = g_szAppName;      /* Service Registry Name */
1315     LPCTSTR         lpszServiceDisplayName = _T("Net SNMP Agent Daemon");       /* Display Name */
1316     LPCTSTR         lpszServiceDescription =
1317         _T("SNMP agent for windows from Net-SNMP");
1318     InputParams     InputOptions;
1319
1320
1321     int             nRunType = RUN_AS_CONSOLE;
1322     nRunType = ParseCmdLineForServiceOption(argc, argv);
1323
1324     switch (nRunType) {
1325     case REGISTER_SERVICE:
1326         /*
1327          * Register As service
1328          */
1329         InputOptions.Argc = argc;
1330         InputOptions.Argv = argv;
1331         RegisterService(lpszServiceName,
1332                         lpszServiceDisplayName,
1333                         lpszServiceDescription, &InputOptions);
1334         exit(0);
1335         break;
1336     case UN_REGISTER_SERVICE:
1337         /*
1338          * Unregister service
1339          */
1340         UnregisterService(lpszServiceName);
1341         exit(0);
1342         break;
1343     case RUN_AS_SERVICE:
1344         /*
1345          * Run as service
1346          */
1347         /*
1348          * Register Stop Function
1349          */
1350         RegisterStopFunction(StopSnmpAgent);
1351         return RunAsService(SnmpDaemonMain);
1352         break;
1353     default:
1354         /*
1355          * Run Net-Snmpd in console mode
1356          */
1357         /*
1358          * Invoke SnmpDeamonMain with input arguments
1359          */
1360         return SnmpDaemonMain(argc, argv);
1361         break;
1362     }
1363 }
1364
1365 /*
1366  * To stop Snmp Agent deamon
1367  * This portion is still not working
1368  */
1369 void
1370 StopSnmpAgent(void)
1371 {
1372     /*
1373      * Shut Down Agent
1374      */
1375     SnmpdShutDown(1);
1376
1377     /*
1378      * Wait till agent is completely stopped
1379      */
1380
1381     while (agent_status != AGENT_STOPPED) {
1382         Sleep(100);
1383     }
1384 }
1385
1386 #endif/*WIN32*/