From 2ad87784f13f595a7f39871d03003a4fa4b16a01 Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Wed, 7 May 2014 21:17:43 +0200 Subject: [PATCH] lib-sieve: editheader: Made control characters allowed for editheader, except NUL. NOTE: Dovecot doesn't currently MIME-encode these in the headers. --- .../plugins/editheader/cmd-addheader.c | 37 ++++++++-- tests/extensions/editheader/addheader.svtest | 69 +++++++++++++++++++ tests/extensions/editheader/errors.svtest | 11 ++- .../editheader/errors/field-value.sieve | 6 +- 4 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/lib-sieve/plugins/editheader/cmd-addheader.c b/src/lib-sieve/plugins/editheader/cmd-addheader.c index 6481edd94..c76e0e239 100644 --- a/src/lib-sieve/plugins/editheader/cmd-addheader.c +++ b/src/lib-sieve/plugins/editheader/cmd-addheader.c @@ -83,6 +83,24 @@ const struct sieve_operation_def addheader_operation = { cmd_addheader_operation_execute }; +/* + * Utility + */ + +static bool _str_contains_nul(const string_t *str) +{ + const unsigned char *p, *pend; + + p = str_data(str); + pend = p + str_len(str); + while (p < pend) { + if (*p == '\0') + return TRUE; + p++; + } + return FALSE; +} + /* * Validation */ @@ -134,12 +152,18 @@ static bool cmd_addheader_validate if ( sieve_argument_is_string_literal(arg) ) { string_t *fvalue = sieve_ast_argument_str(arg); + if ( _str_contains_nul(fvalue) ) { + sieve_argument_validate_error(valdtr, arg, + "addheader command: specified value `%s' is invalid " + "(contains NUL character)", str_sanitize(str_c(fvalue), 80)); + return FALSE; + } + if ( !rfc2822_header_field_body_verify (str_c(fvalue), str_len(fvalue), TRUE, TRUE) ) { - sieve_argument_validate_error(valdtr, arg, + sieve_argument_validate_warning(valdtr, arg, "addheader command: specified value `%s' is invalid", str_sanitize(str_c(fvalue), 80)); - return FALSE; } if ( ext_editheader_header_too_large(cmd->ext, str_len(fvalue)) ) { @@ -281,10 +305,9 @@ static int cmd_addheader_operation_execute return SIEVE_EXEC_OK; } - if ( !rfc2822_header_field_body_verify - (str_c(value), str_len(value), TRUE, TRUE) ) { + if ( _str_contains_nul(value) ) { sieve_runtime_error(renv, NULL, "addheader action: " - "specified value `%s' is invalid", + "specified value `%s' is invalid (contains NUL character)", str_sanitize(str_c(value), 80)); return SIEVE_EXEC_FAILURE; } @@ -304,6 +327,8 @@ static int cmd_addheader_operation_execute str_sanitize(str_c(field_name), 80), str_sanitize(str_c(value), 80)); edmail = sieve_message_edit(renv->msgctx); - edit_mail_header_add(edmail, rfc2822_header_field_name_sanitize(str_c(field_name)), str_c(value), last); + edit_mail_header_add(edmail, + rfc2822_header_field_name_sanitize(str_c(field_name)), + str_c(value), last); return SIEVE_EXEC_OK; } diff --git a/tests/extensions/editheader/addheader.svtest b/tests/extensions/editheader/addheader.svtest index 1ce7d4447..944d66fc0 100644 --- a/tests/extensions/editheader/addheader.svtest +++ b/tests/extensions/editheader/addheader.svtest @@ -1,4 +1,5 @@ require "vnd.dovecot.testsuite"; +require "encoded-character"; require "variables"; require "fileinto"; require "mailbox"; @@ -524,4 +525,72 @@ test "Addheader - implicit keep" { } } +test_set "message" "${message}"; +test "Addheader - UTF 8" { + if size :over 76 { + test_fail "original message is longer than 76 bytes?!"; + } + + addheader "X-Some-Header" "Ðто теÑÑ‚!"; + fileinto :create "folder4"; + + if not test_result_execute { + test_fail "failed to execute result"; + } + + if not test_message :folder "folder4" 0 { + test_fail "message not stored"; + } + + if not exists "x-some-header" { + test_fail "header not added to stored message"; + } + + if not header :is "x-some-header" "Ðто теÑÑ‚!" { + if header :matches "x-some-header" "*" {} + test_fail "Bel character not retained: `${0}`"; + } + + if not body :matches "Frop!*" { + test_fail "body not retained in stored mail"; + } +} + +test_result_reset; + +test_set "message" "${message}"; +test "Addheader - devious characters" { + if size :over 76 { + test_fail "original message is longer than 76 bytes?!"; + } + + addheader "X-Some-Header" "Ring my ${hex:07}!"; + fileinto :create "folder5"; + + if not test_result_execute { + test_fail "failed to execute result"; + } + + if not test_message :folder "folder5" 0 { + test_fail "message not stored"; + } + + if not exists "x-some-header" { + test_fail "header not added to stored message"; + } + + if header :is "x-some-header" "Ring my !" { + if header :matches "x-some-header" "*" {} + test_fail "Bel character not retained: `${0}`"; + } + + if not header :is "x-some-header" "Ring my ${hex:07}!" { + if header :matches "x-some-header" "*" {} + test_fail "Incorrect header value: `${0}`"; + } + + if not body :matches "Frop!*" { + test_fail "body not retained in stored mail"; + } +} diff --git a/tests/extensions/editheader/errors.svtest b/tests/extensions/editheader/errors.svtest index b7d4136c5..1d1f24d57 100644 --- a/tests/extensions/editheader/errors.svtest +++ b/tests/extensions/editheader/errors.svtest @@ -1,6 +1,7 @@ require "vnd.dovecot.testsuite"; require "comparator-i;ascii-numeric"; require "relational"; +require "variables"; require "editheader"; @@ -53,16 +54,12 @@ test "Invalid field value" { test_fail "compile should have failed"; } - if not test_error :count "eq" :comparator "i;ascii-numeric" "3" { + if not test_error :count "eq" :comparator "i;ascii-numeric" "2" { test_fail "wrong number of errors reported"; } - if not test_error :index 1 :matches "*value*Yeah!?*invalid*" { - test_fail "wrong error reported (1)"; - } - - if not test_error :index 2 :matches "*value*Woah!*invalid*" { - test_fail "wrong error reported (2)"; + if not test_error :index 1 :matches "*value*Woah*invalid*" { + test_fail "wrong error reported (1): ${0}"; } } diff --git a/tests/extensions/editheader/errors/field-value.sieve b/tests/extensions/editheader/errors/field-value.sieve index 7dc3fd8ff..c9f4eabd4 100644 --- a/tests/extensions/editheader/errors/field-value.sieve +++ b/tests/extensions/editheader/errors/field-value.sieve @@ -8,8 +8,8 @@ addheader "X-field" "Frop"; addheader "X-field" "Frop Frml"; -# Invalid 'BELL' -addheader "X-field" "Yeah!${hex:07}"; +# Invalid 'BELL'; but not an error +addheader "X-field" "Yeah${hex:07}!"; # Invalid 'NUL' -addheader "X-field" "Woah!${hex:00}"; +addheader "X-field" "Woah${hex:00}!"; -- GitLab