mailbox-list.c revision 1c1cecd3dfaf71b0c9499b044023e631841e88aa
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen then start renaming them to larger names from end to beginning, which
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen eventually would start causing the failures when trying to use too
84a5175b9768da401404635c9b606264585739bdTimo Sirainen long mailbox names. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
5f4e547bb810403e8cfb19a49d8fe34713507ffdTimo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen unsigned int i, count;
d2cf6522779802d0edeab7dcf960ffea2f2e1828Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen for (i = 0; i < count; i++) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
fcb5f4cd72b413a5356a8db55e679403c6a1adb5Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int idx;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int idx;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int idx;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct mailbox_list **list_r, const char **error_r)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int idx;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
5f8d497e88fae77fbeb625246bc18260f6775b83Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen set->maildir_name != NULL && *set->maildir_name != '\0') {
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen *error_r = "maildir_name not supported by this driver";
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen *error_r = "alt_dir not supported by this driver";
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen /* copy settings */
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen p_strdup(list->pool, set->subscription_fname);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s, alt=%s",
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
afc77c5375cdb8f2bf0ab6280d9229ac27c933c6Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
84a5175b9768da401404635c9b606264585739bdTimo Sirainen list->set.alt_dir == NULL ? "" : list->set.alt_dir);
84a5175b9768da401404635c9b606264585739bdTimo Sirainen if ((flags & MAILBOX_LIST_FLAG_SECONDARY) == 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic int fix_path(struct mail_user *user, const char *path,
0d6ae58916bee3452c91d9d81be72227761ec33dTimo Sirainen if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
9f0a996c22ebe39dcfe5cb84c8fd2f22ef5ce9d8Timo Sirainen "No home directory for system user. "
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (mail_user_try_home_expand(user, &path) < 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *error_r = "Home directory not set for user. "
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "Can't expand ~/ for ";
b13d76faf0c82162c29050382cd7f4a808294622Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* string ends with ":", just ignore it. */
e130bb802c8bfb6c6cc44e5c8bc098b4fa5af789Timo Sirainenint mailbox_list_settings_parse(struct mail_user *user, const char *data,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char **error_r)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* <root dir> */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (fix_path(user, str, &set_r->root_dir, &error) < 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strncmp(set_r->root_dir, "INBOX=", 6) == 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* probably mbox user trying to avoid root_dir */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen *error_r = t_strconcat("Mail root directory not given: ",
const char *p, *error;
location++;
location++;
if (p == NULL)
vname++;
const char *vname)
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 *
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;
else 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:
const char *vname;
fname++;
flags_r);
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;
path);
if (p == NULL)
const char *name)
const char *error_string;
return FALSE;
return TRUE;