From 7cc082e2370da69c8783812c251190d316ce82b3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 15 Mar 2018 10:32:23 +0000 Subject: wget: add support for https Allow wget to support https URLs. Changes are: - Add mingw_popen2 which uses a named pipe to allow bidirectional communication with a child process; - Modify ssl_client to accept a WIN32 handle instead of a file descriptor as an argument; - Allow tls_get_random to open /dev/urandom; - Using the above changes implement a WIN32 version of spawn_ssl_client in wget. This closes GitHub issue #75. Also, enable authentication in wget. --- configs/mingw32_defconfig | 11 ++--- configs/mingw64_defconfig | 11 ++--- include/mingw.h | 1 + networking/ssl_client.c | 23 ++++++++++- networking/tls.c | 6 +++ networking/wget.c | 27 ++++++++++++ win32/popen.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 171 insertions(+), 11 deletions(-) diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig index c143d9f0c..8128764a8 100644 --- a/configs/mingw32_defconfig +++ b/configs/mingw32_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.29.0.git -# Wed Feb 7 15:11:44 2018 +# Thu Mar 15 10:05:34 2018 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -478,6 +478,7 @@ CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y # CONFIG_HALT is not set # CONFIG_POWEROFF is not set # CONFIG_REBOOT is not set +# CONFIG_FEATURE_WAIT_FOR_INIT is not set # CONFIG_FEATURE_CALL_TELINIT is not set CONFIG_TELINIT_PATH="" # CONFIG_INIT is not set @@ -904,7 +905,7 @@ CONFIG_NC_SERVER=y # CONFIG_PSCAN is not set # CONFIG_ROUTE is not set # CONFIG_SLATTACH is not set -# CONFIG_SSL_CLIENT is not set +CONFIG_SSL_CLIENT=y # CONFIG_TC is not set # CONFIG_FEATURE_TC_INGRESS is not set # CONFIG_TCPSVD is not set @@ -923,7 +924,7 @@ CONFIG_NC_SERVER=y # CONFIG_FEATURE_TFTP_PUT is not set # CONFIG_FEATURE_TFTP_BLOCKSIZE is not set # CONFIG_TFTP_DEBUG is not set -# CONFIG_TLS is not set +CONFIG_TLS=y # CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set # CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set @@ -934,9 +935,9 @@ CONFIG_NC_SERVER=y CONFIG_WGET=y CONFIG_FEATURE_WGET_LONG_OPTIONS=y # CONFIG_FEATURE_WGET_STATUSBAR is not set -# CONFIG_FEATURE_WGET_AUTHENTICATION is not set +CONFIG_FEATURE_WGET_AUTHENTICATION=y # CONFIG_FEATURE_WGET_TIMEOUT is not set -# CONFIG_FEATURE_WGET_HTTPS is not set +CONFIG_FEATURE_WGET_HTTPS=y # CONFIG_FEATURE_WGET_OPENSSL is not set CONFIG_WHOIS=y # CONFIG_ZCIP is not set diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig index 9427f7b5b..d96dc4540 100644 --- a/configs/mingw64_defconfig +++ b/configs/mingw64_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Busybox version: 1.29.0.git -# Wed Feb 7 15:18:49 2018 +# Thu Mar 15 10:21:09 2018 # CONFIG_HAVE_DOT_CONFIG=y # CONFIG_PLATFORM_POSIX is not set @@ -478,6 +478,7 @@ CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y # CONFIG_HALT is not set # CONFIG_POWEROFF is not set # CONFIG_REBOOT is not set +# CONFIG_FEATURE_WAIT_FOR_INIT is not set # CONFIG_FEATURE_CALL_TELINIT is not set CONFIG_TELINIT_PATH="" # CONFIG_INIT is not set @@ -904,7 +905,7 @@ CONFIG_NC_SERVER=y # CONFIG_PSCAN is not set # CONFIG_ROUTE is not set # CONFIG_SLATTACH is not set -# CONFIG_SSL_CLIENT is not set +CONFIG_SSL_CLIENT=y # CONFIG_TC is not set # CONFIG_FEATURE_TC_INGRESS is not set # CONFIG_TCPSVD is not set @@ -923,7 +924,7 @@ CONFIG_NC_SERVER=y # CONFIG_FEATURE_TFTP_PUT is not set # CONFIG_FEATURE_TFTP_BLOCKSIZE is not set # CONFIG_TFTP_DEBUG is not set -# CONFIG_TLS is not set +CONFIG_TLS=y # CONFIG_TRACEROUTE is not set # CONFIG_TRACEROUTE6 is not set # CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set @@ -934,9 +935,9 @@ CONFIG_NC_SERVER=y CONFIG_WGET=y CONFIG_FEATURE_WGET_LONG_OPTIONS=y # CONFIG_FEATURE_WGET_STATUSBAR is not set -# CONFIG_FEATURE_WGET_AUTHENTICATION is not set +CONFIG_FEATURE_WGET_AUTHENTICATION=y # CONFIG_FEATURE_WGET_TIMEOUT is not set -# CONFIG_FEATURE_WGET_HTTPS is not set +CONFIG_FEATURE_WGET_HTTPS=y # CONFIG_FEATURE_WGET_OPENSSL is not set CONFIG_WHOIS=y # CONFIG_ZCIP is not set diff --git a/include/mingw.h b/include/mingw.h index 386540b37..e56e8f03d 100644 --- a/include/mingw.h +++ b/include/mingw.h @@ -111,6 +111,7 @@ int mingw_rename(const char*, const char*); FILE *mingw_popen(const char *cmd, const char *mode); int mingw_popen_fd(const char *cmd, const char *mode, int fd0, pid_t *pid); +int mingw_popen2(const char *cmd, pid_t *pid); int mingw_pclose(FILE *fd); #undef popen #undef pclose diff --git a/networking/ssl_client.c b/networking/ssl_client.c index eb84e7726..e56d82fc1 100644 --- a/networking/ssl_client.c +++ b/networking/ssl_client.c @@ -15,7 +15,12 @@ //kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o //usage:#define ssl_client_trivial_usage +//usage: IF_NOT_PLATFORM_MINGW32( //usage: "[-e] -s FD [-r FD] [-n SNI]" +//usage: ) +//usage: IF_PLATFORM_MINGW32( +//usage: "[-e] -h handle [-n SNI]" +//usage: ) //usage:#define ssl_client_full_usage "" #include "libbb.h" @@ -26,15 +31,24 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv) tls_state_t *tls; const char *sni = NULL; int opt; +#if ENABLE_PLATFORM_MINGW32 + char *hstr = NULL; + HANDLE h; +#endif // INIT_G(); tls = new_tls_state(); - opt = getopt32(argv, "es:#r:#n:", &tls->ofd, &tls->ifd, &sni); +#if !ENABLE_PLATFORM_MINGW32 + opt = getopt32(argv, "es:+r:+n:", &tls->ofd, &tls->ifd, &sni); + if (!(opt & (1<<2))) { /* -r N defaults to -s N */ tls->ifd = tls->ofd; } +#else + opt = getopt32(argv, "eh:n:", &hstr, &sni); +#endif if (!(opt & (3<<1))) { if (!argv[1]) @@ -47,6 +61,13 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv) sni = argv[1]; tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443); } +#if ENABLE_PLATFORM_MINGW32 + else { + if (!hstr || sscanf(hstr, "%p", &h) != 1) + bb_error_msg_and_die("invalid handle"); + tls->ifd = tls->ofd = _open_osfhandle((intptr_t)h, _O_RDWR|_O_BINARY); + } +#endif tls_handshake(tls, sni); diff --git a/networking/tls.c b/networking/tls.c index 99722cfb4..ec5a56d57 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -289,8 +289,14 @@ static void dump_tls_record(const void *vp, int len) void tls_get_random(void *buf, unsigned len) { +#if !ENABLE_PLATFORM_MINGW32 if (len != open_read_close("/dev/urandom", buf, len)) xfunc_die(); +#else + int fd = mingw_open("/dev/urandom", O_RDONLY|O_SPECIAL); + if (fd < 0 || len != read_close(fd, buf, len)) + xfunc_die(); +#endif } /* Nondestructively see the current hash value */ diff --git a/networking/wget.c b/networking/wget.c index 150bc8e12..776894dca 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -714,6 +714,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) #endif #if ENABLE_FEATURE_WGET_HTTPS +# if !ENABLE_PLATFORM_MINGW32 static void spawn_ssl_client(const char *host, int network_fd, int flags) { int sp[2]; @@ -763,6 +764,32 @@ static void spawn_ssl_client(const char *host, int network_fd, int flags) close(sp[1]); xmove_fd(sp[0], network_fd); } +# else +static void spawn_ssl_client(const char *host, int network_fd, int flags) +{ + int fd1; + pid_t pid; + char *servername, *p, *cmd; + + servername = xstrdup(host); + p = strrchr(servername, ':'); + if (p) *p = '\0'; + + fflush_all(); + + cmd = xasprintf("%s ssl_client -h %p -n %s%s", bb_busybox_exec_path, + (void *)_get_osfhandle(network_fd), servername, + flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? " -e" : ""); + + if ( (fd1=mingw_popen2(cmd, &pid)) == -1 ) { + bb_perror_msg_and_die("can't execute ssl_client"); + } + + free(cmd); + free(servername); + xmove_fd(fd1, network_fd); +} +# endif #endif static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) diff --git a/win32/popen.c b/win32/popen.c index 59f5ca9f0..c075e2144 100644 --- a/win32/popen.c +++ b/win32/popen.c @@ -288,6 +288,109 @@ finito: return fd; } +/* + * Open a bidirectional pipe to a command. The pid of the command is + * returned in the variable pid, which can be NULL. + */ +int mingw_popen2(const char *cmd, pid_t *pid) +{ + pipe_data *p; + char *name = NULL; + SECURITY_ATTRIBUTES sa; + STARTUPINFO siStartInfo; + int success; + int fd = -1; + const int ip = 1; /* index of parent end of pipe */ + const int ic = 0; /* index of child end of pipe */ + + if ( cmd == NULL || *cmd == '\0' ) { + return -1; + } + + /* find an unused pipe structure */ + if ( (p=find_pipe()) == NULL ) { + return -1; + } + + /* Create the pipe */ + name = xasprintf("\\\\.\\pipe\\bb_pipe.%d.%d", getpid(), (int)(p-pipes)); + + sa.nLength = sizeof(sa); /* Length in bytes */ + sa.bInheritHandle = 1; /* the child must inherit these handles */ + sa.lpSecurityDescriptor = NULL; + + p->pipe[ip] = CreateNamedPipe(name, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE|PIPE_WAIT, + 1, 4096, 4096, 0, &sa); + if (p->pipe[ip] == INVALID_HANDLE_VALUE) { + goto finito; + } + + /* Connect to the pipe */ + p->pipe[ic] = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, &sa, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, + NULL); + if (p->pipe[ic] == INVALID_HANDLE_VALUE) { + goto finito; + } + + /* Make the parent end of the pipe non-inheritable */ + SetHandleInformation(p->pipe[ip], HANDLE_FLAG_INHERIT, 0); + + /* Now create the child process */ + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.wShowWindow = SW_HIDE; + siStartInfo.hStdInput = p->pipe[ic]; + siStartInfo.hStdOutput = p->pipe[ic]; + siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + + success = CreateProcess(NULL, + (LPTSTR)cmd, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + TRUE, /* handles are inherited */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &siStartInfo, /* STARTUPINFO pointer */ + &p->piProcInfo); /* receives PROCESS_INFORMATION */ + + if ( !success ) { + goto finito; + } + + /* close child end of pipe */ + CloseHandle(p->pipe[ic]); + p->pipe[ic] = INVALID_HANDLE_VALUE; + + fd = _open_osfhandle((intptr_t)p->pipe[ip], _O_RDWR|_O_BINARY); + +finito: + free(name); + if ( fd == -1 ) { + errno = err_win_to_posix(GetLastError()); + if ( p->pipe[0] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->pipe[0]); + } + if ( p->pipe[1] != INVALID_HANDLE_VALUE ) { + CloseHandle(p->pipe[1]); + } + } + else { + p->mode = 'r'; + p->fd = fd; + if ( pid ) { + *pid = (pid_t)p->piProcInfo.dwProcessId; + } + } + + return fd; +} + int mingw_pclose(FILE *fp) { int i, ip, fd; -- cgit v1.2.3-55-g6feb