dovecot-1.0: Replaced mail_extra_groups setting with mail_privil...

dovecot at dovecot.org dovecot at dovecot.org
Tue Mar 4 07:53:23 EET 2008


details:   http://hg.dovecot.org/dovecot-1.0/rev/2c61c3cad1f1
changeset: 5525:2c61c3cad1f1
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Mar 04 07:53:18 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:

15 files changed, 473 insertions(+), 132 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 |   19 +
src/lib-storage/index/mbox/mbox-storage.h |    2 
src/lib/file-dotlock.c                    |   58 +++--
src/lib/file-dotlock.h                    |    2 
src/lib/restrict-access.c                 |  296 ++++++++++++++++++++---------
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              |   48 ++++
src/master/master-settings.h              |    4 

diffs (truncated from 985 to 300 lines):

diff -r dfa82e24d7bc -r 2c61c3cad1f1 dovecot-example.conf
--- a/dovecot-example.conf	Sun Mar 02 19:52:16 2008 +0200
+++ b/dovecot-example.conf	Tue Mar 04 07:53:18 2008 +0200
@@ -252,12 +252,17 @@
    #hidden = yes
 #}
 
-# 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 dfa82e24d7bc -r 2c61c3cad1f1 src/lib-storage/index/mbox/mbox-lock.c
--- a/src/lib-storage/index/mbox/mbox-lock.c	Sun Mar 02 19:52:16 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-lock.c	Tue Mar 04 07:53:18 2008 +0200
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "lib.h"
+#include "restrict-access.h"
 #include "mail-index-private.h"
 #include "mbox-storage.h"
 #include "mbox-file.h"
@@ -36,6 +37,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];
@@ -43,6 +50,7 @@ struct mbox_lock_context {
 
 	int lock_type;
 	bool dotlock_last_stale;
+	bool using_privileges;
 };
 
 struct mbox_lock_data {
@@ -190,6 +198,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. */
@@ -221,7 +232,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 mbox_lock_dotlock(struct mbox_lock_context *ctx, int lock_type,
@@ -235,7 +329,15 @@ static int mbox_lock_dotlock(struct mbox
 		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;
 		}
@@ -257,6 +359,13 @@ static int mbox_lock_dotlock(struct mbox
 	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) {
 		mbox_set_syscall_error(mbox, "file_lock_dotlock()");
 		return -1;
@@ -601,3 +710,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 dfa82e24d7bc -r 2c61c3cad1f1 src/lib-storage/index/mbox/mbox-lock.h
--- a/src/lib-storage/index/mbox/mbox-lock.h	Sun Mar 02 19:52:16 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-lock.h	Tue Mar 04 07:53:18 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 dfa82e24d7bc -r 2c61c3cad1f1 src/lib-storage/index/mbox/mbox-storage.c
--- a/src/lib-storage/index/mbox/mbox-storage.c	Sun Mar 02 19:52:16 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Tue Mar 04 07:53:18 2008 +0200
@@ -443,6 +443,13 @@ bool mbox_is_valid_mask(struct mail_stor
 	return TRUE;
 }
 
+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_create_name(struct mail_storage *storage,
 				      const char *name)
 {
@@ -458,7 +465,7 @@ static bool mbox_is_valid_create_name(st
 		    return FALSE;
 	}
 
-	return mbox_is_valid_mask(storage, name);
+	return mbox_is_valid_mask(storage, name) && !mbox_name_is_dotlock(name);
 }
 
 static bool mbox_is_valid_existing_name(struct mail_storage *storage,
@@ -470,7 +477,7 @@ static bool mbox_is_valid_existing_name(
 	if (name[0] == '\0' || name[len-1] == '/')
 		return FALSE;
 
-	return mbox_is_valid_mask(storage, name);
+	return mbox_is_valid_mask(storage, name) && !mbox_name_is_dotlock(name);
 }
 
 static const char *mbox_get_index_dir(struct index_storage *storage,
@@ -597,7 +604,7 @@ static void mbox_lock_touch_timeout(void
 {
 	struct mbox_mailbox *mbox = context;
 
-	(void)file_dotlock_touch(mbox->mbox_dotlock);
+	mbox_dotlock_touch(mbox);
 }
 
 static struct mbox_mailbox *
@@ -697,6 +704,12 @@ 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 */
+		if (strncmp(path, istorage->dir, strlen(istorage->dir)) != 0)
+			mbox->mbox_privileged_locking = TRUE;
+	}
 	return &mbox->ibox.box;
 }
 
diff -r dfa82e24d7bc -r 2c61c3cad1f1 src/lib-storage/index/mbox/mbox-storage.h
--- a/src/lib-storage/index/mbox/mbox-storage.h	Sun Mar 02 19:52:16 2008 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Tue Mar 04 07:53:18 2008 +0200
@@ -48,6 +48,8 @@ struct mbox_mailbox {
 	unsigned int mbox_very_dirty_syncs:1;
 	unsigned int mbox_save_md5:1;
 	unsigned int mbox_dotlocked:1;
+	unsigned int mbox_used_privileges:1;
+	unsigned int mbox_privileged_locking:1;
 };
 
 struct mbox_transaction_context {
diff -r dfa82e24d7bc -r 2c61c3cad1f1 src/lib/file-dotlock.c
--- a/src/lib/file-dotlock.c	Sun Mar 02 19:52:16 2008 +0200
+++ b/src/lib/file-dotlock.c	Tue Mar 04 07:53:18 2008 +0200
@@ -319,8 +319,10 @@ static int try_create_lock_hardlink(stru
 		if (errno == EEXIST)
 			return 0;
 
-		i_error("link(%s, %s) failed: %m",
-			lock_info->temp_path, lock_info->lock_path);
+		if (errno != EACCES) {
+			i_error("link(%s, %s) failed: %m",
+				lock_info->temp_path, lock_info->lock_path);
+		}


More information about the dovecot-cvs mailing list