diff --git a/TODO b/TODO index 6015fa4eb330f8ee36458bf4814110732c847733..4a68ed1de996173a2502ff284c26dfecbfccde3f 100644 --- a/TODO +++ b/TODO @@ -4,7 +4,6 @@ Current: - Limit the number of notifications generated (on a per-method basis) * Implement mailto method for the enotify extension: - Finish URI validation to properly recognize invalid characters. - - Check that URI headers are not duplicated if not allowed. * Incorporate enotify extension into default compile. Next (in order of descending priority/precedence): diff --git a/src/lib-sieve/plugins/enotify/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/ntfy-mailto.c index 05f9ad590ab699c3c71908a0d376ad0a64b5796c..571cb54f238772f2b33a6e689064b94b6e280286 100644 --- a/src/lib-sieve/plugins/enotify/ntfy-mailto.c +++ b/src/lib-sieve/plugins/enotify/ntfy-mailto.c @@ -113,6 +113,21 @@ static const char *_reserved_headers[] = { "message-id", "data", "bcc", + "in-reply-to", + "references", + "resent-date", + "resent-from", + "resent-sender", + "resent-to", + "resent-cc", + "resent-bcc", + "resent-msg-id", + "sender", + NULL +}; + +static const char *_unique_headers[] = { + "reply-to", NULL }; @@ -130,6 +145,20 @@ static inline bool _ntfy_mailto_header_allowed(const char *field_name) return TRUE; } +static inline bool _ntfy_mailto_header_unique(const char *field_name) +{ + const char **rhdr = _unique_headers; + + /* Check whether it is supposed to be unique */ + while ( *rhdr != NULL ) { + if ( strcasecmp(field_name, *rhdr) == 0 ) + return FALSE; + rhdr++; + } + + return TRUE; +} + /* * Mailto URI parsing */ @@ -145,6 +174,9 @@ static inline pool_t array_get_pool_i(struct array *array) #define _uri_parse_error(LOG, ...) \ sieve_enotify_error(LOG, "invalid mailto URI: " __VA_ARGS__ ) + +#define _uri_parse_warning(LOG, ...) \ + sieve_enotify_error(LOG, "mailto URI: " __VA_ARGS__ ) /* FIXME: much of this implementation will be common to other URI schemes. This * should be merged into a common implementation. @@ -238,8 +270,7 @@ static bool _uri_add_valid_recipient /* Upgrade existing Cc: recipient to a To: recipient if possible */ rcpts[i].carbon_copy = ( rcpts[i].carbon_copy && cc ); - sieve_enotify_warning(nlog, - "mailto URI: ignored duplicate recipient '%s'", + _uri_parse_warning(nlog, "ignored duplicate recipient '%s'", str_sanitize(str_c(recipient), 80)); return TRUE; } @@ -339,6 +370,23 @@ static bool _uri_parse_header_recipients return TRUE; } +static bool _uri_header_duplicate +(ARRAY_TYPE(headers) *headers, const char *field_name) +{ + if ( _ntfy_mailto_header_unique(field_name) ) { + const struct ntfy_mailto_header_field *hdrs; + unsigned int count, i; + + hdrs = array_get(headers, &count); + for ( i = 0; i < count; i++ ) { + if ( strcasecmp(hdrs[i].name, field_name) == 0 ) + return TRUE; + } + } + + return FALSE; +} + static bool _uri_parse_headers (const struct sieve_enotify_log *nlog, const char **uri_p, ARRAY_TYPE(headers) *headers_r, ARRAY_TYPE(recipients) *recipients_r, @@ -347,7 +395,13 @@ static bool _uri_parse_headers string_t *field = t_str_new(128); const char *p = *uri_p; pool_t pool = NULL; - + + if ( body != NULL ) + *body = NULL; + + if ( subject != NULL ) + *subject = NULL; + if ( headers_r != NULL ) pool = array_get_pool(headers_r); @@ -401,11 +455,20 @@ static bool _uri_parse_headers hname_type = _HNAME_BODY; else if ( _ntfy_mailto_header_allowed(field_name) ) { if ( headers_r != NULL ) { - hdrf = array_append_space(headers_r); - hdrf->name = p_strdup(pool, field_name); - } else + if ( !_uri_header_duplicate(headers_r, field_name) ) { + hdrf = array_append_space(headers_r); + hdrf->name = p_strdup(pool, field_name); + } else { + _uri_parse_warning(nlog, + "ignored duplicate for unique header field '%s'", + str_sanitize(field_name, 32)); + hdrf = NULL; + } + } else hdrf = NULL; } else { + _uri_parse_warning(nlog, "ignored reserved header field '%s'", + str_sanitize(field_name, 32)); hdrf = NULL; } @@ -447,20 +510,32 @@ static bool _uri_parse_headers switch ( hname_type ) { case _HNAME_TO: + /* Gracefully allow duplicate To fields */ if ( !_uri_parse_header_recipients(nlog, field, recipients_r, FALSE) ) return FALSE; break; case _HNAME_CC: + /* Gracefully allow duplicate Cc fields */ if ( !_uri_parse_header_recipients(nlog, field, recipients_r, TRUE) ) return FALSE; break; case _HNAME_SUBJECT: - if ( subject != NULL ) - *subject = p_strdup(pool, str_c(field)); + if ( subject != NULL ) { + /* Igore duplicate subject field */ + if ( *subject == NULL ) + *subject = p_strdup(pool, str_c(field)); + else + _uri_parse_warning(nlog, "ignored duplicate subject field"); + } break; case _HNAME_BODY: - if ( subject != NULL ) - *body = p_strdup(pool, str_c(field)); + if ( subject != NULL ) { + /* Igore duplicate body field */ + if ( *body == NULL ) + *body = p_strdup(pool, str_c(field)); + else + _uri_parse_warning(nlog, "ignored duplicate body field"); + } break; case _HNAME_GENERIC: if ( hdrf != NULL ) @@ -528,10 +603,13 @@ static bool ntfy_mailto_compile_check_uri const char *uri_body) { ARRAY_TYPE(recipients) recipients; + ARRAY_TYPE(headers) headers; + + t_array_init(&recipients, 16); + t_array_init(&headers, 16); - t_array_init(&recipients, 4); - - if ( !ntfy_mailto_parse_uri(nlog, uri_body, &recipients, NULL, NULL, NULL) ) + if ( !ntfy_mailto_parse_uri + (nlog, uri_body, &recipients, &headers, NULL, NULL) ) return FALSE; if ( array_count(&recipients) == 0 )