summaryrefslogtreecommitdiff
path: root/agent/mibgroup/util_funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/util_funcs.c')
-rw-r--r--agent/mibgroup/util_funcs.c1129
1 files changed, 1129 insertions, 0 deletions
diff --git a/agent/mibgroup/util_funcs.c b/agent/mibgroup/util_funcs.c
new file mode 100644
index 0000000..4c34c32
--- /dev/null
+++ b/agent/mibgroup/util_funcs.c
@@ -0,0 +1,1129 @@
+/*
+ * util_funcs.c
+ */
+/*
+ * Portions of this file are copyrighted by:
+ * Copyright Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms specified in the COPYING file
+ * distributed with the Net-SNMP package.
+ */
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-features.h>
+
+#include <sys/types.h>
+#if HAVE_IO_H
+#include <io.h>
+#endif
+#include <stdio.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef __alpha
+#ifndef _BSD
+#define _BSD
+#define _myBSD
+#endif
+#endif
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef __alpha
+#ifdef _myBSD
+#undef _BSD
+#undef _myBSD
+#endif
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#include <ctype.h>
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_BASETSD_H
+#include <basetsd.h>
+#define ssize_t SSIZE_T
+#endif
+#if HAVE_RAISE
+#define alarm raise
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include <net-snmp/library/snmp_logging.h>
+
+#include "struct.h"
+#include "util_funcs.h"
+#include "utilities/execute.h"
+
+#if HAVE_LIMITS_H
+#include "limits.h"
+#endif
+#ifdef USING_UCD_SNMP_ERRORMIB_MODULE
+#include "ucd-snmp/errormib.h"
+#else
+#define setPerrorstatus(x) snmp_log_perror(x)
+#endif
+
+netsnmp_feature_child_of(util_funcs, libnetsnmpmibs)
+
+netsnmp_feature_child_of(shell_command, util_funcs)
+netsnmp_feature_child_of(get_exten_instance, util_funcs)
+netsnmp_feature_child_of(clear_cache, util_funcs)
+netsnmp_feature_child_of(find_field, util_funcs)
+netsnmp_feature_child_of(parse_miboid, util_funcs)
+netsnmp_feature_child_of(string_append_int, util_funcs)
+netsnmp_feature_child_of(internal_mib_table, util_funcs)
+
+#if defined(HAVE_LINUX_RTNETLINK_H)
+netsnmp_feature_child_of(prefix_info_all, util_funcs)
+netsnmp_feature_child_of(prefix_info, prefix_info_all)
+netsnmp_feature_child_of(update_prefix_info, prefix_info_all)
+netsnmp_feature_child_of(delete_prefix_info, prefix_info_all)
+netsnmp_feature_child_of(find_prefix_info, prefix_info_all)
+netsnmp_feature_child_of(create_prefix_info, prefix_info_all)
+#endif /* HAVE_LINUX_RTNETLINK_H */
+
+#ifdef NETSNMP_EXCACHETIME
+static long cachetime;
+#endif
+
+extern int numprocs, numextens;
+
+/** deprecated, use netsnmp_mktemp instead */
+const char *
+make_tempfile(void)
+{
+ return netsnmp_mktemp();
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_SHELL_COMMAND
+int
+shell_command(struct extensible *ex)
+{
+#if HAVE_SYSTEM
+ const char *ofname;
+ char shellline[STRMAX];
+ FILE *shellout;
+
+ ofname = make_tempfile();
+ if (ofname == NULL) {
+ ex->output[0] = 0;
+ ex->result = 127;
+ return ex->result;
+ }
+
+ snprintf(shellline, sizeof(shellline), "%s > %s", ex->command, ofname);
+ shellline[ sizeof(shellline)-1 ] = 0;
+ ex->result = system(shellline);
+ ex->result = WEXITSTATUS(ex->result);
+ shellout = fopen(ofname, "r");
+ if (shellout != NULL) {
+ if (fgets(ex->output, sizeof(ex->output), shellout) == NULL) {
+ ex->output[0] = 0;
+ }
+ fclose(shellout);
+ }
+ unlink(ofname);
+#else
+ ex->output[0] = 0;
+ ex->result = 0;
+#endif
+ return (ex->result);
+}
+#endif /* NETSNMP_FEATURE_REMOVE_SHELL_COMMAND */
+
+#define MAXOUTPUT 300
+
+int
+exec_command(struct extensible *ex)
+{
+#if defined (HAVE_EXECV) || defined (WIN32)
+ int fd;
+ FILE *file;
+
+ if ((fd = get_exec_output(ex)) != -1) {
+ file = fdopen(fd, "r");
+ if (fgets(ex->output, sizeof(ex->output), file) == NULL) {
+ ex->output[0] = 0;
+ }
+ fclose(file);
+ wait_on_exec(ex);
+ } else
+#endif /* HAVE_EXECV */
+ {
+ ex->output[0] = 0;
+ ex->result = 0;
+ }
+ return (ex->result);
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_GET_EXTEN_INSTANCE
+struct extensible *
+get_exten_instance(struct extensible *exten, size_t inst)
+{
+ int i;
+
+ if (exten == NULL)
+ return (NULL);
+ for (i = 1; i != (int) inst && exten != NULL; i++)
+ exten = exten->next;
+ return (exten);
+}
+#endif /* NETSNMP_FEATURE_REMOVE_GET_EXTEN_INSTANCE */
+
+void
+wait_on_exec(struct extensible *ex)
+{
+#if defined(WIN32) && !defined (mingw32)
+ int rc;
+ if (ex->tid != 0 && ex->pid != 0) {
+ HANDLE hThread = ex->tid;
+ HANDLE hProcess = ex->pid;
+ rc = WaitForSingleObject(hProcess, NETSNMP_TIMEOUT_WAITFORSINGLEOBJECT);
+ DEBUGMSGT(("exec:wait_on_exec","WaitForSingleObject rc=(%d)\n",rc ));
+ rc = CloseHandle( hThread );
+ DEBUGMSGT(("exec:wait_on_exec","CloseHandle hThread=(%d)\n",rc ));
+ rc = CloseHandle( hProcess );
+ DEBUGMSGT(("exec:wait_on_exec","CloseHandle hProcess=(%d)\n",rc ));
+ ex->pid = 0;
+ ex->tid = 0;
+ }
+#else
+#ifndef NETSNMP_EXCACHETIME
+ if (ex->pid && waitpid(ex->pid, &ex->result, 0) < 0) {
+ setPerrorstatus("waitpid");
+ }
+ ex->pid = 0;
+#endif /* NETSNMP_EXCACHETIME */
+#endif /* WIN32 */
+}
+
+#define MAXARGS 30
+
+int
+get_exec_output(struct extensible *ex)
+{
+#ifndef USING_UTILITIES_EXECUTE_MODULE
+ ex->result = -1;
+ NETSNMP_LOGONCE((LOG_WARNING, "support for run_exec_command not available\n"));
+#else
+#if HAVE_EXECV
+ char cachefile[STRMAX];
+ char cache[NETSNMP_MAXCACHESIZE];
+ int 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);
+#ifdef NETSNMP_EXCACHETIME
+ cachetime = 0;
+#endif
+ 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 */
+#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: %lu\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: %lu\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: %lu\n", GetLastError()));
+ CloseHandle(hErrorWrite);
+ return -1;
+ }
+
+ /* Close the temporary output and input handles */
+ if (!CloseHandle(hOutputReadTmp)) {
+ DEBUGMSGTL(("util_funcs", "get_exec_output CloseHandle (hOutputReadTmp): %lu\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' %lu\n",ex->command, GetLastError()));
+ CloseHandle(hErrorWrite);
+ CloseHandle(hOutputRead);
+ return -1;
+ }
+
+ /* Set global child process handle */
+ ex->pid = pi.hProcess;
+ ex->tid = 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: %lu\n",
+ GetLastError()));
+ return -1;
+ }
+ if (!CloseHandle(hErrorWrite)) {
+ DEBUGMSGTL(("util_funcs","get_exec_output CloseHandle hErrorWrite: %lu\n",
+ GetLastError()));
+ return -1;
+ }
+ return fd;
+#endif /* WIN32 */
+#endif
+#endif /* !defined(USING_UTILITIES_EXECUTE_MODULE) */
+ return -1;
+}
+int
+get_exec_pipes(char *cmd, int *fdIn, int *fdOut, netsnmp_pid_t *pid)
+{
+/* Alexander Prömel, alexander@proemel.de 08/24/2006
+ The following code, is tested on picotux rev. 1.01.
+ I think, it will be better to put the named pipes, into /var/run or make it selectable via CONFIG file.
+ If the pipe file already exist, the creation will fail.
+ I put the pipes into /flash, the pipepath has to change in ucd-snmp/pass_persist.c too, if you change it here.
+*/
+#if HAVE_EXECV
+#ifdef __uClinux__ /* HAVE uClinux */
+ int in,out;
+ char fifo_in_path[256];
+ char fifo_out_path[256];
+ pid_t tpid;
+
+ if ((tpid = vfork()) == 0) { /*temp child*/
+ execve(cmd, NULL,NULL);
+ perror(cmd);
+ exit(1);
+ } else {
+ if(tpid > 0) {
+ /*initialize workspace*/
+ snprintf(fifo_in_path, 256, "/flash/cp_%d", tpid);
+ snprintf(fifo_out_path, 256, "/flash/pc_%d", tpid);
+
+ in = mkfifo(fifo_in_path, S_IRWXU); /*Create Input Pipe, 700*/
+ if ( in ) {
+ perror("parent: inpipe");
+ exit(0);
+ }
+ out = mkfifo(fifo_out_path, S_IRWXU); /*Create Output Pipe, 700*/
+ if ( out ) {
+ perror("parent: outpipe");
+ exit(0);
+ }
+
+ in = open(fifo_in_path,O_RDONLY); /*open the Input Pipe read Only*/
+ if(in < 0) {
+ perror("parent: input");
+ exit(0);
+ }
+ out = open(fifo_out_path,O_WRONLY); /*open the Output Pipe write Only*/
+ if(out < 0) {
+ perror("parent: output");
+ exit(0);
+ }
+
+ *fdIn = in; /*read*/
+ *fdOut = out; /*write*/
+ *pid = tpid;
+ return (1); /* We are returning 0 for error... */
+ } else { /*pid < 0*/
+ setPerrorstatus("vfork");
+ return 0;
+ }
+
+ }
+#else /*HAVE x86*/
+ int fd[2][2], i, cnt;
+ char ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv,
+ **aptr;
+ /*
+ * Setup our pipes
+ */
+ if (pipe(fd[0]) || pipe(fd[1])) {
+ setPerrorstatus("pipe");
+ return 0;
+ }
+ if ((*pid = fork()) == 0) { /* First handle for the child */
+ close(0);
+ if (dup(fd[0][0]) != 0) {
+ setPerrorstatus("dup 0");
+ return 0;
+ }
+ close(1);
+ if (dup(fd[1][1]) != 1) {
+ setPerrorstatus("dup 1");
+ return 0;
+ }
+
+ /*
+ * write standard output and standard error to pipe.
+ */
+ /*
+ * close all non-standard open file descriptors
+ */
+ for (cnt = getdtablesize() - 1; cnt >= 2; --cnt)
+ (void) close(cnt);
+ (void) dup(1); /* stderr */
+
+ for (cnt = 1, cptr1 = cmd, cptr2 = argvs; *cptr1 != 0;
+ cptr2++, cptr1++) {
+ *cptr2 = *cptr1;
+ if (*cptr1 == ' ') {
+ *(cptr2++) = 0;
+ if ((cptr1 = skip_white(cptr1)) == NULL)
+ break;
+ *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(cmd, ctmp, sizeof(ctmp));
+ execv(ctmp, argv);
+ perror(ctmp);
+ exit(1);
+ } else {
+ close(fd[0][0]);
+ close(fd[1][1]);
+ if (*pid < 0) {
+ close(fd[0][1]);
+ close(fd[1][0]);
+ setPerrorstatus("fork");
+ return 0;
+ }
+ *fdIn = fd[1][0];
+ *fdOut = fd[0][1];
+ return (1); /* We are returning 0 for error... */
+ }
+#endif /* uClinux or x86 */
+#endif /* !HAVE_EXECV */
+#if defined(WIN32) && !defined (mingw32) && !defined(HAVE_EXECV)
+/* MSVC (MinGW not working but should use this code). Cygwin already works as it has execv and fork */
+ /* Reference: MS tech note: 190351 */
+ HANDLE hInputWriteTmp, hInputRead, hInputWrite = NULL;
+ 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;
+
+ /* 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 0;
+ }
+ /* Child temporary input pipe with Inheritance on (sa.bInheritHandle is true) */
+ if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) {
+ DEBUGMSGTL(("util_funcs", "get_exec_pipes CreatePipe ChildIn: %d\n", GetLastError()));
+ return 0;
+ }
+
+ /* 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_pipes DuplicateHandle: %d\n", GetLastError()));
+ return 0;
+ }
+
+ /* 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_pipes DupliateHandle ChildOut: %d\n", GetLastError()));
+ CloseHandle(hErrorWrite);
+ return 0;
+ }
+ if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
+ GetCurrentProcess(), &hInputWrite, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ DEBUGMSGTL(("util_funcs","get_exec_pipes DupliateHandle ChildIn: %d\n", GetLastError()));
+ CloseHandle(hErrorWrite);
+ CloseHandle(hOutputRead);
+ return 0;
+ }
+
+ /* Close the temporary output and input handles */
+ if (!CloseHandle(hOutputReadTmp)) {
+ DEBUGMSGTL(("util_funcs", "get_exec_pipes CloseHandle (hOutputReadTmp): %d\n", GetLastError()));
+ CloseHandle(hErrorWrite);
+ CloseHandle(hOutputRead);
+ CloseHandle(hInputWrite);
+ return 0;
+ }
+ if (!CloseHandle(hInputWriteTmp)) {
+ DEBUGMSGTL(("util_funcs", "get_exec_pipes CloseHandle (hInputWriteTmp): %d\n", GetLastError()));
+ CloseHandle(hErrorWrite);
+ CloseHandle(hOutputRead);
+ CloseHandle(hInputWrite);
+ return 0;
+ }
+
+ /* Associates a C run-time file descriptor with an existing operating-system file handle. */
+ *fdIn = _open_osfhandle((long) hOutputRead, 0);
+ *fdOut = _open_osfhandle((long) hInputWrite, 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.hStdInput = hInputRead;
+ 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, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
+ DEBUGMSGTL(("util_funcs","get_exec_pipes CreateProcess:'%s' %d\n",cmd, GetLastError()));
+ CloseHandle(hErrorWrite);
+ CloseHandle(hOutputRead);
+ CloseHandle(hInputWrite);
+ return 0;
+ }
+
+ DEBUGMSGTL(("util_funcs","child hProcess (stored in pid): %d\n",(int)pi.hProcess));
+ DEBUGMSGTL(("util_funcs","child dwProcessId (task manager): %d\n",(int)pi.dwProcessId));
+
+ /* Set global child process handle */
+ *pid = pi.hProcess;
+
+ /* Cleanup */
+ if (!CloseHandle(pi.hThread))
+ DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle pi.hThread: %d\n",cmd));
+
+ /* 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_pipes CloseHandle hOutputWrite: %d\n",cmd, GetLastError()));
+ return 0;
+ }
+ if (!CloseHandle(hInputRead)) {
+ DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle hInputRead: %d\n",cmd, GetLastError()));
+ return 0;
+ }
+ if (!CloseHandle(hErrorWrite)) {
+ DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle hErrorWrite: %d\n",cmd, GetLastError()));
+ return 0;
+ }
+ return 1;
+#endif /* WIN32 */
+ return 0;
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_CLEAR_CACHE
+int
+clear_cache(int action,
+ u_char * var_val,
+ u_char var_val_type,
+ size_t var_val_len,
+ u_char * statP, oid * name, size_t name_len)
+{
+
+ long tmp = 0;
+
+ if (var_val_type != ASN_INTEGER) {
+ snmp_log(LOG_NOTICE, "Wrong type != int\n");
+ return SNMP_ERR_WRONGTYPE;
+ }
+ tmp = *((long *) var_val);
+ if (tmp == 1 && action == COMMIT) {
+#ifdef NETSNMP_EXCACHETIME
+ cachetime = 0; /* reset the cache next read */
+#endif
+ }
+ return SNMP_ERR_NOERROR;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_CLEAR_CACHE */
+
+void
+print_mib_oid(oid name[], size_t len)
+{
+ char *buffer;
+ buffer = (char *) malloc(11 * len); /* maximum digit lengths for int32 + a '.' */
+ if (!buffer) {
+ snmp_log(LOG_ERR, "Malloc failed - out of memory?");
+ return;
+ }
+ sprint_mib_oid(buffer, name, len);
+ snmp_log(LOG_NOTICE, "Mib: %s\n", buffer);
+ free(buffer);
+}
+
+void
+sprint_mib_oid(char *buf, const oid *name, size_t len)
+{
+ int i;
+
+ for (i = 0; i < (int) len; i++)
+ buf += sprintf(buf, ".%" NETSNMP_PRIo "u", name[i]);
+}
+
+/*
+ * checkmib(): provided for backwards compatibility, do not use:
+ */
+int
+checkmib(struct variable *vp, oid * name, size_t * length,
+ int exact, size_t * var_len, WriteMethod ** write_method, int max)
+{
+ /*
+ * checkmib used to be header_simple_table, with reveresed boolean
+ * return output. header_simple_table() was created to match
+ * header_generic().
+ */
+ return (!header_simple_table(vp, name, length, exact, var_len,
+ write_method, max));
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_FIND_FIELD
+char *
+find_field(char *ptr, int field)
+{
+ int i;
+ char *init = ptr;
+
+ if (field == NETSNMP_LASTFIELD) {
+ /*
+ * skip to end
+ */
+ while (*ptr++);
+ ptr = ptr - 2;
+ /*
+ * rewind a field length
+ */
+ while (*ptr != 0 && isspace((unsigned char)(*ptr)) && init <= ptr)
+ ptr--;
+ while (*ptr != 0 && !isspace((unsigned char)(*ptr)) && init <= ptr)
+ ptr--;
+ if (isspace((unsigned char)(*ptr)))
+ ptr++; /* past space */
+ if (ptr < init)
+ ptr = init;
+ if (!isspace((unsigned char)(*ptr)) && *ptr != 0)
+ return (ptr);
+ } else {
+ if ((ptr = skip_white(ptr)) == NULL)
+ return (NULL);
+ for (i = 1; *ptr != 0 && i != field; i++) {
+ if ((ptr = skip_not_white(ptr)) == NULL)
+ return (NULL);
+ if ((ptr = skip_white(ptr)) == NULL)
+ return (NULL);
+ }
+ if (*ptr != 0 && i == field)
+ return (ptr);
+ return (NULL);
+ }
+ return (NULL);
+}
+#endif /* NETSNMP_FEATURE_REMOVE_FIND_FIELD */
+
+#ifndef NETSNMP_FEATURE_REMOVE_PARSE_MIBOID
+int
+parse_miboid(const char *buf, oid * oidout)
+{
+ int i;
+
+ if (!buf)
+ return 0;
+ if (*buf == '.')
+ buf++;
+ for (i = 0; isdigit((unsigned char)(*buf)); i++) {
+ /* Subidentifiers are unsigned values, up to 2^32-1
+ * so we need to use 'strtoul' rather than 'atoi'
+ */
+ oidout[i] = strtoul(buf, NULL, 10) & 0xffffffff;
+ while (isdigit((unsigned char)(*buf++)));
+ if (*buf == '.')
+ buf++;
+ }
+ /*
+ * oidout[i] = -1; hmmm
+ */
+ return i;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_PARSE_MIBOID */
+
+#ifndef NETSNMP_FEATURE_REMOVE_STRING_APPEND_INT
+void
+string_append_int(char *s, int val)
+{
+ char textVal[16];
+
+ if (val < 10) {
+ *s++ = '0' + val;
+ *s = '\0';
+ return;
+ }
+ sprintf(textVal, "%d", val);
+ strcpy(s, textVal);
+ return;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_STRING_APPEND_INT */
+
+#ifndef NETSNMP_FEATURE_REMOVE_INTERNAL_MIB_TABLE
+
+struct internal_mib_table {
+ int max_size; /* Size of the current data table */
+ int next_index; /* Index of the next free entry */
+ int current_index; /* Index of the 'current' entry */
+ int cache_timeout;
+ marker_t cache_markerM;
+ RELOAD *reload; /* Routine to read in the data */
+ COMPARE *compare; /* Routine to compare two entries */
+ int data_size; /* Size of an individual entry */
+ void *data; /* The table itself */
+};
+
+mib_table_t
+Initialise_Table(int size, int timeout, RELOAD *reload, COMPARE *compare)
+{
+ struct internal_mib_table *t;
+
+ t = (struct internal_mib_table *)
+ malloc(sizeof(struct internal_mib_table));
+ if (t == NULL)
+ return NULL;
+
+ t->max_size = 0;
+ t->next_index = 1; /* Don't use index 0 */
+ t->current_index = 1;
+ t->cache_timeout = timeout;
+ t->cache_markerM = NULL;
+ t->reload = reload;
+ t->compare = compare;
+ t->data_size = size;
+ t->data = NULL;
+
+ return (mib_table_t) t;
+}
+
+#define TABLE_ADD( x, y ) ((void*)((char*)(x) + y))
+#define TABLE_INDEX(t, i) (TABLE_ADD(t->data, i * t->data_size))
+#define TABLE_START(t) (TABLE_INDEX(t, 1))
+#define TABLE_NEXT(t) (TABLE_INDEX(t, t->next_index))
+#define TABLE_CURRENT(t) (TABLE_INDEX(t, t->current_index))
+
+int
+check_and_reload_table(struct internal_mib_table *table)
+{
+ /*
+ * If the saved data is fairly recent,
+ * we don't need to reload it
+ */
+ if (table->cache_markerM &&
+ !(netsnmp_ready_monotonic(table->cache_markerM,
+ table->cache_timeout * 1000)))
+ return 1;
+
+
+ /*
+ * Call the routine provided to read in the data
+ *
+ * N.B: Update the cache marker *before* calling
+ * this routine, to avoid problems with recursion
+ */
+ netsnmp_set_monotonic_marker(&table->cache_markerM);
+
+ table->next_index = 1;
+ if (table->reload((mib_table_t) table) < 0) {
+ free(table->cache_markerM);
+ table->cache_markerM = NULL;
+ return 0;
+ }
+ table->current_index = 1;
+ if (table->compare != NULL) /* Sort the table */
+ qsort(TABLE_START(table), table->next_index-1,
+ table->data_size, table->compare);
+ return 1;
+}
+
+int
+Search_Table(mib_table_t t, void *entry, int exact)
+{
+ struct internal_mib_table *table = (struct internal_mib_table *) t;
+ void *entry2;
+ int res;
+
+ if (!check_and_reload_table(table))
+ return -1;
+
+ if (table->compare == NULL) {
+ /*
+ * XXX - not sure this is right ?
+ */
+ memcpy(entry, table->data, table->data_size);
+ return 0;
+ }
+
+ if (table->next_index == table->current_index)
+ table->current_index = 1;
+
+ entry2 = TABLE_CURRENT(table);
+ res = table->compare(entry, entry2);
+ if ((res < 0) && (table->current_index != 1)) {
+ table->current_index = 1;
+ entry2 = TABLE_CURRENT(table);
+ res = table->compare(entry, entry2);
+ }
+
+ while (res > 0) {
+ table->current_index++;
+ if (table->next_index == table->current_index)
+ return -1;
+ entry2 = TABLE_CURRENT(table);
+ res = table->compare(entry, entry2);
+ }
+
+ if (exact && res != 0)
+ return -1;
+
+ if (!exact && res == 0) {
+ table->current_index++;
+ if (table->next_index == table->current_index)
+ return -1;
+ entry2 = TABLE_CURRENT(table);
+ }
+ memcpy(entry, entry2, table->data_size);
+ return 0;
+}
+
+int
+Add_Entry(mib_table_t t, void *entry)
+{
+ struct internal_mib_table *table = (struct internal_mib_table *) t;
+ int new_max;
+ void *new_data; /* Used for
+ * a) extending the data table
+ * b) the next entry to use
+ */
+
+ if (table->max_size <= table->next_index) {
+ /*
+ * Table is full, so extend it to double the size
+ */
+ new_max = 2 * table->max_size;
+ if (new_max == 0)
+ new_max = 10; /* Start with 10 entries */
+
+ new_data = (void *) malloc(new_max * table->data_size);
+ if (new_data == NULL)
+ return -1;
+
+ if (table->data) {
+ memcpy(new_data, table->data,
+ table->max_size * table->data_size);
+ free(table->data);
+ }
+ table->data = new_data;
+ table->max_size = new_max;
+ }
+
+ /*
+ * Insert the new entry into the data array
+ */
+ new_data = TABLE_NEXT(table);
+ memcpy(new_data, entry, table->data_size);
+ table->next_index++;
+ return 0;
+}
+
+void *
+Retrieve_Table_Data(mib_table_t t, int *max_idx)
+{
+ struct internal_mib_table *table = (struct internal_mib_table *) t;
+
+ if (!check_and_reload_table(table))
+ return NULL;
+ *max_idx = table->next_index - 1;
+ return table->data;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_INTERNAL_MIB_TABLE */
+
+#if defined(HAVE_LINUX_RTNETLINK_H)
+
+#ifndef NETSNMP_FEATURE_REMOVE_CREATE_PREFIX_INFO
+prefix_cbx *net_snmp_create_prefix_info(unsigned long OnLinkFlag,
+ unsigned long AutonomousFlag,
+ char *in6ptr)
+{
+ prefix_cbx *node = SNMP_MALLOC_TYPEDEF(prefix_cbx);
+ if(!in6ptr) {
+ free(node);
+ return NULL;
+ }
+ if(!node) {
+ free(node);
+ return NULL;
+ }
+ node->next_info = NULL;
+ node->ipAddressPrefixOnLinkFlag = OnLinkFlag;
+ node->ipAddressPrefixAutonomousFlag = AutonomousFlag;
+ memcpy(node->in6p, in6ptr, sizeof(node->in6p));
+
+ return node;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_CREATE_PREFIX_INFO */
+
+#ifndef NETSNMP_FEATURE_REMOVE_FIND_PREFIX_INFO
+int net_snmp_find_prefix_info(prefix_cbx **head,
+ char *address,
+ prefix_cbx *node_to_find)
+{
+ int iret;
+ memset(node_to_find, 0, sizeof(prefix_cbx));
+ if(!*head)
+ return -1;
+ memcpy(node_to_find->in6p, address, sizeof(node_to_find->in6p));
+
+ iret = net_snmp_search_update_prefix_info(head, node_to_find, 1);
+ if(iret < 0) {
+ DEBUGMSGTL(("util_funcs:prefix", "Unable to search the list\n"));
+ return -1;
+ } else if (!iret) {
+ DEBUGMSGTL(("util_funcs:prefix", "Could not find prefix info\n"));
+ return -1;
+ } else
+ return 0;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_FIND_PREFIX_INFO */
+
+#ifndef NETSNMP_FEATURE_REMOVE_UPDATE_PREFIX_INFO
+int net_snmp_update_prefix_info(prefix_cbx **head,
+ prefix_cbx *node_to_update)
+{
+ int iret;
+ iret = net_snmp_search_update_prefix_info(head, node_to_update, 0);
+ if(iret < 0) {
+ DEBUGMSGTL(("util_funcs:prefix", "Unable to update prefix info\n"));
+ return -1;
+ } else if (!iret) {
+ DEBUGMSGTL(("util_funcs:prefix", "Unable to find the node to update\n"));
+ return -1;
+ } else
+ return 0;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_UPDATE_PREFIX_INFO */
+
+int net_snmp_search_update_prefix_info(prefix_cbx **head,
+ prefix_cbx *node_to_use,
+ int functionality)
+{
+
+ /* We define functionality based on need *
+ * 0 - Need to do a search and update. We have to provide the node_to_use structure filled fully *
+ * 1 - Need to do only search. Provide the node_to_use with in6p value filled */
+
+ prefix_cbx *temp_node;
+ netsnmp_assert(NULL != head);
+ netsnmp_assert(NULL != node_to_use);
+
+ if(functionality > 1)
+ return -1;
+ if(!node_to_use)
+ return -1;
+
+
+ if (!functionality) {
+ if (!*head) {
+ *head = node_to_use;
+ return 1;
+ }
+
+ for (temp_node = *head; temp_node->next_info != NULL ; temp_node = temp_node->next_info) {
+ if (0 == strcmp(temp_node->in6p, node_to_use->in6p)) {
+ temp_node->ipAddressPrefixOnLinkFlag = node_to_use->ipAddressPrefixOnLinkFlag;
+ temp_node->ipAddressPrefixAutonomousFlag = node_to_use->ipAddressPrefixAutonomousFlag;
+ return 2;
+ }
+ }
+ temp_node->next_info = node_to_use;
+ return 1;
+ } else {
+ for (temp_node = *head; temp_node != NULL ; temp_node = temp_node->next_info) {
+ if (0 == strcmp(temp_node->in6p, node_to_use->in6p)) {
+ /*need yo put sem here as i read here */
+ node_to_use->ipAddressPrefixOnLinkFlag = temp_node->ipAddressPrefixOnLinkFlag;
+ node_to_use->ipAddressPrefixAutonomousFlag = temp_node->ipAddressPrefixAutonomousFlag;
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+
+#ifndef NETSNMP_FEATURE_REMOVE_DELETE_PREFIX_INFO
+int net_snmp_delete_prefix_info(prefix_cbx **head,
+ char *address)
+{
+
+ prefix_cbx *temp_node,*prev_node;
+ if(!address)
+ return -1;
+ if(!head)
+ return -1;
+
+ for (temp_node = *head, prev_node = NULL; temp_node;
+ prev_node = temp_node, temp_node = temp_node->next_info) {
+
+ if (temp_node->in6p && strcmp(temp_node->in6p, address) == 0) {
+ if (prev_node)
+ prev_node->next_info = temp_node->next_info;
+ else
+ *head = temp_node->next_info;
+ free(temp_node);
+ return 1;
+ }
+
+ }
+ return 0;
+}
+#endif /* NETSNMP_FEATURE_REMOVE_DELETE_PREFIX_INFO */
+
+#endif /* HAVE_LINUX_RTNETLINK_H */
+