Hello all, I am submitting a minor patch which includes an option to specify --script-dir. i.e. any user defined script will be run ONLY IF it is present in "script-dir".
The reason I needed this is because I had a frontend to configuration file which allowed administrator to change configuration. I also have script-security set to 2 because I wanted to run a script when client connects. These two option make it insecure. As admin (with bad intention or if admin password is leaked) can simply call "rm -rf /" for certain commands. So my idea was 1) Add a new option called script-dir 2) Frontend will not allow word "script-dir" in config file (so admin cant change it) 3) script-dir will be passed on command line This way admin can not run anything other than what I have put in script-dir. This also helps prevent accidentally run script in some other path. Patch also fixes minor bug in init.c where warning for SSEC_PW_ENV actually would never be shown. So please have a look at it and if acceptable then merge in source tree. Thanks AMM.
--- openvpn-2.2.2/init.c 2011-12-13 22:28:56.000000000 +0530 +++ openvpn-2.2.2/init.c 2012-08-21 11:53:22.809410085 +0530 @@ -2291,9 +2291,13 @@ #endif if (script_security >= SSEC_SCRIPTS) - msg (M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts"); - else if (script_security >= SSEC_PW_ENV) - msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); + { + msg (M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts"); + if (script_security >= SSEC_PW_ENV) + msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); + if (script_dir == NULL) + msg (M_WARN, "WARNING: setting --script-dir is recommended for higher security"); + } else msg (M_WARN, "NOTE: " PACKAGE_NAME " 2.1 requires '--script-security 2' or higher to call user-defined scripts or executables"); --- openvpn-2.2.2/misc.c 2011-12-13 22:28:56.000000000 +0530 +++ openvpn-2.2.2/misc.c 2012-08-21 12:27:24.332296778 +0530 @@ -45,6 +45,7 @@ /* contains an SSEC_x value defined in misc.h */ int script_security = SSEC_BUILT_IN; /* GLOBAL */ +const char *script_dir = NULL; /* GLOBAL */ /* contains SM_x value defined in misc.h */ int script_method = SM_EXECVE; /* GLOBAL */ @@ -484,10 +485,14 @@ } bool -openvpn_execve_allowed (const unsigned int flags) +openvpn_execve_allowed (const char *cmd, const unsigned int flags) { if (flags & S_SCRIPT) - return script_security >= SSEC_SCRIPTS; + { + if (script_dir != NULL && strncmp(script_dir, cmd, strlen(script_dir))) + return false; + return script_security >= SSEC_SCRIPTS; + } else return script_security >= SSEC_BUILT_IN; } @@ -509,11 +514,11 @@ if (a && a->argv[0]) { #if defined(ENABLE_EXECVE) - if (openvpn_execve_allowed (flags)) + const char *cmd = a->argv[0]; + if (openvpn_execve_allowed (cmd, flags)) { 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; --- openvpn-2.2.2/misc.h 2011-12-13 22:28:56.000000000 +0530 +++ openvpn-2.2.2/misc.h 2012-08-21 12:10:59.916050919 +0530 @@ -133,7 +133,7 @@ /* wrapper around the execve() call */ int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags); bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); -bool openvpn_execve_allowed (const unsigned int flags); +bool openvpn_execve_allowed (const char *cmd, const unsigned int flags); int openvpn_system (const char *command, const struct env_set *es, unsigned int flags); static inline bool @@ -353,6 +353,7 @@ #define SSEC_SCRIPTS 2 /* allow calling of built-in programs and user-defined scripts */ #define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */ extern int script_security; /* GLOBAL */ +extern const char *script_dir; /* GLOBAL */ #define SM_EXECVE 0 /* call external programs with execve() or CreateProcess() */ #define SM_SYSTEM 1 /* call external programs with system() */ --- openvpn-2.2.2/options.c 2011-12-13 22:28:56.000000000 +0530 +++ openvpn-2.2.2/options.c 2012-08-21 11:33:15.955648666 +0530 @@ -218,6 +218,7 @@ " 1 -- (default) only call built-ins such as ifconfig\n" " 2 -- allow calling of built-ins and scripts\n" " 3 -- allow password to be passed to scripts via env\n" + "--script-dir dir: Only run user-defined scripts if it resides in this directory\n" "--shaper n : Restrict output to peer to n bytes per second.\n" "--keepalive n m : Helper option for setting timeouts in server mode. Send\n" " ping once every n seconds, restart if ping not received\n" @@ -4748,6 +4749,11 @@ else script_method = SM_EXECVE; } + else if (streq (p[0], "script-dir") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + script_dir = p[1]; + } else if (streq (p[0], "mssfix")) { VERIFY_PERMISSION (OPT_P_GENERAL); --- openvpn-2.2.2/win32.c 2011-12-13 22:28:56.000000000 +0530 +++ openvpn-2.2.2/win32.c 2012-08-21 12:15:56.355627974 +0530 @@ -956,7 +956,8 @@ if (a && a->argv[0]) { - if (openvpn_execve_allowed (flags)) + char *cmd = a->argv[0]; + if (openvpn_execve_allowed (cmd, flags)) { if (script_method == SM_EXECVE) { @@ -965,7 +966,6 @@ char *env = env_block (es); char *cl = cmd_line (a); - char *cmd = a->argv[0]; CLEAR (start_info); CLEAR (proc_info);