diff options
Diffstat (limited to 'src/openvpn/win32.c')
-rwxr-xr-x | src/openvpn/win32.c | 758 |
1 files changed, 0 insertions, 758 deletions
diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c deleted file mode 100755 index f9a80fc..0000000 --- a/src/openvpn/win32.c +++ /dev/null @@ -1,758 +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-2005 OpenVPN Solutions LLC <info@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. - */ - -#ifdef WIN32 - -#include "config-win32.h" - -#include "syshead.h" -#include "buffer.h" -#include "error.h" -#include "mtu.h" -#include "sig.h" -#include "win32.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 */ - -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 (); -} - -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; -} - -#endif |