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-2010 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)
955
static bool exec_warn = false;
959
if (openvpn_execve_allowed (flags))
961
if (script_method == SM_EXECVE)
963
STARTUPINFO start_info;
964
PROCESS_INFORMATION proc_info;
966
char *env = env_block (es);
967
char *cl = cmd_line (a);
968
char *cmd = a->argv[0];
973
/* fill in STARTUPINFO struct */
974
GetStartupInfo(&start_info);
975
start_info.cb = sizeof(start_info);
976
start_info.dwFlags = STARTF_USESHOWWINDOW;
977
start_info.wShowWindow = SW_HIDE;
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);
1007
else if (!exec_warn && (script_security < SSEC_SCRIPTS))
1009
msg (M_WARN, SCRIPT_SECURITY_WARNING);
1015
msg (M_WARN, "openvpn_execve: called with empty argv");
1021
* call ourself in another process
1024
fork_to_self (const char *cmdline)
1026
STARTUPINFO start_info;
1027
PROCESS_INFORMATION proc_info;
1029
char *cl = string_alloc (cmdline, NULL);
1036
status = GetModuleFileName (NULL, self_exe, sizeof(self_exe));
1037
if (status == 0 || status == sizeof(self_exe))
1039
msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName");
1043
/* fill in STARTUPINFO struct */
1044
GetStartupInfo(&start_info);
1045
start_info.cb = sizeof(start_info);
1046
start_info.dwFlags = STARTF_USESHOWWINDOW;
1047
start_info.wShowWindow = SW_HIDE;
1049
if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info))
1051
CloseHandle (proc_info.hThread);
1052
CloseHandle (proc_info.hProcess);
1056
msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline);
1064
get_win_sys_path (void)
1066
ASSERT (win_sys_path);
1067
return win_sys_path;
1071
set_win_sys_path (const char *newpath, struct env_set *es)
1073
free (win_sys_path);
1074
win_sys_path = string_alloc (newpath, NULL);
1075
setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */
1079
set_win_sys_path_via_env (struct env_set *es)
1082
DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf));
1084
msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME);
1085
if (status > sizeof (buf) - 1)
1086
msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME);
1087
set_win_sys_path (buf, es);
1091
env_set_add_win32 (struct env_set *es)
1093
set_win_sys_path (DEFAULT_WIN_SYS_PATH, es);
1100
static char buf[MAX_PATH];
1105
if (!GetTempPath(sizeof(buf),buf)) {
1106
/* Warn if we can't find a valid temporary directory, which should
1109
msg (M_WARN, "Could not find a suitable temporary directory."
1110
" (GetTempPath() failed). Consider to use --tmp-dir");