Hello all,

I am attaching a new patch which takes care of few things discussed yesterday.

Summary of patch:
1) Add new option --script-dir which restricts any user defined script to run 
only from specific directory

2) Backward compatible. If script-dir is not specified then it allows script 
from any directory.


3) Adds compile time configure option --with-script-dir=/some/path/
If this option is used then script-dir becomes hard-coded and CAN NOT be 
changed from config file or command line.


This allows flexibility to anyone (people like me) who wants to compile the 
code on their own making sure that script-dir can not be changed at all.


4) If it is not enabled at compile time then first script-dir has preference.
a) if script-dir is specified on command line, it is given the priority

b) if script-dir is specified twice (either in same config file or included 
config file) then only 1st occurrence is accepted and warning is logged for the 
rest of the occurrences.


This allows, easy binary distribution (by not hard-coding the script-dir) and 
then user can decide on their own script-dir.

Root user can then call OpenVPN with script-dir either on command line or 
inside parent config file. Parent config file can then call child config 
(config child.conf). And then "freely" give access to child.conf to other lower 
admins without worrying about them running any random script.

Even if lower admins specify script-dir, it will be ignored.



Hope that this patch now satisfy everyone in devel group and makes much more 
sense to be implemented.

Security in my opinion should be prime concern especially when we know that 
there is a way to run any random script. And hence atleast for such insecure 
options, sanity checks has to be there in program itself instead of trusting 
the frontend.




Patch is clean and simple and just about 25 lines of real code addition.

Patch eliminates danger of openvpn running any script blindly.

So please review it and consider to merge in source tree.

Thank you

AMM.
--- openvpn-2.2.2.old/config.h.in	2011-12-14 16:51:49.000000000 +0530
+++ openvpn-2.2.2/config.h.in	2012-08-24 21:32:01.843738238 +0530
@@ -468,6 +468,9 @@
 /* Path to route tool */
 #undef ROUTE_PATH
 
+/* Path to script directory */
+#undef SCRIPTDIR_PATH
+
 /* The size of `unsigned int', as computed by sizeof. */
 #undef SIZEOF_UNSIGNED_INT
 
--- openvpn-2.2.2.old/configure	2011-12-14 16:51:11.000000000 +0530
+++ openvpn-2.2.2/configure	2012-08-24 21:32:01.846738307 +0530
@@ -734,6 +734,7 @@
 with_pkcs11_helper_headers
 with_pkcs11_helper_lib
 with_ifconfig_path
+with_script_dir
 with_iproute_path
 with_route_path
 with_netstat_path
@@ -1409,6 +1410,7 @@
   --with-pkcs11-helper-headers=DIR pkcs11-helper Include files location
   --with-pkcs11-helper-lib=DIR     pkcs11-helper Library location
   --with-ifconfig-path=PATH   Path to ifconfig tool
+  --with-script-dir=PATH      Path to script dir
   --with-iproute-path=PATH    Path to iproute tool
   --with-route-path=PATH  Path to route tool
   --with-netstat-path=PATH  Path to netstat tool
@@ -3400,6 +3402,18 @@
 
 
 
+# Check whether --with-script-dir was given.
+if test "${with_script_dir+set}" = set; then :
+  withval=$with_script_dir; test -n $withval &&
+cat >>confdefs.h <<_ACEOF
+#define SCRIPTDIR_PATH "$withval"
+_ACEOF
+
+
+fi
+
+
+
 # Check whether --with-iproute-path was given.
 if test "${with_iproute_path+set}" = set; then :
   withval=$with_iproute_path; IPROUTE="$withval"
--- openvpn-2.2.2.old/configure.ac	2011-12-13 22:28:56.000000000 +0530
+++ openvpn-2.2.2/configure.ac	2012-08-24 21:32:02.027742387 +0530
@@ -257,6 +257,11 @@
 )
 AC_DEFINE_UNQUOTED(IFCONFIG_PATH, "$IFCONFIG", [Path to ifconfig tool])
 
+AC_ARG_WITH(script-dir,
+   [  --with-script-dir=PATH      Path to script dir],
+   test -n $withval && AC_DEFINE_UNQUOTED(SCRIPTDIR_PATH, "$withval", [Path to script directory])
+)
+
 AC_ARG_WITH(iproute-path,
    [  --with-iproute-path=PATH    Path to iproute tool],
    [IPROUTE="$withval"],
--- openvpn-2.2.2.old/init.c	2011-12-13 22:28:56.000000000 +0530
+++ openvpn-2.2.2/init.c	2012-08-24 21:32:02.028742410 +0530
@@ -2291,9 +2291,14 @@
 #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: user-defined scripts will be run only from %s", script_dir);
+    }
   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.old/misc.c	2011-12-13 22:28:56.000000000 +0530
+++ openvpn-2.2.2/misc.c	2012-08-24 21:32:02.029742433 +0530
@@ -45,6 +45,12 @@
 
 /* contains an SSEC_x value defined in misc.h */
 int script_security = SSEC_BUILT_IN; /* GLOBAL */
+#ifdef SCRIPTDIR_PATH
+const char *script_dir = SCRIPTDIR_PATH; /* GLOBAL */
+#else
+#warning use of --with-script-dir=PATH is recommended
+const char *script_dir = NULL; /* GLOBAL */
+#endif
 
 /* contains SM_x value defined in misc.h */
 int script_method = SM_EXECVE; /* GLOBAL */
@@ -484,10 +490,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 && script_dir[0] && strncmp(script_dir, cmd, strlen(script_dir)))
+	return false;
+      return script_security >= SSEC_SCRIPTS;
+    }
   else
     return script_security >= SSEC_BUILT_IN;
 }
@@ -509,11 +519,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.old/misc.h	2011-12-13 22:28:56.000000000 +0530
+++ openvpn-2.2.2/misc.h	2012-08-24 21:32:02.030742455 +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.old/options.c	2011-12-13 22:28:56.000000000 +0530
+++ openvpn-2.2.2/options.c	2012-08-24 21:47:42.068931155 +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 script 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,14 @@
       else
 	script_method = SM_EXECVE;
     }
+  else if (streq (p[0], "script-dir") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      if (script_dir)
+	msg (M_WARN, "--script-dir already set, ignoring new value: %s", p[1]);
+      else
+	script_dir = p[1];
+    }
   else if (streq (p[0], "mssfix"))
     {
       VERIFY_PERMISSION (OPT_P_GENERAL);
--- openvpn-2.2.2.old/win32.c	2011-12-13 22:28:56.000000000 +0530
+++ openvpn-2.2.2/win32.c	2012-08-24 21:32:02.034742544 +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);

Reply via email to