mailbox-list.c revision 2a6dcd984104fed84bed8795ccdfabb20e41ce52
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2010 Dovecot authors, see the included COPYING file */
afa201e7e1d2447e8dfa1aff43de0fdad564105fTimo 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. */
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainen struct mailbox_list_iterate_context *backend_ctx;
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
c6227d7ecc972b6c58602d78602210f75190ae3fTimo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
860e6dd603921f61b0cd53c1cc16e1d66d312699Timo Sirainen unsigned int i, count;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen for (i = 0; i < count; i++) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen unsigned int idx;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen array_append(&mailbox_list_drivers, &list, 1);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen unsigned int idx;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen unsigned int idx;
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen enum mailbox_list_flags flags, const char **error_r)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int idx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "maildir_name not supported by this driver";
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = "alt_dir not supported by this driver";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen /* copy settings */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
7baab0b0b60df7ce9093d0881cd322dff1e79491Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi list->set.control_dir = set->control_dir == NULL ||
4b2a4c8c762e3eaddf7fd2abfe7d4cca6e5e3fd8Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen p_strdup(list->pool, set->subscription_fname);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ? "" :
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("%s: root=%s, index=%s, control=%s, inbox=%s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
1127f3e1ad7135b6ee5d5e13f8fd1e72f85a76f8Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
7e1b549a1d841e59faad16430cbd1d56317db8afTimo Sirainen "No home directory for system user. "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek *error_r = "Home directory not set for user. "
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen "Can't expand ~/ for ";
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* string ends with ":", just ignore it. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mailbox_list_settings_parse(const char *data,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_namespace *ns, const char **error_r)
29337701451b9c9f9dd26b2aec23a31ab5203822Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* <root dir> */
fa7c76955c6bc62689fbdf39318194f85905e6e2Timo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
df3963075d67f76ade66b6a74764f4eae31d9c87Josef 'Jeff' Sipek *error_r = t_strdup_printf("Unknown setting: %s", key);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
57bf90f66f393c2807b2fc543655013f61d1d9e4Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
607a8bc27298b711270381364f2a9a999a810a87Timo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
7b15788793354ca0fd4fdb4dda8e426ca1e9e9d7Timo Sirainen /* add the execute bit if either read or write bit is set */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Boschint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
e5fb952c6d49d3b6bff1746551566202e92947daTimo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen /* use safe defaults */
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen /* no filesystem support in storage */
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi } else if (list->mail_set->mail_debug) {
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi i_debug("Namespace %s: Permission lookup failed from %s",
c72fbbe6328ceb0919b5146ecd43817dc294c314Timo Sirainen /* return defaults */
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen /* we're getting permissions from a file.
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen apply +x modes as necessary. */
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* directory's GID is used automatically for new
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* group has same permissions as world, so don't bother
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen changing it */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* using our own gid, no need to change it */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_debug("Namespace %s: Using permissions from %s: "
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
eadbca0f2b78fcc36332678fee9ee08003df63deTimo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
2b9e49e4e65e3e2dca38f56971029a3051ccdb99Timo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
306cfd77100131c08b243de10f6d40500f4c27c6Timo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen mailbox_list_get_permissions_full(list, name, &file_mode,
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainenbool mailbox_list_is_valid_pattern(struct mailbox_list *list,
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen ret = list->v.is_valid_pattern(list, pattern);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenbool mailbox_list_is_valid_existing_name(struct mailbox_list *list,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*name == '\0' && *list->ns->prefix != '\0') {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* an ugly way to get to mailbox root (e.g. Maildir/ when
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen it's not the INBOX) */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = list->v.is_valid_existing_name(list, name);
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainenbool mailbox_list_is_valid_create_name(struct mailbox_list *list,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *p;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* safer to just disallow all control characters */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (*p < ' ')
} 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;