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 */
static void updateLogmatch(int iindex) { int matchResultCode; char inbuf[1024]; char perfilename[1024]; FILE *perfile; unsigned long pos, ccounter, counter; int result; int toobig; int anyChanges = FALSE; struct stat sb; char lastFilename[256]; /* * ------------------------------------ * we can never be sure if this is the * last time we are being called here, * so we always update a persistent * data file with our current file * position * ------------------------------------ */ snprintf(perfilename, sizeof(perfilename), "%s/snmpd_logmatch_%s.pos", get_persistent_directory(), logmatchTable[iindex].name); if (logmatchTable[iindex].virgin) { /* * ------------------------------------ * this is the first time we are being * called; let's try to find an old * file position stored in a persistent * data file and restore it * ------------------------------------ */ if ((perfile = fopen(perfilename, "r"))) { /* * ------------------------------------ * the persistent data file exists so * let's read it out * ------------------------------------ */ pos = counter = ccounter = 0; if (fscanf(perfile, "%lu %lu %lu %s", &pos, &ccounter, &counter, lastFilename)) { /* * ------------------------------------ * the data could be read; now let's * try to open the logfile to be * scanned * ------------------------------------ */ if (logmatch_update_filename(logmatchTable[iindex].filenamePattern, lastFilename) == 0) { /* * --------------------------------- * the filename is still the same as * the one stored in the persistent * data file. * --------------------------------- */ if ((logmatchTable[iindex].logfile = fopen(logmatchTable[iindex].filename, "r"))) { /* * ------------------------------------ * the log file could be opened; now * let's try to set the pointer * ------------------------------------ */ if (!fseek (logmatchTable[iindex].logfile, pos, SEEK_SET)) { /* * ------------------------------------ * the pointer could be set - this is * the most that we can do: if the * pointer is smaller than the file * size we must assume that the pointer * still points to where it read the * file last time; let's restore the * data * ------------------------------------ */ logmatchTable[iindex].currentFilePosition = pos; logmatchTable[iindex].currentMatchCounter = ccounter; } fclose(logmatchTable[iindex].logfile); } } logmatchTable[iindex].globalMatchCounter = counter; } fclose(perfile); } logmatchTable[iindex].virgin = FALSE; } /* * ------------------------------------------- * check if a new input file needs to be opened * if yes, reset counter and position * ------------------------------------------- */ if (logmatch_update_filename(logmatchTable[iindex].filenamePattern, logmatchTable[iindex].filename) == 1) { logmatchTable[iindex].currentFilePosition = 0; logmatchTable[iindex].currentMatchCounter = 0; } /* * ------------------------------------ * now the pointer and the counter are * set either zero or reset to old * value; now let's try to read some * data * ------------------------------------ */ if (stat(logmatchTable[iindex].filename, &sb) == 0) { if (logmatchTable[iindex].currentFilePosition > sb.st_size) { toobig = TRUE; } else { toobig = FALSE; } if ((logmatchTable[iindex].logfile = fopen(logmatchTable[iindex].filename, "r"))) { result = fseek(logmatchTable[iindex].logfile, logmatchTable[iindex].currentFilePosition, SEEK_SET); if (result || toobig || (errno == EINVAL) || feof(logmatchTable[iindex].logfile)) { /* * ------------------------------------ * when we are here that means we * could't set the file position maybe * the file was rotated; let's reset * the filepointer, but not the counter * ------------------------------------ */ logmatchTable[iindex].currentFilePosition = 0; logmatchTable[iindex].currentMatchCounter = 0; fseek(logmatchTable[iindex].logfile, 0, SEEK_SET); anyChanges = TRUE; } while (fgets (inbuf, sizeof(inbuf), logmatchTable[iindex].logfile)) { matchResultCode = regexec(&(logmatchTable[iindex].regexBuffer), inbuf, 0, NULL, REG_NOTEOL); if (matchResultCode == 0) { logmatchTable[iindex].globalMatchCounter++; logmatchTable[iindex].currentMatchCounter++; logmatchTable[iindex].matchCounter++; anyChanges = TRUE; } } logmatchTable[iindex].currentFilePosition = ftell(logmatchTable[iindex].logfile); fclose(logmatchTable[iindex].logfile); } } /* * ------------------------------------ * at this point we can be safe that * our current file position is * straightened out o.k. - we never * know if this is the last time we are * being called so save the position * in a file * ------------------------------------ */ if (anyChanges && (perfile = fopen(perfilename, "w"))) { /* * ------------------------------------ * o.k. lets write out our variable * ------------------------------------ */ fprintf(perfile, "%lu %lu %lu %s\n", logmatchTable[iindex].currentFilePosition, logmatchTable[iindex].currentMatchCounter, logmatchTable[iindex].globalMatchCounter, logmatchTable[iindex].filename); fclose(perfile); } }
int get_exec_output(struct extensible *ex) { #if HAVE_EXECV && HAVE_FORK char cachefile[STRMAX]; char cache[NETSNMP_MAXCACHESIZE]; ssize_t cachebytes; int cfd; #ifdef NETSNMP_EXCACHETIME long curtime; static char lastcmd[STRMAX]; static int lastresult; #endif DEBUGMSGTL(("exec:get_exec_output","calling %s\n", ex->command)); sprintf(cachefile, "%s/%s", get_persistent_directory(), NETSNMP_CACHEFILE); #ifdef NETSNMP_EXCACHETIME curtime = time(NULL); if (curtime > (cachetime + NETSNMP_EXCACHETIME) || strcmp(ex->command, lastcmd) != 0) { strcpy(lastcmd, ex->command); cachetime = curtime; #endif cachebytes = NETSNMP_MAXCACHESIZE; ex->result = run_exec_command( ex->command, NULL, cache, &cachebytes ); unlink(cachefile); /* * XXX Use SNMP_FILEMODE_CLOSED instead of 644? */ if ((cfd = open(cachefile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) { snmp_log(LOG_ERR,"can not create cache file\n"); setPerrorstatus(cachefile); cachetime = 0; return -1; } if (cachebytes > 0) write(cfd, (void *) cache, cachebytes); close(cfd); #ifdef NETSNMP_EXCACHETIME lastresult = ex->result; } else { ex->result = lastresult; } #endif DEBUGMSGTL(("exec:get_exec_output","using cached value\n")); if ((cfd = open(cachefile, O_RDONLY)) < 0) { snmp_log(LOG_ERR,"can not open cache file\n"); setPerrorstatus(cachefile); return -1; } return (cfd); #else /* !HAVE_EXECV || !HAVE_FORK */ #if defined(WIN32) && !defined(HAVE_EXECV) /* MSVC and MinGW. Cygwin already works as it has execv and fork */ int fd; /* Reference: MS tech note: 190351 */ HANDLE hOutputReadTmp, hOutputRead, hOutputWrite = NULL; HANDLE hErrorWrite; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; STARTUPINFO si; sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; DEBUGMSGTL(("exec:get_exec_output","calling %s\n", ex->command)); /* Child temporary output pipe with Inheritance on (sa.bInheritHandle is true) */ if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes CreatePipe ChildOut: %d\n", GetLastError())); return -1; } /* Copy the stdout handle to the stderr handle in case the child closes one of * its stdout handles. */ if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, GetCurrentProcess(), &hErrorWrite,0, TRUE,DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs", "get_exec_output DuplicateHandle: %d\n", GetLastError())); return -1; } /* Create new copies of the input and output handles but set bInheritHandle to * FALSE so the new handle can not be inherited. Otherwise the handles can not * be closed. */ if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, GetCurrentProcess(), &hOutputRead, 0, FALSE, DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs", "get_exec_output DupliateHandle ChildOut: %d\n", GetLastError())); CloseHandle(hErrorWrite); return -1; } /* Close the temporary output and input handles */ if (!CloseHandle(hOutputReadTmp)) { DEBUGMSGTL(("util_funcs", "get_exec_output CloseHandle (hOutputReadTmp): %d\n", GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); return -1; } /* Associates a C run-time file descriptor with an existing operating-system file handle. */ fd = _open_osfhandle((long) hOutputRead, 0); /* Set up STARTUPINFO for CreateProcess with the handles and have it hide the window * for the new process. */ ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.hStdOutput = hOutputWrite; si.hStdError = hErrorWrite; si.wShowWindow = SW_HIDE; /* Launch the process that you want to redirect. Example snmpd.conf pass_persist: * pass_persist .1.3.6.1.4.1.2021.255 c:/perl/bin/perl c:/temp/pass_persisttest */ if (!CreateProcess(NULL, ex->command, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { DEBUGMSGTL(("util_funcs","get_exec_output CreateProcess:'%s' %d\n",ex->command, GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); return -1; } /* Set global child process handle */ ex->pid = (int)pi.hProcess; ex->tid = (int)pi.hThread; /* Close pipe handles to make sure that no handles to the write end of the * output pipe are maintained in this process or else the pipe will * not close when the child process exits and any calls to ReadFile * will hang. */ if (!CloseHandle(hOutputWrite)){ DEBUGMSGTL(("util_funcs","get_exec_output CloseHandle hOutputWrite: %d\n",ex->command, GetLastError())); return -1; } if (!CloseHandle(hErrorWrite)) { DEBUGMSGTL(("util_funcs","get_exec_output CloseHandle hErrorWrite: %d\n",ex->command, GetLastError())); return -1; } return fd; #endif /* WIN32 */ return -1; #endif }
int get_exec_output(struct extensible *ex) { #if HAVE_EXECV int fd[2], i, cnt; char ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv, **aptr; #ifdef EXCACHETIME char cachefile[STRMAX]; char cache[MAXCACHESIZE]; ssize_t cachebytes; long curtime; static char lastcmd[STRMAX]; int cfd; static int lastresult; int readcount; #endif #ifdef EXCACHETIME sprintf(cachefile, "%s/%s", get_persistent_directory(), CACHEFILE); curtime = time(NULL); if (curtime > (cachetime + EXCACHETIME) || strcmp(ex->command, lastcmd) != 0) { strcpy(lastcmd, ex->command); cachetime = curtime; #endif if (pipe(fd)) { setPerrorstatus("pipe"); #ifdef EXCACHETIME cachetime = 0; #endif return -1; } if ((ex->pid = fork()) == 0) { close(1); if (dup(fd[1]) != 1) { setPerrorstatus("dup"); return -1; } /* * write standard output and standard error to pipe. */ /* * close all other file descriptors. */ for (cnt = getdtablesize() - 1; cnt >= 2; --cnt) (void) close(cnt); (void) dup(1); /* stderr */ /* * set standard input to /dev/null */ close(0); (void) open("/dev/null", O_RDWR); for (cnt = 1, cptr1 = ex->command, cptr2 = argvs; cptr1 && *cptr1 != 0; cptr2++, cptr1++) { *cptr2 = *cptr1; if (*cptr1 == ' ') { *(cptr2++) = 0; if ((cptr1 = skip_white(cptr1)) == NULL) break; if (cptr1) { *cptr2 = *cptr1; if (*cptr1 != 0) cnt++; } } } *cptr2 = 0; *(cptr2 + 1) = 0; argv = (char **) malloc((cnt + 2) * sizeof(char *)); if (argv == NULL) return 0; /* memory alloc error */ aptr = argv; *(aptr++) = argvs; for (cptr2 = argvs, i = 1; i != cnt; cptr2++) if (*cptr2 == 0) { *(aptr++) = cptr2 + 1; i++; } while (*cptr2 != 0) cptr2++; *(aptr++) = NULL; copy_nword(ex->command, ctmp, sizeof(ctmp)); execv(ctmp, argv); perror(ctmp); exit(1); } else { close(fd[1]); if (ex->pid < 0) { close(fd[0]); setPerrorstatus("fork"); #ifdef EXCACHETIME cachetime = 0; #endif return -1; } #ifdef EXCACHETIME unlink(cachefile); /* * XXX Use SNMP_FILEMODE_CLOSED instead of 644? */ if ((cfd = open(cachefile, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { setPerrorstatus(cachefile); cachetime = 0; return -1; } fcntl(fd[0], F_SETFL, O_NONBLOCK); /* don't block on reads */ #ifdef HAVE_USLEEP for (readcount = 0; readcount <= MAXREADCOUNT * 100 && (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE)); readcount++) { #else for (readcount = 0; readcount <= MAXREADCOUNT && (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE)); readcount++) { #endif if (cachebytes > 0) write(cfd, (void *) cache, cachebytes); else if (cachebytes == -1 && errno != EAGAIN) { setPerrorstatus("read"); break; } else #ifdef HAVE_USLEEP usleep(10000); /* sleeps for 0.01 sec */ #else sleep(1); #endif } close(cfd); close(fd[0]); /* * wait for the child to finish */ if (ex->pid > 0 && waitpid(ex->pid, &ex->result, 0) < 0) { setPerrorstatus("waitpid()"); cachetime = 0; return -1; } ex->pid = 0; ex->result = WEXITSTATUS(ex->result); lastresult = ex->result; #else /* !EXCACHETIME */ return (fd[0]); #endif } #ifdef EXCACHETIME } else {
netsnmp_transport * netsnmp_ssh_transport(const struct sockaddr_in *addr, int local) { netsnmp_transport *t = NULL; netsnmp_ssh_addr_pair *addr_pair = NULL; int rc = 0; int i, auth_pw = 0; const char *fingerprint; char *userauthlist; struct sockaddr_un *unaddr; const char *sockpath = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSHTOSNMP_SOCKET); char tmpsockpath[MAXPATHLEN]; #ifdef NETSNMP_NO_LISTEN_SUPPORT if (local) return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ if (addr == NULL || addr->sin_family != AF_INET) { return NULL; } t = SNMP_MALLOC_TYPEDEF(netsnmp_transport); if (t == NULL) { return NULL; } t->domain = netsnmp_snmpSSHDomain; t->domain_length = netsnmp_snmpSSHDomain_len; t->flags = NETSNMP_TRANSPORT_FLAG_STREAM | NETSNMP_TRANSPORT_FLAG_TUNNELED; addr_pair = SNMP_MALLOC_TYPEDEF(netsnmp_ssh_addr_pair); if (addr_pair == NULL) { netsnmp_transport_free(t); return NULL; } t->data = addr_pair; t->data_length = sizeof(netsnmp_ssh_addr_pair); if (local) { #ifndef NETSNMP_NO_LISTEN_SUPPORT #ifdef SNMPSSHDOMAIN_USE_EXTERNAL_PIPE /* XXX: set t->local and t->local_length */ t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN; unaddr = &addr_pair->unix_socket_end; /* open a unix domain socket */ /* XXX: get data from the transport def for it's location */ unaddr->sun_family = AF_UNIX; if (NULL == sockpath) { sprintf(tmpsockpath, "%s/%s", get_persistent_directory(), DEFAULT_SOCK_NAME); sockpath = tmpsockpath; } snprintf(unaddr->sun_path, sizeof(unaddr->sun_path), "%s", sockpath); snprintf(addr_pair->socket_path, sizeof(addr_pair->socket_path), "%s", sockpath); t->sock = socket(PF_UNIX, SOCK_STREAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } /* set the SO_PASSCRED option so we can receive the remote uid */ { int one = 1; setsockopt(t->sock, SOL_SOCKET, SO_PASSCRED, (void *) &one, sizeof(one)); } unlink(unaddr->sun_path); rc = bind(t->sock, unaddr, SUN_LEN(unaddr)); if (rc != 0) { DEBUGMSGTL(("netsnmp_ssh_transport", "couldn't bind \"%s\", errno %d (%s)\n", unaddr->sun_path, errno, strerror(errno))); netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* set the socket permissions */ { /* * Apply any settings to the ownership/permissions of the * Sshdomain socket */ int sshdomain_sock_perm = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_SSHDOMAIN_SOCK_PERM); int sshdomain_sock_user = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_SSHDOMAIN_SOCK_USER); int sshdomain_sock_group = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_SSHDOMAIN_SOCK_GROUP); DEBUGMSGTL(("ssh", "here: %s, %d, %d, %d\n", unaddr->sun_path, sshdomain_sock_perm, sshdomain_sock_user, sshdomain_sock_group)); if (sshdomain_sock_perm != 0) { DEBUGMSGTL(("ssh", "Setting socket perms to %d\n", sshdomain_sock_perm)); chmod(unaddr->sun_path, sshdomain_sock_perm); } if (sshdomain_sock_user || sshdomain_sock_group) { /* * If either of user or group haven't been set, * then leave them unchanged. */ if (sshdomain_sock_user == 0 ) sshdomain_sock_user = -1; if (sshdomain_sock_group == 0 ) sshdomain_sock_group = -1; DEBUGMSGTL(("ssh", "Setting socket user/group to %d/%d\n", sshdomain_sock_user, sshdomain_sock_group)); chown(unaddr->sun_path, sshdomain_sock_user, sshdomain_sock_group); } } rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN); if (rc != 0) { DEBUGMSGTL(("netsnmp_ssh_transport", "couldn't listen to \"%s\", errno %d (%s)\n", unaddr->sun_path, errno, strerror(errno))); netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } #else /* we're called directly by sshd and use stdin/out */ /* for ssh on the server side we've been launched so bind to stdin/out */ /* nothing to do */ /* XXX: verify we're inside ssh */ t->sock = STDIN_FILENO; #endif /* ! SNMPSSHDOMAIN_USE_EXTERNAL_PIPE */ #else /* NETSNMP_NO_LISTEN_SUPPORT */ netsnmp_transport_free(t); return NULL; #endif /* NETSNMP_NO_LISTEN_SUPPORT */ } else { char *username; char *keyfilepub; char *keyfilepriv; /* use the requested user name */ /* XXX: default to the current user name on the system like ssh does */ username = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSH_USERNAME); if (!username || 0 == *username) { snmp_log(LOG_ERR, "You must specify a ssh username to use. See the snmp.conf manual page\n"); netsnmp_transport_free(t); return NULL; } /* use the requested public key file */ keyfilepub = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSH_PUBKEY); if (!keyfilepub || 0 == *keyfilepub) { /* XXX: default to ~/.ssh/id_rsa.pub */ snmp_log(LOG_ERR, "You must specify a ssh public key file to use. See the snmp.conf manual page\n"); netsnmp_transport_free(t); return NULL; } /* use the requested private key file */ keyfilepriv = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SSH_PRIVKEY); if (!keyfilepriv || 0 == *keyfilepriv) { /* XXX: default to keyfilepub without the .pub suffix */ snmp_log(LOG_ERR, "You must specify a ssh private key file to use. See the snmp.conf manual page\n"); netsnmp_transport_free(t); return NULL; } /* xxx: need an ipv6 friendly one too (sigh) */ /* XXX: not ideal when structs don't actually match size wise */ memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in)); t->sock = socket(PF_INET, SOCK_STREAM, 0); if (t->sock < 0) { netsnmp_transport_free(t); return NULL; } t->remote_length = sizeof(*addr); t->remote = netsnmp_memdup(addr, sizeof(*addr)); if (!t->remote) { netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* * This is a client-type session, so attempt to connect to the far * end. We don't go non-blocking here because it's not obvious what * you'd then do if you tried to do snmp_sends before the connection * had completed. So this can block. */ rc = connect(t->sock, addr, sizeof(struct sockaddr)); if (rc < 0) { netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* * Allow user to override the send and receive buffers. Default is * to use os default. Don't worry too much about errors -- * just plough on regardless. */ netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0); netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0); /* open the SSH session and channel */ addr_pair->session = libssh2_session_init(); if (libssh2_session_startup(addr_pair->session, t->sock)) { shutdown: snmp_log(LOG_ERR, "Failed to establish an SSH session\n"); netsnmp_ssh_close(t); netsnmp_transport_free(t); return NULL; } /* At this point we havn't authenticated, The first thing to do is check the hostkey's fingerprint against our known hosts Your app may have it hard coded, may go to a file, may present it to the user, that's your call */ fingerprint = libssh2_hostkey_hash(addr_pair->session, LIBSSH2_HOSTKEY_HASH_MD5); DEBUGMSGTL(("ssh", "Fingerprint: ")); for(i = 0; i < 16; i++) { DEBUGMSG(("ssh", "%02x", (unsigned char)fingerprint[i])); } DEBUGMSG(("ssh", "\n")); /* check what authentication methods are available */ userauthlist = libssh2_userauth_list(addr_pair->session, username, strlen(username)); DEBUGMSG(("ssh", "Authentication methods: %s\n", userauthlist)); /* XXX: allow other types */ /* XXX: 4 seems magic to me... */ if (strstr(userauthlist, "publickey") != NULL) { auth_pw |= 4; } /* XXX: hard coded paths and users */ if (auth_pw & 4) { /* public key */ if (libssh2_userauth_publickey_fromfile(addr_pair->session, username, keyfilepub, keyfilepriv, NULL)) { snmp_log(LOG_ERR,"Authentication by public key failed!\n"); goto shutdown; } else { DEBUGMSG(("ssh", "\tAuthentication by public key succeeded.\n")); } } else { snmp_log(LOG_ERR,"Authentication by public key failed!\n"); goto shutdown; } /* we've now authenticated both sides; contining onward ... */ /* Request a channel */ if (!(addr_pair->channel = libssh2_channel_open_session(addr_pair->session))) { snmp_log(LOG_ERR, "Unable to open a session\n"); goto shutdown; } /* Request a terminal with 'vanilla' terminal emulation * See /etc/termcap for more options */ /* XXX: needed? doubt it */ /* if (libssh2_channel_request_pty(addr_pair->channel, "vanilla")) { */ /* snmp_log(LOG_ERR, "Failed requesting pty\n"); */ /* goto shutdown; */ /* } */ if (libssh2_channel_subsystem(addr_pair->channel, "snmp")) { snmp_log(LOG_ERR, "Failed to request the ssh 'snmp' subsystem\n"); goto shutdown; } } DEBUGMSG(("ssh","Opened connection.\n")); /* * Message size is not limited by this transport (hence msgMaxSize * is equal to the maximum legal size of an SNMP message). */ t->msgMaxSize = SNMP_MAX_PACKET_LEN; t->f_recv = netsnmp_ssh_recv; t->f_send = netsnmp_ssh_send; t->f_close = netsnmp_ssh_close; t->f_accept = netsnmp_ssh_accept; t->f_fmtaddr = netsnmp_ssh_fmtaddr; return t; }