mailbox-list.c revision e22efc90e109ade2936eea0b062a99480310fd41
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen then start renaming them to larger names from end to beginning, which
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen eventually would start causing the failures when trying to use too
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen long mailbox names. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mailbox_list_iterate_context *backend_ctx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int i, count;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen for (i = 0; i < count; i++) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_append(&mailbox_list_drivers, &list, 1);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen enum mailbox_list_flags flags, const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int idx;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "maildir_name not supported by this driver";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "alt_dir not supported by this driver";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* copy settings */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.index_dir = set->index_dir == NULL ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.control_dir = set->control_dir == NULL ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strdup(list->pool, set->subscription_fname);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "No home directory for system user. "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = "Home directory not set for user. "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen "Can't expand ~/ for ";
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic const char *split_next_arg(const char *const **_args)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* string ends with ":", just ignore it. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_list_settings_parse(const char *data,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen struct mail_namespace *ns, const char **error_r)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* <root dir> */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* add the execute bit if either read or write bit is set */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* use safe defaults */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* no filesystem support in storage */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_debug("Namespace %s: Permission lookup failed from %s",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* return defaults */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we're getting permissions from a file.
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen apply +x modes as necessary. */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* directory's GID is used automatically for new
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* group has same permissions as world, so don't bother
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen changing it */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* using our own gid, no need to change it */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->mail_set->mail_debug && name == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_debug("Namespace %s: Using permissions from %s: "
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
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;
return pattern;
const char *name,
struct mailbox_list_iterate_context *
struct mailbox_list_iterate_context *
const char *const *patterns,
static struct mail_namespace *
return ns;
static const struct mailbox_info *
return info;
int ret;
return ret;
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;
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 *error_string;
return FALSE;
return TRUE;