mailbox-list.c revision c58c12049c883b281c088d47a2a7278c21c390e1
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen then start renaming them to larger names from end to beginning, which
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen eventually would start causing the failures when trying to use too
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen long mailbox names. */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen unsigned int i, count;
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen for (i = 0; i < count; i++) {
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen unsigned int idx;
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen array_append(&mailbox_list_drivers, &list, 1);
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen unsigned int idx;
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen unsigned int idx;
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen enum mailbox_list_flags flags, const char **error_r)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen unsigned int idx;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen set->maildir_name != NULL && *set->maildir_name != '\0') {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = "maildir_name not supported by this driver";
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = "alt_dir not supported by this driver";
0482d891a6669537e10a1abc9866b45f2fc55fccTimo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
e869616aca1c2469c436e1e99dad93f7e4b2ae8aTimo Sirainen /* copy settings */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
af5fc8ca268d69dd3ebbe0416ec6270f94121e39Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
af5fc8ca268d69dd3ebbe0416ec6270f94121e39Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen p_strdup(list->pool, set->subscription_fname);
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainenstatic int fix_path(struct mail_user *user, const char *path,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen "No home directory for system user. "
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (mail_user_try_home_expand(user, &path) < 0) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = "Home directory not set for user. "
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen "Can't expand ~/ for ";
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* string ends with ":", just ignore it. */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenint mailbox_list_settings_parse(struct mail_user *user, const char *data,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen const char **error_r)
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* <root dir> */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (fix_path(user, str, &set_r->root_dir, &error) < 0) {
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (strncmp(set_r->root_dir, "INBOX=", 6) == 0) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* probably mbox user trying to avoid root_dir */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = t_strconcat("Mail root directory not given: ",
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen if (fix_path(user, value, dest, &error) < 0) {
075081e25ef07989be10f7c9cf85f833f90be46fTimo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen if (set_r->index_dir != NULL && strcmp(set_r->index_dir, "MEMORY") == 0)
6307d76096764e66bddc63d4a3e5a1aa19cc528fJosef 'Jeff' Sipekconst char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen const char *location = list->ns->unexpanded_set->location;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen const char *p, *error;
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (*location == SETTING_STRVAR_EXPANDED[0]) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* set using -o or userdb lookup. */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen mail_set = mail_user_set_get_driver_settings(user->set_info,
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen user->unexpanded_set, MAIL_STORAGE_SET_DRIVER_NAME);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* type:settings */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (mailbox_list_settings_parse(user, p + 1, &set, &error) < 0)
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen return mailbox_list_get_root_path(&set, type);
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen /* add the execute bit if either read or write bit is set */
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
108340ffacae3b7d09fa51b566d77aa51dd6483bTimo Sirainen /* use safe defaults */
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen /* no filesystem support in storage */
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
9d0be57bcc352f776a327d7e2a6c6232137f4a04Timo Sirainen i_debug("Namespace %s: Permission lookup failed from %s",
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* return defaults */
24d6fd2b8e2c327ae2a20a0c4be8af2ef7b3b468Timo Sirainen /* we're getting permissions from a file.
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen apply +x modes as necessary. */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* directory's GID is used automatically for new
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* group has same permissions as world, so don't bother
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen changing it */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen /* using our own gid, no need to change it */
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
8aeae03f9f447c8a792b215c9fb954468053c556Timo Sirainen i_debug("Namespace %s: Using permissions from %s: "
const char *name,
const char **gid_origin_r)
const char *name,
const char **gid_origin_r)
path);
if (p == NULL)
const char *expanded_full)
const char *ret;
slash_count++;
slash2_count++;
if (slash_count == 0)
slash_count--;
if (slash_count != 0)
if (slash2_count == 0)
slash2_count--;
if (slash2_count != 0)
return ret;
if (p == NULL)
if (p == unexpanded)
const char *pattern)
bool ret;
T_BEGIN {
} T_END;
return ret;
const char *name)
bool ret;
return TRUE;
T_BEGIN {
} T_END;
return ret;
const char *name)
int ret;
return FALSE;
T_BEGIN {
} T_END;
const char *path;
switch (type) {
i_unreached();
return pattern;
const char *name,
struct mailbox_list_iterate_context *
struct mailbox_list_iterate_context *
const char *const *patterns,
return FALSE;
return FALSE;
return TRUE;
return FALSE;
const char *pattern)
const char *prefix_without_sep;
unsigned int len;
len--;
NAMESPACE_FLAG_LIST_CHILDREN)) == 0) {
return FALSE;
switch (result) {
case IMAP_MATCH_YES:
case IMAP_MATCH_CHILDREN:
return TRUE;
case IMAP_MATCH_NO:
case IMAP_MATCH_PARENT:
return FALSE;
switch (result) {
case IMAP_MATCH_YES:
return TRUE;
case IMAP_MATCH_CHILDREN: {
T_BEGIN {
} T_END;
return TRUE;
case IMAP_MATCH_NO:
case IMAP_MATCH_PARENT:
return FALSE;
return FALSE;
T_BEGIN {
} T_END;
static struct mail_namespace *
return ns;
static const struct mailbox_info *
return info;
int ret;
return ret;
unsigned int count)
const char **dup;
for (i = 0; i < count; i++) {
dup[i] = p;
return dup;
struct mailbox_list_iterate_context *
const char *const *patterns,
unsigned int i, count;
for (i = 0; i < count; i++)
const struct mailbox_info *
return info;
unsigned int len;
fname++;
const char *path;
const char *gid_origin;
return TRUE;
return FALSE;
return TRUE;
int ret;
return ret;
const char *name)
if (created) {
if (create_flags != 0)
if (p == NULL)
const char *name)
T_BEGIN {
} T_END;
return TRUE;
levels++;
level_len = 0;
level_len++;
return TRUE;
return TRUE;
return FALSE;
#ifdef HAVE_DIRENT_D_TYPE
switch (d->d_type) {
case DT_UNKNOWN:
case DT_REG:
case DT_DIR:
case DT_LNK:
return type;
return FALSE;
return FALSE;
return TRUE;
const char **name)
unsigned int len;
return FALSE;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
if (p == NULL)
dir);
const char *name)
const char *error_string;
return FALSE;
return TRUE;