diff options
author | Ron Yorston <rmy@pobox.com> | 2017-02-08 20:09:29 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2017-02-08 20:09:29 +0000 |
commit | 373275a708bafb88fa4f0519de2166154f44fed9 (patch) | |
tree | 4587b4fd3f695e0f3705b2a217e199f3144df931 /networking/wget.c | |
parent | b74b2619779b1deb903b7766261807df1e9b1f7f (diff) | |
parent | c2b18583a3df06aeecf535c3cea6856aa1f2e205 (diff) | |
download | busybox-w32-373275a708bafb88fa4f0519de2166154f44fed9.tar.gz busybox-w32-373275a708bafb88fa4f0519de2166154f44fed9.tar.bz2 busybox-w32-373275a708bafb88fa4f0519de2166154f44fed9.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'networking/wget.c')
-rw-r--r-- | networking/wget.c | 226 |
1 files changed, 140 insertions, 86 deletions
diff --git a/networking/wget.c b/networking/wget.c index 460b4b833..b9d840328 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -16,12 +16,15 @@ | |||
16 | //config: wget is a utility for non-interactive download of files from HTTP | 16 | //config: wget is a utility for non-interactive download of files from HTTP |
17 | //config: and FTP servers. | 17 | //config: and FTP servers. |
18 | //config: | 18 | //config: |
19 | //config:config FEATURE_WGET_LONG_OPTIONS | ||
20 | //config: bool "Enable long options" | ||
21 | //config: default y | ||
22 | //config: depends on WGET && LONG_OPTS | ||
23 | //config: | ||
19 | //config:config FEATURE_WGET_STATUSBAR | 24 | //config:config FEATURE_WGET_STATUSBAR |
20 | //config: bool "Enable a nifty process meter (+2k)" | 25 | //config: bool "Enable progress bar (+2k)" |
21 | //config: default y | 26 | //config: default y |
22 | //config: depends on WGET | 27 | //config: depends on WGET |
23 | //config: help | ||
24 | //config: Enable the transfer progress bar for wget transfers. | ||
25 | //config: | 28 | //config: |
26 | //config:config FEATURE_WGET_AUTHENTICATION | 29 | //config:config FEATURE_WGET_AUTHENTICATION |
27 | //config: bool "Enable HTTP authentication" | 30 | //config: bool "Enable HTTP authentication" |
@@ -30,13 +33,6 @@ | |||
30 | //config: help | 33 | //config: help |
31 | //config: Support authenticated HTTP transfers. | 34 | //config: Support authenticated HTTP transfers. |
32 | //config: | 35 | //config: |
33 | //config:config FEATURE_WGET_LONG_OPTIONS | ||
34 | //config: bool "Enable long options" | ||
35 | //config: default y | ||
36 | //config: depends on WGET && LONG_OPTS | ||
37 | //config: help | ||
38 | //config: Support long options for the wget applet. | ||
39 | //config: | ||
40 | //config:config FEATURE_WGET_TIMEOUT | 36 | //config:config FEATURE_WGET_TIMEOUT |
41 | //config: bool "Enable timeout option -T SEC" | 37 | //config: bool "Enable timeout option -T SEC" |
42 | //config: default y | 38 | //config: default y |
@@ -51,18 +47,59 @@ | |||
51 | //config: FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option | 47 | //config: FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option |
52 | //config: will work in addition to -T. | 48 | //config: will work in addition to -T. |
53 | //config: | 49 | //config: |
50 | //config:config FEATURE_WGET_HTTPS | ||
51 | //config: bool "Support HTTPS using internal TLS code" | ||
52 | //config: default y | ||
53 | //config: depends on WGET | ||
54 | //config: select TLS | ||
55 | //config: help | ||
56 | //config: wget will use internal TLS code to connect to https:// URLs. | ||
57 | //config: Note: | ||
58 | //config: On NOMMU machines, ssl_helper applet should be available | ||
59 | //config: in the $PATH for this to work. Make sure to select that applet. | ||
60 | //config: | ||
61 | //config: Note: currently, TLS code only makes TLS I/O work, it | ||
62 | //config: does *not* check that the peer is who it claims to be, etc. | ||
63 | //config: IOW: it uses peer-supplied public keys to establish encryption | ||
64 | //config: and signing keys, then encrypts and signs outgoing data and | ||
65 | //config: decrypts incoming data. | ||
66 | //config: It does not check signature hashes on the incoming data: | ||
67 | //config: this means that attackers manipulating TCP packets can | ||
68 | //config: send altered data and we unknowingly receive garbage. | ||
69 | //config: (This check might be relatively easy to add). | ||
70 | //config: It does not check public key's certificate: | ||
71 | //config: this means that the peer may be an attacker impersonating | ||
72 | //config: the server we think we are talking to. | ||
73 | //config: | ||
74 | //config: If you think this is unacceptable, consider this. As more and more | ||
75 | //config: servers switch to HTTPS-only operation, without such "crippled" | ||
76 | //config: TLS code it is *impossible* to simply download a kernel source | ||
77 | //config: from kernel.org. Which can in real world translate into | ||
78 | //config: "my small automatic tooling to build cross-compilers from sources | ||
79 | //config: no longer works, I need to additionally keep a local copy | ||
80 | //config: of ~4 megabyte source tarball of a SSL library and ~2 megabyte | ||
81 | //config: source of wget, need to compile and built both before I can | ||
82 | //config: download anything. All this despite the fact that the build | ||
83 | //config: is done in a QEMU sandbox on a machine with absolutely nothing | ||
84 | //config: worth stealing, so I don't care if someone would go to a lot | ||
85 | //config: of trouble to intercept my HTTPS download to send me an altered | ||
86 | //config: kernel tarball". | ||
87 | //config: | ||
88 | //config: If you still think this is unacceptable, send patches. | ||
89 | //config: | ||
90 | //config: If you still think this is unacceptable, do not want to send | ||
91 | //config: patches, but do want to waste bandwidth expaining how wrong | ||
92 | //config: it is, you will be ignored. | ||
93 | //config: | ||
54 | //config:config FEATURE_WGET_OPENSSL | 94 | //config:config FEATURE_WGET_OPENSSL |
55 | //config: bool "Try to connect to HTTPS using openssl" | 95 | //config: bool "Try to connect to HTTPS using openssl" |
56 | //config: default y | 96 | //config: default y |
57 | //config: depends on WGET | 97 | //config: depends on WGET |
58 | //config: help | 98 | //config: help |
59 | //config: Choose how wget establishes SSL connection for https:// URLs. | 99 | //config: Try to use openssl to handle HTTPS. |
60 | //config: | ||
61 | //config: Busybox itself contains no SSL code. wget will spawn | ||
62 | //config: a helper program to talk over HTTPS. | ||
63 | //config: | 100 | //config: |
64 | //config: OpenSSL has a simple SSL client for debug purposes. | 101 | //config: OpenSSL has a simple SSL client for debug purposes. |
65 | //config: If you select "openssl" helper, wget will effectively run: | 102 | //config: If you select this option, wget will effectively run: |
66 | //config: "openssl s_client -quiet -connect hostname:443 | 103 | //config: "openssl s_client -quiet -connect hostname:443 |
67 | //config: -servername hostname 2>/dev/null" and pipe its data | 104 | //config: -servername hostname 2>/dev/null" and pipe its data |
68 | //config: through it. -servername is not used if hostname is numeric. | 105 | //config: through it. -servername is not used if hostname is numeric. |
@@ -75,24 +112,9 @@ | |||
75 | //config: openssl is also a big binary, often dynamically linked | 112 | //config: openssl is also a big binary, often dynamically linked |
76 | //config: against ~15 libraries. | 113 | //config: against ~15 libraries. |
77 | //config: | 114 | //config: |
78 | //config:config FEATURE_WGET_SSL_HELPER | 115 | //config: If openssl can't be executed, internal TLS code will be used |
79 | //config: bool "Try to connect to HTTPS using ssl_helper" | 116 | //config: (if you enabled it); if openssl can be executed but fails later, |
80 | //config: default y | 117 | //config: wget can't detect this, and download will fail. |
81 | //config: depends on WGET | ||
82 | //config: help | ||
83 | //config: Choose how wget establishes SSL connection for https:// URLs. | ||
84 | //config: | ||
85 | //config: Busybox itself contains no SSL code. wget will spawn | ||
86 | //config: a helper program to talk over HTTPS. | ||
87 | //config: | ||
88 | //config: ssl_helper is a tool which can be built statically | ||
89 | //config: from busybox sources against a small embedded SSL library. | ||
90 | //config: Please see networking/ssl_helper/README. | ||
91 | //config: It does not require double host resolution and emits | ||
92 | //config: error messages to stderr. | ||
93 | //config: | ||
94 | //config: Precompiled static binary may be available at | ||
95 | //config: http://busybox.net/downloads/binaries/ | ||
96 | 118 | ||
97 | //applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) | 119 | //applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) |
98 | 120 | ||
@@ -105,20 +127,21 @@ | |||
105 | /* Since we ignore these opts, we don't show them in --help */ | 127 | /* Since we ignore these opts, we don't show them in --help */ |
106 | /* //usage: " [--no-check-certificate] [--no-cache] [--passive-ftp] [-t TRIES]" */ | 128 | /* //usage: " [--no-check-certificate] [--no-cache] [--passive-ftp] [-t TRIES]" */ |
107 | /* //usage: " [-nv] [-nc] [-nH] [-np]" */ | 129 | /* //usage: " [-nv] [-nc] [-nH] [-np]" */ |
108 | //usage: " [-U|--user-agent AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." | 130 | //usage: " [-S|--server-response] [-U|--user-agent AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." |
109 | //usage: ) | 131 | //usage: ) |
110 | //usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS( | 132 | //usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS( |
111 | //usage: "[-cq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]" | 133 | //usage: "[-cq] [-O FILE] [-Y on/off] [-P DIR] [-S] [-U AGENT]" |
112 | //usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." | 134 | //usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." |
113 | //usage: ) | 135 | //usage: ) |
114 | //usage:#define wget_full_usage "\n\n" | 136 | //usage:#define wget_full_usage "\n\n" |
115 | //usage: "Retrieve files via HTTP or FTP\n" | 137 | //usage: "Retrieve files via HTTP or FTP\n" |
116 | //usage: IF_FEATURE_WGET_LONG_OPTIONS( | 138 | //usage: IF_FEATURE_WGET_LONG_OPTIONS( |
117 | //usage: "\n --spider Spider mode - only check file existence" | 139 | //usage: "\n --spider Only check URL existence: $? is 0 if exists" |
118 | //usage: ) | 140 | //usage: ) |
119 | //usage: "\n -c Continue retrieval of aborted transfer" | 141 | //usage: "\n -c Continue retrieval of aborted transfer" |
120 | //usage: "\n -q Quiet" | 142 | //usage: "\n -q Quiet" |
121 | //usage: "\n -P DIR Save to DIR (default .)" | 143 | //usage: "\n -P DIR Save to DIR (default .)" |
144 | //usage: "\n -S Show server response" | ||
122 | //usage: IF_FEATURE_WGET_TIMEOUT( | 145 | //usage: IF_FEATURE_WGET_TIMEOUT( |
123 | //usage: "\n -T SEC Network read timeout is SEC seconds" | 146 | //usage: "\n -T SEC Network read timeout is SEC seconds" |
124 | //usage: ) | 147 | //usage: ) |
@@ -141,6 +164,8 @@ | |||
141 | #endif | 164 | #endif |
142 | 165 | ||
143 | 166 | ||
167 | #define SSL_SUPPORTED (ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_HTTPS) | ||
168 | |||
144 | struct host_info { | 169 | struct host_info { |
145 | char *allocated; | 170 | char *allocated; |
146 | const char *path; | 171 | const char *path; |
@@ -151,7 +176,7 @@ struct host_info { | |||
151 | }; | 176 | }; |
152 | static const char P_FTP[] ALIGN1 = "ftp"; | 177 | static const char P_FTP[] ALIGN1 = "ftp"; |
153 | static const char P_HTTP[] ALIGN1 = "http"; | 178 | static const char P_HTTP[] ALIGN1 = "http"; |
154 | #if ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_SSL_HELPER | 179 | #if SSL_SUPPORTED |
155 | static const char P_HTTPS[] ALIGN1 = "https"; | 180 | static const char P_HTTPS[] ALIGN1 = "https"; |
156 | #endif | 181 | #endif |
157 | 182 | ||
@@ -232,16 +257,17 @@ struct globals { | |||
232 | enum { | 257 | enum { |
233 | WGET_OPT_CONTINUE = (1 << 0), | 258 | WGET_OPT_CONTINUE = (1 << 0), |
234 | WGET_OPT_QUIET = (1 << 1), | 259 | WGET_OPT_QUIET = (1 << 1), |
235 | WGET_OPT_OUTNAME = (1 << 2), | 260 | WGET_OPT_SERVER_RESPONSE = (1 << 2), |
236 | WGET_OPT_PREFIX = (1 << 3), | 261 | WGET_OPT_OUTNAME = (1 << 3), |
237 | WGET_OPT_PROXY = (1 << 4), | 262 | WGET_OPT_PREFIX = (1 << 4), |
238 | WGET_OPT_USER_AGENT = (1 << 5), | 263 | WGET_OPT_PROXY = (1 << 5), |
239 | WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 6), | 264 | WGET_OPT_USER_AGENT = (1 << 6), |
240 | WGET_OPT_RETRIES = (1 << 7), | 265 | WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 7), |
241 | WGET_OPT_nsomething = (1 << 8), | 266 | WGET_OPT_RETRIES = (1 << 8), |
242 | WGET_OPT_HEADER = (1 << 9) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | 267 | WGET_OPT_nsomething = (1 << 9), |
243 | WGET_OPT_POST_DATA = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | 268 | WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, |
244 | WGET_OPT_SPIDER = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | 269 | WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, |
270 | WGET_OPT_SPIDER = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS, | ||
245 | }; | 271 | }; |
246 | 272 | ||
247 | enum { | 273 | enum { |
@@ -395,7 +421,7 @@ static FILE *open_socket(len_and_sockaddr *lsa) | |||
395 | } | 421 | } |
396 | 422 | ||
397 | /* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ | 423 | /* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ |
398 | static char fgets_and_trim(FILE *fp) | 424 | static char fgets_and_trim(FILE *fp, const char *fmt) |
399 | { | 425 | { |
400 | char c; | 426 | char c; |
401 | char *buf_ptr; | 427 | char *buf_ptr; |
@@ -413,6 +439,9 @@ static char fgets_and_trim(FILE *fp) | |||
413 | 439 | ||
414 | log_io("< %s", G.wget_buf); | 440 | log_io("< %s", G.wget_buf); |
415 | 441 | ||
442 | if (fmt && (option_mask32 & WGET_OPT_SERVER_RESPONSE)) | ||
443 | fprintf(stderr, fmt, G.wget_buf); | ||
444 | |||
416 | return c; | 445 | return c; |
417 | } | 446 | } |
418 | 447 | ||
@@ -423,6 +452,9 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp) | |||
423 | if (!s2) | 452 | if (!s2) |
424 | s2 = ""; | 453 | s2 = ""; |
425 | fprintf(fp, "%s%s\r\n", s1, s2); | 454 | fprintf(fp, "%s%s\r\n", s1, s2); |
455 | /* With --server-response, wget also shows its ftp commands */ | ||
456 | if (option_mask32 & WGET_OPT_SERVER_RESPONSE) | ||
457 | fprintf(stderr, "--> %s%s\n\n", s1, s2); | ||
426 | fflush(fp); | 458 | fflush(fp); |
427 | log_io("> %s%s", s1, s2); | 459 | log_io("> %s%s", s1, s2); |
428 | #if ENABLE_PLATFORM_MINGW32 | 460 | #if ENABLE_PLATFORM_MINGW32 |
@@ -431,7 +463,7 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp) | |||
431 | } | 463 | } |
432 | 464 | ||
433 | do { | 465 | do { |
434 | fgets_and_trim(fp); | 466 | fgets_and_trim(fp, "%s\n"); |
435 | } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); | 467 | } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); |
436 | #if ENABLE_PLATFORM_MINGW32 | 468 | #if ENABLE_PLATFORM_MINGW32 |
437 | fseek(fp, 0L, SEEK_CUR); | 469 | fseek(fp, 0L, SEEK_CUR); |
@@ -458,7 +490,7 @@ static void parse_url(const char *src_url, struct host_info *h) | |||
458 | if (strcmp(url, P_FTP) == 0) { | 490 | if (strcmp(url, P_FTP) == 0) { |
459 | h->port = bb_lookup_port(P_FTP, "tcp", 21); | 491 | h->port = bb_lookup_port(P_FTP, "tcp", 21); |
460 | } else | 492 | } else |
461 | #if ENABLE_FEATURE_WGET_OPENSSL || ENABLE_FEATURE_WGET_SSL_HELPER | 493 | #if SSL_SUPPORTED |
462 | if (strcmp(url, P_HTTPS) == 0) { | 494 | if (strcmp(url, P_HTTPS) == 0) { |
463 | h->port = bb_lookup_port(P_HTTPS, "tcp", 443); | 495 | h->port = bb_lookup_port(P_HTTPS, "tcp", 443); |
464 | h->protocol = P_HTTPS; | 496 | h->protocol = P_HTTPS; |
@@ -480,7 +512,7 @@ static void parse_url(const char *src_url, struct host_info *h) | |||
480 | 512 | ||
481 | // FYI: | 513 | // FYI: |
482 | // "Real" wget 'http://busybox.net?var=a/b' sends this request: | 514 | // "Real" wget 'http://busybox.net?var=a/b' sends this request: |
483 | // 'GET /?var=a/b HTTP 1.0' | 515 | // 'GET /?var=a/b HTTP/1.0' |
484 | // and saves 'index.html?var=a%2Fb' (we save 'b') | 516 | // and saves 'index.html?var=a%2Fb' (we save 'b') |
485 | // wget 'http://busybox.net?login=john@doe': | 517 | // wget 'http://busybox.net?login=john@doe': |
486 | // request: 'GET /?login=john@doe HTTP/1.0' | 518 | // request: 'GET /?login=john@doe HTTP/1.0' |
@@ -531,7 +563,7 @@ static char *gethdr(FILE *fp) | |||
531 | int c; | 563 | int c; |
532 | 564 | ||
533 | /* retrieve header line */ | 565 | /* retrieve header line */ |
534 | c = fgets_and_trim(fp); | 566 | c = fgets_and_trim(fp, " %s\n"); |
535 | 567 | ||
536 | /* end of the headers? */ | 568 | /* end of the headers? */ |
537 | if (G.wget_buf[0] == '\0') | 569 | if (G.wget_buf[0] == '\0') |
@@ -665,7 +697,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) | |||
665 | char *servername; | 697 | char *servername; |
666 | int sp[2]; | 698 | int sp[2]; |
667 | int pid; | 699 | int pid; |
668 | IF_FEATURE_WGET_SSL_HELPER(volatile int child_failed = 0;) | 700 | IF_FEATURE_WGET_HTTPS(volatile int child_failed = 0;) |
669 | 701 | ||
670 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0) | 702 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0) |
671 | /* Kernel can have AF_UNIX support disabled */ | 703 | /* Kernel can have AF_UNIX support disabled */ |
@@ -710,7 +742,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) | |||
710 | 742 | ||
711 | BB_EXECVP(argv[0], argv); | 743 | BB_EXECVP(argv[0], argv); |
712 | xmove_fd(3, 2); | 744 | xmove_fd(3, 2); |
713 | # if ENABLE_FEATURE_WGET_SSL_HELPER | 745 | # if ENABLE_FEATURE_WGET_HTTPS |
714 | child_failed = 1; | 746 | child_failed = 1; |
715 | xfunc_die(); | 747 | xfunc_die(); |
716 | # else | 748 | # else |
@@ -723,7 +755,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) | |||
723 | free(servername); | 755 | free(servername); |
724 | free(allocated); | 756 | free(allocated); |
725 | close(sp[1]); | 757 | close(sp[1]); |
726 | # if ENABLE_FEATURE_WGET_SSL_HELPER | 758 | # if ENABLE_FEATURE_WGET_HTTPS |
727 | if (child_failed) { | 759 | if (child_failed) { |
728 | close(sp[0]); | 760 | close(sp[0]); |
729 | return -1; | 761 | return -1; |
@@ -733,38 +765,51 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) | |||
733 | } | 765 | } |
734 | #endif | 766 | #endif |
735 | 767 | ||
736 | /* See networking/ssl_helper/README how to build one */ | 768 | #if ENABLE_FEATURE_WGET_HTTPS |
737 | #if ENABLE_FEATURE_WGET_SSL_HELPER | 769 | static void spawn_ssl_client(const char *host, int network_fd) |
738 | static void spawn_https_helper_small(int network_fd) | ||
739 | { | 770 | { |
740 | int sp[2]; | 771 | int sp[2]; |
741 | int pid; | 772 | int pid; |
773 | char *servername, *p; | ||
774 | |||
775 | servername = xstrdup(host); | ||
776 | p = strrchr(servername, ':'); | ||
777 | if (p) *p = '\0'; | ||
742 | 778 | ||
743 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0) | 779 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0) |
744 | /* Kernel can have AF_UNIX support disabled */ | 780 | /* Kernel can have AF_UNIX support disabled */ |
745 | bb_perror_msg_and_die("socketpair"); | 781 | bb_perror_msg_and_die("socketpair"); |
746 | 782 | ||
783 | fflush_all(); | ||
747 | pid = BB_MMU ? xfork() : xvfork(); | 784 | pid = BB_MMU ? xfork() : xvfork(); |
748 | if (pid == 0) { | 785 | if (pid == 0) { |
749 | /* Child */ | 786 | /* Child */ |
750 | char *argv[3]; | ||
751 | |||
752 | close(sp[0]); | 787 | close(sp[0]); |
753 | xmove_fd(sp[1], 0); | 788 | xmove_fd(sp[1], 0); |
754 | xdup2(0, 1); | 789 | xdup2(0, 1); |
755 | xmove_fd(network_fd, 3); | 790 | if (BB_MMU) { |
756 | /* | 791 | tls_state_t *tls = new_tls_state(); |
757 | * A simple ssl/tls helper | 792 | tls->ifd = tls->ofd = network_fd; |
758 | */ | 793 | tls_handshake(tls, servername); |
759 | argv[0] = (char*)"ssl_helper"; | 794 | tls_run_copy_loop(tls); |
760 | argv[1] = (char*)"-d3"; | 795 | exit(0); |
761 | argv[2] = NULL; | 796 | } else { |
762 | BB_EXECVP(argv[0], argv); | 797 | char *argv[5]; |
763 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | 798 | xmove_fd(network_fd, 3); |
799 | argv[0] = (char*)"ssl_client"; | ||
800 | argv[1] = (char*)"-s3"; | ||
801 | //TODO: if (!is_ip_address(servername))... | ||
802 | argv[2] = (char*)"-n"; | ||
803 | argv[3] = servername; | ||
804 | argv[4] = NULL; | ||
805 | BB_EXECVP(argv[0], argv); | ||
806 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | ||
807 | } | ||
764 | /* notreached */ | 808 | /* notreached */ |
765 | } | 809 | } |
766 | 810 | ||
767 | /* Parent */ | 811 | /* Parent */ |
812 | free(servername); | ||
768 | close(sp[1]); | 813 | close(sp[1]); |
769 | xmove_fd(sp[0], network_fd); | 814 | xmove_fd(sp[0], network_fd); |
770 | } | 815 | } |
@@ -886,9 +931,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
886 | if (!G.chunked) | 931 | if (!G.chunked) |
887 | break; | 932 | break; |
888 | 933 | ||
889 | fgets_and_trim(dfp); /* Eat empty line */ | 934 | fgets_and_trim(dfp, NULL); /* Eat empty line */ |
890 | get_clen: | 935 | get_clen: |
891 | fgets_and_trim(dfp); | 936 | fgets_and_trim(dfp, NULL); |
892 | G.content_len = STRTOOFF(G.wget_buf, NULL, 16); | 937 | G.content_len = STRTOOFF(G.wget_buf, NULL, 16); |
893 | /* FIXME: error check? */ | 938 | /* FIXME: error check? */ |
894 | if (G.content_len == 0) | 939 | if (G.content_len == 0) |
@@ -1013,16 +1058,16 @@ static void download_one_url(const char *url) | |||
1013 | 1058 | ||
1014 | /* Open socket to http(s) server */ | 1059 | /* Open socket to http(s) server */ |
1015 | #if ENABLE_FEATURE_WGET_OPENSSL | 1060 | #if ENABLE_FEATURE_WGET_OPENSSL |
1016 | /* openssl (and maybe ssl_helper) support is configured */ | 1061 | /* openssl (and maybe internal TLS) support is configured */ |
1017 | if (target.protocol == P_HTTPS) { | 1062 | if (target.protocol == P_HTTPS) { |
1018 | /* openssl-based helper | 1063 | /* openssl-based helper |
1019 | * Inconvenient API since we can't give it an open fd | 1064 | * Inconvenient API since we can't give it an open fd |
1020 | */ | 1065 | */ |
1021 | int fd = spawn_https_helper_openssl(server.host, server.port); | 1066 | int fd = spawn_https_helper_openssl(server.host, server.port); |
1022 | # if ENABLE_FEATURE_WGET_SSL_HELPER | 1067 | # if ENABLE_FEATURE_WGET_HTTPS |
1023 | if (fd < 0) { /* no openssl? try ssl_helper */ | 1068 | if (fd < 0) { /* no openssl? try internal */ |
1024 | sfp = open_socket(lsa); | 1069 | sfp = open_socket(lsa); |
1025 | spawn_https_helper_small(fileno(sfp)); | 1070 | spawn_ssl_client(server.host, fileno(sfp)); |
1026 | goto socket_opened; | 1071 | goto socket_opened; |
1027 | } | 1072 | } |
1028 | # else | 1073 | # else |
@@ -1035,11 +1080,11 @@ static void download_one_url(const char *url) | |||
1035 | } | 1080 | } |
1036 | sfp = open_socket(lsa); | 1081 | sfp = open_socket(lsa); |
1037 | socket_opened: | 1082 | socket_opened: |
1038 | #elif ENABLE_FEATURE_WGET_SSL_HELPER | 1083 | #elif ENABLE_FEATURE_WGET_HTTPS |
1039 | /* Only ssl_helper support is configured */ | 1084 | /* Only internal TLS support is configured */ |
1040 | sfp = open_socket(lsa); | 1085 | sfp = open_socket(lsa); |
1041 | if (target.protocol == P_HTTPS) | 1086 | if (target.protocol == P_HTTPS) |
1042 | spawn_https_helper_small(fileno(sfp)); | 1087 | spawn_ssl_client(server.host, fileno(sfp)); |
1043 | #else | 1088 | #else |
1044 | /* ssl (https) support is not configured */ | 1089 | /* ssl (https) support is not configured */ |
1045 | sfp = open_socket(lsa); | 1090 | sfp = open_socket(lsa); |
@@ -1099,18 +1144,26 @@ static void download_one_url(const char *url) | |||
1099 | } | 1144 | } |
1100 | 1145 | ||
1101 | fflush(sfp); | 1146 | fflush(sfp); |
1102 | /* If we use SSL helper, keeping our end of the socket open for writing | 1147 | |
1103 | * makes our end (i.e. the same fd!) readable (EAGAIN instead of EOF) | 1148 | /* Tried doing this unconditionally. |
1104 | * even after child closes its copy of the fd. | 1149 | * Cloudflare and nginx/1.11.5 are shocked to see SHUT_WR on non-HTTPS. |
1105 | * This helps: | 1150 | */ |
1106 | */ | 1151 | #if SSL_SUPPORTED |
1107 | shutdown(fileno(sfp), SHUT_WR); | 1152 | if (target.protocol == P_HTTPS) { |
1153 | /* If we use SSL helper, keeping our end of the socket open for writing | ||
1154 | * makes our end (i.e. the same fd!) readable (EAGAIN instead of EOF) | ||
1155 | * even after child closes its copy of the fd. | ||
1156 | * This helps: | ||
1157 | */ | ||
1158 | shutdown(fileno(sfp), SHUT_WR); | ||
1159 | } | ||
1160 | #endif | ||
1108 | 1161 | ||
1109 | /* | 1162 | /* |
1110 | * Retrieve HTTP response line and check for "200" status code. | 1163 | * Retrieve HTTP response line and check for "200" status code. |
1111 | */ | 1164 | */ |
1112 | read_response: | 1165 | read_response: |
1113 | fgets_and_trim(sfp); | 1166 | fgets_and_trim(sfp, " %s\n"); |
1114 | 1167 | ||
1115 | str = G.wget_buf; | 1168 | str = G.wget_buf; |
1116 | str = skip_non_whitespace(str); | 1169 | str = skip_non_whitespace(str); |
@@ -1295,6 +1348,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) | |||
1295 | /* name, has_arg, val */ | 1348 | /* name, has_arg, val */ |
1296 | "continue\0" No_argument "c" | 1349 | "continue\0" No_argument "c" |
1297 | "quiet\0" No_argument "q" | 1350 | "quiet\0" No_argument "q" |
1351 | "server-response\0" No_argument "S" | ||
1298 | "output-document\0" Required_argument "O" | 1352 | "output-document\0" Required_argument "O" |
1299 | "directory-prefix\0" Required_argument "P" | 1353 | "directory-prefix\0" Required_argument "P" |
1300 | "proxy\0" Required_argument "Y" | 1354 | "proxy\0" Required_argument "Y" |
@@ -1337,7 +1391,7 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0") | |||
1337 | #endif | 1391 | #endif |
1338 | opt_complementary = "-1" /* at least one URL */ | 1392 | opt_complementary = "-1" /* at least one URL */ |
1339 | IF_FEATURE_WGET_LONG_OPTIONS(":\xff::"); /* --header is a list */ | 1393 | IF_FEATURE_WGET_LONG_OPTIONS(":\xff::"); /* --header is a list */ |
1340 | getopt32(argv, "cqO:P:Y:U:T:+" | 1394 | getopt32(argv, "cqSO:P:Y:U:T:+" |
1341 | /*ignored:*/ "t:" | 1395 | /*ignored:*/ "t:" |
1342 | /*ignored:*/ "n::" | 1396 | /*ignored:*/ "n::" |
1343 | /* wget has exactly four -n<letter> opts, all of which we can ignore: | 1397 | /* wget has exactly four -n<letter> opts, all of which we can ignore: |