]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
2.1_rc8 and earlier did implicit shell expansion on script
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Sat, 6 Sep 2008 09:42:17 +0000 (09:42 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Sat, 6 Sep 2008 09:42:17 +0000 (09:42 +0000)
arguments since all scripts were called by system().
The security hardening changes made to 2.1_rc9 no longer
use system(), but rather use the safer execve or CreateProcess
system calls.  The security hardening also introduced a
backward incompatibility with 2.1_rc8 and earlier in that
script parameters were no longer shell-expanded, so
for example:

  client-connect "docc CLIENT-CONNECT"

would fail to work because execve would try to execute
a script called "docc CLIENT-CONNECT" instead of "docc"
with "CLIENT-CONNECT" as the first argument.

This patch fixes the issue, bringing the script argument
semantics back to pre 2.1_rc9 behavior in order to preserve
backward compatibility while still using execve or CreateProcess
to execute the script/executable.

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3311 e7ae566f-a301-0410-adde-c780ea21d3b5

buffer.c
buffer.h
errlevel.h
init.c
misc.c
misc.h
multi.c
socket.c
ssl.c

index dfaaaa107e4b32a452ed16f20baaed89236ecde0..c1ffb83113886f6b8d0bdf03ba80ced2fd8e3c70 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -234,258 +234,6 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
   return ret;
 }
 
-/*
- * A printf-like function (that only recognizes a subset of standard printf
- * format operators) that prints arguments to an argv list instead
- * of a standard string.  This is used to build up argv arrays for passing
- * to execve.
- */
-
-void
-argv_init (struct argv *a)
-{
-  a->argc = 0;
-  a->argv = NULL;
-}
-
-struct argv
-argv_new (void)
-{
-  struct argv ret;
-  argv_init (&ret);
-  return ret;
-}
-
-void
-argv_reset (struct argv *a)
-{
-  size_t i;
-  for (i = 0; i < a->argc; ++i)
-    free (a->argv[i]);
-  free (a->argv);
-  a->argc = 0;
-  a->argv = NULL;
-}
-
-size_t
-argv_argc (const char *format)
-{
-  char *term;
-  const char *f = format;
-  size_t argc = 0;
-
-  while ((term = argv_term (&f)) != NULL) 
-    {
-      ++argc;
-      free (term);
-    }
-  return argc;
-}
-
-struct argv
-argv_insert_head (const struct argv *a, const char *head)
-{
-  struct argv r;
-  size_t i;
-
-  r.argc = (a ? a->argc : 0) + 1;
-  ALLOC_ARRAY_CLEAR (r.argv, char *, r.argc + 1);
-  r.argv[0] = string_alloc (head, NULL);
-  if (a)
-    {
-      for (i = 0; i < a->argc; ++i)
-       r.argv[i+1] = string_alloc (a->argv[i], NULL);
-    }
-  return r;
-}
-
-char *
-argv_term (const char **f)
-{
-  const char *p = *f;
-  const char *term = NULL;
-  size_t termlen = 0;
-
-  if (*p == '\0')
-    return NULL;
-
-  while (true)
-    {
-      const int c = *p;
-      if (c == '\0')
-       break;
-      if (term)
-       {
-         if (!isspace (c))
-           ++termlen;
-         else
-           break;
-       }
-      else
-       {
-         if (!isspace (c))
-           {
-             term = p;
-             termlen = 1;
-           }
-       }
-      ++p;
-    }
-  *f = p;
-
-  if (term)
-    {
-      char *ret;
-      ASSERT (termlen > 0);
-      ret = malloc (termlen + 1);
-      check_malloc_return (ret);
-      memcpy (ret, term, termlen);
-      ret[termlen] = '\0';
-      return ret;
-    }
-  else
-    return NULL;
-}
-
-const char *
-argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
-{
-  if (a->argv)
-    return print_argv ((const char **)a->argv, gc, flags);
-  else
-    return "";
-}
-
-void
-argv_msg (const int msglev, const struct argv *a)
-{
-  struct gc_arena gc = gc_new ();
-  msg (msglev, "%s", argv_str (a, &gc, 0));
-  gc_free (&gc);
-}
-
-void
-argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
-{
-  struct gc_arena gc = gc_new ();
-  msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
-  gc_free (&gc);
-}
-
-void
-argv_printf (struct argv *a, const char *format, ...)
-{
-  va_list arglist;
-  va_start (arglist, format);
-  argv_printf_arglist (a, format, 0, arglist);
-  va_end (arglist);
- }
-
-void
-argv_printf_cat (struct argv *a, const char *format, ...)
-{
-  va_list arglist;
-  va_start (arglist, format);
-  argv_printf_arglist (a, format, APA_CAT, arglist);
-  va_end (arglist);
-}
-
-void
-argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
-{
-  char *term;
-  const char *f = format;
-  size_t argc = 0;
-
-  if (flags & APA_CAT)
-    {
-      char **old_argv = a->argv;
-      size_t i;
-      argc = a->argc;
-      a->argc += argv_argc (format);
-      ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1);
-      for (i = 0; i < argc; ++i)
-       a->argv[i] = old_argv[i];
-      free (old_argv);
-    }
-  else
-    {
-      argv_reset (a);
-      a->argc = argv_argc (format);
-      ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1);
-    }
-
-  while ((term = argv_term (&f)) != NULL) 
-    {
-      ASSERT (argc < a->argc);
-      if (term[0] == '%')
-       {
-         if (!strcmp (term, "%s"))
-           {
-             char *s = va_arg (arglist, char *);
-             if (!s)
-               s = "";
-             a->argv[argc++] = string_alloc (s, NULL);
-           }
-         else if (!strcmp (term, "%d"))
-           {
-             char numstr[64];
-             openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-             a->argv[argc++] = string_alloc (numstr, NULL);
-           }
-         else if (!strcmp (term, "%u"))
-           {
-             char numstr[64];
-             openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
-             a->argv[argc++] = string_alloc (numstr, NULL);
-           }
-         else if (!strcmp (term, "%s/%d"))
-           {
-             char numstr[64];
-             char *s = va_arg (arglist, char *);
-
-             if (!s)
-               s = "";
-
-             openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-
-             {
-               const size_t len = strlen(s) + strlen(numstr) + 2;
-               char *combined = (char *) malloc (len);
-               check_malloc_return (combined);
-
-               strcpy (combined, s);
-               strcat (combined, "/");
-               strcat (combined, numstr);
-               a->argv[argc++] = combined;
-             }
-           }
-         else if (!strcmp (term, "%s%s"))
-           {
-             char *s1 = va_arg (arglist, char *);
-             char *s2 = va_arg (arglist, char *);
-             char *combined;
-
-             if (!s1) s1 = "";
-             if (!s2) s2 = "";
-             combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
-             check_malloc_return (combined);
-             strcpy (combined, s1);
-             strcat (combined, s2);
-             a->argv[argc++] = combined;
-           }
-         else
-           ASSERT (0);
-         free (term);
-       }
-      else
-       {
-         a->argv[argc++] = term;
-       }
-    }
-  ASSERT (argc == a->argc);
-}
-
 /*
  * write a string to the end of a buffer that was
  * truncated by buf_printf
index 2320e4c7c3e5f1a56ce71e19c249b987caf0bc1e..e16b670503cabe1b79bd9749bd95e86d2915a188 100644 (file)
--- a/buffer.h
+++ b/buffer.h
@@ -60,6 +60,7 @@ struct buffer
 
 /* used by argv_x functions */
 struct argv {
+  size_t capacity;
   size_t argc;
   char **argv;
 };
@@ -292,37 +293,6 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
 #endif
     ;
 
-/*
- * A printf-like function (that only recognizes a subset of standard printf
- * format operators) that prints arguments to an argv list instead
- * of a standard string.  This is used to build up argv arrays for passing
- * to execve.
- */
-void argv_init (struct argv *a);
-struct argv argv_new (void);
-void argv_reset (struct argv *a);
-size_t argv_argc (const char *format);
-char *argv_term (const char **f);
-const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
-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);
-
-#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);
-
-void argv_printf (struct argv *a, const char *format, ...)
-#ifdef __GNUC__
-  __attribute__ ((format (printf, 2, 3)))
-#endif
-  ;
-
-void argv_printf_cat (struct argv *a, const char *format, ...)
-#ifdef __GNUC__
-  __attribute__ ((format (printf, 2, 3)))
-#endif
-  ;
-
 /*
  * remove/add trailing characters
  */
index 38480ef608d49f739b5ad9cd0e2d0b8d25a2ea76..95c8a30a6718a1d3789524587a9ac95985429e2b 100644 (file)
@@ -75,6 +75,7 @@
 #define D_CLOSE              LOGLEV(2, 22, 0)        /* show socket and TUN/TAP close */
 #define D_SHOW_OCC_HASH      LOGLEV(2, 23, 0)        /* show MD5 hash of option compatibility string */
 #define D_PROXY              LOGLEV(2, 24, 0)        /* show http proxy control packets */
+#define D_ARGV               LOGLEV(2, 25, 0)        /* show struct argv errors */
 
 #define D_TLS_DEBUG_LOW      LOGLEV(3, 20, 0)        /* low frequency info from tls_session routines */
 #define D_GREMLIN            LOGLEV(3, 30, 0)        /* show simulated outage info from gremlin module */
diff --git a/init.c b/init.c
index 08918d646cceaffacf5ecc5995f271a7153611d0..2aa1bd036c33c61ff7e8f2b7a5258d8fa9e15be4 100644 (file)
--- a/init.c
+++ b/init.c
@@ -923,7 +923,7 @@ do_route (const struct options *options,
     {
       struct argv argv = argv_new ();
       setenv_str (es, "script_type", "route-up");
-      argv_printf (&argv, "%s", options->route_script);
+      argv_printf (&argv, "%sc", options->route_script);
       openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
       argv_reset (&argv);
     }
diff --git a/misc.c b/misc.c
index 4cdc3de2dda9d0b8dc413e088afc30d992245456..45356a68952c525101cfc1074366bb8dc5582157 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -220,7 +220,7 @@ run_up_down (const char *command,
       ASSERT (arg);
       setenv_str (es, "script_type", script_type);
       argv_printf (&argv,
-                 "%s %s %d %d %s %s %s",
+                 "%sc %s %d %d %s %s %s",
                  command,
                  arg,
                  tun_mtu, link_mtu,
@@ -1190,24 +1190,6 @@ absolute_pathname (const char *pathname)
     return false;
 }
 
-/*
- * Return the next largest power of 2
- * or u if u is a power of 2.
- */
-unsigned int
-adjust_power_of_2 (unsigned int u)
-{
-  unsigned int ret = 1;
-
-  while (ret < u)
-    {
-      ret <<= 1;
-      ASSERT (ret > 0);
-    }
-
-  return ret;
-}
-
 #ifdef HAVE_GETPASS
 
 static FILE *
@@ -1666,56 +1648,309 @@ openvpn_sleep (const int n)
   sleep (n);
 }
 
-#if 0
 /*
- * Configure PATH.  On Windows, sometimes PATH is not set correctly
- * by default.
+ * Return the next largest power of 2
+ * or u if u is a power of 2.
  */
+size_t
+adjust_power_of_2 (size_t u)
+{
+  size_t ret = 1;
+
+  while (ret < u)
+    {
+      ret <<= 1;
+      ASSERT (ret > 0);
+    }
+
+  return ret;
+}
+
+/*
+ * A printf-like function (that only recognizes a subset of standard printf
+ * format operators) that prints arguments to an argv list instead
+ * of a standard string.  This is used to build up argv arrays for passing
+ * to execve.
+ */
+
 void
-configure_path (void)
+argv_init (struct argv *a)
 {
-#ifdef WIN32
-  FILE *fp;
-  fp = fopen ("c:\\windows\\system32\\route.exe", "rb");
-  if (fp)
+  a->capacity = 0;
+  a->argc = 0;
+  a->argv = NULL;
+}
+
+struct argv
+argv_new (void)
+{
+  struct argv ret;
+  argv_init (&ret);
+  return ret;
+}
+
+void
+argv_reset (struct argv *a)
+{
+  size_t i;
+  for (i = 0; i < a->argc; ++i)
+    free (a->argv[i]);
+  free (a->argv);
+  argv_init (a);
+}
+
+static void
+argv_extend (struct argv *a, const size_t newcap)
+{
+  if (newcap > a->capacity)
     {
-      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)
+      char **newargv;
+      size_t i;
+      ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
+      for (i = 0; i < a->argc; ++i)
+       newargv[i] = a->argv[i];
+      free (a->argv);
+      a->argv = newargv;
+      a->capacity = newcap;
+    }
+}
+
+static void
+argv_grow (struct argv *a, const size_t add)
+{
+  const size_t newargc = a->argc + add + 1;
+  ASSERT (newargc > a->argc);
+  argv_extend (a, adjust_power_of_2 (newargc));
+}
+
+static void
+argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
+{
+  argv_grow (a, 1);
+  a->argv[a->argc++] = str;
+}
+
+struct argv
+argv_clone (const struct argv *a, const size_t headroom)
+{
+  struct argv r;
+  size_t i;
+
+  argv_init (&r);
+  for (i = 0; i < headroom; ++i)
+    argv_append (&r, NULL);
+  if (a)
+    {
+      for (i = 0; i < a->argc; ++i)
+       argv_append (&r, string_alloc (a->argv[i], NULL));
+    }
+  return r;
+}
+
+struct argv
+argv_insert_head (const struct argv *a, const char *head)
+{
+  struct argv r;
+
+  r = argv_clone (a, 1);
+  r.argv[0] = string_alloc (head, NULL);
+
+  return r;
+}
+
+char *
+argv_term (const char **f)
+{
+  const char *p = *f;
+  const char *term = NULL;
+  size_t termlen = 0;
+
+  if (*p == '\0')
+    return NULL;
+
+  while (true)
+    {
+      const int c = *p;
+      if (c == '\0')
+       break;
+      if (term)
        {
-         *BPTR(&oldpath) = '\0';
-         delim = "";
+         if (!isspace (c))
+           ++termlen;
+         else
+           break;
        }
-      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);
+      else
+       {
+         if (!isspace (c))
+           {
+             term = p;
+             termlen = 1;
+           }
+       }
+      ++p;
     }
-#endif
+  *f = p;
+
+  if (term)
+    {
+      char *ret;
+      ASSERT (termlen > 0);
+      ret = malloc (termlen + 1);
+      check_malloc_return (ret);
+      memcpy (ret, term, termlen);
+      ret[termlen] = '\0';
+      return ret;
+    }
+  else
+    return NULL;
+}
+
+const char *
+argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
+{
+  if (a->argv)
+    return print_argv ((const char **)a->argv, gc, flags);
+  else
+    return "";
+}
+
+void
+argv_msg (const int msglev, const struct argv *a)
+{
+  struct gc_arena gc = gc_new ();
+  msg (msglev, "%s", argv_str (a, &gc, 0));
+  gc_free (&gc);
+}
+
+void
+argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
+{
+  struct gc_arena gc = gc_new ();
+  msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
+  gc_free (&gc);
+}
+
+void
+argv_printf (struct argv *a, const char *format, ...)
+{
+  va_list arglist;
+  va_start (arglist, format);
+  argv_printf_arglist (a, format, 0, arglist);
+  va_end (arglist);
+ }
+
+void
+argv_printf_cat (struct argv *a, const char *format, ...)
+{
+  va_list arglist;
+  va_start (arglist, format);
+  argv_printf_arglist (a, format, APA_CAT, arglist);
+  va_end (arglist);
+}
+
+void
+argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
+{
+  struct gc_arena gc = gc_new ();
+  char *term;
+  const char *f = format;
+
+  if (!(flags & APA_CAT))
+    argv_reset (a);
+  argv_extend (a, 1); /* ensure trailing NULL */
+
+  while ((term = argv_term (&f)) != NULL) 
+    {
+      if (term[0] == '%')
+       {
+         if (!strcmp (term, "%s"))
+           {
+             char *s = va_arg (arglist, char *);
+             if (!s)
+               s = "";
+             argv_append (a, string_alloc (s, NULL));
+           }
+         else if (!strcmp (term, "%sc"))
+           {
+             char *s = va_arg (arglist, char *);
+             if (s)
+               {
+                 int nparms;
+                 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));
+               }
+             else
+               argv_append (a, string_alloc ("", NULL));
+           }
+         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));
+           }
+         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));
+           }
+         else if (!strcmp (term, "%s/%d"))
+           {
+             char numstr[64];
+             char *s = va_arg (arglist, char *);
+
+             if (!s)
+               s = "";
+
+             openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
+
+             {
+               const size_t len = strlen(s) + strlen(numstr) + 2;
+               char *combined = (char *) malloc (len);
+               check_malloc_return (combined);
+
+               strcpy (combined, s);
+               strcat (combined, "/");
+               strcat (combined, numstr);
+               argv_append (a, combined);
+             }
+           }
+         else if (!strcmp (term, "%s%s"))
+           {
+             char *s1 = va_arg (arglist, char *);
+             char *s2 = va_arg (arglist, char *);
+             char *combined;
+
+             if (!s1) s1 = "";
+             if (!s2) s2 = "";
+             combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
+             check_malloc_return (combined);
+             strcpy (combined, s1);
+             strcat (combined, s2);
+             argv_append (a, combined);
+           }
+         else
+           ASSERT (0);
+         free (term);
+       }
+      else
+       {
+         argv_append (a, term);
+       }
+    }
+  gc_free (&gc);
 }
-#endif
 
 #ifdef ARGV_TEST
 void
 argv_test (void)
 {
   struct gc_arena gc = gc_new ();
-  char line[512];
   const char *s;
 
   struct argv a;
@@ -1729,7 +1964,7 @@ argv_test (void)
 #endif
 
   argv_msg_prefix (M_INFO, &a, "ARGV");
-  openvpn_execve_check (&a, NULL, 0, "command failed");
+  //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);
@@ -1742,7 +1977,7 @@ argv_test (void)
     printf ("%s\n", s);
   }
 
-  argv_printf (&a, "foo bar %d", 99);
+  argv_printf (&a, "%sc foo bar %d", "\"multi term\" command      following \\\"spaces", 99);
   s = argv_str (&a, &gc, PA_BRACKET);
   argv_reset (&a);
   printf ("%s\n", s);
@@ -1752,25 +1987,28 @@ argv_test (void)
   printf ("%s\n", s);
 
   argv_printf (&a, "foo bar %d", 99);
-  argv_printf_cat (&a, "bar %d foo", 42);
+  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);
 
 #if 0
-  while (fgets (line, sizeof(line), stdin) != NULL)
-    {
-      char *term;
-      const char *f = line;
-      int i = 0;
-
-      while ((term = argv_term (&f)) != NULL) 
-       {
-         printf ("[%d] '%s'\n", i, term);
-         ++i;
-         free (term);
-       }
-    }
+  {
+    char line[512];
+    while (fgets (line, sizeof(line), stdin) != NULL)
+      {
+       char *term;
+       const char *f = line;
+       int i = 0;
+
+       while ((term = argv_term (&f)) != NULL) 
+         {
+           printf ("[%d] '%s'\n", i, term);
+           ++i;
+           free (term);
+         }
+      }
+  }
 #endif
 
   argv_reset (&a);
diff --git a/misc.h b/misc.h
index 87cdb31ec3426723b3bfb64c09bb93cf038192e5..dd81d8281b6c2bfea099b63d0b730cdb00c50692 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -221,9 +221,6 @@ bool delete_file (const char *filename);
 /* return true if pathname is absolute */
 bool absolute_pathname (const char *pathname);
 
-/* return the next largest power of 2 */
-unsigned int adjust_power_of_2 (unsigned int u);
-
 /*
  * Get and store a username/password
  */
@@ -300,4 +297,37 @@ 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 */
 
+/* return the next largest power of 2 */
+size_t adjust_power_of_2 (size_t u);
+
+/*
+ * A printf-like function (that only recognizes a subset of standard printf
+ * format operators) that prints arguments to an argv list instead
+ * of a standard string.  This is used to build up argv arrays for passing
+ * to execve.
+ */
+void argv_init (struct argv *a);
+struct argv argv_new (void);
+void argv_reset (struct argv *a);
+char *argv_term (const char **f);
+const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
+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);
+
+#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);
+
+void argv_printf (struct argv *a, const char *format, ...)
+#ifdef __GNUC__
+  __attribute__ ((format (printf, 2, 3)))
+#endif
+  ;
+
+void argv_printf_cat (struct argv *a, const char *format, ...)
+#ifdef __GNUC__
+  __attribute__ ((format (printf, 2, 3)))
+#endif
+  ;
+
 #endif
diff --git a/multi.c b/multi.c
index 5f70b6f3d1eaa29ec68f9e78273c1a91f1bbc489..78cb5f32a6f879e3d6042f8a88b6061f14db9d9a 100644 (file)
--- a/multi.c
+++ b/multi.c
@@ -103,7 +103,7 @@ learn_address_script (const struct multi_context *m,
     {
       struct argv argv = argv_new ();
       setenv_str (es, "script_type", "learn-address");
-      argv_printf (&argv, "%s %s %s",
+      argv_printf (&argv, "%sc %s %s",
                   m->top.options.learn_address_script,
                   op,
                   mroute_addr_print (addr, &gc));
@@ -473,7 +473,7 @@ multi_client_disconnect_script (struct multi_context *m,
        {
          struct argv argv = argv_new ();
          setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
-         argv_printf (&argv, "%s", mi->context.options.client_disconnect_script);
+         argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
          openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
          argv_reset (&argv);
        }
@@ -1568,7 +1568,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
 
          delete_file (dc_file);
 
-         argv_printf (&argv, "%s %s",
+         argv_printf (&argv, "%sc %s",
                       mi->context.options.client_connect_script,
                       dc_file);
 
index 9622637603a59323108a43841ff89fbb7c53f653..4d7c18052d5ed8ec98e09dc9897760e110a5708c 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -1539,7 +1539,7 @@ ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socke
   const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
   const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
   if (include_cmd)
-    argv_printf (argv, "%s %s %s",
+    argv_printf (argv, "%sc %s %s",
                 info->ipchange_command,
                 ip,
                 port);
diff --git a/ssl.c b/ssl.c
index cd1692b05ed1b5973c74979e87672a4559f4c158..f627999a5e417238ed50910dfb88615e56e64169 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -718,7 +718,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
 
       setenv_str (opt->es, "script_type", "tls-verify");
 
-      argv_printf (&argv, "%s %d %s",
+      argv_printf (&argv, "%sc %d %s",
                   opt->verify_command,
                   ctx->error_depth,
                   subject);
@@ -2937,7 +2937,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
       setenv_untrusted (session);
 
       /* format command line */
-      argv_printf (&argv, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file);
+      argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
       
       /* call command */
       retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);