diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-09-06 09:42:17 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-09-06 09:42:17 +0000 |
commit | b8fb090c167ff500a8d702f612a42914d4f0bb03 (patch) | |
tree | 982fe657f91c834bc17d1e81f04672323a2dda1a /misc.c | |
parent | Added --allow-pull-fqdn option which allows client to pull DNS names (diff) | |
download | openvpn-b8fb090c167ff500a8d702f612a42914d4f0bb03.tar.xz |
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
Diffstat (limited to 'misc.c')
-rw-r--r-- | misc.c | 378 |
1 files changed, 308 insertions, 70 deletions
@@ -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); |