u_char * var_extensible_shell(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { static struct extensible *exten = 0; static long long_ret; int len; if (header_simple_table (vp, name, length, exact, var_len, write_method, numextens)) return (NULL); if ((exten = get_exten_instance(extens, name[*length - 1]))) { switch (vp->magic) { case MIBINDEX: long_ret = name[*length - 1]; return ((u_char *) (&long_ret)); case ERRORNAME: /* name defined in config file */ *var_len = strlen(exten->name); return ((u_char *) (exten->name)); case SHELLCOMMAND: *var_len = strlen(exten->command); return ((u_char *) (exten->command)); case ERRORFLAG: /* return code from the process */ len = sizeof(exten->output); if (exten->type == EXECPROC) { exten->result = run_exec_command( exten->command, NULL, exten->output, &len); } else { exten->result = run_shell_command(exten->command, NULL, exten->output, &len); } long_ret = exten->result; return ((u_char *) (&long_ret)); case ERRORMSG: /* first line of text returned from the process */ len = sizeof(exten->output); if (exten->type == EXECPROC) { exten->result = run_exec_command( exten->command, NULL, exten->output, &len); } else { exten->result = run_shell_command(exten->command, NULL, exten->output, &len); } *var_len = strlen(exten->output); if (exten->output[*var_len - 1] == '\n') exten->output[--(*var_len)] = '\0'; return ((u_char *) (exten->output)); case ERRORFIX: *write_method = fixExecError; long_return = 0; return ((u_char *) & long_return); case ERRORFIXCMD: *var_len = strlen(exten->fixcmd); return ((u_char *) exten->fixcmd); } return NULL; } return NULL; }
u_char * var_extensible_relocatable(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { int i; int len; struct extensible *exten = 0; static long long_ret; static char errmsg[STRMAX]; char *cp, *cp1; struct variable myvp; oid tname[MAX_OID_LEN]; memcpy(&myvp, vp, sizeof(struct variable)); long_ret = *length; for (i = 1; i <= (int) numrelocs; i++) { exten = get_exten_instance(relocs, i); if (!exten) continue; if ((int) exten->miblen == (int) vp->namelen - 1) { memcpy(myvp.name, exten->miboid, exten->miblen * sizeof(oid)); myvp.namelen = exten->miblen; *length = vp->namelen; memcpy(tname, vp->name, vp->namelen * sizeof(oid)); if (!header_simple_table (&myvp, tname, length, -1, var_len, write_method, -1)) break; else exten = NULL; } } if (i > (int) numrelocs || exten == NULL) { *length = long_ret; *var_len = 0; *write_method = NULL; return (NULL); } *length = long_ret; if (header_simple_table(vp, name, length, exact, var_len, write_method, ((vp->magic == ERRORMSG) ? MAXMSGLINES : 1))) return (NULL); switch (vp->magic) { case MIBINDEX: long_ret = name[*length - 1]; return ((u_char *) (&long_ret)); case ERRORNAME: /* name defined in config file */ *var_len = strlen(exten->name); return ((u_char *) (exten->name)); case SHELLCOMMAND: *var_len = strlen(exten->command); return ((u_char *) (exten->command)); case ERRORFLAG: /* return code from the process */ len = sizeof(exten->output); if (exten->type == EXECPROC) exten->result = run_exec_command( exten->command, NULL, exten->output, &len); else exten->result = run_shell_command(exten->command, NULL, exten->output, &len); long_ret = exten->result; return ((u_char *) (&long_ret)); case ERRORMSG: /* first line of text returned from the process */ len = sizeof(exten->output); if (exten->type == EXECPROC) exten->result = run_exec_command( exten->command, NULL, exten->output, &len); else exten->result = run_shell_command(exten->command, NULL, exten->output, &len); /* * Pick the output string apart into individual lines, * and extract the one being asked for.... */ cp1 = exten->output; for (i = 1; i != (int) name[*length - 1]; i++) { cp = strchr(cp1, '\n'); if (!cp) { *var_len = 0; /* wait_on_exec(exten); ??? */ return NULL; } cp1 = ++cp; } /* * ... and quit if we've run off the end of the output */ if (!*cp1) { *var_len = 0; return NULL; } cp = strchr(cp1, '\n'); if (cp) *cp = 0; strlcpy(errmsg, cp1, sizeof(errmsg)); *var_len = strlen(errmsg); if (errmsg[*var_len - 1] == '\n') errmsg[--(*var_len)] = '\0'; return ((u_char *) (errmsg)); case ERRORFIX: *write_method = fixExecError; long_return = 0; return ((u_char *) & long_return); case ERRORFIXCMD: *var_len = strlen(exten->fixcmd); return ((u_char *) exten->fixcmd); } return NULL; }
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 }