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
8 * Copyright (C) 2002-2008 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.
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
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
83 configure_win_path (void)
85 static bool done
= false; /* GLOBAL */
89 fp
= fopen ("c:\\windows\\system32\\route.exe", "rb");
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
= ";";
99 status
= GetEnvironmentVariable ("PATH", BPTR(&oldpath
), (DWORD
)BCAP(&oldpath
));
105 *BPTR(&oldpath
) = '\0';
108 buf_printf (&newpath
, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s",
111 SetEnvironmentVariable ("PATH", BSTR(&newpath
));
113 status
= GetEnvironmentVariable ("PATH", BPTR(&oldpath
), (DWORD
)BCAP(&oldpath
));
115 printf ("PATH: %s\n", BSTR(&oldpath
));
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 ();
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);
146 win32_signal_close (&w
);
149 win32_pause (&win32_signal
);
151 window_title_restore (&window_title
);
152 win32_signal_close (&win32_signal
);
158 set_pause_exit_win32 (void)
160 pause_exit_enabled
= true;
164 init_security_attributes_allow_all (struct security_attributes
*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
))
173 if (!SetSecurityDescriptorDacl (&obj
->sd
, TRUE
, NULL
, FALSE
))
179 overlapped_io_init (struct overlapped_io
*o
,
180 const struct frame
*frame
,
182 bool tuntap_buffer
) /* if true: tuntap buffer, if false: socket buffer */
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);
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
);
207 overlapped_io_state_ascii (const struct overlapped_io
*o
)
211 case IOSTATE_INITIAL
:
215 case IOSTATE_IMMEDIATE_RETURN
:
222 * Event-based notification of network events
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");
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");
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 */
266 return wne
.lNetworkEvents
;
270 close_net_event_win32 (struct rw_handle
*event
, socket_descriptor_t sd
, unsigned int flags
)
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");
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");
303 * struct net_event_win32
307 net_event_win32_init (struct net_event_win32
*ne
)
310 ne
->sd
= SOCKET_UNDEFINED
;
314 net_event_win32_start (struct net_event_win32
*ne
, long network_events
, socket_descriptor_t sd
)
316 ASSERT (!socket_defined (ne
->sd
));
319 init_net_event_win32 (&ne
->handle
, network_events
, sd
, NE32_PERSIST_EVENT
|NE32_WRITE_EVENT
);
323 net_event_win32_reset_write (struct net_event_win32
*ne
)
326 if (ne
->event_mask
& FD_WRITE
)
327 status
= SetEvent (ne
->handle
.write
);
329 status
= ResetEvent (ne
->handle
.write
);
331 msg (M_WARN
| M_ERRNO
, "Warning: SetEvent/ResetEvent failed in net_event_win32_reset_write");
335 net_event_win32_reset (struct net_event_win32
*ne
)
337 ne
->event_mask
|= reset_net_event_win32 (&ne
->handle
, ne
->sd
);
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
;
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.
361 * (1) Console mode -- map keyboard function keys to signals
362 * (2) Service mode -- map Windows event object to SIGTERM
366 win32_signal_clear (struct win32_signal
*ws
)
372 win32_signal_open (struct win32_signal
*ws
,
374 const char *exit_event_name
,
375 bool exit_event_initial_state
)
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
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
;
412 ws
->in
.read
= INVALID_HANDLE_VALUE
; /* probably running as a service */
417 * If console open failed, assume we are running
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
,
430 exit_event_initial_state
? TRUE
: FALSE
,
432 if (ws
->in
.read
== NULL
)
434 msg (M_WARN
|M_ERRNO
, "NOTE: CreateEvent '%s' failed", exit_event_name
);
438 if (WaitForSingleObject (ws
->in
.read
, 0) != WAIT_TIMEOUT
)
439 msg (M_FATAL
, "ERROR: Exit Event ('%s') is signaled", exit_event_name
);
441 ws
->mode
= WSO_MODE_SERVICE
;
447 keyboard_input_available (struct win32_signal
*ws
)
449 ASSERT (ws
->mode
== WSO_MODE_CONSOLE
);
450 if (HANDLE_DEFINED (ws
->in
.read
))
453 if (GetNumberOfConsoleInputEvents (ws
->in
.read
, &n
))
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
;
474 win32_keyboard_get (struct win32_signal
*ws
)
476 ASSERT (ws
->mode
== WSO_MODE_CONSOLE
);
477 if (HANDLE_DEFINED (ws
->in
.read
))
482 if (!keyboard_input_available (ws
))
484 if (!ReadConsoleInput (ws
->in
.read
, &ir
, 1, &n
))
486 } while (ir
.EventType
!= KEY_EVENT
|| ir
.Event
.KeyEvent
.bKeyDown
!= TRUE
);
488 return keyboard_ir_to_key (&ir
);
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");
508 * Return true if interrupt occurs in service mode.
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
)
523 win32_signal_get (struct win32_signal
*ws
)
526 if (siginfo_static
.signal_received
)
528 ret
= siginfo_static
.signal_received
;
532 if (ws
->mode
== WSO_MODE_SERVICE
)
534 if (win32_service_interrupt (ws
))
537 else if (ws
->mode
== WSO_MODE_CONSOLE
)
539 switch (win32_keyboard_get (ws
))
541 case 0x3B: /* F1 -> USR1 */
544 case 0x3C: /* F2 -> USR2 */
547 case 0x3D: /* F3 -> HUP */
550 case 0x3E: /* F4 -> TERM */
557 siginfo_static
.signal_received
= ret
;
558 siginfo_static
.hard
= true;
565 win32_pause (struct win32_signal
*ws
)
567 if (ws
->mode
== WSO_MODE_CONSOLE
&& HANDLE_DEFINED (ws
->in
.read
))
570 msg (M_INFO
|M_NOPREFIX
, "Press any key to continue...");
572 status
= WaitForSingleObject (ws
->in
.read
, INFINITE
);
573 } while (!win32_keyboard_get (ws
));
577 /* window functions */
580 window_title_clear (struct window_title
*wt
)
586 window_title_save (struct window_title
*wt
)
590 if (!GetConsoleTitle (wt
->old_window_title
, sizeof (wt
->old_window_title
)))
592 wt
->old_window_title
[0] = 0;
601 window_title_restore (const struct window_title
*wt
)
604 SetConsoleTitle (wt
->old_window_title
);
608 window_title_generate (const char *title
)
610 struct gc_arena gc
= gc_new ();
611 struct buffer out
= alloc_buf_gc (256, &gc
);
614 buf_printf (&out
, "[%s] " PACKAGE_NAME
" " VERSION
" F4:EXIT F1:USR1 F2:USR2 F3:HUP", title
);
615 SetConsoleTitle (BSTR (&out
));
619 /* semaphore functions */
622 semaphore_clear (struct semaphore
*s
)
628 semaphore_open (struct semaphore
*s
, const char *name
)
630 struct security_attributes sa
;
636 if (init_security_attributes_allow_all (&sa
))
637 s
->hand
= CreateSemaphore(&sa
.sa
, 1, 1, name
);
640 msg (M_WARN
|M_ERRNO
, "WARNING: Cannot create Win32 semaphore '%s'", name
);
642 dmsg (D_SEMAPHORE
, "Created Win32 semaphore '%s'", s
->name
);
646 semaphore_lock (struct semaphore
*s
, int timeout_milliseconds
)
655 dmsg (D_SEMAPHORE_LOW
, "Attempting to lock Win32 semaphore '%s' prior to net shell command (timeout = %d sec)",
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;
664 dmsg (D_SEMAPHORE
, "Locked Win32 semaphore '%s'", s
->name
);
669 dmsg (D_SEMAPHORE
, "Wait on Win32 semaphore '%s' timed out after %d milliseconds",
671 timeout_milliseconds
);
678 semaphore_release (struct semaphore
*s
)
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'",
692 semaphore_close (struct semaphore
*s
)
697 semaphore_release (s
);
698 dmsg (D_SEMAPHORE
, "Closing Win32 semaphore '%s'", s
->name
);
699 CloseHandle (s
->hand
);
705 * Special global semaphore used to protect network
706 * shell commands from simultaneous instantiation.
710 netcmd_semaphore_init (void)
712 semaphore_open (&netcmd_semaphore
, PACKAGE
"_netcmd");
716 netcmd_semaphore_close (void)
718 semaphore_close (&netcmd_semaphore
);
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");
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.
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
;
751 ASSERT (capacity
> 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;
769 if (GetConsoleMode (in
, &flags_save
))
771 DWORD flags
= ENABLE_LINE_INPUT
| ENABLE_PROCESSED_INPUT
;
773 flags
|= ENABLE_ECHO_INPUT
;
774 SetConsoleMode (in
, flags
);
780 status
= ReadFile (in
, input
, capacity
, &len
, NULL
);
782 string_null_terminate (input
, (int)len
, capacity
);
786 WriteFile (err
, "\r\n", 2, &len
, NULL
);
788 SetConsoleMode (in
, flags_save
);
789 if (status
&& !win32_service_interrupt (&win32_signal
))
796 /* get password from console */
799 getpass (const char *prompt
)
801 static char line
[256];
802 if (get_console_input_win32 (prompt
, false, line
, sizeof (line
)))
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
820 cmp_prefix (const char *str
, const bool n
, const char *pre
)
829 const int c1
= pre
[i
];
841 return c2
== '\0' || c2
== '.';
845 if (c1
!= tolower(c2
))
851 win_safe_filename (const char *fn
)
853 if (cmp_prefix (fn
, false, "con"))
855 if (cmp_prefix (fn
, false, "prn"))
857 if (cmp_prefix (fn
, false, "aux"))
859 if (cmp_prefix (fn
, false, "nul"))
861 if (cmp_prefix (fn
, true, "com"))
863 if (cmp_prefix (fn
, true, "lpt"))
865 if (cmp_prefix (fn
, false, "clock$"))
871 * Service functions for openvpn_execve
875 env_block (const struct env_set
*es
)
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
);
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;
907 cmd_line (const struct argv
*a
)
918 for (i
= 0; i
< a
->argc
; ++i
)
920 const char *arg
= a
->argv
[i
];
921 const size_t len
= strlen (arg
);
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
];
935 string_mod (work
, CC_PRINT
, CC_DOUBLE_QUOTE
|CC_CRLF
, '_');
937 buf_printf (&buf
, " ");
938 if (string_class (work
, CC_ANY
, CC_SPACE
))
939 buf_printf (&buf
, "%s", work
);
941 buf_printf (&buf
, "\"%s\"", work
);
949 * Attempt to simulate fork/execve on Windows
952 openvpn_execve (const struct argv
*a
, const struct env_set
*es
, const unsigned int flags
)
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];
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
;
987 msg (M_WARN
|M_ERRNO
, "openvpn_execve: GetExitCodeProcess %s failed", cmd
);
988 CloseHandle (proc_info
.hProcess
);
992 msg (M_WARN
|M_ERRNO
, "openvpn_execve: CreateProcess %s failed", cmd
);
997 else if (script_method
== SM_SYSTEM
)
999 configure_win_path ();
1000 ret
= openvpn_system (argv_system_str (a
), es
, flags
);
1009 msg (M_WARN
, SCRIPT_SECURITY_WARNING
);
1014 msg (M_WARN
, "openvpn_execve: called with empty argv");
1020 get_win_sys_path (void)
1022 ASSERT (win_sys_path
);
1023 return win_sys_path
;
1027 set_win_sys_path (const char *newpath
, struct env_set
*es
)
1029 free (win_sys_path
);
1030 win_sys_path
= string_alloc (newpath
, NULL
);
1031 setenv_str (es
, SYS_PATH_ENV_VAR_NAME
, win_sys_path
); /* route.exe needs this */
1035 set_win_sys_path_via_env (struct env_set
*es
)
1038 DWORD status
= GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME
, buf
, sizeof(buf
));
1040 msg (M_ERR
, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME
);
1041 if (status
> sizeof (buf
) - 1)
1042 msg (M_FATAL
, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME
);
1043 set_win_sys_path (buf
, es
);
1047 env_set_add_win32 (struct env_set
*es
)
1049 set_win_sys_path (DEFAULT_WIN_SYS_PATH
, es
);