Skip to content

Commit

Permalink
lib-storage: Limit folder full name only
Browse files Browse the repository at this point in the history
Before we had limit of 16 levels and 255 bytes per name
which is same as 4096 bytes. Now we limit only the total
length of the name to MAILBOX_LIST_NAME_MAX_LENGTH. For
compability reasons, we are restricting individual component
names to 255 characters.
  • Loading branch information
cmouse authored and sirainen committed Sep 12, 2016
1 parent 38a2542 commit ad082a8
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 35 deletions.
62 changes: 59 additions & 3 deletions src/lib-storage/mail-storage.c
Expand Up @@ -30,6 +30,7 @@
#include <ctype.h>

#define MAILBOX_DELETE_RETRY_SECS 30
#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 255

extern struct mail_search_register *mail_search_register_imap;
extern struct mail_search_register *mail_search_register_human;
Expand Down Expand Up @@ -971,8 +972,6 @@ void mailbox_skip_create_name_restrictions(struct mailbox *box, bool set)

int mailbox_verify_create_name(struct mailbox *box)
{
char sep = mail_namespace_get_sep(box->list->ns);

/* mailbox_alloc() already checks that vname is valid UTF8,
so we don't need to verify that.
Expand All @@ -987,7 +986,25 @@ int mailbox_verify_create_name(struct mailbox *box)
"Control characters not allowed in new mailbox names");
return -1;
}
if (mailbox_list_name_is_too_large(box->vname, sep)) {
if (strlen(box->vname) > MAILBOX_LIST_NAME_MAX_LENGTH) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Mailbox name too long");
return -1;
}
/* check individual component names, too */
const char *old_name = box->name;
const char *name;
const char sep = mailbox_list_get_hierarchy_sep(box->list);
while((name = strchr(old_name, sep)) != NULL) {
if (name - old_name > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Mailbox name too long");
return -1;
}
name++;
old_name = name;
}
if (old_name != NULL && strlen(old_name) > MAILBOX_MAX_HIERARCHY_NAME_LENGTH) {
mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
"Mailbox name too long");
return -1;
Expand Down Expand Up @@ -1469,6 +1486,41 @@ mailbox_lists_rename_compatible(struct mailbox_list *list1,
return TRUE;
}

static
int mailbox_rename_check_children(struct mailbox *src, struct mailbox *dest)
{
int ret = 0;
size_t src_prefix_len = strlen(src->vname)+1; /* include separator */
size_t dest_prefix_len = strlen(dest->vname)+1;
/* this can return folders with * in their name, that are not
actually our children */
const char *pattern = t_strdup_printf("%s%c*", src->vname,
mail_namespace_get_sep(src->list->ns));

struct mailbox_list_iterate_context *iter = mailbox_list_iter_init(src->list, pattern,
MAILBOX_LIST_ITER_RETURN_NO_FLAGS);

const struct mailbox_info *child;
while((child = mailbox_list_iter_next(iter)) != NULL) {
if (strncmp(child->vname, src->vname, src_prefix_len) != 0)
continue; /* not our child */
/* if total length of new name exceeds the limit, fail */
if (strlen(child->vname + src_prefix_len)+dest_prefix_len > MAILBOX_LIST_NAME_MAX_LENGTH) {
mail_storage_set_error(dest->storage, MAIL_ERROR_PARAMS,
"Mailbox or child name too long");
ret = -1;
break;
}
}

/* something went bad */
if (mailbox_list_iter_deinit(&iter) < 0) {
mail_storage_copy_list_error(dest->storage, src->list);
ret = -1;
}
return ret;
}

int mailbox_rename(struct mailbox *src, struct mailbox *dest)
{
const char *error = NULL;
Expand All @@ -1485,6 +1537,10 @@ int mailbox_rename(struct mailbox *src, struct mailbox *dest)
mail_storage_copy_error(dest->storage, src->storage);
return -1;
}
if (mailbox_rename_check_children(src, dest) != 0) {
return -1;
}

if (!mail_storages_rename_compatible(src->storage,
dest->storage, &error) ||
!mailbox_lists_rename_compatible(src->list,
Expand Down
1 change: 0 additions & 1 deletion src/lib-storage/mailbox-list-private.h
Expand Up @@ -204,7 +204,6 @@ void mailbox_list_iter_update(struct mailbox_list_iter_update_context *ctx,
const char *name);
int mailbox_list_iter_subscriptions_refresh(struct mailbox_list *list);

bool mailbox_list_name_is_too_large(const char *name, char sep);
enum mailbox_list_file_type mailbox_list_get_file_type(const struct dirent *d);
int mailbox_list_dirent_is_alias_symlink(struct mailbox_list *list,
const char *dir_path,
Expand Down
31 changes: 0 additions & 31 deletions src/lib-storage/mailbox-list.c
Expand Up @@ -27,15 +27,6 @@
#include <dirent.h>
#include <sys/stat.h>

/* 16 * (255+1) = 4096 which is the standard PATH_MAX. Having these settings
prevents malicious user from creating eg. "a/a/a/.../a" mailbox name and
then start renaming them to larger names from end to beginning, which
eventually would start causing the failures when trying to use too
long mailbox names. 255 is the standard single directory name length, so
allow up to that high. */
#define MAILBOX_MAX_HIERARCHY_LEVELS 16
#define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 255

#define MAILBOX_LIST_FS_CONTEXT(obj) \
MODULE_CONTEXT(obj, mailbox_list_fs_module)

Expand Down Expand Up @@ -1658,28 +1649,6 @@ void mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
list->changelog_timestamp = stamp;
}

bool mailbox_list_name_is_too_large(const char *name, char sep)
{
unsigned int levels = 1, level_len = 0;

for (; *name != '\0'; name++) {
if (*name == sep) {
if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
return TRUE;
levels++;
level_len = 0;
} else {
level_len++;
}
}

if (level_len > MAILBOX_MAX_HIERARCHY_NAME_LENGTH)
return TRUE;
if (levels > MAILBOX_MAX_HIERARCHY_LEVELS)
return TRUE;
return FALSE;
}

enum mailbox_list_file_type
mailbox_list_get_file_type(const struct dirent *d ATTR_UNUSED)
{
Expand Down

0 comments on commit ad082a8

Please sign in to comment.