diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-11 21:04:02 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-11 21:04:02 +0200 |
commit | dd1061b6a79b0161597799e825bfefc27993ace5 (patch) | |
tree | f7099078291da669907c5e3f428c10af27a54417 | |
parent | 5126cf9a15f9e5c3986be0fc2743b63adcc6b1fb (diff) | |
download | busybox-w32-dd1061b6a79b0161597799e825bfefc27993ace5.tar.gz busybox-w32-dd1061b6a79b0161597799e825bfefc27993ace5.tar.bz2 busybox-w32-dd1061b6a79b0161597799e825bfefc27993ace5.zip |
wget: URL-decode user:password before base64-encoding it into auth hdr. Closes 3625.
function old new delta
percent_decode_in_place - 152 +152
parse_url 304 317 +13
handle_incoming_and_exit 2795 2798 +3
httpd_main 763 760 -3
decodeString 152 - -152
------------------------------------------------------------------------------
(add/remove: 2/1 grow/shrink: 2/1 up/down: 168/-155) Total: 13 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | include/libbb.h | 9 | ||||
-rw-r--r-- | libbb/percent_decode.c | 69 | ||||
-rw-r--r-- | networking/httpd.c | 76 | ||||
-rw-r--r-- | networking/wget.c | 13 |
4 files changed, 86 insertions, 81 deletions
diff --git a/include/libbb.h b/include/libbb.h index d0c7ace22..21cbe1cac 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1578,6 +1578,15 @@ int starts_with_cpu(const char *str) FAST_FUNC; | |||
1578 | unsigned get_cpu_count(void) FAST_FUNC; | 1578 | unsigned get_cpu_count(void) FAST_FUNC; |
1579 | 1579 | ||
1580 | 1580 | ||
1581 | /* Use strict=1 if you process input from untrusted source: | ||
1582 | * it will return NULL on invalid %xx (bad hex chars) | ||
1583 | * and str + 1 if decoded char is / or NUL. | ||
1584 | * In non-strict mode, it always succeeds (returns str), | ||
1585 | * and also it additionally decoded '+' to space. | ||
1586 | */ | ||
1587 | char *percent_decode_in_place(char *str, int strict) FAST_FUNC; | ||
1588 | |||
1589 | |||
1581 | extern const char bb_uuenc_tbl_base64[]; | 1590 | extern const char bb_uuenc_tbl_base64[]; |
1582 | extern const char bb_uuenc_tbl_std[]; | 1591 | extern const char bb_uuenc_tbl_std[]; |
1583 | void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; | 1592 | void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; |
diff --git a/libbb/percent_decode.c b/libbb/percent_decode.c new file mode 100644 index 000000000..9a9d80c4a --- /dev/null +++ b/libbb/percent_decode.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
4 | */ | ||
5 | |||
6 | //kbuild:lib-y += percent_decode.o | ||
7 | |||
8 | #include "libbb.h" | ||
9 | |||
10 | static unsigned hex_to_bin(unsigned char c) | ||
11 | { | ||
12 | unsigned v; | ||
13 | |||
14 | v = c - '0'; | ||
15 | if (v <= 9) | ||
16 | return v; | ||
17 | /* c | 0x20: letters to lower case, non-letters | ||
18 | * to (potentially different) non-letters */ | ||
19 | v = (unsigned)(c | 0x20) - 'a'; | ||
20 | if (v <= 5) | ||
21 | return v + 10; | ||
22 | return ~0; | ||
23 | /* For testing: | ||
24 | void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } | ||
25 | int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); | ||
26 | t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } | ||
27 | */ | ||
28 | } | ||
29 | |||
30 | char* FAST_FUNC percent_decode_in_place(char *str, int strict) | ||
31 | { | ||
32 | /* note that decoded string is always shorter than original */ | ||
33 | char *src = str; | ||
34 | char *dst = str; | ||
35 | char c; | ||
36 | |||
37 | while ((c = *src++) != '\0') { | ||
38 | unsigned v; | ||
39 | |||
40 | if (!strict && c == '+') { | ||
41 | *dst++ = ' '; | ||
42 | continue; | ||
43 | } | ||
44 | if (c != '%') { | ||
45 | *dst++ = c; | ||
46 | continue; | ||
47 | } | ||
48 | v = hex_to_bin(src[0]); | ||
49 | if (v > 15) { | ||
50 | bad_hex: | ||
51 | if (strict) | ||
52 | return NULL; | ||
53 | *dst++ = '%'; | ||
54 | continue; | ||
55 | } | ||
56 | v = (v * 16) | hex_to_bin(src[1]); | ||
57 | if (v > 255) | ||
58 | goto bad_hex; | ||
59 | if (strict && (v == '/' || v == '\0')) { | ||
60 | /* caller takes it as indication of invalid | ||
61 | * (dangerous wrt exploits) chars */ | ||
62 | return str + 1; | ||
63 | } | ||
64 | *dst++ = v; | ||
65 | src += 2; | ||
66 | } | ||
67 | *dst = '\0'; | ||
68 | return str; | ||
69 | } | ||
diff --git a/networking/httpd.c b/networking/httpd.c index ba5eebad5..24482fe52 100644 --- a/networking/httpd.c +++ b/networking/httpd.c | |||
@@ -820,78 +820,6 @@ static char *encodeString(const char *string) | |||
820 | } | 820 | } |
821 | #endif | 821 | #endif |
822 | 822 | ||
823 | /* | ||
824 | * Given a URL encoded string, convert it to plain ascii. | ||
825 | * Since decoding always makes strings smaller, the decode is done in-place. | ||
826 | * Thus, callers should xstrdup() the argument if they do not want the | ||
827 | * argument modified. The return is the original pointer, allowing this | ||
828 | * function to be easily used as arguments to other functions. | ||
829 | * | ||
830 | * string The first string to decode. | ||
831 | * option_d 1 if called for httpd -d | ||
832 | * | ||
833 | * Returns a pointer to the decoded string (same as input). | ||
834 | */ | ||
835 | static unsigned hex_to_bin(unsigned char c) | ||
836 | { | ||
837 | unsigned v; | ||
838 | |||
839 | v = c - '0'; | ||
840 | if (v <= 9) | ||
841 | return v; | ||
842 | /* c | 0x20: letters to lower case, non-letters | ||
843 | * to (potentially different) non-letters */ | ||
844 | v = (unsigned)(c | 0x20) - 'a'; | ||
845 | if (v <= 5) | ||
846 | return v + 10; | ||
847 | return ~0; | ||
848 | /* For testing: | ||
849 | void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } | ||
850 | int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); | ||
851 | t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } | ||
852 | */ | ||
853 | } | ||
854 | static char *decodeString(char *orig, int option_d) | ||
855 | { | ||
856 | /* note that decoded string is always shorter than original */ | ||
857 | char *string = orig; | ||
858 | char *ptr = string; | ||
859 | char c; | ||
860 | |||
861 | while ((c = *ptr++) != '\0') { | ||
862 | unsigned v; | ||
863 | |||
864 | if (option_d && c == '+') { | ||
865 | *string++ = ' '; | ||
866 | continue; | ||
867 | } | ||
868 | if (c != '%') { | ||
869 | *string++ = c; | ||
870 | continue; | ||
871 | } | ||
872 | v = hex_to_bin(ptr[0]); | ||
873 | if (v > 15) { | ||
874 | bad_hex: | ||
875 | if (!option_d) | ||
876 | return NULL; | ||
877 | *string++ = '%'; | ||
878 | continue; | ||
879 | } | ||
880 | v = (v * 16) | hex_to_bin(ptr[1]); | ||
881 | if (v > 255) | ||
882 | goto bad_hex; | ||
883 | if (!option_d && (v == '/' || v == '\0')) { | ||
884 | /* caller takes it as indication of invalid | ||
885 | * (dangerous wrt exploits) chars */ | ||
886 | return orig + 1; | ||
887 | } | ||
888 | *string++ = v; | ||
889 | ptr += 2; | ||
890 | } | ||
891 | *string = '\0'; | ||
892 | return orig; | ||
893 | } | ||
894 | |||
895 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH | 823 | #if ENABLE_FEATURE_HTTPD_BASIC_AUTH |
896 | /* | 824 | /* |
897 | * Decode a base64 data stream as per rfc1521. | 825 | * Decode a base64 data stream as per rfc1521. |
@@ -1949,7 +1877,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) | |||
1949 | } | 1877 | } |
1950 | 1878 | ||
1951 | /* Decode URL escape sequences */ | 1879 | /* Decode URL escape sequences */ |
1952 | tptr = decodeString(urlcopy, 0); | 1880 | tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1); |
1953 | if (tptr == NULL) | 1881 | if (tptr == NULL) |
1954 | send_headers_and_exit(HTTP_BAD_REQUEST); | 1882 | send_headers_and_exit(HTTP_BAD_REQUEST); |
1955 | if (tptr == urlcopy + 1) { | 1883 | if (tptr == urlcopy + 1) { |
@@ -2408,7 +2336,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) | |||
2408 | , &verbose | 2336 | , &verbose |
2409 | ); | 2337 | ); |
2410 | if (opt & OPT_DECODE_URL) { | 2338 | if (opt & OPT_DECODE_URL) { |
2411 | fputs(decodeString(url_for_decode, 1), stdout); | 2339 | fputs(percent_decode_in_place(url_for_decode, /*strict:*/ 0), stdout); |
2412 | return 0; | 2340 | return 0; |
2413 | } | 2341 | } |
2414 | #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR | 2342 | #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR |
diff --git a/networking/wget.c b/networking/wget.c index 6443705fd..94a2f7c3d 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -298,8 +298,13 @@ static void parse_url(const char *src_url, struct host_info *h) | |||
298 | 298 | ||
299 | sp = strrchr(h->host, '@'); | 299 | sp = strrchr(h->host, '@'); |
300 | if (sp != NULL) { | 300 | if (sp != NULL) { |
301 | h->user = h->host; | 301 | // URL-decode "user:password" string before base64-encoding: |
302 | // wget http://test:my%20pass@example.com should send | ||
303 | // Authorization: Basic dGVzdDpteSBwYXNz | ||
304 | // which decodes to "test:my pass". | ||
305 | // Standard wget and curl do this too. | ||
302 | *sp = '\0'; | 306 | *sp = '\0'; |
307 | h->user = percent_decode_in_place(h->host, /*strict:*/ 0); | ||
303 | h->host = sp + 1; | 308 | h->host = sp + 1; |
304 | } | 309 | } |
305 | 310 | ||
@@ -660,12 +665,6 @@ static void download_one_url(const char *url) | |||
660 | 665 | ||
661 | #if ENABLE_FEATURE_WGET_AUTHENTICATION | 666 | #if ENABLE_FEATURE_WGET_AUTHENTICATION |
662 | if (target.user) { | 667 | if (target.user) { |
663 | //TODO: URL-decode "user:password" string before base64-encoding: | ||
664 | //wget http://test:my%20pass@example.com should send | ||
665 | // Authorization: Basic dGVzdDpteSBwYXNz | ||
666 | //which decodes to "test:my pass", instead of what we send now: | ||
667 | // Authorization: Basic dGVzdDpteSUyMHBhc3M= | ||
668 | //Can reuse decodeString() from httpd.c | ||
669 | fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, | 668 | fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, |
670 | base64enc(target.user)); | 669 | base64enc(target.user)); |
671 | } | 670 | } |