1138 lines
34 KiB
C
1138 lines
34 KiB
C
/*
|
|
* 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.
|
|
*
|
|
* Portions of this file are copyrighted by:
|
|
* Copyright (c) 2016 VMware, 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 <net-snmp/agent/netsnmp_close_fds.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 */
|
|
|
|
#if defined(NETSNMP_EXCACHETIME) && defined(USING_UTILITIES_EXECUTE_MODULE) && defined(HAVE_EXECV)
|
|
static long cachetime;
|
|
#endif
|
|
|
|
/** 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 = NULL;
|
|
FILE *shellout;
|
|
|
|
ofname = make_tempfile();
|
|
if (ofname == NULL) {
|
|
ex->output[0] = 0;
|
|
ex->result = 127;
|
|
return ex->result;
|
|
}
|
|
|
|
if (asprintf(&shellline, "%s > %s", ex->command, ofname) >= 0) {
|
|
ex->result = system(shellline);
|
|
ex->result = WEXITSTATUS(ex->result);
|
|
free(shellline);
|
|
}
|
|
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) {
|
|
strlcpy(lastcmd, ex->command, sizeof(lastcmd));
|
|
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((intptr_t) 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 /* HAVE_EXEC */
|
|
#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(fd[0][1]);
|
|
close(fd[1][0]);
|
|
close(0);
|
|
if (dup(fd[0][0]) != 0) {
|
|
setPerrorstatus("dup 0");
|
|
return 0;
|
|
}
|
|
close(fd[0][0]);
|
|
close(1);
|
|
if (dup(fd[1][1]) != 1) {
|
|
setPerrorstatus("dup 1");
|
|
return 0;
|
|
}
|
|
close(fd[1][1]);
|
|
|
|
/*
|
|
* write standard output and standard error to pipe.
|
|
*/
|
|
/*
|
|
* close all non-standard open file descriptors
|
|
*/
|
|
netsnmp_close_fds(1);
|
|
(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((intptr_t) hOutputRead, 0);
|
|
*fdOut = _open_osfhandle((intptr_t) 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): %p\n", 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)
|
|
{
|
|
if (var_val_type != ASN_INTEGER) {
|
|
snmp_log(LOG_NOTICE, "Wrong type != int\n");
|
|
return SNMP_ERR_WRONGTYPE;
|
|
}
|
|
#if defined(NETSNMP_EXCACHETIME) && defined(USING_UTILITIES_EXECUTE_MODULE) && defined(HAVE_EXECV)
|
|
else {
|
|
long tmp = 0;
|
|
tmp = *((long *) var_val);
|
|
if (tmp == 1 && action == COMMIT) {
|
|
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))) 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 */
|
|
|