[redhat-lspp] [PATCH] pam_namespace module patch

JANAK DESAI janak at us.ibm.com
Fri Feb 17 23:17:32 UTC 2006


[PATCH] pam_namespace V2

This patch applies on top of the latest version available at

http://people.redhat.com/sgrubb/files/

Changes since the -v1 of the patch available at the above location:
	- Removed creation and use of "orig" directories where the 
	  original polyinstantiated directory was bind mounted for
	  use by trusted applications.
	- Added user name in the instance directory name if polyinstantiation
	  is being done with USER or BOTH (both user and security context)
	- Added a new option to the namespace module to undo any 
	  previous polyinstantiation. This option may be used by trusted
	  applications that want to process instance directories on their
	  own.

Signed-off-by: Janak Desai <janak at us.ibm.com>

---

 Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/README          |   23 
 Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/namespace.conf  |   12 
 Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/pam_namespace.c |  454 ++---------
 modules/pam_namespace/README                                 |   23 
 modules/pam_namespace/namespace.conf                         |   12 
 modules/pam_namespace/pam_namespace.c                        |  454 ++---------
 6 files changed, 250 insertions(+), 728 deletions(-)

diff -Naurp Linux-PAM-0.99.3.0/modules/pam_namespace/README Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/README
--- Linux-PAM-0.99.3.0/modules/pam_namespace/README	2006-02-17 22:26:41.000000000 +0000
+++ Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/README	2006-02-17 22:36:59.000000000 +0000
@@ -11,7 +11,7 @@ and users' home directory.
 
 Each line describes a limit for a user in the form:
 
-<polydir>   <instance_parent_dir>   <orig_dir>   <method>   <list_of_uids>
+<polydir>   <instance_parent_dir>   <method>   <list_of_uids>
 
 Where:
 <polydir> - is the absolute pathname of the directory to polyinstantiate
@@ -26,12 +26,6 @@ Where:
 	directory and parent of user's home directory. This field cannot
 	be blank.
 
-<orig_dir> - is the absolute pathname of the parent directory where the
-        original content of the <polydir> is available. The special entry
-	$HOME_PARENT is supported to designate parent of user's home
-	directory. This field cannot be blank and this directory cannot
-	be a subdirectory of <polydir>.
-
 <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"
@@ -53,25 +47,30 @@ EXAMPLE /etc/security/namespace.conf con
 # 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
+/tmp	/		both		root,adm
 $HOME	$HOME_PARENT	$HOME_PARENT	context
 
 
 ARGUMENTS RECOGNIZED:
     debug		Verbose logging by syslog
 
-    unmnt_first		For programs such as su and newrole, the login
+    unmnt_remnt		For programs such as su and newrole, the login
 			session has already setup a polyinstantiated 
 			namespace. For these programs, polyinstantiation
 			is performed based on new user id or security
 			context, however the command first needs to 
 			undo the polyinstantiation performed by login.
-			This argument is provide in the command's pam
-			configuration file to instruct the command to 
+			This argument instructs the command to 
 			first undo previous polyinstantiation before
 			proceeding with new polyinstantiation based on
 			new id/context.
 
+    unmnt_only		For trusted programs that want to undo any
+			existing bind mounts and process instance 
+			directories on their own, this argument allows
+			them to unmount currently mounted instance
+			directories.
+
     require_selinux	If selinux is not enabled, return failure.
 
 
@@ -83,7 +82,7 @@ USAGE:
 	the following line in /etc/pam.d/<command> as the last line for 
 	session service:
 
-	session  required  /lib/security/pam_namespace.so [unmnt_first] [debug]
+	session  required  /lib/security/pam_namespace.so [unmnt_remnt] [debug]
 
 	Replace "/lib/security" path with your real modules path. This module
 	also depends on pam_selinux.so setting the context.
diff -Naurp Linux-PAM-0.99.3.0/modules/pam_namespace/namespace.conf Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/namespace.conf
--- Linux-PAM-0.99.3.0/modules/pam_namespace/namespace.conf	2006-02-17 22:26:41.000000000 +0000
+++ Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/namespace.conf	2006-02-17 22:37:24.000000000 +0000
@@ -2,7 +2,7 @@
 #
 # Each line describes a limit for a user in the form:
 # 
-# <polydir>  <instance_parent_dir>  <orig_dir>  <method>  <list_of_uids>
+# <polydir>  <instance_parent_dir>  <method>  <list_of_uids>
 # 
 # Where:
 # <polydir> - is the absolute pathname of the directory to polyinstantiate
@@ -16,12 +16,6 @@
 #	$HOME_PARENT are supported to designate user's home directory and
 #	parent of user's home directory. This field cannot be blank.
 # 
-# <orig_dir> - is the absolute pathname of the parent directory where the
-#       original content of the <polydir> is available. The special entry
-#	$HOME_PARENT is supported to designate parent of user's home
-#	directory. This field cannot be blank and this directory cannot
-#	be a subdirectory of <polydir>.
-# 
 # <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"
@@ -44,7 +38,7 @@
 # for user root and adm for directory /tmp, where as home directories
 # are polyinstantiated for all users.
 #
-# /tmp	/		/		both		root,adm
+# /tmp	/		both		root,adm
 #
-# $HOME	$HOME_PARENT	$HOME_PARENT	context
+# $HOME	$HOME_PARENT	context
 # 
diff -Naurp Linux-PAM-0.99.3.0/modules/pam_namespace/pam_namespace.c Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/pam_namespace.c
--- Linux-PAM-0.99.3.0/modules/pam_namespace/pam_namespace.c	2006-02-17 22:26:41.000000000 +0000
+++ Linux-PAM-0.99.3.0-ns2/modules/pam_namespace/pam_namespace.c	2006-02-17 22:44:37.000000000 +0000
@@ -88,12 +88,28 @@ enum polymethod {
 };
 
 /*
+ * Depending on the application using this namespace module, we
+ * may need to unmount priviously bind mounted instance directory.
+ * Applications such as login and sshd, that establish a new 
+ * session unmount of instance directory is not needed. For applications
+ * such as su and newrole, that switch the identity, this module 
+ * has to unmount previous instance directory first and re-mount
+ * based on the new indentity. For other trusted applications that
+ * just want to undo polyinstantiation, only unmount of previous
+ * instance directory is needed.
+ */
+enum unmnt_op {
+    NO_UNMNT,
+    UNMNT_REMNT,
+    UNMNT_ONLY,
+};
+
+/*
  * Structure that holds information about a directory to polyinstantiate
  */
 struct polydir_s {
     char dir[PATH_MAX];    	       	/* directory to polyinstantiate */
     char instance_parent_dir[PATH_MAX]; /* parent dir of instance */
-    char orig_dir[PATH_MAX];  		/* original dir available at */
     enum polymethod method;		/* method used to polyinstantiate */
     unsigned int num_uids;		/* number of override uids */
     uid_t *uid;				/* list of override uids */
@@ -107,6 +123,7 @@ struct instance_data {
 	char user[LOGIN_NAME_MAX];	/* User name */
 	uid_t uid;			/* The uid of the user */
         int selinux_enabled;		/* If selinux is enabled */
+        int cnxt_based_inst;		/* If context based instance needed */
 };
 
 /*
@@ -133,7 +150,6 @@ static int add_polydir_entry(struct inst
     /* Make copy */
     strcpy(pent->dir, ent->dir);
     strcpy(pent->instance_parent_dir, ent->instance_parent_dir);
-    strcpy(pent->orig_dir, ent->orig_dir);
     pent->method = ent->method;
     pent->num_uids = ent->num_uids;
     if (ent->num_uids) {
@@ -170,8 +186,8 @@ static int add_polydir_entry(struct inst
 
         pam_syslog(idata->pamh, LOG_NOTICE, "Poly dirs so far");
         while (dptr) {
-            pam_syslog(idata->pamh, LOG_NOTICE, "%s %s %s %d", dptr->dir,
-                   dptr->instance_parent_dir, dptr->orig_dir, dptr->method);
+            pam_syslog(idata->pamh, LOG_NOTICE, "%s %s %d", dptr->dir,
+                   dptr->instance_parent_dir, 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;
@@ -208,7 +224,7 @@ static void del_polydir_list(struct poly
 static int process_line(char *line, const char *home, 
 			struct instance_data *idata)
 {
-    const char *dir, *instance_parent_dir, *orig_dir;
+    const char *dir, *instance_parent_dir;
     const char *method, *uids;
     char *tmp = strdupa(home);
     const char *parent_home_dir = dirname(tmp); /* parent of homedir */
@@ -259,11 +275,6 @@ static int process_line(char *line, cons
         pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line -- skipping");
         return 0;
     }
-    orig_dir = strtok_r(NULL, " \t", &tptr);
-    if (orig_dir == NULL) {
-        pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line -- skipping");
-        return 0;
-    }
     method = strtok_r(NULL, " \t", &tptr);
     if (method == NULL) {
         pam_syslog(idata->pamh, LOG_NOTICE, "Invalid line -- skipping");
@@ -294,53 +305,41 @@ static int process_line(char *line, cons
 	    instance_parent_dir = parent_home_dir;
     	else if (strcmp(instance_parent_dir, "$HOME") == 0)
     	    instance_parent_dir = home;
-    	if (strcmp(orig_dir, "$HOME_PARENT") == 0) 
-	    orig_dir = parent_home_dir;
-    	else if (strcmp(orig_dir, "$HOME") == 0)
-    	    orig_dir = home;
     }
 
     /*
      * Ensure that all pathnames are absolute path names.
      */
-    if ((dir[0] != '/') || (instance_parent_dir[0] != '/') ||
-					(orig_dir[0] != '/')) {
+    if ((dir[0] != '/') || (instance_parent_dir[0] != '/')) {
         pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must start with '/'");
         return 0;
     }
-    if (strstr(dir, "..") || strstr(instance_parent_dir, "..") ||
-					strstr(orig_dir, "..")) {
+    if (strstr(dir, "..") || strstr(instance_parent_dir, "..")) {
         pam_syslog(idata->pamh, LOG_NOTICE,"Pathnames must not have '..'");
         return 0;
     }
 
     /*
-     * Ensure that orig dir is not a subdirectory of the
-     * directory being polyinstantiated.
-     * Example - /abcdef and /abc 
-     */
-    if (strncmp(orig_dir, dir, strlen(dir)) == 0) {
-        if (idata->debug)
-            pam_syslog(idata->pamh, LOG_NOTICE,
-                "orig_dir %s cannot be inside the poly dir %s",
-                orig_dir, dir);
-        return 0;
-    }
-
-    /*
      * Populate polyinstantiated directory structure with appropriate
      * pathnames and the method with which to polyinstantiate.
      */
     strcpy(poly.dir, dir);
     strcpy(poly.instance_parent_dir, instance_parent_dir);
-    strcpy(poly.orig_dir, orig_dir);
     if (strcmp(method, "user") == 0)
         poly.method = USER;
 #ifdef WITH_SELINUX
-    else if (strcmp(method, "context") == 0)
-        poly.method = CONTEXT;
-    else if (strcmp(method, "both") == 0)
-        poly.method = BOTH;
+    else if (strcmp(method, "context") == 0) {
+        if (idata->cnxt_based_inst)
+            poly.method = CONTEXT;
+	else
+            poly.method = USER;
+    } else if (strcmp(method, "both") == 0) {
+        if (idata->cnxt_based_inst)
+            poly.method = BOTH;
+	else
+            poly.method = USER;
+    }
+
 #endif
     else {
         pam_syslog(idata->pamh, LOG_NOTICE, "Illegal method - skipping");
@@ -496,7 +495,7 @@ static int ns_override(struct polydir_s 
 #ifdef WITH_SELINUX
 static int poly_name(const struct polydir_s *polyptr, char **i_name,
 	security_context_t *i_context, security_context_t *origcon,
-	struct instance_data *idata)
+        struct instance_data *idata)
 #else
 static int poly_name(const struct polydir_s *polyptr, char **i_name, 
 	struct instance_data *idata)
@@ -554,8 +553,8 @@ static int poly_name(const struct polydi
         } else if (idata->debug)
     	    pam_syslog(idata->pamh, LOG_NOTICE, 
 		    "member context returned by policy %s", *i_context);
+	freecon(scon);
     }
-    freecon(scon);
 #endif
     rc = PAM_SUCCESS;
 
@@ -614,17 +613,15 @@ static int poly_name(const struct polydi
 
 
 /*
- * Create polyinstantiated instance directory (ipath) and orig directory
- * (opath), where the original "un-polyinstantiated" contents would be
- * available to authorized processes.
+ * Create polyinstantiated instance directory (ipath).
  */
 #ifdef WITH_SELINUX
-static int create_dirs(const struct polydir_s *polyptr, char *opath,
-	char *ipath, security_context_t icontext,
-	security_context_t ocontext, struct instance_data *idata)
+static int create_dirs(const struct polydir_s *polyptr, char *ipath, 
+        security_context_t icontext, security_context_t ocontext,
+	struct instance_data *idata)
 #else
-static int create_dirs(const struct polydir_s *polyptr, char *opath,
-	char *ipath, struct instance_data *idata)
+static int create_dirs(const struct polydir_s *polyptr, char *ipath,
+	struct instance_data *idata)
 #endif
 {
     struct stat statbuf, newstatbuf;
@@ -632,7 +629,7 @@ static int create_dirs(const struct poly
 
     /*
      * stat the directory to polyinstantiate, so its owner-group-mode
-     * can be propagated to orig and instance directories
+     * can be propagated to instance directory
      */
     if (stat(polyptr->dir, &statbuf) < 0) {
         if (idata->debug)
@@ -651,71 +648,6 @@ static int create_dirs(const struct poly
     }
 
     /*
-     * Create orig directory, set its security context, mode and
-     * ownership attributes to match that of the original directory
-     * that is being polyinstantiated.
-     */
-    if (mkdir(opath, S_IRUSR) < 0) { /* Create with no access */
-        if (errno != EEXIST) {
-            if (idata->debug)
-                pam_syslog(idata->pamh, LOG_ERR, "Error creating %s, %s",
-			opath, strerror(errno));
-            return PAM_SESSION_ERR;
-        }
-    }
-
-    /* Open a descriptor to it to prevent races */
-    fd = open(opath, O_DIRECTORY | O_RDONLY);
-    if (fd < 0) {
-	pam_syslog(idata->pamh, LOG_ERR, "Error opening %s, %s", opath,
-		strerror(errno));
-	return PAM_SESSION_ERR;
-    }
-#ifdef WITH_SELINUX
-    /* If SE Linux is disabled, no need to label it */
-    if (idata->selinux_enabled > 0) {
-        if (fsetfilecon(fd, ocontext) < 0) {
-            if (idata->debug)
-                pam_syslog(idata->pamh, LOG_ERR,
-			"Error setting context of %s to %s", opath, ocontext);
-	    close(fd);
-            return PAM_SESSION_ERR;
-        }
-    }
-#endif
-    /* 
-     * In case this directory currently exists and someone is logging in
-     * for a second session, see if the owner/group is correct. Setting the
-     * owner will reset the sticky bit and others. This could cause 
-     * unexpected and hard to troubleshoot problems.
-     */
-    if (fstat(fd, &newstatbuf) < 0) {
-        if (idata->debug)
-            pam_syslog(idata->pamh, LOG_ERR, "Error stating %s, %s",
-		opath, strerror(errno));
-        return PAM_SESSION_ERR;
-    }
-    if (newstatbuf.st_uid != statbuf.st_uid ||
-			 newstatbuf.st_gid != statbuf.st_gid) {
-        if (fchown(fd, statbuf.st_uid, statbuf.st_gid) < 0) {
-            if (idata->debug)
-                pam_syslog(idata->pamh, LOG_ERR,
-			"Error changing owner for %s, %s",
-			opath, strerror(errno));
-	    close(fd);
-            return PAM_SESSION_ERR;
-        }
-    }
-    if (fchmod(fd, statbuf.st_mode & 07777) < 0) {
-        if (idata->debug)
-            pam_syslog(idata->pamh, LOG_ERR, "Error changing mode for %s, %s",
-			opath, strerror(errno));
-	close(fd);
-        return PAM_SESSION_ERR;
-    }
-    close(fd);
-
-    /*
      * Create instance directory and set its security context to the context
      * returned by the security policy. Set its mode and ownership
      * attributes to match that of the original directory that is being
@@ -792,24 +724,23 @@ static int create_dirs(const struct poly
 
 /*
  * This function performs the namespace setup for a particular directory
- * that is being polyinstantiated. It creates MD5 hashes of orig and
- * instance directories, calls create_dirs to create them with appropriate
- * security attributes, and performs bind mounts to setup the process
+ * that is being polyinstantiated. It creates an MD5 hash of instance 
+ * directory, calls create_dirs to create it with appropriate
+ * security attributes, and performs bind mount to setup the process
  * namespace.
  */
 static int ns_setup(const struct polydir_s *polyptr,
 	struct instance_data *idata)
 {
     int i, retval = 0;
-    char *origname = NULL, *orig_path = NULL;
     char *inst_parent_dir = NULL;
-    char *md5orig = NULL, *md5inst = NULL, *instname = NULL;
+    char *md5inst = NULL, *instname = NULL;
     char *to, *dir, *lastchr;
 #ifdef WITH_SELINUX
     security_context_t instcontext = NULL, origcontext = NULL;
 #endif
     unsigned char inst_digest[MD5_DIGEST_LENGTH];
-    unsigned char orig_digest[MD5_DIGEST_LENGTH];
+    int username = (polyptr->method == USER) || (polyptr->method == BOTH);
 
     if (idata->debug)
         pam_syslog(idata->pamh, LOG_NOTICE,
@@ -819,25 +750,14 @@ static int ns_setup(const struct polydir
     if (dir && strlen(dir) > 1)
         dir++;
 
-    if (strcmp(polyptr->orig_dir, "/") == 0) {
-       if (asprintf(&origname, "/.%s-poly-orig", dir) < 0)
-           goto error_out;
-    } else {
-       if (asprintf(&origname, "%s/.%s-poly-orig", polyptr->orig_dir, dir) < 0)
-           goto error_out;
-    }
-
-    if (idata->debug)
-        pam_syslog(idata->pamh, LOG_NOTICE, "origname %s", origname);
-
     /*
-     * Obtain names of orig and instance pathnames based on the
+     * Obtain the name of instance pathname based on the
      * polyinstantiation method and instance context returned by
      * security policy.
      */
 #ifdef WITH_SELINUX
     retval = poly_name(polyptr, &instname, &instcontext,
-                          &origcontext, idata);
+			&origcontext, idata);
 #else
     retval = poly_name(polyptr, &instname, idata);
 #endif
@@ -850,21 +770,14 @@ static int ns_setup(const struct polydir
 #ifdef WITH_SELINUX
         if (idata->debug && idata->selinux_enabled > 0)
             pam_syslog(idata->pamh, LOG_ERR,"Inst context %s Orig context %s",
-                   instcontext, origcontext);
+		 instcontext, origcontext);
 #endif
     }
 
     /*
-     * Create MD5 hashes for instance and orig_dir pathnames.
+     * Create MD5 hashes for instance pathname.
      */
 
-    if (MD5((unsigned char*)origname, strlen((char*)origname),
-		orig_digest) == NULL) {
-        if (idata->debug)
-            pam_syslog(idata->pamh, LOG_ERR, 
-		"Unable to generate hash for origname");
-        goto error_out;
-    }
     if (MD5((unsigned char*)instname, strlen((char*)instname),
 		inst_digest) == NULL) {
         if (idata->debug)
@@ -873,12 +786,6 @@ static int ns_setup(const struct polydir
         goto error_out;
     }
 
-    if ((md5orig = (char *) malloc(MD5_DIGEST_LENGTH * 2 + 1)) == NULL) {
-        if (idata->debug)
-            pam_syslog(idata->pamh, LOG_ERR, 
-		"Unable to allocate buffer");
-        goto error_out;
-    }
     if ((md5inst = (char *) malloc(MD5_DIGEST_LENGTH * 2 + 1)) == NULL) {
         if (idata->debug)
             pam_syslog(idata->pamh, LOG_ERR, 
@@ -886,27 +793,12 @@ static int ns_setup(const struct polydir
         goto error_out;
     }
 
-    to = md5orig;
-    for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
-        char c[3];
-        snprintf(c, 3, "%02x", (unsigned int)orig_digest[i]);
-        to = stpcpy(to, c);
-    }
-
     /*
-     * In the case where orig or instance path is just / or has a trailing
-     * /, we should not include an extra / in the asprintfs below. It messes
+     * 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
      */
-    lastchr = polyptr->orig_dir + strlen(polyptr->orig_dir) - 1;
-    if (*lastchr == '/') {
-        if(asprintf(&orig_path, "%s.poly-%s", polyptr->orig_dir, md5orig) < 0)
-		goto error_out;
-    } else {
-        if(asprintf(&orig_path, "%s/.poly-%s", polyptr->orig_dir, md5orig) < 0)
-		goto error_out;
-    }
 
     to = md5inst;
     for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
@@ -918,46 +810,35 @@ static int ns_setup(const struct polydir
     lastchr = polyptr->instance_parent_dir +
 			 strlen(polyptr->instance_parent_dir) - 1;
     if (*lastchr == '/') {
-        if (asprintf(&inst_parent_dir, "%s.inst-%s",
-			polyptr->instance_parent_dir, md5inst) < 0)
+        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",
-			polyptr->instance_parent_dir, md5inst) < 0)
+        if (asprintf(&inst_parent_dir, "%s/.inst-%s-%s",
+		polyptr->instance_parent_dir, username ? idata->user : "",
+                md5inst) < 0)
 		goto error_out;
     }
 
-    if (idata->debug) {
-        pam_syslog(idata->pamh, LOG_NOTICE, "orig %s", orig_path);
+    if (idata->debug)
         pam_syslog(idata->pamh, LOG_NOTICE, "instance_parent_dir %s",
 		inst_parent_dir);
-    }
 
     /*
-     * Create orig and instance directories with appropriate security
+     * Create instance directory with appropriate security
      * contexts, owner, group and mode bits.
      */
 #ifdef WITH_SELINUX
-    retval = create_dirs(polyptr, orig_path, inst_parent_dir, instcontext,
-                         origcontext, idata);
+    retval = create_dirs(polyptr, inst_parent_dir, instcontext,
+			 origcontext, idata);
 #else
-    retval = create_dirs(polyptr, orig_path, inst_parent_dir, idata);
+    retval = create_dirs(polyptr, inst_parent_dir, idata);
 #endif
 
     if (retval < 0) {
         if (idata->debug)
-            pam_syslog(idata->pamh,LOG_ERR,"Error creating instance/orig dirs");
-        goto error_out;
-    }
-
-    /*
-     * Bind mount polyinstantiated directory on orig path so it can
-     * be available from that alternate location to authorized trusted
-     * programs.
-     */
-    if (mount(polyptr->dir, orig_path, NULL, MS_BIND, NULL) < 0) {
-        pam_syslog(idata->pamh, LOG_ERR, "Error mounting %s on %s, %s",
-                   polyptr->dir, orig_path, strerror(errno));
+            pam_syslog(idata->pamh,LOG_ERR,"Error creating instance dir");
         goto error_out;
     }
 
@@ -967,7 +848,6 @@ static int ns_setup(const struct polydir
      * based on polyinstantiated method.
      */
     if (mount(inst_parent_dir, polyptr->dir, NULL, MS_BIND, NULL) < 0) {
-// FIXME: should an unmount be attempted since above succeeded?
         pam_syslog(idata->pamh, LOG_ERR, "Error mounting %s on %s, %s",
                    inst_parent_dir, polyptr->dir, strerror(errno));
         goto error_out;
@@ -984,11 +864,8 @@ error_out:
 
 cleanup:
     free(md5inst);
-    free(md5orig);
     free(inst_parent_dir);
-    free(orig_path);
     free(instname);
-    free(origname);
 #ifdef WITH_SELINUX
     freecon(instcontext);
     freecon(origcontext);
@@ -1027,129 +904,12 @@ static int cwd_in(char *dir, struct inst
 
 
 /*
- * This function reads /proc/mounts file to obtain names of mount points
- * of all "orig" directories, where original contents of polyinstantiated
- * directories are available to trusted programs. Once the names are read
- * from /proc/mounts, umount system call is invoked for each of these
- * orig directories.
- */
-static int unmount_orig_dirs(struct instance_data *idata)
-{
-    int i, retval = PAM_SERVICE_ERR, changing_dir;
-    size_t len = 0;
-    FILE *procmounts;
-    char mntdir[PATH_MAX];
-    char *line, *mntpt, *mntpt_name, *mntpt_parent, *fptr, *cptr;
-
-    if (idata->debug)
-        pam_syslog(idata->pamh, LOG_NOTICE, 
-		"Attempting unmount of all orig dirs");
-
-    /*
-     * Open /proc/mounts file, read one line at a time, isolate
-     * mount point name (2nd string), and if starts with ".poly-"
-     * try and unmount it.
-     */
-    procmounts = fopen(PROC_MNTS, "r");
-    if (procmounts == NULL) {
-        pam_syslog(idata->pamh, LOG_ERR, "Error opening %s, %s", PROC_MNTS,
-		strerror(errno));
-        goto bad_file;
-    }
-
-    if ((mntpt = (char *) malloc(PATH_MAX)) == NULL) {
-        pam_syslog(idata->pamh, LOG_ERR, 
-		"Error allocating buffer to hold pathname");
-        goto bad_alloc_mnt;
-    }
-    if ((mntpt_parent = (char *) malloc(PATH_MAX)) == NULL) {
-        pam_syslog(idata->pamh, LOG_ERR, 
-		"Error allocating buffer to hold pathname");
-        goto bad_alloc_mntparent;
-    }
-
-    /* Use unlocked IO */
-    __fsetlocking(procmounts, FSETLOCKING_BYCALLER);
-
-    while (getline(&line, &len, procmounts) > 0) {
-        if ((i = sscanf(line, "%s%s", mntdir, mntpt)) != 2) {
-            pam_syslog(idata->pamh, LOG_ERR, "Error parsing mount entry %s",
-			PROC_MNTS);
-            goto bad_umnt;
-	}
-        if ((mntpt_name = strrchr(mntpt, '/')) != NULL) {
-            strcpy(mntpt_parent, mntpt);
-            if (strncmp(mntpt_name, "/.poly-", 7) == 0) {
-                /*
-                 * Check to see if process current directory is in the
-                 * bind mounted orig directory that we are trying to
-                 * umount
-                 */
-                if ((changing_dir = cwd_in(mntpt, idata)) < 0) {
-                    goto bad_umnt;
-                } else if (changing_dir) {
-                    if (idata->debug)
-                        pam_syslog(idata->pamh, LOG_NOTICE, "changing cwd");
-
-                    /*
-                     * Change current working directory to the parent of
-                     * the mount point, that is parent of the orig
-                     * directory where original contents of the polydir
-                     * are available from
-                     */
-                    strcpy(mntpt_parent, mntpt);
-    	            fptr = strchr(mntpt_parent, '/');
-    	            cptr = strrchr(mntpt_parent, '/');
-    	            if (fptr && cptr && (fptr == cptr))
-    		        strcpy(mntpt_parent, "/");
-    	            else if (cptr)
-    		        *cptr = '\0';
-
-                    if (chdir(mntpt_parent) < 0) {
-                        pam_syslog(idata->pamh, LOG_ERR,
-				"unable to chdir to %s, %s",
-                               mntpt_parent, strerror(errno));
-                    	goto bad_umnt;
-                    }
-                }
-
-                /*
-                 * Now try and umount
-                 */
-                if (umount(mntpt) < 0) {
-                    pam_syslog(idata->pamh, LOG_ERR, "Umount failed for %s, %s",
-                           mntpt, strerror(errno));
-                    goto bad_umnt;
-                } else {
-                    if (idata->debug)
-                        pam_syslog(idata->pamh, LOG_NOTICE, 
-				"umounted orig dir %s",
-                               mntpt);
-                }
-            }
-        }
-    }
-    retval = PAM_SUCCESS;
-
-bad_umnt:
-    free(line);
-    free(mntpt_parent);
-bad_alloc_mntparent:
-    free(mntpt);
-bad_alloc_mnt:
-    fclose(procmounts);
-bad_file:
-    return retval;
-}
-
-
-/*
  * This function checks to see if polyinstantiation is needed for any
  * of the directories listed in the configuration file. If needed,
  * cycles through all polyinstantiated directory entries and calls
  * ns_setup to setup polyinstantiation for each one of them.
  */
-static int setup_namespace(struct instance_data *idata, int unmnt_first)
+static int setup_namespace(struct instance_data *idata, enum unmnt_op unmnt)
 {
     int retval = 0, need_poly = 0, changing_dir = 0;
     char *cptr, *fptr, poly_parent[PATH_MAX];
@@ -1195,20 +955,6 @@ static int setup_namespace(struct instan
         return PAM_SUCCESS;
 
     /*
-     * If need to unmount previously bind mounted polyinstantiated
-     * directories, call unmount_orig_dirs to unmount polyinstantiated
-     * directories from their alternate location where they were available
-     * to trusted programs.
-     */
-    if (unmnt_first) {
-        if ((retval = unmount_orig_dirs(idata)) < 0) {
-            return PAM_SESSION_ERR;
-        } else if (idata->debug)
-            pam_syslog(idata->pamh, LOG_NOTICE,
-			"Unmount of orig directories succeeded");
-    }
-
-    /*
      * Again cycle through all polyinstantiated directories, this time,
      * call ns_setup to setup polyinstantiation for a particular entry.
      */
@@ -1221,7 +967,7 @@ static int setup_namespace(struct instan
 			"Setting poly ns for user %d for dir %s",
                       idata->uid, pptr->dir);
 
-            if (unmnt_first) {
+            if ((unmnt == UNMNT_REMNT) || (unmnt == UNMNT_ONLY)) {
                 /*
                  * Check to see if process current directory is in the
                  * bind mounted instance_parent directory that we are trying to
@@ -1262,9 +1008,11 @@ static int setup_namespace(struct instan
 				pptr->dir);
             }
 
-            retval = ns_setup(pptr, idata);
-            if (retval != PAM_SUCCESS) 
-                break;
+	    if (unmnt != UNMNT_ONLY) {
+                retval = ns_setup(pptr, idata);
+                if (retval != PAM_SUCCESS) 
+                     break;
+	    }
         }
     }
 
@@ -1274,12 +1022,10 @@ static int setup_namespace(struct instan
 
 /*
  * Orig namespace. This function is called from when closing a pam
- * session. If authorized, it unmounts instance_parent directory and orig
- * directory (where original directory was bind mounted).
+ * session. If authorized, it unmounts instance_parent directory.
  */
 static int orig_namespace(struct instance_data *idata)
 {
-    int retval;
     struct polydir_s *pptr;
 
     if (idata->debug)
@@ -1310,19 +1056,34 @@ static int orig_namespace(struct instanc
 			pptr->dir);
         }
     }
+    return 0;
+}
 
-    /*
-     * Call unmount_orig_dirs to unmount polyinstantiated directories
-     * from their alternate location where they were available to trusted
-     * programs.
-     */
-    retval = unmount_orig_dirs(idata);
-    if (retval < 0 && idata->debug)
-        pam_syslog(idata->pamh, LOG_NOTICE,
-			"Unmount of orig directories succeeded");
 
-    return retval;
+#ifdef WITH_SELINUX
+/*
+ * This function checks if the calling program has requested context
+ * change by calling setexeccon(). If context change is not requested
+ * then it does not make sense to polyinstantiate based on context.
+ * The return value from this function is used when selecting the 
+ * polyinstantiation method. If context change is not requested then
+ * the polyinstantiation method is set to USER, even if the configuration
+ * file lists the method as "context" or "both".
+ */
+static int cnxt_based_inst_needed(void)
+{
+    security_context_t scon = NULL;
+    int rc = 0;
+
+    rc = getexeccon(&scon);
+    if (rc < 0 || scon == NULL)
+        return 0;
+    else {
+        freecon(scon);
+        return 1;
+    }
 }
+#endif
 
 
 /*
@@ -1331,10 +1092,11 @@ static int orig_namespace(struct instanc
 PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
                                    int argc, const char **argv)
 {
-    int i, unmnt_first = 0, retval;
+    int i, retval;
     struct instance_data idata;
     char *user_name;
     struct passwd *pwd;
+    enum unmnt_op unmnt = NO_UNMNT;
 
     /* init instance data */
     idata.debug = 0;
@@ -1342,16 +1104,20 @@ PAM_EXTERN int pam_sm_open_session(pam_h
     idata.pamh = pamh;
 #ifdef WITH_SELINUX
     idata.selinux_enabled = is_selinux_enabled();
+    idata.cnxt_based_inst = cnxt_based_inst_needed();
 #else
     idata.selinux_enabled = 0;
+    idata.cnxt_based_inst = 0;
 #endif
 
     /* Parse arguments. */
     for (i = 0; i < argc; i++) {
         if (strcmp(argv[i], "debug") == 0)
             idata.debug = 1;
-        if (strcmp(argv[i], "unmnt_first") == 0)
-            unmnt_first = 1;
+        if (strcmp(argv[i], "unmnt_remnt") == 0)
+            unmnt = UNMNT_REMNT;
+        if (strcmp(argv[i], "unmnt_only") == 0)
+            unmnt = UNMNT_ONLY;
 	if (strcmp(argv[i], "require_selinux") == 0) {
 		if (idata.selinux_enabled != 1) {
         		pam_syslog(idata.pamh, LOG_ERR, 
@@ -1397,7 +1163,7 @@ PAM_EXTERN int pam_sm_open_session(pam_h
     }
 
     if (idata.polydirs_ptr) {
-        retval = setup_namespace(&idata, unmnt_first);
+        retval = setup_namespace(&idata, unmnt);
         if (idata.debug) {
             if (retval)
                 pam_syslog(idata.pamh, LOG_NOTICE,
@@ -1431,8 +1197,10 @@ PAM_EXTERN int pam_sm_close_session(pam_
     idata.pamh = pamh;
 #ifdef WITH_SELINUX
     idata.selinux_enabled = is_selinux_enabled();
+    idata.cnxt_based_inst = cnxt_based_inst_needed();
 #else
     idata.selinux_enabled = 0;
+    idata.cnxt_based_inst = 0;
 #endif
 
     /* Parse arguments. */





More information about the redhat-lspp mailing list