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
... | ... |
@@ -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); |