Mercurial > dovecot > original-hg > dovecot-1.2
changeset 6353:23c9ac999578 HEAD
mailbox_keywords_create() checks keyword validity now and returns failure if
any of them are invalid. Added mailbox_keywords_create_valid() that only
drops invalid keywords. Removed mbox and IMAP-specific keyword checks, they
all use the same checking now.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 02 Sep 2007 06:10:54 +0300 |
parents | 0f1a4b7b39a3 |
children | 8476d665530f |
files | src/deliver/deliver.c src/imap/cmd-append.c src/imap/cmd-copy.c src/imap/cmd-store.c src/imap/commands-util.c src/imap/common.h src/imap/main.c src/lib-storage/index/index-storage.c src/lib-storage/index/index-storage.h src/lib-storage/index/mbox/mbox-sync-parse.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/plugins/convert/convert-storage.c |
diffstat | 14 files changed, 156 insertions(+), 96 deletions(-) [+] |
line wrap: on
line diff
--- a/src/deliver/deliver.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/deliver/deliver.c Sun Sep 02 06:10:54 2007 +0300 @@ -142,7 +142,7 @@ t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL); kw = strarray_length(keywords) == 0 ? NULL : - mailbox_keywords_create(t, keywords); + mailbox_keywords_create_valid(t, keywords); if (mailbox_copy(t, mail, flags, kw, NULL) < 0) ret = -1; mailbox_keywords_free(t, &kw);
--- a/src/imap/cmd-append.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/imap/cmd-append.c Sun Sep 02 06:10:54 2007 +0300 @@ -290,8 +290,13 @@ if (!client_parse_mail_flags(cmd, flags_list, &flags, &keywords_list)) return cmd_append_cancel(ctx, nonsync); - keywords = keywords_list == NULL ? NULL : - mailbox_keywords_create(ctx->t, keywords_list); + if (keywords_list == NULL) + keywords = NULL; + else if (mailbox_keywords_create(ctx->t, keywords_list, + &keywords) < 0) { + client_send_storage_error(cmd, ctx->storage); + return cmd_append_cancel(ctx, nonsync); + } } else { flags = 0; keywords = NULL;
--- a/src/imap/cmd-copy.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/imap/cmd-copy.c Sun Sep 02 06:10:54 2007 +0300 @@ -62,7 +62,7 @@ keywords_list = mail_get_keywords(mail); keywords = strarray_length(keywords_list) == 0 ? NULL : - mailbox_keywords_create(t, keywords_list); + mailbox_keywords_create_valid(t, keywords_list); if (mailbox_copy(t, mail, mail_get_flags(mail), keywords, NULL) < 0) ret = mail->expunged ? 0 : -1;
--- a/src/imap/cmd-store.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/imap/cmd-store.c Sun Sep 02 06:10:54 2007 +0300 @@ -88,8 +88,14 @@ t = mailbox_transaction_begin(box, !silent ? 0 : MAILBOX_TRANSACTION_FLAG_HIDE); - keywords = keywords_list != NULL || modify_type == MODIFY_REPLACE ? - mailbox_keywords_create(t, keywords_list) : NULL; + if (keywords_list == NULL && modify_type != MODIFY_REPLACE) + keywords = NULL; + else if (mailbox_keywords_create(t, keywords_list, &keywords) < 0) { + /* invalid keywords */ + mailbox_transaction_rollback(&t); + client_send_storage_error(cmd, mailbox_get_storage(box)); + return TRUE; + } search_ctx = mailbox_search_init(t, NULL, search_arg, NULL); mail = mail_alloc(t, MAIL_FETCH_FLAGS, NULL);
--- a/src/imap/commands-util.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/imap/commands-util.c Sun Sep 02 06:10:54 2007 +0300 @@ -189,45 +189,17 @@ client_send_line(client, t_strconcat("* NO ", error_string, NULL)); } -static bool is_valid_keyword(struct client_command_context *cmd, - const char *keyword) -{ - const char *const *names; - unsigned int i, count; - - /* if it already exists, skip validity checks */ - if (array_is_created(&cmd->client->keywords.keywords)) { - names = array_get(&cmd->client->keywords.keywords, &count); - for (i = 0; i < count; i++) { - if (strcasecmp(names[i], keyword) == 0) - return TRUE; - } - } - - if (strlen(keyword) > max_keyword_length) { - client_send_tagline(cmd, - t_strdup_printf("BAD Invalid keyword name '%s': " - "Maximum length is %u characters", - keyword, max_keyword_length)); - return FALSE; - } - - return TRUE; -} - bool client_parse_mail_flags(struct client_command_context *cmd, const struct imap_arg *args, enum mail_flags *flags_r, const char *const **keywords_r) { - const char *const *keywords; const char *atom; - buffer_t *buffer; - size_t size, i; + ARRAY_DEFINE(keywords, const char *); *flags_r = 0; *keywords_r = NULL; - buffer = buffer_create_dynamic(cmd->pool, 256); + p_array_init(&keywords, cmd->pool, 16); while (args->type != IMAP_ARG_EOL) { if (args->type != IMAP_ARG_ATOM) { @@ -257,28 +229,19 @@ return FALSE; } } else { - /* keyword - first make sure it's not a duplicate */ - keywords = buffer_get_data(buffer, &size); - size /= sizeof(const char *); - for (i = 0; i < size; i++) { - if (strcasecmp(keywords[i], atom) == 0) - break; - } - - if (i == size) { - if (!is_valid_keyword(cmd, atom)) - return FALSE; - buffer_append(buffer, &atom, sizeof(atom)); - } + /* keyword validity checks are done by lib-storage */ + array_append(&keywords, &atom, 1); } args++; } - atom = NULL; - buffer_append(buffer, &atom, sizeof(atom)); - *keywords_r = buffer->used == sizeof(atom) ? NULL : - buffer_get_data(buffer, NULL); + if (array_count(&keywords) == 0) + *keywords_r = NULL; + else { + (void)array_append_space(&keywords); /* NULL-terminate */ + *keywords_r = array_idx(&keywords, 0); + } return TRUE; }
--- a/src/imap/common.h Sun Sep 02 06:08:58 2007 +0300 +++ b/src/imap/common.h Sun Sep 02 06:10:54 2007 +0300 @@ -21,8 +21,6 @@ by default. */ #define DEFAULT_IMAP_MAX_LINE_LENGTH 65536 -#define DEFAULT_MAX_KEYWORD_LENGTH 50 - enum client_workarounds { WORKAROUND_DELAY_NEWMAIL = 0x01, WORKAROUND_NETSCAPE_EOH = 0x04, @@ -30,7 +28,6 @@ }; extern struct ioloop *ioloop; -extern unsigned int max_keyword_length; extern unsigned int imap_max_line_length; extern enum client_workarounds client_workarounds; extern const char *logout_format;
--- a/src/imap/main.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/imap/main.c Sun Sep 02 06:10:54 2007 +0300 @@ -39,7 +39,6 @@ }; struct ioloop *ioloop; -unsigned int max_keyword_length; unsigned int imap_max_line_length; enum client_workarounds client_workarounds = 0; const char *logout_format; @@ -225,11 +224,6 @@ (unsigned int)strtoul(str, NULL, 10) : DEFAULT_IMAP_MAX_LINE_LENGTH; - str = getenv("MAIL_MAX_KEYWORD_LENGTH"); - max_keyword_length = str != NULL ? - (unsigned int)strtoul(str, NULL, 10) : - DEFAULT_MAX_KEYWORD_LENGTH; - logout_format = getenv("IMAP_LOGOUT_FORMAT"); if (logout_format == NULL) logout_format = "bytes=%i/%o";
--- a/src/lib-storage/index/index-storage.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/lib-storage/index/index-storage.c Sun Sep 02 06:10:54 2007 +0300 @@ -4,6 +4,7 @@ #include "array.h" #include "buffer.h" #include "ioloop.h" +#include "imap-parser.h" #include "mkdir-parents.h" #include "mail-index-private.h" #include "index-storage.h" @@ -469,14 +470,86 @@ mail_index_reset_error(ibox->index); } -struct mail_keywords * -index_keywords_create(struct mailbox_transaction_context *_t, - const char *const keywords[]) +int index_mailbox_keyword_is_valid(struct index_mailbox *ibox, + const char *keyword, const char **error_r) +{ + unsigned int i, idx; + + /* if it already exists, skip validity checks */ + if (mail_index_keyword_lookup(ibox->index, keyword, &idx)) + return TRUE; + + if (*keyword == '\0') { + *error_r = "Empty keywords not allowed"; + return FALSE; + } + + /* these are IMAP-specific restrictions, but for now IMAP is all we + care about */ + for (i = 0; keyword[i] != '\0'; i++) { + if (IS_ATOM_SPECIAL((unsigned char)keyword[i])) { + *error_r = "Invalid characters in keyword"; + return FALSE; + } + if ((unsigned char)keyword[i] >= 0x80) { + *error_r = "8bit characters in keyword"; + return FALSE; + } + } + if (i > ibox->box.storage->keyword_max_len) { + *error_r = "Keyword length too long"; + return FALSE; + } + return TRUE; +} + +static struct mail_keywords * +index_keywords_create_skip(struct index_transaction_context *t, + const char *const keywords[]) +{ + ARRAY_DEFINE(valid_keywords, const char *); + struct mail_keywords *kw; + const char *error; + + t_push(); + t_array_init(&valid_keywords, 32); + for (; *keywords != NULL; keywords++) { + if (index_mailbox_keyword_is_valid(t->ibox, *keywords, &error)) + array_append(&valid_keywords, keywords, 1); + } + (void)array_append_space(&valid_keywords); /* NULL-terminate */ + kw = mail_index_keywords_create(t->trans, keywords); + t_pop(); + return kw; +} + +int index_keywords_create(struct mailbox_transaction_context *_t, + const char *const keywords[], + struct mail_keywords **keywords_r, bool skip_invalid) { struct index_transaction_context *t = (struct index_transaction_context *)_t; + const char *error; + unsigned int i; - return mail_index_keywords_create(t->trans, keywords); + for (i = 0; keywords[i] != NULL; i++) { + if (!index_mailbox_keyword_is_valid(t->ibox, keywords[i], + &error)) { + if (skip_invalid) { + /* found invalid keywords, do this the slow + way */ + *keywords_r = + index_keywords_create_skip(t, keywords); + return 0; + } + mail_storage_set_error(t->ibox->box.storage, + MAIL_ERROR_PARAMS, error); + return -1; + } + } + + *keywords_r = mail_index_keywords_create(t->trans, keywords); + return 0; } void index_keywords_free(struct mailbox_transaction_context *t __attr_unused__,
--- a/src/lib-storage/index/index-storage.h Sun Sep 02 06:08:58 2007 +0300 +++ b/src/lib-storage/index/index-storage.h Sun Sep 02 06:10:54 2007 +0300 @@ -109,9 +109,11 @@ bool index_storage_allow_new_keywords(struct mailbox *box); bool index_storage_is_inconsistent(struct mailbox *box); -struct mail_keywords * -index_keywords_create(struct mailbox_transaction_context *t, - const char *const keywords[]); +int index_mailbox_keyword_is_valid(struct index_mailbox *ibox, + const char *keyword, const char **error_r); +int index_keywords_create(struct mailbox_transaction_context *t, + const char *const keywords[], + struct mail_keywords **keywords_r, bool skip_invalid); void index_keywords_free(struct mailbox_transaction_context *t, struct mail_keywords *keywords);
--- a/src/lib-storage/index/mbox/mbox-sync-parse.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-parse.c Sun Sep 02 06:10:54 2007 +0300 @@ -109,24 +109,11 @@ return TRUE; } -static bool keyword_is_valid(const char *keyword) -{ - /* try to only prevent the most malicious looking keywords. */ - for (; *keyword != '\0'; keyword++) { - if (*keyword == '(' || *keyword == ')' || - *keyword == '{' || *keyword == '}' || - *keyword == '\\' || *keyword == '"' || - (unsigned char)*keyword <= 32) - return FALSE; - } - return TRUE; -} - static void parse_imap_keywords_list(struct mbox_sync_mail_context *ctx, struct message_header_line *hdr, size_t pos) { - const char *keyword; + const char *keyword, *error; size_t keyword_start; unsigned int idx, count; @@ -148,7 +135,8 @@ t_push(); keyword = t_strndup(hdr->full_value + keyword_start, pos - keyword_start); - if (keyword_is_valid(keyword)) { + if (index_mailbox_keyword_is_valid(&ctx->sync_ctx->mbox->ibox, + keyword, &error)) { mail_index_keyword_lookup_or_create( ctx->sync_ctx->mbox->ibox.index, keyword, &idx); }
--- a/src/lib-storage/mail-storage-private.h Sun Sep 02 06:08:58 2007 +0300 +++ b/src/lib-storage/mail-storage-private.h Sun Sep 02 06:10:54 2007 +0300 @@ -61,7 +61,8 @@ const char *user; /* name of user accessing the storage */ enum mail_storage_flags flags; - enum file_lock_method lock_method; + enum file_lock_method lock_method; + unsigned int keyword_max_len; struct mail_storage_callbacks *callbacks; void *callback_context; @@ -116,9 +117,10 @@ uint32_t *last_saved_uid_r); void (*transaction_rollback)(struct mailbox_transaction_context *t); - struct mail_keywords * - (*keywords_create)(struct mailbox_transaction_context *t, - const char *const keywords[]); + int (*keywords_create)(struct mailbox_transaction_context *t, + const char *const keywords[], + struct mail_keywords **keywords_r, + bool skip_invalid); void (*keywords_free)(struct mailbox_transaction_context *t, struct mail_keywords *keywords);
--- a/src/lib-storage/mail-storage.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/lib-storage/mail-storage.c Sun Sep 02 06:10:54 2007 +0300 @@ -19,6 +19,8 @@ "Internal error occurred. Refer to server log for more information." #define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]" +#define DEFAULT_MAX_KEYWORD_LENGTH 50 + struct mail_storage_module_register mail_storage_module_register = { 0 }; struct mail_module_register mail_module_register = { 0 }; @@ -169,7 +171,7 @@ { struct mail_storage *storage_class, *storage; struct mail_storage *const *classes; - const char *home; + const char *home, *value; unsigned int i, count; if (data == NULL) @@ -240,6 +242,10 @@ return -1; } + value = getenv("MAIL_MAX_KEYWORD_LENGTH"); + storage->keyword_max_len = value != NULL ? + atoi(value) : DEFAULT_MAX_KEYWORD_LENGTH; + if (hook_mail_storage_created != NULL) hook_mail_storage_created(storage); @@ -531,11 +537,29 @@ mailbox_notify_changes(box, 0, NULL, NULL); } +int mailbox_keywords_create(struct mailbox_transaction_context *t, + const char *const keywords[], + struct mail_keywords **keywords_r) +{ + const char *empty_keyword_list = NULL; + + if (keywords == NULL) + keywords = &empty_keyword_list; + return t->box->v.keywords_create(t, keywords, keywords_r, FALSE); +} + struct mail_keywords * -mailbox_keywords_create(struct mailbox_transaction_context *t, - const char *const keywords[]) +mailbox_keywords_create_valid(struct mailbox_transaction_context *t, + const char *const keywords[]) { - return t->box->v.keywords_create(t, keywords); + const char *empty_keyword_list = NULL; + struct mail_keywords *kw; + + if (keywords == NULL) + keywords = &empty_keyword_list; + if (t->box->v.keywords_create(t, keywords, &kw, TRUE) < 0) + i_unreached(); + return kw; } void mailbox_keywords_free(struct mailbox_transaction_context *t,
--- a/src/lib-storage/mail-storage.h Sun Sep 02 06:08:58 2007 +0300 +++ b/src/lib-storage/mail-storage.h Sun Sep 02 06:10:54 2007 +0300 @@ -322,10 +322,15 @@ /* Return the number of active transactions for the mailbox. */ unsigned int mailbox_transaction_get_count(struct mailbox *box); -/* Build mail_keywords from NULL-terminated keywords list. */ +/* Build mail_keywords from NULL-terminated keywords list. + Returns 0 if successful, -1 if there are invalid keywords (error is set). */ +int mailbox_keywords_create(struct mailbox_transaction_context *t, + const char *const keywords[], + struct mail_keywords **keywords_r); +/* Like mailbox_keywords_create(), except ignore invalid keywords. */ struct mail_keywords * -mailbox_keywords_create(struct mailbox_transaction_context *t, - const char *const keywords[]); +mailbox_keywords_create_valid(struct mailbox_transaction_context *t, + const char *const keywords[]); void mailbox_keywords_free(struct mailbox_transaction_context *t, struct mail_keywords **keywords);
--- a/src/plugins/convert/convert-storage.c Sun Sep 02 06:08:58 2007 +0300 +++ b/src/plugins/convert/convert-storage.c Sun Sep 02 06:10:54 2007 +0300 @@ -72,7 +72,8 @@ keywords_list = mail_get_keywords(mail); keywords = strarray_length(keywords_list) == 0 ? NULL : - mailbox_keywords_create(dest_trans, keywords_list); + mailbox_keywords_create_valid(dest_trans, + keywords_list); ret = mailbox_copy(dest_trans, mail, mail_get_flags(mail), keywords, NULL);