From: Aki Tuomi Date: Wed, 10 Aug 2016 10:07:01 +0000 (+0300) Subject: lib-storage: Limit folder full name only X-Git-Tag: 2.3.0.rc1~3048 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bedb7f369599d112e62eed14ab692351493bf623;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: Limit folder full name only 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. --- diff --git a/src/lib-storage/mail-storage.c b/src/lib-storage/mail-storage.c index 5c71eb6854..8bed1ae49c 100644 --- a/src/lib-storage/mail-storage.c +++ b/src/lib-storage/mail-storage.c @@ -30,6 +30,7 @@ #include #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; @@ -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. @@ -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; @@ -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; @@ -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, diff --git a/src/lib-storage/mailbox-list-private.h b/src/lib-storage/mailbox-list-private.h index f444acc609..e0659ca233 100644 --- a/src/lib-storage/mailbox-list-private.h +++ b/src/lib-storage/mailbox-list-private.h @@ -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, diff --git a/src/lib-storage/mailbox-list.c b/src/lib-storage/mailbox-list.c index 1ce5c1a617..a09e3ad200 100644 --- a/src/lib-storage/mailbox-list.c +++ b/src/lib-storage/mailbox-list.c @@ -27,15 +27,6 @@ #include #include -/* 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) @@ -1655,28 +1646,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) {