Blame SOURCES/oddjob-override-mask-fix.patch

fd9c3f
From b800e25258353dbb1a88506123c21ac3298fd2d0 Mon Sep 17 00:00:00 2001
fd9c3f
From: Carlos Santos <casantos@redhat.com>
fd9c3f
Date: Tue, 18 Oct 2022 08:59:16 -0300
fd9c3f
Subject: [PATCH 2/2] Always set the home directory permissions according to
fd9c3f
 HOME_MODE
fd9c3f
fd9c3f
Currently the home directory permissions are set by taking the /etc/skel
fd9c3f
mode and masking it with HOME_MODE:
fd9c3f
fd9c3f
    override_umask = 0777 & ~get_umask(&configured_umask, "HOME_MODE");
fd9c3f
    stat(skel, &sb); /* performed by nftw() */
fd9c3f
    oddjob_selinux_mkdir(newpath, sb->st_mode & ~override_umask, uid, gid);
fd9c3f
fd9c3f
The problem is that when HOME_MODE is more permissive than /etc/skel,
fd9c3f
the masking will not produce the desired result, e.g.
fd9c3f
fd9c3f
    skel_mode = 0755
fd9c3f
    HOME_MODE = 0775
fd9c3f
    override_umask = 0777 & ~HOME_MODE /* 0002 */
fd9c3f
    mode = skel_mode & ~override_umask /* 0755 & 0775 = 0755 */
fd9c3f
fd9c3f
In order to fix the problem, always use 0777 & ~override_umask for the
fd9c3f
top home directory.
fd9c3f
fd9c3f
Signed-off-by: Carlos Santos <casantos@redhat.com>
fd9c3f
Fixes: https://pagure.io/oddjob/issue/17
fd9c3f
---
fd9c3f
 src/mkhomedir.c | 45 +++++++++++++++++++++------------------------
fd9c3f
 1 file changed, 21 insertions(+), 24 deletions(-)
fd9c3f
fd9c3f
diff --git a/src/mkhomedir.c b/src/mkhomedir.c
fd9c3f
index ac813a9..932918f 100644
fd9c3f
--- a/src/mkhomedir.c
fd9c3f
+++ b/src/mkhomedir.c
fd9c3f
@@ -67,6 +67,7 @@ copy_single_item(const char *source, const struct stat *sb,
fd9c3f
 {
fd9c3f
 	uid_t uid = pwd->pw_uid;
fd9c3f
 	gid_t gid = pwd->pw_gid;
fd9c3f
+	mode_t mode = sb->st_mode & ~override_umask;
fd9c3f
 	int sfd, dfd, i, res;
fd9c3f
 	char target[PATH_MAX + 1], newpath[PATH_MAX + 1];
fd9c3f
 	unsigned char buf[BUFSIZ];
fd9c3f
@@ -112,8 +113,7 @@ copy_single_item(const char *source, const struct stat *sb,
fd9c3f
 			oddjob_set_selinux_file_creation_context(newpath,
fd9c3f
 								 sb->st_mode |
fd9c3f
 								 S_IFREG);
fd9c3f
-			dfd = open(newpath, O_WRONLY | O_CREAT | O_EXCL,
fd9c3f
-				   sb->st_mode & ~override_umask);
fd9c3f
+			dfd = open(newpath, O_WRONLY | O_CREAT | O_EXCL, mode);
fd9c3f
 			if (dfd != -1) {
fd9c3f
 				while ((i = read(sfd, buf, sizeof(buf))) > 0) {
fd9c3f
 					retry_write(dfd, buf, i);
fd9c3f
@@ -156,20 +156,22 @@ copy_single_item(const char *source, const struct stat *sb,
fd9c3f
 		}
fd9c3f
 		return 0;
fd9c3f
 	case FTW_D:
fd9c3f
-		/* It's the home directory itself. Don't give it to the
fd9c3f
-		 * target user just yet to avoid potential race conditions
fd9c3f
-		 * involving symlink attacks when we copy over the skeleton
fd9c3f
-		 * tree. */
fd9c3f
-		if (status->level == 0 && !owner_mkdir_first) {
fd9c3f
-			uid = 0;
fd9c3f
-			gid = 0;
fd9c3f
-		}
fd9c3f
-
fd9c3f
 		/* It's a directory.  Make one with the same name and
fd9c3f
 		 * permissions, but owned by the target user. */
fd9c3f
-		res = oddjob_selinux_mkdir(newpath,
fd9c3f
-					   sb->st_mode & ~override_umask,
fd9c3f
-					   uid, gid);
fd9c3f
+		if (status->level == 0) {
fd9c3f
+			/* It's the home directory itself.  Use the configured
fd9c3f
+			 * (or overriden) mode, not the source mode & umask. */
fd9c3f
+			mode = 0777 & ~override_umask;
fd9c3f
+
fd9c3f
+			/* Don't give it to the target user just yet to avoid
fd9c3f
+			 * potential race conditions involving symlink attacks
fd9c3f
+			 * when we copy over the skeleton tree. */
fd9c3f
+			if (!owner_mkdir_first) {
fd9c3f
+				uid = 0;
fd9c3f
+				gid = 0;
fd9c3f
+			}
fd9c3f
+		}
fd9c3f
+		res = oddjob_selinux_mkdir(newpath, mode, uid, gid);
fd9c3f
 
fd9c3f
 		/* on unexpected errors, or if the home directory itself
fd9c3f
 		 * suddenly already exists, abort the copy operation. */
fd9c3f
@@ -248,12 +250,8 @@ mkhomedir(const char *user, int flags)
fd9c3f
 
fd9c3f
 				return res;
fd9c3f
 			} else {
fd9c3f
-				if (stat(skel, &st) != 0) {
fd9c3f
-					st.st_mode = S_IRWXU;
fd9c3f
-				}
fd9c3f
 				if ((oddjob_selinux_mkdir(pwd->pw_dir,
fd9c3f
-							  st.st_mode &
fd9c3f
-							  ~override_umask,
fd9c3f
+							  0777 & ~override_umask,
fd9c3f
 							  pwd->pw_uid,
fd9c3f
 							  pwd->pw_gid) != 0) &&
fd9c3f
 				    (errno != EEXIST)) {
fd9c3f
@@ -269,11 +267,11 @@ mkhomedir(const char *user, int flags)
fd9c3f
 }
fd9c3f
 
fd9c3f
 static mode_t
fd9c3f
-get_umask(int *configured, const char *variable)
fd9c3f
+get_umask(int *configured, const char *variable, mode_t default_value)
fd9c3f
 {
fd9c3f
 	FILE *fp;
fd9c3f
 	char buf[BUFSIZ], *p, *end;
fd9c3f
-	mode_t mask = umask(0777);
fd9c3f
+	mode_t mask = default_value;
fd9c3f
 	long tmp;
fd9c3f
 	size_t vlen = strlen(variable);
fd9c3f
 
fd9c3f
@@ -315,11 +313,10 @@ main(int argc, char **argv)
fd9c3f
 
fd9c3f
 	openlog(PACKAGE "-mkhomedir", LOG_PID, LOG_DAEMON);
fd9c3f
 	/* Unlike UMASK, HOME_MODE is the file mode, so needs to be reverted */
fd9c3f
-	override_umask = 0777 & ~get_umask(&configured_umask, "HOME_MODE");
fd9c3f
+	override_umask = 0777 & ~get_umask(&configured_umask, "HOME_MODE", 0);
fd9c3f
 	if (configured_umask == 0) {
fd9c3f
-		override_umask = get_umask(&configured_umask, "UMASK");
fd9c3f
+		override_umask = get_umask(&configured_umask, "UMASK", 022);
fd9c3f
 	}
fd9c3f
-	umask(override_umask);
fd9c3f
 	skel_dir = "/etc/skel";
fd9c3f
 
fd9c3f
 	while ((i = getopt(argc, argv, "nqfs:u:")) != -1) {
fd9c3f
-- 
fd9c3f
2.38.1
fd9c3f