Browse code

2.1_rc8 and earlier did implicit shell expansion on script 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

james authored on 2008/09/06 18:42:17
Showing 9 changed files
... ...
@@ -235,258 +235,6 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
235 235
 }
236 236
 
237 237
 /*
238
- * A printf-like function (that only recognizes a subset of standard printf
239
- * format operators) that prints arguments to an argv list instead
240
- * of a standard string.  This is used to build up argv arrays for passing
241
- * to execve.
242
- */
243
-
244
-void
245
-argv_init (struct argv *a)
246
-{
247
-  a->argc = 0;
248
-  a->argv = NULL;
249
-}
250
-
251
-struct argv
252
-argv_new (void)
253
-{
254
-  struct argv ret;
255
-  argv_init (&ret);
256
-  return ret;
257
-}
258
-
259
-void
260
-argv_reset (struct argv *a)
261
-{
262
-  size_t i;
263
-  for (i = 0; i < a->argc; ++i)
264
-    free (a->argv[i]);
265
-  free (a->argv);
266
-  a->argc = 0;
267
-  a->argv = NULL;
268
-}
269
-
270
-size_t
271
-argv_argc (const char *format)
272
-{
273
-  char *term;
274
-  const char *f = format;
275
-  size_t argc = 0;
276
-
277
-  while ((term = argv_term (&f)) != NULL) 
278
-    {
279
-      ++argc;
280
-      free (term);
281
-    }
282
-  return argc;
283
-}
284
-
285
-struct argv
286
-argv_insert_head (const struct argv *a, const char *head)
287
-{
288
-  struct argv r;
289
-  size_t i;
290
-
291
-  r.argc = (a ? a->argc : 0) + 1;
292
-  ALLOC_ARRAY_CLEAR (r.argv, char *, r.argc + 1);
293
-  r.argv[0] = string_alloc (head, NULL);
294
-  if (a)
295
-    {
296
-      for (i = 0; i < a->argc; ++i)
297
-	r.argv[i+1] = string_alloc (a->argv[i], NULL);
298
-    }
299
-  return r;
300
-}
301
-
302
-char *
303
-argv_term (const char **f)
304
-{
305
-  const char *p = *f;
306
-  const char *term = NULL;
307
-  size_t termlen = 0;
308
-
309
-  if (*p == '\0')
310
-    return NULL;
311
-
312
-  while (true)
313
-    {
314
-      const int c = *p;
315
-      if (c == '\0')
316
-	break;
317
-      if (term)
318
-	{
319
-	  if (!isspace (c))
320
-	    ++termlen;
321
-	  else
322
-	    break;
323
-	}
324
-      else
325
-	{
326
-	  if (!isspace (c))
327
-	    {
328
-	      term = p;
329
-	      termlen = 1;
330
-	    }
331
-	}
332
-      ++p;
333
-    }
334
-  *f = p;
335
-
336
-  if (term)
337
-    {
338
-      char *ret;
339
-      ASSERT (termlen > 0);
340
-      ret = malloc (termlen + 1);
341
-      check_malloc_return (ret);
342
-      memcpy (ret, term, termlen);
343
-      ret[termlen] = '\0';
344
-      return ret;
345
-    }
346
-  else
347
-    return NULL;
348
-}
349
-
350
-const char *
351
-argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
352
-{
353
-  if (a->argv)
354
-    return print_argv ((const char **)a->argv, gc, flags);
355
-  else
356
-    return "";
357
-}
358
-
359
-void
360
-argv_msg (const int msglev, const struct argv *a)
361
-{
362
-  struct gc_arena gc = gc_new ();
363
-  msg (msglev, "%s", argv_str (a, &gc, 0));
364
-  gc_free (&gc);
365
-}
366
-
367
-void
368
-argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
369
-{
370
-  struct gc_arena gc = gc_new ();
371
-  msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
372
-  gc_free (&gc);
373
-}
374
-
375
-void
376
-argv_printf (struct argv *a, const char *format, ...)
377
-{
378
-  va_list arglist;
379
-  va_start (arglist, format);
380
-  argv_printf_arglist (a, format, 0, arglist);
381
-  va_end (arglist);
382
- }
383
-
384
-void
385
-argv_printf_cat (struct argv *a, const char *format, ...)
386
-{
387
-  va_list arglist;
388
-  va_start (arglist, format);
389
-  argv_printf_arglist (a, format, APA_CAT, arglist);
390
-  va_end (arglist);
391
-}
392
-
393
-void
394
-argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
395
-{
396
-  char *term;
397
-  const char *f = format;
398
-  size_t argc = 0;
399
-
400
-  if (flags & APA_CAT)
401
-    {
402
-      char **old_argv = a->argv;
403
-      size_t i;
404
-      argc = a->argc;
405
-      a->argc += argv_argc (format);
406
-      ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1);
407
-      for (i = 0; i < argc; ++i)
408
-	a->argv[i] = old_argv[i];
409
-      free (old_argv);
410
-    }
411
-  else
412
-    {
413
-      argv_reset (a);
414
-      a->argc = argv_argc (format);
415
-      ALLOC_ARRAY_CLEAR (a->argv, char *, a->argc + 1);
416
-    }
417
-
418
-  while ((term = argv_term (&f)) != NULL) 
419
-    {
420
-      ASSERT (argc < a->argc);
421
-      if (term[0] == '%')
422
-	{
423
-	  if (!strcmp (term, "%s"))
424
-	    {
425
-	      char *s = va_arg (arglist, char *);
426
-	      if (!s)
427
-		s = "";
428
-	      a->argv[argc++] = string_alloc (s, NULL);
429
-	    }
430
-	  else if (!strcmp (term, "%d"))
431
-	    {
432
-	      char numstr[64];
433
-	      openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
434
-	      a->argv[argc++] = string_alloc (numstr, NULL);
435
-	    }
436
-	  else if (!strcmp (term, "%u"))
437
-	    {
438
-	      char numstr[64];
439
-	      openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
440
-	      a->argv[argc++] = string_alloc (numstr, NULL);
441
-	    }
442
-	  else if (!strcmp (term, "%s/%d"))
443
-	    {
444
-	      char numstr[64];
445
-	      char *s = va_arg (arglist, char *);
446
-
447
-	      if (!s)
448
-		s = "";
449
-
450
-	      openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
451
-
452
-	      {
453
-		const size_t len = strlen(s) + strlen(numstr) + 2;
454
-		char *combined = (char *) malloc (len);
455
-		check_malloc_return (combined);
456
-
457
-		strcpy (combined, s);
458
-		strcat (combined, "/");
459
-		strcat (combined, numstr);
460
-		a->argv[argc++] = combined;
461
-	      }
462
-	    }
463
-	  else if (!strcmp (term, "%s%s"))
464
-	    {
465
-	      char *s1 = va_arg (arglist, char *);
466
-	      char *s2 = va_arg (arglist, char *);
467
-	      char *combined;
468
-
469
-	      if (!s1) s1 = "";
470
-	      if (!s2) s2 = "";
471
-	      combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
472
-	      check_malloc_return (combined);
473
-	      strcpy (combined, s1);
474
-	      strcat (combined, s2);
475
-	      a->argv[argc++] = combined;
476
-	    }
477
-	  else
478
-	    ASSERT (0);
479
-	  free (term);
480
-	}
481
-      else
482
-	{
483
-	  a->argv[argc++] = term;
484
-	}
485
-    }
486
-  ASSERT (argc == a->argc);
487
-}
488
-
489
-/*
490 238
  * write a string to the end of a buffer that was
491 239
  * truncated by buf_printf
492 240
  */
... ...
@@ -60,6 +60,7 @@ struct buffer
60 60
 
61 61
 /* used by argv_x functions */
62 62
 struct argv {
63
+  size_t capacity;
63 64
   size_t argc;
64 65
   char **argv;
65 66
 };
... ...
@@ -293,37 +294,6 @@ int openvpn_snprintf(char *str, size_t size, const char *format, ...)
293 293
     ;
294 294
 
295 295
 /*
296
- * A printf-like function (that only recognizes a subset of standard printf
297
- * format operators) that prints arguments to an argv list instead
298
- * of a standard string.  This is used to build up argv arrays for passing
299
- * to execve.
300
- */
301
-void argv_init (struct argv *a);
302
-struct argv argv_new (void);
303
-void argv_reset (struct argv *a);
304
-size_t argv_argc (const char *format);
305
-char *argv_term (const char **f);
306
-const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
307
-struct argv argv_insert_head (const struct argv *a, const char *head);
308
-void argv_msg (const int msglev, const struct argv *a);
309
-void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
310
-
311
-#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
312
-void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
313
-
314
-void argv_printf (struct argv *a, const char *format, ...)
315
-#ifdef __GNUC__
316
-  __attribute__ ((format (printf, 2, 3)))
317
-#endif
318
-  ;
319
-
320
-void argv_printf_cat (struct argv *a, const char *format, ...)
321
-#ifdef __GNUC__
322
-  __attribute__ ((format (printf, 2, 3)))
323
-#endif
324
-  ;
325
-
326
-/*
327 296
  * remove/add trailing characters
328 297
  */
329 298
 
... ...
@@ -75,6 +75,7 @@
75 75
 #define D_CLOSE              LOGLEV(2, 22, 0)        /* show socket and TUN/TAP close */
76 76
 #define D_SHOW_OCC_HASH      LOGLEV(2, 23, 0)        /* show MD5 hash of option compatibility string */
77 77
 #define D_PROXY              LOGLEV(2, 24, 0)        /* show http proxy control packets */
78
+#define D_ARGV               LOGLEV(2, 25, 0)        /* show struct argv errors */
78 79
 
79 80
 #define D_TLS_DEBUG_LOW      LOGLEV(3, 20, 0)        /* low frequency info from tls_session routines */
80 81
 #define D_GREMLIN            LOGLEV(3, 30, 0)        /* show simulated outage info from gremlin module */
... ...
@@ -923,7 +923,7 @@ do_route (const struct options *options,
923 923
     {
924 924
       struct argv argv = argv_new ();
925 925
       setenv_str (es, "script_type", "route-up");
926
-      argv_printf (&argv, "%s", options->route_script);
926
+      argv_printf (&argv, "%sc", options->route_script);
927 927
       openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
928 928
       argv_reset (&argv);
929 929
     }
... ...
@@ -220,7 +220,7 @@ run_up_down (const char *command,
220 220
       ASSERT (arg);
221 221
       setenv_str (es, "script_type", script_type);
222 222
       argv_printf (&argv,
223
-		  "%s %s %d %d %s %s %s",
223
+		  "%sc %s %d %d %s %s %s",
224 224
 		  command,
225 225
 		  arg,
226 226
 		  tun_mtu, link_mtu,
... ...
@@ -1190,24 +1190,6 @@ absolute_pathname (const char *pathname)
1190 1190
     return false;
1191 1191
 }
1192 1192
 
1193
-/*
1194
- * Return the next largest power of 2
1195
- * or u if u is a power of 2.
1196
- */
1197
-unsigned int
1198
-adjust_power_of_2 (unsigned int u)
1199
-{
1200
-  unsigned int ret = 1;
1201
-
1202
-  while (ret < u)
1203
-    {
1204
-      ret <<= 1;
1205
-      ASSERT (ret > 0);
1206
-    }
1207
-
1208
-  return ret;
1209
-}
1210
-
1211 1193
 #ifdef HAVE_GETPASS
1212 1194
 
1213 1195
 static FILE *
... ...
@@ -1666,56 +1648,309 @@ openvpn_sleep (const int n)
1666 1666
   sleep (n);
1667 1667
 }
1668 1668
 
1669
-#if 0
1670 1669
 /*
1671
- * Configure PATH.  On Windows, sometimes PATH is not set correctly
1672
- * by default.
1670
+ * Return the next largest power of 2
1671
+ * or u if u is a power of 2.
1673 1672
  */
1673
+size_t
1674
+adjust_power_of_2 (size_t u)
1675
+{
1676
+  size_t ret = 1;
1677
+
1678
+  while (ret < u)
1679
+    {
1680
+      ret <<= 1;
1681
+      ASSERT (ret > 0);
1682
+    }
1683
+
1684
+  return ret;
1685
+}
1686
+
1687
+/*
1688
+ * A printf-like function (that only recognizes a subset of standard printf
1689
+ * format operators) that prints arguments to an argv list instead
1690
+ * of a standard string.  This is used to build up argv arrays for passing
1691
+ * to execve.
1692
+ */
1693
+
1674 1694
 void
1675
-configure_path (void)
1695
+argv_init (struct argv *a)
1676 1696
 {
1677
-#ifdef WIN32
1678
-  FILE *fp;
1679
-  fp = fopen ("c:\\windows\\system32\\route.exe", "rb");
1680
-  if (fp)
1697
+  a->capacity = 0;
1698
+  a->argc = 0;
1699
+  a->argv = NULL;
1700
+}
1701
+
1702
+struct argv
1703
+argv_new (void)
1704
+{
1705
+  struct argv ret;
1706
+  argv_init (&ret);
1707
+  return ret;
1708
+}
1709
+
1710
+void
1711
+argv_reset (struct argv *a)
1712
+{
1713
+  size_t i;
1714
+  for (i = 0; i < a->argc; ++i)
1715
+    free (a->argv[i]);
1716
+  free (a->argv);
1717
+  argv_init (a);
1718
+}
1719
+
1720
+static void
1721
+argv_extend (struct argv *a, const size_t newcap)
1722
+{
1723
+  if (newcap > a->capacity)
1681 1724
     {
1682
-      const int bufsiz = 4096;
1683
-      struct gc_arena gc = gc_new ();
1684
-      struct buffer oldpath = alloc_buf_gc (bufsiz, &gc);
1685
-      struct buffer newpath = alloc_buf_gc (bufsiz, &gc);
1686
-      const char* delim = ";";
1687
-      DWORD status;
1688
-      fclose (fp);
1689
-      status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
1690
-#if 0
1691
-      status = 0;
1692
-#endif
1693
-      if (!status)
1725
+      char **newargv;
1726
+      size_t i;
1727
+      ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
1728
+      for (i = 0; i < a->argc; ++i)
1729
+	newargv[i] = a->argv[i];
1730
+      free (a->argv);
1731
+      a->argv = newargv;
1732
+      a->capacity = newcap;
1733
+    }
1734
+}
1735
+
1736
+static void
1737
+argv_grow (struct argv *a, const size_t add)
1738
+{
1739
+  const size_t newargc = a->argc + add + 1;
1740
+  ASSERT (newargc > a->argc);
1741
+  argv_extend (a, adjust_power_of_2 (newargc));
1742
+}
1743
+
1744
+static void
1745
+argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
1746
+{
1747
+  argv_grow (a, 1);
1748
+  a->argv[a->argc++] = str;
1749
+}
1750
+
1751
+struct argv
1752
+argv_clone (const struct argv *a, const size_t headroom)
1753
+{
1754
+  struct argv r;
1755
+  size_t i;
1756
+
1757
+  argv_init (&r);
1758
+  for (i = 0; i < headroom; ++i)
1759
+    argv_append (&r, NULL);
1760
+  if (a)
1761
+    {
1762
+      for (i = 0; i < a->argc; ++i)
1763
+	argv_append (&r, string_alloc (a->argv[i], NULL));
1764
+    }
1765
+  return r;
1766
+}
1767
+
1768
+struct argv
1769
+argv_insert_head (const struct argv *a, const char *head)
1770
+{
1771
+  struct argv r;
1772
+
1773
+  r = argv_clone (a, 1);
1774
+  r.argv[0] = string_alloc (head, NULL);
1775
+
1776
+  return r;
1777
+}
1778
+
1779
+char *
1780
+argv_term (const char **f)
1781
+{
1782
+  const char *p = *f;
1783
+  const char *term = NULL;
1784
+  size_t termlen = 0;
1785
+
1786
+  if (*p == '\0')
1787
+    return NULL;
1788
+
1789
+  while (true)
1790
+    {
1791
+      const int c = *p;
1792
+      if (c == '\0')
1793
+	break;
1794
+      if (term)
1694 1795
 	{
1695
-	  *BPTR(&oldpath) = '\0';
1696
-	  delim = "";
1796
+	  if (!isspace (c))
1797
+	    ++termlen;
1798
+	  else
1799
+	    break;
1697 1800
 	}
1698
-      buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s",
1699
-		  delim,
1700
-		  BSTR(&oldpath));
1701
-      SetEnvironmentVariable ("PATH", BSTR(&newpath));
1702
-#if 0
1703
-      status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath));
1704
-      if (status > 0)
1705
-	printf ("PATH: %s\n", BSTR(&oldpath));
1706
-#endif
1707
-      gc_free (&gc);
1801
+      else
1802
+	{
1803
+	  if (!isspace (c))
1804
+	    {
1805
+	      term = p;
1806
+	      termlen = 1;
1807
+	    }
1808
+	}
1809
+      ++p;
1708 1810
     }
1709
-#endif
1811
+  *f = p;
1812
+
1813
+  if (term)
1814
+    {
1815
+      char *ret;
1816
+      ASSERT (termlen > 0);
1817
+      ret = malloc (termlen + 1);
1818
+      check_malloc_return (ret);
1819
+      memcpy (ret, term, termlen);
1820
+      ret[termlen] = '\0';
1821
+      return ret;
1822
+    }
1823
+  else
1824
+    return NULL;
1825
+}
1826
+
1827
+const char *
1828
+argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
1829
+{
1830
+  if (a->argv)
1831
+    return print_argv ((const char **)a->argv, gc, flags);
1832
+  else
1833
+    return "";
1834
+}
1835
+
1836
+void
1837
+argv_msg (const int msglev, const struct argv *a)
1838
+{
1839
+  struct gc_arena gc = gc_new ();
1840
+  msg (msglev, "%s", argv_str (a, &gc, 0));
1841
+  gc_free (&gc);
1842
+}
1843
+
1844
+void
1845
+argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
1846
+{
1847
+  struct gc_arena gc = gc_new ();
1848
+  msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
1849
+  gc_free (&gc);
1850
+}
1851
+
1852
+void
1853
+argv_printf (struct argv *a, const char *format, ...)
1854
+{
1855
+  va_list arglist;
1856
+  va_start (arglist, format);
1857
+  argv_printf_arglist (a, format, 0, arglist);
1858
+  va_end (arglist);
1859
+ }
1860
+
1861
+void
1862
+argv_printf_cat (struct argv *a, const char *format, ...)
1863
+{
1864
+  va_list arglist;
1865
+  va_start (arglist, format);
1866
+  argv_printf_arglist (a, format, APA_CAT, arglist);
1867
+  va_end (arglist);
1868
+}
1869
+
1870
+void
1871
+argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
1872
+{
1873
+  struct gc_arena gc = gc_new ();
1874
+  char *term;
1875
+  const char *f = format;
1876
+
1877
+  if (!(flags & APA_CAT))
1878
+    argv_reset (a);
1879
+  argv_extend (a, 1); /* ensure trailing NULL */
1880
+
1881
+  while ((term = argv_term (&f)) != NULL) 
1882
+    {
1883
+      if (term[0] == '%')
1884
+	{
1885
+	  if (!strcmp (term, "%s"))
1886
+	    {
1887
+	      char *s = va_arg (arglist, char *);
1888
+	      if (!s)
1889
+		s = "";
1890
+	      argv_append (a, string_alloc (s, NULL));
1891
+	    }
1892
+	  else if (!strcmp (term, "%sc"))
1893
+	    {
1894
+	      char *s = va_arg (arglist, char *);
1895
+	      if (s)
1896
+		{
1897
+		  int nparms;
1898
+		  char *parms[MAX_PARMS+1];
1899
+		  int i;
1900
+
1901
+		  nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, M_FATAL, &gc);
1902
+		  for (i = 0; i < nparms; ++i)
1903
+		    argv_append (a, string_alloc (parms[i], NULL));
1904
+		}
1905
+	      else
1906
+		argv_append (a, string_alloc ("", NULL));
1907
+	    }
1908
+	  else if (!strcmp (term, "%d"))
1909
+	    {
1910
+	      char numstr[64];
1911
+	      openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
1912
+	      argv_append (a, string_alloc (numstr, NULL));
1913
+	    }
1914
+	  else if (!strcmp (term, "%u"))
1915
+	    {
1916
+	      char numstr[64];
1917
+	      openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
1918
+	      argv_append (a, string_alloc (numstr, NULL));
1919
+	    }
1920
+	  else if (!strcmp (term, "%s/%d"))
1921
+	    {
1922
+	      char numstr[64];
1923
+	      char *s = va_arg (arglist, char *);
1924
+
1925
+	      if (!s)
1926
+		s = "";
1927
+
1928
+	      openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
1929
+
1930
+	      {
1931
+		const size_t len = strlen(s) + strlen(numstr) + 2;
1932
+		char *combined = (char *) malloc (len);
1933
+		check_malloc_return (combined);
1934
+
1935
+		strcpy (combined, s);
1936
+		strcat (combined, "/");
1937
+		strcat (combined, numstr);
1938
+		argv_append (a, combined);
1939
+	      }
1940
+	    }
1941
+	  else if (!strcmp (term, "%s%s"))
1942
+	    {
1943
+	      char *s1 = va_arg (arglist, char *);
1944
+	      char *s2 = va_arg (arglist, char *);
1945
+	      char *combined;
1946
+
1947
+	      if (!s1) s1 = "";
1948
+	      if (!s2) s2 = "";
1949
+	      combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
1950
+	      check_malloc_return (combined);
1951
+	      strcpy (combined, s1);
1952
+	      strcat (combined, s2);
1953
+	      argv_append (a, combined);
1954
+	    }
1955
+	  else
1956
+	    ASSERT (0);
1957
+	  free (term);
1958
+	}
1959
+      else
1960
+	{
1961
+	  argv_append (a, term);
1962
+	}
1963
+    }
1964
+  gc_free (&gc);
1710 1965
 }
1711
-#endif
1712 1966
 
1713 1967
 #ifdef ARGV_TEST
1714 1968
 void
1715 1969
 argv_test (void)
1716 1970
 {
1717 1971
   struct gc_arena gc = gc_new ();
1718
-  char line[512];
1719 1972
   const char *s;
1720 1973
 
1721 1974
   struct argv a;
... ...
@@ -1729,7 +1964,7 @@ argv_test (void)
1729 1729
 #endif
1730 1730
 
1731 1731
   argv_msg_prefix (M_INFO, &a, "ARGV");
1732
-  openvpn_execve_check (&a, NULL, 0, "command failed");
1732
+  //openvpn_execve_check (&a, NULL, 0, "command failed");
1733 1733
 
1734 1734
   argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
1735 1735
   s = argv_str (&a, &gc, PA_BRACKET);
... ...
@@ -1742,7 +1977,7 @@ argv_test (void)
1742 1742
     printf ("%s\n", s);
1743 1743
   }
1744 1744
 
1745
-  argv_printf (&a, "foo bar %d", 99);
1745
+  argv_printf (&a, "%sc foo bar %d", "\"multi term\" command      following \\\"spaces", 99);
1746 1746
   s = argv_str (&a, &gc, PA_BRACKET);
1747 1747
   argv_reset (&a);
1748 1748
   printf ("%s\n", s);
... ...
@@ -1752,25 +1987,28 @@ argv_test (void)
1752 1752
   printf ("%s\n", s);
1753 1753
 
1754 1754
   argv_printf (&a, "foo bar %d", 99);
1755
-  argv_printf_cat (&a, "bar %d foo", 42);
1755
+  argv_printf_cat (&a, "bar %d foo %sc", 42, "nonesuch");
1756 1756
   argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7);
1757 1757
   s = argv_str (&a, &gc, PA_BRACKET);
1758 1758
   printf ("%s\n", s);
1759 1759
 
1760 1760
 #if 0
1761
-  while (fgets (line, sizeof(line), stdin) != NULL)
1762
-    {
1763
-      char *term;
1764
-      const char *f = line;
1765
-      int i = 0;
1766
-
1767
-      while ((term = argv_term (&f)) != NULL) 
1768
-	{
1769
-	  printf ("[%d] '%s'\n", i, term);
1770
-	  ++i;
1771
-	  free (term);
1772
-	}
1773
-    }
1761
+  {
1762
+    char line[512];
1763
+    while (fgets (line, sizeof(line), stdin) != NULL)
1764
+      {
1765
+	char *term;
1766
+	const char *f = line;
1767
+	int i = 0;
1768
+
1769
+	while ((term = argv_term (&f)) != NULL) 
1770
+	  {
1771
+	    printf ("[%d] '%s'\n", i, term);
1772
+	    ++i;
1773
+	    free (term);
1774
+	  }
1775
+      }
1776
+  }
1774 1777
 #endif
1775 1778
 
1776 1779
   argv_reset (&a);
... ...
@@ -221,9 +221,6 @@ bool delete_file (const char *filename);
221 221
 /* return true if pathname is absolute */
222 222
 bool absolute_pathname (const char *pathname);
223 223
 
224
-/* return the next largest power of 2 */
225
-unsigned int adjust_power_of_2 (unsigned int u);
226
-
227 224
 /*
228 225
  * Get and store a username/password
229 226
  */
... ...
@@ -300,4 +297,37 @@ extern const char *iproute_path;
300 300
 #define SSEC_PW_ENV    3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */
301 301
 extern int script_security; /* GLOBAL */
302 302
 
303
+/* return the next largest power of 2 */
304
+size_t adjust_power_of_2 (size_t u);
305
+
306
+/*
307
+ * A printf-like function (that only recognizes a subset of standard printf
308
+ * format operators) that prints arguments to an argv list instead
309
+ * of a standard string.  This is used to build up argv arrays for passing
310
+ * to execve.
311
+ */
312
+void argv_init (struct argv *a);
313
+struct argv argv_new (void);
314
+void argv_reset (struct argv *a);
315
+char *argv_term (const char **f);
316
+const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
317
+struct argv argv_insert_head (const struct argv *a, const char *head);
318
+void argv_msg (const int msglev, const struct argv *a);
319
+void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
320
+
321
+#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
322
+void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
323
+
324
+void argv_printf (struct argv *a, const char *format, ...)
325
+#ifdef __GNUC__
326
+  __attribute__ ((format (printf, 2, 3)))
327
+#endif
328
+  ;
329
+
330
+void argv_printf_cat (struct argv *a, const char *format, ...)
331
+#ifdef __GNUC__
332
+  __attribute__ ((format (printf, 2, 3)))
333
+#endif
334
+  ;
335
+
303 336
 #endif
... ...
@@ -103,7 +103,7 @@ learn_address_script (const struct multi_context *m,
103 103
     {
104 104
       struct argv argv = argv_new ();
105 105
       setenv_str (es, "script_type", "learn-address");
106
-      argv_printf (&argv, "%s %s %s",
106
+      argv_printf (&argv, "%sc %s %s",
107 107
 		   m->top.options.learn_address_script,
108 108
 		   op,
109 109
 		   mroute_addr_print (addr, &gc));
... ...
@@ -473,7 +473,7 @@ multi_client_disconnect_script (struct multi_context *m,
473 473
 	{
474 474
 	  struct argv argv = argv_new ();
475 475
 	  setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
476
-	  argv_printf (&argv, "%s", mi->context.options.client_disconnect_script);
476
+	  argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
477 477
 	  openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
478 478
 	  argv_reset (&argv);
479 479
 	}
... ...
@@ -1568,7 +1568,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
1568 1568
 
1569 1569
 	  delete_file (dc_file);
1570 1570
 
1571
-	  argv_printf (&argv, "%s %s",
1571
+	  argv_printf (&argv, "%sc %s",
1572 1572
 		       mi->context.options.client_connect_script,
1573 1573
 		       dc_file);
1574 1574
 
... ...
@@ -1539,7 +1539,7 @@ ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socke
1539 1539
   const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
1540 1540
   const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
1541 1541
   if (include_cmd)
1542
-    argv_printf (argv, "%s %s %s",
1542
+    argv_printf (argv, "%sc %s %s",
1543 1543
 		 info->ipchange_command,
1544 1544
 		 ip,
1545 1545
 		 port);
... ...
@@ -718,7 +718,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
718 718
 
719 719
       setenv_str (opt->es, "script_type", "tls-verify");
720 720
 
721
-      argv_printf (&argv, "%s %d %s",
721
+      argv_printf (&argv, "%sc %d %s",
722 722
 		   opt->verify_command,
723 723
 		   ctx->error_depth,
724 724
 		   subject);
... ...
@@ -2937,7 +2937,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
2937 2937
       setenv_untrusted (session);
2938 2938
 
2939 2939
       /* format command line */
2940
-      argv_printf (&argv, "%s %s", session->opt->auth_user_pass_verify_script, tmp_file);
2940
+      argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
2941 2941
       
2942 2942
       /* call command */
2943 2943
       retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);