Add OpenVPN 2.1rc12 source (unconfigured)
[tomato.git] / release / src / router / openvpn / win32.c
blobe6d7b483c97a132e4edb959264efb6b3e81d9478
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-2008 Telethra, 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 */
78 void
79 init_win32 (void)
81 if (WSAStartup(0x0101, &wsa_state))
83 msg (M_ERR, "WSAStartup failed");
85 window_title_clear (&window_title);
86 win32_signal_clear (&win32_signal);
87 netcmd_semaphore_init ();
90 void
91 uninit_win32 (void)
93 netcmd_semaphore_close ();
94 if (pause_exit_enabled)
96 if (win32_signal.mode == WSO_MODE_UNDEF)
98 struct win32_signal w;
99 win32_signal_open (&w, WSO_FORCE_CONSOLE, NULL, false);
100 win32_pause (&w);
101 win32_signal_close (&w);
103 else
104 win32_pause (&win32_signal);
106 window_title_restore (&window_title);
107 win32_signal_close (&win32_signal);
108 WSACleanup ();
109 free (win_sys_path);
112 void
113 set_pause_exit_win32 (void)
115 pause_exit_enabled = true;
118 bool
119 init_security_attributes_allow_all (struct security_attributes *obj)
121 CLEAR (*obj);
123 obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES);
124 obj->sa.lpSecurityDescriptor = &obj->sd;
125 obj->sa.bInheritHandle = FALSE;
126 if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION))
127 return false;
128 if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE))
129 return false;
130 return true;
133 void
134 overlapped_io_init (struct overlapped_io *o,
135 const struct frame *frame,
136 BOOL event_state,
137 bool tuntap_buffer) /* if true: tuntap buffer, if false: socket buffer */
139 CLEAR (*o);
141 /* manual reset event, initially set according to event_state */
142 o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL);
143 if (o->overlapped.hEvent == NULL)
144 msg (M_ERR, "Error: overlapped_io_init: CreateEvent failed");
146 /* allocate buffer for overlapped I/O */
147 alloc_buf_sock_tun (&o->buf_init, frame, tuntap_buffer, 0);
150 void
151 overlapped_io_close (struct overlapped_io *o)
153 if (o->overlapped.hEvent)
155 if (!CloseHandle (o->overlapped.hEvent))
156 msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on overlapped I/O event object");
158 free_buf (&o->buf_init);
161 char *
162 overlapped_io_state_ascii (const struct overlapped_io *o)
164 switch (o->iostate)
166 case IOSTATE_INITIAL:
167 return "0";
168 case IOSTATE_QUEUED:
169 return "Q";
170 case IOSTATE_IMMEDIATE_RETURN:
171 return "1";
173 return "?";
177 * Event-based notification of network events
180 void
181 init_net_event_win32 (struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags)
183 /* manual reset events, initially set to unsignaled */
185 /* initialize write event */
186 if (!(flags & NE32_PERSIST_EVENT) || !event->write)
188 if (flags & NE32_WRITE_EVENT)
190 event->write = CreateEvent (NULL, TRUE, FALSE, NULL);
191 if (event->write == NULL)
192 msg (M_ERR, "Error: init_net_event_win32: CreateEvent (write) failed");
194 else
195 event->write = NULL;
198 /* initialize read event */
199 if (!(flags & NE32_PERSIST_EVENT) || !event->read)
201 event->read = CreateEvent (NULL, TRUE, FALSE, NULL);
202 if (event->read == NULL)
203 msg (M_ERR, "Error: init_net_event_win32: CreateEvent (read) failed");
206 /* setup network events to change read event state */
207 if (WSAEventSelect (sd, event->read, network_events) != 0)
208 msg (M_FATAL | M_ERRNO_SOCK, "Error: init_net_event_win32: WSAEventSelect call failed");
211 long
212 reset_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd)
214 WSANETWORKEVENTS wne;
215 if (WSAEnumNetworkEvents (sd, event->read, &wne) != 0)
217 msg (M_FATAL | M_ERRNO_SOCK, "Error: reset_net_event_win32: WSAEnumNetworkEvents call failed");
218 return 0; /* NOTREACHED */
220 else
221 return wne.lNetworkEvents;
224 void
225 close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, unsigned int flags)
227 if (event->read)
229 if (socket_defined (sd))
231 if (WSAEventSelect (sd, event->read, 0) != 0)
232 msg (M_WARN | M_ERRNO_SOCK, "Warning: close_net_event_win32: WSAEventSelect call failed");
234 if (!ResetEvent (event->read))
235 msg (M_WARN | M_ERRNO, "Warning: ResetEvent (read) failed in close_net_event_win32");
236 if (!(flags & NE32_PERSIST_EVENT))
238 if (!CloseHandle (event->read))
239 msg (M_WARN | M_ERRNO, "Warning: CloseHandle (read) failed in close_net_event_win32");
240 event->read = NULL;
244 if (event->write)
246 if (!ResetEvent (event->write))
247 msg (M_WARN | M_ERRNO, "Warning: ResetEvent (write) failed in close_net_event_win32");
248 if (!(flags & NE32_PERSIST_EVENT))
250 if (!CloseHandle (event->write))
251 msg (M_WARN | M_ERRNO, "Warning: CloseHandle (write) failed in close_net_event_win32");
252 event->write = NULL;
258 * struct net_event_win32
261 void
262 net_event_win32_init (struct net_event_win32 *ne)
264 CLEAR (*ne);
265 ne->sd = SOCKET_UNDEFINED;
268 void
269 net_event_win32_start (struct net_event_win32 *ne, long network_events, socket_descriptor_t sd)
271 ASSERT (!socket_defined (ne->sd));
272 ne->sd = sd;
273 ne->event_mask = 0;
274 init_net_event_win32 (&ne->handle, network_events, sd, NE32_PERSIST_EVENT|NE32_WRITE_EVENT);
277 void
278 net_event_win32_reset_write (struct net_event_win32 *ne)
280 BOOL status;
281 if (ne->event_mask & FD_WRITE)
282 status = SetEvent (ne->handle.write);
283 else
284 status = ResetEvent (ne->handle.write);
285 if (!status)
286 msg (M_WARN | M_ERRNO, "Warning: SetEvent/ResetEvent failed in net_event_win32_reset_write");
289 void
290 net_event_win32_reset (struct net_event_win32 *ne)
292 ne->event_mask |= reset_net_event_win32 (&ne->handle, ne->sd);
295 void
296 net_event_win32_stop (struct net_event_win32 *ne)
298 if (net_event_win32_defined (ne))
299 close_net_event_win32 (&ne->handle, ne->sd, NE32_PERSIST_EVENT);
300 ne->sd = SOCKET_UNDEFINED;
301 ne->event_mask = 0;
304 void
305 net_event_win32_close (struct net_event_win32 *ne)
307 if (net_event_win32_defined (ne))
308 close_net_event_win32 (&ne->handle, ne->sd, 0);
309 net_event_win32_init (ne);
313 * Simulate *nix signals on Windows.
315 * Two modes:
316 * (1) Console mode -- map keyboard function keys to signals
317 * (2) Service mode -- map Windows event object to SIGTERM
320 void
321 win32_signal_clear (struct win32_signal *ws)
323 CLEAR (*ws);
326 void
327 win32_signal_open (struct win32_signal *ws,
328 int force,
329 const char *exit_event_name,
330 bool exit_event_initial_state)
332 CLEAR (*ws);
334 ws->mode = WSO_MODE_UNDEF;
335 ws->in.read = INVALID_HANDLE_VALUE;
336 ws->in.write = INVALID_HANDLE_VALUE;
337 ws->console_mode_save = 0;
338 ws->console_mode_save_defined = false;
340 if (force == WSO_NOFORCE || force == WSO_FORCE_CONSOLE)
343 * Try to open console.
345 ws->in.read = GetStdHandle (STD_INPUT_HANDLE);
346 if (ws->in.read != INVALID_HANDLE_VALUE)
348 if (GetConsoleMode (ws->in.read, &ws->console_mode_save))
350 /* running on a console */
351 const DWORD new_console_mode = ws->console_mode_save
352 & ~(ENABLE_WINDOW_INPUT
353 | ENABLE_PROCESSED_INPUT
354 | ENABLE_LINE_INPUT
355 | ENABLE_ECHO_INPUT
356 | ENABLE_MOUSE_INPUT);
358 if (new_console_mode != ws->console_mode_save)
360 if (!SetConsoleMode (ws->in.read, new_console_mode))
361 msg (M_ERR, "Error: win32_signal_open: SetConsoleMode failed");
362 ws->console_mode_save_defined = true;
364 ws->mode = WSO_MODE_CONSOLE;
366 else
367 ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a service */
372 * If console open failed, assume we are running
373 * as a service.
375 if ((force == WSO_NOFORCE || force == WSO_FORCE_SERVICE)
376 && !HANDLE_DEFINED (ws->in.read) && exit_event_name)
378 struct security_attributes sa;
380 if (!init_security_attributes_allow_all (&sa))
381 msg (M_ERR, "Error: win32_signal_open: init SA failed");
383 ws->in.read = CreateEvent (&sa.sa,
384 TRUE,
385 exit_event_initial_state ? TRUE : FALSE,
386 exit_event_name);
387 if (ws->in.read == NULL)
389 msg (M_WARN|M_ERRNO, "NOTE: CreateEvent '%s' failed", exit_event_name);
391 else
393 if (WaitForSingleObject (ws->in.read, 0) != WAIT_TIMEOUT)
394 msg (M_FATAL, "ERROR: Exit Event ('%s') is signaled", exit_event_name);
395 else
396 ws->mode = WSO_MODE_SERVICE;
401 static bool
402 keyboard_input_available (struct win32_signal *ws)
404 ASSERT (ws->mode == WSO_MODE_CONSOLE);
405 if (HANDLE_DEFINED (ws->in.read))
407 DWORD n;
408 if (GetNumberOfConsoleInputEvents (ws->in.read, &n))
409 return n > 0;
411 return false;
414 static unsigned int
415 keyboard_ir_to_key (INPUT_RECORD *ir)
417 if (ir->Event.KeyEvent.uChar.AsciiChar == 0)
418 return ir->Event.KeyEvent.wVirtualScanCode;
420 if ((ir->Event.KeyEvent.dwControlKeyState
421 & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
422 && (ir->Event.KeyEvent.wVirtualKeyCode != 18))
423 return ir->Event.KeyEvent.wVirtualScanCode * 256;
425 return ir->Event.KeyEvent.uChar.AsciiChar;
428 static unsigned int
429 win32_keyboard_get (struct win32_signal *ws)
431 ASSERT (ws->mode == WSO_MODE_CONSOLE);
432 if (HANDLE_DEFINED (ws->in.read))
434 INPUT_RECORD ir;
435 do {
436 DWORD n;
437 if (!keyboard_input_available (ws))
438 return 0;
439 if (!ReadConsoleInput (ws->in.read, &ir, 1, &n))
440 return 0;
441 } while (ir.EventType != KEY_EVENT || ir.Event.KeyEvent.bKeyDown != TRUE);
443 return keyboard_ir_to_key (&ir);
445 else
446 return 0;
449 void
450 win32_signal_close (struct win32_signal *ws)
452 if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED (ws->in.read))
453 CloseHandle (ws->in.read);
454 if (ws->console_mode_save_defined)
456 if (!SetConsoleMode (ws->in.read, ws->console_mode_save))
457 msg (M_ERR, "Error: win32_signal_close: SetConsoleMode failed");
459 CLEAR (*ws);
463 * Return true if interrupt occurs in service mode.
465 static bool
466 win32_service_interrupt (struct win32_signal *ws)
468 if (ws->mode == WSO_MODE_SERVICE)
470 if (HANDLE_DEFINED (ws->in.read)
471 && WaitForSingleObject (ws->in.read, 0) == WAIT_OBJECT_0)
472 return true;
474 return false;
478 win32_signal_get (struct win32_signal *ws)
480 int ret = 0;
481 if (siginfo_static.signal_received)
483 ret = siginfo_static.signal_received;
485 else
487 if (ws->mode == WSO_MODE_SERVICE)
489 if (win32_service_interrupt (ws))
490 ret = SIGTERM;
492 else if (ws->mode == WSO_MODE_CONSOLE)
494 switch (win32_keyboard_get (ws))
496 case 0x3B: /* F1 -> USR1 */
497 ret = SIGUSR1;
498 break;
499 case 0x3C: /* F2 -> USR2 */
500 ret = SIGUSR2;
501 break;
502 case 0x3D: /* F3 -> HUP */
503 ret = SIGHUP;
504 break;
505 case 0x3E: /* F4 -> TERM */
506 ret = SIGTERM;
507 break;
510 if (ret)
512 siginfo_static.signal_received = ret;
513 siginfo_static.hard = true;
516 return ret;
519 void
520 win32_pause (struct win32_signal *ws)
522 if (ws->mode == WSO_MODE_CONSOLE && HANDLE_DEFINED (ws->in.read))
524 int status;
525 msg (M_INFO|M_NOPREFIX, "Press any key to continue...");
526 do {
527 status = WaitForSingleObject (ws->in.read, INFINITE);
528 } while (!win32_keyboard_get (ws));
532 /* window functions */
534 void
535 window_title_clear (struct window_title *wt)
537 CLEAR (*wt);
540 void
541 window_title_save (struct window_title *wt)
543 if (!wt->saved)
545 if (!GetConsoleTitle (wt->old_window_title, sizeof (wt->old_window_title)))
547 wt->old_window_title[0] = 0;
548 wt->saved = false;
550 else
551 wt->saved = true;
555 void
556 window_title_restore (const struct window_title *wt)
558 if (wt->saved)
559 SetConsoleTitle (wt->old_window_title);
562 void
563 window_title_generate (const char *title)
565 struct gc_arena gc = gc_new ();
566 struct buffer out = alloc_buf_gc (256, &gc);
567 if (!title)
568 title = "";
569 buf_printf (&out, "[%s] " PACKAGE_NAME " " VERSION " F4:EXIT F1:USR1 F2:USR2 F3:HUP", title);
570 SetConsoleTitle (BSTR (&out));
571 gc_free (&gc);
574 /* semaphore functions */
576 void
577 semaphore_clear (struct semaphore *s)
579 CLEAR (*s);
582 void
583 semaphore_open (struct semaphore *s, const char *name)
585 struct security_attributes sa;
587 s->locked = false;
588 s->name = name;
589 s->hand = NULL;
591 if (init_security_attributes_allow_all (&sa))
592 s->hand = CreateSemaphore(&sa.sa, 1, 1, name);
594 if (s->hand == NULL)
595 msg (M_WARN|M_ERRNO, "WARNING: Cannot create Win32 semaphore '%s'", name);
596 else
597 dmsg (D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name);
600 bool
601 semaphore_lock (struct semaphore *s, int timeout_milliseconds)
603 bool ret = true;
605 if (s->hand)
607 DWORD status;
608 ASSERT (!s->locked);
610 dmsg (D_SEMAPHORE_LOW, "Attempting to lock Win32 semaphore '%s' prior to net shell command (timeout = %d sec)",
611 s->name,
612 timeout_milliseconds / 1000);
613 status = WaitForSingleObject (s->hand, timeout_milliseconds);
614 if (status == WAIT_FAILED)
615 msg (M_ERR, "Wait failed on Win32 semaphore '%s'", s->name);
616 ret = (status == WAIT_TIMEOUT) ? false : true;
617 if (ret)
619 dmsg (D_SEMAPHORE, "Locked Win32 semaphore '%s'", s->name);
620 s->locked = true;
622 else
624 dmsg (D_SEMAPHORE, "Wait on Win32 semaphore '%s' timed out after %d milliseconds",
625 s->name,
626 timeout_milliseconds);
629 return ret;
632 void
633 semaphore_release (struct semaphore *s)
635 if (s->hand)
637 ASSERT (s->locked);
638 dmsg (D_SEMAPHORE, "Releasing Win32 semaphore '%s'", s->name);
639 if (!ReleaseSemaphore(s->hand, 1, NULL))
640 msg (M_WARN | M_ERRNO, "ReleaseSemaphore failed on Win32 semaphore '%s'",
641 s->name);
642 s->locked = false;
646 void
647 semaphore_close (struct semaphore *s)
649 if (s->hand)
651 if (s->locked)
652 semaphore_release (s);
653 dmsg (D_SEMAPHORE, "Closing Win32 semaphore '%s'", s->name);
654 CloseHandle (s->hand);
655 s->hand = NULL;
660 * Special global semaphore used to protect network
661 * shell commands from simultaneous instantiation.
664 void
665 netcmd_semaphore_init (void)
667 semaphore_open (&netcmd_semaphore, PACKAGE "_netcmd");
670 void
671 netcmd_semaphore_close (void)
673 semaphore_close (&netcmd_semaphore);
676 void
677 netcmd_semaphore_lock (void)
679 const int timeout_seconds = 600;
680 if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000))
681 msg (M_FATAL, "Cannot lock net command semaphore");
684 void
685 netcmd_semaphore_release (void)
687 semaphore_release (&netcmd_semaphore);
691 * Get input from console.
693 * Return false on input error, or if service
694 * exit event is signaled.
697 bool
698 get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
700 HANDLE in = INVALID_HANDLE_VALUE;
701 HANDLE err = INVALID_HANDLE_VALUE;
702 DWORD len = 0;
704 ASSERT (prompt);
705 ASSERT (input);
706 ASSERT (capacity > 0);
708 input[0] = '\0';
710 in = GetStdHandle (STD_INPUT_HANDLE);
711 err = get_orig_stderr ();
713 if (in != INVALID_HANDLE_VALUE
714 && err != INVALID_HANDLE_VALUE
715 && !win32_service_interrupt (&win32_signal)
716 && WriteFile (err, prompt, strlen (prompt), &len, NULL))
718 bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
719 DWORD flags_save = 0;
720 int status = 0;
722 if (is_console)
724 if (GetConsoleMode (in, &flags_save))
726 DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
727 if (echo)
728 flags |= ENABLE_ECHO_INPUT;
729 SetConsoleMode (in, flags);
731 else
732 is_console = 0;
735 status = ReadFile (in, input, capacity, &len, NULL);
737 string_null_terminate (input, (int)len, capacity);
738 chomp (input);
740 if (!echo)
741 WriteFile (err, "\r\n", 2, &len, NULL);
742 if (is_console)
743 SetConsoleMode (in, flags_save);
744 if (status && !win32_service_interrupt (&win32_signal))
745 return true;
748 return false;
751 /* get password from console */
753 char *
754 getpass (const char *prompt)
756 static char line[256];
757 if (get_console_input_win32 (prompt, false, line, sizeof (line)))
758 return line;
759 else
760 return NULL;
764 * Return true if filename is safe to be used on Windows,
765 * by avoiding the following reserved names:
767 * CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9,
768 * LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, and CLOCK$
770 * See: http://msdn.microsoft.com/en-us/library/aa365247.aspx
771 * and http://msdn.microsoft.com/en-us/library/86k9f82k(VS.80).aspx
774 static bool
775 cmp_prefix (const char *str, const bool n, const char *pre)
777 size_t i = 0;
779 if (!str)
780 return false;
782 while (true)
784 const int c1 = pre[i];
785 int c2 = str[i];
786 ++i;
787 if (c1 == '\0')
789 if (n)
791 if (isdigit (c2))
792 c2 = str[i];
793 else
794 return false;
796 return c2 == '\0' || c2 == '.';
798 else if (c2 == '\0')
799 return false;
800 if (c1 != tolower(c2))
801 return false;
805 bool
806 win_safe_filename (const char *fn)
808 if (cmp_prefix (fn, false, "con"))
809 return false;
810 if (cmp_prefix (fn, false, "prn"))
811 return false;
812 if (cmp_prefix (fn, false, "aux"))
813 return false;
814 if (cmp_prefix (fn, false, "nul"))
815 return false;
816 if (cmp_prefix (fn, true, "com"))
817 return false;
818 if (cmp_prefix (fn, true, "lpt"))
819 return false;
820 if (cmp_prefix (fn, false, "clock$"))
821 return false;
822 return true;
826 * Service functions for openvpn_execve
829 static char *
830 env_block (const struct env_set *es)
832 if (es)
834 struct env_item *e;
835 char *ret;
836 char *p;
837 size_t nchars = 1;
839 for (e = es->list; e != NULL; e = e->next)
840 nchars += strlen (e->string) + 1;
842 ret = (char *) malloc (nchars);
843 check_malloc_return (ret);
845 p = ret;
846 for (e = es->list; e != NULL; e = e->next)
848 if (env_allowed (e->string))
850 strcpy (p, e->string);
851 p += strlen (e->string) + 1;
854 *p = '\0';
855 return ret;
857 else
858 return NULL;
861 static char *
862 cmd_line (const struct argv *a)
864 size_t nchars = 1;
865 size_t maxlen = 0;
866 size_t i;
867 struct buffer buf;
868 char *work = NULL;
870 if (!a)
871 return NULL;
873 for (i = 0; i < a->argc; ++i)
875 const char *arg = a->argv[i];
876 const size_t len = strlen (arg);
877 nchars += len + 3;
878 if (len > maxlen)
879 maxlen = len;
882 work = (char *) malloc (maxlen + 1);
883 check_malloc_return (work);
884 buf = alloc_buf (nchars);
886 for (i = 0; i < a->argc; ++i)
888 const char *arg = a->argv[i];
889 strcpy (work, arg);
890 string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_');
891 if (i)
892 buf_printf (&buf, " ");
893 if (string_class (work, CC_ANY, CC_SPACE))
894 buf_printf (&buf, "%s", work);
895 else
896 buf_printf (&buf, "\"%s\"", work);
899 free (work);
900 return BSTR(&buf);
904 * Attempt to simulate fork/execve on Windows
907 openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
909 int ret = -1;
910 if (a && a->argv[0])
912 if (openvpn_execve_allowed (flags))
914 STARTUPINFO start_info;
915 PROCESS_INFORMATION proc_info;
917 char *env = env_block (es);
918 char *cl = cmd_line (a);
919 char *cmd = a->argv[0];
921 CLEAR (start_info);
922 CLEAR (proc_info);
924 /* fill in STARTUPINFO struct */
925 GetStartupInfo(&start_info);
926 start_info.cb = sizeof(start_info);
927 start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
928 start_info.wShowWindow = SW_HIDE;
929 start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
930 start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
932 if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info))
934 DWORD exit_status = 0;
935 CloseHandle (proc_info.hThread);
936 WaitForSingleObject (proc_info.hProcess, INFINITE);
937 if (GetExitCodeProcess (proc_info.hProcess, &exit_status))
938 ret = (int)exit_status;
939 else
940 msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd);
941 CloseHandle (proc_info.hProcess);
943 else
945 msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd);
947 free (cl);
948 free (env);
950 else
952 msg (M_WARN, "openvpn_execve: external program may not be called due to setting of --script-security level");
955 else
957 msg (M_WARN, "openvpn_execve: called with empty argv");
959 return ret;
962 char *
963 get_win_sys_path (void)
965 ASSERT (win_sys_path);
966 return win_sys_path;
969 void
970 set_win_sys_path (const char *newpath, struct env_set *es)
972 free (win_sys_path);
973 win_sys_path = string_alloc (newpath, NULL);
974 setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */
977 void
978 set_win_sys_path_via_env (struct env_set *es)
980 char buf[256];
981 DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf));
982 if (!status)
983 msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME);
984 if (status > sizeof (buf) - 1)
985 msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME);
986 set_win_sys_path (buf, es);
989 void
990 env_set_add_win32 (struct env_set *es)
992 set_win_sys_path (DEFAULT_WIN_SYS_PATH, es);
995 #endif