cosmetics
[tomato.git] / release / src / router / openvpn / win32.c
blobeb94eb85762c0b4333f2f00c761bd2a115b7585b
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * Win32-specific OpenVPN code, targetted at the mingw
27 * development environment.
29 #include "syshead.h"
31 #ifdef WIN32
33 #include "buffer.h"
34 #include "error.h"
35 #include "mtu.h"
36 #include "sig.h"
37 #include "win32.h"
38 #include "misc.h"
40 #include "memdbg.h"
43 * Windows internal socket API state (opaque).
45 static struct WSAData wsa_state; /* GLOBAL */
48 * Should we call win32_pause() on program exit?
50 static bool pause_exit_enabled = false; /* GLOBAL */
53 * win32_signal is used to get input from the keyboard
54 * if we are running in a console, or get input from an
55 * event object if we are running as a service.
58 struct win32_signal win32_signal; /* GLOBAL */
61 * Save our old window title so we can restore
62 * it on exit.
64 struct window_title window_title; /* GLOBAL*/
67 * Special global semaphore used to protect network
68 * shell commands from simultaneous instantiation.
71 struct semaphore netcmd_semaphore; /* GLOBAL */
74 * Windows system pathname such as c:\windows
76 static char *win_sys_path = NULL; /* GLOBAL */
79 * Configure PATH. On Windows, sometimes PATH is not set correctly
80 * by default.
82 static void
83 configure_win_path (void)
85 static bool done = false; /* GLOBAL */
86 if (!done)
88 FILE *fp;
89 fp = fopen ("c:\\windows\\system32\\route.exe", "rb");
90 if (fp)
92 const int bufsiz = 4096;
93 struct gc_arena gc = gc_new ();
94 struct buffer oldpath = alloc_buf_gc (bufsiz, &gc);
95 struct buffer newpath = alloc_buf_gc (bufsiz, &gc);
96 const char* delim = ";";
97 DWORD status;
98 fclose (fp);
99 status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
100 #if 0
101 status = 0;
102 #endif
103 if (!status)
105 *BPTR(&oldpath) = '\0';
106 delim = "";
108 buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s",
109 delim,
110 BSTR(&oldpath));
111 SetEnvironmentVariable ("PATH", BSTR(&newpath));
112 #if 0
113 status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
114 if (status > 0)
115 printf ("PATH: %s\n", BSTR(&oldpath));
116 #endif
117 gc_free (&gc);
118 done = true;
123 void
124 init_win32 (void)
126 if (WSAStartup(0x0101, &wsa_state))
128 msg (M_ERR, "WSAStartup failed");
130 window_title_clear (&window_title);
131 win32_signal_clear (&win32_signal);
132 netcmd_semaphore_init ();
135 void
136 uninit_win32 (void)
138 netcmd_semaphore_close ();
139 if (pause_exit_enabled)
141 if (win32_signal.mode == WSO_MODE_UNDEF)
143 struct win32_signal w;
144 win32_signal_open (&w, WSO_FORCE_CONSOLE, NULL, false);
145 win32_pause (&w);
146 win32_signal_close (&w);
148 else
149 win32_pause (&win32_signal);
151 window_title_restore (&window_title);
152 win32_signal_close (&win32_signal);
153 WSACleanup ();
154 free (win_sys_path);
157 void
158 set_pause_exit_win32 (void)
160 pause_exit_enabled = true;
163 bool
164 init_security_attributes_allow_all (struct security_attributes *obj)
166 CLEAR (*obj);
168 obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES);
169 obj->sa.lpSecurityDescriptor = &obj->sd;
170 obj->sa.bInheritHandle = FALSE;
171 if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION))
172 return false;
173 if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE))
174 return false;
175 return true;
178 void
179 overlapped_io_init (struct overlapped_io *o,
180 const struct frame *frame,
181 BOOL event_state,
182 bool tuntap_buffer) /* if true: tuntap buffer, if false: socket buffer */
184 CLEAR (*o);
186 /* manual reset event, initially set according to event_state */
187 o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL);
188 if (o->overlapped.hEvent == NULL)
189 msg (M_ERR, "Error: overlapped_io_init: CreateEvent failed");
191 /* allocate buffer for overlapped I/O */
192 alloc_buf_sock_tun (&o->buf_init, frame, tuntap_buffer, 0);
195 void
196 overlapped_io_close (struct overlapped_io *o)
198 if (o->overlapped.hEvent)
200 if (!CloseHandle (o->overlapped.hEvent))
201 msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on overlapped I/O event object");
203 free_buf (&o->buf_init);
206 char *
207 overlapped_io_state_ascii (const struct overlapped_io *o)
209 switch (o->iostate)
211 case IOSTATE_INITIAL:
212 return "0";
213 case IOSTATE_QUEUED:
214 return "Q";
215 case IOSTATE_IMMEDIATE_RETURN:
216 return "1";
218 return "?";
222 * Event-based notification of network events
225 void
226 init_net_event_win32 (struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags)
228 /* manual reset events, initially set to unsignaled */
230 /* initialize write event */
231 if (!(flags & NE32_PERSIST_EVENT) || !event->write)
233 if (flags & NE32_WRITE_EVENT)
235 event->write = CreateEvent (NULL, TRUE, FALSE, NULL);
236 if (event->write == NULL)
237 msg (M_ERR, "Error: init_net_event_win32: CreateEvent (write) failed");
239 else
240 event->write = NULL;
243 /* initialize read event */
244 if (!(flags & NE32_PERSIST_EVENT) || !event->read)
246 event->read = CreateEvent (NULL, TRUE, FALSE, NULL);
247 if (event->read == NULL)
248 msg (M_ERR, "Error: init_net_event_win32: CreateEvent (read) failed");
251 /* setup network events to change read event state */
252 if (WSAEventSelect (sd, event->read, network_events) != 0)
253 msg (M_FATAL | M_ERRNO_SOCK, "Error: init_net_event_win32: WSAEventSelect call failed");
256 long
257 reset_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd)
259 WSANETWORKEVENTS wne;
260 if (WSAEnumNetworkEvents (sd, event->read, &wne) != 0)
262 msg (M_FATAL | M_ERRNO_SOCK, "Error: reset_net_event_win32: WSAEnumNetworkEvents call failed");
263 return 0; /* NOTREACHED */
265 else
266 return wne.lNetworkEvents;
269 void
270 close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, unsigned int flags)
272 if (event->read)
274 if (socket_defined (sd))
276 if (WSAEventSelect (sd, event->read, 0) != 0)
277 msg (M_WARN | M_ERRNO_SOCK, "Warning: close_net_event_win32: WSAEventSelect call failed");
279 if (!ResetEvent (event->read))
280 msg (M_WARN | M_ERRNO, "Warning: ResetEvent (read) failed in close_net_event_win32");
281 if (!(flags & NE32_PERSIST_EVENT))
283 if (!CloseHandle (event->read))
284 msg (M_WARN | M_ERRNO, "Warning: CloseHandle (read) failed in close_net_event_win32");
285 event->read = NULL;
289 if (event->write)
291 if (!ResetEvent (event->write))
292 msg (M_WARN | M_ERRNO, "Warning: ResetEvent (write) failed in close_net_event_win32");
293 if (!(flags & NE32_PERSIST_EVENT))
295 if (!CloseHandle (event->write))
296 msg (M_WARN | M_ERRNO, "Warning: CloseHandle (write) failed in close_net_event_win32");
297 event->write = NULL;
303 * struct net_event_win32
306 void
307 net_event_win32_init (struct net_event_win32 *ne)
309 CLEAR (*ne);
310 ne->sd = SOCKET_UNDEFINED;
313 void
314 net_event_win32_start (struct net_event_win32 *ne, long network_events, socket_descriptor_t sd)
316 ASSERT (!socket_defined (ne->sd));
317 ne->sd = sd;
318 ne->event_mask = 0;
319 init_net_event_win32 (&ne->handle, network_events, sd, NE32_PERSIST_EVENT|NE32_WRITE_EVENT);
322 void
323 net_event_win32_reset_write (struct net_event_win32 *ne)
325 BOOL status;
326 if (ne->event_mask & FD_WRITE)
327 status = SetEvent (ne->handle.write);
328 else
329 status = ResetEvent (ne->handle.write);
330 if (!status)
331 msg (M_WARN | M_ERRNO, "Warning: SetEvent/ResetEvent failed in net_event_win32_reset_write");
334 void
335 net_event_win32_reset (struct net_event_win32 *ne)
337 ne->event_mask |= reset_net_event_win32 (&ne->handle, ne->sd);
340 void
341 net_event_win32_stop (struct net_event_win32 *ne)
343 if (net_event_win32_defined (ne))
344 close_net_event_win32 (&ne->handle, ne->sd, NE32_PERSIST_EVENT);
345 ne->sd = SOCKET_UNDEFINED;
346 ne->event_mask = 0;
349 void
350 net_event_win32_close (struct net_event_win32 *ne)
352 if (net_event_win32_defined (ne))
353 close_net_event_win32 (&ne->handle, ne->sd, 0);
354 net_event_win32_init (ne);
358 * Simulate *nix signals on Windows.
360 * Two modes:
361 * (1) Console mode -- map keyboard function keys to signals
362 * (2) Service mode -- map Windows event object to SIGTERM
365 void
366 win32_signal_clear (struct win32_signal *ws)
368 CLEAR (*ws);
371 void
372 win32_signal_open (struct win32_signal *ws,
373 int force,
374 const char *exit_event_name,
375 bool exit_event_initial_state)
377 CLEAR (*ws);
379 ws->mode = WSO_MODE_UNDEF;
380 ws->in.read = INVALID_HANDLE_VALUE;
381 ws->in.write = INVALID_HANDLE_VALUE;
382 ws->console_mode_save = 0;
383 ws->console_mode_save_defined = false;
385 if (force == WSO_NOFORCE || force == WSO_FORCE_CONSOLE)
388 * Try to open console.
390 ws->in.read = GetStdHandle (STD_INPUT_HANDLE);
391 if (ws->in.read != INVALID_HANDLE_VALUE)
393 if (GetConsoleMode (ws->in.read, &ws->console_mode_save))
395 /* running on a console */
396 const DWORD new_console_mode = ws->console_mode_save
397 & ~(ENABLE_WINDOW_INPUT
398 | ENABLE_PROCESSED_INPUT
399 | ENABLE_LINE_INPUT
400 | ENABLE_ECHO_INPUT
401 | ENABLE_MOUSE_INPUT);
403 if (new_console_mode != ws->console_mode_save)
405 if (!SetConsoleMode (ws->in.read, new_console_mode))
406 msg (M_ERR, "Error: win32_signal_open: SetConsoleMode failed");
407 ws->console_mode_save_defined = true;
409 ws->mode = WSO_MODE_CONSOLE;
411 else
412 ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a service */
417 * If console open failed, assume we are running
418 * as a service.
420 if ((force == WSO_NOFORCE || force == WSO_FORCE_SERVICE)
421 && !HANDLE_DEFINED (ws->in.read) && exit_event_name)
423 struct security_attributes sa;
425 if (!init_security_attributes_allow_all (&sa))
426 msg (M_ERR, "Error: win32_signal_open: init SA failed");
428 ws->in.read = CreateEvent (&sa.sa,
429 TRUE,
430 exit_event_initial_state ? TRUE : FALSE,
431 exit_event_name);
432 if (ws->in.read == NULL)
434 msg (M_WARN|M_ERRNO, "NOTE: CreateEvent '%s' failed", exit_event_name);
436 else
438 if (WaitForSingleObject (ws->in.read, 0) != WAIT_TIMEOUT)
439 msg (M_FATAL, "ERROR: Exit Event ('%s') is signaled", exit_event_name);
440 else
441 ws->mode = WSO_MODE_SERVICE;
446 static bool
447 keyboard_input_available (struct win32_signal *ws)
449 ASSERT (ws->mode == WSO_MODE_CONSOLE);
450 if (HANDLE_DEFINED (ws->in.read))
452 DWORD n;
453 if (GetNumberOfConsoleInputEvents (ws->in.read, &n))
454 return n > 0;
456 return false;
459 static unsigned int
460 keyboard_ir_to_key (INPUT_RECORD *ir)
462 if (ir->Event.KeyEvent.uChar.AsciiChar == 0)
463 return ir->Event.KeyEvent.wVirtualScanCode;
465 if ((ir->Event.KeyEvent.dwControlKeyState
466 & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
467 && (ir->Event.KeyEvent.wVirtualKeyCode != 18))
468 return ir->Event.KeyEvent.wVirtualScanCode * 256;
470 return ir->Event.KeyEvent.uChar.AsciiChar;
473 static unsigned int
474 win32_keyboard_get (struct win32_signal *ws)
476 ASSERT (ws->mode == WSO_MODE_CONSOLE);
477 if (HANDLE_DEFINED (ws->in.read))
479 INPUT_RECORD ir;
480 do {
481 DWORD n;
482 if (!keyboard_input_available (ws))
483 return 0;
484 if (!ReadConsoleInput (ws->in.read, &ir, 1, &n))
485 return 0;
486 } while (ir.EventType != KEY_EVENT || ir.Event.KeyEvent.bKeyDown != TRUE);
488 return keyboard_ir_to_key (&ir);
490 else
491 return 0;
494 void
495 win32_signal_close (struct win32_signal *ws)
497 if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED (ws->in.read))
498 CloseHandle (ws->in.read);
499 if (ws->console_mode_save_defined)
501 if (!SetConsoleMode (ws->in.read, ws->console_mode_save))
502 msg (M_ERR, "Error: win32_signal_close: SetConsoleMode failed");
504 CLEAR (*ws);
508 * Return true if interrupt occurs in service mode.
510 static bool
511 win32_service_interrupt (struct win32_signal *ws)
513 if (ws->mode == WSO_MODE_SERVICE)
515 if (HANDLE_DEFINED (ws->in.read)
516 && WaitForSingleObject (ws->in.read, 0) == WAIT_OBJECT_0)
517 return true;
519 return false;
523 win32_signal_get (struct win32_signal *ws)
525 int ret = 0;
526 if (siginfo_static.signal_received)
528 ret = siginfo_static.signal_received;
530 else
532 if (ws->mode == WSO_MODE_SERVICE)
534 if (win32_service_interrupt (ws))
535 ret = SIGTERM;
537 else if (ws->mode == WSO_MODE_CONSOLE)
539 switch (win32_keyboard_get (ws))
541 case 0x3B: /* F1 -> USR1 */
542 ret = SIGUSR1;
543 break;
544 case 0x3C: /* F2 -> USR2 */
545 ret = SIGUSR2;
546 break;
547 case 0x3D: /* F3 -> HUP */
548 ret = SIGHUP;
549 break;
550 case 0x3E: /* F4 -> TERM */
551 ret = SIGTERM;
552 break;
555 if (ret)
557 siginfo_static.signal_received = ret;
558 siginfo_static.hard = true;
561 return ret;
564 void
565 win32_pause (struct win32_signal *ws)
567 if (ws->mode == WSO_MODE_CONSOLE && HANDLE_DEFINED (ws->in.read))
569 int status;
570 msg (M_INFO|M_NOPREFIX, "Press any key to continue...");
571 do {
572 status = WaitForSingleObject (ws->in.read, INFINITE);
573 } while (!win32_keyboard_get (ws));
577 /* window functions */
579 void
580 window_title_clear (struct window_title *wt)
582 CLEAR (*wt);
585 void
586 window_title_save (struct window_title *wt)
588 if (!wt->saved)
590 if (!GetConsoleTitle (wt->old_window_title, sizeof (wt->old_window_title)))
592 wt->old_window_title[0] = 0;
593 wt->saved = false;
595 else
596 wt->saved = true;
600 void
601 window_title_restore (const struct window_title *wt)
603 if (wt->saved)
604 SetConsoleTitle (wt->old_window_title);
607 void
608 window_title_generate (const char *title)
610 struct gc_arena gc = gc_new ();
611 struct buffer out = alloc_buf_gc (256, &gc);
612 if (!title)
613 title = "";
614 buf_printf (&out, "[%s] " PACKAGE_NAME " " VERSION " F4:EXIT F1:USR1 F2:USR2 F3:HUP", title);
615 SetConsoleTitle (BSTR (&out));
616 gc_free (&gc);
619 /* semaphore functions */
621 void
622 semaphore_clear (struct semaphore *s)
624 CLEAR (*s);
627 void
628 semaphore_open (struct semaphore *s, const char *name)
630 struct security_attributes sa;
632 s->locked = false;
633 s->name = name;
634 s->hand = NULL;
636 if (init_security_attributes_allow_all (&sa))
637 s->hand = CreateSemaphore(&sa.sa, 1, 1, name);
639 if (s->hand == NULL)
640 msg (M_WARN|M_ERRNO, "WARNING: Cannot create Win32 semaphore '%s'", name);
641 else
642 dmsg (D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name);
645 bool
646 semaphore_lock (struct semaphore *s, int timeout_milliseconds)
648 bool ret = true;
650 if (s->hand)
652 DWORD status;
653 ASSERT (!s->locked);
655 dmsg (D_SEMAPHORE_LOW, "Attempting to lock Win32 semaphore '%s' prior to net shell command (timeout = %d sec)",
656 s->name,
657 timeout_milliseconds / 1000);
658 status = WaitForSingleObject (s->hand, timeout_milliseconds);
659 if (status == WAIT_FAILED)
660 msg (M_ERR, "Wait failed on Win32 semaphore '%s'", s->name);
661 ret = (status == WAIT_TIMEOUT) ? false : true;
662 if (ret)
664 dmsg (D_SEMAPHORE, "Locked Win32 semaphore '%s'", s->name);
665 s->locked = true;
667 else
669 dmsg (D_SEMAPHORE, "Wait on Win32 semaphore '%s' timed out after %d milliseconds",
670 s->name,
671 timeout_milliseconds);
674 return ret;
677 void
678 semaphore_release (struct semaphore *s)
680 if (s->hand)
682 ASSERT (s->locked);
683 dmsg (D_SEMAPHORE, "Releasing Win32 semaphore '%s'", s->name);
684 if (!ReleaseSemaphore(s->hand, 1, NULL))
685 msg (M_WARN | M_ERRNO, "ReleaseSemaphore failed on Win32 semaphore '%s'",
686 s->name);
687 s->locked = false;
691 void
692 semaphore_close (struct semaphore *s)
694 if (s->hand)
696 if (s->locked)
697 semaphore_release (s);
698 dmsg (D_SEMAPHORE, "Closing Win32 semaphore '%s'", s->name);
699 CloseHandle (s->hand);
700 s->hand = NULL;
705 * Special global semaphore used to protect network
706 * shell commands from simultaneous instantiation.
709 void
710 netcmd_semaphore_init (void)
712 semaphore_open (&netcmd_semaphore, PACKAGE "_netcmd");
715 void
716 netcmd_semaphore_close (void)
718 semaphore_close (&netcmd_semaphore);
721 void
722 netcmd_semaphore_lock (void)
724 const int timeout_seconds = 600;
725 if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000))
726 msg (M_FATAL, "Cannot lock net command semaphore");
729 void
730 netcmd_semaphore_release (void)
732 semaphore_release (&netcmd_semaphore);
736 * Get input from console.
738 * Return false on input error, or if service
739 * exit event is signaled.
742 bool
743 get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
745 HANDLE in = INVALID_HANDLE_VALUE;
746 HANDLE err = INVALID_HANDLE_VALUE;
747 DWORD len = 0;
749 ASSERT (prompt);
750 ASSERT (input);
751 ASSERT (capacity > 0);
753 input[0] = '\0';
755 in = GetStdHandle (STD_INPUT_HANDLE);
756 err = get_orig_stderr ();
758 if (in != INVALID_HANDLE_VALUE
759 && err != INVALID_HANDLE_VALUE
760 && !win32_service_interrupt (&win32_signal)
761 && WriteFile (err, prompt, strlen (prompt), &len, NULL))
763 bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
764 DWORD flags_save = 0;
765 int status = 0;
767 if (is_console)
769 if (GetConsoleMode (in, &flags_save))
771 DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
772 if (echo)
773 flags |= ENABLE_ECHO_INPUT;
774 SetConsoleMode (in, flags);
776 else
777 is_console = 0;
780 status = ReadFile (in, input, capacity, &len, NULL);
782 string_null_terminate (input, (int)len, capacity);
783 chomp (input);
785 if (!echo)
786 WriteFile (err, "\r\n", 2, &len, NULL);
787 if (is_console)
788 SetConsoleMode (in, flags_save);
789 if (status && !win32_service_interrupt (&win32_signal))
790 return true;
793 return false;
796 /* get password from console */
798 char *
799 getpass (const char *prompt)
801 static char line[256];
802 if (get_console_input_win32 (prompt, false, line, sizeof (line)))
803 return line;
804 else
805 return NULL;
809 * Return true if filename is safe to be used on Windows,
810 * by avoiding the following reserved names:
812 * CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9,
813 * LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, and CLOCK$
815 * See: http://msdn.microsoft.com/en-us/library/aa365247.aspx
816 * and http://msdn.microsoft.com/en-us/library/86k9f82k(VS.80).aspx
819 static bool
820 cmp_prefix (const char *str, const bool n, const char *pre)
822 size_t i = 0;
824 if (!str)
825 return false;
827 while (true)
829 const int c1 = pre[i];
830 int c2 = str[i];
831 ++i;
832 if (c1 == '\0')
834 if (n)
836 if (isdigit (c2))
837 c2 = str[i];
838 else
839 return false;
841 return c2 == '\0' || c2 == '.';
843 else if (c2 == '\0')
844 return false;
845 if (c1 != tolower(c2))
846 return false;
850 bool
851 win_safe_filename (const char *fn)
853 if (cmp_prefix (fn, false, "con"))
854 return false;
855 if (cmp_prefix (fn, false, "prn"))
856 return false;
857 if (cmp_prefix (fn, false, "aux"))
858 return false;
859 if (cmp_prefix (fn, false, "nul"))
860 return false;
861 if (cmp_prefix (fn, true, "com"))
862 return false;
863 if (cmp_prefix (fn, true, "lpt"))
864 return false;
865 if (cmp_prefix (fn, false, "clock$"))
866 return false;
867 return true;
871 * Service functions for openvpn_execve
874 static char *
875 env_block (const struct env_set *es)
877 if (es)
879 struct env_item *e;
880 char *ret;
881 char *p;
882 size_t nchars = 1;
884 for (e = es->list; e != NULL; e = e->next)
885 nchars += strlen (e->string) + 1;
887 ret = (char *) malloc (nchars);
888 check_malloc_return (ret);
890 p = ret;
891 for (e = es->list; e != NULL; e = e->next)
893 if (env_allowed (e->string))
895 strcpy (p, e->string);
896 p += strlen (e->string) + 1;
899 *p = '\0';
900 return ret;
902 else
903 return NULL;
906 static char *
907 cmd_line (const struct argv *a)
909 size_t nchars = 1;
910 size_t maxlen = 0;
911 size_t i;
912 struct buffer buf;
913 char *work = NULL;
915 if (!a)
916 return NULL;
918 for (i = 0; i < a->argc; ++i)
920 const char *arg = a->argv[i];
921 const size_t len = strlen (arg);
922 nchars += len + 3;
923 if (len > maxlen)
924 maxlen = len;
927 work = (char *) malloc (maxlen + 1);
928 check_malloc_return (work);
929 buf = alloc_buf (nchars);
931 for (i = 0; i < a->argc; ++i)
933 const char *arg = a->argv[i];
934 strcpy (work, arg);
935 string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_');
936 if (i)
937 buf_printf (&buf, " ");
938 if (string_class (work, CC_ANY, CC_SPACE))
939 buf_printf (&buf, "%s", work);
940 else
941 buf_printf (&buf, "\"%s\"", work);
944 free (work);
945 return BSTR(&buf);
949 * Attempt to simulate fork/execve on Windows
952 openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
954 int ret = -1;
955 if (a && a->argv[0])
957 if (openvpn_execve_allowed (flags))
959 if (script_method == SM_EXECVE)
961 STARTUPINFO start_info;
962 PROCESS_INFORMATION proc_info;
964 char *env = env_block (es);
965 char *cl = cmd_line (a);
966 char *cmd = a->argv[0];
968 CLEAR (start_info);
969 CLEAR (proc_info);
971 /* fill in STARTUPINFO struct */
972 GetStartupInfo(&start_info);
973 start_info.cb = sizeof(start_info);
974 start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
975 start_info.wShowWindow = SW_HIDE;
976 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
977 start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
979 if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info))
981 DWORD exit_status = 0;
982 CloseHandle (proc_info.hThread);
983 WaitForSingleObject (proc_info.hProcess, INFINITE);
984 if (GetExitCodeProcess (proc_info.hProcess, &exit_status))
985 ret = (int)exit_status;
986 else
987 msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd);
988 CloseHandle (proc_info.hProcess);
990 else
992 msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd);
994 free (cl);
995 free (env);
997 else if (script_method == SM_SYSTEM)
999 configure_win_path ();
1000 ret = openvpn_system (argv_system_str (a), es, flags);
1002 else
1004 ASSERT (0);
1007 else
1009 msg (M_WARN, SCRIPT_SECURITY_WARNING);
1012 else
1014 msg (M_WARN, "openvpn_execve: called with empty argv");
1016 return ret;
1020 * call ourself in another process
1022 void
1023 fork_to_self (const char *cmdline)
1025 STARTUPINFO start_info;
1026 PROCESS_INFORMATION proc_info;
1027 char self_exe[256];
1028 char *cl = string_alloc (cmdline, NULL);
1029 DWORD status;
1031 CLEAR (start_info);
1032 CLEAR (proc_info);
1033 CLEAR (self_exe);
1035 status = GetModuleFileName (NULL, self_exe, sizeof(self_exe));
1036 if (status == 0 || status == sizeof(self_exe))
1038 msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName");
1039 goto done;
1042 /* fill in STARTUPINFO struct */
1043 GetStartupInfo(&start_info);
1044 start_info.cb = sizeof(start_info);
1045 start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
1046 start_info.wShowWindow = SW_HIDE;
1047 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
1048 start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
1050 if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info))
1052 CloseHandle (proc_info.hThread);
1053 CloseHandle (proc_info.hProcess);
1055 else
1057 msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline);
1060 done:
1061 free (cl);
1064 char *
1065 get_win_sys_path (void)
1067 ASSERT (win_sys_path);
1068 return win_sys_path;
1071 void
1072 set_win_sys_path (const char *newpath, struct env_set *es)
1074 free (win_sys_path);
1075 win_sys_path = string_alloc (newpath, NULL);
1076 setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */
1079 void
1080 set_win_sys_path_via_env (struct env_set *es)
1082 char buf[256];
1083 DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf));
1084 if (!status)
1085 msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME);
1086 if (status > sizeof (buf) - 1)
1087 msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME);
1088 set_win_sys_path (buf, es);
1091 void
1092 env_set_add_win32 (struct env_set *es)
1094 set_win_sys_path (DEFAULT_WIN_SYS_PATH, es);
1097 #endif