diff options
Diffstat (limited to 'agent/mibgroup/util_funcs.c')
-rw-r--r-- | agent/mibgroup/util_funcs.c | 1129 |
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 */ + |