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);
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);
#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"
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);
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;
#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"
}
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;
}
}
- if (mkdir_parents(dir, CREATE_MODE) == 0)
+ if (mkdir_parents_chown(dir, mode, (uid_t)-1, gid) == 0)
return 0;
if (errno == EEXIST) {
/* 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);
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;
}
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) {
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);
}
/* 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);
{
const char *path;
mode_t old_mask;
- unsigned int i;
int fd;
/* add the execute bit if either read or write bit is set */
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);
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;
}
"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 */
{
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);
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);
#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;
{
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);
/* 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;
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)
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) {
*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)
{
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. */
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 */