Mercurial > dovecot > original-hg > dovecot-1.2
changeset 9168:2bbf175bb6d3 HEAD
Whenever file's group changing fails, show the group origin in the error message.
line wrap: on
line diff
--- a/src/deliver/deliver.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/deliver/deliver.c Sat Jun 27 20:39:30 2009 -0400 @@ -616,6 +616,7 @@ static int deliver_create_dir(struct mail_user *user, const char *dir) { struct mail_namespace *ns; + const char *origin; mode_t mode; gid_t gid; @@ -623,8 +624,8 @@ if (ns == NULL) ns = user->namespaces; - mailbox_list_get_dir_permissions(ns->list, NULL, &mode, &gid); - if (mkdir_parents_chown(dir, mode, (uid_t)-1, gid) == 0) { + mailbox_list_get_dir_permissions(ns->list, NULL, &mode, &gid, &origin); + if (mkdir_parents_chgrp(dir, mode, gid, origin) == 0) { return 0; } else if (errno == EACCES) { i_error("%s", eacces_error_get_creating("mkdir_parents_chown",
--- a/src/lib-index/mail-index-private.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-index/mail-index-private.h Sat Jun 27 20:39:30 2009 -0400 @@ -174,6 +174,7 @@ enum mail_index_sync_type fsync_mask; mode_t mode; gid_t gid; + char *gid_origin; pool_t extension_pool; ARRAY_DEFINE(extensions, struct mail_index_registered_ext);
--- a/src/lib-index/mail-index-strmap.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-index/mail-index-strmap.c Sat Jun 27 20:39:30 2009 -0400 @@ -997,8 +997,9 @@ str = t_str_new(256); str_append(str, strmap->path); - fd = safe_mkstemp_hostpid(str, view->view->index->mode, - (uid_t)-1, view->view->index->gid); + fd = safe_mkstemp_hostpid_group(str, view->view->index->mode, + view->view->index->gid, + view->view->index->gid_origin); temp_path = str_c(str); if (fd == -1) {
--- a/src/lib-index/mail-index.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-index/mail-index.c Sat Jun 27 20:39:30 2009 -0400 @@ -73,6 +73,7 @@ array_free(&index->keywords); array_free(&index->module_contexts); + i_free(index->gid_origin); i_free(index->error); i_free(index->dir); i_free(index->prefix); @@ -86,10 +87,13 @@ } void mail_index_set_permissions(struct mail_index *index, - mode_t mode, gid_t gid) + mode_t mode, gid_t gid, const char *gid_origin) { index->mode = mode & 0666; index->gid = gid; + + i_free(index->gid_origin); + index->gid_origin = i_strdup(gid_origin); } uint32_t mail_index_ext_register(struct mail_index *index, const char *name, @@ -644,7 +648,13 @@ really matter. ignore silently. */ return; } - mail_index_file_set_syscall_error(index, path, "fchown()"); + if (errno != EACCES) + mail_index_file_set_syscall_error(index, path, "fchown()"); + else { + mail_index_set_error(index, "%s", + eperm_error_get_chgrp("fchown", path, index->gid, + index->gid_origin)); + } /* continue, but change permissions so that only the common subset of group and world is used. this makes sure no one
--- a/src/lib-index/mail-index.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-index/mail-index.h Sat Jun 27 20:39:30 2009 -0400 @@ -185,7 +185,7 @@ void mail_index_set_fsync_types(struct mail_index *index, enum mail_index_sync_type fsync_mask); void mail_index_set_permissions(struct mail_index *index, - mode_t mode, gid_t gid); + mode_t mode, gid_t gid, const char *gid_origin); int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags, enum file_lock_method lock_method);
--- a/src/lib-storage/index/cydir/cydir-storage.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/cydir/cydir-storage.c Sat Jun 27 20:39:30 2009 -0400 @@ -132,11 +132,13 @@ static int create_cydir(struct mail_storage *storage, const char *path) { + const char *origin; mode_t mode; gid_t gid; - mailbox_list_get_dir_permissions(storage->list, NULL, &mode, &gid); - if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) < 0 && + mailbox_list_get_dir_permissions(storage->list, NULL, + &mode, &gid, &origin); + if (mkdir_parents_chgrp(path, mode, gid, origin) < 0 && errno != EEXIST) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage,
--- a/src/lib-storage/index/dbox/dbox-storage.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/dbox/dbox-storage.c Sat Jun 27 20:39:30 2009 -0400 @@ -160,11 +160,13 @@ static int create_dbox(struct mail_storage *storage, const char *path) { + const char *origin; mode_t mode; gid_t gid; - mailbox_list_get_dir_permissions(storage->list, NULL, &mode, &gid); - if (mkdir_parents_chown(path, mode, (uid_t)-1, gid) < 0 && + mailbox_list_get_dir_permissions(storage->list, NULL, + &mode, &gid, &origin); + if (mkdir_parents_chgrp(path, mode, gid, origin) < 0 && errno != EEXIST) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage,
--- a/src/lib-storage/index/index-storage.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/index-storage.c Sat Jun 27 20:39:30 2009 -0400 @@ -70,6 +70,7 @@ static int create_index_dir(struct mail_storage *storage, const char *name) { const char *root_dir, *index_dir, *p, *parent_dir; + const char *origin, *parent_origin; mode_t mode, parent_mode; gid_t gid, parent_gid; int n = 0; @@ -81,8 +82,9 @@ if (strcmp(index_dir, root_dir) == 0 || *index_dir == '\0') return 0; - mailbox_list_get_dir_permissions(storage->list, name, &mode, &gid); - while (mkdir_chown(index_dir, mode, (uid_t)-1, gid) < 0) { + mailbox_list_get_dir_permissions(storage->list, name, + &mode, &gid, &origin); + while (mkdir_chgrp(index_dir, mode, gid, origin) < 0) { if (errno == EEXIST) break; @@ -94,10 +96,11 @@ } /* create the parent directory first */ mailbox_list_get_dir_permissions(storage->list, NULL, - &parent_mode, &parent_gid); + &parent_mode, &parent_gid, + &parent_origin); parent_dir = t_strdup_until(index_dir, p); - if (mkdir_parents_chown(parent_dir, parent_mode, - (uid_t)-1, parent_gid) < 0 && + if (mkdir_parents_chgrp(parent_dir, parent_mode, + parent_gid, parent_origin) < 0 && errno != EEXIST) { mail_storage_set_critical(storage, "mkdir(%s) failed: %m", parent_dir); @@ -435,6 +438,7 @@ struct mail_storage *storage = ibox->storage; struct mailbox *box = &ibox->box; gid_t dir_gid; + const char *origin, *dir_origin; i_assert(name != NULL); @@ -444,12 +448,13 @@ if (box->file_create_mode == 0) { mailbox_list_get_permissions(box->storage->list, name, &box->file_create_mode, - &box->file_create_gid); + &box->file_create_gid, &origin); + box->file_create_gid_origin = p_strdup(box->pool, origin); mailbox_list_get_dir_permissions(box->storage->list, name, &box->dir_create_mode, - &dir_gid); + &dir_gid, &dir_origin); mail_index_set_permissions(ibox->index, box->file_create_mode, - box->file_create_gid); + box->file_create_gid, origin); } p_array_init(&box->search_results, box->pool, 16);
--- a/src/lib-storage/index/maildir/maildir-keywords.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/maildir/maildir-keywords.c Sat Jun 27 20:39:30 2009 -0400 @@ -10,6 +10,7 @@ #include "hash.h" #include "str.h" #include "istream.h" +#include "eacces-error.h" #include "file-dotlock.h" #include "write-full.h" #include "nfs-workarounds.h" @@ -285,6 +286,7 @@ const char *path, int fd) { struct maildir_mailbox *mbox = mk->mbox; + struct mailbox *box = &mbox->ibox.box; const char *const *keywords; unsigned int i, count; string_t *str; @@ -308,11 +310,18 @@ return -1; } - if (st.st_gid != mbox->ibox.box.file_create_gid && - mbox->ibox.box.file_create_gid != (gid_t)-1) { - if (fchown(fd, (uid_t)-1, mbox->ibox.box.file_create_gid) < 0) { - mail_storage_set_critical(mk->storage, - "fchown(%s) failed: %m", path); + if (st.st_gid != box->file_create_gid && + box->file_create_gid != (gid_t)-1) { + if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + if (errno == EPERM) { + mail_storage_set_critical(mk->storage, "%s", + eperm_error_get_chgrp("fchown", path, + box->file_create_gid, + box->file_create_gid_origin)); + } else { + mail_storage_set_critical(mk->storage, + "fchown(%s) failed: %m", path); + } } }
--- a/src/lib-storage/index/maildir/maildir-save.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/maildir/maildir-save.c Sat Jun 27 20:39:30 2009 -0400 @@ -8,6 +8,7 @@ #include "istream-crlf.h" #include "ostream.h" #include "fdatasync-path.h" +#include "eacces-error.h" #include "str.h" #include "index-mail.h" #include "maildir-storage.h" @@ -338,8 +339,16 @@ } } else if (box->file_create_gid != (gid_t)-1) { if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { - mail_storage_set_critical(box->storage, - "fchown(%s) failed: %m", str_c(path)); + if (errno == EPERM) { + mail_storage_set_critical(box->storage, "%s", + eperm_error_get_chgrp("fchown", + str_c(path), + box->file_create_gid, + box->file_create_gid_origin)); + } else { + mail_storage_set_critical(box->storage, + "fchown(%s) failed: %m", str_c(path)); + } } }
--- a/src/lib-storage/index/maildir/maildir-storage.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/maildir/maildir-storage.c Sat Jun 27 20:39:30 2009 -0400 @@ -6,6 +6,7 @@ #include "hostpid.h" #include "str.h" #include "mkdir-parents.h" +#include "eacces-error.h" #include "unlink-directory.h" #include "unlink-old-files.h" #include "mailbox-uidvalidity.h" @@ -298,8 +299,9 @@ return TRUE; } -static int mkdir_verify(struct mail_storage *storage, - const char *dir, mode_t mode, gid_t gid, bool verify) +static int mkdir_verify(struct mail_storage *storage, const char *dir, + mode_t mode, gid_t gid, const char *gid_origin, + bool verify) { struct stat st; @@ -314,7 +316,7 @@ } } - if (mkdir_parents_chown(dir, mode, (uid_t)-1, gid) == 0) + if (mkdir_parents_chgrp(dir, mode, gid, gid_origin) == 0) return 0; if (errno == EEXIST) { @@ -372,8 +374,9 @@ } /* create or fix maildir, ignore if it already exists */ -static int create_maildir(struct mail_storage *storage, - const char *dir, mode_t mode, gid_t gid, bool verify) +static int create_maildir(struct mail_storage *storage, const char *dir, + mode_t mode, gid_t gid, const char *gid_origin, + bool verify) { const char *path; unsigned int i; @@ -394,7 +397,8 @@ /* doesn't exist, create */ 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) + if (mkdir_verify(storage, path, mode, gid, + gid_origin, verify) < 0) return -1; } return 0; @@ -420,7 +424,7 @@ { struct maildir_mailbox *mbox; struct mail_index *index; - const char *path, *control_dir; + const char *path, *shared_path, *control_dir; struct stat st; pool_t pool; @@ -446,18 +450,22 @@ /* for shared mailboxes get the create mode from the permissions of dovecot-shared file. */ - if (stat(t_strconcat(path, "/dovecot-shared", NULL), &st) == 0) { + shared_path = t_strconcat(path, "/dovecot-shared", NULL); + if (stat(shared_path, &st) == 0) { if ((st.st_mode & S_ISGID) != 0 || (st.st_mode & 0060) == 0) { /* Ignore GID */ st.st_gid = (gid_t)-1; } - mail_index_set_permissions(index, st.st_mode & 0666, st.st_gid); + mail_index_set_permissions(index, st.st_mode & 0666, st.st_gid, + shared_path); mbox->ibox.box.file_create_mode = st.st_mode & 0666; mbox->ibox.box.dir_create_mode = get_dir_mode(st.st_mode & 0666); mbox->ibox.box.file_create_gid = st.st_gid; + mbox->ibox.box.file_create_gid_origin = + p_strdup(pool, shared_path); mbox->ibox.box.private_flags_mask = MAIL_SEEN; } @@ -492,7 +500,7 @@ struct istream *input, enum mailbox_open_flags flags) { struct maildir_storage *storage = (struct maildir_storage *)_storage; - const char *path; + const char *path, *origin; struct stat st; mode_t mode; gid_t gid; @@ -511,8 +519,8 @@ (_storage->ns->flags & NAMESPACE_FLAG_INBOX) != 0) { /* INBOX always exists */ mailbox_list_get_dir_permissions(_storage->list, NULL, - &mode, &gid); - if (create_maildir(_storage, path, mode, gid, TRUE) < 0) + &mode, &gid, &origin); + if (create_maildir(_storage, path, mode, gid, origin, TRUE) < 0) return NULL; return maildir_open(storage, "INBOX", flags); } @@ -531,8 +539,8 @@ if (stat(path, &st) == 0) { /* yes, we'll need to create the missing dirs */ mailbox_list_get_dir_permissions(_storage->list, name, - &mode, &gid); - if (create_maildir(_storage, path, mode, gid, TRUE) < 0) + &mode, &gid, &origin); + if (create_maildir(_storage, path, mode, gid, origin, TRUE) < 0) return NULL; return maildir_open(storage, name, flags); @@ -548,7 +556,8 @@ } static int maildir_create_shared(struct mail_storage *storage, - const char *dir, mode_t mode, gid_t gid) + const char *dir, const char *gid_origin, + mode_t mode, gid_t gid) { const char *path; mode_t old_mask; @@ -559,7 +568,7 @@ if ((mode & 0060) != 0) mode |= 0010; if ((mode & 0006) != 0) mode |= 0001; - if (create_maildir(storage, dir, mode, gid, FALSE) < 0) + if (create_maildir(storage, dir, mode, gid, gid_origin, FALSE) < 0) return -1; old_mask = umask(0777 ^ mode); @@ -573,8 +582,14 @@ } if (fchown(fd, (uid_t)-1, gid) < 0) { - mail_storage_set_critical(storage, - "fchown(%s) failed: %m", path); + if (errno == EPERM) { + mail_storage_set_critical(storage, "%s", + eperm_error_get_chgrp("fchown", path, + gid, gid_origin)); + } else { + mail_storage_set_critical(storage, + "fchown(%s) failed: %m", path); + } } (void)close(fd); return 0; @@ -585,7 +600,7 @@ bool directory ATTR_UNUSED) { struct stat st; - const char *path, *root_dir, *shared_path; + const char *path, *root_dir, *shared_path, *gid_origin; mode_t old_mask; int fd; @@ -598,14 +613,16 @@ its permissions and gid, and copy the dovecot-shared inside it. */ shared_path = t_strconcat(root_dir, "/dovecot-shared", NULL); if (stat(shared_path, &st) == 0) { - if (maildir_create_shared(_storage, path, + gid_origin = shared_path; + if (maildir_create_shared(_storage, path, gid_origin, st.st_mode & 0666, st.st_gid) < 0) return -1; } else { mailbox_list_get_dir_permissions(_storage->list, NULL, - &st.st_mode, &st.st_gid); + &st.st_mode, &st.st_gid, + &gid_origin); if (create_maildir(_storage, path, st.st_mode, st.st_gid, - FALSE) < 0) + gid_origin, FALSE) < 0) return -1; } @@ -617,8 +634,15 @@ umask(old_mask); if (fd != -1) { /* if dovecot-shared exists, use the same group */ - if (st.st_gid != (gid_t)-1 && - fchown(fd, (uid_t)-1, st.st_gid) < 0) { + if (st.st_gid == (gid_t)-1) { + /* doesn't exist */ + } else if (fchown(fd, (uid_t)-1, st.st_gid) == 0) { + /* ok */ + } else if (errno == EPERM) { + mail_storage_set_critical(_storage, "%s", + eperm_error_get_chgrp("fchown", path, + st.st_gid, gid_origin)); + } else { mail_storage_set_critical(_storage, "fchown(%s) failed: %m", path); }
--- a/src/lib-storage/index/maildir/maildir-uidlist.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/maildir/maildir-uidlist.c Sat Jun 27 20:39:30 2009 -0400 @@ -1231,8 +1231,14 @@ return -1; } - if (box->file_create_gid != (gid_t)-1) { - if (fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + if (box->file_create_gid != (gid_t)-1 && + fchown(fd, (uid_t)-1, box->file_create_gid) < 0) { + if (errno == EPERM) { + mail_storage_set_critical(box->storage, "%s", + eperm_error_get_chgrp("fchown", temp_path, + box->file_create_gid, + box->file_create_gid_origin)); + } else { mail_storage_set_critical(box->storage, "fchown(%s) failed: %m", temp_path); }
--- a/src/lib-storage/index/maildir/maildir-util.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/maildir/maildir-util.c Sat Jun 27 20:39:30 2009 -0400 @@ -133,12 +133,12 @@ static int maildir_create_path(struct mailbox *box, const char *path, bool is_mail_dir) { - const char *p, *parent; + const char *p, *parent, *origin; mode_t parent_mode; gid_t parent_gid; - if (mkdir_chown(path, box->dir_create_mode, - (uid_t)-1, box->file_create_gid) == 0) + if (mkdir_chgrp(path, box->dir_create_mode, box->file_create_gid, + box->file_create_gid_origin) == 0) return 0; switch (errno) { @@ -154,9 +154,10 @@ /* create index/control root directory */ parent = t_strdup_until(path, p); mailbox_list_get_dir_permissions(box->storage->list, NULL, - &parent_mode, &parent_gid); - if (mkdir_parents_chown(parent, parent_mode, (uid_t)-1, - parent_gid) == 0 || errno == EEXIST) { + &parent_mode, &parent_gid, + &origin); + if (mkdir_parents_chgrp(parent, parent_mode, parent_gid, + origin) == 0 || errno == EEXIST) { /* should work now, try again */ return maildir_create_path(box, path, TRUE); }
--- a/src/lib-storage/index/mbox/mbox-storage.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/index/mbox/mbox-storage.c Sat Jun 27 20:39:30 2009 -0400 @@ -718,7 +718,7 @@ static int mbox_mailbox_create(struct mail_storage *_storage, const char *name, bool directory) { - const char *path, *p; + const char *path, *p, *origin; struct stat st; mode_t mode; gid_t gid; @@ -749,8 +749,8 @@ if (p != NULL) { p = t_strdup_until(path, p); mailbox_list_get_dir_permissions(_storage->list, NULL, - &mode, &gid); - if (mkdir_parents_chown(p, mode, (uid_t)-1, gid) < 0 && + &mode, &gid, &origin); + if (mkdir_parents_chgrp(p, mode, gid, origin) < 0 && errno != EEXIST) { if (!mail_storage_set_error_from_errno(_storage)) { mail_storage_set_critical(_storage,
--- a/src/lib-storage/list/mailbox-list-fs.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/list/mailbox-list-fs.c Sat Jun 27 20:39:30 2009 -0400 @@ -302,7 +302,7 @@ static int fs_list_rename_mailbox(struct mailbox_list *list, const char *oldname, const char *newname) { - const char *oldpath, *newpath, *p; + const char *oldpath, *newpath, *p, *origin; struct stat st; mode_t mode; gid_t gid; @@ -315,9 +315,10 @@ /* create the hierarchy */ p = strrchr(newpath, '/'); if (p != NULL) { - mailbox_list_get_dir_permissions(list, NULL, &mode, &gid); + mailbox_list_get_dir_permissions(list, NULL, &mode, + &gid, &origin); p = t_strdup_until(newpath, p); - if (mkdir_parents_chown(p, mode, (uid_t)-1, gid) < 0 && + if (mkdir_parents_chgrp(p, mode, gid, origin) < 0 && errno != EEXIST) { if (mailbox_list_set_error_from_errno(list)) return -1;
--- a/src/lib-storage/list/subscription-file.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/list/subscription-file.c Sat Jun 27 20:39:30 2009 -0400 @@ -91,7 +91,7 @@ { struct dotlock_settings dotlock_set; struct dotlock *dotlock; - const char *line, *p, *dir; + const char *line, *p, *dir, *origin; struct istream *input; struct ostream *output; int fd_in, fd_out; @@ -111,22 +111,22 @@ dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT; dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT; - mailbox_list_get_permissions(list, NULL, &mode, &gid); - mailbox_list_get_dir_permissions(list, NULL, &dir_mode, &gid); - fd_out = file_dotlock_open_mode(&dotlock_set, path, 0, - mode, (uid_t)-1, gid, &dotlock); + mailbox_list_get_permissions(list, NULL, &mode, &gid, &origin); + mailbox_list_get_dir_permissions(list, NULL, &dir_mode, &gid, &origin); + fd_out = file_dotlock_open_group(&dotlock_set, path, 0, + mode, gid, origin, &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_chown(dir, dir_mode, (uid_t)-1, gid) < 0 && + mkdir_parents_chgrp(dir, dir_mode, gid, origin) < 0 && errno != EEXIST) { subswrite_set_syscall_error(list, "mkdir()", dir); return -1; } - fd_out = file_dotlock_open_mode(&dotlock_set, path, 0, - mode, (uid_t)-1, gid, &dotlock); + fd_out = file_dotlock_open_group(&dotlock_set, path, 0, + mode, gid, origin, &dotlock); } if (fd_out == -1) { if (errno == EAGAIN) {
--- a/src/lib-storage/mail-storage-private.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/mail-storage-private.h Sat Jun 27 20:39:30 2009 -0400 @@ -205,6 +205,8 @@ /* mode and GID to use for newly created files/dirs */ mode_t file_create_mode, dir_create_mode; gid_t file_create_gid; + /* origin (e.g. path) where the file_create_gid was got from */ + const char *file_create_gid_origin; /* Mailbox notification settings: */ unsigned int notify_min_interval;
--- a/src/lib-storage/mailbox-list-private.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/mailbox-list-private.h Sat Jun 27 20:39:30 2009 -0400 @@ -83,6 +83,8 @@ /* -1 if not set yet. use mailbox_list_get_permissions() to set them */ mode_t file_create_mode, dir_create_mode; gid_t file_create_gid; + /* origin (e.g. path) where the file_create_gid was got from */ + const char *file_create_gid_origin; char *error_string; enum mail_error error;
--- a/src/lib-storage/mailbox-list.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/mailbox-list.c Sat Jun 27 20:39:30 2009 -0400 @@ -306,7 +306,7 @@ static void mailbox_list_get_permissions_full(struct mailbox_list *list, const char *name, mode_t *file_mode_r, mode_t *dir_mode_r, - gid_t *gid_r) + gid_t *gid_r, const char **gid_origin_r) { const char *path; struct stat st; @@ -324,16 +324,19 @@ /* return defaults */ mailbox_list_get_permissions_full(list, NULL, file_mode_r, - dir_mode_r, gid_r); + dir_mode_r, gid_r, + gid_origin_r); return; } /* return safe defaults */ *file_mode_r = 0600; *dir_mode_r = 0700; *gid_r = (gid_t)-1; + *gid_origin_r = "defaults"; } else { *file_mode_r = st.st_mode & 0666; *dir_mode_r = st.st_mode & 0777; + *gid_origin_r = path; if (!S_ISDIR(st.st_mode)) { /* we're getting permissions from a file. @@ -361,6 +364,8 @@ list->file_create_mode = *file_mode_r; list->dir_create_mode = *dir_mode_r; list->file_create_gid = *gid_r; + list->file_create_gid_origin = + p_strdup(list->pool, *gid_origin_r); } if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0 && name == NULL) { @@ -372,34 +377,40 @@ } } -void mailbox_list_get_permissions(struct mailbox_list *list, const char *name, - mode_t *mode_r, gid_t *gid_r) +void mailbox_list_get_permissions(struct mailbox_list *list, + const char *name, + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r) { mode_t dir_mode; if (list->file_create_mode != (mode_t)-1 && name == NULL) { *mode_r = list->file_create_mode; *gid_r = list->file_create_gid; + *gid_origin_r = list->file_create_gid_origin; return; } - mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r); + mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r, + gid_origin_r); } void mailbox_list_get_dir_permissions(struct mailbox_list *list, const char *name, - mode_t *mode_r, gid_t *gid_r) + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r) { mode_t file_mode; if (list->dir_create_mode != (mode_t)-1 && name == NULL) { *mode_r = list->dir_create_mode; *gid_r = list->file_create_gid; + *gid_origin_r = list->file_create_gid_origin; return; } mailbox_list_get_permissions_full(list, name, &file_mode, - mode_r, gid_r); + mode_r, gid_r, gid_origin_r); } bool mailbox_list_is_valid_pattern(struct mailbox_list *list,
--- a/src/lib-storage/mailbox-list.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib-storage/mailbox-list.h Sat Jun 27 20:39:30 2009 -0400 @@ -148,13 +148,16 @@ /* Returns the mode and GID that should be used when creating new files to the specified mailbox, or to mailbox list root if name is NULL. (gid_t)-1 is returned if it's not necessary to change the default gid. */ -void mailbox_list_get_permissions(struct mailbox_list *list, const char *name, - mode_t *mode_r, gid_t *gid_r); +void mailbox_list_get_permissions(struct mailbox_list *list, + const char *name, + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_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, const char *name, - mode_t *mode_r, gid_t *gid_r); + mode_t *mode_r, gid_t *gid_r, + const char **gid_origin_r); /* Returns TRUE if the name doesn't contain any invalid characters. The create name check can be more strict. */
--- a/src/lib/eacces-error.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/eacces-error.c Sat Jun 27 20:39:30 2009 -0400 @@ -88,8 +88,9 @@ const struct group *group; string_t *errmsg; struct stat st, dir_st; - int ret = -1; + int orig_errno, ret = -1; + orig_errno = errno; errmsg = t_str_new(256); str_printfa(errmsg, "%s(%s) failed: Permission denied (euid=%s", func, path, dec2str(geteuid())); @@ -145,6 +146,7 @@ str_printfa(errmsg, " UNIX perms seem ok, ACL problem?"); } str_append_c(errmsg, ')'); + errno = orig_errno; return str_c(errmsg); } @@ -157,3 +159,29 @@ { return eacces_error_get_full(func, path, TRUE); } + +const char *eperm_error_get_chgrp(const char *func, const char *path, + gid_t gid, const char *gid_origin) +{ + string_t *errmsg; + const struct group *group; + int orig_errno = errno; + + errmsg = t_str_new(256); + + str_printfa(errmsg, "%s(%s, -1, %s", func, path, dec2str(gid)); + group = getgrgid(gid); + if (group != NULL) + str_printfa(errmsg, "(%s)", group->gr_name); + + str_printfa(errmsg, ") failed: Operation not permitted (egid=%s", + dec2str(getegid())); + group = getgrgid(getegid()); + if (group != NULL) + str_printfa(errmsg, "(%s)", group->gr_name); + if (gid_origin != NULL) + str_printfa(errmsg, ", group based on %s", gid_origin); + str_append_c(errmsg, ')'); + errno = orig_errno; + return str_c(errmsg); +}
--- a/src/lib/eacces-error.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/eacces-error.h Sat Jun 27 20:39:30 2009 -0400 @@ -4,5 +4,10 @@ /* Return a user-friendly error message for EACCES failures. */ const char *eacces_error_get(const char *func, const char *path); const char *eacces_error_get_creating(const char *func, const char *path); +/* Return a user-friendly error message for fchown() or chown() EPERM + failures when only the group is being changed. gid_origin specifies why + exactly this group is being used. */ +const char *eperm_error_get_chgrp(const char *func, const char *path, + gid_t gid, const char *gid_origin); #endif
--- a/src/lib/file-dotlock.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/file-dotlock.c Sat Jun 27 20:39:30 2009 -0400 @@ -6,6 +6,7 @@ #include "hex-binary.h" #include "hostpid.h" #include "randgen.h" +#include "eacces-error.h" #include "write-full.h" #include "safe-mkstemp.h" #include "nfs-workarounds.h" @@ -765,10 +766,11 @@ return dotlock->fd; } -int file_dotlock_open_mode(const struct dotlock_settings *set, const char *path, - enum dotlock_create_flags flags, - mode_t mode, uid_t uid, gid_t gid, - struct dotlock **dotlock_r) +static int +file_dotlock_open_mode_full(const struct dotlock_settings *set, const char *path, + enum dotlock_create_flags flags, + mode_t mode, uid_t uid, gid_t gid, + const char *gid_origin, struct dotlock **dotlock_r) { struct dotlock *dotlock; mode_t old_mask; @@ -780,9 +782,15 @@ if (fd != -1) { if (fchown(fd, uid, gid) < 0) { - i_error("fchown(%s, %ld, %ld) failed: %m", - file_dotlock_get_lock_path(dotlock), - (long)uid, (long)gid); + if (errno == EPERM && uid == (uid_t)-1) { + i_error("%s", eperm_error_get_chgrp("fchown", + file_dotlock_get_lock_path(dotlock), + gid, gid_origin)); + } else { + i_error("fchown(%s, %ld, %ld) failed: %m", + file_dotlock_get_lock_path(dotlock), + (long)uid, (long)gid); + } file_dotlock_delete(&dotlock); return -1; } @@ -791,6 +799,24 @@ return fd; } +int file_dotlock_open_mode(const struct dotlock_settings *set, const char *path, + enum dotlock_create_flags flags, + mode_t mode, uid_t uid, gid_t gid, + struct dotlock **dotlock_r) +{ + return file_dotlock_open_mode_full(set, path, flags, mode, uid, gid, + NULL, dotlock_r); +} + +int file_dotlock_open_group(const struct dotlock_settings *set, const char *path, + enum dotlock_create_flags flags, + mode_t mode, gid_t gid, const char *gid_origin, + struct dotlock **dotlock_r) +{ + return file_dotlock_open_mode_full(set, path, flags, mode, (uid_t)-1, + gid, gid_origin, dotlock_r); +} + int file_dotlock_replace(struct dotlock **dotlock_p, enum dotlock_replace_flags flags) {
--- a/src/lib/file-dotlock.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/file-dotlock.h Sat Jun 27 20:39:30 2009 -0400 @@ -73,6 +73,10 @@ enum dotlock_create_flags flags, mode_t mode, uid_t uid, gid_t gid, struct dotlock **dotlock_r); +int file_dotlock_open_group(const struct dotlock_settings *set, const char *path, + enum dotlock_create_flags flags, + mode_t mode, gid_t gid, const char *gid_origin, + struct dotlock **dotlock_r); /* Replaces the file dotlock protects with the dotlock file itself. */ int file_dotlock_replace(struct dotlock **dotlock, enum dotlock_replace_flags flags);
--- a/src/lib/mkdir-parents.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/mkdir-parents.c Sat Jun 27 20:39:30 2009 -0400 @@ -1,15 +1,22 @@ /* Copyright (c) 2003-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "str.h" +#include "eacces-error.h" #include "mkdir-parents.h" #include <sys/stat.h> #include <unistd.h> +#include <pwd.h> +#include <grp.h> -int mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) +static int +mkdir_chown_full(const char *path, mode_t mode, uid_t uid, + gid_t gid, const char *gid_origin) { + string_t *str; mode_t old_mask; - int ret; + int ret, orig_errno; old_mask = umask(0); ret = mkdir(path, mode); @@ -26,20 +33,57 @@ return -1; } if (chown(path, uid, gid) < 0) { - i_error("chown(%s, %ld, %ld) failed: %m", path, - uid == (uid_t)-1 ? -1L : (long)uid, - gid == (gid_t)-1 ? -1L : (long)gid); + if (errno == EPERM && uid == (uid_t)-1) { + i_error("%s", eperm_error_get_chgrp("chown", path, gid, + gid_origin)); + return -1; + } + orig_errno = errno; + + str = t_str_new(256); + str_printfa(str, "chown(%s, %ld", path, + uid == (uid_t)-1 ? -1L : (long)uid); + if (uid != (uid_t)-1) { + struct passwd *pw = getpwuid(uid); + + if (pw != NULL) + str_printfa(str, "(%s)", pw->pw_name); + + } + str_printfa(str, ", %ld", + gid == (gid_t)-1 ? -1L : (long)gid); + if (gid != (gid_t)-1) { + struct group *gr = getgrgid(uid); + + if (gr != NULL) + str_printfa(str, "(%s)", gr->gr_name); + } + errno = orig_errno; + i_error("%s) failed: %m", str_c(str)); return -1; } return 0; } -int mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) +int mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) +{ + return mkdir_chown_full(path, mode, uid, gid, NULL); +} + +int mkdir_chgrp(const char *path, mode_t mode, + gid_t gid, const char *gid_origin) +{ + return mkdir_chown_full(path, mode, (uid_t)-1, gid, gid_origin); +} + +static int +mkdir_parents_chown_full(const char *path, mode_t mode, uid_t uid, gid_t gid, + const char *gid_origin) { const char *p; int ret; - if (mkdir_chown(path, mode, uid, gid) < 0) { + if (mkdir_chown_full(path, mode, uid, gid, gid_origin) < 0) { if (errno != ENOENT) return -1; @@ -49,19 +93,31 @@ return -1; /* shouldn't happen */ T_BEGIN { - ret = mkdir_parents_chown(t_strdup_until(path, p), - mode, uid, gid); + ret = mkdir_parents_chown_full(t_strdup_until(path, p), + mode, uid, + gid, gid_origin); } T_END; if (ret < 0) return -1; /* should work now */ - if (mkdir_chown(path, mode, uid, gid) < 0) + if (mkdir_chown_full(path, mode, uid, gid, gid_origin) < 0) return -1; } return 0; } +int mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) +{ + return mkdir_parents_chown_full(path, mode, uid, gid, NULL); +} + +int mkdir_parents_chgrp(const char *path, mode_t mode, + gid_t gid, const char *gid_origin) +{ + return mkdir_parents_chown_full(path, mode, (uid_t)-1, gid, gid_origin); +} + int mkdir_parents(const char *path, mode_t mode) { return mkdir_parents_chown(path, mode, (uid_t)-1, (gid_t)-1);
--- a/src/lib/mkdir-parents.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/mkdir-parents.h Sat Jun 27 20:39:30 2009 -0400 @@ -7,10 +7,17 @@ int mkdir_parents(const char *path, mode_t mode); /* Like mkdir_parents(), but use the given uid/gid for newly created - directories. */ + directories. (uid_t)-1 or (gid_t)-1 can be used to indicate that it + doesn't need to be changed. */ int mkdir_parents_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +/* Like mkdir_parents_chown(), but change only group. If chown() fails with + EACCES, use gid_origin in the error message. */ +int mkdir_parents_chgrp(const char *path, mode_t mode, + gid_t gid, const char *gid_origin); /* Like mkdir_parents_chown(), but don't actually create any parents. */ int mkdir_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_chgrp(const char *path, mode_t mode, + gid_t gid, const char *gid_origin); #endif
--- a/src/lib/safe-mkstemp.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/safe-mkstemp.c Sat Jun 27 20:39:30 2009 -0400 @@ -5,13 +5,16 @@ #include "hex-binary.h" #include "randgen.h" #include "hostpid.h" +#include "eacces-error.h" #include "safe-mkstemp.h" #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> -int safe_mkstemp(string_t *prefix, mode_t mode, uid_t uid, gid_t gid) +static int +safe_mkstemp_full(string_t *prefix, mode_t mode, uid_t uid, gid_t gid, + const char *gid_origin) { size_t prefix_len; struct stat st; @@ -45,22 +48,46 @@ return -1; } } - if (uid != (uid_t)-1 || gid != (gid_t)-1) { - if (fchown(fd, uid, gid) < 0) { + if (uid == (uid_t)-1 && gid == (gid_t)-1) + return fd; + + if (fchown(fd, uid, gid) < 0) { + if (errno == EPERM) { + i_error("%s", eperm_error_get_chgrp("fchown", + str_c(prefix), gid, gid_origin)); + } else { i_error("fchown(%s, %ld, %ld) failed: %m", str_c(prefix), uid == (uid_t)-1 ? -1L : (long)uid, gid == (gid_t)-1 ? -1L : (long)gid); - (void)close(fd); - (void)unlink(str_c(prefix)); - return -1; } + (void)close(fd); + (void)unlink(str_c(prefix)); + return -1; } return fd; } +int safe_mkstemp(string_t *prefix, mode_t mode, uid_t uid, gid_t gid) +{ + return safe_mkstemp_full(prefix, mode, uid, gid, NULL); +} + +int safe_mkstemp_group(string_t *prefix, mode_t mode, + gid_t gid, const char *gid_origin) +{ + return safe_mkstemp_full(prefix, mode, (uid_t)-1, gid, gid_origin); +} + int safe_mkstemp_hostpid(string_t *prefix, mode_t mode, uid_t uid, gid_t gid) { str_printfa(prefix, "%s.%s.", my_hostname, my_pid); return safe_mkstemp(prefix, mode, uid, gid); } + +int safe_mkstemp_hostpid_group(string_t *prefix, mode_t mode, + gid_t gid, const char *gid_origin) +{ + str_printfa(prefix, "%s.%s.", my_hostname, my_pid); + return safe_mkstemp_group(prefix, mode, gid, gid_origin); +}
--- a/src/lib/safe-mkstemp.h Sat Jun 27 19:55:17 2009 -0400 +++ b/src/lib/safe-mkstemp.h Sat Jun 27 20:39:30 2009 -0400 @@ -5,7 +5,11 @@ created filename. uid and gid can be (uid_t)-1 and (gid_t)-1 to use the defaults. */ int safe_mkstemp(string_t *prefix, mode_t mode, uid_t uid, gid_t gid); +int safe_mkstemp_group(string_t *prefix, mode_t mode, + gid_t gid, const char *gid_origin); /* Append host and PID to the prefix. */ int safe_mkstemp_hostpid(string_t *prefix, mode_t mode, uid_t uid, gid_t gid); +int safe_mkstemp_hostpid_group(string_t *prefix, mode_t mode, + gid_t gid, const char *gid_origin); #endif
--- a/src/plugins/acl/acl-backend-vfile-acllist.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/plugins/acl/acl-backend-vfile-acllist.c Sat Jun 27 20:39:30 2009 -0400 @@ -171,7 +171,7 @@ struct mail_namespace *ns; struct mailbox_list_iterate_context *iter; const struct mailbox_info *info; - const char *rootdir, *acllist_path; + const char *rootdir, *acllist_path, *origin; struct ostream *output; struct stat st; string_t *path; @@ -198,8 +198,8 @@ /* Build it into a temporary file and rename() over. There's no need to use locking, because even if multiple processes are rebuilding the file at the same time the result should be the same. */ - mailbox_list_get_permissions(list, NULL, &mode, &gid); - fd = safe_mkstemp(path, mode, (uid_t)-1, gid); + mailbox_list_get_permissions(list, NULL, &mode, &gid, &origin); + fd = safe_mkstemp_group(path, mode, gid, origin); if (fd == -1) { if (errno == EACCES) { /* Ignore silently if we can't create it */
--- a/src/plugins/acl/acl-backend-vfile.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/plugins/acl/acl-backend-vfile.c Sat Jun 27 20:39:30 2009 -0400 @@ -840,18 +840,18 @@ struct dotlock **dotlock_r) { struct acl_object *_aclobj = &aclobj->aclobj; + const char *gid_origin; mode_t mode; gid_t gid; int fd; /* first lock the ACL file */ mailbox_list_get_permissions(_aclobj->backend->list, _aclobj->name, - &mode, &gid); - fd = file_dotlock_open_mode(&dotlock_set, aclobj->local_path, 0, - mode, (uid_t)-1, gid, dotlock_r); + &mode, &gid, &gid_origin); + fd = file_dotlock_open_group(&dotlock_set, aclobj->local_path, 0, + mode, gid, gid_origin, dotlock_r); if (fd == -1) { - i_error("file_dotlock_open_mode(%s) failed: %m", - aclobj->local_path); + i_error("file_dotlock_open(%s) failed: %m", aclobj->local_path); return -1; }
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c Sat Jun 27 20:39:30 2009 -0400 @@ -381,6 +381,7 @@ { const char *dest_name = *_dest_name; const char *srcdir, *src2dir, *src3dir, *destdir, *p, *destparent; + const char *origin; struct stat st; mode_t mode; gid_t gid; @@ -401,9 +402,9 @@ return 0; mailbox_list_get_dir_permissions(dest_list, NULL, - &mode, &gid); - if (mkdir_parents_chown(destparent, mode, - (uid_t)-1, gid) < 0) { + &mode, &gid, &origin); + if (mkdir_parents_chgrp(destparent, mode, + gid, origin) < 0) { if (errno == EEXIST) { /* race condition */ continue;
--- a/src/plugins/quota/quota-maildir.c Sat Jun 27 19:55:17 2009 -0400 +++ b/src/plugins/quota/quota-maildir.c Sat Jun 27 20:39:30 2009 -0400 @@ -222,7 +222,7 @@ struct mail_storage *const *storages; unsigned int i, count; struct dotlock *dotlock; - const char *p, *dir; + const char *p, *dir, *gid_origin, *dir_gid_origin; string_t *str; mode_t mode, dir_mode; gid_t gid, dir_gid; @@ -232,42 +232,40 @@ /* figure out what permissions we should use for maildirsize. use the inbox namespace's permissions if possible. */ - mode = 0600; dir_mode = 0700; + mode = 0600; dir_mode = 0700; gid_origin = "default"; gid = dir_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, - NULL, &mode, &gid); + NULL, &mode, &gid, + &gid_origin); mailbox_list_get_dir_permissions(storages[i]->ns->list, NULL, - &dir_mode, &dir_gid); + &dir_mode, &dir_gid, + &dir_gid_origin); break; } } dotlock_settings.use_excl_lock = getenv("DOTLOCK_USE_EXCL") != NULL; dotlock_settings.nfs_flush = getenv("MAIL_NFS_STORAGE") != NULL; - fd = file_dotlock_open_mode(&dotlock_settings, path, - DOTLOCK_CREATE_FLAG_NONBLOCK, - mode, (uid_t)-1, gid, &dotlock); + fd = file_dotlock_open_group(&dotlock_settings, path, + DOTLOCK_CREATE_FLAG_NONBLOCK, + mode, gid, gid_origin, &dotlock); if (fd == -1 && errno == ENOENT) { /* the control directory doesn't exist yet? create it */ p = strrchr(path, '/'); dir = t_strdup_until(path, p); - if (mkdir_parents(dir, dir_mode) < 0 && errno != EEXIST) { + if (mkdir_parents_chgrp(dir, dir_mode, dir_gid, + dir_gid_origin) < 0 && + errno != EEXIST) { i_error("mkdir_parents(%s) failed: %m", dir); return -1; } - if (dir_gid != (gid_t)-1) { - if (chown(dir, (uid_t)-1, dir_gid) < 0) { - i_error("chown(%s,-1,%ld) failed: %m", - dir, (long)dir_gid); - } - } - fd = file_dotlock_open_mode(&dotlock_settings, path, - DOTLOCK_CREATE_FLAG_NONBLOCK, - mode, (uid_t)-1, gid, &dotlock); + fd = file_dotlock_open_group(&dotlock_settings, path, + DOTLOCK_CREATE_FLAG_NONBLOCK, + mode, gid, gid_origin, &dotlock); } if (fd == -1) { if (errno == EAGAIN) {