mailbox-list.c revision 6600c05e2ab38e9f662582b63c56b0c980a03748
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen then start renaming them to larger names from end to beginning, which
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen eventually would start causing the failures when trying to use too
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen long mailbox names. */
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen unsigned int i, count;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen for (i = 0; i < count; i++) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
4b41116563110d00330896a568eff1078c382827Timo Sirainen unsigned int idx;
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
6060b7c8edf8fce73470d0df6a2479b69b01c537Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
fe6c1556d3529a6376d4cbb3766c34aebde0de99Timo Sirainen unsigned int idx;
4b41116563110d00330896a568eff1078c382827Timo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen unsigned int idx;
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen enum mailbox_list_flags flags, const char **error_r)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen unsigned int idx;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen set->maildir_name != NULL && *set->maildir_name != '\0') {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen *error_r = "maildir_name not supported by this driver";
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen *error_r = "alt_dir not supported by this driver";
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen /* copy settings */
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen list->set.index_dir = set->index_dir == NULL ||
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen list->set.control_dir = set->control_dir == NULL ||
a0b0d629931773c17a236f6214adbe0e13b9b3fdTimo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen p_strdup(list->pool, set->subscription_fname);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainenstatic int fix_path(struct mail_user *user, const char *path,
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen "No home directory for system user. "
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_user_try_home_expand(user, &path) < 0) {
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen *error_r = "Home directory not set for user. "
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen "Can't expand ~/ for ";
aa215ab623706463cea1d047f975ffe51d3f0c05Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen /* string ends with ":", just ignore it. */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainenint mailbox_list_settings_parse(struct mail_user *user, const char *data,
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const char **error_r)
f480b30abdddf6f1beb8a2c5b1ce4bf8999400dbTimo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen /* <root dir> */
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen if (fix_path(user, str, &set_r->root_dir, &error) < 0) {
64a67c0296b120b6e15169ac9d84dec964e55969Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (fix_path(user, value, dest, &error) < 0) {
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen if (set_r->index_dir != NULL && strcmp(set_r->index_dir, "MEMORY") == 0)
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenconst char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const char *location = list->ns->unexpanded_set->location;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen const char *p, *error;
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen if (*location == SETTING_STRVAR_EXPANDED[0]) {
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen /* set using -o or userdb lookup. */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen mail_set = mail_user_set_get_driver_settings(user->set_info,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen user->unexpanded_set, MAIL_STORAGE_SET_DRIVER_NAME);
location++;
if (p == NULL)
struct mail_namespace *
return mode;
struct mail_user *
const char *path;
path);
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;
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;