changeset 20868:82e8fc1b394f

lib: uri-util: Always fully check the syntax of percent encoding while parsing URI components.
author Stephan Bosch <stephan@dovecot.fi>
date Sun, 02 Oct 2016 14:14:48 +0200
parents 32678cf64cd1
children 7cadfa7cb8f7
files src/lib/uri-util.c
diffstat 1 files changed, 48 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/uri-util.c	Sun May 08 22:56:59 2016 +0200
+++ b/src/lib/uri-util.c	Sun Oct 02 14:14:48 2016 +0200
@@ -597,33 +597,37 @@
 
 int uri_parse_path_segment(struct uri_parser *parser, const char **segment_r)
 {
-	const unsigned char *p = parser->cur;
+	const unsigned char *first = parser->cur;
+	int ret;
 
-	while (p < parser->end) {
-		if (*p == '%') {
-			p++;
-			continue;
+	while (parser->cur < parser->end) {
+		if (*parser->cur == '%') {
+			unsigned char ch = 0;
+			if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
+				return -1;
+			if (ret > 0)
+				continue;
 		}
 
-		if ((*p & 0x80) != 0 || (_uri_char_lookup[*p] & CHAR_MASK_PCHAR) == 0)
+		if ((*parser->cur & 0x80) != 0 ||
+			(_uri_char_lookup[*parser->cur] & CHAR_MASK_PCHAR) == 0)
 			break;
 
-		p++;
+		parser->cur++;
 	}
 
-	if (p < parser->end &&
-		*p != '/' && *p != '?' && *p != '#' ) {
+	if (parser->cur < parser->end &&
+		*parser->cur != '/' && *parser->cur != '?' && *parser->cur != '#' ) {
 		parser->error =
 			"Path component contains invalid character";
 		return -1;
 	}
 
-	if (p == parser->cur)
+	if (first == parser->cur)
 		return 0;
 
 	if (segment_r != NULL)
-		*segment_r = p_strdup_until(parser->pool, parser->cur, p);
-	parser->cur = p;
+		*segment_r = p_strdup_until(parser->pool, first, parser->cur);
 	return 1;
 }
 
@@ -728,7 +732,8 @@
 
 int uri_parse_query(struct uri_parser *parser, const char **query_r)
 {
-	const unsigned char *p = parser->cur;
+	const unsigned char *first = parser->cur;
+	int ret;
 
 	/* RFC 3986:
 	 *
@@ -736,35 +741,39 @@
 	 * query         = *( pchar / "/" / "?" )
 	 * pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 	 */
-	if (p >= parser->end || *p != '?')
+	if (parser->cur >= parser->end || *parser->cur != '?')
 		return 0;
-	p++;
+	parser->cur++;
 
-	while (p < parser->end) {
-		if (*p == '%') {
-			p++;
-			continue;
+	while (parser->cur < parser->end) {
+		if (*parser->cur == '%') {
+			unsigned char ch = 0;
+			if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
+				return -1;
+			if (ret > 0)
+				continue;
 		}
 
-		if ((*p & 0x80) != 0 || (_uri_char_lookup[*p] & CHAR_MASK_QCHAR) == 0)
+		if ((*parser->cur & 0x80) != 0 ||
+			(_uri_char_lookup[*parser->cur] & CHAR_MASK_QCHAR) == 0)
 			break;
-		p++;
+		parser->cur++;
 	}
 
-	if (p < parser->end && *p != '#') {
+	if (parser->cur < parser->end && *parser->cur != '#') {
 		parser->error = "Query component contains invalid character";
 		return -1;
 	}
 
 	if (query_r != NULL)
-		*query_r = p_strdup_until(parser->pool, parser->cur+1, p);
-	parser->cur = p;
+		*query_r = p_strdup_until(parser->pool, first+1, parser->cur);
 	return 1;
 }
 
 int uri_parse_fragment(struct uri_parser *parser, const char **fragment_r)
 {
-	const unsigned char *p = parser->cur;
+	const unsigned char *first = parser->cur;
+	int ret;
 
 	/* RFC 3986:
 	 *
@@ -773,29 +782,32 @@
 	 * pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 	 */
 
-	if (p >= parser->end || *p != '#')
+	if (parser->cur >= parser->end || *parser->cur != '#')
 		return 0;
-	p++;
+	parser->cur++;
 
-	while (p < parser->end) {
-		if (*p == '%') {
-			p++;
-			continue;
+	while (parser->cur < parser->end) {
+		if (*parser->cur == '%') {
+			unsigned char ch = 0;
+			if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
+				return -1;
+			if (ret > 0)
+				continue;
 		}
 
-		if ((*p & 0x80) != 0 || (_uri_char_lookup[*p] & CHAR_MASK_QCHAR) == 0)
+		if ((*parser->cur & 0x80) != 0 ||
+			(_uri_char_lookup[*parser->cur] & CHAR_MASK_QCHAR) == 0)
 			break;
-		p++;
+		parser->cur++;
 	}
 
-	if (p < parser->end) {
+	if (parser->cur < parser->end) {
 		parser->error = "Fragment component contains invalid character";
 		return -1;
 	}
 
 	if (fragment_r != NULL)
-		*fragment_r = p_strdup_until(parser->pool, parser->cur+1, p);
-	parser->cur = p;
+		*fragment_r = p_strdup_until(parser->pool, first+1, parser->cur);
 	return 1;
 }