aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-09-11 21:04:02 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-09-11 21:04:02 +0200
commitdd1061b6a79b0161597799e825bfefc27993ace5 (patch)
treef7099078291da669907c5e3f428c10af27a54417
parent5126cf9a15f9e5c3986be0fc2743b63adcc6b1fb (diff)
downloadbusybox-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.h9
-rw-r--r--libbb/percent_decode.c69
-rw-r--r--networking/httpd.c76
-rw-r--r--networking/wget.c13
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;
1578unsigned get_cpu_count(void) FAST_FUNC; 1578unsigned 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 */
1587char *percent_decode_in_place(char *str, int strict) FAST_FUNC;
1588
1589
1581extern const char bb_uuenc_tbl_base64[]; 1590extern const char bb_uuenc_tbl_base64[];
1582extern const char bb_uuenc_tbl_std[]; 1591extern const char bb_uuenc_tbl_std[];
1583void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; 1592void 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
10static 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:
24void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
25int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
26t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
27*/
28}
29
30char* 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 */
835static 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:
849void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
850int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
851t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
852*/
853}
854static 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 }