diff --git a/ChangeLog b/ChangeLog index 1f3109e06..044204095 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 1f3109e06..044204095 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,24 @@ +2002-02-08 Darin Adler + + * glib/gconvert.h: Make hostname parameter const char *. + * glib/gconvert.c: (g_unescape_uri_string): Added a new + "ASCII must not be escaped" feature, and some missing error + checking. + (is_escalphanum): New. + (is_escalpha): New. + (hostname_validate): New. + (g_filename_from_uri): Don't allow hostnames to include + escaped ASCII, validate hostnames with the new + hostname_validate. + (g_filename_to_uri): Validate hostnames with the new + hostname_validate. + + * tests/uri-test.c: Updated tests to reflect the hostname + validation changes above. + + * glib/gdate.c: (g_date_fill_parse_tokens): Remove the + include and do isdigit -> g_ascii_isdigit. + Fri Feb 8 12:32:14 2002 Owen Taylor * tests/hash-test.c (second_hash_test): Fix access to diff --git a/glib/gconvert.c b/glib/gconvert.c index 7a1f4a514..7b06d6ab0 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -37,8 +37,15 @@ #include "glibintl.h" +#if defined(USE_LIBICONV) && !defined (_LIBICONV_H) +#error libiconv in use but included iconv.h not from libiconv +#endif +#if !defined(USE_LIBICONV) && defined (_LIBICONV_H) +#error libiconv not in use but included iconv.h is from libiconv +#endif + GQuark -g_convert_error_quark() +g_convert_error_quark (void) { static GQuark quark; if (!quark) @@ -47,13 +54,6 @@ g_convert_error_quark() return quark; } -#if defined(USE_LIBICONV) && !defined (_LIBICONV_H) -#error libiconv in use but included iconv.h not from libiconv -#endif -#if !defined(USE_LIBICONV) && defined (_LIBICONV_H) -#error libiconv not in use but included iconv.h is from libiconv -#endif - static gboolean try_conversion (const char *to_codeset, const char *from_codeset, @@ -1433,12 +1433,11 @@ unescape_character (const char *scanner) int first_digit; int second_digit; - first_digit = g_ascii_xdigit_value (*scanner++); - + first_digit = g_ascii_xdigit_value (scanner[0]); if (first_digit < 0) return -1; - second_digit = g_ascii_xdigit_value (*scanner++); + second_digit = g_ascii_xdigit_value (scanner[1]); if (second_digit < 0) return -1; @@ -1446,13 +1445,14 @@ unescape_character (const char *scanner) } static gchar * -g_unescape_uri_string (const gchar *escaped, - const gchar *illegal_characters, - int len) +g_unescape_uri_string (const char *escaped, + int len, + const char *illegal_escaped_characters, + gboolean ascii_must_not_be_escaped) { const gchar *in, *in_end; gchar *out, *result; - int character; + int c; if (escaped == NULL) return NULL; @@ -1460,42 +1460,99 @@ g_unescape_uri_string (const gchar *escaped, if (len < 0) len = strlen (escaped); - result = g_malloc (len + 1); + result = g_malloc (len + 1); out = result; - for (in = escaped, in_end = escaped + len; in < in_end && *in != '\0'; in++) + for (in = escaped, in_end = escaped + len; in < in_end; in++) { - character = *in; - if (character == '%') + c = *in; + + if (c == '%') { - character = unescape_character (in + 1); - - /* Check for an illegal character. We consider '\0' illegal here. */ - if (character == 0 - || (illegal_characters != NULL - && strchr (illegal_characters, (char)character) != NULL)) - { - g_free (result); - return NULL; - } + /* catch partial escape sequences past the end of the substring */ + if (in + 3 > in_end) + break; + + c = unescape_character (in + 1); + + /* catch bad escape sequences and NUL characters */ + if (c <= 0) + break; + + /* catch escaped ASCII */ + if (ascii_must_not_be_escaped && c <= 0x7F) + break; + + /* catch other illegal escaped characters */ + if (strchr (illegal_escaped_characters, c) != NULL) + break; + in += 2; } - *out++ = character; + + *out++ = c; } + g_assert (out - result <= len); *out = '\0'; - - g_assert (out - result <= strlen (escaped)); - if (!g_utf8_validate (result, -1, NULL)) + if (in != in_end || !g_utf8_validate (result, -1, NULL)) { g_free (result); return NULL; } - + return result; } +static gboolean +is_escalphanum (gunichar c) +{ + return c > 0x7F || g_ascii_isalnum (c); +} + +static gboolean +is_escalpha (gunichar c) +{ + return c > 0x7F || g_ascii_isalpha (c); +} + +/* allows an empty string */ +static gboolean +hostname_validate (const char *hostname) +{ + const char *p; + gunichar c, first_char, last_char; + + p = hostname; + if (*p == '\0') + return TRUE; + do + { + /* read in a label */ + c = g_utf8_get_char (p); + p = g_utf8_next_char (p); + if (!is_escalphanum (c)) + return FALSE; + first_char = c; + do + { + last_char = c; + c = g_utf8_get_char (p); + p = g_utf8_next_char (p); + } + while (is_escalphanum (c) || c == '-'); + if (last_char == '-') + return FALSE; + + /* if that was the last label, check that it was a toplabel */ + if (c == '\0' || (c == '.' && *p == '\0')) + return is_escalpha (first_char); + } + while (c == '.'); + return FALSE; +} + /** * g_filename_from_uri: * @uri: a uri describing a filename (escaped, encoded in UTF-8). @@ -1564,11 +1621,14 @@ g_filename_from_uri (const char *uri, return NULL; } - unescaped_hostname = g_unescape_uri_string (host_part, "", path_part - host_part); - if (unescaped_hostname == NULL) + unescaped_hostname = g_unescape_uri_string (host_part, path_part - host_part, "", TRUE); + + if (unescaped_hostname == NULL || + !hostname_validate (unescaped_hostname)) { + g_free (unescaped_hostname); g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI, - _("The hostname of the URI '%s' contains invalidly escaped characters"), + _("The hostname of the URI '%s' is invalid"), uri); return NULL; } @@ -1579,7 +1639,7 @@ g_filename_from_uri (const char *uri, g_free (unescaped_hostname); } - filename = g_unescape_uri_string (path_part, "/", -1); + filename = g_unescape_uri_string (path_part, -1, "/", FALSE); if (filename == NULL) { @@ -1644,7 +1704,7 @@ g_filename_from_uri (const char *uri, **/ gchar * g_filename_to_uri (const char *filename, - char *hostname, + const char *hostname, GError **error) { char *escaped_uri; @@ -1660,19 +1720,19 @@ g_filename_to_uri (const char *filename, return NULL; } + if (hostname && + !(g_utf8_validate (hostname, -1, NULL) + && hostname_validate (hostname))) + { + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, + _("Invalid hostname")); + return NULL; + } + utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, error); if (utf8_filename == NULL) return NULL; - if (hostname && - !g_utf8_validate (hostname, -1, NULL)) - { - g_free (utf8_filename); - g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE, - _("Invalid byte sequence in hostname")); - return NULL; - } - #ifdef G_OS_WIN32 /* Don't use localhost unnecessarily */ if (hostname && g_ascii_strcasecmp (hostname, "localhost") == 0) diff --git a/glib/gconvert.h b/glib/gconvert.h index b7c5a4045..c705078fb 100644 --- a/glib/gconvert.h +++ b/glib/gconvert.h @@ -114,7 +114,7 @@ gchar *g_filename_from_uri (const char *uri, GError **error); gchar *g_filename_to_uri (const char *filename, - char *hostname, + const char *hostname, GError **error); diff --git a/glib/gdate.c b/glib/gdate.c index a9e38ea4b..b59d38206 100644 --- a/glib/gdate.c +++ b/glib/gdate.c @@ -41,7 +41,6 @@ #include #include -#include #include #include @@ -486,7 +485,7 @@ g_date_fill_parse_tokens (const gchar *str, GDateParseTokens *pt) { i = 0; - while (*s && isdigit (*s) && i <= NUM_LEN) + while (*s && g_ascii_isdigit (*s) && i <= NUM_LEN) { num[pt->num_ints][i] = *s; ++s; diff --git a/tests/uri-test.c b/tests/uri-test.c index 6ca1b16bc..f16d26552 100644 --- a/tests/uri-test.c +++ b/tests/uri-test.c @@ -63,11 +63,11 @@ to_uri_tests[] = { /* g_filename_to_utf8 uses current code page on Win32, these tests assume that * local filenames *are* in UTF-8. */ - { "/etc/öäå", NULL, NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, - { "/etc/öäå", NULL, "file:///etc/%C3%B6%C3%A4%C3%A5"}, + { "/etc/\xE5\xE4\xF6", NULL, NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/etc/\xC3\xB6\xC3\xA4\xC3\xA5", NULL, "file:///etc/%C3%B6%C3%A4%C3%A5"}, #endif - { "/etc", "öäå", "file://%C3%B6%C3%A4%C3%A5/etc"}, - { "/etc", "åäö", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/etc", "\xC3\xB6\xC3\xA4\xC3\xA5", "file://%C3%B6%C3%A4%C3%A5/etc"}, + { "/etc", "\xE5\xE4\xF6", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, { "/etc/file with #%", NULL, "file:///etc/file%20with%20%23%25"}, { "", NULL, NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH}, { "", "", NULL, G_CONVERT_ERROR_NOT_ABSOLUTE_PATH}, @@ -90,14 +90,14 @@ to_uri_tests[] = { */ { "/:", NULL, "file:///:"}, { "/?&=", NULL, "file:///?&="}, /* these are not escaped and other reserved characters are -- is that really what we want? */ - { "/", "0123456789", "file://0123456789/"}, + { "/", "0123456789-", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, { "/", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "file://ABCDEFGHIJKLMNOPQRSTUVWXYZ/"}, { "/", "abcdefghijklmnopqrstuvwxyz", "file://abcdefghijklmnopqrstuvwxyz/"}, - { "/", "-_.!~*'()", "file://-_.!~*'()/"}, - { "/", "\"#%<>[\\]^`{|}\x7F", "file://%22%23%25%3C%3E%5B%5C%5D%5E%60%7B%7C%7D%7F/"}, - { "/", ";?&=+$,", "file://%3B%3F%26%3D%2B%24%2C/"}, - { "/", "/", "file:////"}, /* should be "file://%2F/" or an error */ - { "/", "@:", "file://@:/"}, /* these are not escaped and other reserved characters are -- is that really what we want? */ + { "/", "_.!~*'()", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/", "\"#%<>[\\]^`{|}\x7F", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/", ";?&=+$,", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/", "/", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, + { "/", "@:", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, { "/", "\x80\xFF", NULL, G_CONVERT_ERROR_ILLEGAL_SEQUENCE}, { "/", "\xC3\x80\xC3\xBF", "file://%C3%80%C3%BF/"}, }; @@ -127,10 +127,12 @@ from_uri_tests[] = { #endif { "file://otherhost/etc", "/etc", "otherhost"}, { "file://otherhost/etc/%23%25%20file", "/etc/#% file", "otherhost"}, - { "file://%C3%B6%C3%A4%C3%A5/etc", "/etc", "öäå"}, + { "file://%C3%B6%C3%A4%C3%A5/etc", "/etc", "\xC3\xB6\xC3\xA4\xC3\xA5"}, { "file:////etc/%C3%B6%C3%C3%C3%A5", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, - { "file://localhost/åäö", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, - { "file://åäö/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://localhost/\xE5\xE4\xF6", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://\xE5\xE4\xF6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://localhost/%E5%E4%F6", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://%E5%E4%F6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file:///some/file#bad", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file://some", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, @@ -152,18 +154,18 @@ from_uri_tests[] = { { "file:///c:/foo", "/c:/foo"}, { "file:////c:/foo", "//c:/foo"}, #endif - { "file://0123456789/", "/", "0123456789"}, + { "file://0123456789/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file://ABCDEFGHIJKLMNOPQRSTUVWXYZ/", "/", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"}, { "file://abcdefghijklmnopqrstuvwxyz/", "/", "abcdefghijklmnopqrstuvwxyz"}, - { "file://-_.!~*'()/", "/", "-_.!~*'()"}, - { "file://\"<>[\\]^`{|}\x7F/", "/", "\"<>[\\]^`{|}\x7F"}, - { "file://;?&=+$,/", "/", ";?&=+$,"}, + { "file://-_.!~*'()/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://\"<>[\\]^`{|}\x7F/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://;?&=+$,/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file://%C3%80%C3%BF/", "/", "\xC3\x80\xC3\xBF"}, - { "file://@/", "/", "@"}, - { "file://:/", "/", ":"}, + { "file://@/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://:/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file://#/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, - { "file://%23/", "/", "#"}, /* is it dangerous to return a hostname with a "#" character in it? */ - { "file://%2F/", "/", "/"}, /* is it dangerous to return a hostname with a "/" character in it? */ + { "file://%23/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, + { "file://%2F/", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, };