mailbox-list.c revision 93107c0447855ce051cb4a2215ac1089536110ca
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* 20 * (200+1) < 4096 which is the standard PATH_MAX. Having these settings
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen then start renaming them to larger names from end to beginning, which
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen eventually would start causing the failures when trying to use too
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen long mailbox names. */
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct mailbox_list_iterate_context *backend_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid (*hook_mailbox_list_created)(struct mailbox_list *list);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic ARRAY_DEFINE(mailbox_list_drivers, const struct mailbox_list *);
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i, count;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen drivers = array_get(&mailbox_list_drivers, &count);
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen for (i = 0; i < count; i++) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen if (strcasecmp(drivers[i]->name, name) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("mailbox_list_register(%s): duplicate driver",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&mailbox_list_drivers, &list, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_list_unregister(const struct mailbox_list *list)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen unsigned int idx;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (!mailbox_list_driver_find(list->name, &idx)) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen i_fatal("mailbox_list_unregister(%s): unknown driver",
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainenint mailbox_list_create(const char *driver, struct mail_namespace *ns,
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen enum mailbox_list_flags flags, const char **error_r)
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen unsigned int idx;
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen i_assert(set->root_dir == NULL || *set->root_dir != '\0');
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen if (!mailbox_list_driver_find(driver, &idx)) {
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen *error_r = t_strdup_printf("Unknown mailbox list driver: %s",
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen /* copy settings */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.root_dir = p_strdup(list->pool, set->root_dir);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.index_dir = set->index_dir == NULL ||
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen list->set.control_dir = set->control_dir == NULL ||
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
ed1f14af0d426b5550521a58fc414d130aa14172Timo Sirainen list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen p_strdup(list->pool, set->subscription_fname);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->set.maildir_name = set->maildir_name == NULL ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (list->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 ? "" :
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen if (set->mailbox_dir_name == NULL || *set->mailbox_dir_name == '\0')
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->set.root_dir == NULL ? "" : list->set.root_dir,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen list->set.index_dir == NULL ? "" : list->set.index_dir,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen path = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen path = t_strconcat(path, "/"MAILBOX_LOG_FILE_NAME, NULL);
8830fab191cab8440281eb641dfdd93974b2933bTimo Sirainenstatic int fix_path(struct mail_namespace *ns, const char *path,
1b56f5fdd415270c743a38719d41b4d9497bcacdTimo Sirainen "No home directory for system user. "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_user_try_home_expand(ns->user, &path) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = "Home directory not set for user. "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Can't expand ~/ for ";
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic const char *split_next_arg(const char *const **_args)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mailbox_list_settings_parse(const char *data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_namespace *ns, const char **error_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *const *tmp, *key, *value, **dest, *str, *error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* <root dir> */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fix_path(ns, str, &set->root_dir, &error) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = t_strconcat(error, "mail root dir in: ", data, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = t_strdup_printf("Unknown setting: %s", key);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *error_r = t_strconcat(error, key, " in: ", data, NULL);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (set->index_dir != NULL && strcmp(set->index_dir, "MEMORY") == 0)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainenvoid mailbox_list_destroy(struct mailbox_list **_list)
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainenconst char *mailbox_list_get_driver_name(const struct mailbox_list *list)
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainenchar mailbox_list_get_hierarchy_sep(const struct mailbox_list *list)
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainenenum mailbox_list_flags mailbox_list_get_flags(const struct mailbox_list *list)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainenmailbox_list_get_namespace(const struct mailbox_list *list)
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen /* add the execute bit if either read or write bit is set */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenmailbox_list_get_user(const struct mailbox_list *list)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenint mailbox_list_get_storage(struct mailbox_list **list, const char **name,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return (*list)->v.get_storage(list, name, storage_r);
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainenvoid mailbox_list_get_closest_storage(struct mailbox_list *list,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainenmailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen mailbox_list_set_critical(list, "stat(%s) failed: %m",
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen i_info("Namespace %s: Permission lookup failed from %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* return defaults */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* return safe defaults */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* we're getting permissions from a file.
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen apply +x modes as necessary. */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen if (S_ISDIR(st.st_mode) && (st.st_mode & S_ISGID) != 0) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* directory's GID is used automatically for new
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen } else if ((st.st_mode & 0070) >> 3 == (st.st_mode & 0007)) {
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen /* group has same permissions as world, so don't bother
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen changing it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* using our own gid, no need to change it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->mail_set->mail_debug && name == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_info("Namespace %s: Using permissions from %s: "
6e354c4070b611471727692919d29440d73a73f7Timo Sirainenvoid mailbox_list_get_permissions(struct mailbox_list *list,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->file_create_mode != (mode_t)-1 && name == NULL) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mailbox_list_get_permissions_full(list, name, mode_r, &dir_mode, gid_r,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenvoid mailbox_list_get_dir_permissions(struct mailbox_list *list,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->dir_create_mode != (mode_t)-1 && name == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mailbox_list_get_permissions_full(list, name, &file_mode,
const char *pattern)
const char *name)
return TRUE;
const char *name)
int ret;
return FALSE;
T_BEGIN {
} 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;
const char *path;
*flags_r = 0;
flags_r);
const char *oldname,
rename_children) < 0)
if (ret > 0)
if (ret < 0) {
path);
path);
if (ret < 0) {
if (ret == 0) {
int ret;
T_BEGIN {
} T_END;
return ret;
const char *name)
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;
const char **name)
return FALSE;
return TRUE;
return FALSE;
return TRUE;
return TRUE;
return FALSE;
if (p == NULL)
dir);
const char *error_string;
return FALSE;
return TRUE;