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