summaryrefslogtreecommitdiffstats
path: root/win32.c
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-07-26 07:27:03 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-07-26 07:27:03 +0000
commit5a2e9a2587372aeb4b74fa1aadf53283ed7cae10 (patch)
treebc79922f81699bc51c2ac047309e6ab594eebcd2 /win32.c
parent26bb4c740b12cf3f606f657103a1695c23f6b72f (diff)
downloadopenvpn-5a2e9a2587372aeb4b74fa1aadf53283ed7cae10.tar.gz
openvpn-5a2e9a2587372aeb4b74fa1aadf53283ed7cae10.tar.xz
openvpn-5a2e9a2587372aeb4b74fa1aadf53283ed7cae10.zip
Completely revamped the system for calling external programs and scripts:
* All external programs and scripts are now called by execve() on unix and CreateProcess on Windows. * The system() function is no longer used. * Argument lists for external programs and scripts are now built by the new argv_printf function which natively outputs to string arrays (i.e. char *argv[] lists), never truncates its output, and eliminates the security issues inherent in formatting and parsing command lines, and dealing with argument quoting. * The --script-security directive has been added to offer policy controls on OpenVPN's execution of external programs and scripts. Also added a new plugin example (openvpn/plugin/examples/log.c) that logs information to stdout for every plugin method called by OpenVPN. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3122 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to 'win32.c')
-rw-r--r--win32.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/win32.c b/win32.c
index 516bf8e..ec9247e 100644
--- a/win32.c
+++ b/win32.c
@@ -35,6 +35,7 @@
#include "mtu.h"
#include "sig.h"
#include "win32.h"
+#include "misc.h"
#include "memdbg.h"
@@ -69,6 +70,11 @@ struct window_title window_title; /* GLOBAL*/
struct semaphore netcmd_semaphore; /* GLOBAL */
+/*
+ * Windows system pathname such as c:\windows
+ */
+static char *win_sys_path = NULL; /* GLOBAL */
+
void
init_win32 (void)
{
@@ -100,6 +106,7 @@ uninit_win32 (void)
window_title_restore (&window_title);
win32_signal_close (&win32_signal);
WSACleanup ();
+ free (win_sys_path);
}
void
@@ -816,4 +823,174 @@ win_safe_filename (const char *fn)
return true;
}
+/*
+ * Service functions for openvpn_execve
+ */
+
+static char *
+env_block (const struct env_set *es)
+{
+ if (es)
+ {
+ struct env_item *e;
+ char *ret;
+ char *p;
+ size_t nchars = 1;
+
+ for (e = es->list; e != NULL; e = e->next)
+ nchars += strlen (e->string) + 1;
+
+ ret = (char *) malloc (nchars);
+ check_malloc_return (ret);
+
+ p = ret;
+ for (e = es->list; e != NULL; e = e->next)
+ {
+ if (env_allowed (e->string))
+ {
+ strcpy (p, e->string);
+ p += strlen (e->string) + 1;
+ }
+ }
+ *p = '\0';
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+static char *
+cmd_line (const struct argv *a)
+{
+ size_t nchars = 1;
+ size_t maxlen = 0;
+ size_t i;
+ struct buffer buf;
+ char *work = NULL;
+
+ if (!a)
+ return NULL;
+
+ for (i = 0; i < a->argc; ++i)
+ {
+ const char *arg = a->argv[i];
+ const size_t len = strlen (arg);
+ nchars += len + 3;
+ if (len > maxlen)
+ maxlen = len;
+ }
+
+ work = (char *) malloc (maxlen + 1);
+ check_malloc_return (work);
+ buf = alloc_buf (nchars);
+
+ for (i = 0; i < a->argc; ++i)
+ {
+ const char *arg = a->argv[i];
+ strcpy (work, arg);
+ string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_');
+ if (i)
+ buf_printf (&buf, " ");
+ if (string_class (work, CC_ANY, CC_SPACE))
+ buf_printf (&buf, "%s", work);
+ else
+ buf_printf (&buf, "\"%s\"", work);
+ }
+
+ free (work);
+ return BSTR(&buf);
+}
+
+/*
+ * Attempt to simulate fork/execve on Windows
+ */
+int
+openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
+{
+ int ret = -1;
+ if (a && a->argv[0])
+ {
+ if (openvpn_execve_allowed (flags))
+ {
+ STARTUPINFO start_info;
+ PROCESS_INFORMATION proc_info;
+
+ char *env = env_block (es);
+ char *cl = cmd_line (a);
+ char *cmd = a->argv[0];
+
+ CLEAR (start_info);
+ CLEAR (proc_info);
+
+ /* fill in STARTUPINFO struct */
+ GetStartupInfo(&start_info);
+ start_info.cb = sizeof(start_info);
+ start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ start_info.wShowWindow = SW_HIDE;
+ start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info))
+ {
+ DWORD exit_status = 0;
+ CloseHandle (proc_info.hThread);
+ WaitForSingleObject (proc_info.hProcess, INFINITE);
+ if (GetExitCodeProcess (proc_info.hProcess, &exit_status))
+ ret = (int)exit_status;
+ else
+ msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd);
+ CloseHandle (proc_info.hProcess);
+ }
+ else
+ {
+ msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd);
+ }
+ free (cl);
+ free (env);
+ }
+ else
+ {
+ msg (M_WARN, "openvpn_execve: external program may not be called due to setting of --script-security level");
+ }
+ }
+ else
+ {
+ msg (M_WARN, "openvpn_execve: called with empty argv");
+ }
+ return ret;
+}
+
+char *
+get_win_sys_path (void)
+{
+ ASSERT (win_sys_path);
+ return win_sys_path;
+}
+
+void
+set_win_sys_path (const char *newpath, struct env_set *es)
+{
+ free (win_sys_path);
+ win_sys_path = string_alloc (newpath, NULL);
+ setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */
+}
+
+void
+set_win_sys_path_via_env (struct env_set *es)
+{
+ char buf[256];
+ DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf));
+ if (!status)
+ msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME);
+ if (status > sizeof (buf) - 1)
+ msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME);
+ set_win_sys_path (buf, es);
+}
+
+void
+env_set_add_win32 (struct env_set *es)
+{
+ set_win_sys_path (DEFAULT_WIN_SYS_PATH, es);
+}
+
#endif