From 9e32d835f208bbec9a6392b71b2e897c861141ef Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Fri, 19 Dec 2008 17:06:02 +0100 Subject: [PATCH] Enotify: mailto: implemented verification of (unstructured) header field bodies and improved URI syntax checking. --- TODO | 2 - src/lib-sieve/plugins/enotify/ntfy-mailto.c | 40 +++++++++++++++++++- src/lib-sieve/rfc2822.c | 42 +++++++++++++++++++-- src/lib-sieve/rfc2822.h | 2 + 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index e6f7886b3..5372b7ef7 100644 --- a/TODO +++ b/TODO @@ -8,8 +8,6 @@ Current: - Limit the number of notifications generated (on a per-method basis) * Implement mailto method for the enotify extension: - Implement verification of recipient addresses in mailto uris. - - Implement verification of (unstructured) header field bodies in - in mailto uris. - Add addresses contained in to to and cc URI headers to the recipients. Conversely, the generated To header must include the URI recipients apart from those stated explicitly in the To URI diff --git a/src/lib-sieve/plugins/enotify/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/ntfy-mailto.c index ba5374c78..50c806b8a 100644 --- a/src/lib-sieve/plugins/enotify/ntfy-mailto.c +++ b/src/lib-sieve/plugins/enotify/ntfy-mailto.c @@ -109,6 +109,31 @@ static inline bool _ntfy_mailto_header_allowed(const char *field_name) /* FIXME: much of this implementation will be common to other URI schemes. This * should be merged into a common implementation. */ + +static const char _qchar_lookup[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 + 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70 + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F0 +}; + +static inline bool _is_qchar(unsigned char c) +{ + return _qchar_lookup[c]; +} static inline int _decode_hex_digit(char digit) { @@ -251,7 +276,12 @@ static bool _uri_parse_headers *error_r = "invalid % encoding"; return FALSE; } + } else if ( ch != '=' && !_is_qchar(ch) ) { + *error_r = t_strdup_printf + ("invalid character '%c' in header field name part", *p); + return FALSE; } + str_append_c(field, ch); } if ( *p != '\0' ) p++; @@ -292,14 +322,20 @@ static bool _uri_parse_headers *error_r = "invalid % encoding"; return FALSE; } + } else if ( ch != '=' && !_is_qchar(ch) ) { + *error_r = t_strdup_printf + ("invalid character '%c' in header field value part", *p); + return FALSE; } str_append_c(field, ch); } if ( *p != '\0' ) p++; /* Verify field body */ - - // FIXME .... + if ( !rfc2822_header_field_body_verify(str_c(field), str_len(field)) ) { + *error_r = "invalid header field body"; + return FALSE; + } /* Assign field body */ diff --git a/src/lib-sieve/rfc2822.c b/src/lib-sieve/rfc2822.c index 6aed0c815..15e2a4f73 100644 --- a/src/lib-sieve/rfc2822.c +++ b/src/lib-sieve/rfc2822.c @@ -1,6 +1,10 @@ /* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file */ +/* NOTE: much of the functionality implemented here should eventually appear + * somewhere in Dovecot itself. + */ + #include "lib.h" #include "str.h" @@ -8,10 +12,6 @@ #include <stdio.h> #include <ctype.h> - -/* NOTE: much of the functionality implemented here should eventually appear - * somewhere in Dovecot itself. - */ bool rfc2822_header_field_name_verify (const char *field_name, unsigned int len) @@ -35,6 +35,40 @@ bool rfc2822_header_field_name_verify return TRUE; } +bool rfc2822_header_field_body_verify +(const char *field_body, unsigned int len) +{ + const char *p = field_body; + const char *pend = p + len; + + /* unstructured = *([FWS] utext) [FWS] + * FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space + * obs-FWS + * utext = NO-WS-CTL / ; Non white space controls + * %d33-126 / ; The rest of US-ASCII + * obs-utext + * NO-WS-CTL = %d1-8 / ; US-ASCII control characters + * %d11 / ; that do not include the + * %d12 / ; carriage return, line feed, + * %d14-31 / ; and white space characters + * %d127 + * WSP = SP / HTAB + */ + + /* This verification does not allow content to be folded. This should done + * automatically upon message composition. + */ + + while ( p < pend ) { + if ( *p == '\0' || *p == '\r' || *p == '\n' || *p > 127 ) + return FALSE; + + p++; + } + + return TRUE; +} + /* * */ diff --git a/src/lib-sieve/rfc2822.h b/src/lib-sieve/rfc2822.h index fc85ac2a6..2476d11ba 100644 --- a/src/lib-sieve/rfc2822.h +++ b/src/lib-sieve/rfc2822.h @@ -14,6 +14,8 @@ bool rfc2822_header_field_name_verify (const char *field_name, unsigned int len); +bool rfc2822_header_field_body_verify +(const char *field_body, unsigned int len); /* * -- GitLab