changeset 8037:ab1c170b1559 HEAD

Use permissions based on mail root directory when creating new files/dirs under it.
author Timo Sirainen <tss@iki.fi>
date Sun, 20 Jul 2008 23:20:19 +0300
parents b3303b65c3f2
children dc280df713f4
files src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/index-storage.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-util.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/list/mailbox-list-fs.c src/lib-storage/list/subscription-file.c src/lib-storage/mailbox-list.c src/lib-storage/mailbox-list.h src/plugins/quota/quota-maildir.c
diffstat 11 files changed, 130 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/cydir/cydir-storage.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Sun Jul 20 23:20:19 2008 +0300
@@ -130,7 +130,12 @@
 
 static int create_cydir(struct mail_storage *storage, const char *path)
 {
-	if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
+	mode_t mode;
+	gid_t gid;
+
+	mailbox_list_get_dir_permissions(storage->list, &mode, &gid);
+	if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) < 0 &&
+	    errno != EEXIST) {
 		if (!mail_storage_set_error_from_errno(storage)) {
 			mail_storage_set_critical(storage,
 				"mkdir(%s) failed: %m", path);
--- a/src/lib-storage/index/dbox/dbox-storage.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Sun Jul 20 23:20:19 2008 +0300
@@ -146,7 +146,12 @@
 
 static int create_dbox(struct mail_storage *storage, const char *path)
 {
-	if (mkdir_parents(path, CREATE_MODE) < 0 && errno != EEXIST) {
+	mode_t mode;
+	gid_t gid;
+
+	mailbox_list_get_dir_permissions(storage->list, &mode, &gid);
+	if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) < 0 &&
+	    errno != EEXIST) {
 		if (!mail_storage_set_error_from_errno(storage)) {
 			mail_storage_set_critical(storage,
 				"mkdir(%s) failed: %m", path);
--- a/src/lib-storage/index/index-storage.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/index/index-storage.c	Sun Jul 20 23:20:19 2008 +0300
@@ -17,8 +17,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#define CREATE_MODE 0770 /* umask() should limit it more */
-
 #define DEFAULT_CACHE_FIELDS ""
 #define DEFAULT_NEVER_CACHE_FIELDS "imap.envelope"
 
@@ -69,9 +67,38 @@
 	i_free(list);
 }
 
+static int stat_parent(struct mail_storage *storage, const char *path,
+		       mode_t *mode_r, gid_t *gid_r)
+{
+	struct stat st;
+	const char *p;
+
+	while ((p = strrchr(path, '/')) != NULL) {
+		path = t_strdup_until(path, p);
+		if (stat(path, &st) == 0) {
+			*mode_r = st.st_mode;
+			*gid_r = (st.st_mode & S_ISGID) != 0 ||
+				st.st_gid == getegid() ?
+				(gid_t)-1 : st.st_gid;
+			return 0;
+		}
+		if (errno != ENOENT) {
+			mail_storage_set_critical(storage,
+						  "stat(%s) failed: %m", path);
+			return -1;
+		}
+	}
+	/* use default permissions */
+	*mode_r = 0700;
+	*gid_r = (gid_t)-1;
+	return 0;
+}
+
 static int create_index_dir(struct mail_storage *storage, const char *name)
 {
 	const char *root_dir, *index_dir;
+	mode_t mode;
+	gid_t gid;
 
 	root_dir = mailbox_list_get_path(storage->list, name,
 					 MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -80,7 +107,12 @@
 	if (strcmp(index_dir, root_dir) == 0 || *index_dir == '\0')
 		return 0;
 
-	if (mkdir_parents(index_dir, CREATE_MODE) < 0 && errno != EEXIST) {
+	/* get permissions from the parent directory */
+	if (stat_parent(storage, index_dir, &mode, &gid) < 0)
+		return -1;
+
+	if (mkdir_parents_chown(index_dir, mode, (uid_t)-1, gid) < 0 &&
+	    errno != EEXIST) {
 		mail_storage_set_critical(storage, "mkdir(%s) failed: %m",
 					  index_dir);
 		return -1;
--- a/src/lib-storage/index/maildir/maildir-storage.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Sun Jul 20 23:20:19 2008 +0300
@@ -21,8 +21,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#define CREATE_MODE 0777 /* umask() should limit it more */
-
 #define MAILDIR_PLUSPLUS_DRIVER_NAME "maildir++"
 #define MAILDIR_SUBFOLDER_FILENAME "maildirfolder"
 
@@ -290,7 +288,7 @@
 }
 
 static int mkdir_verify(struct mail_storage *storage,
-			const char *dir, bool verify)
+			const char *dir, mode_t mode, gid_t gid, bool verify)
 {
 	struct stat st;
 
@@ -305,7 +303,7 @@
 		}
 	}
 
-	if (mkdir_parents(dir, CREATE_MODE) == 0)
+	if (mkdir_parents_chown(dir, mode, (uid_t)-1, gid) == 0)
 		return 0;
 
 	if (errno == EEXIST) {
@@ -355,8 +353,10 @@
 
 /* create or fix maildir, ignore if it already exists */
 static int create_maildir(struct mail_storage *storage,
-			  const char *dir, bool verify)
+			  const char *dir, mode_t mode, gid_t gid, bool verify)
 {
+	const char *path;
+	unsigned int i;
 	int ret;
 
 	ret = maildir_check_tmp(storage, dir);
@@ -372,12 +372,11 @@
 		return -1;
 
 	/* doesn't exist, create */
-	if (mkdir_verify(storage, t_strconcat(dir, "/cur", NULL), verify) < 0)
-		return -1;
-	if (mkdir_verify(storage, t_strconcat(dir, "/new", NULL), verify) < 0)
-		return -1;
-	if (mkdir_verify(storage, t_strconcat(dir, "/tmp", NULL), verify) < 0)
-		return -1;
+	for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
+		path = t_strconcat(dir, "/", maildir_subdirs[i], NULL);
+		if (mkdir_verify(storage, path, mode, gid, verify) < 0)
+			return -1;
+	}
 	return 0;
 }
 
@@ -474,6 +473,8 @@
 	struct maildir_storage *storage = (struct maildir_storage *)_storage;
 	const char *path;
 	struct stat st;
+	mode_t mode;
+	gid_t gid;
 	int ret;
 
 	if (input != NULL) {
@@ -488,7 +489,8 @@
 	if (strcmp(name, "INBOX") == 0 &&
 	    (_storage->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
 		/* INBOX always exists */
-		if (create_maildir(_storage, path, TRUE) < 0)
+		mailbox_list_get_dir_permissions(_storage->list, &mode, &gid);
+		if (create_maildir(_storage, path, mode, gid, TRUE) < 0)
 			return NULL;
 		return maildir_open(storage, "INBOX", flags);
 	}
@@ -506,7 +508,8 @@
 	/* tmp/ directory doesn't exist. does the maildir? */
 	if (stat(path, &st) == 0) {
 		/* yes, we'll need to create the missing dirs */
-		if (create_maildir(_storage, path, TRUE) < 0)
+		mailbox_list_get_dir_permissions(_storage->list, &mode, &gid);
+		if (create_maildir(_storage, path, mode, gid, TRUE) < 0)
 			return NULL;
 
 		return maildir_open(storage, name, flags);
@@ -526,7 +529,6 @@
 {
 	const char *path;
 	mode_t old_mask;
-	unsigned int i;
 	int fd;
 
 	/* add the execute bit if either read or write bit is set */
@@ -534,23 +536,10 @@
 	if ((mode & 0060) != 0) mode |= 0010;
 	if ((mode & 0006) != 0) mode |= 0001;
 
-	old_mask = umask(0777 ^ mode);
-	if (create_maildir(storage, dir, FALSE) < 0) {
-		umask(old_mask);
+	if (create_maildir(storage, dir, mode, gid, FALSE) < 0)
 		return -1;
-	}
-	if (chown(dir, (uid_t)-1, gid) < 0) {
-		mail_storage_set_critical(storage,
-					  "chown(%s) failed: %m", dir);
-	}
-	for (i = 0; i < N_ELEMENTS(maildir_subdirs); i++) {
-		path = t_strconcat(dir, "/", maildir_subdirs[i], NULL);
-		if (chown(path, (uid_t)-1, gid) < 0) {
-			mail_storage_set_critical(storage,
-						  "chown(%s) failed: %m", path);
-		}
-	}
 
+	old_mask = umask(0777 ^ mode);
 	path = t_strconcat(dir, "/dovecot-shared", NULL);
 	fd = open(path, O_WRONLY | O_CREAT, mode & 0666);
 	umask(old_mask);
@@ -590,9 +579,10 @@
 					  st.st_mode & 0666, st.st_gid) < 0)
 			return -1;
 	} else {
-		st.st_mode = CREATE_MODE;
-		st.st_gid = (gid_t)-1;
-		if (create_maildir(_storage, path, FALSE) < 0)
+		mailbox_list_get_dir_permissions(_storage->list,
+						 &st.st_mode, &st.st_gid);
+		if (create_maildir(_storage, path, st.st_mode, st.st_gid,
+				   FALSE) < 0)
 			return -1;
 	}
 
--- a/src/lib-storage/index/maildir/maildir-util.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/index/maildir/maildir-util.c	Sun Jul 20 23:20:19 2008 +0300
@@ -115,7 +115,8 @@
 						  "stat(%s) failed: %m", path);
 			break;
 		}
-		if (mkdir_parents(path, box->dir_create_mode) < 0 &&
+		if (mkdir_parents_chown(path, box->dir_create_mode,
+					(uid_t)-1, box->file_create_gid) < 0 &&
 		    errno != EEXIST) {
 			if (errno == ENOENT) {
 				/* mailbox was being deleted just now */
--- a/src/lib-storage/index/mbox/mbox-storage.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Sun Jul 20 23:20:19 2008 +0300
@@ -692,9 +692,10 @@
 {
 	const char *path, *p;
 	struct stat st;
+	mode_t mode;
+	gid_t gid;
 	int fd;
 
-
 	/* make sure it doesn't exist already */
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -719,7 +720,9 @@
 	p = directory ? path + strlen(path) : strrchr(path, '/');
 	if (p != NULL) {
 		p = t_strdup_until(path, p);
-		if (mkdir_parents(p, CREATE_MODE) < 0 && errno != EEXIST) {
+		mailbox_list_get_dir_permissions(_storage->list, &mode, &gid);
+		if (mkdir_parents_chown(p, mode, (uid_t)-1, gid) < 0 &&
+		    errno != EEXIST) {
 			if (!mail_storage_set_error_from_errno(_storage)) {
 				mail_storage_set_critical(_storage,
 					"mkdir_parents(%s) failed: %m", p);
--- a/src/lib-storage/list/mailbox-list-fs.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/list/mailbox-list-fs.c	Sun Jul 20 23:20:19 2008 +0300
@@ -11,7 +11,6 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
-#define CREATE_MODE 0770 /* umask() should limit it more */
 #define GLOBAL_TEMP_PREFIX ".temp."
 
 extern struct mailbox_list fs_mailbox_list;
@@ -283,6 +282,8 @@
 {
 	const char *oldpath, *newpath, *old_indexdir, *new_indexdir, *p;
 	struct stat st;
+	mode_t mode;
+	gid_t gid;
 
 	oldpath = mailbox_list_get_path(list, oldname,
 					MAILBOX_LIST_PATH_TYPE_DIR);
@@ -292,8 +293,10 @@
 	/* create the hierarchy */
 	p = strrchr(newpath, '/');
 	if (p != NULL) {
+		mailbox_list_get_dir_permissions(list, &mode, &gid);
 		p = t_strdup_until(newpath, p);
-		if (mkdir_parents(p, CREATE_MODE) < 0 && errno != EEXIST) {
+		if (mkdir_parents_chown(p, mode, (uid_t)-1, gid) < 0 &&
+		    errno != EEXIST) {
 			if (mailbox_list_set_error_from_errno(list))
 				return -1;
 
--- a/src/lib-storage/list/subscription-file.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/list/subscription-file.c	Sun Jul 20 23:20:19 2008 +0300
@@ -82,6 +82,8 @@
 	struct istream *input;
 	struct ostream *output;
 	int fd_in, fd_out;
+	mode_t mode, dir_mode;
+	gid_t gid;
 	bool found, failed = FALSE;
 
 	if (strcasecmp(name, "INBOX") == 0)
@@ -96,17 +98,22 @@
 	dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT;
 	dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT;
 
-	fd_out = file_dotlock_open(&dotlock_set, path, 0, &dotlock);
+	mailbox_list_get_permissions(list, &mode, &gid);
+	mailbox_list_get_dir_permissions(list, &dir_mode, &gid);
+	fd_out = file_dotlock_open_mode(&dotlock_set, path, 0,
+					mode, (uid_t)-1, gid, &dotlock);
 	if (fd_out == -1 && errno == ENOENT) {
 		/* directory hasn't been created yet. */
 		p = strrchr(path, '/');
 		dir = p == NULL ? NULL : t_strdup_until(path, p);
-		if (dir != NULL && mkdir_parents(dir, 0700) < 0 &&
+		if (dir != NULL &&
+		    mkdir_parents_chown(dir, dir_mode, (uid_t)-1, gid) < 0 &&
 		    errno != EEXIST) {
 			subsfile_set_syscall_error(list, "mkdir()", dir);
 			return -1;
 		}
-		fd_out = file_dotlock_open(&dotlock_set, path, 0, &dotlock);
+		fd_out = file_dotlock_open_mode(&dotlock_set, path, 0,
+						mode, (uid_t)-1, gid, &dotlock);
 	}
 	if (fd_out == -1) {
 		if (errno == EAGAIN) {
--- a/src/lib-storage/mailbox-list.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/mailbox-list.c	Sun Jul 20 23:20:19 2008 +0300
@@ -291,6 +291,21 @@
 	*gid_r = list->file_create_gid;
 }
 
+void mailbox_list_get_dir_permissions(struct mailbox_list *list,
+				      mode_t *mode_r, gid_t *gid_r)
+{
+	mode_t mode;
+
+	mailbox_list_get_permissions(list, &mode, gid_r);
+
+	/* add the execute bit if either read or write bit is set */
+	if ((mode & 0600) != 0) mode |= 0100;
+	if ((mode & 0060) != 0) mode |= 0010;
+	if ((mode & 0006) != 0) mode |= 0001;
+
+	*mode_r = mode;
+}
+
 bool mailbox_list_is_valid_pattern(struct mailbox_list *list,
 				   const char *pattern)
 {
--- a/src/lib-storage/mailbox-list.h	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/lib-storage/mailbox-list.h	Sun Jul 20 23:20:19 2008 +0300
@@ -141,6 +141,10 @@
    necessary to change the default */
 void mailbox_list_get_permissions(struct mailbox_list *list,
 				  mode_t *mode_r, gid_t *gid_r);
+/* Like mailbox_list_get_permissions(), but add execute-bits for mode
+   if either read or write bit is set (e.g. 0640 -> 0750). */
+void mailbox_list_get_dir_permissions(struct mailbox_list *list,
+				      mode_t *mode_r, gid_t *gid_r);
 
 /* Returns TRUE if the name doesn't contain any invalid characters.
    The create name check can be more strict. */
--- a/src/plugins/quota/quota-maildir.c	Sun Jul 20 23:19:34 2008 +0300
+++ b/src/plugins/quota/quota-maildir.c	Sun Jul 20 23:20:19 2008 +0300
@@ -218,16 +218,34 @@
 static int maildirsize_write(struct maildir_quota_root *root, const char *path)
 {
 	const struct quota_rule *rule = &root->root.default_rule;
+	struct mail_storage *const *storages;
+	unsigned int i, count;
 	struct dotlock *dotlock;
 	string_t *str;
+	mode_t mode;
+	gid_t gid;
 	int fd;
 
 	i_assert(root->fd == -1);
 
+	/* figure out what permissions we should use for maildirsize.
+	   use the inbox namespace's permissions if possible. */
+	mode = 0600;
+	gid = (gid_t)-1;
+	storages = array_get(&root->root.quota->storages, &count);
+	for (i = 0; i < count; i++) {
+		if ((storages[i]->ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
+			mailbox_list_get_permissions(storages[i]->ns->list,
+						     &mode, &gid);
+			break;
+		}
+	}
+
 	dotlock_settings.use_excl_lock = getenv("DOTLOCK_USE_EXCL") != NULL;
 	dotlock_settings.nfs_flush = getenv("MAIL_NFS_STORAGE") != NULL;
-	fd = file_dotlock_open(&dotlock_settings, path,
-			       DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
+	fd = file_dotlock_open_mode(&dotlock_settings, path,
+				    DOTLOCK_CREATE_FLAG_NONBLOCK,
+				    mode, (uid_t)-1, gid, &dotlock);
 	if (fd == -1) {
 		if (errno == EAGAIN) {
 			/* someone's just in the middle of updating it */