📄 win32.c
字号:
/* * 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-2004 James Yonan <jim@yonan.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 "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 */voidinit_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 ();}voiduninit_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 ();}voidset_pause_exit_win32 (void){ pause_exit_enabled = true;}boolinit_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;}voidoverlapped_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);}voidoverlapped_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 "?";}/* * 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 */voidwin32_signal_clear (struct win32_signal *ws){ CLEAR (*ws);}voidwin32_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 boolkeyboard_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 intkeyboard_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 intwin32_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;}voidwin32_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);}intwin32_signal_get (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 SIGTERM; else return 0; } else if (ws->mode == WSO_MODE_CONSOLE) { switch (win32_keyboard_get (ws)) { case 0x3B: /* F1 -> USR1 */ return SIGUSR1; case 0x3C: /* F2 -> USR2 */ return SIGUSR2; case 0x3D: /* F3 -> HUP */ return SIGHUP; case 0x3E: /* F4 -> TERM */ return SIGTERM; default: return 0; } } return 0;}voidwin32_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 */voidwindow_title_clear (struct window_title *wt){ CLEAR (*wt);}voidwindow_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; }}voidwindow_title_restore (const struct window_title *wt){ if (wt->saved) SetConsoleTitle (wt->old_window_title);}voidwindow_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 */voidsemaphore_clear (struct semaphore *s){ CLEAR (*s);}voidsemaphore_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 msg (D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name);}boolsemaphore_lock (struct semaphore *s, int timeout_milliseconds){ bool ret = true; if (s->hand) { DWORD status; ASSERT (!s->locked); msg (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) { msg (D_SEMAPHORE, "Locked Win32 semaphore '%s'", s->name); s->locked = true; } else { msg (D_SEMAPHORE, "Wait on Win32 semaphore '%s' timed out after %d milliseconds", s->name, timeout_milliseconds); } } return ret;}voidsemaphore_release (struct semaphore *s){ if (s->hand) { ASSERT (s->locked); msg (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; }}voidsemaphore_close (struct semaphore *s){ if (s->hand) { if (s->locked) semaphore_release (s); msg (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. */voidnetcmd_semaphore_init (void){ semaphore_open (&netcmd_semaphore, PACKAGE "_netcmd");}voidnetcmd_semaphore_close (void){ semaphore_close (&netcmd_semaphore);}voidnetcmd_semaphore_lock (void){ const int timeout_seconds = 600; if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000)) msg (M_FATAL, "Cannot lock net command semaphore"); }voidnetcmd_semaphore_release (void){ semaphore_release (&netcmd_semaphore);}/* get password from console */char *getpass (const char *prompt){ static char input[256]; /* GLOBAL */ HANDLE in; HANDLE err; DWORD count; input[0] = '\0'; in = GetStdHandle (STD_INPUT_HANDLE); err = GetStdHandle (STD_ERROR_HANDLE); if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE) return NULL; if (WriteFile (err, prompt, strlen (prompt), &count, NULL)) { int istty = (GetFileType (in) == FILE_TYPE_CHAR); DWORD old_flags; int rc; if (istty) { if (GetConsoleMode (in, &old_flags)) SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); else istty = 0; } rc = ReadFile (in, input, sizeof (input), &count, NULL); if (count >= 2 && input[count - 2] == '\r') input[count - 2] = '\0'; else { /* deplete excess input */ char buf[256]; while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0) if (count >= 2 && buf[count - 2] == '\r') break; } WriteFile (err, "\r\n", 2, &count, NULL); if (istty) SetConsoleMode (in, old_flags); if (rc) return input; } return NULL;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -