]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Use permissions based on mail root directory when creating new files/dirs under it.
authorTimo Sirainen <tss@iki.fi>
Sun, 20 Jul 2008 20:20:19 +0000 (23:20 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 20 Jul 2008 20:20:19 +0000 (23:20 +0300)
--HG--
branch : HEAD

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

index 27b4c87004d50fec6220f6134c6f135e983293c6..278352b39503132c8b0729849c8ea800da7d3c41 100644 (file)
@@ -130,7 +130,12 @@ static int cydir_create(struct mail_storage *_storage, const char *data,
 
 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);
index c089ff818ce3d932751c50841fc200c7cb451398..e974119d6c79c8a19f93cae868cc526c8e9e9560 100644 (file)
@@ -146,7 +146,12 @@ static int dbox_create(struct mail_storage *_storage, const char *data,
 
 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);
index 59c943bff94c50c0c4fa1261a0fe9729e53b4bc5..7473190b76aec6d798cb0302d5dce07075687add 100644 (file)
@@ -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 @@ static void index_list_free(struct index_list *list)
        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 @@ static int create_index_dir(struct mail_storage *storage, const char *name)
        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;
index 3299d1ee2e24a4f10bdedc2d0cf84de547500f3f..f3c86cebc4be47d84285920bd373886535c41de0 100644 (file)
@@ -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 bool maildir_autodetect(const char *data, enum mail_storage_flags flags)
 }
 
 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 @@ static int mkdir_verify(struct mail_storage *storage,
                }
        }
 
-       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 @@ static int maildir_check_tmp(struct mail_storage *storage, const char *dir)
 
 /* 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 @@ static int create_maildir(struct mail_storage *storage,
                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 @@ maildir_mailbox_open(struct mail_storage *_storage, const char *name,
        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 @@ maildir_mailbox_open(struct mail_storage *_storage, const char *name,
        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 @@ maildir_mailbox_open(struct mail_storage *_storage, const char *name,
        /* 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 @@ static int maildir_create_shared(struct mail_storage *storage,
 {
        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 @@ static int maildir_create_shared(struct mail_storage *storage,
        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 @@ static int maildir_mailbox_create(struct mail_storage *_storage,
                                          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;
        }
 
index ffbfc2502f347e99aa35b5e63b4007ce66e312a2..1c3416b45945b86c4eb924dc27442ac8dd7c29f9 100644 (file)
@@ -115,7 +115,8 @@ static int maildir_create_subdirs(struct maildir_mailbox *mbox)
                                                  "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 */
index 85f07d67a7d65bdaf62c84c4cc50d0a6923ad630..9bb24e74b586dd8b81ef44ff30e1dfdd4f2d3762 100644 (file)
@@ -692,9 +692,10 @@ static int mbox_mailbox_create(struct mail_storage *_storage, const char *name,
 {
        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 @@ static int mbox_mailbox_create(struct mail_storage *_storage, const char *name,
        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);
index da62552c566f26b0ff7f0bf6651f138f11fa6131..eff14501b3cec97b609f21e625d5652b94de31a5 100644 (file)
@@ -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 @@ static int fs_list_rename_mailbox(struct mailbox_list *list,
 {
        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 @@ static int fs_list_rename_mailbox(struct mailbox_list *list,
        /* 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;
 
index 69c5fff5c8b3ee1d63d86aebf682707c5320038a..f79b9ff68778c78ea8c422340ce28812f1c54fdf 100644 (file)
@@ -82,6 +82,8 @@ int subsfile_set_subscribed(struct mailbox_list *list, const char *path,
        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 @@ int subsfile_set_subscribed(struct mailbox_list *list, const char *path,
        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) {
index 43665c1536d82957fd5a8c507919ad0ea8e104f7..3dff964fa68a4e817cd5af56b20f8624c60ed4d8 100644 (file)
@@ -291,6 +291,21 @@ void mailbox_list_get_permissions(struct mailbox_list *list,
        *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)
 {
index 9bdf9fdc3cfbb059e7a14afa495a6bd0a1bfa576..7cbd458abb62a14fd2237ba73c00edf20aa65a65 100644 (file)
@@ -141,6 +141,10 @@ mailbox_list_get_namespace(const struct mailbox_list *list) ATTR_PURE;
    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. */
index f81326fc428a61bdf4a48f9bdfb179edcbdb32a6..d73c7f8bc926e78fc77979b26d7e4ed0d93eb0fa 100644 (file)
@@ -218,16 +218,34 @@ maildirs_check_have_changed(struct maildir_quota_root *root,
 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 */