summaryrefslogtreecommitdiff
path: root/win32.c
diff options
context:
space:
mode:
authorAlberto Gonzalez Iniesta <agi@inittab.org>2012-11-05 16:28:09 +0100
committerAlberto Gonzalez Iniesta <agi@inittab.org>2012-11-05 16:28:09 +0100
commit8dd0350e1607aa30f7a043c8d5ec7a7eeb874115 (patch)
tree566d0620eb693320cb121dfd93a5675fa704a30b /win32.c
parent349cfa7acb95abe865209a28e417ec74b56f9bba (diff)
Imported Upstream version 2.3_rc1
Diffstat (limited to 'win32.c')
-rw-r--r--win32.c1115
1 files changed, 0 insertions, 1115 deletions
diff --git a/win32.c b/win32.c
deleted file mode 100644
index 2b7bf7b..0000000
--- a/win32.c
+++ /dev/null
@@ -1,1115 +0,0 @@
-/*
- * OpenVPN -- An application to securely tunnel IP networks
- * over a single UDP port, with support for SSL/TLS-based
- * session authentication and key exchange,
- * packet encryption, packet authentication, and
- * packet compression.
- *
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * Win32-specific OpenVPN code, targetted at the mingw
- * development environment.
- */
-#include "syshead.h"
-
-#ifdef WIN32
-
-#include "buffer.h"
-#include "error.h"
-#include "mtu.h"
-#include "sig.h"
-#include "win32.h"
-#include "misc.h"
-
-#include "memdbg.h"
-
-/*
- * Windows internal socket API state (opaque).
- */
-static struct WSAData wsa_state; /* GLOBAL */
-
-/*
- * Should we call win32_pause() on program exit?
- */
-static bool pause_exit_enabled = false; /* GLOBAL */
-
-/*
- * win32_signal is used to get input from the keyboard
- * if we are running in a console, or get input from an
- * event object if we are running as a service.
- */
-
-struct win32_signal win32_signal; /* GLOBAL */
-
-/*
- * Save our old window title so we can restore
- * it on exit.
- */
-struct window_title window_title; /* GLOBAL*/
-
-/*
- * Special global semaphore used to protect network
- * shell commands from simultaneous instantiation.
- */
-
-struct semaphore netcmd_semaphore; /* GLOBAL */
-
-/*
- * Windows system pathname such as c:\windows
- */
-static char *win_sys_path = NULL; /* GLOBAL */
-
-/*
- * Configure PATH. On Windows, sometimes PATH is not set correctly
- * by default.
- */
-static void
-configure_win_path (void)
-{
- static bool done = false; /* GLOBAL */
- if (!done)
- {
- FILE *fp;
- fp = fopen ("c:\\windows\\system32\\route.exe", "rb");
- if (fp)
- {
- const int bufsiz = 4096;
- struct gc_arena gc = gc_new ();
- struct buffer oldpath = alloc_buf_gc (bufsiz, &gc);
- struct buffer newpath = alloc_buf_gc (bufsiz, &gc);
- const char* delim = ";";
- DWORD status;
- fclose (fp);
- status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
-#if 0
- status = 0;
-#endif
- if (!status)
- {
- *BPTR(&oldpath) = '\0';
- delim = "";
- }
- buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s",
- delim,
- BSTR(&oldpath));
- SetEnvironmentVariable ("PATH", BSTR(&newpath));
-#if 0
- status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
- if (status > 0)
- printf ("PATH: %s\n", BSTR(&oldpath));
-#endif
- gc_free (&gc);
- done = true;
- }
- }
-}
-
-void
-init_win32 (void)
-{
- if (WSAStartup(0x0101, &wsa_state))
- {
- msg (M_ERR, "WSAStartup failed");
- }
- window_title_clear (&window_title);
- win32_signal_clear (&win32_signal);
- netcmd_semaphore_init ();
-}
-
-void
-uninit_win32 (void)
-{
- netcmd_semaphore_close ();
- if (pause_exit_enabled)
- {
- if (win32_signal.mode == WSO_MODE_UNDEF)
- {
- struct win32_signal w;
- win32_signal_open (&w, WSO_FORCE_CONSOLE, NULL, false);
- win32_pause (&w);
- win32_signal_close (&w);
- }
- else
- win32_pause (&win32_signal);
- }
- window_title_restore (&window_title);
- win32_signal_close (&win32_signal);
- WSACleanup ();
- free (win_sys_path);
-}
-
-void
-set_pause_exit_win32 (void)
-{
- pause_exit_enabled = true;
-}
-
-bool
-init_security_attributes_allow_all (struct security_attributes *obj)
-{
- CLEAR (*obj);
-
- obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES);
- obj->sa.lpSecurityDescriptor = &obj->sd;
- obj->sa.bInheritHandle = FALSE;
- if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION))
- return false;
- if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE))
- return false;
- return true;
-}
-
-void
-overlapped_io_init (struct overlapped_io *o,
- const struct frame *frame,
- BOOL event_state,
- bool tuntap_buffer) /* if true: tuntap buffer, if false: socket buffer */
-{
- CLEAR (*o);
-
- /* manual reset event, initially set according to event_state */
- o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL);
- if (o->overlapped.hEvent == NULL)
- msg (M_ERR, "Error: overlapped_io_init: CreateEvent failed");
-
- /* allocate buffer for overlapped I/O */
- alloc_buf_sock_tun (&o->buf_init, frame, tuntap_buffer, 0);
-}
-
-void
-overlapped_io_close (struct overlapped_io *o)
-{
- if (o->overlapped.hEvent)
- {
- if (!CloseHandle (o->overlapped.hEvent))
- msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on overlapped I/O event object");
- }
- free_buf (&o->buf_init);
-}
-
-char *
-overlapped_io_state_ascii (const struct overlapped_io *o)
-{
- switch (o->iostate)
- {
- case IOSTATE_INITIAL:
- return "0";
- case IOSTATE_QUEUED:
- return "Q";
- case IOSTATE_IMMEDIATE_RETURN:
- return "1";
- }
- return "?";
-}
-
-/*
- * Event-based notification of network events
- */
-
-void
-init_net_event_win32 (struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags)
-{
- /* manual reset events, initially set to unsignaled */
-
- /* initialize write event */
- if (!(flags & NE32_PERSIST_EVENT) || !event->write)
- {
- if (flags & NE32_WRITE_EVENT)
- {
- event->write = CreateEvent (NULL, TRUE, FALSE, NULL);
- if (event->write == NULL)
- msg (M_ERR, "Error: init_net_event_win32: CreateEvent (write) failed");
- }
- else
- event->write = NULL;
- }
-
- /* initialize read event */
- if (!(flags & NE32_PERSIST_EVENT) || !event->read)
- {
- event->read = CreateEvent (NULL, TRUE, FALSE, NULL);
- if (event->read == NULL)
- msg (M_ERR, "Error: init_net_event_win32: CreateEvent (read) failed");
- }
-
- /* setup network events to change read event state */
- if (WSAEventSelect (sd, event->read, network_events) != 0)
- msg (M_FATAL | M_ERRNO_SOCK, "Error: init_net_event_win32: WSAEventSelect call failed");
-}
-
-long
-reset_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd)
-{
- WSANETWORKEVENTS wne;
- if (WSAEnumNetworkEvents (sd, event->read, &wne) != 0)
- {
- msg (M_FATAL | M_ERRNO_SOCK, "Error: reset_net_event_win32: WSAEnumNetworkEvents call failed");
- return 0; /* NOTREACHED */
- }
- else
- return wne.lNetworkEvents;
-}
-
-void
-close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, unsigned int flags)
-{
- if (event->read)
- {
- if (socket_defined (sd))
- {
- if (WSAEventSelect (sd, event->read, 0) != 0)
- msg (M_WARN | M_ERRNO_SOCK, "Warning: close_net_event_win32: WSAEventSelect call failed");
- }
- if (!ResetEvent (event->read))
- msg (M_WARN | M_ERRNO, "Warning: ResetEvent (read) failed in close_net_event_win32");
- if (!(flags & NE32_PERSIST_EVENT))
- {
- if (!CloseHandle (event->read))
- msg (M_WARN | M_ERRNO, "Warning: CloseHandle (read) failed in close_net_event_win32");
- event->read = NULL;
- }
- }
-
- if (event->write)
- {
- if (!ResetEvent (event->write))
- msg (M_WARN | M_ERRNO, "Warning: ResetEvent (write) failed in close_net_event_win32");
- if (!(flags & NE32_PERSIST_EVENT))
- {
- if (!CloseHandle (event->write))
- msg (M_WARN | M_ERRNO, "Warning: CloseHandle (write) failed in close_net_event_win32");
- event->write = NULL;
- }
- }
-}
-
-/*
- * struct net_event_win32
- */
-
-void
-net_event_win32_init (struct net_event_win32 *ne)
-{
- CLEAR (*ne);
- ne->sd = SOCKET_UNDEFINED;
-}
-
-void
-net_event_win32_start (struct net_event_win32 *ne, long network_events, socket_descriptor_t sd)
-{
- ASSERT (!socket_defined (ne->sd));
- ne->sd = sd;
- ne->event_mask = 0;
- init_net_event_win32 (&ne->handle, network_events, sd, NE32_PERSIST_EVENT|NE32_WRITE_EVENT);
-}
-
-void
-net_event_win32_reset_write (struct net_event_win32 *ne)
-{
- BOOL status;
- if (ne->event_mask & FD_WRITE)
- status = SetEvent (ne->handle.write);
- else
- status = ResetEvent (ne->handle.write);
- if (!status)
- msg (M_WARN | M_ERRNO, "Warning: SetEvent/ResetEvent failed in net_event_win32_reset_write");
-}
-
-void
-net_event_win32_reset (struct net_event_win32 *ne)
-{
- ne->event_mask |= reset_net_event_win32 (&ne->handle, ne->sd);
-}
-
-void
-net_event_win32_stop (struct net_event_win32 *ne)
-{
- if (net_event_win32_defined (ne))
- close_net_event_win32 (&ne->handle, ne->sd, NE32_PERSIST_EVENT);
- ne->sd = SOCKET_UNDEFINED;
- ne->event_mask = 0;
-}
-
-void
-net_event_win32_close (struct net_event_win32 *ne)
-{
- if (net_event_win32_defined (ne))
- close_net_event_win32 (&ne->handle, ne->sd, 0);
- net_event_win32_init (ne);
-}
-
-/*
- * Simulate *nix signals on Windows.
- *
- * Two modes:
- * (1) Console mode -- map keyboard function keys to signals
- * (2) Service mode -- map Windows event object to SIGTERM
- */
-
-void
-win32_signal_clear (struct win32_signal *ws)
-{
- CLEAR (*ws);
-}
-
-void
-win32_signal_open (struct win32_signal *ws,
- int force,
- const char *exit_event_name,
- bool exit_event_initial_state)
-{
- CLEAR (*ws);
-
- ws->mode = WSO_MODE_UNDEF;
- ws->in.read = INVALID_HANDLE_VALUE;
- ws->in.write = INVALID_HANDLE_VALUE;
- ws->console_mode_save = 0;
- ws->console_mode_save_defined = false;
-
- if (force == WSO_NOFORCE || force == WSO_FORCE_CONSOLE)
- {
- /*
- * Try to open console.
- */
- ws->in.read = GetStdHandle (STD_INPUT_HANDLE);
- if (ws->in.read != INVALID_HANDLE_VALUE)
- {
- if (GetConsoleMode (ws->in.read, &ws->console_mode_save))
- {
- /* running on a console */
- const DWORD new_console_mode = ws->console_mode_save
- & ~(ENABLE_WINDOW_INPUT
- | ENABLE_PROCESSED_INPUT
- | ENABLE_LINE_INPUT
- | ENABLE_ECHO_INPUT
- | ENABLE_MOUSE_INPUT);
-
- if (new_console_mode != ws->console_mode_save)
- {
- if (!SetConsoleMode (ws->in.read, new_console_mode))
- msg (M_ERR, "Error: win32_signal_open: SetConsoleMode failed");
- ws->console_mode_save_defined = true;
- }
- ws->mode = WSO_MODE_CONSOLE;
- }
- else
- ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a service */
- }
- }
-
- /*
- * If console open failed, assume we are running
- * as a service.
- */
- if ((force == WSO_NOFORCE || force == WSO_FORCE_SERVICE)
- && !HANDLE_DEFINED (ws->in.read) && exit_event_name)
- {
- struct security_attributes sa;
-
- if (!init_security_attributes_allow_all (&sa))
- msg (M_ERR, "Error: win32_signal_open: init SA failed");
-
- ws->in.read = CreateEvent (&sa.sa,
- TRUE,
- exit_event_initial_state ? TRUE : FALSE,
- exit_event_name);
- if (ws->in.read == NULL)
- {
- msg (M_WARN|M_ERRNO, "NOTE: CreateEvent '%s' failed", exit_event_name);
- }
- else
- {
- if (WaitForSingleObject (ws->in.read, 0) != WAIT_TIMEOUT)
- msg (M_FATAL, "ERROR: Exit Event ('%s') is signaled", exit_event_name);
- else
- ws->mode = WSO_MODE_SERVICE;
- }
- }
-}
-
-static bool
-keyboard_input_available (struct win32_signal *ws)
-{
- ASSERT (ws->mode == WSO_MODE_CONSOLE);
- if (HANDLE_DEFINED (ws->in.read))
- {
- DWORD n;
- if (GetNumberOfConsoleInputEvents (ws->in.read, &n))
- return n > 0;
- }
- return false;
-}
-
-static unsigned int
-keyboard_ir_to_key (INPUT_RECORD *ir)
-{
- if (ir->Event.KeyEvent.uChar.AsciiChar == 0)
- return ir->Event.KeyEvent.wVirtualScanCode;
-
- if ((ir->Event.KeyEvent.dwControlKeyState
- & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
- && (ir->Event.KeyEvent.wVirtualKeyCode != 18))
- return ir->Event.KeyEvent.wVirtualScanCode * 256;
-
- return ir->Event.KeyEvent.uChar.AsciiChar;
-}
-
-static unsigned int
-win32_keyboard_get (struct win32_signal *ws)
-{
- ASSERT (ws->mode == WSO_MODE_CONSOLE);
- if (HANDLE_DEFINED (ws->in.read))
- {
- INPUT_RECORD ir;
- do {
- DWORD n;
- if (!keyboard_input_available (ws))
- return 0;
- if (!ReadConsoleInput (ws->in.read, &ir, 1, &n))
- return 0;
- } while (ir.EventType != KEY_EVENT || ir.Event.KeyEvent.bKeyDown != TRUE);
-
- return keyboard_ir_to_key (&ir);
- }
- else
- return 0;
-}
-
-void
-win32_signal_close (struct win32_signal *ws)
-{
- if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED (ws->in.read))
- CloseHandle (ws->in.read);
- if (ws->console_mode_save_defined)
- {
- if (!SetConsoleMode (ws->in.read, ws->console_mode_save))
- msg (M_ERR, "Error: win32_signal_close: SetConsoleMode failed");
- }
- CLEAR (*ws);
-}
-
-/*
- * Return true if interrupt occurs in service mode.
- */
-static bool
-win32_service_interrupt (struct win32_signal *ws)
-{
- if (ws->mode == WSO_MODE_SERVICE)
- {
- if (HANDLE_DEFINED (ws->in.read)
- && WaitForSingleObject (ws->in.read, 0) == WAIT_OBJECT_0)
- return true;
- }
- return false;
-}
-
-int
-win32_signal_get (struct win32_signal *ws)
-{
- int ret = 0;
- if (siginfo_static.signal_received)
- {
- ret = siginfo_static.signal_received;
- }
- else
- {
- if (ws->mode == WSO_MODE_SERVICE)
- {
- if (win32_service_interrupt (ws))
- ret = SIGTERM;
- }
- else if (ws->mode == WSO_MODE_CONSOLE)
- {
- switch (win32_keyboard_get (ws))
- {
- case 0x3B: /* F1 -> USR1 */
- ret = SIGUSR1;
- break;
- case 0x3C: /* F2 -> USR2 */
- ret = SIGUSR2;
- break;
- case 0x3D: /* F3 -> HUP */
- ret = SIGHUP;
- break;
- case 0x3E: /* F4 -> TERM */
- ret = SIGTERM;
- break;
- }
- }
- if (ret)
- {
- siginfo_static.signal_received = ret;
- siginfo_static.hard = true;
- }
- }
- return ret;
-}
-
-void
-win32_pause (struct win32_signal *ws)
-{
- if (ws->mode == WSO_MODE_CONSOLE && HANDLE_DEFINED (ws->in.read))
- {
- int status;
- msg (M_INFO|M_NOPREFIX, "Press any key to continue...");
- do {
- status = WaitForSingleObject (ws->in.read, INFINITE);
- } while (!win32_keyboard_get (ws));
- }
-}
-
-/* window functions */
-
-void
-window_title_clear (struct window_title *wt)
-{
- CLEAR (*wt);
-}
-
-void
-window_title_save (struct window_title *wt)
-{
- if (!wt->saved)
- {
- if (!GetConsoleTitle (wt->old_window_title, sizeof (wt->old_window_title)))
- {
- wt->old_window_title[0] = 0;
- wt->saved = false;
- }
- else
- wt->saved = true;
- }
-}
-
-void
-window_title_restore (const struct window_title *wt)
-{
- if (wt->saved)
- SetConsoleTitle (wt->old_window_title);
-}
-
-void
-window_title_generate (const char *title)
-{
- struct gc_arena gc = gc_new ();
- struct buffer out = alloc_buf_gc (256, &gc);
- if (!title)
- title = "";
- buf_printf (&out, "[%s] " PACKAGE_NAME " " VERSION " F4:EXIT F1:USR1 F2:USR2 F3:HUP", title);
- SetConsoleTitle (BSTR (&out));
- gc_free (&gc);
-}
-
-/* semaphore functions */
-
-void
-semaphore_clear (struct semaphore *s)
-{
- CLEAR (*s);
-}
-
-void
-semaphore_open (struct semaphore *s, const char *name)
-{
- struct security_attributes sa;
-
- s->locked = false;
- s->name = name;
- s->hand = NULL;
-
- if (init_security_attributes_allow_all (&sa))
- s->hand = CreateSemaphore(&sa.sa, 1, 1, name);
-
- if (s->hand == NULL)
- msg (M_WARN|M_ERRNO, "WARNING: Cannot create Win32 semaphore '%s'", name);
- else
- dmsg (D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name);
-}
-
-bool
-semaphore_lock (struct semaphore *s, int timeout_milliseconds)
-{
- bool ret = true;
-
- if (s->hand)
- {
- DWORD status;
- ASSERT (!s->locked);
-
- dmsg (D_SEMAPHORE_LOW, "Attempting to lock Win32 semaphore '%s' prior to net shell command (timeout = %d sec)",
- s->name,
- timeout_milliseconds / 1000);
- status = WaitForSingleObject (s->hand, timeout_milliseconds);
- if (status == WAIT_FAILED)
- msg (M_ERR, "Wait failed on Win32 semaphore '%s'", s->name);
- ret = (status == WAIT_TIMEOUT) ? false : true;
- if (ret)
- {
- dmsg (D_SEMAPHORE, "Locked Win32 semaphore '%s'", s->name);
- s->locked = true;
- }
- else
- {
- dmsg (D_SEMAPHORE, "Wait on Win32 semaphore '%s' timed out after %d milliseconds",
- s->name,
- timeout_milliseconds);
- }
- }
- return ret;
-}
-
-void
-semaphore_release (struct semaphore *s)
-{
- if (s->hand)
- {
- ASSERT (s->locked);
- dmsg (D_SEMAPHORE, "Releasing Win32 semaphore '%s'", s->name);
- if (!ReleaseSemaphore(s->hand, 1, NULL))
- msg (M_WARN | M_ERRNO, "ReleaseSemaphore failed on Win32 semaphore '%s'",
- s->name);
- s->locked = false;
- }
-}
-
-void
-semaphore_close (struct semaphore *s)
-{
- if (s->hand)
- {
- if (s->locked)
- semaphore_release (s);
- dmsg (D_SEMAPHORE, "Closing Win32 semaphore '%s'", s->name);
- CloseHandle (s->hand);
- s->hand = NULL;
- }
-}
-
-/*
- * Special global semaphore used to protect network
- * shell commands from simultaneous instantiation.
- */
-
-void
-netcmd_semaphore_init (void)
-{
- semaphore_open (&netcmd_semaphore, PACKAGE "_netcmd");
-}
-
-void
-netcmd_semaphore_close (void)
-{
- semaphore_close (&netcmd_semaphore);
-}
-
-void
-netcmd_semaphore_lock (void)
-{
- const int timeout_seconds = 600;
- if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000))
- msg (M_FATAL, "Cannot lock net command semaphore");
-}
-
-void
-netcmd_semaphore_release (void)
-{
- semaphore_release (&netcmd_semaphore);
-}
-
-/*
- * Get input from console.
- *
- * Return false on input error, or if service
- * exit event is signaled.
- */
-
-bool
-get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
-{
- HANDLE in = INVALID_HANDLE_VALUE;
- HANDLE err = INVALID_HANDLE_VALUE;
- DWORD len = 0;
-
- ASSERT (prompt);
- ASSERT (input);
- ASSERT (capacity > 0);
-
- input[0] = '\0';
-
- in = GetStdHandle (STD_INPUT_HANDLE);
- err = get_orig_stderr ();
-
- if (in != INVALID_HANDLE_VALUE
- && err != INVALID_HANDLE_VALUE
- && !win32_service_interrupt (&win32_signal)
- && WriteFile (err, prompt, strlen (prompt), &len, NULL))
- {
- bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
- DWORD flags_save = 0;
- int status = 0;
-
- if (is_console)
- {
- if (GetConsoleMode (in, &flags_save))
- {
- DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
- if (echo)
- flags |= ENABLE_ECHO_INPUT;
- SetConsoleMode (in, flags);
- }
- else
- is_console = 0;
- }
-
- status = ReadFile (in, input, capacity, &len, NULL);
-
- string_null_terminate (input, (int)len, capacity);
- chomp (input);
-
- if (!echo)
- WriteFile (err, "\r\n", 2, &len, NULL);
- if (is_console)
- SetConsoleMode (in, flags_save);
- if (status && !win32_service_interrupt (&win32_signal))
- return true;
- }
-
- return false;
-}
-
-/* get password from console */
-
-char *
-getpass (const char *prompt)
-{
- static char line[256];
- if (get_console_input_win32 (prompt, false, line, sizeof (line)))
- return line;
- else
- return NULL;
-}
-
-/*
- * Return true if filename is safe to be used on Windows,
- * by avoiding the following reserved names:
- *
- * CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9,
- * LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, and CLOCK$
- *
- * See: http://msdn.microsoft.com/en-us/library/aa365247.aspx
- * and http://msdn.microsoft.com/en-us/library/86k9f82k(VS.80).aspx
- */
-
-static bool
-cmp_prefix (const char *str, const bool n, const char *pre)
-{
- size_t i = 0;
-
- if (!str)
- return false;
-
- while (true)
- {
- const int c1 = pre[i];
- int c2 = str[i];
- ++i;
- if (c1 == '\0')
- {
- if (n)
- {
- if (isdigit (c2))
- c2 = str[i];
- else
- return false;
- }
- return c2 == '\0' || c2 == '.';
- }
- else if (c2 == '\0')
- return false;
- if (c1 != tolower(c2))
- return false;
- }
-}
-
-bool
-win_safe_filename (const char *fn)
-{
- if (cmp_prefix (fn, false, "con"))
- return false;
- if (cmp_prefix (fn, false, "prn"))
- return false;
- if (cmp_prefix (fn, false, "aux"))
- return false;
- if (cmp_prefix (fn, false, "nul"))
- return false;
- if (cmp_prefix (fn, true, "com"))
- return false;
- if (cmp_prefix (fn, true, "lpt"))
- return false;
- if (cmp_prefix (fn, false, "clock$"))
- return false;
- 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;
- static bool exec_warn = false;
-
- if (a && a->argv[0])
- {
- if (openvpn_execve_allowed (flags))
- {
- if (script_method == SM_EXECVE)
- {
- 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_USESHOWWINDOW;
- start_info.wShowWindow = SW_HIDE;
-
- 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 if (script_method == SM_SYSTEM)
- {
- configure_win_path ();
- ret = openvpn_system (argv_system_str (a), es, flags);
- }
- else
- {
- ASSERT (0);
- }
- }
- else if (!exec_warn && (script_security < SSEC_SCRIPTS))
- {
- msg (M_WARN, SCRIPT_SECURITY_WARNING);
- exec_warn = true;
- }
- }
- else
- {
- msg (M_WARN, "openvpn_execve: called with empty argv");
- }
- return ret;
-}
-
-/*
- * call ourself in another process
- */
-void
-fork_to_self (const char *cmdline)
-{
- STARTUPINFO start_info;
- PROCESS_INFORMATION proc_info;
- char self_exe[256];
- char *cl = string_alloc (cmdline, NULL);
- DWORD status;
-
- CLEAR (start_info);
- CLEAR (proc_info);
- CLEAR (self_exe);
-
- status = GetModuleFileName (NULL, self_exe, sizeof(self_exe));
- if (status == 0 || status == sizeof(self_exe))
- {
- msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName");
- goto done;
- }
-
- /* fill in STARTUPINFO struct */
- GetStartupInfo(&start_info);
- start_info.cb = sizeof(start_info);
- start_info.dwFlags = STARTF_USESHOWWINDOW;
- start_info.wShowWindow = SW_HIDE;
-
- if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info))
- {
- CloseHandle (proc_info.hThread);
- CloseHandle (proc_info.hProcess);
- }
- else
- {
- msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline);
- }
-
- done:
- free (cl);
-}
-
-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);
-}
-
-
-const char *
-win_get_tempdir()
-{
- static char buf[MAX_PATH];
- char *tmpdir = buf;
-
- CLEAR(buf);
-
- if (!GetTempPath(sizeof(buf),buf)) {
- /* Warn if we can't find a valid temporary directory, which should
- * be unlikely.
- */
- msg (M_WARN, "Could not find a suitable temporary directory."
- " (GetTempPath() failed). Consider to use --tmp-dir");
- tmpdir = NULL;
- }
- return tmpdir;
-}
-#endif