mailbox-list.c revision 9ba91492d2eb29199674b669c673332ae2b01438
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen then start renaming them to larger names from end to beginning, which
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen eventually would start causing the failures when trying to use too
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen long mailbox names. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainen unsigned int i, count;
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainen for (i = 0; i < count; i++) {
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx;
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
d7b205394bd07152718152976dfa089e13253d7eTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
b58aafbd21b365117538f73f306d22f75acd91f1Timo Sirainen unsigned int idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_list **list_r, const char **error_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
ea1f67e14d727496179ee4ff391f592bce8f4f2dTimo Sirainen set->maildir_name != NULL && *set->maildir_name != '\0') {
ea1f67e14d727496179ee4ff391f592bce8f4f2dTimo Sirainen *error_r = "maildir_name not supported by this driver";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
ea1f67e14d727496179ee4ff391f592bce8f4f2dTimo Sirainen *error_r = "alt_dir not supported by this driver";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
ea1f67e14d727496179ee4ff391f592bce8f4f2dTimo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
2d01cc1880cf2afd4fb1c8ad7fa6ce78e562e71eTimo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* copy settings */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
d22301419109ed4a38351715e6760011421dadecTimo Sirainen list->set.control_dir = set->control_dir == NULL ||
d22301419109ed4a38351715e6760011421dadecTimo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
c04f9a724a7b3cc649485a61b0a540868d25d71bTimo Sirainen p_strdup(list->pool, set->subscription_fname);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
0dc7a67fb62b2aac82ff1c03319bd4976c56dbc1Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
0dc7a67fb62b2aac82ff1c03319bd4976c56dbc1Timo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((flags & MAILBOX_LIST_FLAG_SECONDARY) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int fix_path(struct mail_user *user, const char *path,
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen "No home directory for system user. "
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen if (mail_user_try_home_expand(user, &path) < 0) {
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen *error_r = "Home directory not set for user. "
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen "Can't expand ~/ for ";
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* string ends with ":", just ignore it. */
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainenint mailbox_list_settings_parse(struct mail_user *user, const char *data,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **error_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <root dir> */
value++;
const char *p, *error;
location++;
location++;
if (p == NULL)
vname++;
const char *vname)
if (prefix_len > 0) {
return storage_name;
return storage_name;
if (*p == ns_sep)
*p = list_sep;
return ret;
const char *vname)
unsigned int num;
const char *storage_name)
for (i = 0; i < name_len; i++) {
return vname;
struct mail_namespace *
return mode;
struct mail_user *
const char *name,
path);
if (p == NULL) {
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;
struct mailbox_list_iterate_context *
struct mailbox_list_iterate_context *
const char *const *patterns,
int ret = 0;
if (ret < 0)
return ctx;
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;
const char *pattern;
int ret;
return ret;
unsigned int len;
*flags_r = 0;
int ret;
if (ret < 0) {
switch (existence) {
case MAILBOX_EXISTENCE_NONE:
case MAILBOX_EXISTENCE_SELECT:
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;
const char *origin;
path);
if (p == NULL)
const char *name)
const char *error_string;
return FALSE;
return TRUE;