diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-11-17 04:28:07 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-11-17 04:28:07 +0000 |
commit | a82813527551f0e79c6d6ed5a9c1162e3c171bcf (patch) | |
tree | 65e82c2976c568a6f4099b8518c490c4d603e4cb /misc.c | |
parent | Interim release. (diff) | |
download | openvpn-a82813527551f0e79c6d6ed5a9c1162e3c171bcf.tar.xz |
* Added additional method parameter to --script-security to preserve
backward compatibility with system() call semantics used in OpenVPN
2.1_rc8 and earlier. To preserve backward compatibility use:
script-security 3 system
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3495 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to 'misc.c')
-rw-r--r-- | misc.c | 241 |
1 files changed, 211 insertions, 30 deletions
@@ -46,6 +46,9 @@ const char *iproute_path = IPROUTE_PATH; /* GLOBAL */ /* contains an SSEC_x value defined in misc.h */ int script_security = SSEC_BUILT_IN; /* GLOBAL */ +/* contains SM_x value defined in misc.h */ +int script_method = SM_EXECVE; /* GLOBAL */ + /* Redefine the top level directory of the filesystem to restrict access to files for security */ void @@ -507,23 +510,34 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i #if defined(ENABLE_EXECVE) if (openvpn_execve_allowed (flags)) { - const char *cmd = a->argv[0]; - char *const *argv = a->argv; - char *const *envp = (char *const *)make_env_array (es, true, &gc); - pid_t pid; + if (script_method == SM_EXECVE) + { + const char *cmd = a->argv[0]; + char *const *argv = a->argv; + char *const *envp = (char *const *)make_env_array (es, true, &gc); + pid_t pid; - pid = fork (); - if (pid == (pid_t)0) /* child side */ + pid = fork (); + if (pid == (pid_t)0) /* child side */ + { + execve (cmd, argv, envp); + exit (127); + } + else if (pid < (pid_t)0) /* fork failed */ + ; + else /* parent side */ + { + if (waitpid (pid, &ret, 0) != pid) + ret = -1; + } + } + else if (script_method == SM_SYSTEM) { - execve (cmd, argv, envp); - exit (127); + ret = openvpn_system (argv_system_str (a), es, flags); } - else if (pid < (pid_t)0) /* fork failed */ - ; - else /* parent side */ + else { - if (waitpid (pid, &ret, 0) != pid) - ret = -1; + ASSERT (0); } } else @@ -545,6 +559,52 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i #endif /* + * Wrapper around the system() call. + */ +int +openvpn_system (const char *command, const struct env_set *es, unsigned int flags) +{ +#ifdef HAVE_SYSTEM + int ret; + + perf_push (PERF_SCRIPT); + + /* + * add env_set to environment. + */ + if (flags & S_SCRIPT) + env_set_add_to_environment (es); + + + /* debugging */ + dmsg (D_SCRIPT, "SYSTEM[%u] '%s'", flags, command); + if (flags & S_SCRIPT) + env_set_print (D_SCRIPT, es); + + /* + * execute the command + */ + ret = system (command); + + /* debugging */ + dmsg (D_SCRIPT, "SYSTEM return=%u", ret); + + /* + * remove env_set from environment + */ + if (flags & S_SCRIPT) + env_set_remove_from_environment (es); + + perf_pop (); + return ret; + +#else + msg (M_FATAL, "Sorry but I can't execute the shell command '%s' because this operating system doesn't appear to support the system() call", command); + return -1; /* NOTREACHED */ +#endif +} + +/* * Initialize random number seed. random() is only used * when "weak" random numbers are acceptable. * OpenSSL routines are always used when cryptographically @@ -1679,6 +1739,7 @@ argv_init (struct argv *a) a->capacity = 0; a->argc = 0; a->argv = NULL; + a->system_str = NULL; } struct argv @@ -1696,6 +1757,7 @@ argv_reset (struct argv *a) for (i = 0; i < a->argc; ++i) free (a->argv[i]); free (a->argv); + free (a->system_str); argv_init (a); } @@ -1730,6 +1792,64 @@ argv_append (struct argv *a, char *str) /* str must have been malloced or be NUL a->argv[a->argc++] = str; } +static void +argv_system_str_append (struct argv *a, const char *str, const bool enquote) +{ + if (str) + { + char *newstr; + + /* compute length of new system_str */ + size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */ + if (a->system_str) + l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */ + if (enquote) + l += 2; /* space for two quotes */ + + /* build new system_str */ + newstr = (char *) malloc (l); + newstr[0] = '\0'; + check_malloc_return (newstr); + if (a->system_str) + { + strcpy (newstr, a->system_str); + strcat (newstr, " "); + } + if (enquote) + strcat (newstr, "\""); + strcat (newstr, str); + if (enquote) + strcat (newstr, "\""); + free (a->system_str); + a->system_str = newstr; + } +} + +static char * +argv_extract_cmd_name (const char *path) +{ + if (path) + { + const char *bn = openvpn_basename (path); + if (bn) + { + char *ret = string_alloc (bn, NULL); + char *dot = strrchr (ret, '.'); + if (dot) + *dot = '\0'; + if (ret[0] != '\0') + return ret; + } + } + return NULL; +} + +const char * +argv_system_str (const struct argv *a) +{ + return a->system_str; +} + struct argv argv_clone (const struct argv *a, const size_t headroom) { @@ -1744,6 +1864,7 @@ argv_clone (const struct argv *a, const size_t headroom) for (i = 0; i < a->argc; ++i) argv_append (&r, string_alloc (a->argv[i], NULL)); } + r.system_str = string_alloc (a->system_str, NULL); return r; } @@ -1751,10 +1872,17 @@ struct argv argv_insert_head (const struct argv *a, const char *head) { struct argv r; + char *s; r = argv_clone (a, 1); r.argv[0] = string_alloc (head, NULL); - + s = r.system_str; + r.system_str = string_alloc (head, NULL); + if (s) + { + argv_system_str_append (&r, s, false); + free (s); + } return r; } @@ -1870,6 +1998,7 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag if (!s) s = ""; argv_append (a, string_alloc (s, NULL)); + argv_system_str_append (a, s, true); } else if (!strcmp (term, "%sc")) { @@ -1880,24 +2009,36 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag 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)); + nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); + if (nparms) + { + for (i = 0; i < nparms; ++i) + argv_append (a, string_alloc (parms[i], NULL)); + } + else + argv_append (a, string_alloc (s, NULL)); + + argv_system_str_append (a, s, false); } else - argv_append (a, string_alloc ("", NULL)); + { + argv_append (a, string_alloc ("", NULL)); + argv_system_str_append (a, "echo", false); + } } 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)); + argv_system_str_append (a, numstr, false); } 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)); + argv_system_str_append (a, numstr, false); } else if (!strcmp (term, "%s/%d")) { @@ -1918,13 +2059,15 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag strcat (combined, "/"); strcat (combined, numstr); argv_append (a, combined); + argv_system_str_append (a, combined, false); } } - else if (!strcmp (term, "%s%s")) + else if (!strcmp (term, "%s%sc")) { char *s1 = va_arg (arglist, char *); char *s2 = va_arg (arglist, char *); char *combined; + char *cmd_name; if (!s1) s1 = ""; if (!s2) s2 = ""; @@ -1933,6 +2076,13 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag strcpy (combined, s1); strcat (combined, s2); argv_append (a, combined); + + cmd_name = argv_extract_cmd_name (combined); + if (cmd_name) + { + argv_system_str_append (a, cmd_name, false); + free (cmd_name); + } } else ASSERT (0); @@ -1941,6 +2091,7 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag else { argv_append (a, term); + argv_system_str_append (a, term, false); } } gc_free (&gc); @@ -1954,43 +2105,54 @@ argv_test (void) const char *s; struct argv a; + argv_init (&a); + argv_printf (&a, "%sc foo bar %s", "c:\\\\src\\\\test\\\\jyargs.exe", "foo bar"); + argv_msg_prefix (M_INFO, &a, "ARGV"); + msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); + //openvpn_execve_check (&a, NULL, 0, "command failed"); -#ifdef WIN32 - argv_printf (&a, "%s foo bar %s", "c:\\src\\test\\jyargs.exe", "foo bar"); - //argv_printf (&a, "%s %s %s", "c:\\src\\test files\\batargs.bat", "foo", "bar"); -#else - argv_printf (&a, "./myechox foo bar"); -#endif + argv_printf (&a, "%sc %s %s", "c:\\\\src\\\\test files\\\\batargs.bat", "foo", "bar"); + argv_msg_prefix (M_INFO, &a, "ARGV"); + msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); + //openvpn_execve_check (&a, NULL, 0, "command failed"); + argv_printf (&a, "%s%sc foo bar %s %s/%d %d %u", "/foo", "/bar.exe", "one two", "1.2.3.4", 24, -69, 96); argv_msg_prefix (M_INFO, &a, "ARGV"); + msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); //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); - printf ("%s\n", s); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); { struct argv b = argv_insert_head (&a, "MARK"); s = argv_str (&b, &gc, PA_BRACKET); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&b)); argv_reset (&b); - printf ("%s\n", s); } argv_printf (&a, "%sc foo bar %d", "\"multi term\" command following \\\"spaces", 99); s = argv_str (&a, &gc, PA_BRACKET); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); argv_reset (&a); - printf ("%s\n", s); s = argv_str (&a, &gc, PA_BRACKET); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); argv_reset (&a); - printf ("%s\n", s); argv_printf (&a, "foo bar %d", 99); 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); + printf ("PF: %s\n", s); + printf ("PF-S: %s\n", argv_system_str(&a)); + argv_reset (&a); #if 0 { @@ -2015,3 +2177,22 @@ argv_test (void) gc_free (&gc); } #endif + +const char * +openvpn_basename (const char *path) +{ + const char *ret; + const int dirsep = OS_SPECIFIC_DIRSEP; + + if (path) + { + ret = strrchr (path, dirsep); + if (ret && *ret) + ++ret; + else + ret = path; + if (*ret) + return ret; + } + return NULL; +} |