[redhat-lspp] Re: [PATCH] pam_namespace module patch

Klaus Weidner klaus at atsec.com
Sat Feb 18 03:51:56 UTC 2006


On Fri, Feb 17, 2006 at 06:17:32PM -0500, JANAK DESAI wrote:
> Changes since the -v1 of the patch available at the above location:
> 	- Added user name in the instance directory name if polyinstantiation
> 	  is being done with USER or BOTH (both user and security context)

This should be local policy and not hardcoded... I personally definitely
want the username in the home directory names as well (even though those
are not user instantiated), and don't want the directories hidden.

This patch (on top of Janak's new patch) adds rudimentary variable
expansion, and puts the filename patterns in the config file:

	/tmp     /tmp.inst-$USER-       both      root,adm
	$HOME    $HOME.inst-            context

This results in the following filenames:

	/tmp.inst-kw-9d3cb6031d5ea2d160a2bf80a123fbab
	/home/kw.inst-b3aabde70434ffd30d62c76cba31d321

Using the following config gets the original behavior back (I've removed
support for $HOME_PARENT, this could be added back if people really want
it):

	/tmp     /.inst-       both      root,adm
	$HOME    /home/.inst-  context

Warning: I've modified the hash calculation slightly to avoid
invalidating the hash if the prefix changes - if you depend on the old
names this part should be reverted. I hope nobody is using this on a
production system yet...

Also, I've removed duplication between the README and the sample config
to simplify editing while this is still in flux, we can re-expand that
later.

Signed-off-by: Klaus Weidner <klaus at atsec.com>

 README          |   36 +++++++-------
 namespace.conf  |   38 +--------------
 pam_namespace.c |  138 +++++++++++++++++++-------------------------------------
 3 files changed, 71 insertions(+), 141 deletions(-)

diff -ur Janak/namespace.conf ./namespace.conf
--- Janak/namespace.conf	2006-02-17 02:34:28.000000000 -0600
+++ ./namespace.conf	2006-02-17 03:14:36.000000000 -0600
@@ -1,35 +1,6 @@
 # /etc/security/namespace.conf
 #
-# Each line describes a limit for a user in the form:
-# 
-# <polydir>  <instance_parent_dir>  <method>  <list_of_uids>
-# 
-# Where:
-# <polydir> - is the absolute pathname of the directory to polyinstantiate
-#       Special entry $HOME is supported to designate user's home directory.
-#       This field cannot be blank.
-# 
-# <instance_parent_dir> - is the absolute pathname of the parent directory
-# 	where an instantiation of <polydir> is to be created. This instance
-#	is bind mounted on the <polydir> to provide an instance of <polydir>
-#	based on the <method> column. Two special entries $HOME and
-#	$HOME_PARENT are supported to designate user's home directory and
-#	parent of user's home directory. This field cannot be blank.
-# 
-# <method> - is the method used for polyinstantiation. It can take 3 different
-# 	values; "user" for polyinstantiation based on user name, "context"
-# 	for polyinstantiation based on process security context, and "both"
-# 	for polyinstantiation based on both user name and security context.
-# 	Methods "context" and "both" are only available with SELinux. This
-#       field cannot be blank.
-# 
-# <list_of_uids> - is a comma separated list of user names for whom the
-#       poyinstantiation is not performed. If left blank, polyinstantiation
-# 	will be performed for all users.
-# 
-# EXAMPLE /etc/security/namespace.conf configuration file:
-# =======================================================
-# comments
+# See /usr/share/doc/pam-*/txts/README.pam_namespace for more information.
 # 
 # Following two lines will polyinstantiate /tmp directory and user's home
 # directory. /tmp will be polyinstantiated based on both security context
@@ -38,7 +9,6 @@
 # for user root and adm for directory /tmp, where as home directories
 # are polyinstantiated for all users.
 #
-# /tmp	/		both		root,adm
-#
-# $HOME	$HOME_PARENT	context
-# 
+# /tmp     /tmp.inst-$USER-       both      root,adm
+# /var/tmp /var/tmp.inst-$USER-   both      root,adm
+# $HOME    $HOME.inst-            context
diff -ur Janak/pam_namespace.c ./pam_namespace.c
--- Janak/pam_namespace.c	2006-02-17 02:34:28.000000000 -0600
+++ ./pam_namespace.c	2006-02-17 03:29:12.000000000 -0600
@@ -71,7 +71,6 @@
 /*
  * Module defines
  */
-#define PROC_MNTS "/proc/mounts"
 #define MD5_DIGEST_LENGTH 16
 #ifndef PAM_NAMESPACE_CONFIG
 #define PAM_NAMESPACE_CONFIG "/etc/security/namespace.conf"
@@ -109,7 +108,7 @@
  */
 struct polydir_s {
     char dir[PATH_MAX];    	       	/* directory to polyinstantiate */
-    char instance_parent_dir[PATH_MAX]; /* parent dir of instance */
+    char instance_prefix[PATH_MAX];	/* prefix for instance dir path name */
     enum polymethod method;		/* method used to polyinstantiate */
     unsigned int num_uids;		/* number of override uids */
     uid_t *uid;				/* list of override uids */
@@ -149,7 +148,7 @@
 
     /* Make copy */
     strcpy(pent->dir, ent->dir);
-    strcpy(pent->instance_parent_dir, ent->instance_parent_dir);
+    strcpy(pent->instance_prefix, ent->instance_prefix);
     pent->method = ent->method;
     pent->num_uids = ent->num_uids;
     if (ent->num_uids) {
@@ -186,8 +185,8 @@
 
         pam_syslog(idata->pamh, LOG_NOTICE, "Poly dirs so far");
         while (dptr) {
-            pam_syslog(idata->pamh, LOG_NOTICE, "%s %s %d", dptr->dir,
-                   dptr->instance_parent_dir, dptr->method);
+            pam_syslog(idata->pamh, LOG_NOTICE, "dir='%s' iprefix='%s' meth=%d",
+		   dptr->dir, dptr->instance_prefix, dptr->method);
             for (i = 0, iptr = dptr->uid; i < dptr->num_uids; i++, iptr++)
                 pam_syslog(idata->pamh, LOG_NOTICE, "override user %d ", *iptr);
             dptr = dptr->next;
@@ -224,10 +223,9 @@
 static int process_line(char *line, const char *home, 
 			struct instance_data *idata)
 {
-    const char *dir, *instance_parent_dir;
+    const char *dir, *instance_prefix;
     const char *method, *uids;
     char *tmp = strdupa(home);
-    const char *parent_home_dir = dirname(tmp); /* parent of homedir */
     char *tptr;
     struct polydir_s poly;
     int retval = 0;
@@ -270,8 +268,8 @@
         pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line -- skipping");
         return 0;
     }
-    instance_parent_dir = strtok_r(NULL, " \t", &tptr);
-    if (instance_parent_dir == NULL) {
+    instance_prefix = strtok_r(NULL, " \t", &tptr);
+    if (instance_prefix == NULL) {
         pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line -- skipping");
         return 0;
     }
@@ -297,24 +295,33 @@
      */
     if (strcmp(dir, "$HOME") == 0) {
 	dir = home;
-        /*
-         * For $HOME_PARENT, use the passed in home directory
-         * to obtain the parent of home directory.
-         */
-    	if (strcmp(instance_parent_dir, "$HOME_PARENT") == 0) 
-	    instance_parent_dir = parent_home_dir;
-    	else if (strcmp(instance_parent_dir, "$HOME") == 0)
-    	    instance_parent_dir = home;
+    }
+
+    /*
+     * Expand $HOME and $USER in instance dir prefix
+     */
+    if ((tptr = strstr(instance_prefix, "$USER")) != 0) {
+	/* FIXME: should only support this if method is USER or BOTH */
+	char *expanded = alloca(strlen(idata->user) + strlen(instance_prefix)-5+1);
+	*tptr = 0;
+	sprintf(expanded, "%s%s%s", instance_prefix, idata->user, tptr+5);
+	instance_prefix = expanded;
+    }
+    if ((tptr = strstr(instance_prefix, "$HOME")) != 0) {
+	char *expanded = alloca(strlen(home)+strlen(instance_prefix)-5+1);
+	*tptr = 0;
+	sprintf(expanded, "%s%s%s", instance_prefix, home, tptr+5);
+	instance_prefix = expanded;
     }
 
     /*
      * Ensure that all pathnames are absolute path names.
      */
-    if ((dir[0] != '/') || (instance_parent_dir[0] != '/')) {
+    if ((dir[0] != '/') || (instance_prefix[0] != '/')) {
         pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must start with '/'");
         return 0;
     }
-    if (strstr(dir, "..") || strstr(instance_parent_dir, "..")) {
+    if (strstr(dir, "..") || strstr(instance_prefix, "..")) {
         pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must not have '..'");
         return 0;
     }
@@ -324,7 +331,7 @@
      * pathnames and the method with which to polyinstantiate.
      */
     strcpy(poly.dir, dir);
-    strcpy(poly.instance_parent_dir, instance_parent_dir);
+    strcpy(poly.instance_prefix, instance_prefix);
     if (strcmp(method, "user") == 0)
         poly.method = USER;
 #ifdef WITH_SELINUX
@@ -501,22 +508,12 @@
 	struct instance_data *idata)
 #endif
 {
-    char *dir;
 #ifdef WITH_SELINUX
     security_context_t scon = NULL;
     security_class_t tclass;
     int rc;
 #endif
 
-    /*
-     * Get the last component of the pathname to polyinstantiate.
-     */
-    dir = strrchr(polyptr->dir, '/');
-    if (dir && (strlen(dir) > 1))
-        dir++;
-    else
-        dir = polyptr->dir;
-
 # ifdef WITH_SELINUX
     /*
      * Get the security context of the directory to polyinstantiate.
@@ -564,38 +561,20 @@
      */
     switch (polyptr->method) {
         case USER:
-	    if (strcmp(polyptr->instance_parent_dir, "/") == 0) {
-    	        if (asprintf(i_name, "/.%s%s", idata->user, dir) < 0) 
-		    rc = PAM_SESSION_ERR;
-            } else {
-    	        if (asprintf(i_name, "%s/.%s%s", polyptr->instance_parent_dir, 
-			idata->user, dir) < 0) 
-		    rc = PAM_SESSION_ERR;
-            }
+	    if (asprintf(i_name, "%s;%s", polyptr->dir, idata->user) < 0) 
+		rc = PAM_SESSION_ERR;
     	    break;
 
 #ifdef WITH_SELINUX
         case CONTEXT:
-	    if (strcmp(polyptr->instance_parent_dir, "/") == 0) {
-    	        if (asprintf(i_name, "/.%s%s", *i_context, dir) < 0) 
-		    rc = PAM_SESSION_ERR;
-            } else {
-    	        if (asprintf(i_name, "%s/.%s%s", polyptr->instance_parent_dir,
-			*i_context, dir) < 0) 
-		    rc = PAM_SESSION_ERR;
-            }
+	    if (asprintf(i_name, "%s;%s", polyptr->dir, *i_context) < 0) 
+		rc = PAM_SESSION_ERR;
     	    break;
 
     	case BOTH:
-	    if (strcmp(polyptr->instance_parent_dir, "/") == 0) {
-    	        if (asprintf(i_name, "/.%s%s%s", *i_context,
-			 idata->user, dir) < 0)
-		    rc = PAM_SESSION_ERR;
-            } else {
-    	        if (asprintf(i_name, "%s/.%s%s%s", polyptr->instance_parent_dir,
-			*i_context, idata->user, dir) < 0)
-		    rc = PAM_SESSION_ERR;
-            }
+	    if (asprintf(i_name, "%s;%s;%s", polyptr->dir,
+		    *i_context, idata->user) < 0)
+		rc = PAM_SESSION_ERR;
     	    break;
 #endif /* WITH_SELINUX */
 
@@ -733,14 +712,13 @@
 	struct instance_data *idata)
 {
     int i, retval = 0;
-    char *inst_parent_dir = NULL;
+    char *inst_dir = NULL;
     char *md5inst = NULL, *instname = NULL;
-    char *to, *dir, *lastchr;
+    char *to, *dir;
 #ifdef WITH_SELINUX
     security_context_t instcontext = NULL, origcontext = NULL;
 #endif
     unsigned char inst_digest[MD5_DIGEST_LENGTH];
-    int username = (polyptr->method == USER) || (polyptr->method == BOTH);
 
     if (idata->debug)
         pam_syslog(idata->pamh, LOG_NOTICE,
@@ -793,13 +771,6 @@
         goto error_out;
     }
 
-    /*
-     * In the case where instance path is just / or has a trailing, 
-     * we should not include an extra / in the asprintfs below. It messes
-     * up when we are trying to unmount the filesystem based on
-     * /proc/mounts
-     */
-
     to = md5inst;
     for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
         char c[3];
@@ -807,33 +778,22 @@
         to = stpcpy(to, c);
     }
 
-    lastchr = polyptr->instance_parent_dir +
-			 strlen(polyptr->instance_parent_dir) - 1;
-    if (*lastchr == '/') {
-        if (asprintf(&inst_parent_dir, "%s.inst-%s-%s",
-		polyptr->instance_parent_dir, username ? idata->user : "",
-                md5inst) < 0)
-		goto error_out;
-    } else {
-        if (asprintf(&inst_parent_dir, "%s/.inst-%s-%s",
-		polyptr->instance_parent_dir, username ? idata->user : "",
-                md5inst) < 0)
-		goto error_out;
-    }
+    if (asprintf(&inst_dir, "%s%s", polyptr->instance_prefix, md5inst) < 0)
+	goto error_out;
 
     if (idata->debug)
-        pam_syslog(idata->pamh, LOG_NOTICE, "instance_parent_dir %s",
-		inst_parent_dir);
+        pam_syslog(idata->pamh, LOG_NOTICE, "instance_dir %s",
+		inst_dir);
 
     /*
      * Create instance directory with appropriate security
      * contexts, owner, group and mode bits.
      */
 #ifdef WITH_SELINUX
-    retval = create_dirs(polyptr, inst_parent_dir, instcontext,
+    retval = create_dirs(polyptr, inst_dir, instcontext,
 			 origcontext, idata);
 #else
-    retval = create_dirs(polyptr, inst_parent_dir, idata);
+    retval = create_dirs(polyptr, inst_dir, idata);
 #endif
 
     if (retval < 0) {
@@ -843,13 +803,13 @@
     }
 
     /*
-     * Bind mount instance parent directory on top of the polyinstantiated
+     * Bind mount instance directory on top of the polyinstantiated
      * directory to provide an instance of polyinstantiated directory
      * based on polyinstantiated method.
      */
-    if (mount(inst_parent_dir, polyptr->dir, NULL, MS_BIND, NULL) < 0) {
+    if (mount(inst_dir, polyptr->dir, NULL, MS_BIND, NULL) < 0) {
         pam_syslog(idata->pamh, LOG_ERR, "Error mounting %s on %s, %s",
-                   inst_parent_dir, polyptr->dir, strerror(errno));
+                   inst_dir, polyptr->dir, strerror(errno));
         goto error_out;
     }
 
@@ -864,7 +824,7 @@
 
 cleanup:
     free(md5inst);
-    free(inst_parent_dir);
+    free(inst_dir);
     free(instname);
 #ifdef WITH_SELINUX
     freecon(instcontext);
@@ -1022,7 +982,7 @@
 
 /*
  * Orig namespace. This function is called from when closing a pam
- * session. If authorized, it unmounts instance_parent directory.
+ * session. If authorized, it unmounts instance directory.
  */
 static int orig_namespace(struct instance_data *idata)
 {
@@ -1036,7 +996,7 @@
      * Cycle through all polyinstantiated directories from the namespace
      * configuration file to see if polyinstantiation was performed for
      * this user for each of the entry. If it was, try and unmount
-     * appropriate polyinstantiated instance parent directories.
+     * appropriate polyinstantiated instance directories.
      */
     for (pptr = idata->polydirs_ptr; pptr; pptr = pptr->next) {
         if (ns_override(pptr, idata))
@@ -1044,7 +1004,7 @@
         else {
             if (idata->debug)
                 pam_syslog(idata->pamh, LOG_NOTICE, 
-			"Unmounting instance parent dir for user %d & dir %s",
+			"Unmounting instance dir for user %d & dir %s",
                        idata->uid, pptr->dir);
 
             if (umount(pptr->dir) < 0) {
diff -ur Janak/README ./README
--- Janak/README	2006-02-17 02:34:28.000000000 -0600
+++ ./README	2006-02-17 03:15:34.000000000 -0600
@@ -9,47 +9,47 @@
 installed by default provides example for polyinstantiating /tmp 
 and users' home directory.
 
-Each line describes a limit for a user in the form:
+Each line in namespace.conf describes a limit for a user in the form:
 
-<polydir>   <instance_parent_dir>   <method>   <list_of_uids>
+<polydir>  <instance_prefix>  <method>  <list_of_uids>
 
 Where:
 <polydir> - is the absolute pathname of the directory to polyinstantiate
-        Special entry $HOME is supported to designate user's home directory.
-        This field cannot be blank.
+      Special entry $HOME is supported to designate user's home directory.
+      This field cannot be blank.
 
-<instance_parent_dir> - is the absolute pathname of the parent directory
-	where an instantiation of <polydir> is to be created. This
-	instance is bind mounted on the <polydir> to provide an instance
-	of <polydir> based on the <method> column. Two special entries
-	$HOME and $HOME_PARENT are supported to designate user's home
-	directory and parent of user's home directory. This field cannot
-	be blank.
+<instance_prefix> - is the string prefix used to build the pathname for the
+	instantiation of <polydir>. A md5sum string (32 hex characters) is appended
+	to the prefix to generate the final instance directory path. This 
+	directory is created if it did not exist already, and is then
+	bind mounted on the <polydir> to provide an instance of <polydir>
+	based on the <method> column. The special string $HOME is replaced with 
+	the user's home directory, and $USER with the username.
+	This field cannot be blank.
 
 <method> - is the method used for polyinstantiation. It can take 3 different
 	values; "user" for polyinstantiation based on user name, "context"
 	for polyinstantiation based on process security context, and "both"
 	for polyinstantiation based on both user name and security context.
 	Methods "context" and "both" are only available with SELinux. This
-        field cannot be blank.
+	field cannot be blank.
 
 <list_of_uids> - is a comma separated list of user names for whom the
-        poyinstantiation is not performed. If left blank, polyinstantiation
+	polyinstantiation is not performed. If left blank, polyinstantiation
 	will be performed for all users.
 
 EXAMPLE /etc/security/namespace.conf configuration file:
 =======================================================
-# comments
-# 
 # Following two lines will polyinstantiate /tmp directory and user's home
 # directory. /tmp will be polyinstantiated based on both security context
 # as well as user name, where as home directory will be polyinstantiated
 # based on security context only. Polyinstantion will not be performed
 # for user root and adm for directory /tmp, where as home directories
 # are polyinstantiated for all users.
-/tmp	/		both		root,adm
-$HOME	$HOME_PARENT	$HOME_PARENT	context
-
+#
+# /tmp     /tmp.inst-$USER-       both      root,adm
+# /var/tmp /var/tmp.inst-$USER-   both      root,adm
+# $HOME    $HOME.inst-            context
 
 ARGUMENTS RECOGNIZED:
     debug		Verbose logging by syslog




More information about the redhat-lspp mailing list