mailbox-list.c revision 758d8b46f9e8fd87cf58bb4912cddf6bf28918cf
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2006-2013 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen then start renaming them to larger names from end to beginning, which
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen eventually would start causing the failures when trying to use too
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen long mailbox names. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(const struct mailbox_list *) mailbox_list_drivers;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int i, count;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen for (i = 0; i < count; i++) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen unsigned int idx;
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen unsigned int idx;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen struct mailbox_list **list_r, const char **error_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unsigned int idx;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen *error_r = "maildir_name not supported by this driver";
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen *error_r = "alt_dir not supported by this driver";
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen list->root_permissions.file_create_mode = (mode_t)-1;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen list->root_permissions.dir_create_mode = (mode_t)-1;
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen list->root_permissions.file_create_gid = (gid_t)-1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* copy settings */
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen list->set.index_pvt_dir = set->index_pvt_dir == NULL ||
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen strcmp(set->index_pvt_dir, set->root_dir) == 0 ? NULL :
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen p_strdup(list->pool, set->subscription_fname);
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
360123b1b41b7aa8af6c4a91c39046be646cd349Timo Sirainen list->set.alt_dir_nocheck = set->alt_dir_nocheck;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen i_debug("%s: root=%s, index=%s, indexpvt=%s, control=%s, inbox=%s, alt=%s",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk list->set.root_dir == NULL ? "" : list->set.root_dir,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk list->set.index_dir == NULL ? "" : list->set.index_dir,
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen list->set.index_pvt_dir == NULL ? "" : list->set.index_pvt_dir,
7920a47321690c932ffd4d286cd16b4048d22d41Timo Sirainen list->set.alt_dir == NULL ? "" : list->set.alt_dir);
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen if ((flags & MAILBOX_LIST_FLAG_SECONDARY) == 0)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenstatic int fix_path(struct mail_user *user, const char *path, bool expand_home,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* no ~ expansion */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen } else if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "No home directory for system user. "
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (mail_user_try_home_expand(user, &path) < 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = "Home directory not set for user. "
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen "Can't expand ~/ for ";
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen /* string ends with ":", just ignore it. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenmailbox_list_settings_parse_full(struct mail_user *user, const char *data,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen const char **error_r)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen /* <root dir> */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (fix_path(user, str, expand_home, &set_r->root_dir, &error) < 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen if (strncmp(set_r->root_dir, "INBOX=", 6) == 0) {
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen /* probably mbox user trying to avoid root_dir */
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen *error_r = t_strconcat("Mail root directory not given: ",
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (fix_path(user, value, expand_home, dest, &error) < 0) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (set_r->index_dir != NULL && strcmp(set_r->index_dir, "MEMORY") == 0)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainenint mailbox_list_settings_parse(struct mail_user *user, const char *data,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen const char **error_r)
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen return mailbox_list_settings_parse_full(user, data, TRUE,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenconst char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *location = list->ns->unexpanded_set->location;
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen if (*location == SETTING_STRVAR_EXPANDED[0]) {
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen /* set using -o or userdb lookup. */
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen mail_set = mail_user_set_get_driver_settings(user->set_info,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen user->unexpanded_set, MAIL_STORAGE_SET_DRIVER_NAME);
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen i_assert(*location == SETTING_STRVAR_UNEXPANDED[0]);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* type:settings */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (mailbox_list_settings_parse_full(user, p + 1, FALSE,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_set_get_root_path(&set, type, &path) <= 0)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainenstatic bool need_escape_dirstart(const char *vname, const char *maildir_name)
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen unsigned int len;
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen if (vname[1] == '.' && (vname[2] == '\0' || vname[2] == '/'))
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic const char *
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenmailbox_list_escape_name(struct mailbox_list *list, const char *vname)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen char ns_sep = mail_namespace_get_sep(list->ns);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen char list_sep = mailbox_list_get_hierarchy_sep(list);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* no escaping of namespace prefix */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (strncmp(list->ns->prefix, vname, list->ns->prefix_len) == 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_append_n(escaped_name, vname, list->ns->prefix_len);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* escape the mailbox name */
d508ab8db2b0f74b5e225d199b4aaa5293342746Timo Sirainen need_escape_dirstart(vname, list->set.maildir_name))) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_unescape_broken_chars(struct mailbox_list *list, char *name)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen unsigned char chr;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if ((src = strchr(name, list->set.broken_char)) == NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenstatic char *mailbox_list_convert_sep(const char *storage_name, char src, char dest)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = p_strdup(unsafe_data_stack_pool, storage_name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenconst char *mailbox_list_default_get_storage_name(struct mailbox_list *list,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen storage_name = mailbox_list_escape_name(list, vname);
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen if (prefix_len > 0 && (strcmp(storage_name, "INBOX") != 0 ||
e58f291e777b25c1286965b80e142ada6fdacb03Timo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* skip namespace prefix, except if this is INBOX */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (strncmp(ns->prefix, storage_name, prefix_len) == 0)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen else if (strncmp(ns->prefix, storage_name, prefix_len-1) == 0 &&
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen ns->prefix[prefix_len-1] == mail_namespace_get_sep(ns)) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* trying to access the namespace prefix itself */
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen /* we're converting a nonexistent mailbox name,
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen such as a LIST pattern. */
1c1cecd3dfaf71b0c9499b044023e631841e88aaTimo Sirainen /* UTF-8 -> mUTF-7 conversion */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(list);
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen if (*storage_name == '\0' && ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen (ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 &&
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen !list->mail_set->mail_shared_explicit_inbox) {
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* opening shared/$user. it's the same as INBOX. */
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen if (list_sep != ns_sep && list->set.escape_char == '\0') {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* shared namespace root. the backend storage's
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen hierarchy separator isn't known yet, so do
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = mailbox_list_convert_sep(storage_name, ns_sep, list_sep);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen strchr(storage_name, list->set.broken_char) == NULL) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen /* no need to convert broken chars */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen ret = p_strdup(unsafe_data_stack_pool, storage_name);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (mailbox_list_unescape_broken_chars(list, ret) < 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenconst char *mailbox_list_get_storage_name(struct mailbox_list *list,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenstatic const char *
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainenmailbox_list_unescape_name(struct mailbox_list *list, const char *src)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen char ns_sep = mail_namespace_get_sep(list->ns);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen char list_sep = mailbox_list_get_hierarchy_sep(list);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned int num;
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen if (strncmp(src, list->ns->prefix, list->ns->prefix_len) == 0) {
8f70c97f7ab7b7e1683ed5cfcd96721a899c2520Timo Sirainen str_append_n(dest, src, list->ns->prefix_len);
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_escape_broken_chars(struct mailbox_list *list, string_t *str)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen unsigned int i;
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (strchr(str_c(str), list->set.broken_char) == NULL)
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainenmailbox_list_escape_broken_name(struct mailbox_list *list,
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen if (*vname == '&' || (unsigned char)*vname >= 0x80) {
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen str_printfa(str, "%c%02x", list->set.broken_char,
1f4399a277b861419b82758ab0462e90c00a4c41Timo Sirainen (unsigned char)*vname);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenconst char *mailbox_list_default_get_vname(struct mailbox_list *list,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen /* user's INBOX - use as-is. NOTE: don't do case-insensitive
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen comparison, otherwise we can't differentiate between INBOX
9b00ecffbe74fd864d0d72e6112ec53b86f619baTimo Sirainen and <ns prefix>/inBox. */
3e0bae44b65f5c46989fcef3d1e07203f496327eTimo Sirainen list->ns->type == MAIL_NAMESPACE_TYPE_SHARED &&
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen (list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0 &&
0bd259973f98837cf0e41fdee3e2a578e51ad09eTimo Sirainen !list->mail_set->mail_shared_explicit_inbox) {
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen /* convert to shared/$user, we don't really care about the
e4cb3bfcd42f1f2c9e676ece6f7f53803f5c6a16Timo Sirainen INBOX suffix here. */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* return namespace prefix without the separator */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen /* mUTF-7 -> UTF-8 conversion */
69af83d4e6c2c5c825a17edd7a41a4fb014caa8fTimo Sirainen mailbox_list_escape_broken_name(list, vname, str);
6f970b9a0dadb80e120d017c75c637b5a3879dacTimo Sirainen vname = mailbox_list_unescape_name(list, vname);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen list_sep = mailbox_list_get_hierarchy_sep(list);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* @UNSAFE */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (i = 0; i < name_len; i++) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenconst char *mailbox_list_get_vname(struct mailbox_list *list, const char *name)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen if (hash_table_is_created(list->guid_cache)) {
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
ae2b61a8c6318e56dabd44de17e227c95985aedaTimo Sirainenmailbox_list_get_settings(const struct mailbox_list *list)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen /* add the execute bit if either read or write bit is set */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainenmailbox_list_get_storage_driver(struct mailbox_list *list, const char *driver,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen array_foreach(&list->ns->all_storages, storagep) {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen if (mail_storage_create_full(list->ns, driver, data, 0,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen "Namespace %s: Failed to create storage '%s': %s",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char *vname,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return (*list)->v.get_storage(list, vname, storage_r);
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen set = mailbox_settings_find((*list)->ns->user, vname);
4809537f0c5a2e1cee9559ec842cc869884d2cb7Timo Sirainen if (set != NULL && set->driver != NULL && set->driver[0] != '\0') {
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen return mailbox_list_get_storage_driver(*list, set->driver,
d2e74f2af690b8e2d536400f02f397cbed1334b7Timo Sirainen *storage_r = mail_namespace_get_default_storage((*list)->ns);
8709b2fe6ec2b5ca1d90a63490f8371472062efdTimo Sirainenvoid mailbox_list_get_default_storage(struct mailbox_list *list,
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen *storage = mail_namespace_get_default_storage(list->ns);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenchar mailbox_list_get_hierarchy_sep(struct mailbox_list *list)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenmailbox_list_get_permissions_internal(struct mailbox_list *list,
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen const char *path, *parent_name, *parent_path, *p;
3f2dd5867a85b15555eb43a33ea5029393a45103Timo Sirainen memset(permissions_r, 0, sizeof(*permissions_r));
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* use safe defaults */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen permissions_r->file_create_gid_origin = "defaults";
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen (void)mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_DIR,
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen mailbox_list_get_default_storage(list, &storage);
758d8b46f9e8fd87cf58bb4912cddf6bf28918cfTimo Sirainen (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen /* no filesystem support in storage */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen i_debug("Namespace %s: %s doesn't exist yet, "
e200d1ba38eeebfb0b9e60150d93753ec6d823c8Timo Sirainen "using default permissions",
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen /* return parent mailbox */
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen p = strrchr(name, mailbox_list_get_hierarchy_sep(list));
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen /* return root defaults */
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen mailbox_list_get_permissions(list, parent_name,
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen /* assume current defaults for mailboxes that don't exist or
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen can't be looked up for some other reason */
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen permissions_r->file_create_mode = (st.st_mode & 0666) | 0600;
47d5cc09738defd0020c797866e2a25a344aa65aTimo Sirainen permissions_r->dir_create_mode = (st.st_mode & 0777) | 0700;
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen permissions_r->gid_origin_is_mailbox_path = name != NULL;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* we're getting permissions from a file.
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen apply +x modes as necessary. */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* directory's GID is used automatically for new
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen /* group has same permissions as world, so don't bother
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen changing it */
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* using our own gid, no need to change it */
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen permissions_r->file_create_gid != (gid_t)-1) {
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen /* we need to stat() the parent directory to see if
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen it has setgid-bit set */
a7e1fd461a52bc597b7c0319c613dfbb6d3dc914Timo Sirainen /* directory's GID is used automatically for
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen list->root_permissions.file_create_gid_origin =
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Namespace %s: Using permissions from %s: "
dbc86748934bc34826d9cc8c43d24df09b3ba402Timo Sirainen permissions_r->file_create_gid == (gid_t)-1 ? "default" :
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list, const char *name,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen mailbox_list_get_permissions_internal(list, name, permissions_r);
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainenvoid mailbox_list_get_root_permissions(struct mailbox_list *list,
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen if (list->root_permissions.file_create_mode != (mode_t)-1)
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mailbox_list_get_permissions_internal(list, NULL,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic const char *
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenget_expanded_path(const char *unexpanded_start, const char *unexpanded_stop,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *ret;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int i, slash_count = 0, slash2_count = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* get the expanded path up to the same amount of '/' characters.
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if there isn't the same amount of '/' characters, it means %variable
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen expansion added more of them and we can't handle this. */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (i = 0; unexpanded_start+i != unexpanded_stop; i++) {
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainenmailbox_list_try_mkdir_root_parent(struct mailbox_list *list,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char **error_r)
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char *expanded, *unexpanded, *root_dir, *p;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* get the directory path up to last %variable. for example
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unexpanded path may be "/var/mail/%d/%2n/%n/Maildir", and we want
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen to get expanded="/var/mail/domain/nn" */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unexpanded = mailbox_list_get_unexpanded_path(list, type);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* home directory used */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (!mailbox_list_get_root_path(list, type, &expanded))
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen } else if (p == NULL) {
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen if (!mailbox_list_get_root_path(list, type, &expanded))
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen expanded = get_expanded_path(unexpanded, p, expanded);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* get the first existing parent directory's permissions */
70a2782edc5cb342ed67a46ce30a95ca316f86c9Timo Sirainen if (stat_first_parent(expanded, &root_dir, &st) < 0) {
c905571984fe8ccdb6f2a266b813f19b0643a66cTimo Sirainen t_strdup_printf("stat(%s) failed: %m", root_dir);
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* if the parent directory doesn't have setgid-bit enabled, we don't
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen copy any permissions from it. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* assuming we have e.g. /var/vmail/%d/%n directory, here we
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen want to create up to /var/vmail/%d with permissions from
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen the parent directory. we never want to create the %n
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen directory itself. */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* this is the %n directory */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* change the group for user directories */
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen /* when using %h and the parent has setgid-bit,
0bf25546c91ccafff9e2cc93368d2d25acb5c39eTimo Sirainen copy the permissions from it for the home we're creating */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainenint mailbox_list_try_mkdir_root(struct mailbox_list *list, const char *path,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char **error_r)
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* looks like it already exists, don't bother checking
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen mailbox_list_get_root_permissions(list, &perm);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (!mailbox_list_get_root_path(list, type, &root_dir))
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen i_assert(strncmp(root_dir, path, strlen(root_dir)) == 0);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (strcmp(root_dir, path) != 0 && stat(root_dir, &st) == 0) {
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen /* creating a subdirectory under an already existing root dir.
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen use the root's permissions */
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen } else if (mail_user_is_path_mounted(list->ns->user, path, &error)) {
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (mailbox_list_try_mkdir_root_parent(list, type,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen "Can't create mailbox root dir %s: %s", path, error);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* the rest of the directories exist only for one user. create them
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen with default directory permissions */
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen if (mkdir_parents_chgrp(path, perm.dir_create_mode,
4b8a6aec5fe2daa564799867f31e39e7ea46b9c3Timo Sirainen *error_r = mail_error_create_eacces_msg("mkdir", path);
4b8a6aec5fe2daa564799867f31e39e7ea46b9c3Timo Sirainen *error_r = t_strdup_printf("mkdir(%s) failed: %m", path);
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainenint mailbox_list_mkdir_root(struct mailbox_list *list, const char *path,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen if (mailbox_list_try_mkdir_root(list, path, type, &error) < 0) {
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainenmailbox_list_is_valid_fs_name(struct mailbox_list *list, const char *name,
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen const char **error_r)
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen if (list->mail_set->mail_full_filesystem_access)
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen /* make sure it's not absolute path */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen /* make sure the mailbox name doesn't contain any foolishness:
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen "../" could give access outside the mailbox directory.
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen "./" and "//" could fool ACL checks.
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen some mailbox formats have reserved directory names, such as
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen Maildir's cur/new/tmp. if any of those would conflict with the
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen mailbox directory name, it's not valid. maildir++ is kludged here as
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen a special case because all of its mailbox dirs begin with "." */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen allow_internal_dirs = list->v.is_internal_name == NULL ||
a58e63b4928017b5af123967c1c98f8bcb242a9aTimo Sirainen strcmp(list->name, MAILBOX_LIST_NAME_MAILDIRPLUSPLUS) == 0;
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen const char *const *names;
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen const char *n = *names;
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (*n == '\0') {
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen break; /* // */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen if (*n == '.') {
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen break; /* ./ */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen break; /* ../ */
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen /* don't allow maildir_name to be used as part
442b4c6c0d69e04297c00beb1a06da9855cb5ebeTimo Sirainen of the mailbox name */
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainenbool mailbox_list_is_valid_name(struct mailbox_list *list,
64ee8113a88e5d6e3cba7b1c4abd537cc2632bb9Timo Sirainen /* an ugly way to get to mailbox root (e.g. Maildir/
64ee8113a88e5d6e3cba7b1c4abd537cc2632bb9Timo Sirainen when it's not the INBOX) */
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen return mailbox_list_is_valid_fs_name(list, name, error_r);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenint mailbox_list_get_path(struct mailbox_list *list, const char *name,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char **path_r)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((ret = list->v.get_path(list, name, type, path_r)) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenbool mailbox_list_get_root_path(struct mailbox_list *list,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char **path_r)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if ((ret = list->v.get_path(list, NULL, type, path_r)) < 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenconst char *mailbox_list_get_root_forced(struct mailbox_list *list,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (!mailbox_list_get_root_path(list, type, &path))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainenbool mailbox_list_set_get_root_path(const struct mailbox_list_settings *set,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen const char **path_r)
5c95939662dc6e4317f4eec60289bb12fd51982bTimo Sirainen /* in-memory indexes */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *mailbox_list_get_temp_prefix(struct mailbox_list *list)
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainenconst char *mailbox_list_get_global_temp_prefix(struct mailbox_list *list)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainenconst char *mailbox_list_join_refpattern(struct mailbox_list *list,
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen return list->v.join_refpattern(list, ref, pattern);
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen /* the default implementation: */
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen /* merge reference and pattern */
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainenint mailbox_has_children(struct mailbox_list *list, const char *name)
9b2bbd89073e5b78f3f39a19f3f8d7c6d03bbd4cTimo Sirainen ret = mailbox_list_iter_next(iter) != NULL ? 1 : 0;
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainenint mailbox_list_mailbox(struct mailbox_list *list, const char *name,
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen const char *path, *fname, *rootdir, *dir, *inbox;
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen unsigned int len;
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen /* special handling for INBOX, mainly because with Maildir++
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen layout it needs to check if the cur/ directory exists,
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen which the Maildir++ layout backend itself can't do.. */
7cf1c7dd3dfd989cba1ed32a8e17c1b031c4629bTimo Sirainen /* kludge: with imapc backend we can get here with
7cf1c7dd3dfd989cba1ed32a8e17c1b031c4629bTimo Sirainen list=Maildir++ (for indexes), but list->ns->list=imapc */
7cf1c7dd3dfd989cba1ed32a8e17c1b031c4629bTimo Sirainen box = mailbox_alloc(list->ns->list, "INBOX", 0);
9ba91492d2eb29199674b669c673332ae2b01438Timo Sirainen /* this can only be an internal error */
ba36444cdf332c75ecdd2696e34c391eea75597cTimo Sirainen /* can't do this optimized. do it the slow way. */
ba36444cdf332c75ecdd2696e34c391eea75597cTimo Sirainen iter = mailbox_list_iter_init(list, vname, 0);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen rootdir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_MAILBOX);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR, &path) <= 0)
b6eced3d628ad0c50a3cbc9f966da0edc20108abTimo Sirainen if (strncmp(path, rootdir, len) == 0 && path[len] == '/') {
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen /* looking up a regular mailbox under mail root dir */
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen } else if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen /* looking up INBOX that's elsewhere */
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen /* looking up the root dir itself */
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen /* if INBOX is in e.g. ~/Maildir, it shouldn't be possible to
e22efc90e109ade2936eea0b062a99480310fd41Timo Sirainen access it also via namespace prefix. */
f7ee94201b23b4bd5764cb85cb51d5c995e475ecTimo Sirainen return list->v.get_mailbox_flags(list, dir, fname,
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainenstatic bool mailbox_list_init_changelog(struct mailbox_list *list)
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen /* don't do this in mailbox_list_create(), because _get_path() might be
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen overridden by storage (mbox). */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (!mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_INDEX, &path))
32f4b9ab23148bec295196a8029a43ff89ce124dTimo Sirainen path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
76b91bac787101e6b0075122ab6478dd98c8a884Timo Sirainen mailbox_list_get_root_permissions(list, &perm);
db7ca286e3ef53f73a3e8e46104a31247ebfe213Timo Sirainen mailbox_log_set_permissions(list->changelog, perm.file_create_mode,
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainenint mailbox_list_mkdir_missing_index_root(struct mailbox_list *list)
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen /* if index root dir hasn't been created yet, do it now */
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen ret = mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_INDEX,
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen ret = mailbox_list_get_root_path(list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenvoid mailbox_list_add_change(struct mailbox_list *list,
43487bb7de9e907ad61e186714956a83f5be4a15Timo Sirainen if (mailbox_list_mkdir_missing_index_root(list) <= 0)
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen stamp = list->changelog_timestamp != (time_t)-1 ?
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen mailbox_log_record_set_timestamp(&rec, stamp);
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen (void)mailbox_log_append(list->changelog, &rec);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint mailbox_list_set_subscribed(struct mailbox_list *list,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen /* make sure we'll refresh the file on next list */
5a0fc34c5cc525334c5a10531713017ae321c573Timo Sirainen if ((ret = list->v.set_subscribed(list, name, set)) <= 0)
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainenint mailbox_list_delete_dir(struct mailbox_list *list, const char *name)
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (!mailbox_list_is_valid_name(list, name, &error) || *name == '\0') {
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
2f30b72d49fbff0c4096125c139e4bdfef45669cTimo Sirainen "Invalid mailbox name");
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainenint mailbox_list_delete_symlink(struct mailbox_list *list, const char *name)
e9df0f285429d2b896ecdb4cd873d25e5e895620Timo Sirainen if (!mailbox_list_is_valid_name(list, name, &error) || *name == '\0') {
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainen mailbox_list_set_error(list, MAIL_ERROR_PARAMS,
0b25846ba794ce19536a24d4065beaf2a0bd9464Timo Sirainen "Invalid mailbox name");
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainenvoid mailbox_name_get_sha128(const char *name, guid_128_t guid_128_r)
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen memcpy(guid_128_r, sha, I_MIN(GUID_128_SIZE, sizeof(sha)));
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainenstruct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list)
78bb4a443b4ca97ce27976916953e4898aa8a125Timo Sirainen return !mailbox_list_init_changelog(list) ? NULL : list->changelog;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainenvoid mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenbool mailbox_list_name_is_too_large(const char *name, char sep)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenmailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen switch (d->d_type) {
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainenint mailbox_list_dirent_is_alias_symlink(struct mailbox_list *list,
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen const struct dirent *d)
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen if (mailbox_list_get_file_type(d) == MAILBOX_LIST_FILE_TYPE_SYMLINK)
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen path = t_strconcat(dir_path, "/", d->d_name, NULL);
77b5fd56e5a06d624f3ab92198272287333114f4Timo Sirainen /* it's an alias only if it points to the same
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainenmailbox_list_try_get_home_path(struct mailbox_list *list, const char **name)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* ~/dir - use the configured home directory */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (mail_user_try_home_expand(list->ns->user, name) < 0)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* ~otheruser/dir - assume we're using system users */
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainenbool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
96f2533c48ce5def0004931606a2fdf275578880Timo Sirainen const char **name)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen unsigned int len;
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (!list->mail_set->mail_full_filesystem_access)
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* try to expand home directory */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (!mailbox_list_try_get_home_path(list, name)) {
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* fallback to using actual "~name" mailbox */
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* okay, we have an absolute path now. but check first if it points to
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen same directory as one of our regular mailboxes. */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen root_dir = mailbox_list_get_root_forced(list, MAILBOX_LIST_PATH_TYPE_MAILBOX);
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen if (strncmp(root_dir, *name, len) == 0 && (*name)[len] == '/') {
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen /* yeah, we can replace the full path with mailbox
ff1777f61db8b45c72d8bcb843f9106eb0227ab6Timo Sirainen name. this way we can use indexes. */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenconst char *mailbox_list_get_last_error(struct mailbox_list *list,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return list->error_string != NULL ? list->error_string :
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "Unknown internal list error";
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_clear_error(struct mailbox_list *list)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenvoid mailbox_list_set_error(struct mailbox_list *list,
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainenvoid mailbox_list_set_internal_error(struct mailbox_list *list)
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen const char *str;
b1f37113a5760bee842c5a7678bb5fa6f5bd8b60Timo Sirainen str = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenvoid mailbox_list_set_critical(struct mailbox_list *list, const char *fmt, ...)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* critical errors may contain sensitive data, so let user
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen see only "Internal error" with a timestamp to make it
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen easier to look from log files the actual error message. */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenbool mailbox_list_set_error_from_errno(struct mailbox_list *list)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (!mail_error_from_errno(&error, &error_string))
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen mailbox_list_set_error(list, error, error_string);
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainenint mailbox_list_init_fs(struct mailbox_list *list, const char *driver,
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen ssl_set.ca_dir = list->mail_set->ssl_client_ca_dir;
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen ssl_set.ca_file = list->mail_set->ssl_client_ca_file;
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen fs_set.temp_file_prefix = mailbox_list_get_global_temp_prefix(list);
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen fs_set.base_dir = list->ns->user->set->base_dir;
9393445a6dabd17ce62ebfc12fd73545b0065824Timo Sirainen fs_set.temp_dir = list->ns->user->set->mail_temp_dir;