]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
* Added additional method parameter to --script-security to preserve
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 17 Nov 2008 04:28:07 +0000 (04:28 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 17 Nov 2008 04:28:07 +0000 (04:28 +0000)
  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

14 files changed:
ChangeLog
buffer.h
common.h
errlevel.h
init.c
misc.c
misc.h
openvpn.8
options.c
route.c
tun.c
tun.h
version.m4
win32.c

index 14d4a5cc728d90635705fa2cf1790d699b21a0f6..ef5e408023c9d94fc85a35e8341b5de9b3e6242b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,7 +3,7 @@ Copyright (C) 2002-2008 OpenVPN Technologies, Inc. <sales@openvpn.net>
 
 $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.
index bfb6a1c47b235f57ff1853570af99513feaf198f..7872c3740b1a57ce0bfb4cd2410dd56e6a3efe21 100644 (file)
--- 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
index 7aa70a5d562aaff0c151e6b8f8c3265bbbe43f22..59b31b3efa334e24a5028667f6d9f996d7ace776 100644 (file)
--- 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
index b2c423a2d5befb4a6ccb016c14ebb5b36ebad939..fc05fe63476cbc0c977b65e162cdea16c19882a9 100644 (file)
 #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 519dc8bcbe10eac1520f1863c1c0f9f81c1de666..455712a772d2732d32bb7df7f4d57fe0847850de 100644 (file)
--- 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 911e911166942a51df458d84dfee953ff87be78e..5f890884ee3877cfcef1ddd26c713d07c6d61452 100644 (file)
--- 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 */
+             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 (script_method == SM_SYSTEM)
            {
-             execve (cmd, argv, envp);
-             exit (127);
+             ret = openvpn_system (argv_system_str (a), es, flags);
            }
-         else if (pid < (pid_t)0) /* fork failed */
-           ;
-         else /* parent side */
+         else
            {
-             if (waitpid (pid, &ret, 0) != pid)
-               ret = -1;
+             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);
+  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");
 
-#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 %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 a9c011a2acc06a2d9f0fbda5c7e55686d804d269..d96d1719ef3473ee09808af4297eb4dbee4977ed 100644 (file)
--- a/misc.h
+++ b/misc.h
 /* 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);
index 921f8fb674474e3db5a582c39f64180cb1c81318..c45f83962dc6fb961486bff0eb554a76870c92d2 100644 (file)
--- 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
index 5e579e9bbe9cf2295f11a3cfc76e8dc7eda73e4e..50f69821dee82ce7a2e1c4c93c8ca1ee615f9d23 100644 (file)
--- 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 86bbfe6a79f2e43e27eb72671779f42e50d6dcb1..1efcf4e7d0ac339f9a601d1092f19ff5f486cb6a 100644 (file)
--- 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 ee32e4c5402f205fc657469ca1a6dd0dc52591d5..7247d2afd2248ad89c80f6eb0ec734279561aff7 100644 (file)
--- 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 85e850fc3418c3cfd98171fe6887588ea41f6948..9d702fe1f793e604ad8555f7aeb7b8e2e270a329 100644 (file)
--- 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);
index c8bc01ebef5043a872d2d61c473f01516f655369..46a96fb979268c9035c877f52403046108c730d6 100644 (file)
@@ -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 9272cb7e17df17ef8dffefd765268844d402390b..f6ac6fe2f5796189dde71d94b3a97e0a9ff18fd2 100644 (file)
--- 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;
+         if (script_method == SM_EXECVE)
+           {
+             STARTUPINFO start_info;
+             PROCESS_INFORMATION proc_info;
 
-         char *env = env_block (es);
-         char *cl = cmd_line (a);
-         char *cmd = a->argv[0];
+             char *env = env_block (es);
+             char *cl = cmd_line (a);
+             char *cmd = a->argv[0];
 
-         CLEAR (start_info);
-         CLEAR (proc_info);
+             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);
+             /* 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;
+             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
        {