From a82813527551f0e79c6d6ed5a9c1162e3c171bcf Mon Sep 17 00:00:00 2001 From: james Date: Mon, 17 Nov 2008 04:28:07 +0000 Subject: [PATCH] * Added additional method parameter to --script-security to preserve backward compatibility with system() call semantics used in OpenVPN 2.1_rc8 and earlier. To preserve backward compatibility use: script-security 3 system git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3495 e7ae566f-a301-0410-adde-c780ea21d3b5 --- ChangeLog | 8 +- buffer.h | 7 -- common.h | 2 +- errlevel.h | 1 + init.c | 5 +- misc.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++------- misc.h | 17 ++++ openvpn.8 | 25 +++++- options.c | 35 ++++++-- route.c | 4 +- tun.c | 30 ++----- tun.h | 2 - version.m4 | 2 +- win32.c | 115 ++++++++++++++++++------- 14 files changed, 389 insertions(+), 111 deletions(-) diff --git a/ChangeLog b/ChangeLog index 14d4a5cc..ef5e4080 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,7 @@ Copyright (C) 2002-2008 OpenVPN Technologies, Inc. $Id$ -2008.11.xx -- Version 2.1_rc13b +2008.11.xx -- Version 2.1_rc14 * Added AC_GNU_SOURCE to configure.ac to enable struct ucred, with the goal of fixing a build issue on Fedora 9 that was @@ -89,6 +89,12 @@ $Id$ config file syntax checking to allow directives for future OpenVPN versions to be ignored. +* Added additional method parameter to --script-security to preserve + backward compatibility with system() call semantics used in OpenVPN + 2.1_rc8 and earlier. To preserve backward compatibility use: + + script-security 3 system + 2008.10.07 -- Version 2.1_rc13 * Bundled OpenSSL 0.9.8i with Windows installer. diff --git a/buffer.h b/buffer.h index bfb6a1c4..7872c374 100644 --- a/buffer.h +++ b/buffer.h @@ -58,13 +58,6 @@ struct buffer #endif }; -/* used by argv_x functions */ -struct argv { - size_t capacity; - size_t argc; - char **argv; -}; - /* for garbage collection */ struct gc_entry diff --git a/common.h b/common.h index 7aa70a5d..59b31b3e 100644 --- a/common.h +++ b/common.h @@ -84,6 +84,6 @@ typedef unsigned long ptr_type; /* * Script security warning */ -#define SCRIPT_SECURITY_WARNING "openvpn_execve: external program may not be called unless '--script-security 2' or higher is enabled. See --help text for detailed info." +#define SCRIPT_SECURITY_WARNING "openvpn_execve: external program may not be called unless '--script-security 2' or higher is enabled. Use '--script-security 3 system' for backward compatibility with 2.1_rc8 and earlier. See --help text or man page for detailed info." #endif diff --git a/errlevel.h b/errlevel.h index b2c423a2..fc05fe63 100644 --- a/errlevel.h +++ b/errlevel.h @@ -139,6 +139,7 @@ #define D_PS_PROXY_DEBUG LOGLEV(7, 70, M_DEBUG) /* port share proxy debug */ #define D_AUTO_USERID LOGLEV(7, 70, M_DEBUG) /* AUTO_USERID debugging */ #define D_TLS_KEYSELECT LOGLEV(7, 70, M_DEBUG) /* show information on key selection for data channel */ +#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_printf %sc */ #define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */ #define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */ diff --git a/init.c b/init.c index 519dc8bc..455712a7 100644 --- a/init.c +++ b/init.c @@ -523,7 +523,7 @@ void init_options_dev (struct options *options) { if (!options->dev) - options->dev = dev_component_in_dev_node (options->dev_node); + options->dev = openvpn_basename (options->dev_node); } bool @@ -2003,6 +2003,9 @@ do_option_warnings (struct context *c) msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); else msg (M_WARN, "NOTE: " PACKAGE_NAME " 2.1 requires '--script-security 2' or higher to call user-defined scripts or executables"); + + if (script_method == SM_SYSTEM) + msg (M_WARN, "NOTE: --script-security method='system' is deprecated due to the fact that passed parameters will be subject to shell expansion"); } static void diff --git a/misc.c b/misc.c index 911e9111..5f890884 100644 --- a/misc.c +++ b/misc.c @@ -46,6 +46,9 @@ const char *iproute_path = IPROUTE_PATH; /* GLOBAL */ /* contains an SSEC_x value defined in misc.h */ int script_security = SSEC_BUILT_IN; /* GLOBAL */ +/* contains SM_x value defined in misc.h */ +int script_method = SM_EXECVE; /* GLOBAL */ + /* Redefine the top level directory of the filesystem to restrict access to files for security */ void @@ -507,23 +510,34 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i #if defined(ENABLE_EXECVE) if (openvpn_execve_allowed (flags)) { - const char *cmd = a->argv[0]; - char *const *argv = a->argv; - char *const *envp = (char *const *)make_env_array (es, true, &gc); - pid_t pid; + if (script_method == SM_EXECVE) + { + const char *cmd = a->argv[0]; + char *const *argv = a->argv; + char *const *envp = (char *const *)make_env_array (es, true, &gc); + pid_t pid; - pid = fork (); - if (pid == (pid_t)0) /* child side */ - { - execve (cmd, argv, envp); - exit (127); + pid = fork (); + if (pid == (pid_t)0) /* child side */ + { + execve (cmd, argv, envp); + exit (127); + } + else if (pid < (pid_t)0) /* fork failed */ + ; + else /* parent side */ + { + if (waitpid (pid, &ret, 0) != pid) + ret = -1; + } } - else if (pid < (pid_t)0) /* fork failed */ - ; - else /* parent side */ + else if (script_method == SM_SYSTEM) { - if (waitpid (pid, &ret, 0) != pid) - ret = -1; + ret = openvpn_system (argv_system_str (a), es, flags); + } + else + { + ASSERT (0); } } else @@ -544,6 +558,52 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i } #endif +/* + * Wrapper around the system() call. + */ +int +openvpn_system (const char *command, const struct env_set *es, unsigned int flags) +{ +#ifdef HAVE_SYSTEM + int ret; + + perf_push (PERF_SCRIPT); + + /* + * add env_set to environment. + */ + if (flags & S_SCRIPT) + env_set_add_to_environment (es); + + + /* debugging */ + dmsg (D_SCRIPT, "SYSTEM[%u] '%s'", flags, command); + if (flags & S_SCRIPT) + env_set_print (D_SCRIPT, es); + + /* + * execute the command + */ + ret = system (command); + + /* debugging */ + dmsg (D_SCRIPT, "SYSTEM return=%u", ret); + + /* + * remove env_set from environment + */ + if (flags & S_SCRIPT) + env_set_remove_from_environment (es); + + perf_pop (); + return ret; + +#else + msg (M_FATAL, "Sorry but I can't execute the shell command '%s' because this operating system doesn't appear to support the system() call", command); + return -1; /* NOTREACHED */ +#endif +} + /* * Initialize random number seed. random() is only used * when "weak" random numbers are acceptable. @@ -1679,6 +1739,7 @@ argv_init (struct argv *a) a->capacity = 0; a->argc = 0; a->argv = NULL; + a->system_str = NULL; } struct argv @@ -1696,6 +1757,7 @@ argv_reset (struct argv *a) for (i = 0; i < a->argc; ++i) free (a->argv[i]); free (a->argv); + free (a->system_str); argv_init (a); } @@ -1730,6 +1792,64 @@ argv_append (struct argv *a, char *str) /* str must have been malloced or be NUL a->argv[a->argc++] = str; } +static void +argv_system_str_append (struct argv *a, const char *str, const bool enquote) +{ + if (str) + { + char *newstr; + + /* compute length of new system_str */ + size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */ + if (a->system_str) + l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */ + if (enquote) + l += 2; /* space for two quotes */ + + /* build new system_str */ + newstr = (char *) malloc (l); + newstr[0] = '\0'; + check_malloc_return (newstr); + if (a->system_str) + { + strcpy (newstr, a->system_str); + strcat (newstr, " "); + } + if (enquote) + strcat (newstr, "\""); + strcat (newstr, str); + if (enquote) + strcat (newstr, "\""); + free (a->system_str); + a->system_str = newstr; + } +} + +static char * +argv_extract_cmd_name (const char *path) +{ + if (path) + { + const char *bn = openvpn_basename (path); + if (bn) + { + char *ret = string_alloc (bn, NULL); + char *dot = strrchr (ret, '.'); + if (dot) + *dot = '\0'; + if (ret[0] != '\0') + return ret; + } + } + return NULL; +} + +const char * +argv_system_str (const struct argv *a) +{ + return a->system_str; +} + struct argv argv_clone (const struct argv *a, const size_t headroom) { @@ -1744,6 +1864,7 @@ argv_clone (const struct argv *a, const size_t headroom) for (i = 0; i < a->argc; ++i) argv_append (&r, string_alloc (a->argv[i], NULL)); } + r.system_str = string_alloc (a->system_str, NULL); return r; } @@ -1751,10 +1872,17 @@ struct argv argv_insert_head (const struct argv *a, const char *head) { struct argv r; + char *s; r = argv_clone (a, 1); r.argv[0] = string_alloc (head, NULL); - + s = r.system_str; + r.system_str = string_alloc (head, NULL); + if (s) + { + argv_system_str_append (&r, s, false); + free (s); + } return r; } @@ -1870,6 +1998,7 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag if (!s) s = ""; argv_append (a, string_alloc (s, NULL)); + argv_system_str_append (a, s, true); } else if (!strcmp (term, "%sc")) { @@ -1880,24 +2009,36 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag char *parms[MAX_PARMS+1]; int i; - nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, M_FATAL, &gc); - for (i = 0; i < nparms; ++i) - argv_append (a, string_alloc (parms[i], NULL)); + nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); + if (nparms) + { + for (i = 0; i < nparms; ++i) + argv_append (a, string_alloc (parms[i], NULL)); + } + else + argv_append (a, string_alloc (s, NULL)); + + argv_system_str_append (a, s, false); } else - argv_append (a, string_alloc ("", NULL)); + { + argv_append (a, string_alloc ("", NULL)); + argv_system_str_append (a, "echo", false); + } } else if (!strcmp (term, "%d")) { char numstr[64]; openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); argv_append (a, string_alloc (numstr, NULL)); + argv_system_str_append (a, numstr, false); } else if (!strcmp (term, "%u")) { char numstr[64]; openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); argv_append (a, string_alloc (numstr, NULL)); + argv_system_str_append (a, numstr, false); } else if (!strcmp (term, "%s/%d")) { @@ -1918,13 +2059,15 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag strcat (combined, "/"); strcat (combined, numstr); argv_append (a, combined); + argv_system_str_append (a, combined, false); } } - else if (!strcmp (term, "%s%s")) + else if (!strcmp (term, "%s%sc")) { char *s1 = va_arg (arglist, char *); char *s2 = va_arg (arglist, char *); char *combined; + char *cmd_name; if (!s1) s1 = ""; if (!s2) s2 = ""; @@ -1933,6 +2076,13 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag strcpy (combined, s1); strcat (combined, s2); argv_append (a, combined); + + cmd_name = argv_extract_cmd_name (combined); + if (cmd_name) + { + argv_system_str_append (a, cmd_name, false); + free (cmd_name); + } } else ASSERT (0); @@ -1941,6 +2091,7 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag else { argv_append (a, term); + argv_system_str_append (a, term, false); } } gc_free (&gc); @@ -1954,43 +2105,54 @@ argv_test (void) const char *s; struct argv a; + argv_init (&a); - -#ifdef WIN32 - argv_printf (&a, "%s foo bar %s", "c:\\src\\test\\jyargs.exe", "foo bar"); - //argv_printf (&a, "%s %s %s", "c:\\src\\test files\\batargs.bat", "foo", "bar"); -#else - argv_printf (&a, "./myechox foo bar"); -#endif - + argv_printf (&a, "%sc foo bar %s", "c:\\\\src\\\\test\\\\jyargs.exe", "foo bar"); argv_msg_prefix (M_INFO, &a, "ARGV"); + msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); + //openvpn_execve_check (&a, NULL, 0, "command failed"); + + argv_printf (&a, "%sc %s %s", "c:\\\\src\\\\test files\\\\batargs.bat", "foo", "bar"); + argv_msg_prefix (M_INFO, &a, "ARGV"); + msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); + //openvpn_execve_check (&a, NULL, 0, "command failed"); + + argv_printf (&a, "%s%sc foo bar %s %s/%d %d %u", "/foo", "/bar.exe", "one two", "1.2.3.4", 24, -69, 96); + argv_msg_prefix (M_INFO, &a, "ARGV"); + msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); //openvpn_execve_check (&a, NULL, 0, "command failed"); argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42); s = argv_str (&a, &gc, PA_BRACKET); - printf ("%s\n", s); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); { struct argv b = argv_insert_head (&a, "MARK"); s = argv_str (&b, &gc, PA_BRACKET); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&b)); argv_reset (&b); - printf ("%s\n", s); } argv_printf (&a, "%sc foo bar %d", "\"multi term\" command following \\\"spaces", 99); s = argv_str (&a, &gc, PA_BRACKET); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); argv_reset (&a); - printf ("%s\n", s); s = argv_str (&a, &gc, PA_BRACKET); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); argv_reset (&a); - printf ("%s\n", s); argv_printf (&a, "foo bar %d", 99); argv_printf_cat (&a, "bar %d foo %sc", 42, "nonesuch"); argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7); s = argv_str (&a, &gc, PA_BRACKET); - printf ("%s\n", s); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); + argv_reset (&a); #if 0 { @@ -2015,3 +2177,22 @@ argv_test (void) gc_free (&gc); } #endif + +const char * +openvpn_basename (const char *path) +{ + const char *ret; + const int dirsep = OS_SPECIFIC_DIRSEP; + + if (path) + { + ret = strrchr (path, dirsep); + if (ret && *ret) + ++ret; + else + ret = path; + if (*ret) + return ret; + } + return NULL; +} diff --git a/misc.h b/misc.h index a9c011a2..d96d1719 100644 --- a/misc.h +++ b/misc.h @@ -36,6 +36,14 @@ /* forward declarations */ struct plugin_list; +/* used by argv_x functions */ +struct argv { + size_t capacity; + size_t argc; + char **argv; + char *system_str; +}; + /* * Handle environmental variable lists */ @@ -126,6 +134,7 @@ const char *system_error_message (int, struct gc_arena *gc); int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags); bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); bool openvpn_execve_allowed (const unsigned int flags); +int openvpn_system (const char *command, const struct env_set *es, unsigned int flags); #ifdef HAVE_STRERROR /* a thread-safe version of strerror */ @@ -297,9 +306,16 @@ extern const char *iproute_path; #define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */ extern int script_security; /* GLOBAL */ +#define SM_EXECVE 0 /* call external programs with execve() or CreateProcess() */ +#define SM_SYSTEM 1 /* call external programs with system() */ +extern int script_method; /* GLOBAL */ + /* return the next largest power of 2 */ size_t adjust_power_of_2 (size_t u); +/* return the basename of path */ +const char *openvpn_basename (const char *path); + /* * A printf-like function (that only recognizes a subset of standard printf * format operators) that prints arguments to an argv list instead @@ -314,6 +330,7 @@ const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned struct argv argv_insert_head (const struct argv *a, const char *head); void argv_msg (const int msglev, const struct argv *a); void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); +const char *argv_system_str (const struct argv *a); #define APA_CAT (1<<0) /* concatentate onto existing struct argv list */ void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist); diff --git a/openvpn.8 b/openvpn.8 index 921f8fb6..c45f8396 100644 --- a/openvpn.8 +++ b/openvpn.8 @@ -2034,9 +2034,11 @@ is a safety precaution to prevent a LD_PRELOAD style attack from a malicious or compromised server. .\"********************************************************* .TP -.B --script-security level +.B --script-security level [method] This directive offers policy-level control over OpenVPN's usage of external programs -and scripts. Lower values are more restrictive, higher values are more permissive. Settings for +and scripts. Lower +.B level +values are more restrictive, higher values are more permissive. Settings for .B level: .B 0 -- @@ -2050,6 +2052,25 @@ Allow calling of built-in executables and user-defined scripts. .br .B 3 -- Allow passwords to be passed to scripts via environmental variables (potentially unsafe). + +The +.B method +parameter indicates how OpenVPN should call external commands and scripts. +Settings for +.B method: + +.B execve -- +(default) Use execve() function on Unix family OSes and CreateProcess() on Windows. +.br +.B system -- +Use system() function (deprecated and less safe since the external program command +line is subject to shell expansion). + +The +.B --script-security +option was introduced in OpenVPN 2.1_rc9. For configuration file compatibility +with previous OpenVPN versions, use: +.B --script-security 3 system .\"********************************************************* .TP .B --disable-occ diff --git a/options.c b/options.c index 5e579e9b..50f69821 100644 --- a/options.c +++ b/options.c @@ -193,10 +193,11 @@ static const char usage_message[] = "--setenv name value : Set a custom environmental variable to pass to script.\n" "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n" " directives for future OpenVPN versions to be ignored.\n" - "--script-security level : 0 -- strictly no calling of external programs\n" - " 1 -- (default) only call built-ins such as ifconfig\n" - " 2 -- allow calling of built-ins and scripts\n" - " 3 -- allow password to be passed to scripts via env\n" + "--script-security level mode : mode='execve' (default) or 'system', level=\n" + " 0 -- strictly no calling of external programs\n" + " 1 -- (default) only call built-ins such as ifconfig\n" + " 2 -- allow calling of built-ins and scripts\n" + " 3 -- allow password to be passed to scripts via env\n" "--shaper n : Restrict output to peer to n bytes per second.\n" "--keepalive n m : Helper option for setting timeouts in server mode. Send\n" " ping once every n seconds, restart if ping not received\n" @@ -1714,6 +1715,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr) msg (M_USAGE, "--auth-user-pass-optional %s", postfix); } + + if ((options->ssl_flags & SSLF_NO_NAME_REMAPPING) && script_method == SM_SYSTEM) + msg (M_USAGE, "--script-security method='system' cannot be combined with --no-name-remapping"); } else { @@ -2843,11 +2847,14 @@ parse_line (const char *line, if (backslash && out) { if (!(out == '\\' || out == '\"' || space (out))) + { #ifdef ENABLE_SMALL - msg (msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d", error_prefix, file, line_num); + msg (msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d", error_prefix, file, line_num); #else - msg (msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d: remember that backslashes are treated as shell-escapes and if you need to pass backslash characters as part of a Windows filename, you should use double backslashes such as \"c:\\\\" PACKAGE "\\\\static.key\"", error_prefix, file, line_num); + msg (msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d: remember that backslashes are treated as shell-escapes and if you need to pass backslash characters as part of a Windows filename, you should use double backslashes such as \"c:\\\\" PACKAGE "\\\\static.key\"", error_prefix, file, line_num); #endif + return 0; + } } backslash = false; } @@ -4402,7 +4409,21 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); script_security = atoi (p[1]); - } + if (p[2]) + { + if (streq (p[2], "execve")) + script_method = SM_EXECVE; + else if (streq (p[2], "system")) + script_method = SM_SYSTEM; + else + { + msg (msglevel, "unknown --script-security method: %s", p[2]); + goto err; + } + } + else + script_method = SM_EXECVE; + } else if (streq (p[0], "mssfix")) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/route.c b/route.c index 86bbfe6a..1efcf4e7 100644 --- a/route.c +++ b/route.c @@ -827,7 +827,7 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s #elif defined (WIN32) - argv_printf (&argv, "%s%s ADD %s MASK %s %s", + argv_printf (&argv, "%s%sc ADD %s MASK %s %s", get_win_sys_path(), WIN_ROUTE_PATH_SUFFIX, network, @@ -1007,7 +1007,7 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags #elif defined (WIN32) - argv_printf (&argv, "%s%s DELETE %s MASK %s %s", + argv_printf (&argv, "%s%sc DELETE %s MASK %s %s", get_win_sys_path(), WIN_ROUTE_PATH_SUFFIX, network, diff --git a/tun.c b/tun.c index ee32e4c5..7247d2af 100644 --- a/tun.c +++ b/tun.c @@ -106,25 +106,6 @@ dev_type_string (const char *dev, const char *dev_type) } } -const char * -dev_component_in_dev_node (const char *dev_node) -{ - const char *ret; - const int dirsep = OS_SPECIFIC_DIRSEP; - - if (dev_node) - { - ret = strrchr (dev_node, dirsep); - if (ret && *ret) - ++ret; - else - ret = dev_node; - if (*ret) - return ret; - } - return NULL; -} - /* * Try to predict the actual TUN/TAP device instance name, * before the device is actually opened. @@ -3481,7 +3462,7 @@ netsh_ifconfig_options (const char *type, /* delete existing DNS/WINS settings from TAP interface */ if (delete_first) { - argv_printf (&argv, "%s%s interface ip delete %s %s all", + argv_printf (&argv, "%s%sc interface ip delete %s %s all", get_win_sys_path(), NETSH_PATH_SUFFIX, type, @@ -3498,8 +3479,8 @@ netsh_ifconfig_options (const char *type, if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current)) { const char *fmt = count ? - "%s%s interface ip add %s %s %s" - : "%s%s interface ip set %s %s static %s"; + "%s%sc interface ip add %s %s %s" + : "%s%sc interface ip set %s %s static %s"; argv_printf (&argv, fmt, get_win_sys_path(), @@ -3575,8 +3556,7 @@ netsh_ifconfig (const struct tuntap_options *to, else { /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ - argv_printf (&argv, - "%s%s interface ip set address %s static %s %s", + argv_printf (&argv, "%s%sc interface ip set address %s static %s %s", get_win_sys_path(), NETSH_PATH_SUFFIX, flex_name, @@ -3624,7 +3604,7 @@ netsh_enable_dhcp (const struct tuntap_options *to, /* example: netsh interface ip set address my-tap dhcp */ argv_printf (&argv, - "%s%s interface ip set address %s dhcp", + "%s%sc interface ip set address %s dhcp", get_win_sys_path(), NETSH_PATH_SUFFIX, actual_name); diff --git a/tun.h b/tun.h index 85e850fc..9d702fe1 100644 --- a/tun.h +++ b/tun.h @@ -231,8 +231,6 @@ void do_ifconfig (struct tuntap *tt, int tun_mtu, const struct env_set *es); -const char *dev_component_in_dev_node (const char *dev_node); - bool is_dev_type (const char *dev, const char *dev_type, const char *match_type); int dev_type_enum (const char *dev, const char *dev_type); const char *dev_type_string (const char *dev, const char *dev_type); diff --git a/version.m4 b/version.m4 index c8bc01eb..46a96fb9 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1_rc13b]) +define(PRODUCT_VERSION,[2.1_rc13c]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) diff --git a/win32.c b/win32.c index 9272cb7e..f6ac6fe2 100644 --- a/win32.c +++ b/win32.c @@ -75,6 +75,51 @@ struct semaphore netcmd_semaphore; /* GLOBAL */ */ static char *win_sys_path = NULL; /* GLOBAL */ +/* + * Configure PATH. On Windows, sometimes PATH is not set correctly + * by default. + */ +static void +configure_win_path (void) +{ + static bool done = false; /* GLOBAL */ + if (!done) + { + FILE *fp; + fp = fopen ("c:\\windows\\system32\\route.exe", "rb"); + if (fp) + { + const int bufsiz = 4096; + struct gc_arena gc = gc_new (); + struct buffer oldpath = alloc_buf_gc (bufsiz, &gc); + struct buffer newpath = alloc_buf_gc (bufsiz, &gc); + const char* delim = ";"; + DWORD status; + fclose (fp); + status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); +#if 0 + status = 0; +#endif + if (!status) + { + *BPTR(&oldpath) = '\0'; + delim = ""; + } + buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s", + delim, + BSTR(&oldpath)); + SetEnvironmentVariable ("PATH", BSTR(&newpath)); +#if 0 + status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); + if (status > 0) + printf ("PATH: %s\n", BSTR(&oldpath)); +#endif + gc_free (&gc); + done = true; + } + } +} + void init_win32 (void) { @@ -911,41 +956,53 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i { if (openvpn_execve_allowed (flags)) { - STARTUPINFO start_info; - PROCESS_INFORMATION proc_info; - - char *env = env_block (es); - char *cl = cmd_line (a); - char *cmd = a->argv[0]; - - CLEAR (start_info); - CLEAR (proc_info); - - /* fill in STARTUPINFO struct */ - GetStartupInfo(&start_info); - start_info.cb = sizeof(start_info); - start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - start_info.wShowWindow = SW_HIDE; - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE); - - if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) + if (script_method == SM_EXECVE) { - DWORD exit_status = 0; - CloseHandle (proc_info.hThread); - WaitForSingleObject (proc_info.hProcess, INFINITE); - if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) - ret = (int)exit_status; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + + char *env = env_block (es); + char *cl = cmd_line (a); + char *cmd = a->argv[0]; + + CLEAR (start_info); + CLEAR (proc_info); + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE); + + if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) + { + DWORD exit_status = 0; + CloseHandle (proc_info.hThread); + WaitForSingleObject (proc_info.hProcess, INFINITE); + if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) + ret = (int)exit_status; + else + msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd); + CloseHandle (proc_info.hProcess); + } else - msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %s failed", cmd); - CloseHandle (proc_info.hProcess); + { + msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd); + } + free (cl); + free (env); + } + else if (script_method == SM_SYSTEM) + { + configure_win_path (); + ret = openvpn_system (argv_system_str (a), es, flags); } else { - msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %s failed", cmd); + ASSERT (0); } - free (cl); - free (env); } else {