mailbox-list.c revision f0d09be40bd0c4423873128ae2f88a4020075dc4
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* Copyright (c) 2006-2015 Dovecot authors, see the included COPYING file */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch/* 16 * (255+1) = 4096 which is the standard PATH_MAX. Having these settings
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch then start renaming them to larger names from end to beginning, which
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch eventually would start causing the failures when trying to use too
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch long mailbox names. 255 is the standard single directory name length, so
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch allow up to that high. */
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstruct mailbox_list_module_register mailbox_list_module_register = { 0 };
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic ARRAY(const struct mailbox_list *) mailbox_list_drivers;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Boschstatic MODULE_CONTEXT_DEFINE_INIT(mailbox_list_fs_module,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic bool mailbox_list_driver_find(const char *name, unsigned int *idx_r)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int i, count;
7c7117e542b6a44c1db7fc91c0180bdace6dbce7Stephan Bosch drivers = array_get(&mailbox_list_drivers, &count);
7c7117e542b6a44c1db7fc91c0180bdace6dbce7Stephan Bosch for (i = 0; i < count; i++) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (strcasecmp(drivers[i]->name, name) == 0) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenvoid mailbox_list_register(const struct mailbox_list *list)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen unsigned int idx;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (mailbox_list_driver_find(list->name, &idx)) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_fatal("mailbox_list_register(%s): duplicate driver",
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch array_append(&mailbox_list_drivers, &list, 1);
dc05b1fb4b7a2b4d91248078311458cb4cbad9a1Stephan Boschvoid mailbox_list_unregister(const struct mailbox_list *list)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int idx;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (!mailbox_list_driver_find(list->name, &idx)) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_fatal("mailbox_list_unregister(%s): unknown driver",
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int idx;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen class_p = array_idx(&mailbox_list_drivers, idx);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschint mailbox_list_create(const char *driver, struct mail_namespace *ns,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch struct mailbox_list **list_r, const char **error_r)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch unsigned int idx;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (!mailbox_list_driver_find(driver, &idx)) {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch class_p = array_idx(&mailbox_list_drivers, idx);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch if (((*class_p)->props & MAILBOX_LIST_PROP_NO_MAILDIR_NAME) != 0 &&
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen *error_r = "maildir_name not supported by this driver";
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (((*class_p)->props & MAILBOX_LIST_PROP_NO_ALT_DIR) != 0 &&
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen *error_r = "alt_dir not supported by this driver";
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_assert(set->root_dir == NULL || *set->root_dir != '\0' ||
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch ((*class_p)->props & MAILBOX_LIST_PROP_NO_ROOT) != 0);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch array_create(&list->module_contexts, list->pool, sizeof(void *), 5);
e1a4ea6ad3e799ef8df7395e765c0ae9218e6c5dStephan Bosch list->root_permissions.file_create_mode = (mode_t)-1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen list->root_permissions.dir_create_mode = (mode_t)-1;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch list->root_permissions.file_create_gid = (gid_t)-1;
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch /* copy settings */
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch list->set.root_dir = p_strdup(list->pool, set->root_dir);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch list->set.index_dir = set->index_dir == NULL ||
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch strcmp(set->index_dir, set->root_dir) == 0 ? NULL :
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch list->set.index_pvt_dir = set->index_pvt_dir == NULL ||
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch strcmp(set->index_pvt_dir, set->root_dir) == 0 ? NULL :
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch list->set.control_dir = set->control_dir == NULL ||
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch strcmp(set->control_dir, set->root_dir) == 0 ? NULL :
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch list->set.inbox_path = p_strdup(list->pool, set->inbox_path);
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch p_strdup(list->pool, set->subscription_fname);
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch list->set.alt_dir = p_strdup(list->pool, set->alt_dir);
2f64a4c88de91c483fb378bc80d10e1caa6f2305Stephan Bosch list->set.alt_dir_nocheck = set->alt_dir_nocheck;
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch else if (set->mailbox_dir_name[strlen(set->mailbox_dir_name)-1] == '/') {
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch p_strconcat(list->pool, set->mailbox_dir_name, "/", NULL);
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch i_debug("%s: root=%s, index=%s, indexpvt=%s, control=%s, inbox=%s, alt=%s",
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch list->set.root_dir == NULL ? "" : list->set.root_dir,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch list->set.index_dir == NULL ? "" : list->set.index_dir,
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch list->set.index_pvt_dir == NULL ? "" : list->set.index_pvt_dir,
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch list->set.alt_dir == NULL ? "" : list->set.alt_dir);
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch if ((flags & MAILBOX_LIST_FLAG_SECONDARY) == 0)
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Boschstatic int fix_path(struct mail_user *user, const char *path, bool expand_home,
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch /* no ~ expansion */
5560e4cd4f5eded857471042fb5485dfa16b7c46Stephan Bosch } else if (path[0] == '~' && path[1] != '/' && path[1] != '\0') {
3fcb3d2d1f3583025ff62bae95ec706920f398b1Stephan Bosch "No home directory for system user. "
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch if (mail_user_try_home_expand(user, &path) < 0) {
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Bosch *error_r = "Home directory not set for user. "
711e8e4c5c5d702dfa062f42a1ede5de14c151c9Stephan Bosch "Can't expand ~/ for ";
ee2633056e67353157bfbce4d9e0d1c3ceaa627aStephan Boschstatic const char *split_next_arg(const char *const **_args)
args++;
args++;
return str;
bool expand_home,
const char **error_r)
value++;
const char **error_r)
location++;
location++;
if (p == NULL)
return path;
unsigned int len;
return FALSE;
vname++;
(dirstart &&
unsigned char chr;
char *ret, *p;
if (*p == src)
*p = dest;
return ret;
const char *vname)
return storage_name;
return storage_name;
return ret;
const char *vname)
unsigned int num;
(unsigned char)*vname);
const char *storage_name)
return vname;
for (i = 0; i < name_len; i++) {
return vname;
const struct mailbox_list_settings *
struct mail_namespace *
return mode;
struct mail_user *
data++;
const char *name,
&path) < 0)
&path);
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;
const char **error_r)
i_unreached();
} else if (p == NULL) {
if (p == unexpanded)
i_unreached();
if (!home) {
const char **error_r)
const char *root_dir;
i_unreached();
const char *error;
const char **error_r)
return TRUE;
return FALSE;
return FALSE;
T_BEGIN {
const char *const *names;
const char *n = *names;
if (!allow_internal_dirs &&
} T_END;
return ret;
return TRUE;
return FALSE;
return FALSE;
const char **path_r)
int ret;
return ret;
const char **path_r)
int ret;
i_unreached();
if (ret == 0)
return ret > 0;
const char *path;
i_unreached();
return path;
const char **path_r)
switch (type) {
return pattern;
const char *pattern;
int ret;
return ret;
unsigned int len;
*flags_r = 0;
int ret;
if (ret < 0) {
const char *errstr;
if (ret < 0)
switch (existence) {
case MAILBOX_EXISTENCE_NONE:
case MAILBOX_EXISTENCE_SELECT:
const char *vname;
i_unreached();
fname++;
&inbox) <= 0)
i_unreached();
flags_r);
const char *path;
return TRUE;
return FALSE;
return TRUE;
int ret;
&index_dir);
if (ret <= 0)
return ret;
&root_dir);
if (ret <= 0)
return ret;
int ret;
return ret;
const char *error;
const char *error;
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 *dir_path,
const struct dirent *d)
int ret;
T_BEGIN {
ret = 0;
} T_END;
return ret;
return FALSE;
return FALSE;
return TRUE;
const char **name)
unsigned int len;
return FALSE;
return FALSE;
return FALSE;
&path) <= 0)
return FALSE;
return FALSE;
return TRUE;
const char *str;
const char *error_string;
return FALSE;
return TRUE;