dovecot: Replaced mail_extra_groups setting with mail_privileged...

dovecot at dovecot.org dovecot at dovecot.org
Tue Mar 4 08:51:53 EET 2008


details:   http://hg.dovecot.org/dovecot/rev/12adb981226e
changeset: 7329:12adb981226e
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Mar 04 07:54:53 2008 +0200
description:
Replaced mail_extra_groups setting with mail_privileged_group and
mail_access_groups settings. mail_privileged_group allows temporary access
to the group when creating mbox INBOX dotlocks.

diffstat:

13 files changed, 354 insertions(+), 37 deletions(-)
dovecot-example.conf                      |   17 ++-
src/lib-storage/index/mbox/mbox-lock.c    |  124 +++++++++++++++++++++++++
src/lib-storage/index/mbox/mbox-lock.h    |    2 
src/lib-storage/index/mbox/mbox-storage.c |   41 ++++++++
src/lib-storage/index/mbox/mbox-storage.h |    2 
src/lib/restrict-access.c                 |  141 +++++++++++++++++++++++++----
src/lib/restrict-access.h                 |   13 ++
src/master/auth-process.c                 |    4 
src/master/login-process.c                |    2 
src/master/mail-process.c                 |   12 +-
src/master/master-settings-defs.c         |    2 
src/master/master-settings.c              |   26 +++++
src/master/master-settings.h              |    5 -

diffs (truncated from 702 to 300 lines):

diff -r 2e8ff3074f5b -r 12adb981226e dovecot-example.conf
--- a/dovecot-example.conf	Tue Mar 04 07:44:19 2008 +0200
+++ b/dovecot-example.conf	Tue Mar 04 07:54:53 2008 +0200
@@ -269,12 +269,17 @@
 #mail_uid =
 #mail_gid =
 
-# Grant access to these extra groups for mail processes. Typical use would be
-# to give "mail" group write access to /var/mail to be able to create dotlocks.
-# WARNING: If your users can create symlinks, this will allow the users to
-# read any files that are group-readable by one of these groups! Make sure at
-# least all the common mailboxes have 0600 permissions (or a different group).
-#mail_extra_groups =
+# Group to enable temporarily for privileged operations. Currently this is
+# used only for creating mbox dotlock files when creation fails for INBOX.
+# Typically this is set to "mail" to give access to /var/mail.
+#mail_privileged_group =
+
+# Grant access to these supplementary groups for mail processes. Typically
+# these are used to set up access to shared mailboxes. Note that it may be
+# dangerous to set these if users can create symlinks (e.g. if "mail" group is
+# set here, ln -s /var/mail ~/mail/var could allow a user to delete others'
+# mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it).
+#mail_access_groups =
 
 # Allow full filesystem access to clients. There's no access checks other than
 # what the operating system does for the active UID/GID. It works with both
diff -r 2e8ff3074f5b -r 12adb981226e src/lib-storage/index/mbox/mbox-lock.c
--- a/src/lib-storage/index/mbox/mbox-lock.c	Tue Mar 04 07:44:19 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-lock.c	Tue Mar 04 07:54:53 2008 +0200
@@ -1,6 +1,7 @@
 /* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "restrict-access.h"
 #include "nfs-workarounds.h"
 #include "mail-index-private.h"
 #include "mbox-storage.h"
@@ -38,6 +39,12 @@ enum mbox_lock_type {
 	MBOX_LOCK_COUNT
 };
 
+enum mbox_dotlock_op {
+	MBOX_DOTLOCK_OP_LOCK,
+	MBOX_DOTLOCK_OP_UNLOCK,
+	MBOX_DOTLOCK_OP_TOUCH
+};
+
 struct mbox_lock_context {
 	struct mbox_mailbox *mbox;
 	int lock_status[MBOX_LOCK_COUNT];
@@ -46,6 +53,7 @@ struct mbox_lock_context {
 	int lock_type;
 	bool dotlock_last_stale;
 	bool fcntl_locked;
+	bool using_privileges;
 };
 
 struct mbox_lock_data {
@@ -200,6 +208,9 @@ static bool dotlock_callback(unsigned in
 	enum mbox_lock_type *lock_types;
 	int i;
 
+	if (ctx->using_privileges)
+		restrict_access_drop_priv_gid();
+
 	if (stale && !ctx->dotlock_last_stale) {
 		/* get next index we wish to try locking. it's the one after
 		   dotlocking. */
@@ -231,7 +242,90 @@ static bool dotlock_callback(unsigned in
 				  MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE :
 				  MAILBOX_LOCK_NOTIFY_MAILBOX_ABORT,
 				  secs_left);
+	if (ctx->using_privileges) {
+		if (restrict_access_use_priv_gid() < 0) {
+			/* shouldn't get here */
+			return FALSE;
+		}
+	}
 	return TRUE;
+}
+
+static int mbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
+				      struct dotlock_settings *set,
+				      enum mbox_dotlock_op op)
+{
+	const char *dir, *fname;
+	int ret = -1, orig_dir_fd;
+
+	orig_dir_fd = open(".", O_RDONLY);
+	if (orig_dir_fd == -1) {
+		i_error("open(.) failed: %m");
+		return -1;
+	}
+
+	/* allow dotlocks to be created only for files we can read while we're
+	   unprivileged. to make sure there are no race conditions we first
+	   have to chdir to the mbox file's directory and then use relative
+	   paths. unless this is done, users could:
+	    - create *.lock files to any directory writable by the
+	      privileged group
+	    - DoS other users by dotlocking their mailboxes infinitely
+	*/
+	fname = strrchr(mbox->path, '/');
+	if (fname == NULL) {
+		/* already relative */
+		fname = mbox->path;
+	} else {
+		dir = t_strdup_until(mbox->path, fname);
+		if (chdir(dir) < 0) {
+			i_error("chdir(%s) failed: %m", dir);
+			(void)close(orig_dir_fd);
+			return -1;
+		}
+		fname++;
+	}
+	if (op == MBOX_DOTLOCK_OP_LOCK) {
+		if (access(fname, R_OK) < 0) {
+			i_error("access(%s) failed: %m", mbox->path);
+			return -1;
+		}
+	}
+
+	if (restrict_access_use_priv_gid() < 0) {
+		(void)close(orig_dir_fd);
+		return -1;
+	}
+
+	switch (op) {
+	case MBOX_DOTLOCK_OP_LOCK:
+		/* we're now privileged - avoid doing as much as possible */
+		ret = file_dotlock_create(set, fname, 0, &mbox->mbox_dotlock);
+		if (ret > 0)
+			mbox->mbox_used_privileges = TRUE;
+		break;
+	case MBOX_DOTLOCK_OP_UNLOCK:
+		/* we're now privileged - avoid doing as much as possible */
+		ret = file_dotlock_delete(&mbox->mbox_dotlock);
+		mbox->mbox_used_privileges = FALSE;
+		break;
+	case MBOX_DOTLOCK_OP_TOUCH:
+		if (!file_dotlock_is_locked(mbox->mbox_dotlock)) {
+			file_dotlock_delete(&mbox->mbox_dotlock);
+			mbox->mbox_used_privileges = TRUE;
+			ret = -1;
+		} else {
+			ret = file_dotlock_touch(mbox->mbox_dotlock);
+		}
+		break;
+	}
+
+	restrict_access_drop_priv_gid();
+
+	if (fchdir(orig_dir_fd) < 0)
+		i_error("fchdir() failed: %m");
+	(void)close(orig_dir_fd);
+	return ret;
 }
 
 static int
@@ -245,7 +339,15 @@ mbox_lock_dotlock_int(struct mbox_lock_c
 		if (!mbox->mbox_dotlocked)
 			return 1;
 
-		if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
+		if (!mbox->mbox_used_privileges)
+			ret = file_dotlock_delete(&mbox->mbox_dotlock);
+		else {
+			ctx->using_privileges = TRUE;
+			ret = mbox_dotlock_privileged_op(mbox, NULL,
+							MBOX_DOTLOCK_OP_UNLOCK);
+			ctx->using_privileges = FALSE;
+		}
+		if (ret <= 0) {
 			mbox_set_syscall_error(mbox, "file_dotlock_delete()");
 			ret = -1;
 		}
@@ -269,6 +371,13 @@ mbox_lock_dotlock_int(struct mbox_lock_c
 	set.context = ctx;
 
 	ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
+	if (ret < 0 && errno == EACCES && restrict_access_have_priv_gid() &&
+	    mbox->mbox_privileged_locking) {
+		/* try again, this time with extra privileges */
+		ret = mbox_dotlock_privileged_op(mbox, &set,
+						 MBOX_DOTLOCK_OP_LOCK);
+	}
+
 	if (ret < 0) {
 		if ((ENOSPACE(errno) || errno == EACCES) && try)
 			return 1;
@@ -643,3 +752,16 @@ int mbox_unlock(struct mbox_mailbox *mbo
 
 	return mbox_unlock_files(&ctx);
 }
+
+void mbox_dotlock_touch(struct mbox_mailbox *mbox)
+{
+	if (mbox->mbox_dotlock == NULL)
+		return;
+
+	if (!mbox->mbox_used_privileges)
+		(void)file_dotlock_touch(mbox->mbox_dotlock);
+	else {
+		(void)mbox_dotlock_privileged_op(mbox, NULL,
+						 MBOX_DOTLOCK_OP_TOUCH);
+	}
+}
diff -r 2e8ff3074f5b -r 12adb981226e src/lib-storage/index/mbox/mbox-lock.h
--- a/src/lib-storage/index/mbox/mbox-lock.h	Tue Mar 04 07:44:19 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-lock.h	Tue Mar 04 07:54:53 2008 +0200
@@ -7,4 +7,6 @@ int mbox_lock(struct mbox_mailbox *mbox,
 	      unsigned int *lock_id_r);
 int mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id);
 
+void mbox_dotlock_touch(struct mbox_mailbox *mbox);
+
 #endif
diff -r 2e8ff3074f5b -r 12adb981226e src/lib-storage/index/mbox/mbox-storage.c
--- a/src/lib-storage/index/mbox/mbox-storage.c	Tue Mar 04 07:44:19 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Tue Mar 04 07:54:53 2008 +0200
@@ -396,6 +396,33 @@ static struct mail_storage *mbox_alloc(v
 	return &storage->storage;
 }
 
+static bool mbox_name_is_dotlock(const char *name)
+{
+	unsigned int len = strlen(name);
+
+	return len >= 5 && strcmp(name + len - 5, ".lock") == 0;
+}
+
+static bool
+mbox_is_valid_existing_name(struct mailbox_list *list, const char *name)
+{
+	struct mbox_storage *storage = MBOX_LIST_CONTEXT(list);
+
+	return storage->list_module_ctx.super.
+		is_valid_existing_name(list, name) &&
+		!mbox_name_is_dotlock(name);
+}
+
+static bool
+mbox_is_valid_create_name(struct mailbox_list *list, const char *name)
+{
+	struct mbox_storage *storage = MBOX_LIST_CONTEXT(list);
+
+	return storage->list_module_ctx.super.
+		is_valid_create_name(list, name) &&
+		!mbox_name_is_dotlock(name);
+}
+
 static int mbox_create(struct mail_storage *_storage, const char *data,
 		       const char **error_r)
 {
@@ -419,6 +446,8 @@ static int mbox_create(struct mail_stora
 	}
 	_storage->list->v.iter_is_mailbox = mbox_list_iter_is_mailbox;
 	_storage->list->v.delete_mailbox = mbox_list_delete_mailbox;
+	_storage->list->v.is_valid_existing_name = mbox_is_valid_existing_name;
+	_storage->list->v.is_valid_create_name = mbox_is_valid_create_name;
 
 	MODULE_CONTEXT_SET_FULL(_storage->list, mbox_mailbox_list_module,
 				storage, &storage->list_module_ctx);
@@ -492,7 +521,7 @@ static bool want_memory_indexes(struct m
 
 static void mbox_lock_touch_timeout(struct mbox_mailbox *mbox)
 {
-	(void)file_dotlock_touch(mbox->mbox_dotlock);
+	mbox_dotlock_touch(mbox);
 }
 
 static struct mbox_mailbox *
@@ -553,7 +582,7 @@ mbox_open(struct mbox_storage *storage, 
 	struct mail_storage *_storage = &storage->storage;
 	struct mbox_mailbox *mbox;
 	struct mail_index *index;
-	const char *path;
+	const char *path, *rootdir;
 
 	path = mailbox_list_get_path(_storage->list, name,
 				     MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -570,6 +599,14 @@ mbox_open(struct mbox_storage *storage, 
 		}
 	}
 
+	if (strcmp(name, "INBOX") == 0) {
+		/* if INBOX isn't under the root directory, it's probably in
+		   /var/mail and we want to allow privileged dotlocking */
+		rootdir = mailbox_list_get_path(_storage->list, NULL,
+						MAILBOX_LIST_PATH_TYPE_DIR);
+		if (strncmp(path, rootdir, strlen(rootdir)) != 0)
+			mbox->mbox_privileged_locking = TRUE;
+	}
 	return &mbox->ibox.box;
 }
 
diff -r 2e8ff3074f5b -r 12adb981226e src/lib-storage/index/mbox/mbox-storage.h
--- a/src/lib-storage/index/mbox/mbox-storage.h	Tue Mar 04 07:44:19 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Tue Mar 04 07:54:53 2008 +0200


More information about the dovecot-cvs mailing list