From 5a2e9a2587372aeb4b74fa1aadf53283ed7cae10 Mon Sep 17 00:00:00 2001 From: james Date: Sat, 26 Jul 2008 07:27:03 +0000 Subject: Completely revamped the system for calling external programs and scripts: * All external programs and scripts are now called by execve() on unix and CreateProcess on Windows. * The system() function is no longer used. * Argument lists for external programs and scripts are now built by the new argv_printf function which natively outputs to string arrays (i.e. char *argv[] lists), never truncates its output, and eliminates the security issues inherent in formatting and parsing command lines, and dealing with argument quoting. * The --script-security directive has been added to offer policy controls on OpenVPN's execution of external programs and scripts. Also added a new plugin example (openvpn/plugin/examples/log.c) that logs information to stdout for every plugin method called by OpenVPN. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3122 e7ae566f-a301-0410-adde-c780ea21d3b5 --- buffer.c | 132 ++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 52 deletions(-) (limited to 'buffer.c') diff --git a/buffer.c b/buffer.c index c7eab07..b62d4b8 100644 --- a/buffer.c +++ b/buffer.c @@ -240,6 +240,14 @@ argv_init (struct argv *a) a->argv = NULL; } +struct argv +argv_new (void) +{ + struct argv ret; + argv_init (&ret); + return ret; +} + void argv_reset (struct argv *a) { @@ -266,6 +274,23 @@ argv_argc (const char *format) 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) { @@ -323,6 +348,22 @@ argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags) 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, ...) { @@ -373,7 +414,10 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag { if (!strcmp (term, "%s")) { - a->argv[argc++] = string_alloc (va_arg (arglist, char *), NULL); + char *s = va_arg (arglist, char *); + if (!s) + s = ""; + a->argv[argc++] = string_alloc (s, NULL); } else if (!strcmp (term, "%d")) { @@ -387,6 +431,41 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag 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); @@ -399,57 +478,6 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag ASSERT (argc == a->argc); } -#ifdef ARGV_TEST -void -argv_test (void) -{ - struct gc_arena gc = gc_new (); - char line[512]; - const char *s; - - struct argv a; - argv_init (&a); - argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42); - s = argv_str (&a, &gc, PA_BRACKET); - argv_reset (&a); - printf ("%s\n", s); - - argv_init (&a); - argv_printf (&a, "foo bar %d", 99); - s = argv_str (&a, &gc, PA_BRACKET); - argv_reset (&a); - printf ("%s\n", s); - - argv_init (&a); - s = argv_str (&a, &gc, PA_BRACKET); - argv_reset (&a); - printf ("%s\n", s); - - argv_init (&a); - argv_printf (&a, "foo bar %d", 99); - argv_printf_cat (&a, "bar %d foo", 42); - argv_printf_cat (&a, "cool %s %d u", "frood", 4); - s = argv_str (&a, &gc, PA_BRACKET); - argv_reset (&a); - printf ("%s\n", s); - - 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); - } - } - gc_free (&gc); -} -#endif - /* * write a string to the end of a buffer that was * truncated by buf_printf -- cgit