diff --git a/libr/bin/pdb/pdb_downloader.c b/libr/bin/pdb/pdb_downloader.c index f9b0f8699b0a1..5aa9c89843ce8 100644 --- a/libr/bin/pdb/pdb_downloader.c +++ b/libr/bin/pdb/pdb_downloader.c @@ -18,150 +18,107 @@ static bool checkExtract() { return true; } -static bool checkCurl() { - const char nul[] = R_SYS_DEVNULL; - if (r_sys_cmdf ("curl --version > %s", nul) != 0) { +static bool download_and_write(SPDBDownloaderOpt *opt, const char *file) { + char *dir = r_str_newf ("%s%s%s%s%s", + opt->symbol_store_path, R_SYS_DIR, + opt->dbg_file, R_SYS_DIR, + opt->guid); + if (!r_sys_mkdirp (dir)) { + free (dir); return false; } + char *url = r_str_newf ("%s/%s/%s/%s", opt->symbol_server, opt->dbg_file, opt->guid, file); + int len; + char *file_buf = r_socket_http_get (url, NULL, &len); + free (url); + if (!len || R_STR_ISEMPTY (file_buf)) { + free (dir); + free (file_buf); + return false; + } + char *path = r_str_newf ("%s%s%s", dir, R_SYS_DIR, opt->dbg_file); + FILE *f = fopen (path, "wb"); + if (f) { + fwrite (file_buf, sizeof (char), (size_t)len, f); + fclose (f); + } + free (dir); + free (path); + free (file_buf); return true; } static int download(struct SPDBDownloader *pd) { SPDBDownloaderOpt *opt = pd->opt; - char *curl_cmd = NULL; - char *extractor_cmd = NULL; - char *abspath_to_archive = NULL; - char *abspath_to_file = NULL; - char *archive_name = NULL; - size_t archive_name_len = 0; - char *symbol_store_path = NULL; - char *dbg_file = NULL; - char *guid = NULL; - char *archive_name_escaped = NULL; - char *user_agent = NULL; - char *symbol_server = NULL; - int res = 0; int cmd_ret; + if (!opt->dbg_file || !*opt->dbg_file) { // no pdb debug file return 0; } - if (!checkCurl ()) { - return 0; - } - // dbg_file len is > 0 - archive_name_len = strlen (opt->dbg_file); - archive_name = malloc (archive_name_len + 1); - if (!archive_name) { - return 0; - } - memcpy (archive_name, opt->dbg_file, archive_name_len + 1); - archive_name[archive_name_len - 1] = '_'; - symbol_store_path = r_str_escape (opt->symbol_store_path); - dbg_file = r_str_escape (opt->dbg_file); - guid = r_str_escape (opt->guid); - archive_name_escaped = r_str_escape (archive_name); - user_agent = r_str_escape (opt->user_agent); - symbol_server = r_str_escape (opt->symbol_server); - - abspath_to_archive = r_str_newf ("%s%s%s%s%s%s%s", - symbol_store_path, R_SYS_DIR, - dbg_file, R_SYS_DIR, - guid, R_SYS_DIR, - archive_name_escaped); - - abspath_to_file = strdup (abspath_to_archive); - abspath_to_file[strlen (abspath_to_file) - 1] = 'b'; + + char *abspath_to_file = r_str_newf ("%s%s%s%s%s%s%s", + opt->symbol_store_path, R_SYS_DIR, + opt->dbg_file, R_SYS_DIR, + opt->guid, R_SYS_DIR, + opt->dbg_file); + if (r_file_exists (abspath_to_file)) { eprintf ("File already downloaded.\n"); - R_FREE (user_agent); - R_FREE (abspath_to_archive); - R_FREE (archive_name_escaped); - R_FREE (symbol_store_path); - R_FREE (dbg_file); - R_FREE (guid); - R_FREE (archive_name); - R_FREE (abspath_to_file); - R_FREE (symbol_server); + free (abspath_to_file); return 1; } if (checkExtract () || opt->extract == 0) { - res = 1; - - curl_cmd = r_str_newf ("curl -sfLA \"%s\" \"%s/%s/%s/%s\" --create-dirs -o \"%s\"", - user_agent, - symbol_server, - dbg_file, - guid, - archive_name_escaped, - abspath_to_archive); + char *extractor_cmd = NULL; + char *archive_name = strdup (opt->dbg_file); + archive_name[strlen (archive_name) - 1] = '_'; + char *abspath_to_archive = r_str_newf ("%s%s%s%s%s%s%s", + opt->symbol_store_path, R_SYS_DIR, + opt->dbg_file, R_SYS_DIR, + opt->guid, R_SYS_DIR, + archive_name); + + eprintf ("Attempting to download compressed pdb in %s\n", abspath_to_archive); + char *abs_arch_esc = r_str_escape_sh (abspath_to_archive); #if __WINDOWS__ - const char *cabextractor = "expand"; - const char *format = "%s %s %s"; - - // extractor_cmd -> %1 %2 %3 - // %1 - 'expand' - // %2 - absolute path to archive - // %3 - absolute path to file that will be dearchive - extractor_cmd = r_str_newf (format, cabextractor, - abspath_to_archive, abspath_to_file); + char *abs_file_esc = r_str_escape_sh (abspath_to_file); + // expand %1 %2 + // %1 - absolute path to archive + // %2 - absolute path to file that will be dearchive + extractor_cmd = r_str_newf ("expand \"%s\" \"%s\"", abs_arch_esc, abs_file_esc); + free (abs_file_esc); #else - const char *cabextractor = "cabextract"; - const char *format = "%s -d \"%s\" \"%s\""; char *abspath_to_dir = r_file_dirname (abspath_to_archive); + char *abs_dir_esc = r_str_escape_sh (abspath_to_dir); // cabextract -d %1 %2 // %1 - path to directory where to extract all files from cab archive // %2 - absolute path to cab archive - extractor_cmd = r_str_newf (format, cabextractor, abspath_to_dir, abspath_to_archive); - R_FREE (abspath_to_dir); + extractor_cmd = r_str_newf ("cabextract -d \"%s\" \"%s\"", abs_arch_esc, abs_dir_esc); + free (abs_dir_esc); + free (abspath_to_dir); #endif - eprintf ("Attempting to download compressed pdb in %s\n", abspath_to_archive); - if ((cmd_ret = r_sys_cmd (curl_cmd) != 0)) { - eprintf("curl exited with error %d\n", cmd_ret); - res = 0; - } - eprintf ("Attempting to decompress pdb\n"); - if (opt->extract > 0) { + free (abs_arch_esc); + res = download_and_write (opt, archive_name); + + if (opt->extract > 0 && res) { + eprintf ("Attempting to decompress pdb\n"); if (res && ((cmd_ret = r_sys_cmd (extractor_cmd)) != 0)) { eprintf ("cab extractor exited with error %d\n", cmd_ret); res = 0; } r_file_rm (abspath_to_archive); } - R_FREE (curl_cmd); + free (archive_name); + free (abspath_to_archive); } if (res == 0) { eprintf ("Falling back to uncompressed pdb\n"); - res = 1; - - archive_name_escaped[strlen (archive_name_escaped) - 1] = 'b'; - - curl_cmd = r_str_newf ("curl -sfLA \"%s\" \"%s/%s/%s/%s\" --create-dirs -o \"%s\"", - opt->user_agent, - opt->symbol_server, - opt->dbg_file, - opt->guid, - archive_name_escaped, - abspath_to_file); eprintf ("Attempting to download uncompressed pdb in %s\n", abspath_to_file); - if ((cmd_ret = r_sys_cmd (curl_cmd) != 0)) { - eprintf("curl exited with error %d\n", cmd_ret); - res = 0; - } - R_FREE (curl_cmd); - } - R_FREE (abspath_to_archive); - R_FREE (abspath_to_file); - R_FREE (archive_name); - R_FREE (extractor_cmd); - R_FREE (symbol_store_path); - R_FREE (dbg_file); - R_FREE (guid); - R_FREE (archive_name_escaped); - R_FREE (user_agent); - R_FREE (symbol_server); + res = download_and_write (opt, opt->dbg_file); + } + free (abspath_to_file); return res; } @@ -191,6 +148,19 @@ void deinit_pdb_downloader(SPDBDownloader *pd) { pd->download = 0; } +static bool is_valid_guid(const char *guid) { + if (!guid) { + return false; + } + size_t i; + for (i = 0; guid[i]; i++) { + if (!isxdigit (guid[i])) { + return false; + } + } + return i >= 33; // len of GUID and age +} + int r_bin_pdb_download(RCore *core, int isradjson, int *actions_done, SPDBOptions *options) { int ret; SPDBDownloaderOpt opt; @@ -202,6 +172,11 @@ int r_bin_pdb_download(RCore *core, int isradjson, int *actions_done, SPDBOption return 1; } + if (!is_valid_guid (info->guid)) { + eprintf ("Invalid GUID for file\n"); + return 1; + } + if (!options || !options->symbol_server || !options->user_agent) { eprintf ("Can't retrieve pdb configurations\n"); return 1; diff --git a/libr/config.mk.tail b/libr/config.mk.tail index 7e4569ea6c09b..7cda953aec825 100644 --- a/libr/config.mk.tail +++ b/libr/config.mk.tail @@ -52,6 +52,11 @@ CFLAGS+=-DHAVE_LIB_GMP=1 BN_LIBS=-lgmp endif +# open-ssl +ifeq (${HAVE_LIB_SSL},1) +BN_LIBS=${SSL_LDFLAGS} +endif + #both of these need ssl includes ifneq (,$(filter r_socket r_util,$(BINDEPS))) ifeq (${HAVE_LIB_SSL},1) diff --git a/libr/include/r_socket.h b/libr/include/r_socket.h index fbda80a31c1f7..b9fa714032a34 100644 --- a/libr/include/r_socket.h +++ b/libr/include/r_socket.h @@ -1,11 +1,6 @@ #ifndef R2_SOCKET_H #define R2_SOCKET_H -/* Must be included before windows.h (r_types) */ -#if defined(__WINDOWS__) -#include -#endif - #include "r_types.h" #include "r_bind.h" #include "r_list.h" diff --git a/libr/include/r_types.h b/libr/include/r_types.h index 78ea8562cb89d..27c7ec5a0d731 100644 --- a/libr/include/r_types.h +++ b/libr/include/r_types.h @@ -152,6 +152,7 @@ #ifdef _MSC_VER /* Must be included before windows.h */ #include + #include #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif diff --git a/libr/include/r_util/r_str.h b/libr/include/r_util/r_str.h index c54a0be97cb19..28526e9d2c9c1 100644 --- a/libr/include/r_util/r_str.h +++ b/libr/include/r_util/r_str.h @@ -148,6 +148,7 @@ R_API int r_str_path_unescape(char *path); R_API char *r_str_path_escape(const char *path); R_API int r_str_unescape(char *buf); R_API char *r_str_escape(const char *buf); +R_API char *r_str_escape_sh(const char *buf); R_API char *r_str_escape_dot(const char *buf); R_API char *r_str_escape_latin1(const char *buf, bool show_asciidot, bool esc_bslash, bool colors); R_API char *r_str_escape_utf8(const char *buf, bool show_asciidot, bool esc_bslash); diff --git a/libr/socket/socket.c b/libr/socket/socket.c index 1b24f2f05ad1e..b3a50e7f26e0d 100644 --- a/libr/socket/socket.c +++ b/libr/socket/socket.c @@ -260,80 +260,30 @@ R_API bool r_socket_spawn(RSocket *s, const char *cmd, unsigned int timeout) { R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int proto, unsigned int timeout) { r_return_val_if_fail (s, false); #if __WINDOWS__ +#define gai_strerror gai_strerrorA struct sockaddr_in sa; - struct hostent *he; WSADATA wsadata; - TIMEVAL Timeout; - Timeout.tv_sec = timeout; - Timeout.tv_usec = 0; if (WSAStartup (MAKEWORD (1, 1), &wsadata) == SOCKET_ERROR) { eprintf ("Error creating socket."); return false; } - s->fd = socket (AF_INET, SOCK_STREAM, 0); - if (s->fd == R_INVALID_SOCKET) { - return false; - } - - unsigned long iMode = 1; - int iResult = ioctlsocket (s->fd, FIONBIO, &iMode); - if (iResult != NO_ERROR) { - eprintf ("ioctlsocket error: %d\n", iResult); - } - memset (&sa, 0, sizeof (sa)); - sa.sin_family = AF_INET; - he = (struct hostent *)gethostbyname (host); - if (he == (struct hostent*)0) { -#ifdef _MSC_VER - closesocket (s->fd); -#else - close (s->fd); #endif - return false; - } - sa.sin_addr = *((struct in_addr *)he->h_addr); - s->port = r_socket_port_by_name (port); - s->proto = proto; - sa.sin_port = htons (s->port); - if (!connect (s->fd, (const struct sockaddr*)&sa, sizeof (struct sockaddr))) { -#ifdef _MSC_VER - closesocket (s->fd); -#else - close (s->fd); -#endif - return false; - } - iMode = 0; - iResult = ioctlsocket (s->fd, FIONBIO, &iMode); - if (iResult != NO_ERROR) { - eprintf ("ioctlsocket error: %d\n", iResult); - } - if (timeout > 0) { - r_socket_block_time (s, 1, timeout, 0); - } - fd_set Write, Err; - FD_ZERO (&Write); - FD_ZERO (&Err); - FD_SET (s->fd, &Write); - FD_SET (s->fd, &Err); - select (0, NULL, &Write, &Err, &Timeout); - if (FD_ISSET (s->fd, &Write)) { - return true; - } - return false; -#elif __UNIX__ int ret; - struct addrinfo hints = {0}; + struct addrinfo hints = { 0 }; struct addrinfo *res, *rp; if (!proto) { proto = R_SOCKET_PROTO_TCP; } +#if __UNIX__ r_sys_signal (SIGPIPE, SIG_IGN); +#endif if (proto == R_SOCKET_PROTO_UNIX) { +#if __UNIX__ if (!__connect_unix (s, host)) { return false; } +#endif } else { hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_protocol = proto; @@ -367,17 +317,15 @@ R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int return true; } if (errno == EINPROGRESS) { - struct timeval tv; - tv.tv_sec = timeout; - tv.tv_usec = 0; + struct timeval tv = {timeout, 0}; fd_set wfds; - FD_ZERO(&wfds); - FD_SET(s->fd, &wfds); + FD_ZERO (&wfds); + FD_SET (s->fd, &wfds); if ((ret = select (s->fd + 1, NULL, &wfds, NULL, &tv)) != -1) { if (r_socket_is_connected (s)) { freeaddrinfo (res); - return true; + goto success; } } else { perror ("connect"); @@ -391,18 +339,42 @@ R_API bool r_socket_connect(RSocket *s, const char *host, const char *port, int return false; } } -#endif +success: #if HAVE_LIB_SSL if (s->is_ssl) { s->ctx = SSL_CTX_new (SSLv23_client_method ()); if (!s->ctx) { - r_socket_free (s); + r_socket_close (s); return false; } s->sfd = SSL_new (s->ctx); SSL_set_fd (s->sfd, s->fd); - if (SSL_connect (s->sfd) != 1) { - r_socket_free (s); + int ret = SSL_connect (s->sfd); + if (ret != 1) { + int error = SSL_get_error (s->sfd, ret); + int tries = 10; + while (tries && ret && (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE)) { + struct timeval tv = {1, 0}; + fd_set rfds, wfds; + FD_ZERO (&rfds); + FD_ZERO (&wfds); + if (error == SSL_ERROR_WANT_READ) { + FD_SET (s->fd, &rfds); + } else { + FD_SET (s->fd, &wfds); + } + if ((ret = select (s->fd + 1, &rfds, &wfds, NULL, &tv)) < 1) { + r_socket_close (s); + return false; + } + ret = SSL_connect (s->sfd); + if (ret == 1) { + return true; + } + error = SSL_get_error (s->sfd, ret); + tries--; + } + r_socket_close (s); return false; } } @@ -622,9 +594,7 @@ R_API RSocket *r_socket_accept_timeout(RSocket *s, unsigned int timeout) { FD_ZERO (&except_fds); FD_SET (s->fd, &except_fds); - struct timeval t; - t.tv_sec = timeout; - t.tv_usec = 0; + struct timeval t = {timeout, 0}; int r = select (s->fd + 1, &read_fds, NULL, &except_fds, &t); if(r < 0) { @@ -659,9 +629,7 @@ R_API int r_socket_block_time(RSocket *s, int block, int sec, int usec) { ioctlsocket (s->fd, FIONBIO, (u_long FAR*)&block); #endif if (sec > 0 || usec > 0) { - struct timeval tv = {0}; - tv.tv_sec = sec; - tv.tv_usec = usec; + struct timeval tv = {sec, usec}; if (setsockopt (s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof (tv)) < 0) { return false; } @@ -678,32 +646,17 @@ R_API int r_socket_flush(RSocket *s) { return true; } -// XXX: rewrite it to use select // /* waits secs until new data is received. */ /* returns -1 on error, 0 is false, 1 is true */ R_API int r_socket_ready(RSocket *s, int secs, int usecs) { -#if __UNIX__ - //int msecs = (1000 * secs) + (usecs / 1000); - int msecs = (usecs / 1000); - struct pollfd fds[1]; - fds[0].fd = s->fd; - fds[0].events = POLLIN | POLLPRI; - fds[0].revents = POLLNVAL | POLLHUP | POLLERR; - return poll ((struct pollfd *)&fds, 1, msecs); -#elif __WINDOWS__ fd_set rfds; - struct timeval tv; + struct timeval tv = {secs, usecs}; if (s->fd == R_INVALID_SOCKET) { return -1; } FD_ZERO (&rfds); FD_SET (s->fd, &rfds); - tv.tv_sec = secs; - tv.tv_usec = usecs; return select (s->fd + 1, &rfds, NULL, NULL, &tv); -#else - return true; /* always ready if unknown */ -#endif } R_API char *r_socket_to_string(RSocket *s) { @@ -794,21 +747,10 @@ R_API int r_socket_read(RSocket *s, unsigned char *buf, int len) { return SSL_read (s->sfd, buf, len); } #endif -#if __WINDOWS__ -rep: - { - int ret = recv (s->fd, (void *)buf, len, 0); - if (ret == -1) { - goto rep; - } - return ret; - } -#else // int r = read (s->fd, buf, len); int r = recv (s->fd, buf, len, 0); D { eprintf ("READ "); int i; for (i = 0; isfd, r) == SSL_ERROR_WANT_READ) { + if (r_socket_ready (s, 1, 0) == 1) { + continue; + } + } +#endif return -1; } if (r < 1) { diff --git a/libr/socket/socket_http.c b/libr/socket/socket_http.c index cbc04d6fde9bc..aea330b70da5e 100644 --- a/libr/socket/socket_http.c +++ b/libr/socket/socket_http.c @@ -3,45 +3,81 @@ #include #include -static int __socket_slurp (RSocket *s, ut8 *buf, int bufsz) { - int i; - int chsz = 1; - // r_socket_block_time (s, 1, 1, 0); - if (r_socket_read_block (s, (ut8 *) buf, 1) != 1) { +#if __WINDOWS__ +#include +#endif + +#define SOCKET_HTTP_MAX_HEADER_LENGTH 0x2000 +#define SOCKET_HTTP_MAX_REDIRECTS 5 + +static size_t socket_slurp(RSocket *s, RBuffer *buf) { + size_t i; + if (r_socket_ready (s, 1, 0) != 1) { return 0; } - for (i = 1; i < bufsz; i += chsz) { - buf[i] =0; - r_socket_block_time (s, 1, 0, 1000); - int olen = r_socket_read_block (s, (ut8 *) buf + i , chsz); - if (olen != chsz) { - buf[i] = 0; + r_socket_block_time (s, 1, 0, 1000); + for (i = 0; i < SOCKET_HTTP_MAX_HEADER_LENGTH; i += 1) { + ut8 c; + int olen = r_socket_read_block (s, &c, 1); + if (olen != 1) { + r_buf_append_bytes (buf, (ut8 *)"", 1); break; } + r_buf_append_bytes (buf, &c, 1); } return i; } -static char *r_socket_http_answer (RSocket *s, int *code, int *rlen) { +static char *socket_http_get_recursive(const char *url, int *code, int *rlen, ut32 redirections); + +static char *socket_http_answer(RSocket *s, int *code, int *rlen, ut32 redirections) { r_return_val_if_fail (s, NULL); const char *p; - int ret, len = 0, bufsz = 32768, delta = 0; - char *dn, *buf = calloc (1, bufsz + 32); // XXX: use r_buffer here - if (!buf) { + int ret, len = 0, delta = 0; + char *dn; + RBuffer *b = r_buf_new (); + if (!b) { return NULL; } char *res = NULL; - int olen = __socket_slurp (s, (ut8*)buf, bufsz); + size_t olen = socket_slurp (s, b); + char *buf = malloc (olen + 1); + if (!buf) { + goto exit; + } + r_buf_read_at (b, 0, (ut8 *)buf, olen); + buf[olen] = 0; if ((dn = (char*)r_str_casestr (buf, "\n\n"))) { delta += 2; } else if ((dn = (char*)r_str_casestr (buf, "\r\n\r\n"))) { delta += 4; } else { - goto fail; + goto exit; } olen -= delta; *dn = 0; // chop headers + + /* Follow redirects */ + p = r_str_casestr (buf, "Location:"); + if (p) { + if (!redirections) { + eprintf ("Too many redirects\n"); + goto exit; + } + p += strlen ("Location:"); + char *end_url = strchr (p, '\n'); + if (end_url) { + int url_len = end_url - p; + char *url = r_str_ndup (p, url_len); + r_str_trim (url); + res = socket_http_get_recursive (url, code, rlen, --redirections); + free (url); + len = *rlen; + } + goto exit; + } + /* Parse Len */ p = r_str_casestr (buf, "Content-Length: "); if (p) { @@ -52,6 +88,10 @@ static char *r_socket_http_answer (RSocket *s, int *code, int *rlen) { if (len > 0) { if (len > olen) { res = malloc (len + 2); + if (!res) { + goto exit; + } + olen -= dn - buf; memcpy (res, dn + delta, olen); do { ret = r_socket_read_block (s, (ut8*) res + olen, len - olen); @@ -71,9 +111,9 @@ static char *r_socket_http_answer (RSocket *s, int *code, int *rlen) { } else { res = NULL; } -fail: +exit: free (buf); -// is 's' free'd? isn't this going to cause a double free? + r_buf_free (b); r_socket_close (s); if (rlen) { *rlen = len; @@ -81,38 +121,108 @@ static char *r_socket_http_answer (RSocket *s, int *code, int *rlen) { return res; } -R_API char *r_socket_http_get(const char *url, int *code, int *rlen) { +#if __WINDOWS__ +static char *http_get_w32(const char *url, int *code, int *rlen) { + HINTERNET hInternet = InternetOpenA ("radare2 "R2_VERSION, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + if (!hInternet) { + r_sys_perror ("InternetOpenA"); + return NULL; + } + HINTERNET hOpenUrl = InternetOpenUrlA (hInternet, url, NULL, 0, 0, 0); + if (!hOpenUrl) { + r_sys_perror ("InternetOpenUrlA"); + InternetCloseHandle (hInternet); + return NULL; + } + + char *ret = NULL; + size_t read_sz = 0x100000; + DWORD r = 0, w = 0; + bool res = true; + do { + w += r; + if (!res && GetLastError () == ERROR_INSUFFICIENT_BUFFER) { + read_sz *= 2; + } + char *tmp = realloc (ret, read_sz + w); + if (!tmp) { + R_FREE (ret); + goto exit; + } + ret = tmp; + } while (!(res = InternetReadFile (hOpenUrl, ret + w, read_sz, &r)) || r); + + if (w) { + char *tmp = realloc (ret, (size_t)w + 1); + if (tmp) { + ret = tmp; + ret[w] = 0; + } else { + R_FREE (ret); + } + } else { + R_FREE (ret); + } + +exit: + if (rlen) { + *rlen = w; + } + if (code && w) { + *code = 200; + } + InternetCloseHandle (hInternet); + InternetCloseHandle (hOpenUrl); + return ret; +} +#endif + +static char *socket_http_get_recursive(const char *url, int *code, int *rlen, ut32 redirections) { + if (code) { + *code = 0; + } + if (rlen) { + *rlen = 0; + } char *curl_env = r_sys_getenv ("R2_CURL"); - if (curl_env && *curl_env) { - char *encoded_url = r_str_escape (url); - char *res = r_sys_cmd_strf ("curl '%s'", encoded_url); - free (encoded_url); + if (!R_STR_ISEMPTY (curl_env) && atoi (curl_env)) { + int len; + char *escaped_url = r_str_escape_sh (url); + char *command = r_str_newf ("curl -sfL -o - \"%s\"", escaped_url); + char *res = r_sys_cmd_str (command, NULL, &len); + free (escaped_url); + free (command); + free (curl_env); + if (!res) { + return NULL; + } if (res) { if (code) { *code = 200; } if (rlen) { - *rlen = strlen (res); + *rlen = len; } } - free (curl_env); return res; } free (curl_env); +#if __WINDOWS__ + return http_get_w32 (url, code, rlen); +#else RSocket *s; int ssl = r_str_startswith (url, "https://"); +#if !HAVE_LIB_SSL + if (ssl) { + eprintf ("Tried to get '%s', but SSL support is disabled, set R2_CURL=1 to use curl\n", url); + return NULL; + } +#endif char *response, *host, *path, *port = "80"; char *uri = strdup (url); if (!uri) { return NULL; } - - if (code) { - *code = 0; - } - if (rlen) { - *rlen = 0; - } host = strstr (uri, "://"); if (!host) { free (uri); @@ -147,7 +257,7 @@ R_API char *r_socket_http_get(const char *url, int *code, int *rlen) { "Accept: */*\r\n" "Host: %s:%s\r\n" "\r\n", path, host, port); - response = r_socket_http_answer (s, code, rlen); + response = socket_http_answer (s, code, rlen, redirections); } else { eprintf ("Cannot connect to %s:%s\n", host, port); response = NULL; @@ -155,9 +265,14 @@ R_API char *r_socket_http_get(const char *url, int *code, int *rlen) { free (uri); r_socket_free (s); return response; +#endif +} + +R_API char *r_socket_http_get(const char *url, int *code, int *rlen) { + return socket_http_get_recursive (url, code, rlen, SOCKET_HTTP_MAX_REDIRECTS); } -R_API char *r_socket_http_post (const char *url, const char *data, int *code, int *rlen) { +R_API char *r_socket_http_post(const char *url, const char *data, int *code, int *rlen) { RSocket *s; bool ssl = r_str_startswith (url, "https://"); char *uri = strdup (url); @@ -206,7 +321,7 @@ R_API char *r_socket_http_post (const char *url, const char *data, int *code, in "\r\n", path, host, (int)strlen (data)); free (uri); r_socket_write (s, (void *)data, strlen (data)); - return r_socket_http_answer (s, code, rlen); + return socket_http_answer (s, code, rlen, 0); } #if TEST diff --git a/libr/util/str.c b/libr/util/str.c index 3956255f590f9..ba18d9b0fb824 100644 --- a/libr/util/str.c +++ b/libr/util/str.c @@ -1351,6 +1351,34 @@ R_API char *r_str_escape(const char *buf) { return r_str_escape_ (buf, false, true, true, false, true); } +// Return MUST BE surrounded by double-quotes +R_API char *r_str_escape_sh(const char *buf) { + r_return_val_if_fail (buf, NULL); + char *new_buf = malloc (1 + strlen (buf) * 2); + if (!new_buf) { + return NULL; + } + const char *p = buf; + char *q = new_buf; + while (*p) { + switch (*p) { +#if __UNIX__ + case '$': + case '`': +#endif + case '\\': + case '"': + *q++ = '\\'; + /* FALLTHRU */ + default: + *q++ = *p++; + break; + } + } + *q = '\0'; + return new_buf; +} + R_API char *r_str_escape_dot(const char *buf) { return r_str_escape_ (buf, true, true, true, false, true); } diff --git a/libr/util/sys.c b/libr/util/sys.c index 4326a7536aa3d..e259d409271bb 100644 --- a/libr/util/sys.c +++ b/libr/util/sys.c @@ -660,6 +660,7 @@ R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, } // we should handle broken pipes somehow better r_sys_signal (SIGPIPE, SIG_IGN); + size_t err_len = 0, out_len = 0; for (;;) { fd_set rfds, wfds; int nfd; @@ -680,20 +681,29 @@ R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, break; } if (output && FD_ISSET (sh_out[0], &rfds)) { - if (!(bytes = read (sh_out[0], buffer, sizeof (buffer)-1))) { + if ((bytes = read (sh_out[0], buffer, sizeof (buffer))) < 1) { break; } - buffer[sizeof (buffer) - 1] = '\0'; - if (len) { - *len += bytes; + char *tmp = realloc (outputptr, out_len + bytes + 1); + if (!tmp) { + R_FREE (outputptr); + break; } - outputptr = r_str_append (outputptr, buffer); + outputptr = tmp; + memcpy (outputptr + out_len, buffer, bytes); + out_len += bytes; } else if (FD_ISSET (sh_err[0], &rfds) && sterr) { - if (!read (sh_err[0], buffer, sizeof (buffer)-1)) { + if ((bytes = read (sh_err[0], buffer, sizeof (buffer))) < 1) { + break; + } + char *tmp = realloc (*sterr, err_len + bytes + 1); + if (!tmp) { + R_FREE (*sterr); break; } - buffer[sizeof (buffer) - 1] = '\0'; - *sterr = r_str_append (*sterr, buffer); + *sterr = tmp; + memcpy (*sterr + err_len, buffer, bytes); + err_len += bytes; } else if (FD_ISSET (sh_in[1], &wfds) && inputptr && *inputptr) { int inputptr_len = strlen (inputptr); bytes = write (sh_in[1], inputptr, inputptr_len); @@ -727,6 +737,15 @@ R_API int r_sys_cmd_str_full(const char *cmd, const char *input, char **output, ret = false; } + if (len) { + *len = out_len; + } + if (*sterr) { + (*sterr)[err_len] = 0; + } + if (outputptr) { + outputptr[out_len] = 0; + } if (output) { *output = outputptr; } else { @@ -829,7 +848,7 @@ R_API bool r_sys_mkdirp(const char *dir) { { char *p = strstr (ptr, ":\\"); if (p) { - ptr = p + 2; + ptr = p + 3; } } #endif diff --git a/meson.build b/meson.build index 5c3025e1cf894..498ecbc64dd71 100644 --- a/meson.build +++ b/meson.build @@ -112,7 +112,7 @@ endif platform_deps = [] platform_inc = ['.', 'libr/include'] if host_machine.system() == 'windows' - platform_deps = [cc.find_library('ws2_32'), cc.find_library('psapi')] + platform_deps = [cc.find_library('ws2_32'), cc.find_library('wininet'), cc.find_library('psapi')] endif platform_inc = include_directories(platform_inc) diff --git a/shlr/sdb/src/disk.c b/shlr/sdb/src/disk.c index 9b9d7d0afa857..edba1eff11e69 100644 --- a/shlr/sdb/src/disk.c +++ b/shlr/sdb/src/disk.c @@ -64,7 +64,7 @@ static inline int r_sys_mkdirp(char *dir) { #if __SDB_WINDOWS__ char *p = strstr (ptr, ":\\"); if (p) { - ptr = p + 2; + ptr = p + 3; } #endif while ((ptr = strchr (ptr, slash))) { diff --git a/test/db/formats/pdb b/test/db/formats/pdb index d230b81992aa9..d59431b811e23 100644 --- a/test/db/formats/pdb +++ b/test/db/formats/pdb @@ -1,6 +1,9 @@ NAME=PDB downloader check FILE=bins/pdb/user32.dll -CMDS=!!rabin2 -PP ${R2_FILE} ~PDB +CMDS=<