static void fill_init_list( struct ne_init_list *list, HMODULE16 hModule ) { NE_MODULE *pModule; HMODULE16 *pModRef; int i; if (!(pModule = NE_GetPtr( hModule ))) return; assert( !(pModule->ne_flags & NE_FFLAGS_WIN32) ); /* Never add a module twice */ for ( i = 0; i < list->count; i++ ) if ( list->module[i] == pModule ) return; /* Check for recursive call */ if ( pModule->ne_flagsothers & 0x80 ) return; TRACE_(dll)("(%s) - START\n", NE_MODULE_NAME(pModule) ); /* Tag current module to prevent recursive loop */ pModule->ne_flagsothers |= 0x80; /* Recursively attach all DLLs this one depends on */ pModRef = (HMODULE16 *)((char *)pModule + pModule->ne_modtab); for ( i = 0; i < pModule->ne_cmod; i++ ) if ( pModRef[i] ) fill_init_list( list, pModRef[i] ); /* Add current module */ add_to_init_list( list, pModule ); /* Remove recursion flag */ pModule->ne_flagsothers &= ~0x80; TRACE_(dll)("(%s) - END\n", NE_MODULE_NAME(pModule) ); }
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:Ptu:vx:X-:"; netsnmp_session *sess_list = NULL, *ss = NULL; netsnmp_transport *transport = NULL; int arg, i = 0; int uid = 0, gid = 0; int exit_code = 1; char *cp, *listen_ports = NULL; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) int agentx_subagent = 1; #endif netsnmp_trapd_handler *traph; #ifndef WIN32 int prepared_sockets = 0; #endif #ifndef NETSNMP_NO_SYSTEMD /* check if systemd has sockets for us and don't close them */ prepared_sockets = netsnmp_sd_listen_fds(0); #endif #ifndef WIN32 /* * close all non-standard file descriptors we may have * inherited from the shell. */ if (!prepared_sockets) netsnmp_close_fds(2); #endif #ifdef SIGTERM signal(SIGTERM, term_handler); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGINT signal(SIGINT, term_handler); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif /* * register our configuration handlers now so -H properly displays them */ snmptrapd_register_configs( ); #ifdef NETSNMP_USE_MYSQL snmptrapd_register_sql_configs( ); #endif #ifdef NETSNMP_SECMOD_USM init_usm_conf( "snmptrapd" ); #endif /* NETSNMP_SECMOD_USM */ register_config_handler("snmptrapd", "snmpTrapdAddr", parse_trapd_address, free_trapd_address, "string"); register_config_handler("snmptrapd", "doNotLogTraps", parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)"); #if HAVE_GETPID register_config_handler("snmptrapd", "pidFile", parse_config_pidFile, NULL, "string"); #endif #ifdef HAVE_UNISTD_H register_config_handler("snmptrapd", "agentuser", parse_config_agentuser, NULL, "userid"); register_config_handler("snmptrapd", "agentgroup", parse_config_agentgroup, NULL, "groupid"); #endif register_config_handler("snmptrapd", "doNotFork", parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "ignoreAuthFailure", parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "outputOption", parse_config_outputOption, NULL, "string"); /* * Add some options if they are available. */ #if HAVE_GETPID strcat(options, "p:"); #endif #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0 || strcasecmp(optarg, "version") == 0) { version(); exit_code = 0; goto out; } handle_long_opt(optarg); break; case 'a': dropauth = 1; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(); goto out; } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET, 1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'f': dofork = 0; break; case 'F': if (optarg != NULL) { if (( strncmp( optarg, "print", 5 ) == 0 ) || ( strncmp( optarg, "syslog", 6 ) == 0 ) || ( strncmp( optarg, "execute", 7 ) == 0 )) { /* New style: "type=format" */ trap1_fmt_str_remember = strdup(optarg); cp = strchr( trap1_fmt_str_remember, '=' ); if (cp) *cp = ' '; } else { /* Old style: implicitly "print=format" */ trap1_fmt_str_remember = malloc(strlen(optarg) + 7); sprintf( trap1_fmt_str_remember, "print %s", optarg ); } } else { usage(); goto out; } break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid = atoi(optarg)); } else { usage(); goto out; } break; #endif case 'h': usage(); exit_code = 0; goto out; case 'H': init_agent("snmptrapd"); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE init_notification_log(); #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); #endif init_snmp("snmptrapd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit_code = 0; goto out; case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(); } break; case 'S': fprintf(stderr, "Warning: -S option has been withdrawn; use -Ls <facility> instead\n"); goto out; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(); goto out; } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(); goto out; } break; case 'n': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NUMERIC_IP, 1); break; case 'o': fprintf(stderr, "Warning: -o option has been withdrawn; use -Lf <file> instead\n"); goto out; case 'O': cp = snmp_out_toggle_options(optarg); if (cp != NULL) { fprintf(stderr, "Unknown output option passed to -O: %c\n", *cp); usage(); goto out; } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(); goto out; } break; #if HAVE_GETPID case 'p': if (optarg != NULL) { parse_config_pidFile(NULL, optarg); } else { usage(); goto out; } break; #endif case 'P': fprintf(stderr, "Warning: -P option has been withdrawn; use -f -Le instead\n"); goto out; case 's': fprintf(stderr, "Warning: -s option has been withdrawn; use -Lsd instead\n"); goto out; case 't': SyslogTrap++; break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; uid = strtoul(optarg, &ecp, 10); #if HAVE_GETPWNAM && HAVE_PWD_H if (*ecp) { struct passwd *info; info = getpwnam(optarg); uid = info ? info->pw_uid : -1; endpwent(); } #endif if (uid < 0) { fprintf(stderr, "Bad user id: %s\n", optarg); goto out; } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(); goto out; } break; #endif case 'v': version(); exit(0); break; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(); goto out; } break; case 'X': agentx_subagent = 0; break; #endif default: fprintf(stderr, "invalid option: -%c\n", arg); usage(); goto out; break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ for (i = optind; i < argc; i++) { char *astring; if (listen_ports != NULL) { astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); goto out; } sprintf(astring, "%s,%s", listen_ports, argv[i]); free(listen_ports); listen_ports = astring; } else { listen_ports = strdup(argv[i]); if (listen_ports == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); goto out; } } } } SOCK_STARTUP; /* * I'm being lazy here, and not checking the * return value from these registration calls. * Don't try this at home, children! */ if (0 == snmp_get_do_logging()) { #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_syslog(); #else /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_stderr(); #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ } else { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; } #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * we're an agentx subagent? */ if (agentx_subagent) { /* * make us a agentx client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); } #endif /* * don't fail if we can't do agentx (ie, socket not there, or not root) */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); /* * ignore any warning messages. */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS); /* * initialize the agent library */ init_agent("snmptrapd"); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) #ifdef NETSNMP_FEATURE_CHECKING netsnmp_feature_require(register_snmpEngine_scalars_context) #endif /* NETSNMP_FEATURE_CHECKING */ /* * initialize local modules */ if (agentx_subagent) { #ifdef USING_SNMPV3_SNMPENGINE_MODULE extern void register_snmpEngine_scalars_context(const char *); #endif subagent_init(); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE /* register the notification log table */ if (should_init("notificationLogMib")) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_NOTIF_LOG_CTX, "snmptrapd"); traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER, notification_handler); traph->authtypes = TRAP_AUTH_LOG; init_notification_log(); } #endif #ifdef USING_SNMPV3_SNMPENGINE_MODULE /* * register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group; * allows engineID probes via the master agent under the * snmptrapd context */ register_snmpEngine_scalars_context("snmptrapd"); #endif } #endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */ /* register our authorization handler */ init_netsnmp_trapd_auth(); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) if (agentx_subagent) { #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE extern void init_register_nsVacm_context(const char *); #endif #ifdef USING_SNMPV3_USMUSER_MODULE #ifdef NETSNMP_FEATURE_CHECKING netsnmp_feature_require(init_register_usmUser_context) #endif /* NETSNMP_FEATURE_CHECKING */ extern void init_register_usmUser_context(const char *); /* register ourselves as having a USM user database */ init_register_usmUser_context("snmptrapd"); #endif #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE /* register net-snmp vacm extensions */ init_register_nsVacm_context("snmptrapd"); #endif #ifdef USING_TLSTM_MIB_SNMPTLSTMCERTTOTSNTABLE_MODULE init_snmpTlstmCertToTSNTable_context("snmptrapd"); #endif } #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); { /* set the default path to load */ char init_file[SNMP_MAXBUF]; snprintf(init_file, sizeof(init_file) - 1, "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl"); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PERL_INIT_FILE, init_file); } #endif /* * Initialize the world. */ init_snmp("snmptrapd"); #ifdef SIGHUP signal(SIGHUP, hup_handler); #endif if (trap1_fmt_str_remember) { parse_format( NULL, trap1_fmt_str_remember ); } if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { /* * just starting up to process specific configuration and then * shutting down immediately. */ netsnmp_running = 0; } /* * if no logging options on command line or in conf files, use syslog */ if (0 == snmp_get_do_logging()) { #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ } if (listen_ports) cp = listen_ports; else cp = default_port; while (cp != NULL) { char *sep = strchr(cp, ','); if (sep != NULL) { *sep = 0; } transport = netsnmp_transport_open_server("snmptrap", cp); if (transport == NULL) { snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n", cp, errno, strerror(errno)); snmptrapd_close_sessions(sess_list); goto sock_cleanup; } else { ss = snmptrapd_add_session(transport); if (ss == NULL) { /* * Shouldn't happen? We have already opened the transport * successfully so what could have gone wrong? */ snmptrapd_close_sessions(sess_list); snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno)); goto sock_cleanup; } else { ss->next = sess_list; sess_list = ss; } } /* * Process next listen address, if there is one. */ if (sep != NULL) { *sep = ','; cp = sep + 1; } else { cp = NULL; } } SNMP_FREE(listen_ports); /* done with them */ #ifdef NETSNMP_USE_MYSQL if( netsnmp_mysql_init() ) { fprintf(stderr, "MySQL initialization failed\n"); goto sock_cleanup; } #endif #ifndef WIN32 /* * fork the process to the background if we are not printing to stderr */ if (dofork && netsnmp_running) { int fd; #if HAVE_FORKALL switch (forkall()) { #else switch (fork()) { #endif case -1: fprintf(stderr, "bad fork - %s\n", strerror(errno)); goto sock_cleanup; case 0: /* * become process group leader */ if (setsid() == -1) { fprintf(stderr, "bad setsid - %s\n", strerror(errno)); goto sock_cleanup; } /* * if we are forked, we don't want to print out to stdout or stderr */ fd = open("/dev/null", O_RDWR); if (fd >= 0) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); } break; default: _exit(0); } } #endif /* WIN32 */ #if HAVE_GETPID if (pid_file != NULL) { if ((PID = fopen(pid_file, "w")) == NULL) { snmp_log_perror("fopen"); goto sock_cleanup; } fprintf(PID, "%d\n", (int) getpid()); fclose(PID); free_config_pidFile(); } #endif snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); /* * ignore early sighup during startup */ reconfig = 0; #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) > 0) { DEBUGMSGTL(("snmptrapd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { goto sock_cleanup; } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { goto sock_cleanup; } } } #endif #endif /* * Let systemd know we're up. */ #ifndef NETSNMP_NO_SYSTEMD netsnmp_sd_notify(1, "READY=1\n"); if (prepared_sockets) /* * Clear the environment variable, we already processed all the sockets * by now. */ netsnmp_sd_listen_fds(1); #endif #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_RUNNING; #endif snmptrapd_main_loop(); if (snmp_get_do_logging()) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } snmp_log(LOG_INFO, "Stopping snmptrapd\n"); #ifdef NETSNMP_EMBEDDED_PERL shutdown_perl(); #endif snmptrapd_close_sessions(sess_list); snmp_shutdown("snmptrapd"); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_STOPPED; #endif snmp_disable_log(); exit_code = 0; sock_cleanup: SOCK_CLEANUP; out: return exit_code; } /* * Read the configuration files. Implemented as a signal handler so that * receipt of SIGHUP will cause configuration to be re-read when the * trap daemon is running detatched from the console. * */ void trapd_update_config(void) { free_config(); #ifdef USING_MIBII_VACM_CONF_MODULE vacm_standard_views(0,0,NULL,NULL); #endif read_configs(); }
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:"; int arg, i, ret; int dont_fork = 0, do_help = 0; int log_set = 0; int agent_mode = -1; char *pid_file = NULL; char option_compatability[] = "-Le"; #ifndef WIN32 int prepared_sockets = 0; #endif #if HAVE_GETPID int fd; FILE *PID; #endif #ifndef WIN32 #ifndef NETSNMP_NO_SYSTEMD /* check if systemd has sockets for us and don't close them */ prepared_sockets = netsnmp_sd_listen_fds(0); #endif /* NETSNMP_NO_SYSTEMD */ /* * close all non-standard file descriptors we may have * inherited from the shell. */ if (!prepared_sockets) { for (i = getdtablesize() - 1; i > 2; --i) { (void) close(i); } } #endif /* #WIN32 */ /* * register signals ASAP to prevent default action (usually core) * for signals during startup... */ #ifdef SIGTERM DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n")); signal(SIGTERM, SnmpdShutDown); #endif #ifdef SIGINT DEBUGMSGTL(("signal", "registering SIGINT signal handler\n")); signal(SIGINT, SnmpdShutDown); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGUSR1 DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n")); signal(SIGUSR1, SnmpdDump); #endif #ifdef SIGPIPE DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n")); signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif #ifdef SIGXFSZ signal(SIGXFSZ, SnmpdCatchRandomSignal); #endif #ifdef NETSNMP_NO_ROOT_ACCESS /* * Default to no. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); #endif /* * Default to NOT running an AgentX master. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 0); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_RETRIES, -1); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5); /* * Add some options if they are available. */ #if HAVE_UNISTD_H strcat(options, "g:u:"); #endif #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) strcat(options, "x:"); #endif #ifdef USING_AGENTX_SUBAGENT_MODULE strcat(options, "X"); #endif /* * This is incredibly ugly, but it's probably the simplest way * to handle the old '-L' option as well as the new '-Lx' style */ for (i=0; i<argc; i++) { if (!strcmp(argv[i], "-L")) argv[i] = option_compatability; } #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE, app_name); /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(argv[0]); } if (strcasecmp(optarg, "version") == 0) { version(); } handle_long_opt(optarg); break; case 'a': log_addresses++; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(argv[0]); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET, ++snmp_dump_packet); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'f': dont_fork = 1; break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { char *ecp; int gid; gid = strtoul(optarg, &ecp, 10); #if HAVE_GETGRNAM && HAVE_PWD_H if (*ecp) { struct group *info; info = getgrnam(optarg); gid = info ? info->gr_gid : -1; endgrent(); } #endif if (gid < 0) { fprintf(stderr, "Bad group id: %s\n", optarg); exit(1); } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid); } else { usage(argv[0]); } break; #endif case 'h': usage(argv[0]); break; case 'H': do_help = 1; break; case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(argv[0]); } break; #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE case 'l': printf("Warning: -l option is deprecated, use -Lf <file> instead\n"); if (optarg != NULL) { if (strlen(optarg) > PATH_MAX) { fprintf(stderr, "%s: logfile path too long (limit %d chars)\n", argv[0], PATH_MAX); exit(1); } snmp_enable_filelog(optarg, netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES)); log_set = 1; } else { usage(argv[0]); } break; #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */ case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(argv[0]); } log_set = 1; break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(argv[0]); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(argv[0]); } break; case 'n': if (optarg != NULL) { app_name = optarg; netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE, app_name); } else { usage(argv[0]); } break; case 'P': printf("Warning: -P option is deprecated, use -p instead\n"); case 'p': if (optarg != NULL) { pid_file = optarg; } else { usage(argv[0]); } break; case 'q': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, 1); break; case 'r': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); break; #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG case 's': printf("Warning: -s option is deprecated, use -Lsd instead\n"); snmp_enable_syslog(); log_set = 1; break; case 'S': printf("Warning: -S option is deprecated, use -Ls <facility> instead\n"); if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(argv[0]); } snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility); log_set = 1; } else { fprintf(stderr, "no syslog facility specified\n"); usage(argv[0]); } break; #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ case 'U': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE); break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; int uid; uid = strtoul(optarg, &ecp, 10); #if HAVE_GETPWNAM && HAVE_PWD_H if (*ecp) { struct passwd *info; info = getpwnam(optarg); uid = info ? info->pw_uid : -1; endpwent(); } #endif if (uid < 0) { fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(argv[0]); } break; #endif case 'v': version(); case 'V': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1); break; #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(argv[0]); } netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 1); break; #endif case 'X': #if defined(USING_AGENTX_SUBAGENT_MODULE) agent_mode = SUB_AGENT; #else fprintf(stderr, "%s: Illegal argument -X:" "AgentX support not compiled in.\n", argv[0]); usage(argv[0]); exit(1); #endif break; case 'Y': netsnmp_config_remember(optarg); break; default: usage(argv[0]); break; } } if (do_help) { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); init_agent(app_name); /* register our .conf handlers */ init_mib_modules(); init_snmp(app_name); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); } if (optind < argc) { #ifndef NETSNMP_NO_LISTEN_SUPPORT /* * There are optional transport addresses on the command line. */ DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc)); for (i = optind; i < argc; i++) { char *c, *astring; if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))) { astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", c, argv[i]); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, astring); SNMP_FREE(astring); } else { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, argv[i]); } } DEBUGMSGTL(("snmpd/main", "port spec: %s\n", netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))); #else /* NETSNMP_NO_LISTEN_SUPPORT */ fprintf(stderr, "You specified ports to open; this agent was built to only send notifications\n"); exit(1); #endif /* NETSNMP_NO_LISTEN_SUPPORT */ } #ifdef NETSNMP_LOGFILE #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE if (0 == log_set) snmp_enable_filelog(NETSNMP_LOGFILE, netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES)); #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */ #endif #ifdef USING_UTIL_FUNCS_RESTART_MODULE { /* * Initialize a argv set to the current for restarting the agent. */ char *cptr, **argvptr; argvrestartp = (char **)malloc((argc + 2) * sizeof(char *)); argvptr = argvrestartp; for (i = 0, ret = 1; i < argc; i++) { ret += strlen(argv[i]) + 1; } argvrestart = (char *) malloc(ret); argvrestartname = (char *) malloc(strlen(argv[0]) + 1); if (!argvrestartp || !argvrestart || !argvrestartname) { fprintf(stderr, "malloc failure processing argvrestart\n"); exit(1); } strcpy(argvrestartname, argv[0]); for (cptr = argvrestart, i = 0; i < argc; i++) { strcpy(cptr, argv[i]); *(argvptr++) = cptr; cptr += strlen(argv[i]) + 1; } } #endif /* USING_UTIL_FUNCS_RESTART_MODULE */ if (agent_mode == -1) { if (strstr(argv[0], "agentxd") != NULL) { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, SUB_AGENT); } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, MASTER_AGENT); } } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, agent_mode); } SOCK_STARTUP; if (init_agent(app_name) != 0) { snmp_log(LOG_ERR, "Agent initialization failed\n"); exit(1); } init_mib_modules(); /* * start library */ init_snmp(app_name); if ((ret = init_master_agent()) != 0) { /* * Some error opening one of the specified agent transports. */ snmp_log(LOG_ERR, "Server Exiting with code 1\n"); exit(1); } /* * Initialize the world. Detach from the shell. Create initial user. */ if(!dont_fork) { int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY); ret = netsnmp_daemonize(quit, #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO snmp_stderrlog_status() #else /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ 0 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ ); /* * xxx-rks: do we care if fork fails? I think we should... */ if(ret != 0) { snmp_log(LOG_ERR, "Server Exiting with code 1\n"); exit(1); } } #if HAVE_GETPID if (pid_file != NULL) { /* * unlink the pid_file, if it exists, prior to open. Without * doing this the open will fail if the user specified pid_file * already exists. */ unlink(pid_file); fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600); if (fd == -1) { snmp_log_perror(pid_file); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } else { if ((PID = fdopen(fd, "w")) == NULL) { snmp_log_perror(pid_file); exit(1); } else { fprintf(PID, "%d\n", (int) getpid()); fclose(PID); } #ifndef _MSC_VER /* The sequence open()/fdopen()/fclose()/close() makes MSVC crash, hence skip the close() call when using the MSVC runtime. */ close(fd); #endif } } #endif #if defined(HAVE_UNISTD_H) && (defined(HAVE_CHOWN) || defined(HAVE_SETGID) || defined(HAVE_SETUID)) { const char *persistent_dir; int uid, gid; persistent_dir = get_persistent_directory(); mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 ); uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID); gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID); #ifdef HAVE_CHOWN if ( uid != 0 || gid != 0 ) chown( persistent_dir, uid, gid ); #endif #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) > 0) { DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) > 0) { #if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS struct passwd *info; /* * Set supplementary groups before changing UID * (which probably involves giving up privileges) */ info = getpwuid(uid); if (info) { DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name)); if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) { snmp_log_perror("initgroups failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } endpwent(); #endif DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif } #endif /* * Store persistent data immediately in case we crash later. */ snmp_store(app_name); #ifdef SIGHUP DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n")); signal(SIGHUP, SnmpdReconfig); #endif /* * Send coldstart trap if possible. */ send_easy_trap(0, 0); /* * We're up, log our version number. */ snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); #ifdef WIN32SERVICE agent_status = AGENT_RUNNING; #endif netsnmp_addrcache_initialise(); /* * Let systemd know we're up. */ #ifndef NETSNMP_NO_SYSTEMD netsnmp_sd_notify(1, "READY=1\n"); if (prepared_sockets) /* * Clear the environment variable, we already processed all the sockets * by now. */ netsnmp_sd_listen_fds(1); #endif /* * Forever monitor the dest_port for incoming PDUs. */ DEBUGMSGTL(("snmpd/main", "We're up. Starting to process data.\n")); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) receive(); DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n")); SnmpTrapNodeDown(); DEBUGMSGTL(("snmpd/main", "Bye...\n")); snmp_shutdown(app_name); shutdown_master_agent(); shutdown_agent(); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE) && (pid_file != NULL)) { unlink(pid_file); } #ifdef WIN32SERVICE agent_status = AGENT_STOPPED; #endif #ifdef USING_UTIL_FUNCS_RESTART_MODULE SNMP_FREE(argvrestartname); SNMP_FREE(argvrestart); SNMP_FREE(argvrestartp); #endif /* USING_UTIL_FUNCS_RESTART_MODULE */ SOCK_CLEANUP; return 0; } /* End main() -- snmpd */
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::efF:g:hHI:L:m:M:no:O:PqsS:tu:vx:-:"; netsnmp_session *sess_list = NULL, *ss = NULL; netsnmp_transport *transport = NULL; int arg, i = 0, depmsg = 0; int uid = 0, gid = 0; int count, numfds, block; fd_set readfds,writefds,exceptfds; struct timeval timeout, *tvp; char *cp, *listen_ports = NULL; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) int agentx_subagent = 1; #endif netsnmp_trapd_handler *traph; #ifdef NETSNMP_EMBEDDED_PERL extern void init_perl(void); #endif #ifndef WIN32 /* * close all non-standard file descriptors we may have * inherited from the shell. */ for (i = getdtablesize() - 1; i > 2; --i) { (void) close(i); } #endif /* #WIN32 */ #ifdef SIGTERM signal(SIGTERM, term_handler); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGINT signal(SIGINT, term_handler); #endif #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif /* * register our configuration handlers now so -H properly displays them */ snmptrapd_register_configs( ); init_usm_conf( "snmptrapd" ); register_config_handler("snmptrapd", "snmpTrapdAddr", parse_trapd_address, free_trapd_address, "string"); register_config_handler("snmptrapd", "doNotLogTraps", parse_config_doNotLogTraps, NULL, "(1|yes|true|0|no|false)"); #if HAVE_GETPID register_config_handler("snmptrapd", "pidFile", parse_config_pidFile, NULL, "string"); #endif #ifdef HAVE_UNISTD_H register_config_handler("snmptrapd", "agentuser", parse_config_agentuser, NULL, "userid"); register_config_handler("snmptrapd", "agentgroup", parse_config_agentgroup, NULL, "groupid"); #endif register_config_handler("snmptrapd", "logOption", parse_config_logOption, NULL, "string"); register_config_handler("snmptrapd", "doNotFork", parse_config_doNotFork, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "printEventNumbers", parse_config_printEventNumbers, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "ignoreAuthFailure", parse_config_ignoreAuthFailure, NULL, "(1|yes|true|0|no|false)"); register_config_handler("snmptrapd", "outputOption", parse_config_outputOption, NULL, "string"); #ifdef WIN32 setvbuf(stdout, NULL, _IONBF, BUFSIZ); #else setvbuf(stdout, NULL, _IOLBF, BUFSIZ); #endif /* * Add some options if they are available. */ #if HAVE_GETPID strcat(options, "p:"); #endif #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(); exit(0); } if (strcasecmp(optarg, "version") == 0) { version(); exit(0); } handle_long_opt(optarg); break; case 'a': dropauth = 1; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(); exit(1); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': snmp_set_dump_packet(1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'e': Event++; break; case 'f': dofork = 0; break; case 'F': if (optarg != NULL) { trap1_fmt_str_remember = optarg; } else { usage(); exit(1); } break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid = atoi(optarg)); } else { usage(); exit(1); } break; #endif case 'h': usage(); exit(0); case 'H': init_agent("snmptrapd"); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE init_notification_log(); #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); #endif init_snmp("snmptrapd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(); } break; case 'S': fprintf(stderr, "Warning: -S option is deprecated; use -Ls <facility> instead\n"); depmsg = 1; if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(); exit(1); } } else { fprintf(stderr, "no syslog facility specified\n"); usage(); exit(1); } break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(); exit(1); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(); exit(1); } break; case 'n': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_APP_NUMERIC_IP, 1); break; case 'o': fprintf(stderr, "Warning: -o option is deprecated; use -Lf <file> instead\n"); if (optarg != NULL) { logfile = optarg; snmp_enable_filelog(optarg, netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES)); } else { usage(); exit(1); } break; case 'O': cp = snmp_out_toggle_options(optarg); if (cp != NULL) { fprintf(stderr, "Unknown output option passed to -O: %c\n", *cp); usage(); exit(1); } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(); exit(1); } break; #if HAVE_GETPID case 'p': if (optarg != NULL) { parse_config_pidFile(NULL, optarg); } else { usage(); exit(1); } break; #endif case 'P': fprintf(stderr, "Warning: -P option is deprecated; use -f -Le instead\n"); dofork = 0; snmp_enable_stderrlog(); break; case 's': fprintf(stderr, "Warning: -s option is deprecated; use -Lsd instead\n"); depmsg = 1; #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif break; case 't': SyslogTrap++; break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; uid = strtoul(optarg, &ecp, 10); if (*ecp) { #if HAVE_GETPWNAM && HAVE_PWD_H struct passwd *info; info = getpwnam(optarg); if (info) { uid = info->pw_uid; } else { #endif fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); #if HAVE_GETPWNAM && HAVE_PWD_H } #endif } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(); exit(1); } break; #endif case 'v': version(); exit(0); break; case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(); exit(1); } break; default: fprintf(stderr, "invalid option: -%c\n", arg); usage(); exit(1); break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ for (i = optind; i < argc; i++) { char *astring; if (listen_ports != NULL) { astring = malloc(strlen(listen_ports) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", listen_ports, argv[i]); free(listen_ports); listen_ports = astring; } else { listen_ports = strdup(argv[i]); if (listen_ports == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } } } } SOCK_STARTUP; /* * I'm being lazy here, and not checking the * return value from these registration calls. * Don't try this at home, children! */ if (0 == snmp_get_do_logging()) { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, syslog_handler); traph->authtypes = TRAP_AUTH_LOG; snmp_enable_syslog(); } else { traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_PRE_HANDLER, print_handler); traph->authtypes = TRAP_AUTH_LOG; } if (Event) { traph = netsnmp_add_traphandler(event_handler, risingAlarm, OID_LENGTH(risingAlarm)); traph->authtypes = TRAP_AUTH_LOG; traph = netsnmp_add_traphandler(event_handler, fallingAlarm, OID_LENGTH(fallingAlarm)); traph->authtypes = TRAP_AUTH_LOG; traph = netsnmp_add_traphandler(event_handler, unavailableAlarm, OID_LENGTH(unavailableAlarm)); traph->authtypes = TRAP_AUTH_LOG; /* XXX - might be worth setting some "magic data" * in the traphandler structure that 'event_handler' * can use to avoid checking the trap OID values. */ } #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * we're an agentx subagent? */ if (agentx_subagent) { /* * make us a agentx client. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1); } #endif /* * don't fail if we can't do agentx (ie, socket not there, or not root) */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); /* * ignore any warning messages. */ netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS); /* * initialize the agent library */ init_agent("snmptrapd"); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) /* * initialize local modules */ if (agentx_subagent) { #ifdef USING_SNMPV3_SNMPENGINE_MODULE extern void register_snmpEngine_scalars_context(const char *); #endif subagent_init(); #ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE /* register the notification log table */ if (should_init("notificationLogMib")) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_NOTIF_LOG_CTX, "snmptrapd"); traph = netsnmp_add_global_traphandler(NETSNMPTRAPD_POST_HANDLER, notification_handler); traph->authtypes = TRAP_AUTH_LOG; init_notification_log(); } #endif #ifdef USING_SNMPV3_SNMPENGINE_MODULE /* * register scalars from SNMP-FRAMEWORK-MIB::snmpEngineID group; * allows engineID probes via the master agent under the * snmptrapd context */ register_snmpEngine_scalars_context("snmptrapd"); #endif } #endif /* USING_AGENTX_SUBAGENT_MODULE && !NETSNMP_SNMPTRAPD_DISABLE_AGENTX */ /* register our authorization handler */ init_netsnmp_trapd_auth(); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(NETSNMP_SNMPTRAPD_DISABLE_AGENTX) if (agentx_subagent) { #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE extern void init_register_nsVacm_context(const char *); #endif #ifdef USING_SNMPV3_USMUSER_MODULE extern void init_register_usmUser_context(const char *); /* register ourselves as having a USM user database */ init_register_usmUser_context("snmptrapd"); #endif #ifdef USING_AGENT_NSVACMACCESSTABLE_MODULE /* register net-snmp vacm extensions */ init_register_nsVacm_context("snmptrapd"); #endif } #endif #ifdef NETSNMP_EMBEDDED_PERL init_perl(); { /* set the default path to load */ char init_file[SNMP_MAXBUF]; snprintf(init_file, sizeof(init_file) - 1, "%s/%s", SNMPSHAREPATH, "snmp_perl_trapd.pl"); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PERL_INIT_FILE, init_file); } #endif /* * Initialize the world. */ init_snmp("snmptrapd"); #ifdef SIGHUP signal(SIGHUP, hup_handler); #endif if (trap1_fmt_str_remember) { free_trap1_fmt(); free_trap2_fmt(); print_format1 = strdup(trap1_fmt_str_remember); print_format2 = strdup(trap1_fmt_str_remember); } if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { /* * just starting up to process specific configuration and then * shutting down immediately. */ netsnmp_running = 0; } /* * if no logging options on command line or in conf files, use syslog */ if (0 == snmp_get_do_logging()) { #ifdef WIN32 snmp_enable_syslog_ident(app_name_long, Facility); #else snmp_enable_syslog_ident(app_name, Facility); #endif } #ifndef WIN32 /* * fork the process to the background if we are not printing to stderr */ if (dofork && netsnmp_running) { int fd; switch (fork()) { case -1: fprintf(stderr, "bad fork - %s\n", strerror(errno)); _exit(1); case 0: /* * become process group leader */ if (setsid() == -1) { fprintf(stderr, "bad setsid - %s\n", strerror(errno)); _exit(1); } /* * if we are forked, we don't want to print out to stdout or stderr */ fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); break; default: _exit(0); } } #endif /* WIN32 */ #if HAVE_GETPID if (pid_file != NULL) { if ((PID = fopen(pid_file, "w")) == NULL) { snmp_log_perror("fopen"); exit(1); } fprintf(PID, "%d\n", (int) getpid()); fclose(PID); free_config_pidFile(); } #endif snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); if (depmsg) { snmp_log(LOG_WARNING, "-s and -S options are deprecated; use -Ls <facility> instead\n"); } if (listen_ports) cp = listen_ports; else cp = default_port; while (cp != NULL) { char *sep = strchr(cp, ','); if (sep != NULL) { *sep = 0; } transport = netsnmp_transport_open_server("snmptrap", cp); if (transport == NULL) { snmp_log(LOG_ERR, "couldn't open %s -- errno %d (\"%s\")\n", cp, errno, strerror(errno)); snmptrapd_close_sessions(sess_list); SOCK_CLEANUP; exit(1); } else { ss = snmptrapd_add_session(transport); if (ss == NULL) { /* * Shouldn't happen? We have already opened the transport * successfully so what could have gone wrong? */ snmptrapd_close_sessions(sess_list); netsnmp_transport_free(transport); snmp_log(LOG_ERR, "couldn't open snmp - %s", strerror(errno)); SOCK_CLEANUP; exit(1); } else { ss->next = sess_list; sess_list = ss; } } /* * Process next listen address, if there is one. */ if (sep != NULL) { *sep = ','; cp = sep + 1; } else { cp = NULL; } } /* * ignore early sighup during startup */ reconfig = 0; #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmptrapd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #endif #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_RUNNING; #endif while (netsnmp_running) { if (reconfig) { /* * If we are logging to a file, receipt of SIGHUP also * indicates the the log file should be closed and * re-opened. This is useful for users that want to * rotate logs in a more predictable manner. */ netsnmp_logging_restart(); snmp_log(LOG_INFO, "NET-SNMP version %s restarted\n", netsnmp_get_version()); trapd_update_config(); if (trap1_fmt_str_remember) { free_trap1_fmt(); free_trap2_fmt(); print_format1 = strdup(trap1_fmt_str_remember); print_format2 = strdup(trap1_fmt_str_remember); } reconfig = 0; } numfds = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); block = 0; tvp = &timeout; timerclear(tvp); tvp->tv_sec = 5; snmp_select_info(&numfds, &readfds, tvp, &block); if (block == 1) tvp = NULL; /* block without timeout */ netsnmp_external_event_info(&numfds, &readfds, &writefds, &exceptfds); count = select(numfds, &readfds, &writefds, &exceptfds, tvp); gettimeofday(&Now, 0); if (count > 0) { netsnmp_dispatch_external_events(&count, &readfds, &writefds, &exceptfds); /* If there are any more events after external events, then * try SNMP events. */ if (count > 0) { snmp_read(&readfds); } } else switch (count) { case 0: snmp_timeout(); break; case -1: if (errno == EINTR) continue; snmp_log_perror("select"); netsnmp_running = 0; break; default: fprintf(stderr, "select returned %d\n", count); netsnmp_running = 0; } run_alarms(); } if (snmp_get_do_logging()) { struct tm *tm; time_t timer; time(&timer); tm = localtime(&timer); snmp_log(LOG_INFO, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d NET-SNMP version %s Stopped.\n", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, netsnmp_get_version()); } snmp_log(LOG_INFO, "Stopping snmptrapd"); snmptrapd_close_sessions(sess_list); snmp_shutdown("snmptrapd"); #ifdef WIN32SERVICE trapd_status = SNMPTRAPD_STOPPED; #endif snmp_disable_log(); SOCK_CLEANUP; return 0; }
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::fhHI:l:L:m:M:p:P:qrsS:UvV-:"; int arg, i, ret; int dont_fork = 0; int dont_zero_log = 0; int syslog_log = 0; int uid = 0, gid = 0; int agent_mode = -1; char logfile[PATH_MAX + 1] = { 0 }; char *cptr, **argvptr; char *pid_file = NULL; char option_compatability[] = "-Le"; #if HAVE_GETPID int fd; FILE *PID; #endif #ifndef WIN32 /* * close all non-standard file descriptors we may have * inherited from the shell. */ for (i = getdtablesize() - 1; i > 2; --i) { (void) close(i); } #endif /* #WIN32 */ /* * register signals ASAP to prevent default action (usually core) * for signals during startup... */ #ifdef SIGTERM DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n")); signal(SIGTERM, SnmpdShutDown); #endif #ifdef SIGINT DEBUGMSGTL(("signal", "registering SIGINT signal handler\n")); signal(SIGINT, SnmpdShutDown); #endif #ifdef SIGHUP DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n")); signal(SIGHUP, SnmpdReconfig); #endif #ifdef SIGUSR1 DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n")); signal(SIGUSR1, SnmpdDump); #endif #ifdef SIGPIPE DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n")); signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif #ifdef SIGXFSZ signal(SIGXFSZ, SnmpdCatchRandomSignal); #endif #ifdef LOGFILE strncpy(logfile, LOGFILE, PATH_MAX); #endif #ifdef NO_ROOT_ACCESS /* * Default to no. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); #endif /* * Default to NOT running an AgentX master. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 0); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_RETRIES, -1); /* * Add some options if they are available. */ #if HAVE_UNISTD_H strcat(options, "g:u:"); #endif #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) strcat(options, "x:"); #endif #ifdef USING_AGENTX_SUBAGENT_MODULE strcat(options, "X"); #endif /* * This is incredibly ugly, but it's probably the simplest way * to handle the old '-L' option as well as the new '-Lx' style */ for (i=0; i<argc; i++) { if (!strcmp(argv[i], "-L")) argv[i] = option_compatability; } snmp_log_syslogname(app_name); /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(argv[0]); } if (strcasecmp(optarg, "version") == 0) { version(); } handle_long_opt(optarg); break; case 'a': log_addresses++; break; case 'A': dont_zero_log = 1; break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(argv[0]); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': snmp_set_dump_packet(++snmp_dump_packet); netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'f': dont_fork = 1; break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, atoi(optarg)); } else { usage(argv[0]); } break; #endif case 'h': usage(argv[0]); break; case 'H': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); init_agent("snmpd"); /* register our .conf handlers */ init_mib_modules(); init_snmp("snmpd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(argv[0]); } break; case 'l': printf("Warning: -l option is deprecated, use -Lf <file> instead\n"); if (optarg != NULL) { if (strlen(optarg) > PATH_MAX) { fprintf(stderr, "%s: logfile path too long (limit %d chars)\n", argv[0], PATH_MAX); exit(1); } strncpy(logfile, optarg, PATH_MAX); } else { usage(argv[0]); } break; case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(argv[0]); } break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(argv[0]); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(argv[0]); } break; case 'P': printf("Warning: -P option is deprecated, use -p instead\n"); case 'p': if (optarg != NULL) { pid_file = optarg; } else { usage(argv[0]); } break; case 'q': snmp_set_quick_print(1); break; case 'r': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); break; case 's': printf("Warning: -s option is deprecated, use -Lsd instead\n"); syslog_log = 1; break; case 'S': printf("Warning: -S option is deprecated, use -Ls <facility> instead\n"); if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(argv[0]); } } else { fprintf(stderr, "no syslog facility specified\n"); usage(argv[0]); } break; case 'U': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE); break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; int uid; uid = strtoul(optarg, &ecp, 10); if (*ecp) { #if HAVE_GETPWNAM && HAVE_PWD_H struct passwd *info; info = getpwnam(optarg); if (info) { uid = info->pw_uid; } else { #endif fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); #if HAVE_GETPWNAM && HAVE_PWD_H } #endif } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(argv[0]); } break; #endif case 'v': version(); case 'V': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1); break; #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(argv[0]); } netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 1); break; #endif case 'X': #if defined(USING_AGENTX_SUBAGENT_MODULE) agent_mode = SUB_AGENT; #else fprintf(stderr, "%s: Illegal argument -X:" "AgentX support not compiled in.\n", argv[0]); usage(argv[0]); exit(1); #endif break; default: usage(argv[0]); break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc)); for (i = optind; i < argc; i++) { char *c, *astring; if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))) { astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", c, argv[i]); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, astring); SNMP_FREE(astring); } else { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, argv[i]); } } DEBUGMSGTL(("snmpd/main", "port spec: %s\n", netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))); } setup_log(0, dont_zero_log, 0, syslog_log, logfile); /* * Initialize a argv set to the current for restarting the agent. */ argvrestartp = (char **)malloc((argc + 2) * sizeof(char *)); argvptr = argvrestartp; for (i = 0, ret = 1; i < argc; i++) { ret += strlen(argv[i]) + 1; } argvrestart = (char *) malloc(ret); argvrestartname = (char *) malloc(strlen(argv[0]) + 1); if (!argvrestartp || !argvrestart || !argvrestartname) { fprintf(stderr, "malloc failure processing argvrestart\n"); exit(1); } strcpy(argvrestartname, argv[0]); if (agent_mode == -1) { if (strstr(argvrestartname, "agentxd") != NULL) { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, SUB_AGENT); } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, MASTER_AGENT); } } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, agent_mode); } for (cptr = argvrestart, i = 0; i < argc; i++) { strcpy(cptr, argv[i]); *(argvptr++) = cptr; cptr += strlen(argv[i]) + 1; } *cptr = 0; *argvptr = NULL; #ifdef BUFSIZ setvbuf(stdout, NULL, _IOLBF, BUFSIZ); #endif /* * Initialize the world. Detach from the shell. Create initial user. */ if(!dont_fork) { int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY); ret = netsnmp_daemonize(quit, snmp_stderrlog_status()); /* * xxx-rks: do we care if fork fails? I think we should... */ if(ret != 0) Exit(1); /* Exit logs exit val for us */ } SOCK_STARTUP; init_agent("snmpd"); /* do what we need to do first. */ init_mib_modules(); /* * start library */ init_snmp("snmpd"); if ((ret = init_master_agent()) != 0) { /* * Some error opening one of the specified agent transports. */ Exit(1); /* Exit logs exit val for us */ } /* * Store persistent data immediately in case we crash later. */ snmp_store("snmpd"); /* * Send coldstart trap if possible. */ send_easy_trap(0, 0); #if HAVE_GETPID if (pid_file != NULL) { /* * unlink the pid_file, if it exists, prior to open. Without * doing this the open will fail if the user specified pid_file * already exists. */ unlink(pid_file); fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600); if (fd == -1) { snmp_log_perror(pid_file); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } else { if ((PID = fdopen(fd, "w")) == NULL) { snmp_log_perror(pid_file); exit(1); } else { fprintf(PID, "%d\n", (int) getpid()); fclose(PID); } close(fd); } } #endif #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) != 0) { DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #endif /* * We're up, log our version number. */ snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); #ifdef WIN32SERVICE agent_status = AGENT_RUNNING; #endif netsnmp_addrcache_initialise(); /* * Forever monitor the dest_port for incoming PDUs. */ DEBUGMSGTL(("snmpd/main", "We're up. Starting to process data.\n")); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) receive(); #include "mib_module_shutdown.h" DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n")); SnmpTrapNodeDown(); DEBUGMSGTL(("snmpd/main", "Bye...\n")); snmp_shutdown("snmpd"); #ifdef SHUTDOWN_AGENT_CLEANLY /* broken code */ /* these attempt to free all known memory, but result in double frees */ shutdown_master_agent(); shutdown_agent(); #endif if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE) && (pid_file != NULL)) { unlink(pid_file); } #ifdef WIN32SERVICE agent_status = AGENT_STOPPED; #endif SNMP_FREE(argvrestartname); SNMP_FREE(argvrestart); SNMP_FREE(argvrestartp); SOCK_CLEANUP; return 0; } /* End main() -- snmpd */
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::fhHI:l:LP:qrsS:UvV-:"; int arg, i, ret; int dont_fork = 0; int dont_zero_log = 0; int stderr_log = 0, syslog_log = 0; int uid = 0, gid = 0; int agent_mode = -1; char logfile[PATH_MAX + 1] = { 0 }; char *cptr, **argvptr; char *pid_file = NULL; #if HAVE_GETPID int fd; FILE *PID; #endif #ifdef LOGFILE strncpy(logfile, LOGFILE, PATH_MAX); #endif #ifdef NO_ROOT_ACCESS /* * Default to no. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); #endif /* * Default to NOT running an AgentX master. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 0); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_RETRIES, -1); /* * Add some options if they are available. */ #if HAVE_UNISTD_H strcat(options, "g:u:"); #endif #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) strcat(options, "x:"); #endif #ifdef USING_AGENTX_SUBAGENT_MODULE strcat(options, "X"); #endif /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(argv[0]); } if (strcasecmp(optarg, "version") == 0) { version(); } handle_long_opt(optarg); break; case 'a': log_addresses++; break; case 'A': dont_zero_log = 1; break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(argv[0]); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': snmp_set_dump_packet(++snmp_dump_packet); netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1); break; case 'D': debug_register_tokens(optarg); snmp_set_do_debugging(1); break; case 'f': dont_fork = 1; break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, atoi(optarg)); } else { usage(argv[0]); } break; #endif case 'h': usage(argv[0]); break; case 'H': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); init_agent("snmpd"); /* register our .conf handlers */ init_mib_modules(); init_snmp("snmpd"); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(argv[0]); } break; case 'l': if (optarg != NULL) { if (strlen(optarg) > PATH_MAX) { fprintf(stderr, "%s: logfile path too long (limit %d chars)\n", argv[0], PATH_MAX); exit(1); } strncpy(logfile, optarg, PATH_MAX); } else { usage(argv[0]); } break; case 'L': stderr_log = 1; break; case 'P': if (optarg != NULL) { pid_file = optarg; } else { usage(argv[0]); } break; case 'q': snmp_set_quick_print(1); break; case 'r': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); break; case 's': syslog_log = 1; break; case 'S': if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(argv[0]); } } else { fprintf(stderr, "no syslog facility specified\n"); usage(argv[0]); } break; case 'U': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE); break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; int uid; uid = strtoul(optarg, &ecp, 10); if (*ecp) { #if HAVE_GETPWNAM && HAVE_PWD_H struct passwd *info; info = getpwnam(optarg); if (info) { uid = info->pw_uid; } else { #endif fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); #if HAVE_GETPWNAM && HAVE_PWD_H } #endif } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(argv[0]); } break; #endif case 'v': version(); case 'V': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1); break; #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(argv[0]); } netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 1); break; #endif case 'X': #if defined(USING_AGENTX_SUBAGENT_MODULE) agent_mode = SUB_AGENT; #else fprintf(stderr, "%s: Illegal argument -X:" "AgentX support not compiled in.\n", argv[0]); usage(argv[0]); exit(1); #endif break; default: usage(argv[0]); break; } } if (optind < argc) { /* * There are optional transport addresses on the command line. */ DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc)); for (i = optind; i < argc; i++) { char *c, *astring; if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))) { astring = malloc(strlen(c) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", c, argv[i]); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, astring); free(astring); } else { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, argv[i]); } } DEBUGMSGTL(("snmpd/main", "port spec: %s\n", netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))); } setup_log(0, dont_zero_log, stderr_log, syslog_log, logfile); /* * Initialize a argv set to the current for restarting the agent. */ argvrestartp = (char **)malloc((argc + 2) * sizeof(char *)); argvptr = argvrestartp; for (i = 0, ret = 1; i < argc; i++) { ret += strlen(argv[i]) + 1; } argvrestart = (char *) malloc(ret); argvrestartname = (char *) malloc(strlen(argv[0]) + 1); if (!argvrestartp || !argvrestart || !argvrestartname) { fprintf(stderr, "malloc failure processing argvrestart\n"); exit(1); } strcpy(argvrestartname, argv[0]); if (agent_mode == -1) { if (strstr(argvrestartname, "agentxd") != NULL) { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, SUB_AGENT); } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, MASTER_AGENT); } } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, agent_mode); } for (cptr = argvrestart, i = 0; i < argc; i++) { strcpy(cptr, argv[i]); *(argvptr++) = cptr; cptr += strlen(argv[i]) + 1; } *cptr = 0; *argvptr = NULL; #ifdef BUFSIZ setvbuf(stdout, NULL, _IOLBF, BUFSIZ); #endif /* * Initialize the world. Detach from the shell. Create initial user. */ #if HAVE_FORK if (!dont_fork) { /* * Fork to return control to the invoking process and to * guarantee that we aren't a process group leader. */ if (fork() != 0) { /* Parent. */ if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) { exit(0); } } else { /* Child. */ #ifdef HAVE_SETSID /* Become a process/session group leader. */ setsid(); #endif /* * Fork to let the process/session group leader exit. */ if (fork() != 0) { /* Parent. */ exit(0); } #ifndef WIN32 else { /* Child. */ /* Avoid keeping any directory in use. */ chdir("/"); if (!stderr_log) { /* * Close inherited file descriptors to avoid * keeping unnecessary references. */ close(0); close(1); close(2); /* * Redirect std{in,out,err} to /dev/null, just in * case. */ open("/dev/null", O_RDWR); dup(0); dup(0); } } #endif /* !WIN32 */ } } #endif /* HAVE_FORK */ SOCK_STARTUP; init_agent("snmpd"); /* do what we need to do first. */ init_mib_modules(); /* * start library */ init_snmp("snmpd"); if ((ret = init_master_agent()) != 0) { /* * Some error opening one of the specified agent transports. */ Exit(1); /* Exit logs exit val for us */ } #ifdef SIGTERM DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n")); signal(SIGTERM, SnmpdShutDown); #endif #ifdef SIGINT DEBUGMSGTL(("signal", "registering SIGINT signal handler\n")); signal(SIGINT, SnmpdShutDown); #endif #ifdef SIGHUP DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n")); signal(SIGHUP, SnmpdReconfig); #endif #ifdef SIGUSR1 DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n")); signal(SIGUSR1, SnmpdDump); #endif #ifdef SIGPIPE DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n")); signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif /* * Store persistent data immediately in case we crash later. */ snmp_store("snmpd"); /* * Send coldstart trap if possible. */ send_easy_trap(0, 0); #if HAVE_GETPID if (pid_file != NULL) { /* * unlink the pid_file, if it exists, prior to open. Without * doing this the open will fail if the user specified pid_file * already exists. */ unlink(pid_file); fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600); if (fd == -1) { snmp_log_perror(pid_file); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } else { if ((PID = fdopen(fd, "w")) == NULL) { snmp_log_perror(pid_file); exit(1); } else { fprintf(PID, "%d\n", (int) getpid()); fclose(PID); } close(fd); } } #endif #if HAVE_UNISTD_H #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) != 0) { DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) != 0) { DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #endif /* * We're up, log our version number. */ snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); #ifdef WIN32 agent_status = AGENT_RUNNING; #endif netsnmp_addrcache_initialise(); /* * Forever monitor the dest_port for incoming PDUs. */ DEBUGMSGTL(("snmpd/main", "We're up. Starting to process data.\n")); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) receive(); #include "mib_module_shutdown.h" DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n")); SnmpTrapNodeDown(); DEBUGMSGTL(("snmpd/main", "Bye...\n")); snmp_shutdown("snmpd"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE) && (pid_file != NULL)) { unlink(pid_file); } #ifdef WIN32 agent_status = AGENT_STOPPED; #endif return 0; } /* End main() -- snmpd */