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