⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 win32.c

📁 OpenVPN is a robust and highly flexible tunneling application that uses all of the encryption, authe
💻 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 + -