diff --git a/TODO b/TODO index c526512f9ec9b8f00c9a3f8991c85dab6337b504..807c5b9ffa38ca9d065420d40a98062f54940c2c 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ Current: * Implement enotify extension: - - Implement valid_notify_method test (currently skeleton) - Implement notify_method_capability test (currently skeleton) - Implement parsing :options argument - Check whether handling of error conditions matches the standard diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.c b/src/lib-sieve/plugins/enotify/ext-enotify-common.c index c735046cacb83f5059117603caafbf91bf83f31f..c9756a333e670f1e2a0372e40f11da32d9014708 100644 --- a/src/lib-sieve/plugins/enotify/ext-enotify-common.c +++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.c @@ -201,9 +201,9 @@ const struct sieve_enotify_method *ext_enotify_runtime_check_operands (const struct sieve_runtime_env *renv, unsigned int source_line, string_t *method_uri, string_t *message, string_t *from, void **context) { + const struct sieve_enotify_method *method; const char *uri = str_c(method_uri); const char *scheme; - const struct sieve_enotify_method *method; if ( (scheme=ext_enotify_uri_scheme_parse(&uri)) == NULL ) { sieve_runtime_error @@ -219,7 +219,7 @@ const struct sieve_enotify_method *ext_enotify_runtime_check_operands "invalid notify method '%s'", scheme); return NULL; } - + if ( method->runtime_check_operands != NULL ) { struct sieve_enotify_log nlog; @@ -239,6 +239,39 @@ const struct sieve_enotify_method *ext_enotify_runtime_check_operands return method; } +bool ext_enotify_runtime_method_validate +(const struct sieve_runtime_env *renv, unsigned int source_line, + string_t *method_uri) +{ + const struct sieve_enotify_method *method; + const char *uri = str_c(method_uri); + const char *scheme; + + if ( (scheme=ext_enotify_uri_scheme_parse(&uri)) == NULL ) + return FALSE; + + if ( (method=ext_enotify_method_find(scheme)) == NULL ) + return FALSE; + + if ( method->runtime_check_operands != NULL ) { + struct sieve_enotify_log nlog; + + memset(&nlog, 0, sizeof(nlog)); + nlog.location = sieve_error_script_location(renv->script, source_line); + nlog.ehandler = sieve_interpreter_get_error_handler(renv->interp); + nlog.prefix = NULL; + + if ( method->runtime_check_operands + (&nlog, str_c(method_uri), uri, NULL, NULL, NULL, NULL) ) + return TRUE; + + return FALSE; + } + + return TRUE; +} + + /* * Method logging */ @@ -249,6 +282,8 @@ void sieve_enotify_error va_list args; va_start(args, fmt); + if ( nlog == NULL ) return; + T_BEGIN { if ( nlog->prefix == NULL ) sieve_verror(nlog->ehandler, nlog->location, fmt, args); @@ -266,6 +301,8 @@ void sieve_enotify_warning va_list args; va_start(args, fmt); + if ( nlog == NULL ) return; + T_BEGIN { if ( nlog->prefix == NULL ) sieve_vwarning(nlog->ehandler, nlog->location, fmt, args); @@ -282,6 +319,8 @@ void sieve_enotify_log { va_list args; va_start(args, fmt); + + if ( nlog == NULL ) return; T_BEGIN { if ( nlog->prefix == NULL ) diff --git a/src/lib-sieve/plugins/enotify/ext-enotify-common.h b/src/lib-sieve/plugins/enotify/ext-enotify-common.h index ed372f91a46e0b1dee43fdccec9deec9aafe840e..95c2bf0aa85cc0ddbf7e9d45c1045bcf73176511 100644 --- a/src/lib-sieve/plugins/enotify/ext-enotify-common.h +++ b/src/lib-sieve/plugins/enotify/ext-enotify-common.h @@ -83,6 +83,10 @@ const struct sieve_enotify_method *ext_enotify_runtime_check_operands string_t *method_uri, string_t *message, string_t *from, void **context); +bool ext_enotify_runtime_method_validate + (const struct sieve_runtime_env *renv, unsigned int source_line, + string_t *method_uri); + /* * Method logging */ diff --git a/src/lib-sieve/plugins/enotify/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/ntfy-mailto.c index 4a3d11c0c674bd6491c96c7b6c1f6bf69627dd55..f83732726166bd50f7a83ed32878e5a50d28c8c3 100644 --- a/src/lib-sieve/plugins/enotify/ntfy-mailto.c +++ b/src/lib-sieve/plugins/enotify/ntfy-mailto.c @@ -84,6 +84,7 @@ struct ntfy_mailto_context { ARRAY_TYPE(headers) headers; const char *subject; const char *body; + const char *from_normalized; }; /* @@ -518,24 +519,47 @@ static bool ntfy_mailto_compile_check_from */ static bool ntfy_mailto_runtime_check_operands - (const struct sieve_enotify_log *nlog, const char *uri, - const char *uri_body, string_t *message, string_t *from, + (const struct sieve_enotify_log *nlog, const char *uri ATTR_UNUSED, + const char *uri_body, string_t *message ATTR_UNUSED, string_t *from, pool_t context_pool, void **context) { struct ntfy_mailto_context *mtctx; + const char *error, *normalized; + + if ( context_pool != NULL && context != NULL ) { + /* Need to create context before validation to have arrays present */ + mtctx = p_new(context_pool, struct ntfy_mailto_context, 1); - /* Need to create context before validation to have arrays present */ - mtctx = p_new(context_pool, struct ntfy_mailto_context, 1); - p_array_init(&mtctx->recipients, context_pool, NTFY_MAILTO_MAX_RECIPIENTS); - p_array_init(&mtctx->headers, context_pool, NTFY_MAILTO_MAX_HEADERS); - - if ( !ntfy_mailto_parse_uri - (nlog, uri_body, &mtctx->recipients, &mtctx->headers, &mtctx->body, - &mtctx->subject) ) { - return FALSE; - } + /* Validate :from */ + if ( from != NULL ) { + T_BEGIN { + normalized = sieve_address_normalize(from, &error); + + if ( normalized == NULL ) { + sieve_enotify_error(nlog, + "specified :from address '%s' is invalid for " + "the mailto method: %s", + str_sanitize(str_c(from), 128), error); + } else + mtctx->from_normalized = p_strdup(context_pool, normalized); + } T_END; + + if ( !normalized ) return FALSE; + } + + p_array_init(&mtctx->recipients, context_pool, NTFY_MAILTO_MAX_RECIPIENTS); + p_array_init(&mtctx->headers, context_pool, NTFY_MAILTO_MAX_HEADERS); + + if ( !ntfy_mailto_parse_uri + (nlog, uri_body, &mtctx->recipients, &mtctx->headers, &mtctx->body, + &mtctx->subject) ) { + return FALSE; + } - *context = (void *) mtctx; + *context = (void *) mtctx; + } else { + return ntfy_mailto_parse_uri(NULL, uri_body, NULL, NULL, NULL, NULL); + } return TRUE; } diff --git a/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c b/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c index 2152ca03769a780c8a756e65395b56760c2f8472..847ffbb92735fb5abbe7383caa03c7726c58ab08 100644 --- a/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c +++ b/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c @@ -111,6 +111,8 @@ static int tst_vnotifym_operation_execute const struct sieve_runtime_env *renv, sieve_size_t *address) { struct sieve_coded_stringlist *notify_uris; + string_t *uri_item; + bool result = TRUE, all_valid = TRUE; /* * Read operands @@ -128,6 +130,21 @@ static int tst_vnotifym_operation_execute sieve_runtime_trace(renv, "VALID_NOTIFY_METHOD test"); - sieve_interpreter_set_test_result(renv->interp, FALSE); + uri_item = NULL; + while ( (result=sieve_coded_stringlist_next_item(notify_uris, &uri_item)) + && uri_item != NULL ) { + + if ( !ext_enotify_runtime_method_validate(renv, 0 /* FIXME */, uri_item) ) { + all_valid = FALSE; + break; + } + } + + if ( !result ) { + sieve_runtime_trace_error(renv, "invalid method uri item"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + sieve_interpreter_set_test_result(renv->interp, all_valid); return SIEVE_EXEC_OK; } diff --git a/tests/extensions/enotify/errors.svtest b/tests/extensions/enotify/errors.svtest index cb7d4e3d65a95b4cef8a127c6212083e430b8ba0..da11ff662c2a97021790ac7aae9fe51758c1227f 100644 --- a/tests/extensions/enotify/errors.svtest +++ b/tests/extensions/enotify/errors.svtest @@ -6,7 +6,7 @@ require "enotify"; test "Invalid URL (FIXME: count only)" { - if test_compile "errors/url.sieve" { + if test_compile "errors/uri.sieve" { test_fail "compile should have failed"; } @@ -16,7 +16,7 @@ test "Invalid URL (FIXME: count only)" { } test "Invalid mailto URL (FIXME: count only)" { - if test_compile "errors/url-mailto.sieve" { + if test_compile "errors/uri-mailto.sieve" { test_fail "compile should have failed"; } diff --git a/tests/extensions/enotify/errors/url-mailto.sieve b/tests/extensions/enotify/errors/uri-mailto.sieve similarity index 100% rename from tests/extensions/enotify/errors/url-mailto.sieve rename to tests/extensions/enotify/errors/uri-mailto.sieve diff --git a/tests/extensions/enotify/errors/url.sieve b/tests/extensions/enotify/errors/uri.sieve similarity index 100% rename from tests/extensions/enotify/errors/url.sieve rename to tests/extensions/enotify/errors/uri.sieve diff --git a/tests/extensions/enotify/valid-notify-method.svtest b/tests/extensions/enotify/valid-notify-method.svtest new file mode 100644 index 0000000000000000000000000000000000000000..6ad92495d682e16da6e78474b3b11632278bd7d1 --- /dev/null +++ b/tests/extensions/enotify/valid-notify-method.svtest @@ -0,0 +1,31 @@ +require "vnd.dovecot.testsuite"; + +require "enotify"; + +test "Invalid header name" { + if valid_notify_method + "mailto:stephan@rename-it.nl?header:=frop" { + test_fail "invalid uri accepted"; + } +} + +test "Invalid recipient" { + if valid_notify_method + "mailto:stephan%23rename-it.nl" { + test_fail "invalid uri accepted"; + } +} + +test "Invalid to header recipient" { + if valid_notify_method + "mailto:stephan@rename-it.nl?to=nico%23vestingbar.nl" { + test_fail "invalid uri accepted"; + } +} + +test "Valid URI" { + if not valid_notify_method + "mailto:stephan@rename-it.nl" { + test_fail "valid uri denied"; + } +}