diff options
author | Brad King <brad.king@kitware.com> | 2017-05-11 14:55:44 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2017-05-11 15:27:21 (GMT) |
commit | 299975908ada992800791fac7f3739050e0ae2a9 (patch) | |
tree | 38cd8fb04ce84196dfa04d514eb92649900a1bc5 /Utilities/cmcurl/lib | |
parent | 5af9c8e2451afd8e63d6b05e69cd141af543a164 (diff) | |
parent | fd7d521c9d70655618db8232d45e5aaf81700f91 (diff) | |
download | CMake-299975908ada992800791fac7f3739050e0ae2a9.zip CMake-299975908ada992800791fac7f3739050e0ae2a9.tar.gz CMake-299975908ada992800791fac7f3739050e0ae2a9.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2017-04-19 (d957e218)
Resolve conflicts in `CMakeLists.txt` in favor of the upstream version.
We will re-apply our logic as needed in following commits.
Diffstat (limited to 'Utilities/cmcurl/lib')
102 files changed, 2901 insertions, 2094 deletions
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c index c038c2a..281fb03 100644 --- a/Utilities/cmcurl/lib/asyn-ares.c +++ b/Utilities/cmcurl/lib/asyn-ares.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -358,12 +358,20 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct timeval now = Curl_tvnow(); struct Curl_dns_entry *temp_entry; + if(entry) + *entry = NULL; /* clear on entry */ + timeout = Curl_timeleft(data, &now, TRUE); + if(timeout < 0) { + /* already expired! */ + connclose(conn, "Timed out before name resolve started"); + return CURLE_OPERATION_TIMEDOUT; + } if(!timeout) timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */ /* Wait for the name resolve query to complete. */ - for(;;) { + while(!result) { struct timeval *tvp, tv, store; long timediff; int itimeout; @@ -385,28 +393,25 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, timeout_ms = 1000; waitperform(conn, timeout_ms); - Curl_resolver_is_resolved(conn, &temp_entry); + result = Curl_resolver_is_resolved(conn, &temp_entry); - if(conn->async.done) + if(result || conn->async.done) break; - if(Curl_pgrsUpdate(conn)) { + if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; - timeout = -1; /* trigger the cancel below */ - } else { struct timeval now2 = Curl_tvnow(); timediff = Curl_tvdiff(now2, now); /* spent time */ timeout -= timediff?timediff:1; /* always deduct at least 1 */ now = now2; /* for next loop */ } - - if(timeout < 0) { - /* our timeout, so we cancel the ares operation */ - ares_cancel((ares_channel)data->state.resolver); - break; - } + if(timeout < 0) + result = CURLE_OPERATION_TIMEDOUT; } + if(result) + /* failure, so we cancel the ares operation */ + ares_cancel((ares_channel)data->state.resolver); /* Operation complete, if the lookup was successful we now have the entry in the cache. */ diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c index d8ef9a5..0590ec6 100644 --- a/Utilities/cmcurl/lib/conncache.c +++ b/Utilities/cmcurl/lib/conncache.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012, 2016, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se> + * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,11 +56,7 @@ static CURLcode bundle_create(struct Curl_easy *data, (*cb_ptr)->num_connections = 0; (*cb_ptr)->multiuse = BUNDLE_UNKNOWN; - (*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor); - if(!(*cb_ptr)->conn_list) { - Curl_safefree(*cb_ptr); - return CURLE_OUT_OF_MEMORY; - } + Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor); return CURLE_OK; } @@ -69,10 +65,8 @@ static void bundle_destroy(struct connectbundle *cb_ptr) if(!cb_ptr) return; - if(cb_ptr->conn_list) { - Curl_llist_destroy(cb_ptr->conn_list, NULL); - cb_ptr->conn_list = NULL; - } + Curl_llist_destroy(&cb_ptr->conn_list, NULL); + free(cb_ptr); } @@ -80,7 +74,7 @@ static void bundle_destroy(struct connectbundle *cb_ptr) static CURLcode bundle_add_conn(struct connectbundle *cb_ptr, struct connectdata *conn) { - if(!Curl_llist_insert_next(cb_ptr->conn_list, cb_ptr->conn_list->tail, conn)) + if(!Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn)) return CURLE_OUT_OF_MEMORY; conn->bundle = cb_ptr; @@ -95,10 +89,10 @@ static int bundle_remove_conn(struct connectbundle *cb_ptr, { struct curl_llist_element *curr; - curr = cb_ptr->conn_list->head; + curr = cb_ptr->conn_list.head; while(curr) { if(curr->ptr == conn) { - Curl_llist_remove(cb_ptr->conn_list, curr, NULL); + Curl_llist_remove(&cb_ptr->conn_list, curr, NULL); cb_ptr->num_connections--; conn->bundle = NULL; return 1; /* we removed a handle */ @@ -127,8 +121,9 @@ void Curl_conncache_destroy(struct conncache *connc) Curl_hash_destroy(&connc->hash); } -/* returns an allocated key to find a bundle for this connection */ -static char *hashkey(struct connectdata *conn) +/* creates a key to find a bundle for this connection */ +static void hashkey(struct connectdata *conn, char *buf, + size_t len) /* something like 128 is fine */ { const char *hostname; @@ -141,7 +136,10 @@ static char *hashkey(struct connectdata *conn) else hostname = conn->host.name; - return aprintf("%s:%d", hostname, conn->port); + DEBUGASSERT(len > 32); + + /* put the number first so that the hostname gets cut off if too long */ + snprintf(buf, len, "%ld%s", conn->port, hostname); } /* Look up the bundle with all the connections to the same host this @@ -151,11 +149,9 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn, { struct connectbundle *bundle = NULL; if(connc) { - char *key = hashkey(conn); - if(key) { - bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); - free(key); - } + char key[128]; + hashkey(conn, key, sizeof(key)); + bundle = Curl_hash_pick(&connc->hash, key, strlen(key)); } return bundle; @@ -204,21 +200,16 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); if(!bundle) { - char *key; int rc; + char key[128]; result = bundle_create(data, &new_bundle); if(result) return result; - key = hashkey(conn); - if(!key) { - bundle_destroy(new_bundle); - return CURLE_OUT_OF_MEMORY; - } - + hashkey(conn, key, sizeof(key)); rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle); - free(key); + if(!rc) { bundle_destroy(new_bundle); return CURLE_OUT_OF_MEMORY; @@ -292,7 +283,7 @@ void Curl_conncache_foreach(struct conncache *connc, bundle = he->ptr; he = Curl_hash_next_element(&iter); - curr = bundle->conn_list->head; + curr = bundle->conn_list.head; while(curr) { /* Yes, we need to update curr before calling func(), because func() might decide to remove the connection */ @@ -321,7 +312,7 @@ Curl_conncache_find_first_connection(struct conncache *connc) struct curl_llist_element *curr; bundle = he->ptr; - curr = bundle->conn_list->head; + curr = bundle->conn_list.head; if(curr) { return curr->ptr; } diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h index b1dadf9..f976cfd 100644 --- a/Utilities/cmcurl/lib/conncache.h +++ b/Utilities/cmcurl/lib/conncache.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se> * * This software is licensed as described in the file COPYING, which @@ -38,7 +38,7 @@ struct conncache { struct connectbundle { int multiuse; /* supports multi-use */ size_t num_connections; /* Number of connections in the bundle */ - struct curl_llist *conn_list; /* The connectdata members of the bundle */ + struct curl_llist conn_list; /* The connectdata members of the bundle */ }; int Curl_conncache_init(struct conncache *, int size); diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index 524d885..63ec50f 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -810,8 +810,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, return CURLE_OK; } - else - infof(data, "Connection failed\n"); + infof(data, "Connection failed\n"); } else if(rc & CURL_CSELECT_ERR) (void)verifyconnect(conn->tempsock[i], &error); @@ -1386,7 +1385,7 @@ CURLcode Curl_socket(struct connectdata *conn, */ void Curl_conncontrol(struct connectdata *conn, int ctrl /* see defines in header */ -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) , const char *reason #endif ) diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h index 5653cb4..44bdb10 100644 --- a/Utilities/cmcurl/lib/connect.h +++ b/Utilities/cmcurl/lib/connect.h @@ -127,16 +127,16 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); void Curl_conncontrol(struct connectdata *conn, int closeit -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) , const char *reason #endif ); -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) #define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) #define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) -#else /* if !CURLDEBUG */ +#else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */ #define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) #define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) #define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c index 5385058..652ed97 100644 --- a/Utilities/cmcurl/lib/content_encoding.c +++ b/Utilities/cmcurl/lib/content_encoding.c @@ -130,8 +130,7 @@ inflate_stream(struct connectdata *conn, free(decomp); if(inflateEnd(z) == Z_OK) return exit_zlib(z, &k->zlib_init, result); - else - return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); + return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z)); } /* Done with these bytes, exit */ @@ -314,7 +313,7 @@ Curl_unencode_gzip_write(struct connectdata *conn, #ifndef OLD_ZLIB_SUPPORT /* Support for old zlib versions is compiled away and we are running with an old version, so return an error. */ - return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND); + return exit_zlib(z, &k->zlib_init, CURLE_WRITE_ERROR); #else /* This next mess is to get around the potential case where there isn't diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index 092a226..6b678ae 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -492,7 +492,6 @@ Curl_cookie_add(struct Curl_easy *data, } else if(strcasecompare("domain", name)) { bool is_ip; - const char *dotp; /* Now, we make sure that our host is within the given domain, or the given domain is not valid and thus cannot be set. */ @@ -500,12 +499,22 @@ Curl_cookie_add(struct Curl_easy *data, if('.' == whatptr[0]) whatptr++; /* ignore preceding dot */ - is_ip = isip(domain ? domain : whatptr); +#ifndef USE_LIBPSL + /* + * Without PSL we don't know when the incoming cookie is set on a + * TLD or otherwise "protected" suffix. To reduce risk, we require a + * dot OR the exact host name being "localhost". + */ + { + const char *dotp; + /* check for more dots */ + dotp = strchr(whatptr, '.'); + if(!dotp && !strcasecompare("localhost", whatptr)) + domain=":"; + } +#endif - /* check for more dots */ - dotp = strchr(whatptr, '.'); - if(!dotp) - domain=":"; + is_ip = isip(domain ? domain : whatptr); if(!domain || (is_ip && !strcmp(whatptr, domain)) @@ -920,9 +929,8 @@ static char *get_line(char *buf, int len, FILE *input) } return b; } - else - /* read a partial, discard the next piece that ends with newline */ - partial = TRUE; + /* read a partial, discard the next piece that ends with newline */ + partial = TRUE; } else break; @@ -1055,16 +1063,16 @@ static int cookie_sort(const void *p1, const void *p2) #define CLONE(field) \ do { \ if(src->field) { \ - dup->field = strdup(src->field); \ - if(!dup->field) \ + d->field = strdup(src->field); \ + if(!d->field) \ goto fail; \ } \ } while(0) static struct Cookie *dup_cookie(struct Cookie *src) { - struct Cookie *dup = calloc(sizeof(struct Cookie), 1); - if(dup) { + struct Cookie *d = calloc(sizeof(struct Cookie), 1); + if(d) { CLONE(expirestr); CLONE(domain); CLONE(path); @@ -1073,16 +1081,16 @@ static struct Cookie *dup_cookie(struct Cookie *src) CLONE(value); CLONE(maxage); CLONE(version); - dup->expires = src->expires; - dup->tailmatch = src->tailmatch; - dup->secure = src->secure; - dup->livecookie = src->livecookie; - dup->httponly = src->httponly; + d->expires = src->expires; + d->tailmatch = src->tailmatch; + d->secure = src->secure; + d->livecookie = src->livecookie; + d->httponly = src->httponly; } - return dup; + return d; fail: - freecookie(dup); + freecookie(d); return NULL; } diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c index 61cdadd..1adf319 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.c +++ b/Utilities/cmcurl/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,6 +47,8 @@ # define in_addr_t unsigned long #endif +#include <stddef.h> + #include "curl_addrinfo.h" #include "inet_pton.h" #include "warnless.h" @@ -467,7 +469,7 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) /* This is a dotted IP address 123.123.123.123-style */ return Curl_ip2addr(AF_INET, &in, address, port); #ifdef ENABLE_IPV6 - else { + { struct in6_addr in6; if(Curl_inet_pton(AF_INET6, address, &in6) > 0) /* This is a dotted IPv6 address ::1-style */ @@ -483,24 +485,29 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) * struct initialized with this path. * Set '*longpath' to TRUE if the error is a too long path. */ -Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath) +Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) { Curl_addrinfo *ai; struct sockaddr_un *sa_un; size_t path_len; + *longpath = FALSE; + ai = calloc(1, sizeof(Curl_addrinfo)); if(!ai) return NULL; ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); if(!ai->ai_addr) { free(ai); - *longpath = FALSE; return NULL; } + + sa_un = (void *) ai->ai_addr; + sa_un->sun_family = AF_UNIX; + /* sun_path must be able to store the NUL-terminated path */ - path_len = strlen(path); - if(path_len >= sizeof(sa_un->sun_path)) { + path_len = strlen(path) + 1; + if(path_len > sizeof(sa_un->sun_path)) { free(ai->ai_addr); free(ai); *longpath = TRUE; @@ -509,10 +516,15 @@ Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath) ai->ai_family = AF_UNIX; ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ - ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); - sa_un = (void *) ai->ai_addr; - sa_un->sun_family = AF_UNIX; - memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */ + ai->ai_addrlen = (curl_socklen_t) + ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF); + + /* Abstract Unix domain socket have NULL prefix instead of suffix */ + if(abstract) + memcpy(sa_un->sun_path + 1, path, path_len - 1); + else + memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */ + return ai; } #endif diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h index 4f24730..8f6f3d1 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.h +++ b/Utilities/cmcurl/lib/curl_addrinfo.h @@ -80,7 +80,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_addrinfo *Curl_str2addr(char *dotted, int port); #ifdef USE_UNIX_SOCKETS -Curl_addrinfo *Curl_unix2addr(const char *path, int *longpath); +Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract); #endif #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake index 13f69b2..f9d54b4 100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@ -512,6 +512,15 @@ /* Define to 1 if you have the send function. */ #cmakedefine HAVE_SEND 1 +/* Define to 1 if you have the 'fsetxattr' function. */ +#cmakedefine HAVE_FSETXATTR 1 + +/* fsetxattr() takes 5 args */ +#cmakedefine HAVE_FSETXATTR_5 1 + +/* fsetxattr() takes 6 args */ +#cmakedefine HAVE_FSETXATTR_6 1 + /* Define to 1 if you have the <setjmp.h> header file. */ #cmakedefine HAVE_SETJMP_H 1 @@ -912,6 +921,9 @@ /* if PolarSSL is enabled */ #cmakedefine USE_POLARSSL 1 +/* if DarwinSSL is enabled */ +#cmakedefine USE_DARWINSSL 1 + /* if mbedTLS is enabled */ #cmakedefine USE_MBEDTLS 1 diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c index 421c9f7..b123a00 100644 --- a/Utilities/cmcurl/lib/curl_des.c +++ b/Utilities/cmcurl/lib/curl_des.c @@ -34,7 +34,7 @@ * * The function is a port of the Java based oddParity() function over at: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * * Parameters: * diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c index e8108bb..46d3ada 100644 --- a/Utilities/cmcurl/lib/curl_fnmatch.c +++ b/Utilities/cmcurl/lib/curl_fnmatch.c @@ -145,8 +145,7 @@ static int setcharset(unsigned char **p, unsigned char *charset) else if(c == ']') { if(something_found) return SETCHARSET_OK; - else - something_found = TRUE; + something_found = TRUE; state = CURLFNM_SCHS_RIGHTBR; charset[c] = 1; (*p)++; @@ -244,7 +243,7 @@ static int setcharset(unsigned char **p, unsigned char *charset) if(c == ']') { return SETCHARSET_OK; } - else if(c == '\\') { + if(c == '\\') { c = *(++(*p)); if(ISPRINT(c)) { charset[c] = 1; @@ -345,8 +344,7 @@ static int loop(const unsigned char *pattern, const unsigned char *string) else if(*p == '\0') { if(*s == '\0') return CURL_FNMATCH_MATCH; - else - return CURL_FNMATCH_NOMATCH; + return CURL_FNMATCH_NOMATCH; } else if(*p == '\\') { state = CURLFNM_LOOP_BACKSLASH; diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h index 6f792ff..fccf468 100644 --- a/Utilities/cmcurl/lib/curl_memory.h +++ b/Utilities/cmcurl/lib/curl_memory.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -70,7 +70,7 @@ * * Programs and libraries in 'tests' subdirectories have specific * purposes and needs, and as such each one will use whatever fits - * best, depending additionally wether it links with libcurl or not. + * best, depending additionally whether it links with libcurl or not. * * Caveat emptor. Proper curlx_* separation is a work in progress * the same as CURLX_NO_MEMORY_CALLBACKS usage, some adjustments may diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c index 73d983c..fb43dda 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.c +++ b/Utilities/cmcurl/lib/curl_ntlm_core.c @@ -27,7 +27,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -501,7 +501,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, return CURLE_OK; } -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES static void ascii_to_unicode_le(unsigned char *dest, const char *src, size_t srclen) { @@ -512,7 +512,7 @@ static void ascii_to_unicode_le(unsigned char *dest, const char *src, } } -#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) +#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) static void ascii_uppercase_to_unicode_le(unsigned char *dest, const char *src, size_t srclen) @@ -597,7 +597,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, return CURLE_OK; } -#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) +#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) /* This returns the HMAC MD5 digest */ CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, @@ -715,8 +715,10 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, /* Create the BLOB structure */ snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, - NTLMv2_BLOB_SIGNATURE + "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ "%c%c%c%c", /* Reserved = 0 */ + NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], + NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], 0, 0, 0, 0); Curl_write64_le(tw, ptr + 24); diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h index c5f90e7..4a83d40 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.h +++ b/Utilities/cmcurl/lib/curl_ntlm_core.h @@ -33,31 +33,26 @@ !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H) # error "curl_ntlm_core.h shall not be included before OpenSSL headers." # endif -# ifdef OPENSSL_NO_MD4 -# define USE_NTRESPONSES 0 -# define USE_NTLM2SESSION 0 -# define USE_NTLM_V2 0 -# endif #endif -/* Define USE_NTRESPONSES to 1 in order to make the type-3 message include +/* Define USE_NTRESPONSES in order to make the type-3 message include * the NT response message. */ -#ifndef USE_NTRESPONSES -#define USE_NTRESPONSES 1 +#if !defined(USE_OPENSSL) || !defined(OPENSSL_NO_MD4) +#define USE_NTRESPONSES #endif -/* Define USE_NTLM2SESSION to 1 in order to make the type-3 message include the +/* Define USE_NTLM2SESSION in order to make the type-3 message include the NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a Crypto engine that we have curl_ssl_md5sum() for. */ -#if !defined(USE_NTLM2SESSION) && USE_NTRESPONSES && !defined(USE_WIN32_CRYPTO) -#define USE_NTLM2SESSION 1 +#if defined(USE_NTRESPONSES) && !defined(USE_WIN32_CRYPTO) +#define USE_NTLM2SESSION #endif -/* Define USE_NTLM_V2 to 1 in order to allow the type-3 message to include the +/* Define USE_NTLM_V2 in order to allow the type-3 message to include the LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 and support for 64-bit integers. */ -#if !defined(USE_NTLM_V2) && USE_NTRESPONSES && (CURL_SIZEOF_CURL_OFF_T > 4) -#define USE_NTLM_V2 1 +#if defined(USE_NTRESPONSES) && (CURL_SIZEOF_CURL_OFF_T > 4) +#define USE_NTLM_V2 #endif void Curl_ntlm_core_lm_resp(const unsigned char *keys, @@ -68,12 +63,12 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */); -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */); -#if USE_NTLM_V2 && !defined(USE_WINDOWS_SSPI) +#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI) CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, const unsigned char *data, unsigned int datalen, diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c index 6a90e62..9f5b87b 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_wb.c +++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c @@ -28,7 +28,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c index 807f5de..b3789da 100644 --- a/Utilities/cmcurl/lib/curl_sasl.c +++ b/Utilities/cmcurl/lib/curl_sasl.c @@ -50,7 +50,7 @@ #include "memdebug.h" /* Supported mechanisms */ -const struct { +static const struct { const char *name; /* Name */ size_t len; /* Name length */ unsigned int bit; /* Flag bit */ diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index c861e97..6ab18cd 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -128,18 +128,7 @@ /* please, do it beyond the point further indicated in this file. */ /* ================================================================ */ -/* - * libcurl's external interface definitions are also used internally, - * and might also include required system header files to define them. - */ - -#include <curl/curlbuild.h> - -/* - * Compile time sanity checks must also be done when building the library. - */ - -#include <curl/curlrules.h> +#include <curl/curl.h> /* * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c index 69defc4..451ec38 100644 --- a/Utilities/cmcurl/lib/dict.c +++ b/Utilities/cmcurl/lib/dict.c @@ -92,7 +92,7 @@ const struct Curl_handler Curl_handler_dict = { static char *unescape_word(struct Curl_easy *data, const char *inputbuff) { - char *newp; + char *newp = NULL; char *dictp; char *ptr; size_t len; diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index 1242369..2b5f972 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -179,7 +179,7 @@ curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; #endif #else /* - * Symbian OS doesn't support initialization to code in writeable static data. + * Symbian OS doesn't support initialization to code in writable static data. * Initialization will occur in the curl_global_init() call. */ curl_malloc_callback Curl_cmalloc; @@ -619,7 +619,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) /* If nothing updated the timeout, we decrease it by the spent time. * If it was updated, it has the new timeout time stored already. */ - ev->ms += curlx_tvdiff(after, before); + ev->ms += (long)curlx_tvdiff(after, before); } else @@ -773,8 +773,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) curl_multi_cleanup(multi); if(mcode == CURLM_OUT_OF_MEMORY) return CURLE_OUT_OF_MEMORY; - else - return CURLE_FAILED_INIT; + return CURLE_FAILED_INIT; } sigpipe_ignore(data, &pipe_st); @@ -870,6 +869,11 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) * get setup on-demand in the code, as that would probably decrease * the likeliness of us forgetting to init a buffer here in the future. */ + outcurl->set.buffer_size = data->set.buffer_size; + outcurl->state.buffer = malloc(CURL_BUFSIZE(outcurl->set.buffer_size) + 1); + if(!outcurl->state.buffer) + goto fail; + outcurl->state.headerbuff = malloc(HEADERSIZE); if(!outcurl->state.headerbuff) goto fail; @@ -940,6 +944,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) if(outcurl) { curl_slist_free_all(outcurl->change.cookielist); outcurl->change.cookielist = NULL; + Curl_safefree(outcurl->state.buffer); Curl_safefree(outcurl->state.headerbuff); Curl_safefree(outcurl->change.url); Curl_safefree(outcurl->change.referer); @@ -975,6 +980,10 @@ void curl_easy_reset(struct Curl_easy *data) data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ + + /* zero out authentication data: */ + memset(&data->state.authhost, 0, sizeof(struct auth)); + memset(&data->state.authproxy, 0, sizeof(struct auth)); } /* @@ -1002,19 +1011,32 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) /* put it back in the keepon */ k->keepon = newstate; - if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) { - /* we have a buffer for sending that we now seem to be able to deliver - since the receive pausing is lifted! */ - - /* get the pointer in local copy since the function may return PAUSE - again and then we'll get a new copy allocted and stored in - the tempwrite variables */ - char *tempwrite = data->state.tempwrite; - - data->state.tempwrite = NULL; - result = Curl_client_chop_write(data->easy_conn, data->state.tempwritetype, - tempwrite, data->state.tempwritesize); - free(tempwrite); + if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) { + /* there are buffers for sending that can be delivered as the receive + pausing is lifted! */ + unsigned int i; + unsigned int count = data->state.tempcount; + struct tempbuf writebuf[3]; /* there can only be three */ + + /* copy the structs to allow for immediate re-pausing */ + for(i=0; i < data->state.tempcount; i++) { + writebuf[i] = data->state.tempwrite[i]; + data->state.tempwrite[i].buf = NULL; + } + data->state.tempcount = 0; + + for(i=0; i < count; i++) { + /* even if one function returns error, this loops through and frees all + buffers */ + if(!result) + result = Curl_client_chop_write(data->easy_conn, + writebuf[i].type, + writebuf[i].buf, + writebuf[i].len); + free(writebuf[i].buf); + } + if(result) + return result; } /* if there's no error and we're not pausing both directions, we want diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c index 9c811b8..973aeb6 100644 --- a/Utilities/cmcurl/lib/escape.c +++ b/Utilities/cmcurl/lib/escape.c @@ -113,9 +113,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, testing_ptr = Curl_saferealloc(ns, alloc); if(!testing_ptr) return NULL; - else { - ns = testing_ptr; - } + ns = testing_ptr; } result = Curl_convert_to_network(data, &in, 1); diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c index 3dbc0f2..b26bdea 100644 --- a/Utilities/cmcurl/lib/file.c +++ b/Utilities/cmcurl/lib/file.c @@ -355,8 +355,7 @@ static CURLcode file_upload(struct connectdata *conn) failf(data, "Can't get the size of %s", file->path); return CURLE_WRITE_ERROR; } - else - data->state.resume_from = (curl_off_t)file_stat.st_size; + data->state.resume_from = (curl_off_t)file_stat.st_size; } while(!result) { @@ -476,7 +475,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) time_t filetime; struct tm buffer; const struct tm *tm = &buffer; - snprintf(buf, sizeof(data->state.buffer), + snprintf(buf, CURL_BUFSIZE(data->set.buffer_size), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); if(result) @@ -519,8 +518,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) failf(data, "Can't get the size of file."); return CURLE_READ_ERROR; } - else - data->state.resume_from += (curl_off_t)statbuf.st_size; + data->state.resume_from += (curl_off_t)statbuf.st_size; } if(data->state.resume_from <= expected_size) diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c index abd2da0..2a93434 100644 --- a/Utilities/cmcurl/lib/formdata.c +++ b/Utilities/cmcurl/lib/formdata.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -342,6 +342,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, #else current_form->flags |= HTTPPOST_PTRNAME; /* fall through */ #endif + /* FALLTHROUGH */ case CURLFORM_COPYNAME: if(current_form->name) return_value = CURL_FORMADD_OPTION_TWICE; @@ -629,70 +630,68 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, return_value = CURL_FORMADD_INCOMPLETE; break; } - else { - if(((form->flags & HTTPPOST_FILENAME) || - (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype) { - char *f = form->flags & HTTPPOST_BUFFER? - form->showfilename : form->value; - - /* our contenttype is missing */ - form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); - if(!form->contenttype) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->contenttype_alloc = TRUE; + if(((form->flags & HTTPPOST_FILENAME) || + (form->flags & HTTPPOST_BUFFER)) && + !form->contenttype) { + char *f = form->flags & HTTPPOST_BUFFER? + form->showfilename : form->value; + + /* our contenttype is missing */ + form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); + if(!form->contenttype) { + return_value = CURL_FORMADD_MEMORY; + break; } - if(!(form->flags & HTTPPOST_PTRNAME) && - (form == first_form) ) { - /* Note that there's small risk that form->name is NULL here if the - app passed in a bad combo, so we better check for that first. */ - if(form->name) { - /* copy name (without strdup; possibly contains null characters) */ - form->name = Curl_memdup(form->name, form->namelength? - form->namelength: - strlen(form->name)+1); - } - if(!form->name) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->name_alloc = TRUE; + form->contenttype_alloc = TRUE; + } + if(!(form->flags & HTTPPOST_PTRNAME) && + (form == first_form) ) { + /* Note that there's small risk that form->name is NULL here if the + app passed in a bad combo, so we better check for that first. */ + if(form->name) { + /* copy name (without strdup; possibly contains null characters) */ + form->name = Curl_memdup(form->name, form->namelength? + form->namelength: + strlen(form->name)+1); } - if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | - HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | - HTTPPOST_CALLBACK)) && form->value) { - /* copy value (without strdup; possibly contains null characters) */ - size_t clen = (size_t) form->contentslength; - if(!clen) - clen = strlen(form->value)+1; + if(!form->name) { + return_value = CURL_FORMADD_MEMORY; + break; + } + form->name_alloc = TRUE; + } + if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE | + HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER | + HTTPPOST_CALLBACK)) && form->value) { + /* copy value (without strdup; possibly contains null characters) */ + size_t clen = (size_t) form->contentslength; + if(!clen) + clen = strlen(form->value)+1; - form->value = Curl_memdup(form->value, clen); + form->value = Curl_memdup(form->value, clen); - if(!form->value) { - return_value = CURL_FORMADD_MEMORY; - break; - } - form->value_alloc = TRUE; - } - post = AddHttpPost(form->name, form->namelength, - form->value, form->contentslength, - form->buffer, form->bufferlength, - form->contenttype, form->flags, - form->contentheader, form->showfilename, - form->userp, - post, httppost, - last_post); - - if(!post) { + if(!form->value) { return_value = CURL_FORMADD_MEMORY; break; } - - if(form->contenttype) - prevtype = form->contenttype; + form->value_alloc = TRUE; + } + post = AddHttpPost(form->name, form->namelength, + form->value, form->contentslength, + form->buffer, form->bufferlength, + form->contenttype, form->flags, + form->contentheader, form->showfilename, + form->userp, + post, httppost, + last_post); + + if(!post) { + return_value = CURL_FORMADD_MEMORY; + break; } + + if(form->contenttype) + prevtype = form->contenttype; } if(CURL_FORMADD_OK != return_value) { /* On error, free allocated fields for nodes of the FormInfo linked @@ -1332,7 +1331,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data, char buffer[512]; while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); - if(result) + if(result || feof(fileread) || ferror(fileread)) break; } } @@ -1462,8 +1461,7 @@ static size_t readfromfile(struct Form *form, char *buffer, if(callback) { if(form->fread_func == ZERO_NULL) return 0; - else - nread = form->fread_func(buffer, 1, size, form->data->line); + nread = form->fread_func(buffer, 1, size, form->data->line); } else { if(!form->fp) { @@ -1553,7 +1551,7 @@ char *Curl_formpostheader(void *formp, size_t *len) struct Form *form=(struct Form *)formp; if(!form->data) - return 0; /* nothing, ERROR! */ + return NULL; /* nothing, ERROR! */ header = form->data->line; *len = form->data->length; diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index 89c7e40..a5ca2ab 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -916,8 +916,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, return bits; } - else - return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); } /* This is called after the FTP_QUOTE state is passed. @@ -1209,7 +1208,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, possibly_non_local = FALSE; /* don't try this again */ continue; } - else if(error != EADDRINUSE && error != EACCES) { + if(error != EADDRINUSE && error != EACCES) { failf(data, "bind(port=%hu) failed: %s", port, Curl_strerror(conn, error) ); Curl_closesocket(conn, portsock); @@ -1307,7 +1306,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, } break; } - else if(PORT == fcmd) { + if(PORT == fcmd) { char *source = myhost; char *dest = tmp; @@ -1674,31 +1673,29 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, } if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed=0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - else { - curl_off_t passed=0; - do { - size_t readthisamountnow = - (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? - BUFSIZE : curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, - data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } + do { + size_t readthisamountnow = + (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? + BUFSIZE : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = + data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ if(data->state.infilesize>0) { @@ -1757,7 +1754,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, /* * This state uses: * 'count1' to iterate over the commands to send - * 'count2' to store wether to allow commands to fail + * 'count2' to store whether to allow commands to fail */ if(init) @@ -2000,7 +1997,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, if(!addr) { failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); - return CURLE_FTP_CANT_GET_HOST; + return CURLE_COULDNT_RESOLVE_PROXY; } } else { @@ -2040,11 +2037,14 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); + Curl_resolv_unlock(data, addr); /* we're done using this address */ + Curl_safefree(conn->secondaryhostname); - conn->secondaryhostname = strdup(ftpc->newhost); conn->secondary_port = ftpc->newport; + conn->secondaryhostname = strdup(ftpc->newhost); + if(!conn->secondaryhostname) + return CURLE_OUT_OF_MEMORY; - Curl_resolv_unlock(data, addr); /* we're done using this address */ conn->bits.do_more = TRUE; state(conn, FTP_STOP); /* this phase is completed */ @@ -2107,7 +2107,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, /* we have a time, reformat it */ time_t secs=time(NULL); /* using the good old yacc/bison yuck */ - snprintf(buf, sizeof(conn->data->state.buffer), + snprintf(buf, CURL_BUFSIZE(conn->data->set.buffer_size), "%04d%02d%02d %02d:%02d:%02d GMT", year, month, day, hour, minute, second); /* now, convert this into a time() value: */ @@ -2318,7 +2318,7 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, if(instate == FTP_SIZE) { #ifdef CURL_FTP_HTTPSTYLE_HEAD if(-1 != filesize) { - snprintf(buf, sizeof(data->state.buffer), + snprintf(buf, CURL_BUFSIZE(data->set.buffer_size), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); if(result) @@ -2409,8 +2409,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn, return CURLE_OK; } - else - return InitiateTransfer(conn); + return InitiateTransfer(conn); } /* for LIST and RETR responses */ @@ -2823,6 +2822,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PWD: if(ftpcode == 257) { char *ptr=&data->state.buffer[4]; /* start on the first letter */ + const size_t buf_size = CURL_BUFSIZE(data->set.buffer_size); char *dir; char *store; @@ -2840,7 +2840,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) */ /* scan for the first double-quote for non-standard responses */ - while(ptr < &data->state.buffer[sizeof(data->state.buffer)] + while(ptr < &data->state.buffer[buf_size] && *ptr != '\n' && *ptr != '\0' && *ptr != '"') ptr++; @@ -2870,7 +2870,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) does not start with a '/'), we probably need some server-dependent adjustments. For example, this is the case when connecting to an OS400 FTP server: this server supports two name syntaxes, - the default one being incompatible with standard pathes. In + the default one being incompatible with standard paths. In addition, this server switches automatically to the regular path syntax when one is encountered in a command: this results in having an entrypath in the wrong syntax when later used in CWD. @@ -2944,12 +2944,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) state(conn, FTP_NAMEFMT); break; } - else { - /* Nothing special for the target server. */ - /* remember target server OS */ - Curl_safefree(ftpc->server_os); - ftpc->server_os = os; - } + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; } else { /* Cannot identify server OS. Continue anyway and cross fingers. */ @@ -3210,6 +3208,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* until we cope better with prematurely ended requests, let them * fallback as if in complete failure */ + /* FALLTHROUGH */ default: /* by default, an error means the control connection is wedged and should not be used anymore */ ftpc->ctl_valid = FALSE; @@ -3553,7 +3552,7 @@ static CURLcode ftp_range(struct connectdata *conn) " to %" CURL_FORMAT_CURL_OFF_T ", totally %" CURL_FORMAT_CURL_OFF_T " bytes\n", from, to, data->req.maxdownload)); - ftpc->dont_check = TRUE; /* dont check for successful transfer */ + ftpc->dont_check = TRUE; /* don't check for successful transfer */ } else data->req.maxdownload = -1; @@ -3796,12 +3795,10 @@ static CURLcode init_wc_data(struct connectdata *conn) result = ftp_parse_url_path(conn); return result; } - else { - wildcard->pattern = strdup(last_slash); - if(!wildcard->pattern) - return CURLE_OUT_OF_MEMORY; - last_slash[0] = '\0'; /* cut file from path */ - } + wildcard->pattern = strdup(last_slash); + if(!wildcard->pattern) + return CURLE_OUT_OF_MEMORY; + last_slash[0] = '\0'; /* cut file from path */ } else { /* there is only 'wildcard pattern' or nothing */ if(path[0]) { @@ -3886,8 +3883,7 @@ static CURLcode wc_statemach(struct connectdata *conn) if(wildcard->state == CURLWC_CLEAN) /* only listing! */ break; - else - wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; + wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING; break; case CURLWC_MATCHING: { @@ -3905,7 +3901,7 @@ static CURLcode wc_statemach(struct connectdata *conn) wildcard->state = CURLWC_CLEAN; return wc_statemach(conn); } - else if(wildcard->filelist->size == 0) { + if(wildcard->filelist.size == 0) { /* no corresponding file */ wildcard->state = CURLWC_CLEAN; return CURLE_REMOTE_FILE_NOT_FOUND; @@ -3916,7 +3912,7 @@ static CURLcode wc_statemach(struct connectdata *conn) case CURLWC_DOWNLOADING: { /* filelist has at least one file, lets get first one */ struct ftp_conn *ftpc = &conn->proto.ftpc; - struct curl_fileinfo *finfo = wildcard->filelist->head->ptr; + struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); if(!tmp_path) @@ -3931,7 +3927,7 @@ static CURLcode wc_statemach(struct connectdata *conn) infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); if(conn->data->set.chunk_bgn) { long userresponse = conn->data->set.chunk_bgn( - finfo, wildcard->customptr, (int)wildcard->filelist->size); + finfo, wildcard->customptr, (int)wildcard->filelist.size); switch(userresponse) { case CURL_CHUNK_BGN_FUNC_SKIP: infof(conn->data, "Wildcard - \"%s\" skipped by user\n", @@ -3956,9 +3952,9 @@ static CURLcode wc_statemach(struct connectdata *conn) return result; /* we don't need the Curl_fileinfo of first file anymore */ - Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL); + Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); - if(wildcard->filelist->size == 0) { /* remains only one file to down. */ + if(wildcard->filelist.size == 0) { /* remains only one file to down. */ wildcard->state = CURLWC_CLEAN; /* after that will be ftp_do called once again and no transfer will be done because of CURLWC_CLEAN state */ @@ -3969,8 +3965,8 @@ static CURLcode wc_statemach(struct connectdata *conn) case CURLWC_SKIP: { if(conn->data->set.chunk_end) conn->data->set.chunk_end(conn->data->wildcard.customptr); - Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL); - wildcard->state = (wildcard->filelist->size == 0) ? + Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); + wildcard->state = (wildcard->filelist.size == 0) ? CURLWC_CLEAN : CURLWC_DOWNLOADING; return wc_statemach(conn); } @@ -3986,6 +3982,7 @@ static CURLcode wc_statemach(struct connectdata *conn) case CURLWC_DONE: case CURLWC_ERROR: + case CURLWC_CLEAR: break; } @@ -4283,7 +4280,6 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) &ftpc->dirs[ftpc->dirdepth], NULL, TRUE); if(result) { - free(ftpc->dirs[ftpc->dirdepth]); freedirs(ftpc); return result; } diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c index f94b31b..bc18680 100644 --- a/Utilities/cmcurl/lib/ftplistparser.c +++ b/Utilities/cmcurl/lib/ftplistparser.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -280,7 +280,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn, curl_fnmatch_callback compare; struct WildcardData *wc = &conn->data->wildcard; struct ftp_wc_tmpdata *tmpdata = wc->tmp; - struct curl_llist *llist = wc->filelist; + struct curl_llist *llist = &wc->filelist; struct ftp_parselist_data *parser = tmpdata->parser; bool add = TRUE; @@ -433,10 +433,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); return bufflen; } - else { - parser->state.UNIX.main = PL_UNIX_FILETYPE; - finfo->b_used = 0; - } + parser->state.UNIX.main = PL_UNIX_FILETYPE; + finfo->b_used = 0; } else { PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST); diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c index a073d0b..e6d2746 100644 --- a/Utilities/cmcurl/lib/gopher.c +++ b/Utilities/cmcurl/lib/gopher.c @@ -78,7 +78,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) curl_off_t *bytecount = &data->req.bytecount; char *path = data->state.path; - char *sel; + char *sel = NULL; char *sel_org = NULL; ssize_t amount, k; size_t len; @@ -106,8 +106,8 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) /* ... and finally unescape */ result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE); - if(!sel) - return CURLE_OUT_OF_MEMORY; + if(result) + return result; sel_org = sel; } diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c index 0655042..b7305a5 100644 --- a/Utilities/cmcurl/lib/hash.c +++ b/Utilities/cmcurl/lib/hash.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,8 +37,6 @@ hash_element_dtor(void *user, void *element) struct curl_hash *h = (struct curl_hash *) user; struct curl_hash_element *e = (struct curl_hash_element *) element; - Curl_safefree(e->key); - if(e->ptr) { h->dtor(e->ptr); e->ptr = NULL; @@ -74,54 +72,32 @@ Curl_hash_init(struct curl_hash *h, h->size = 0; h->slots = slots; - h->table = malloc(slots * sizeof(struct curl_llist *)); + h->table = malloc(slots * sizeof(struct curl_llist)); if(h->table) { - for(i = 0; i < slots; ++i) { - h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); - if(!h->table[i]) { - while(i--) { - Curl_llist_destroy(h->table[i], NULL); - h->table[i] = NULL; - } - free(h->table); - h->table = NULL; - h->slots = 0; - return 1; /* failure */ - } - } + for(i = 0; i < slots; ++i) + Curl_llist_init(&h->table[i], (curl_llist_dtor) hash_element_dtor); return 0; /* fine */ } - else { - h->slots = 0; - return 1; /* failure */ - } + h->slots = 0; + return 1; /* failure */ } static struct curl_hash_element * mk_hash_element(const void *key, size_t key_len, const void *p) { - struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element)); - + /* allocate the struct plus memory after it to store the key */ + struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element) + + key_len); if(he) { - void *dupkey = malloc(key_len); - if(dupkey) { - /* copy the key */ - memcpy(dupkey, key, key_len); - - he->key = dupkey; - he->key_len = key_len; - he->ptr = (void *) p; - } - else { - /* failed to duplicate the key, free memory and fail */ - free(he); - he = NULL; - } + /* copy the key */ + memcpy(he->key, key, key_len); + he->key_len = key_len; + he->ptr = (void *) p; } return he; } -#define FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)] +#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)] /* Insert the data in the hash. If there already was a match in the hash, * that data is replaced. @@ -158,7 +134,6 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) * "destructor" for the actual data 'p'. When we fail, we shall not touch * that data. */ - free(he->key); free(he); } @@ -243,8 +218,7 @@ Curl_hash_destroy(struct curl_hash *h) int i; for(i = 0; i < h->slots; ++i) { - Curl_llist_destroy(h->table[i], (void *) h); - h->table[i] = NULL; + Curl_llist_destroy(&h->table[i], (void *) h); } Curl_safefree(h->table); @@ -276,7 +250,7 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, return; for(i = 0; i < h->slots; ++i) { - list = h->table[i]; + list = &h->table[i]; le = list->head; /* get first list entry */ while(le) { struct curl_hash_element *he = le->ptr; @@ -335,8 +309,8 @@ Curl_hash_next_element(struct curl_hash_iterator *iter) /* If we have reached the end of the list, find the next one */ if(!iter->current_element) { for(i = iter->slot_index;i < h->slots;i++) { - if(h->table[i]->head) { - iter->current_element = h->table[i]->head; + if(h->table[i].head) { + iter->current_element = h->table[i].head; iter->slot_index = i+1; break; } @@ -347,10 +321,8 @@ Curl_hash_next_element(struct curl_hash_iterator *iter) struct curl_hash_element *he = iter->current_element->ptr; return he; } - else { - iter->current_element = NULL; - return NULL; - } + iter->current_element = NULL; + return NULL; } #if 0 /* useful function for debugging hashes and their contents */ diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h index a5a6cac..a345c8c 100644 --- a/Utilities/cmcurl/lib/hash.h +++ b/Utilities/cmcurl/lib/hash.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,7 +44,7 @@ typedef size_t (*comp_function) (void *key1, typedef void (*curl_hash_dtor)(void *); struct curl_hash { - struct curl_llist **table; + struct curl_llist *table; /* Hash function to be used for this hash table */ hash_function hash_func; @@ -58,8 +58,8 @@ struct curl_hash { struct curl_hash_element { void *ptr; - char *key; size_t key_len; + char key[1]; /* allocated memory following the struct */ }; struct curl_hash_iterator { diff --git a/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c index cbd0893..156091c 100644 --- a/Utilities/cmcurl/lib/hostcheck.c +++ b/Utilities/cmcurl/lib/hostcheck.c @@ -87,7 +87,7 @@ static int hostmatch(char *hostname, char *pattern) if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) return CURL_HOST_NOMATCH; #ifdef ENABLE_IPV6 - else if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) + if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0) return CURL_HOST_NOMATCH; #endif diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index fa4bad9..ed18763 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -143,7 +143,7 @@ void Curl_global_host_cache_dtor(void) } /* - * Return # of adresses in a Curl_addrinfo struct + * Return # of addresses in a Curl_addrinfo struct */ int Curl_num_addresses(const Curl_addrinfo *addr) { @@ -573,7 +573,7 @@ int Curl_resolv_timeout(struct connectdata *conn, #ifdef USE_ALARM_TIMEOUT #ifdef HAVE_SIGACTION struct sigaction keep_sigact; /* store the old struct here */ - volatile bool keep_copysig = FALSE; /* wether old sigact has been saved */ + volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */ struct sigaction sigact; #else #ifdef HAVE_SIGNAL diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h index 1dc4079..298eeeee 100644 --- a/Utilities/cmcurl/lib/hostip.h +++ b/Utilities/cmcurl/lib/hostip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -130,7 +130,7 @@ int Curl_mk_dnscache(struct curl_hash *hash); /* prune old entries from the DNS cache */ void Curl_hostcache_prune(struct Curl_easy *data); -/* Return # of adresses in a Curl_addrinfo struct */ +/* Return # of addresses in a Curl_addrinfo struct */ int Curl_num_addresses(const Curl_addrinfo *addr); #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index 4c1c07f..22d4547 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -297,7 +297,8 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) pwd = conn->passwd; } - snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); + snprintf(data->state.buffer, CURL_BUFSIZE(data->set.buffer_size), + "%s:%s", user, pwd); result = Curl_base64_encode(data, data->state.buffer, strlen(data->state.buffer), @@ -644,10 +645,10 @@ output_auth_headers(struct connectdata *conn, proxy ? "Proxy" : "Server", auth, proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : (conn->user ? conn->user : "")); - authstatus->multi = (!authstatus->done) ? TRUE : FALSE; + authstatus->multipass = (!authstatus->done) ? TRUE : FALSE; } else - authstatus->multi = FALSE; + authstatus->multipass = FALSE; return CURLE_OK; } @@ -1196,8 +1197,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, This needs FIXing. */ return CURLE_SEND_ERROR; - else - Curl_pipeline_leave_write(conn); + Curl_pipeline_leave_write(conn); } } Curl_add_buffer_free(in); @@ -1358,6 +1358,10 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) if(result) return result; + if(conn->bits.proxy_connect_closed) + /* this is not an error, just part of the connection negotiation */ + return CURLE_OK; + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ @@ -1365,7 +1369,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; - if(conn->given->flags & PROTOPT_SSL) { + if(conn->given->protocol & CURLPROTO_HTTPS) { /* perform SSL initialization */ result = https_connecting(conn, done); if(result) @@ -1425,7 +1429,10 @@ CURLcode Curl_http_done(struct connectdata *conn, struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; - infof(data, "Curl_http_done: called premature == %d\n", premature); + /* Clear multipass flag. If authentication isn't done yet, then it will get + * a chance to be set back to true when we output the next auth header */ + data->state.authhost.multipass = FALSE; + data->state.authproxy.multipass = FALSE; Curl_unencode_cleanup(conn); @@ -1511,6 +1518,20 @@ static bool use_http_1_1plus(const struct Curl_easy *data, (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); } +static const char *get_http_string(const struct Curl_easy *data, + const struct connectdata *conn) +{ +#ifdef USE_NGHTTP2 + if(conn->proto.httpc.h2) + return "2"; +#endif + + if(use_http_1_1plus(data, conn)) + return "1.1"; + + return "1.0"; +} + /* check and possibly add an Expect: header */ static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, @@ -1849,7 +1870,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(result) return result; - if((data->state.authhost.multi || data->state.authproxy.multi) && + if((data->state.authhost.multipass || data->state.authproxy.multipass) && (httpreq != HTTPREQ_GET) && (httpreq != HTTPREQ_HEAD)) { /* Auth is required and we are not authenticated yet. Make a PUT or POST @@ -2134,32 +2155,31 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed=0; + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_READ_ERROR; } /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - else { - curl_off_t passed=0; - do { - size_t readthisamountnow = - (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? - BUFSIZE : curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, readthisamountnow, - data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T - " bytes from the input", passed); - return CURLE_READ_ERROR; - } - } while(passed < data->state.resume_from); - } + do { + size_t readthisamountnow = + (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? + BUFSIZE : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = + data->state.fread_func(data->state.buffer, 1, readthisamountnow, + data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T + " bytes from the input", passed); + return CURLE_READ_ERROR; + } + } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ @@ -2225,9 +2245,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } - /* Use 1.1 unless the user specifically asked for 1.0 or the server only - supports 1.0 */ - httpstring= use_http_1_1plus(data, conn)?"1.1":"1.0"; + httpstring = get_http_string(data, conn); /* initialize a dynamic send-buffer */ req_buffer = Curl_add_buffer_init(); @@ -2294,20 +2312,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) te ); - /* clear userpwd to avoid re-using credentials from re-used connections */ + /* clear userpwd and proxyuserpwd to avoid re-using old credentials + * from re-used connections */ Curl_safefree(conn->allocptr.userpwd); - - /* - * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated - * with the connection and shouldn't be repeated over it either. - */ - switch(data->state.authproxy.picked) { - case CURLAUTH_NEGOTIATE: - case CURLAUTH_NTLM: - case CURLAUTH_NTLM_WB: - Curl_safefree(conn->allocptr.proxyuserpwd); - break; - } + Curl_safefree(conn->allocptr.proxyuserpwd); if(result) return result; @@ -2501,7 +2509,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = data->state.infilesize; if((postsize != -1) && !data->req.upload_chunky && - !Curl_checkheaders(conn, "Content-Length:")) { + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T @@ -2553,7 +2561,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) we don't upload data chunked, as RFC2616 forbids us to set both kinds of headers (Transfer-Encoding: chunked and Content-Length) */ if((postsize != -1) && !data->req.upload_chunky && - !Curl_checkheaders(conn, "Content-Length:")) { + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ result = Curl_add_bufferf(req_buffer, @@ -2807,8 +2815,7 @@ checkrtspprefix(struct Curl_easy *data, #endif /* CURL_DOES_CONVERSIONS */ if(checkprefix("RTSP/", s)) return TRUE; - else - return FALSE; + return FALSE; } #endif /* CURL_DISABLE_RTSP */ @@ -3229,9 +3236,17 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, k->maxdownload = k->size; } - /* If max download size is *zero* (nothing) we already - have nothing and can safely return ok now! */ - if(0 == k->maxdownload) + /* If max download size is *zero* (nothing) we already have + nothing and can safely return ok now! But for HTTP/2, we'd + like to call http2_handle_stream_close to properly close a + stream. In order to do this, we keep reading until we + close the stream. */ + if(0 == k->maxdownload +#if defined(USE_NGHTTP2) + && !((conn->handler->protocol & PROTO_FAMILY_HTTP) && + conn->httpversion == 20) +#endif + ) *stop_reading = TRUE; if(*stop_reading) { @@ -3288,7 +3303,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* * https://tools.ietf.org/html/rfc7230#section-3.1.2 * - * The reponse code is always a three-digit number in HTTP as the spec + * The response code is always a three-digit number in HTTP as the spec * says. We try to allow any number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h index 9fb669c..7ce4bd9 100644 --- a/Utilities/cmcurl/lib/http.h +++ b/Utilities/cmcurl/lib/http.h @@ -219,6 +219,10 @@ struct http_conn { /* this is a hash of all individual streams (Curl_easy structs) */ struct h2settings settings; + + /* list of settings that will be sent */ + nghttp2_settings_entry local_settings[3]; + size_t local_settings_num; #else int unused; /* prevent a compiler warning */ #endif diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index 4cc17ba..264c667 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -116,18 +116,11 @@ static int http2_getsock(struct connectdata *conn, return http2_perform_getsock(conn, sock, numsocks); } -static CURLcode http2_disconnect(struct connectdata *conn, - bool dead_connection) +/* + * http2_stream_free() free HTTP2 stream related data + */ +static void http2_stream_free(struct HTTP *http) { - struct HTTP *http = conn->data->req.protop; - struct http_conn *c = &conn->proto.httpc; - (void)dead_connection; - - DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); - - nghttp2_session_del(c->h2); - Curl_safefree(c->inbuf); - if(http) { Curl_add_buffer_free(http->header_recvbuf); http->header_recvbuf = NULL; /* clear the pointer */ @@ -139,6 +132,19 @@ static CURLcode http2_disconnect(struct connectdata *conn, free(http->push_headers); http->push_headers = NULL; } +} + +static CURLcode http2_disconnect(struct connectdata *conn, + bool dead_connection) +{ + struct http_conn *c = &conn->proto.httpc; + (void)dead_connection; + + DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); + + nghttp2_session_del(c->h2); + Curl_safefree(c->inbuf); + http2_stream_free(conn->data->req.protop); DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); @@ -402,6 +408,7 @@ static int push_promise(struct Curl_easy *data, stream = data->req.protop; if(!stream) { failf(data, "Internal NULL stream!\n"); + (void)Curl_close(newhandle); rv = 1; goto fail; } @@ -415,9 +422,11 @@ static int push_promise(struct Curl_easy *data, free(stream->push_headers[i]); free(stream->push_headers); stream->push_headers = NULL; + stream->push_headers_used = 0; if(rv) { /* denied, kill off the new handle again */ + http2_stream_free(newhandle->req.protop); (void)Curl_close(newhandle); goto fail; } @@ -432,6 +441,7 @@ static int push_promise(struct Curl_easy *data, rc = Curl_multi_add_perform(data->multi, newhandle, conn); if(rc) { infof(data, "failed to add handle to multi\n"); + http2_stream_free(newhandle->req.protop); Curl_close(newhandle); rv = 1; goto fail; @@ -587,6 +597,9 @@ static int on_invalid_frame_recv(nghttp2_session *session, { struct Curl_easy *data_s = NULL; (void)userp; +#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS) + (void)lib_error_code; +#endif data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); if(data_s) { @@ -697,6 +710,9 @@ static int on_frame_not_send(nghttp2_session *session, { struct Curl_easy *data_s; (void)userp; +#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS) + (void)lib_error_code; +#endif data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); if(data_s) { @@ -967,14 +983,6 @@ static ssize_t data_source_read_callback(nghttp2_session *session, return nread; } -/* - * The HTTP2 settings we send in the Upgrade request - */ -static nghttp2_settings_entry settings[] = { - { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }, - { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, HTTP2_HUGE_WINDOW_SIZE }, -}; - #define H2_BUFSIZE 32768 #ifdef NGHTTP2_HAS_ERROR_CALLBACK @@ -990,6 +998,23 @@ static int error_callback(nghttp2_session *session, } #endif +static void populate_settings(struct connectdata *conn, + struct http_conn *httpc) +{ + nghttp2_settings_entry *iv = httpc->local_settings; + + iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; + iv[0].value = 100; + + iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[1].value = HTTP2_HUGE_WINDOW_SIZE; + + iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + iv[2].value = conn->data->multi->push_cb != NULL; + + httpc->local_settings_num = 3; +} + void Curl_http2_done(struct connectdata *conn, bool premature) { struct Curl_easy *data = conn->data; @@ -1103,16 +1128,14 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, size_t blen; struct SingleRequest *k = &conn->data->req; uint8_t *binsettings = conn->proto.httpc.binsettings; + struct http_conn *httpc = &conn->proto.httpc; - /* As long as we have a fixed set of settings, we don't have to dynamically - * figure out the base64 strings since it'll always be the same. However, - * the settings will likely not be fixed every time in the future. - */ + populate_settings(conn, httpc); /* this returns number of bytes it wrote */ binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, - settings, - sizeof(settings)/sizeof(settings[0])); + httpc->local_settings, + httpc->local_settings_num); if(!binlen) { failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); return CURLE_FAILED_INIT; @@ -1862,28 +1885,22 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, /* Warn stream may be rejected if cumulative length of headers is too large. It appears nghttp2 will not send a header frame larger than 64KB. */ +#define MAX_ACC 60000 /* <64KB to account for some overhead */ { size_t acc = 0; - const size_t max_acc = 60000; /* <64KB to account for some overhead */ for(i = 0; i < nheader; ++i) { - if(nva[i].namelen > max_acc - acc) - break; - acc += nva[i].namelen; - - if(nva[i].valuelen > max_acc - acc) - break; - acc += nva[i].valuelen; + acc += nva[i].namelen + nva[i].valuelen; DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", nva[i].namelen, nva[i].name, nva[i].valuelen, nva[i].value)); } - if(i != nheader) { + if(acc > MAX_ACC) { infof(conn->data, "http2_send: Warning: The cumulative length of all " - "headers exceeds %zu bytes and that could cause the " - "stream to be rejected.\n", max_acc); + "headers exceeds %zu bytes and that could cause the " + "stream to be rejected.\n", MAX_ACC); } } @@ -2037,10 +2054,13 @@ CURLcode Curl_http2_switched(struct connectdata *conn, conn->data); } else { + populate_settings(conn, httpc); + /* stream ID is unknown at this point */ stream->stream_id = -1; - rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, settings, - sizeof(settings) / sizeof(settings[0])); + rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, + httpc->local_settings, + httpc->local_settings_num); if(rv != 0) { failf(data, "nghttp2_submit_settings() failed: %s(%d)", nghttp2_strerror(rv), rv); diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c index 21c77cd..8a78bd2 100644 --- a/Utilities/cmcurl/lib/http_ntlm.c +++ b/Utilities/cmcurl/lib/http_ntlm.c @@ -27,7 +27,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index e0213f3..d53685f 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -98,16 +98,21 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) * original pointer * * This function might be called several times in the multi interface case - * if the proxy's CONNTECT response is not instant. + * if the proxy's CONNECT response is not instant. */ prot_save = conn->data->req.protop; memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); - if(sockindex == SECONDARYSOCKET) - hostname = conn->secondaryhostname; - else if(conn->bits.conn_to_host) + + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + + if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; + else if(sockindex == SECONDARYSOCKET) + hostname = conn->secondaryhostname; else hostname = conn->host.name; @@ -199,7 +204,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(host_port); if(!result) { - char *host=(char *)""; + char *host = NULL; const char *proxyconn=""; const char *useragent=""; const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? @@ -242,13 +247,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, "%s", /* Proxy-Connection */ hostheader, http, - host, + host?host:"", conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", useragent, proxyconn); - if(host && *host) + if(host) free(host); free(hostheader); @@ -288,10 +293,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(!Curl_conn_data_pending(conn, sockindex)) /* return so we'll be called again polling-style */ return CURLE_OK; - else { - DEBUGF(infof(data, - "Read response immediately from proxy CONNECT\n")); - } + DEBUGF(infof(data, + "Read response immediately from proxy CONNECT\n")); } /* at this point, the tunnel_connecting phase is over. */ @@ -311,8 +314,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, perline = 0; while(nread < BUFSIZE && keepon && !error) { - int writetype; - if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; @@ -339,7 +340,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } continue; } - else if(result) { + if(result) { keepon = FALSE; break; } @@ -414,19 +415,20 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, Curl_debug(data, CURLINFO_HEADER_IN, line_start, (size_t)perline, conn); - /* send the header to the callback */ - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; + if(!data->set.suppress_connect_headers) { + /* send the header to the callback */ + int writetype = CLIENTWRITE_HEADER; + if(data->set.include_header) + writetype |= CLIENTWRITE_BODY; - result = Curl_client_write(conn, writetype, line_start, perline); + result = Curl_client_write(conn, writetype, line_start, perline); + if(result) + return result; + } data->info.header_size += (long)perline; data->req.headerbytecount += (long)perline; - if(result) - return result; - /* Newlines are CRLF, so the CR is ignored as the line isn't really terminated until the LF comes. Treat a following CR as end-of-headers as well.*/ @@ -510,33 +512,34 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } else if(checkprefix("Content-Length:", line_start)) { if(k->httpcode/100 == 2) { - /* A server MUST NOT send any Transfer-Encoding or - Content-Length header fields in a 2xx (Successful) - response to CONNECT. (RFC 7231 section 4.3.6) */ - failf(data, "Content-Length: in %03d response", + /* A client MUST ignore any Content-Length or Transfer-Encoding + header fields received in a successful response to CONNECT. + "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ + infof(data, "Ignoring Content-Length in CONNECT %03d response\n", k->httpcode); - return CURLE_RECV_ERROR; } - - cl = curlx_strtoofft(line_start + - strlen("Content-Length:"), NULL, 10); + else { + cl = curlx_strtoofft(line_start + + strlen("Content-Length:"), NULL, 10); + } } else if(Curl_compareheader(line_start, "Connection:", "close")) closeConnection = TRUE; - else if(Curl_compareheader(line_start, - "Transfer-Encoding:", - "chunked")) { + else if(checkprefix("Transfer-Encoding:", line_start)) { if(k->httpcode/100 == 2) { - /* A server MUST NOT send any Transfer-Encoding or - Content-Length header fields in a 2xx (Successful) - response to CONNECT. (RFC 7231 section 4.3.6) */ - failf(data, "Transfer-Encoding: in %03d response", k->httpcode); - return CURLE_RECV_ERROR; + /* A client MUST ignore any Content-Length or Transfer-Encoding + header fields received in a successful response to CONNECT. + "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */ + infof(data, "Ignoring Transfer-Encoding in " + "CONNECT %03d response\n", k->httpcode); + } + else if(Curl_compareheader(line_start, + "Transfer-Encoding:", "chunked")) { + infof(data, "CONNECT responded chunked\n"); + chunked_encoding = TRUE; + /* init our chunky engine */ + Curl_httpchunk_init(conn); } - infof(data, "CONNECT responded chunked\n"); - chunked_encoding = TRUE; - /* init our chunky engine */ - Curl_httpchunk_init(conn); } else if(Curl_compareheader(line_start, "Proxy-Connection:", "close")) closeConnection = TRUE; @@ -612,11 +615,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(conn->bits.proxy_connect_closed) /* this is not an error, just part of the connection negotiation */ return CURLE_OK; - else { - failf(data, "Received HTTP code %d from proxy after CONNECT", - data->req.httpcode); - return CURLE_RECV_ERROR; - } + failf(data, "Received HTTP code %d from proxy after CONNECT", + data->req.httpcode); + return CURLE_RECV_ERROR; } conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c index 78dc6fa..b528f77 100644 --- a/Utilities/cmcurl/lib/imap.c +++ b/Utilities/cmcurl/lib/imap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -130,7 +130,8 @@ const struct Curl_handler Curl_handler_imap = { ZERO_NULL, /* readwrite */ PORT_IMAP, /* defport */ CURLPROTO_IMAP, /* protocol */ - PROTOPT_CLOSEACTION /* flags */ + PROTOPT_CLOSEACTION| /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -952,7 +953,7 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, if(imapcode != 'O') { if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", imapcode); + failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; } else @@ -1748,7 +1749,7 @@ static CURLcode imap_setup_connection(struct connectdata *conn) * * imap_sendf() * - * Sends the formated string as an IMAP command to the server. + * Sends the formatted string as an IMAP command to the server. * * Designed to never block. */ diff --git a/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc index c1efbad..3316fba 100644 --- a/Utilities/cmcurl/lib/libcurl.rc +++ b/Utilities/cmcurl/lib/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,7 +51,7 @@ BEGIN VALUE "OriginalFilename", "libcurl.dll\0" VALUE "ProductName", "The curl library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" - VALUE "LegalCopyright", "© " LIBCURL_COPYRIGHT "\0" + VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */ VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" END END diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c index 482aaa0..b8836bb 100644 --- a/Utilities/cmcurl/lib/llist.c +++ b/Utilities/cmcurl/lib/llist.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,8 +33,8 @@ /* * @unittest: 1300 */ -static void -llist_init(struct curl_llist *l, curl_llist_dtor dtor) +void +Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor) { l->size = 0; l->dtor = dtor; @@ -42,20 +42,6 @@ llist_init(struct curl_llist *l, curl_llist_dtor dtor) l->tail = NULL; } -struct curl_llist * -Curl_llist_alloc(curl_llist_dtor dtor) -{ - struct curl_llist *list; - - list = malloc(sizeof(struct curl_llist)); - if(!list) - return NULL; - - llist_init(list, dtor); - - return list; -} - /* * Curl_llist_insert_next() * @@ -149,8 +135,6 @@ Curl_llist_destroy(struct curl_llist *list, void *user) if(list) { while(list->size > 0) Curl_llist_remove(list, list->tail, user); - - free(list); } } diff --git a/Utilities/cmcurl/lib/llist.h b/Utilities/cmcurl/lib/llist.h index 39ff408..47935ad 100644 --- a/Utilities/cmcurl/lib/llist.h +++ b/Utilities/cmcurl/lib/llist.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -43,7 +43,7 @@ struct curl_llist { size_t size; }; -struct curl_llist *Curl_llist_alloc(curl_llist_dtor); +void Curl_llist_init(struct curl_llist *, curl_llist_dtor); int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *, const void *); int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *, diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c index 15e8661..32d2adf 100644 --- a/Utilities/cmcurl/lib/memdebug.c +++ b/Utilities/cmcurl/lib/memdebug.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -458,7 +458,7 @@ int curl_fclose(FILE *file, int line, const char *source) #define LOGLINE_BUFSIZE 1024 -/* this does the writting to the memory tracking log file */ +/* this does the writing to the memory tracking log file */ void curl_memlog(const char *format, ...) { char *buf; diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c index 4baa1cc..6d4e733 100644 --- a/Utilities/cmcurl/lib/mprintf.c +++ b/Utilities/cmcurl/lib/mprintf.c @@ -1092,8 +1092,7 @@ char *curl_maprintf(const char *format, ...) info.buffer[info.len] = 0; /* we terminate this with a zero byte */ return info.buffer; } - else - return strdup(""); + return strdup(""); } char *curl_mvaprintf(const char *format, va_list ap_save) @@ -1117,8 +1116,7 @@ char *curl_mvaprintf(const char *format, va_list ap_save) info.buffer[info.len] = 0; /* we terminate this with a zero byte */ return info.buffer; } - else - return strdup(""); + return strdup(""); } static int storebuffer(int output, FILE *data) diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index 950b600..b24ce19 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -280,7 +280,7 @@ static int sh_init(struct curl_hash *hash, int hashsize) static CURLMcode multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg) { - if(!Curl_llist_insert_next(multi->msglist, multi->msglist->tail, msg)) + if(!Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg)) return CURLM_OUT_OF_MEMORY; return CURLM_OK; @@ -316,13 +316,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ if(Curl_conncache_init(&multi->conn_cache, chashsize)) goto error; - multi->msglist = Curl_llist_alloc(multi_freeamsg); - if(!multi->msglist) - goto error; - - multi->pending = Curl_llist_alloc(multi_freeamsg); - if(!multi->pending) - goto error; + Curl_llist_init(&multi->msglist, multi_freeamsg); + Curl_llist_init(&multi->pending, multi_freeamsg); /* allocate a new easy handle to use when closing cached connections */ multi->closure_handle = curl_easy_init(); @@ -345,8 +340,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ Curl_conncache_destroy(&multi->conn_cache); Curl_close(multi->closure_handle); multi->closure_handle = NULL; - Curl_llist_destroy(multi->msglist, NULL); - Curl_llist_destroy(multi->pending, NULL); + Curl_llist_destroy(&multi->msglist, NULL); + Curl_llist_destroy(&multi->pending, NULL); free(multi); return NULL; @@ -361,8 +356,6 @@ struct Curl_multi *curl_multi_init(void) CURLMcode curl_multi_add_handle(struct Curl_multi *multi, struct Curl_easy *data) { - struct curl_llist *timeoutlist; - /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -376,10 +369,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, if(data->multi) return CURLM_ADDED_ALREADY; - /* Allocate and initialize timeout list for easy handle */ - timeoutlist = Curl_llist_alloc(multi_freetimeout); - if(!timeoutlist) - return CURLM_OUT_OF_MEMORY; + /* Initialize timeout list for this handle */ + Curl_llist_init(&data->state.timeoutlist, multi_freetimeout); /* * No failure allowed in this function beyond this point. And no @@ -388,10 +379,6 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, * function no matter what. */ - /* Make easy handle use timeout list initialized above */ - data->state.timeoutlist = timeoutlist; - timeoutlist = NULL; - /* set the easy handle */ multistate(data, CURLM_STATE_INIT); @@ -532,6 +519,7 @@ static CURLcode multi_done(struct connectdata **connp, CURLcode result; struct connectdata *conn; struct Curl_easy *data; + unsigned int i; DEBUGASSERT(*connp); @@ -579,7 +567,7 @@ static CURLcode multi_done(struct connectdata **connp, result = CURLE_ABORTED_BY_CALLBACK; } - if(conn->send_pipe->size + conn->recv_pipe->size != 0 && + if(conn->send_pipe.size + conn->recv_pipe.size != 0 && !data->set.reuse_forbid && !conn->bits.close) { /* Stop if pipeline is not empty and we do not have to close @@ -598,9 +586,11 @@ static CURLcode multi_done(struct connectdata **connp, } /* if the transfer was completed in a paused state there can be buffered - data left to write and then kill */ - free(data->state.tempwrite); - data->state.tempwrite = NULL; + data left to free */ + for(i=0; i < data->state.tempcount; i++) { + free(data->state.tempwrite[i].buf); + } + data->state.tempcount = 0; /* if data->set.reuse_forbid is TRUE, it means the libcurl client has forced us to close this connection. This is ignored for requests taking @@ -638,7 +628,10 @@ static CURLcode multi_done(struct connectdata **connp, infof(data, "Connection #%ld to host %s left intact\n", conn->connection_id, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + conn->bits.socksproxy ? conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname); } else data->state.lastconnect = NULL; @@ -692,13 +685,13 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, if(data->easy_conn && data->mstate > CURLM_STATE_DO && data->mstate < CURLM_STATE_COMPLETED) { + /* Set connection owner so that the DONE function closes it. We can + safely do this here since connection is killed. */ + data->easy_conn->data = easy; /* If the handle is in a pipeline and has started sending off its request but not received its response yet, we need to close connection. */ streamclose(data->easy_conn, "Removed with partial response"); - /* Set connection owner so that the DONE function closes it. We can - safely do this here since connection is killed. */ - data->easy_conn->data = easy; easy_owns_conn = TRUE; } @@ -735,10 +728,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* destroy the timeout list that is held in the easy handle, do this *after* multi_done() as that may actually call Curl_expire that uses this */ - if(data->state.timeoutlist) { - Curl_llist_destroy(data->state.timeoutlist, NULL); - data->state.timeoutlist = NULL; - } + Curl_llist_destroy(&data->state.timeoutlist, NULL); /* as this was using a shared connection cache we clear the pointer to that since we're not part of that multi handle anymore */ @@ -761,11 +751,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* make sure there's no pending message in the queue sent from this easy handle */ - for(e = multi->msglist->head; e; e = e->next) { + for(e = multi->msglist.head; e; e = e->next) { struct Curl_message *msg = e->ptr; if(msg->extmsg.easy_handle == easy) { - Curl_llist_remove(multi->msglist, e, NULL); + Curl_llist_remove(&multi->msglist, e, NULL); /* there can only be one from this specific handle */ break; } @@ -956,10 +946,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, if(s == CURL_SOCKET_BAD) /* this socket is unused, break out of loop */ break; - else { - if((int)s > this_max_fd) - this_max_fd = (int)s; - } + if((int)s > this_max_fd) + this_max_fd = (int)s; } data = data->next; /* check next handle */ @@ -970,6 +958,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, return CURLM_OK; } +#define NUM_POLLS_ON_STACK 10 + CURLMcode curl_multi_wait(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, @@ -983,8 +973,10 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, unsigned int nfds = 0; unsigned int curlfds; struct pollfd *ufds = NULL; + bool ufds_malloc = FALSE; long timeout_internal; int retcode = 0; + struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -1024,9 +1016,14 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, nfds += extra_nfds; /* add the externally provided ones */ if(nfds || extra_nfds) { - ufds = malloc(nfds * sizeof(struct pollfd)); - if(!ufds) - return CURLM_OUT_OF_MEMORY; + if(nfds > NUM_POLLS_ON_STACK) { + ufds = malloc(nfds * sizeof(struct pollfd)); + if(!ufds) + return CURLM_OUT_OF_MEMORY; + ufds_malloc = TRUE; + } + else + ufds = &a_few_on_stack[0]; } nfds = 0; @@ -1104,7 +1101,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi, } } - free(ufds); + if(ufds_malloc) + free(ufds); if(ret) *ret = retcode; return CURLM_OK; @@ -1307,6 +1305,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLcode result = CURLE_OK; struct SingleRequest *k; time_t timeout_ms; + time_t recv_timeout_ms; + time_t send_timeout_ms; int control; if(!GOOD_EASY_HANDLE(data)) @@ -1432,7 +1432,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_CONNECT_PEND); /* add this handle to the list of connect-pending handles */ - if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data)) + if(!Curl_llist_insert_next(&multi->pending, multi->pending.tail, data)) result = CURLE_OUT_OF_MEMORY; else result = CURLE_OK; @@ -1477,8 +1477,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, struct connectdata *conn = data->easy_conn; const char *hostname; - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else @@ -1826,19 +1826,30 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else result = Curl_speedcheck(data, now); - if(( (data->set.max_send_speed == 0) || - (Curl_pgrsLimitWaitTime(data->progress.uploaded, - data->progress.ul_limit_size, - data->set.max_send_speed, - data->progress.ul_limit_start, - now) <= 0)) && - ( (data->set.max_recv_speed == 0) || - (Curl_pgrsLimitWaitTime(data->progress.downloaded, - data->progress.dl_limit_size, - data->set.max_recv_speed, - data->progress.dl_limit_start, - now) <= 0))) - multistate(data, CURLM_STATE_PERFORM); + if(!result) { + send_timeout_ms = 0; + if(data->set.max_send_speed > 0) + send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now); + + recv_timeout_ms = 0; + if(data->set.max_recv_speed > 0) + recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now); + + if(send_timeout_ms <= 0 && recv_timeout_ms <= 0) + multistate(data, CURLM_STATE_PERFORM); + else if(send_timeout_ms >= recv_timeout_ms) + Curl_expire_latest(data, send_timeout_ms); + else + Curl_expire_latest(data, recv_timeout_ms); + } break; case CURLM_STATE_PERFORM: @@ -1848,31 +1859,30 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, bool comeback = FALSE; /* check if over send speed */ - if(data->set.max_send_speed > 0) { - timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, - data->progress.ul_limit_size, - data->set.max_send_speed, - data->progress.ul_limit_start, - now); - if(timeout_ms > 0) { - multistate(data, CURLM_STATE_TOOFAST); - Curl_expire_latest(data, timeout_ms); - break; - } - } + send_timeout_ms = 0; + if(data->set.max_send_speed > 0) + send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now); /* check if over recv speed */ - if(data->set.max_recv_speed > 0) { - timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, - data->progress.dl_limit_size, - data->set.max_recv_speed, - data->progress.dl_limit_start, - now); - if(timeout_ms > 0) { - multistate(data, CURLM_STATE_TOOFAST); - Curl_expire_latest(data, timeout_ms); - break; - } + recv_timeout_ms = 0; + if(data->set.max_recv_speed > 0) + recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now); + + if(send_timeout_ms > 0 || recv_timeout_ms > 0) { + multistate(data, CURLM_STATE_TOOFAST); + if(send_timeout_ms >= recv_timeout_ms) + Curl_expire_latest(data, send_timeout_ms); + else + Curl_expire_latest(data, recv_timeout_ms); + break; } /* read/write data if it is ready to do so */ @@ -1928,11 +1938,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(data); /* we're no longer receiving */ - Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); + Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe); /* expire the new receiving pipeline head */ - if(data->easy_conn->recv_pipe->head) - Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 0); + if(data->easy_conn->recv_pipe.head) + Curl_expire_latest(data->easy_conn->recv_pipe.head->ptr, 0); /* Check if we can move pending requests to send pipe */ Curl_multi_process_pending_handles(multi); @@ -1997,7 +2007,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLcode res; /* Remove ourselves from the receive pipeline, if we are there. */ - Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); + Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe); /* Check if we can move pending requests to send pipe */ Curl_multi_process_pending_handles(multi); @@ -2073,8 +2083,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* if this has a connection, unsubscribe from the pipelines */ Curl_pipeline_leave_write(data->easy_conn); Curl_pipeline_leave_read(data->easy_conn); - Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe); - Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); + Curl_removeHandleFromPipeline(data, &data->easy_conn->send_pipe); + Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe); if(stream_error) { /* Don't attempt to send data over a connection that timed out */ @@ -2229,8 +2239,8 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) Curl_hash_destroy(&multi->sockhash); Curl_conncache_destroy(&multi->conn_cache); - Curl_llist_destroy(multi->msglist, NULL); - Curl_llist_destroy(multi->pending, NULL); + Curl_llist_destroy(&multi->msglist, NULL); + Curl_llist_destroy(&multi->pending, NULL); /* remove all easy handles */ data = multi->easyp; @@ -2262,8 +2272,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) return CURLM_OK; } - else - return CURLM_BAD_HANDLE; + return CURLM_BAD_HANDLE; } /* @@ -2282,24 +2291,23 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) *msgs_in_queue = 0; /* default to none */ - if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) { + if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(&multi->msglist)) { /* there is one or more messages in the list */ struct curl_llist_element *e; /* extract the head of the list to return */ - e = multi->msglist->head; + e = multi->msglist.head; msg = e->ptr; /* remove the extracted entry */ - Curl_llist_remove(multi->msglist, e, NULL); + Curl_llist_remove(&multi->msglist, e, NULL); - *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist)); + *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist)); return &msg->extmsg; } - else - return NULL; + return NULL; } /* @@ -2394,7 +2402,7 @@ static void singlesocket(struct Curl_multi *multi, removed. */ struct connectdata *easy_conn = data->easy_conn; if(easy_conn) { - if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) { + if(easy_conn->recv_pipe.size > 1) { /* the handle should not be removed from the pipe yet */ remove_sock_from_hash = FALSE; @@ -2403,12 +2411,12 @@ static void singlesocket(struct Curl_multi *multi, isn't already) */ if(entry->easy == data) { if(Curl_recvpipe_head(data, easy_conn)) - entry->easy = easy_conn->recv_pipe->head->next->ptr; + entry->easy = easy_conn->recv_pipe.head->next->ptr; else - entry->easy = easy_conn->recv_pipe->head->ptr; + entry->easy = easy_conn->recv_pipe.head->ptr; } } - if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) { + if(easy_conn->send_pipe.size > 1) { /* the handle should not be removed from the pipe yet */ remove_sock_from_hash = FALSE; @@ -2417,9 +2425,9 @@ static void singlesocket(struct Curl_multi *multi, isn't already) */ if(entry->easy == data) { if(Curl_sendpipe_head(data, easy_conn)) - entry->easy = easy_conn->send_pipe->head->next->ptr; + entry->easy = easy_conn->send_pipe.head->next->ptr; else - entry->easy = easy_conn->send_pipe->head->ptr; + entry->easy = easy_conn->send_pipe.head->ptr; } } /* Don't worry about overwriting recv_pipe head with send_pipe_head, @@ -2494,7 +2502,7 @@ static CURLMcode add_next_timeout(struct timeval now, struct Curl_easy *d) { struct timeval *tv = &d->state.expiretime; - struct curl_llist *list = d->state.timeoutlist; + struct curl_llist *list = &d->state.timeoutlist; struct curl_llist_element *e; /* move over the timeout list for this specific handle and remove all @@ -2560,7 +2568,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, /* or should we fall-through and do the timer-based stuff? */ return result; } - else if(s != CURL_SOCKET_TIMEOUT) { + if(s != CURL_SOCKET_TIMEOUT) { struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s); @@ -2585,13 +2593,11 @@ static CURLMcode multi_socket(struct Curl_multi *multi, head. If we should read from the socket, take the recv_pipe head. */ if(data->easy_conn) { if((ev_bitmask & CURL_POLL_OUT) && - data->easy_conn->send_pipe && - data->easy_conn->send_pipe->head) - data = data->easy_conn->send_pipe->head->ptr; + data->easy_conn->send_pipe.head) + data = data->easy_conn->send_pipe.head->ptr; else if((ev_bitmask & CURL_POLL_IN) && - data->easy_conn->recv_pipe && - data->easy_conn->recv_pipe->head) - data = data->easy_conn->recv_pipe->head->ptr; + data->easy_conn->recv_pipe.head) + data = data->easy_conn->recv_pipe.head->ptr; } if(data->easy_conn && @@ -2928,7 +2934,7 @@ void Curl_expire(struct Curl_easy *data, time_t milli) set = Curl_tvnow(); set.tv_sec += (long)(milli/1000); - set.tv_usec += (milli%1000)*1000; + set.tv_usec += (long)(milli%1000)*1000; if(set.tv_usec >= 1000000) { set.tv_sec++; @@ -2943,13 +2949,13 @@ void Curl_expire(struct Curl_easy *data, time_t milli) if(diff > 0) { /* the new expire time was later so just add it to the queue and get out */ - multi_addtimeout(data->state.timeoutlist, &set); + multi_addtimeout(&data->state.timeoutlist, &set); return; } /* the new time is newer than the presently set one, so add the current to the queue and update the head */ - multi_addtimeout(data->state.timeoutlist, nowp); + multi_addtimeout(&data->state.timeoutlist, nowp); /* Since this is an updated time, we must remove the previous entry from the splay tree first and then re-add the new value */ @@ -2985,7 +2991,7 @@ void Curl_expire_latest(struct Curl_easy *data, time_t milli) set = Curl_tvnow(); set.tv_sec += (long)(milli / 1000); - set.tv_usec += (milli % 1000) * 1000; + set.tv_usec += (long)(milli % 1000) * 1000; if(set.tv_usec >= 1000000) { set.tv_sec++; @@ -2995,11 +3001,14 @@ void Curl_expire_latest(struct Curl_easy *data, time_t milli) if(expire->tv_sec || expire->tv_usec) { /* This means that the struct is added as a node in the splay tree. Compare if the new time is earlier, and only remove-old/add-new if it - is. */ + is. */ time_t diff = curlx_tvdiff(set, *expire); - if(diff > 0) - /* the new expire time was later than the top time, so just skip this */ + if((diff > 0) && (diff < milli)) { + /* if the new expire time is later than the top time, skip it, but not + if the diff is larger than the new offset since then the previous + time is already expired! */ return; + } } /* Just add the timeout like normal */ @@ -3026,7 +3035,7 @@ void Curl_expire_clear(struct Curl_easy *data) if(nowp->tv_sec || nowp->tv_usec) { /* Since this is an cleared time, we must remove the previous entry from the splay tree */ - struct curl_llist *list = data->state.timeoutlist; + struct curl_llist *list = &data->state.timeoutlist; rc = Curl_splayremovebyaddr(multi->timetree, &data->state.timenode, @@ -3086,17 +3095,17 @@ curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi) struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi) { - return multi->pipelining_site_bl; + return &multi->pipelining_site_bl; } struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi) { - return multi->pipelining_server_bl; + return &multi->pipelining_server_bl; } void Curl_multi_process_pending_handles(struct Curl_multi *multi) { - struct curl_llist_element *e = multi->pending->head; + struct curl_llist_element *e = multi->pending.head; while(e) { struct Curl_easy *data = e->ptr; @@ -3106,7 +3115,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) multistate(data, CURLM_STATE_CONNECT); /* Remove this node from the list */ - Curl_llist_remove(multi->pending, e, NULL); + Curl_llist_remove(&multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ Curl_expire_latest(data, 0); diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h index 0b78de9..915b857 100644 --- a/Utilities/cmcurl/lib/multihandle.h +++ b/Utilities/cmcurl/lib/multihandle.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -80,10 +80,10 @@ struct Curl_multi { int num_alive; /* amount of easy handles that are added but have not yet reached COMPLETE state */ - struct curl_llist *msglist; /* a list of messages from completed transfers */ + struct curl_llist msglist; /* a list of messages from completed transfers */ - struct curl_llist *pending; /* Curl_easys that are in the - CURLM_STATE_CONNECT_PEND state */ + struct curl_llist pending; /* Curl_easys that are in the + CURLM_STATE_CONNECT_PEND state */ /* callback function and user data pointer for the *socket() API */ curl_socket_callback socket_cb; @@ -138,11 +138,11 @@ struct Curl_multi { bigger than this is not considered for pipelining */ - struct curl_llist *pipelining_site_bl; /* List of sites that are blacklisted - from pipelining */ + struct curl_llist pipelining_site_bl; /* List of sites that are blacklisted + from pipelining */ - struct curl_llist *pipelining_server_bl; /* List of server types that are - blacklisted from pipelining */ + struct curl_llist pipelining_server_bl; /* List of server types that are + blacklisted from pipelining */ /* timer callback and user data pointer for the *socket() API */ curl_multi_timer_callback timer_cb; diff --git a/Utilities/cmcurl/lib/nonblock.c b/Utilities/cmcurl/lib/nonblock.c index b764278..5959281 100644 --- a/Utilities/cmcurl/lib/nonblock.c +++ b/Utilities/cmcurl/lib/nonblock.c @@ -58,8 +58,7 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ flags = sfcntl(sockfd, F_GETFL, 0); if(nonblock) return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK); - else - return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); + return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); #elif defined(HAVE_IOCTL_FIONBIO) diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c index 7a99357..b833fcd 100644 --- a/Utilities/cmcurl/lib/pingpong.c +++ b/Utilities/cmcurl/lib/pingpong.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -152,7 +152,7 @@ void Curl_pp_init(struct pingpong *pp) * * Curl_pp_vsendf() * - * Send the formated string as a command to a pingpong server. Note that + * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * @@ -239,7 +239,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, * * Curl_pp_sendf() * - * Send the formated string as a command to a pingpong server. Note that + * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h index 500100a..ee1a59b 100644 --- a/Utilities/cmcurl/lib/pingpong.h +++ b/Utilities/cmcurl/lib/pingpong.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -95,7 +95,7 @@ time_t Curl_pp_state_timeout(struct pingpong *pp); * * Curl_pp_sendf() * - * Send the formated string as a command to a pingpong server. Note that + * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * @@ -108,7 +108,7 @@ CURLcode Curl_pp_sendf(struct pingpong *pp, * * Curl_pp_vsendf() * - * Send the formated string as a command to a pingpong server. Note that + * Send the formatted string as a command to a pingpong server. Note that * the string should not have any CRLF appended, as this function will * append the necessary things itself. * diff --git a/Utilities/cmcurl/lib/pipeline.c b/Utilities/cmcurl/lib/pipeline.c index 40a5e82..4a14fdd 100644 --- a/Utilities/cmcurl/lib/pipeline.c +++ b/Utilities/cmcurl/lib/pipeline.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se> - * Copyright (C) 2013-2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,8 +69,8 @@ bool Curl_pipeline_penalized(struct Curl_easy *data, curl_off_t recv_size = -2; /* Make it easy to spot in the log */ /* Find the head of the recv pipe, if any */ - if(conn->recv_pipe && conn->recv_pipe->head) { - struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr; + if(conn->recv_pipe.head) { + struct Curl_easy *recv_handle = conn->recv_pipe.head->ptr; recv_size = recv_handle->req.size; @@ -103,18 +103,18 @@ static CURLcode addHandleToPipeline(struct Curl_easy *data, CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn) { - struct curl_llist_element *sendhead = conn->send_pipe->head; + struct curl_llist_element *sendhead = conn->send_pipe.head; struct curl_llist *pipeline; CURLcode result; - pipeline = conn->send_pipe; + pipeline = &conn->send_pipe; result = addHandleToPipeline(handle, pipeline); - if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { + if(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head) { /* this is a new one as head, expire it */ Curl_pipeline_leave_write(conn); /* not in use yet */ - Curl_expire(conn->send_pipe->head->ptr, 0); + Curl_expire(conn->send_pipe.head->ptr, 0); } #if 0 /* enable for pipeline debugging */ @@ -135,21 +135,21 @@ void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, { struct curl_llist_element *curr; - curr = conn->send_pipe->head; + curr = conn->send_pipe.head; while(curr) { if(curr->ptr == handle) { - Curl_llist_move(conn->send_pipe, curr, - conn->recv_pipe, conn->recv_pipe->tail); + Curl_llist_move(&conn->send_pipe, curr, + &conn->recv_pipe, conn->recv_pipe.tail); - if(conn->send_pipe->head) { + if(conn->send_pipe.head) { /* Since there's a new easy handle at the start of the send pipeline, set its timeout value to 1ms to make it trigger instantly */ Curl_pipeline_leave_write(conn); /* not used now */ #ifdef DEBUGBUILD infof(conn->data, "%p is at send pipe head B!\n", - (void *)conn->send_pipe->head->ptr); + (void *)conn->send_pipe.head->ptr); #endif - Curl_expire(conn->send_pipe->head->ptr, 0); + Curl_expire(conn->send_pipe.head->ptr, 0); } /* The receiver's list is not really interesting here since either this @@ -191,15 +191,14 @@ bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, } CURLMcode Curl_pipeline_set_site_blacklist(char **sites, - struct curl_llist **list_ptr) + struct curl_llist *list) { - struct curl_llist *old_list = *list_ptr; - struct curl_llist *new_list = NULL; + /* Free the old list */ + if(list->size) + Curl_llist_destroy(list, NULL); if(sites) { - new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor); - if(!new_list) - return CURLM_OUT_OF_MEMORY; + Curl_llist_init(list, (curl_llist_dtor) site_blacklist_llist_dtor); /* Parse the URLs and populate the list */ while(*sites) { @@ -209,14 +208,14 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, hostname = strdup(*sites); if(!hostname) { - Curl_llist_destroy(new_list, NULL); + Curl_llist_destroy(list, NULL); return CURLM_OUT_OF_MEMORY; } entry = malloc(sizeof(struct site_blacklist_entry)); if(!entry) { free(hostname); - Curl_llist_destroy(new_list, NULL); + Curl_llist_destroy(list, NULL); return CURLM_OUT_OF_MEMORY; } @@ -233,9 +232,9 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, entry->hostname = hostname; - if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) { + if(!Curl_llist_insert_next(list, list->tail, entry)) { site_blacklist_llist_dtor(NULL, entry); - Curl_llist_destroy(new_list, NULL); + Curl_llist_destroy(list, NULL); return CURLM_OUT_OF_MEMORY; } @@ -243,14 +242,6 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, } } - /* Free the old list */ - if(old_list) { - Curl_llist_destroy(old_list, NULL); - } - - /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ - *list_ptr = new_list; - return CURLM_OK; } @@ -284,15 +275,14 @@ bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, } CURLMcode Curl_pipeline_set_server_blacklist(char **servers, - struct curl_llist **list_ptr) + struct curl_llist *list) { - struct curl_llist *old_list = *list_ptr; - struct curl_llist *new_list = NULL; + /* Free the old list */ + if(list->size) + Curl_llist_destroy(list, NULL); if(servers) { - new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor); - if(!new_list) - return CURLM_OUT_OF_MEMORY; + Curl_llist_init(list, (curl_llist_dtor) server_blacklist_llist_dtor); /* Parse the URLs and populate the list */ while(*servers) { @@ -300,12 +290,12 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, server_name = strdup(*servers); if(!server_name) { - Curl_llist_destroy(new_list, NULL); + Curl_llist_destroy(list, NULL); return CURLM_OUT_OF_MEMORY; } - if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) { - Curl_llist_destroy(new_list, NULL); + if(!Curl_llist_insert_next(list, list->tail, server_name)) { + Curl_llist_destroy(list, NULL); Curl_safefree(server_name); return CURLM_OUT_OF_MEMORY; } @@ -314,13 +304,6 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, } } - /* Free the old list */ - if(old_list) { - Curl_llist_destroy(old_list, NULL); - } - - /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ - *list_ptr = new_list; return CURLM_OK; } @@ -340,14 +323,14 @@ static bool pipe_head(struct Curl_easy *data, bool Curl_recvpipe_head(struct Curl_easy *data, struct connectdata *conn) { - return pipe_head(data, conn->recv_pipe); + return pipe_head(data, &conn->recv_pipe); } /* returns TRUE if the given handle is head of the send pipe */ bool Curl_sendpipe_head(struct Curl_easy *data, struct connectdata *conn) { - return pipe_head(data, conn->send_pipe); + return pipe_head(data, &conn->send_pipe); } diff --git a/Utilities/cmcurl/lib/pipeline.h b/Utilities/cmcurl/lib/pipeline.h index a64f710..413ba31 100644 --- a/Utilities/cmcurl/lib/pipeline.h +++ b/Utilities/cmcurl/lib/pipeline.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2013 - 2014, Linus Nielsen Feltzing, <linus@haxx.se> * * This software is licensed as described in the file COPYING, which @@ -34,13 +34,13 @@ bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn); CURLMcode Curl_pipeline_set_site_blacklist(char **sites, - struct curl_llist **list_ptr); + struct curl_llist *list_ptr); bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name); CURLMcode Curl_pipeline_set_server_blacklist(char **servers, - struct curl_llist **list_ptr); + struct curl_llist *list_ptr); bool Curl_pipeline_checkget_write(struct Curl_easy *data, struct connectdata *conn); diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c index 9bb691c..3feb3be 100644 --- a/Utilities/cmcurl/lib/pop3.c +++ b/Utilities/cmcurl/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -127,7 +127,8 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -153,7 +154,7 @@ const struct Curl_handler Curl_handler_pop3s = { PORT_POP3S, /* defport */ CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY /* flags */ + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif @@ -799,7 +800,7 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, if(pop3code != '+') { if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", pop3code); + failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; } else diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c index 60627b2..cfaf404 100644 --- a/Utilities/cmcurl/lib/progress.c +++ b/Utilities/cmcurl/lib/progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -229,16 +229,16 @@ void Curl_pgrsStartNow(struct Curl_easy *data) * need to wait until we're back under the speed limit, if needed. * * The way it works is by having a "starting point" (time & amount of data - * transfered by then) used in the speed computation, to be used instead of the - * start of the transfer. - * This starting point is regularly moved as transfer goes on, to keep getting - * accurate values (instead of average over the entire tranfer). + * transferred by then) used in the speed computation, to be used instead of + * the start of the transfer. This starting point is regularly moved as + * transfer goes on, to keep getting accurate values (instead of average over + * the entire transfer). * - * This function takes the current amount of data transfered, the amount at the - * starting point, the limit (in bytes/s), the time of the starting point and - * the current time. + * This function takes the current amount of data transferred, the amount at + * the starting point, the limit (in bytes/s), the time of the starting point + * and the current time. * - * Returns -1 if no waiting is needed (not enough data transfered since + * Returns -1 if no waiting is needed (not enough data transferred since * starting point yet), 0 when no waiting is needed but the starting point * should be reset (to current), or the number of milliseconds to wait to get * back under the speed limit. @@ -267,8 +267,8 @@ long Curl_pgrsLimitWaitTime(curl_off_t cursize, if(actual < minimum) /* this is a conversion on some systems (64bit time_t => 32bit long) */ return (long)(minimum - actual); - else - return 0; + + return 0; } void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) @@ -454,7 +454,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) failf(data, "Callback aborted"); return result; } - else if(data->set.fprogress) { + if(data->set.fprogress) { /* The older deprecated callback is set, call that */ result= data->set.fprogress(data->set.progress_client, (double)data->progress.size_dl, diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c index a51951c..8a14084 100644 --- a/Utilities/cmcurl/lib/rand.c +++ b/Utilities/cmcurl/lib/rand.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,9 @@ #include "curl_setup.h" +#ifdef HAVE_FCNTL_H #include <fcntl.h> +#endif #include <curl/curl.h> #include "vtls/vtls.h" @@ -61,7 +63,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) /* data may be NULL! */ result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); if(result != CURLE_NOT_BUILT_IN) - /* only if there is no random funtion in the TLS backend do the non crypto + /* only if there is no random function in the TLS backend do the non crypto version, otherwise return result */ return result; diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index 65c6c3b..1810cda 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -216,7 +216,7 @@ static CURLcode rtsp_done(struct connectdata *conn, CSeq_sent, CSeq_recv); return CURLE_RTSP_CSEQ_ERROR; } - else if(data->set.rtspreq == RTSPREQ_RECEIVE && + if(data->set.rtspreq == RTSPREQ_RECEIVE && (conn->proto.rtspc.rtp_channel == -1)) { infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv); /* TODO CPC: Server -> Client logic here */ @@ -648,31 +648,29 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, *readmore = TRUE; break; } - else { - /* We have the full RTP interleaved packet - * Write out the header including the leading '$' */ - DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n", - rtspc->rtp_channel, rtp_length)); - result = rtp_client_write(conn, &rtp[0], rtp_length + 4); - if(result) { - failf(data, "Got an error writing an RTP packet"); - *readmore = FALSE; - Curl_safefree(rtspc->rtp_buf); - rtspc->rtp_buf = NULL; - rtspc->rtp_bufsize = 0; - return result; - } + /* We have the full RTP interleaved packet + * Write out the header including the leading '$' */ + DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n", + rtspc->rtp_channel, rtp_length)); + result = rtp_client_write(conn, &rtp[0], rtp_length + 4); + if(result) { + failf(data, "Got an error writing an RTP packet"); + *readmore = FALSE; + Curl_safefree(rtspc->rtp_buf); + rtspc->rtp_buf = NULL; + rtspc->rtp_bufsize = 0; + return result; + } - /* Move forward in the buffer */ - rtp_dataleft -= rtp_length + 4; - rtp += rtp_length + 4; + /* Move forward in the buffer */ + rtp_dataleft -= rtp_length + 4; + rtp += rtp_length + 4; - if(data->set.rtspreq == RTSPREQ_RECEIVE) { - /* If we are in a passive receive, give control back - * to the app as often as we can. - */ - k->keepon &= ~KEEP_RECV; - } + if(data->set.rtspreq == RTSPREQ_RECEIVE) { + /* If we are in a passive receive, give control back + * to the app as often as we can. + */ + k->keepon &= ~KEEP_RECV; } } else { @@ -703,20 +701,18 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, *nread = 0; return CURLE_OK; } - else { - /* Fix up k->str to point just after the last RTP packet */ - k->str += *nread - rtp_dataleft; + /* Fix up k->str to point just after the last RTP packet */ + k->str += *nread - rtp_dataleft; - /* either all of the data has been read or... - * rtp now points at the next byte to parse - */ - if(rtp_dataleft > 0) - DEBUGASSERT(k->str[0] == rtp[0]); + /* either all of the data has been read or... + * rtp now points at the next byte to parse + */ + if(rtp_dataleft > 0) + DEBUGASSERT(k->str[0] == rtp[0]); - DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */ + DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */ - *nread = rtp_dataleft; - } + *nread = rtp_dataleft; /* If we get here, we have finished with the leftover/merge buffer */ Curl_safefree(rtspc->rtp_buf); @@ -797,7 +793,7 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn, /* If the Session ID is not set, and we find it in a response, then set * it. * - * Allow any non whitespace content, up to the field seperator or end of + * Allow any non whitespace content, up to the field separator or end of * line. RFC 2326 isn't 100% clear on the session ID and for example * gstreamer does url-encoded session ID's not covered by the standard. */ diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c index 4a8f444..f4a8763 100644 --- a/Utilities/cmcurl/lib/security.c +++ b/Utilities/cmcurl/lib/security.c @@ -367,6 +367,10 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, size_t decoded_sz = 0; CURLcode error; + if(!conn->mech) + /* not inititalized, return error */ + return -1; + DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c index 6bb0ab1..4430072 100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -129,7 +129,7 @@ int Curl_wait_ms(int timeout_ms) * and a file descriptor is too large for FD_SETSIZE. * * A negative timeout value makes this function wait indefinitely, - * unles no valid file descriptor is given, when this happens the + * unless no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. * * Return values: @@ -164,7 +164,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ int r; int ret; -#if SIZEOF_LONG != SIZEOF_INT +#if SIZEOF_TIME_T != SIZEOF_INT /* wrap-around precaution */ if(timeout_ms >= INT_MAX) timeout_ms = INT_MAX; @@ -380,7 +380,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ * select() is used instead. An error is returned if select() is * being used and a file descriptor is too large for FD_SETSIZE. * A negative timeout value makes this function wait indefinitely, - * unles no valid file descriptor is given, when this happens the + * unless no valid file descriptor is given, when this happens the * negative timeout is ignored and the function times out immediately. * * Return values: diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h index e247bd9..4ed5dd2 100644 --- a/Utilities/cmcurl/lib/select.h +++ b/Utilities/cmcurl/lib/select.h @@ -24,10 +24,10 @@ #include "curl_setup.h" -#ifdef HAVE_SYS_POLL_H -#include <sys/poll.h> -#elif defined(HAVE_POLL_H) +#ifdef HAVE_POLL_H #include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> #endif /* diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c index 7601697..84b6b4b 100644 --- a/Utilities/cmcurl/lib/sendf.c +++ b/Utilities/cmcurl/lib/sendf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,6 +33,7 @@ #include "non-ascii.h" #include "strerror.h" #include "select.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -262,7 +263,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) va_end(ap); } -/* Curl_sendf() sends formated data to the server */ +/* Curl_sendf() sends formatted data to the server */ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, const char *fmt, ...) { @@ -474,21 +475,58 @@ static CURLcode pausewrite(struct Curl_easy *data, we want to send we need to dup it to save a copy for when the sending is again enabled */ struct SingleRequest *k = &data->req; - char *dupl = malloc(len); - if(!dupl) - return CURLE_OUT_OF_MEMORY; + struct UrlState *s = &data->state; + char *dupl; + unsigned int i; + bool newtype = TRUE; + + if(s->tempcount) { + for(i=0; i< s->tempcount; i++) { + if(s->tempwrite[i].type == type) { + /* data for this type exists */ + newtype = FALSE; + break; + } + } + DEBUGASSERT(i < 3); + } + else + i = 0; + + if(!newtype) { + /* append new data to old data */ + + /* figure out the new size of the data to save */ + size_t newlen = len + s->tempwrite[i].len; + /* allocate the new memory area */ + char *newptr = realloc(s->tempwrite[i].buf, newlen); + if(!newptr) + return CURLE_OUT_OF_MEMORY; + /* copy the new data to the end of the new area */ + memcpy(newptr + s->tempwrite[i].len, ptr, len); + + /* update the pointer and the size */ + s->tempwrite[i].buf = newptr; + s->tempwrite[i].len = newlen; + } + else { + dupl = Curl_memdup(ptr, len); + if(!dupl) + return CURLE_OUT_OF_MEMORY; - memcpy(dupl, ptr, len); + /* store this information in the state struct for later use */ + s->tempwrite[i].buf = dupl; + s->tempwrite[i].len = len; + s->tempwrite[i].type = type; - /* store this information in the state struct for later use */ - data->state.tempwrite = dupl; - data->state.tempwritesize = len; - data->state.tempwritetype = type; + if(newtype) + s->tempcount++; + } /* mark the connection as RECV paused */ k->keepon |= KEEP_RECV_PAUSE; - DEBUGF(infof(data, "Pausing with %zu bytes in buffer for type %02x\n", + DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n", len, type)); return CURLE_OK; @@ -511,31 +549,10 @@ CURLcode Curl_client_chop_write(struct connectdata *conn, if(!len) return CURLE_OK; - /* If reading is actually paused, we're forced to append this chunk of data - to the already held data, but only if it is the same type as otherwise it - can't work and it'll return error instead. */ - if(data->req.keepon & KEEP_RECV_PAUSE) { - size_t newlen; - char *newptr; - if(type != data->state.tempwritetype) - /* major internal confusion */ - return CURLE_RECV_ERROR; - - DEBUGASSERT(data->state.tempwrite); - - /* figure out the new size of the data to save */ - newlen = len + data->state.tempwritesize; - /* allocate the new memory area */ - newptr = realloc(data->state.tempwrite, newlen); - if(!newptr) - return CURLE_OUT_OF_MEMORY; - /* copy the new data to the end of the new area */ - memcpy(newptr + data->state.tempwritesize, ptr, len); - /* update the pointer and the size */ - data->state.tempwrite = newptr; - data->state.tempwritesize = newlen; - return CURLE_OK; - } + /* If reading is paused, append this data to the already held data for this + type. */ + if(data->req.keepon & KEEP_RECV_PAUSE) + return pausewrite(data, type, ptr, len); /* Determine the callback(s) to use. */ if(type & CLIENTWRITE_BODY) @@ -565,10 +582,9 @@ CURLcode Curl_client_chop_write(struct connectdata *conn, failf(data, "Write callback asked for PAUSE when not supported!"); return CURLE_WRITE_ERROR; } - else - return pausewrite(data, type, ptr, len); + return pausewrite(data, type, ptr, len); } - else if(wrote != chunklen) { + if(wrote != chunklen) { failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen); return CURLE_WRITE_ERROR; } @@ -616,6 +632,8 @@ CURLcode Curl_client_write(struct connectdata *conn, if(0 == len) len = strlen(ptr); + DEBUGASSERT(type <= 3); + /* FTP data may need conversion. */ if((type & CLIENTWRITE_BODY) && (conn->handler->protocol & PROTO_FAMILY_FTP) && @@ -652,8 +670,7 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, #endif if(return_error) return CURLE_AGAIN; - else - return CURLE_RECV_ERROR; + return CURLE_RECV_ERROR; } /* we only return number of bytes read when we return OK */ diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c index f197fe1..51b3434 100644 --- a/Utilities/cmcurl/lib/smb.c +++ b/Utilities/cmcurl/lib/smb.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies - * Copyright (C) 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2016-2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,8 +23,8 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ - (CURL_SIZEOF_CURL_OFF_T > 4) +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) @@ -32,8 +32,12 @@ #ifdef HAVE_PROCESS_H #include <process.h> +#ifdef CURL_WINDOWS_APP +#define getpid GetCurrentProcessId +#else #define getpid _getpid #endif +#endif #include "smb.h" #include "urldata.h" @@ -117,18 +121,18 @@ const struct Curl_handler Curl_handler_smbs = { #define SERVICENAME "?????" /* Append a string to an SMB message */ -#define MSGCAT(str) \ - strcpy(p, (str)); \ +#define MSGCAT(str) \ + strcpy(p, (str)); \ p += strlen(str); /* Append a null-terminated string to an SMB message */ -#define MSGCATNULL(str) \ - strcpy(p, (str)); \ +#define MSGCATNULL(str) \ + strcpy(p, (str)); \ p += strlen(str) + 1; /* SMB is mostly little endian */ #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ - defined(__OS400__) + defined(__OS400__) static unsigned short smb_swap16(unsigned short x) { return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); @@ -137,20 +141,20 @@ static unsigned short smb_swap16(unsigned short x) static unsigned int smb_swap32(unsigned int x) { return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | - ((x >> 24) & 0xff); + ((x >> 24) & 0xff); } #ifdef HAVE_LONGLONG static unsigned long long smb_swap64(unsigned long long x) { return ((unsigned long long) smb_swap32((unsigned int) x) << 32) | - smb_swap32((unsigned int) (x >> 32)); + smb_swap32((unsigned int) (x >> 32)); } #else static unsigned __int64 smb_swap64(unsigned __int64 x) { return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) | - smb_swap32((unsigned int) (x >> 32)); + smb_swap32((unsigned int) (x >> 32)); } #endif #else @@ -197,7 +201,7 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) if(smb->state != newstate) infof(conn->data, "SMB conn %p state change from %s to %s\n", - (void *)smb, names[smb->state], names[newstate]); + (void *)smb, names[smb->state], names[newstate]); #endif smb->state = newstate; @@ -223,7 +227,7 @@ static void request_state(struct connectdata *conn, if(req->state != newstate) infof(conn->data, "SMB request %p state change from %s to %s\n", - (void *)req, names[req->state], names[newstate]); + (void *)req, names[req->state], names[newstate]); #endif req->state = newstate; @@ -308,8 +312,9 @@ static CURLcode smb_recv_message(struct connectdata *conn, void **msg) if(smbc->got < sizeof(unsigned int)) return CURLE_OK; - nbt_size = Curl_read16_be((const unsigned char *)(buf + - sizeof(unsigned short))) + sizeof(unsigned int); + nbt_size = Curl_read16_be((const unsigned char *) + (buf + sizeof(unsigned short))) + + sizeof(unsigned int); if(smbc->got < nbt_size) return CURLE_OK; @@ -320,7 +325,7 @@ static CURLcode smb_recv_message(struct connectdata *conn, void **msg) if(nbt_size >= msg_size + sizeof(unsigned short)) { /* Add the byte count */ msg_size += sizeof(unsigned short) + - Curl_read16_le((const unsigned char *)&buf[msg_size]); + Curl_read16_le((const unsigned char *)&buf[msg_size]); if(nbt_size < msg_size) return CURLE_READ_ERROR; } @@ -441,7 +446,7 @@ static CURLcode smb_send_setup(struct connectdata *conn) Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash); Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm); -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash); Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt); #else @@ -603,7 +608,7 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) /* Check if there is data in the transfer buffer */ if(!smbc->send_size && smbc->upload_size) { int nread = smbc->upload_size > BUFSIZE ? BUFSIZE : - (int) smbc->upload_size; + (int) smbc->upload_size; conn->data->req.upload_fromhere = conn->data->state.uploadbuffer; result = Curl_fillreadbuffer(conn, nread, &nread); if(result && result != CURLE_AGAIN) diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c index ff8e80d..adc346a 100644 --- a/Utilities/cmcurl/lib/smtp.c +++ b/Utilities/cmcurl/lib/smtp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -126,7 +126,8 @@ const struct Curl_handler Curl_handler_smtp = { ZERO_NULL, /* readwrite */ PORT_SMTP, /* defport */ CURLPROTO_SMTP, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -152,7 +153,7 @@ const struct Curl_handler Curl_handler_smtps = { PORT_SMTPS, /* defport */ CURLPROTO_SMTPS, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY /* flags */ + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif @@ -692,7 +693,7 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, if(smtpcode != 220) { if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", smtpcode); + failf(data, "STARTTLS denied, code %d", smtpcode); result = CURLE_USE_SSL_FAILED; } else diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c index 774fb20..97a44b2 100644 --- a/Utilities/cmcurl/lib/socks.c +++ b/Utilities/cmcurl/lib/socks.c @@ -73,7 +73,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ result = Curl_read_plain(sockfd, buf, buffersize, &nread); if(CURLE_AGAIN == result) continue; - else if(result) + if(result) break; if(buffersize == nread) { @@ -416,7 +416,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, failf(conn->data, "SOCKS5: no connection here"); return CURLE_COULDNT_CONNECT; } - else if(0 == result) { + if(0 == result) { failf(conn->data, "SOCKS5: connection timeout"); return CURLE_OPERATION_TIMEDOUT; } @@ -457,7 +457,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, failf(conn->data, "SOCKS5 nothing to read"); return CURLE_COULDNT_CONNECT; } - else if(0 == result) { + if(0 == result) { failf(conn->data, "SOCKS5 read timeout"); return CURLE_OPERATION_TIMEDOUT; } @@ -553,7 +553,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, "SOCKS5 GSSAPI per-message authentication is not supported."); return CURLE_COULDNT_CONNECT; } - else if(socksreq[1] == 255) { + if(socksreq[1] == 255) { #endif if(!proxy_name || !*proxy_name) { failf(data, @@ -772,9 +772,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } return CURLE_COULDNT_CONNECT; } - else { - infof(data, "SOCKS5 request granted.\n"); - } + infof(data, "SOCKS5 request granted.\n"); (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ diff --git a/Utilities/cmcurl/lib/speedcheck.c b/Utilities/cmcurl/lib/speedcheck.c index bc15d97..f0daf82 100644 --- a/Utilities/cmcurl/lib/speedcheck.c +++ b/Utilities/cmcurl/lib/speedcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -33,42 +33,41 @@ void Curl_speedinit(struct Curl_easy *data) memset(&data->state.keeps_speed, 0, sizeof(struct timeval)); } +/* + * @unittest: 1606 + */ CURLcode Curl_speedcheck(struct Curl_easy *data, struct timeval now) { - if((data->progress.current_speed >= 0) && - data->set.low_speed_time && - (Curl_tvlong(data->state.keeps_speed) != 0) && - (data->progress.current_speed < data->set.low_speed_limit)) { - time_t howlong = Curl_tvdiff(now, data->state.keeps_speed); - time_t nextcheck = (data->set.low_speed_time * 1000) - howlong; + if((data->progress.current_speed >= 0) && data->set.low_speed_time) { + if(data->progress.current_speed < data->set.low_speed_limit) { + if(!data->state.keeps_speed.tv_sec) + /* under the limit at this very moment */ + data->state.keeps_speed = now; + else { + /* how long has it been under the limit */ + time_t howlong = Curl_tvdiff(now, data->state.keeps_speed); - /* We are now below the "low speed limit". If we are below it - for "low speed time" seconds we consider that enough reason - to abort the download. */ - if(nextcheck <= 0) { - /* we have been this slow for long enough, now die */ - failf(data, - "Operation too slow. " - "Less than %ld bytes/sec transferred the last %ld seconds", - data->set.low_speed_limit, - data->set.low_speed_time); - return CURLE_OPERATION_TIMEDOUT; - } - else { - /* wait complete low_speed_time */ - Curl_expire_latest(data, nextcheck); + if(howlong >= data->set.low_speed_time * 1000) { + /* too long */ + failf(data, + "Operation too slow. " + "Less than %ld bytes/sec transferred the last %ld seconds", + data->set.low_speed_limit, + data->set.low_speed_time); + return CURLE_OPERATION_TIMEDOUT; + } + } } + else + /* faster right now */ + data->state.keeps_speed.tv_sec = 0; } - else { - /* we keep up the required speed all right */ - data->state.keeps_speed = now; - if(data->set.low_speed_limit) - /* if there is a low speed limit enabled, we set the expire timer to - make this connection's speed get checked again no later than when - this time is up */ - Curl_expire_latest(data, data->set.low_speed_time*1000); - } + if(data->set.low_speed_limit) + /* if low speed limit is enabled, set the expire timer to make this + connection's speed get checked again in a second */ + Curl_expire_latest(data, 1000); + return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c index 7aa2e4b..1b301f9 100644 --- a/Utilities/cmcurl/lib/splay.c +++ b/Utilities/cmcurl/lib/splay.c @@ -110,22 +110,17 @@ struct Curl_tree *Curl_splayinsert(struct timeval i, t = Curl_splay(i, t); if(compare(i, t->key)==0) { /* There already exists a node in the tree with the very same key. Build - a linked list of nodes. We make the new 'node' struct the new master - node and make the previous node the first one in the 'same' list. */ + a doubly-linked circular list of nodes. We add the new 'node' struct + to the end of this list. */ - node->same = t; - node->key = i; - node->smaller = t->smaller; - node->larger = t->larger; - - t->smaller = node; /* in the sub node for this same key, we use the - smaller pointer to point back to the master - node */ - - t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED + node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED to quickly identify this node as a subnode */ + node->samen = t; + node->samep = t->samep; + t->samep->samen = node; + t->samep = node; - return node; /* new root node */ + return t; /* the root node always stays the same */ } } @@ -145,16 +140,20 @@ struct Curl_tree *Curl_splayinsert(struct timeval i, } node->key = i; - node->same = NULL; /* no identical node (yet) */ + /* no identical nodes (yet), we are the only one in the list of nodes */ + node->samen = node; + node->samep = node; return node; } /* Finds and deletes the best-fit node from the tree. Return a pointer to the - resulting tree. best-fit means the node with the given or lower key */ + resulting tree. best-fit means the smallest node if it is not larger than + the key */ struct Curl_tree *Curl_splaygetbest(struct timeval i, - struct Curl_tree *t, - struct Curl_tree **removed) + struct Curl_tree *t, + struct Curl_tree **removed) { + static struct timeval tv_zero = {0, 0}; struct Curl_tree *x; if(!t) { @@ -162,49 +161,36 @@ struct Curl_tree *Curl_splaygetbest(struct timeval i, return NULL; } - t = Curl_splay(i, t); + /* find smallest */ + t = Curl_splay(tv_zero, t); if(compare(i, t->key) < 0) { - /* too big node, try the smaller chain */ - if(t->smaller) - t=Curl_splay(t->smaller->key, t); - else { - /* fail */ - *removed = NULL; - return t; - } + /* even the smallest is too big */ + *removed = NULL; + return t; } - if(compare(i, t->key) >= 0) { /* found it */ - /* FIRST! Check if there is a list with identical keys */ - x = t->same; - if(x) { - /* there is, pick one from the list */ + /* FIRST! Check if there is a list with identical keys */ + x = t->samen; + if(x != t) { + /* there is, pick one from the list */ - /* 'x' is the new root node */ + /* 'x' is the new root node */ - x->key = t->key; - x->larger = t->larger; - x->smaller = t->smaller; - - *removed = t; - return x; /* new root */ - } + x->key = t->key; + x->larger = t->larger; + x->smaller = t->smaller; + x->samep = t->samep; + t->samep->samen = x; - if(t->smaller == NULL) { - x = t->larger; - } - else { - x = Curl_splay(i, t->smaller); - x->larger = t->larger; - } *removed = t; - - return x; - } - else { - *removed = NULL; /* no match */ - return t; /* It wasn't there */ + return x; /* new root */ } + + /* we splayed the tree to the smallest element, there is no smaller */ + x = t->larger; + *removed = t; + + return x; } @@ -231,19 +217,17 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, if(compare(KEY_NOTUSED, removenode->key) == 0) { /* Key set to NOTUSED means it is a subnode within a 'same' linked list - and thus we can unlink it easily. The 'smaller' link of a subnode - links to the parent node. */ - if(removenode->smaller == NULL) + and thus we can unlink it easily. */ + if(removenode->samen == removenode) + /* A non-subnode should never be set to KEY_NOTUSED */ return 3; - removenode->smaller->same = removenode->same; - if(removenode->same) - removenode->same->smaller = removenode->smaller; + removenode->samep->samen = removenode->samen; + removenode->samen->samep = removenode->samep; /* Ensures that double-remove gets caught. */ - removenode->smaller = NULL; + removenode->samen = removenode; - /* voila, we're done! */ *newroot = t; /* return the same root */ return 0; } @@ -262,14 +246,16 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, /* Check if there is a list with identical sizes, as then we're trying to remove the root node of a list of nodes with identical keys. */ - x = t->same; - if(x) { + x = t->samen; + if(x != t) { /* 'x' is the new root node, we just make it use the root node's smaller/larger links */ x->key = t->key; x->larger = t->larger; x->smaller = t->smaller; + x->samep = t->samep; + t->samep->samen = x; } else { /* Remove the root node */ diff --git a/Utilities/cmcurl/lib/splay.h b/Utilities/cmcurl/lib/splay.h index 427bfc8..da81894 100644 --- a/Utilities/cmcurl/lib/splay.h +++ b/Utilities/cmcurl/lib/splay.h @@ -26,7 +26,8 @@ struct Curl_tree { struct Curl_tree *smaller; /* smaller node */ struct Curl_tree *larger; /* larger node */ - struct Curl_tree *same; /* points to a node with identical key */ + struct Curl_tree *samen; /* points to the next node with identical key */ + struct Curl_tree *samep; /* points to the prev node with identical key */ struct timeval key; /* this node's "sort" key */ void *payload; /* data the splay code doesn't care about */ }; diff --git a/Utilities/cmcurl/lib/ssh.c b/Utilities/cmcurl/lib/ssh.c index 5ed036a..72fa06a 100644 --- a/Utilities/cmcurl/lib/ssh.c +++ b/Utilities/cmcurl/lib/ssh.c @@ -688,14 +688,11 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } - else { - infof(data, "MD5 checksum match!\n"); - /* as we already matched, we skip the check for known hosts */ - return CURLE_OK; - } + infof(data, "MD5 checksum match!\n"); + /* as we already matched, we skip the check for known hosts */ + return CURLE_OK; } - else - return ssh_knownhost(conn); + return ssh_knownhost(conn); } /* @@ -738,7 +735,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + if(rc) { failf(data, "Failure establishing ssh session"); state(conn, SSH_SESSION_FREE); sshc->actualcode = CURLE_FAILED_INIT; @@ -782,16 +779,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_AUTH_DONE); break; } + err = libssh2_session_last_errno(sshc->ssh_session); + if(err == LIBSSH2_ERROR_EAGAIN) + rc = LIBSSH2_ERROR_EAGAIN; else { - err = libssh2_session_last_errno(sshc->ssh_session); - if(err == LIBSSH2_ERROR_EAGAIN) - rc = LIBSSH2_ERROR_EAGAIN; - else { - state(conn, SSH_SESSION_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(err); - } - break; + state(conn, SSH_SESSION_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(err); } + break; } infof(data, "SSH authentication methods available: %s\n", sshc->authlist); @@ -918,6 +913,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) &err_msg, NULL, 0); infof(data, "SSH public key authentication failed: %s\n", err_msg); state(conn, SSH_AUTH_PASS_INIT); + rc = 0; /* clear rc and continue */ } break; @@ -928,6 +924,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else { state(conn, SSH_AUTH_HOST_INIT); + rc = 0; /* clear rc and continue */ } break; @@ -940,7 +937,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc == 0) { + if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized password authentication\n"); state(conn, SSH_AUTH_DONE); @@ -989,6 +986,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc < 0) { infof(data, "Failure connecting to agent\n"); state(conn, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ } else { state(conn, SSH_AUTH_AGENT_LIST); @@ -1008,6 +1006,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc < 0) { infof(data, "Failure requesting identities to agent\n"); state(conn, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ } else { state(conn, SSH_AUTH_AGENT); @@ -1077,7 +1076,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc == 0) { + if(rc == 0) { sshc->authed = TRUE; infof(data, "Initialized keyboard interactive authentication\n"); } @@ -1116,21 +1115,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) */ sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session); if(!sshc->sftp_session) { + char *err_msg; if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } - else { - char *err_msg; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - failf(data, "Failure initializing sftp session: %s", err_msg); - state(conn, SSH_SESSION_FREE); - sshc->actualcode = CURLE_FAILED_INIT; - break; - } + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + failf(data, "Failure initializing sftp session: %s", err_msg); + state(conn, SSH_SESSION_FREE); + sshc->actualcode = CURLE_FAILED_INIT; + break; } state(conn, SSH_SFTP_REALPATH); break; @@ -1147,7 +1144,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc > 0) { + if(rc > 0) { /* It seems that this string is not always NULL terminated */ tempHome[rc] = '\0'; sshc->homedir = strdup(tempHome); @@ -1261,7 +1258,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_NEXT_QUOTE); break; } - else if(cmd) { + if(cmd) { /* * the arguments following the command must be separated from the * command with a space so we can check for it unconditionally @@ -1321,7 +1318,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_STAT); break; } - else if(strncasecompare(cmd, "ln ", 3) || + if(strncasecompare(cmd, "ln ", 3) || strncasecompare(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ @@ -1443,7 +1440,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { /* get those attributes */ + if(rc != 0 && !sshc->acceptfail) { /* get those attributes */ err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1514,7 +1511,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1537,7 +1534,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1558,7 +1555,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err)); @@ -1582,7 +1579,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); @@ -1601,7 +1598,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err)); @@ -1619,7 +1616,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", sftp_libssh2_strerror(err)); @@ -1642,7 +1639,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc != 0 && !sshc->acceptfail) { + if(rc != 0 && !sshc->acceptfail) { err = sftp_libssh2_last_error(sshc->sftp_session); Curl_safefree(sshc->quote_path1); failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err)); @@ -1705,7 +1702,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc == 0) { + if(rc == 0) { data->info.filetime = (long)attrs.mtime; } @@ -1743,7 +1740,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + if(rc) { data->state.resume_from = 0; } else { @@ -1778,47 +1775,47 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(LIBSSH2_ERROR_EAGAIN == rc) break; - else { - if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) - /* only when there was an SFTP protocol error can we extract - the sftp error! */ - err = sftp_libssh2_last_error(sshc->sftp_session); - else - err = -1; /* not an sftp error at all */ - if(sshc->secondCreateDirs) { - state(conn, SSH_SFTP_CLOSE); - sshc->actualcode = err>= LIBSSH2_FX_OK? - sftp_libssh2_error_to_CURLE(err):CURLE_SSH; - failf(data, "Creating the dir/file failed: %s", - sftp_libssh2_strerror(err)); - break; - } - else if(((err == LIBSSH2_FX_NO_SUCH_FILE) || - (err == LIBSSH2_FX_FAILURE) || - (err == LIBSSH2_FX_NO_SUCH_PATH)) && - (data->set.ftp_create_missing_dirs && - (strlen(sftp_scp->path) > 1))) { - /* try to create the path remotely */ - sshc->secondCreateDirs = 1; - state(conn, SSH_SFTP_CREATE_DIRS_INIT); - break; - } + if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc) + /* only when there was an SFTP protocol error can we extract + the sftp error! */ + err = sftp_libssh2_last_error(sshc->sftp_session); + else + err = -1; /* not an sftp error at all */ + + if(sshc->secondCreateDirs) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = err>= LIBSSH2_FX_OK? sftp_libssh2_error_to_CURLE(err):CURLE_SSH; - if(!sshc->actualcode) { - /* Sometimes, for some reason libssh2_sftp_last_error() returns - zero even though libssh2_sftp_open() failed previously! We need - to work around that! */ - sshc->actualcode = CURLE_SSH; - err=-1; - } - failf(data, "Upload failed: %s (%d/%d)", - err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error", - err, rc); + failf(data, "Creating the dir/file failed: %s", + sftp_libssh2_strerror(err)); + break; + } + if(((err == LIBSSH2_FX_NO_SUCH_FILE) || + (err == LIBSSH2_FX_FAILURE) || + (err == LIBSSH2_FX_NO_SUCH_PATH)) && + (data->set.ftp_create_missing_dirs && + (strlen(sftp_scp->path) > 1))) { + /* try to create the path remotely */ + rc = 0; /* clear rc and continue */ + sshc->secondCreateDirs = 1; + state(conn, SSH_SFTP_CREATE_DIRS_INIT); break; } + state(conn, SSH_SFTP_CLOSE); + sshc->actualcode = err>= LIBSSH2_FX_OK? + sftp_libssh2_error_to_CURLE(err):CURLE_SSH; + if(!sshc->actualcode) { + /* Sometimes, for some reason libssh2_sftp_last_error() returns + zero even though libssh2_sftp_open() failed previously! We need + to work around that! */ + sshc->actualcode = CURLE_SSH; + err=-1; + } + failf(data, "Upload failed: %s (%d/%d)", + err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error", + err, rc); + break; } /* If we have a restart point then we need to seek to the correct @@ -1831,32 +1828,30 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed=0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); return CURLE_FTP_COULDNT_USE_REST; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */ - else { - curl_off_t passed=0; - do { - size_t readthisamountnow = - (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? - BUFSIZE : curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread = - data->state.fread_func(data->state.buffer, 1, - readthisamountnow, data->state.in); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } + do { + size_t readthisamountnow = + (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ? + BUFSIZE : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread = + data->state.fread_func(data->state.buffer, 1, + readthisamountnow, data->state.in); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); } /* now, decrease the size of the read */ @@ -1921,9 +1916,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_CREATE_DIRS_MKDIR); break; } - else { - state(conn, SSH_SFTP_UPLOAD_INIT); - } + state(conn, SSH_SFTP_UPLOAD_INIT); break; case SSH_SFTP_CREATE_DIRS_MKDIR: @@ -1936,7 +1929,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } *sshc->slash_pos = '/'; ++sshc->slash_pos; - if(rc == -1) { + if(rc < 0) { /* * Abort if failure wasn't that the dir already exists or the * permission was denied (creation might succeed further down the @@ -1951,6 +1944,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = result?result:CURLE_SSH; break; } + rc = 0; /* clear rc and continue */ } state(conn, SSH_SFTP_CREATE_DIRS); break; @@ -1977,15 +1971,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) rc = LIBSSH2_ERROR_EAGAIN; break; } - else { - err = sftp_libssh2_last_error(sshc->sftp_session); - failf(data, "Could not open directory for reading: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; - break; - } + err = sftp_libssh2_last_error(sshc->sftp_session); + failf(data, "Could not open directory for reading: %s", + sftp_libssh2_strerror(err)); + state(conn, SSH_SFTP_CLOSE); + result = sftp_libssh2_error_to_CURLE(err); + sshc->actualcode = result?result:CURLE_SSH; + break; } sshc->readdir_filename = malloc(PATH_MAX+1); if(!sshc->readdir_filename) { @@ -2192,15 +2184,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) rc = LIBSSH2_ERROR_EAGAIN; break; } - else { - err = sftp_libssh2_last_error(sshc->sftp_session); - failf(data, "Could not open remote file for reading: %s", - sftp_libssh2_strerror(err)); - state(conn, SSH_SFTP_CLOSE); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; - break; - } + err = sftp_libssh2_last_error(sshc->sftp_session); + failf(data, "Could not open remote file for reading: %s", + sftp_libssh2_strerror(err)); + state(conn, SSH_SFTP_CLOSE); + result = sftp_libssh2_error_to_CURLE(err); + sshc->actualcode = result?result:CURLE_SSH; + break; } state(conn, SSH_SFTP_DOWNLOAD_STAT); break; @@ -2215,7 +2205,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc || + if(rc || !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) || (attrs.filesize == 0)) { /* @@ -2313,18 +2303,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_STOP); break; } - else { - Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size, - FALSE, NULL, -1, NULL); + Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size, + FALSE, NULL, -1, NULL); - /* not set by Curl_setup_transfer to preserve keepon bits */ - conn->writesockfd = conn->sockfd; + /* not set by Curl_setup_transfer to preserve keepon bits */ + conn->writesockfd = conn->sockfd; + + /* we want to use the _receiving_ function even when the socket turns + out writableable as the underlying libssh2 recv function will deal + with both accordingly */ + conn->cselect_bits = CURL_CSELECT_IN; - /* we want to use the _receiving_ function even when the socket turns - out writableable as the underlying libssh2 recv function will deal - with both accordingly */ - conn->cselect_bits = CURL_CSELECT_IN; - } if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ @@ -2342,7 +2331,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to close libssh2 file\n"); } sshc->sftp_handle = NULL; @@ -2376,7 +2365,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to close libssh2 file\n"); } sshc->sftp_handle = NULL; @@ -2386,7 +2375,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to stop libssh2 sftp subsystem\n"); } sshc->sftp_session = NULL; @@ -2431,22 +2420,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms, data->state.infilesize); if(!sshc->ssh_channel) { + int ssh_err; + char *err_msg; + if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } - else { - int ssh_err; - char *err_msg; - ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0)); - failf(conn->data, "%s", err_msg); - state(conn, SSH_SCP_CHANNEL_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); - break; - } + ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0)); + failf(conn->data, "%s", err_msg); + state(conn, SSH_SCP_CHANNEL_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); + break; } /* upload data */ @@ -2501,22 +2489,22 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) #endif if(!sshc->ssh_channel) { + int ssh_err; + char *err_msg; + if(libssh2_session_last_errno(sshc->ssh_session) == LIBSSH2_ERROR_EAGAIN) { rc = LIBSSH2_ERROR_EAGAIN; break; } - else { - int ssh_err; - char *err_msg; - ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0)); - failf(conn->data, "%s", err_msg); - state(conn, SSH_SCP_CHANNEL_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); - break; - } + + ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0)); + failf(conn->data, "%s", err_msg); + state(conn, SSH_SCP_CHANNEL_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err); + break; } /* download data */ @@ -2554,7 +2542,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + if(rc) { infof(data, "Failed to send libssh2 channel EOF\n"); } } @@ -2567,7 +2555,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + if(rc) { infof(data, "Failed to get channel EOF: %d\n", rc); } } @@ -2580,7 +2568,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc) { + if(rc) { infof(data, "Channel failed to close: %d\n", rc); } } @@ -2593,7 +2581,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to free libssh2 scp subsystem\n"); } sshc->ssh_channel = NULL; @@ -2615,7 +2603,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to free libssh2 scp subsystem\n"); } sshc->ssh_channel = NULL; @@ -2626,7 +2614,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to disconnect libssh2 session\n"); } } @@ -2651,7 +2639,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to disconnect from libssh2 agent\n"); } libssh2_agent_free(sshc->ssh_agent); @@ -2669,7 +2657,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc == LIBSSH2_ERROR_EAGAIN) { break; } - else if(rc < 0) { + if(rc < 0) { infof(data, "Failed to free libssh2 session\n"); } sshc->ssh_session = NULL; @@ -2834,7 +2822,8 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, while((sshc->state != SSH_STOP) && !result) { bool block; - long left; + time_t left; + struct timeval now = Curl_tvnow(); result = ssh_statemach_act(conn, &block); if(result) @@ -2842,12 +2831,10 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, if(Curl_pgrsUpdate(conn)) return CURLE_ABORTED_BY_CALLBACK; - else { - struct timeval now = Curl_tvnow(); - result = Curl_speedcheck(data, now); - if(result) - break; - } + + result = Curl_speedcheck(data, now); + if(result) + break; left = Curl_timeleft(data, NULL, duringconnect); if(left < 0) { diff --git a/Utilities/cmcurl/lib/strcase.c b/Utilities/cmcurl/lib/strcase.c index a750f7b..a74a4be 100644 --- a/Utilities/cmcurl/lib/strcase.c +++ b/Utilities/cmcurl/lib/strcase.c @@ -125,9 +125,9 @@ int Curl_safe_strcasecompare(const char *first, const char *second) if(first && second) /* both pointers point to something then compare them */ return Curl_strcasecompare(first, second); - else - /* if both pointers are NULL then treat them as equal */ - return (NULL == first && NULL == second); + + /* if both pointers are NULL then treat them as equal */ + return (NULL == first && NULL == second); } /* diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c index 7873759..cfbbf32 100644 --- a/Utilities/cmcurl/lib/system_win32.c +++ b/Utilities/cmcurl/lib/system_win32.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2016 - 2017, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -68,7 +68,7 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); * * majorVersion [in] - The major version number. * minorVersion [in] - The minor version number. - * platform [in] - The optional platform identifer. + * platform [in] - The optional platform identifier. * condition [in] - The test condition used to specifier whether we are * checking a version less then, equal to or greater than * what is specified in the major and minor version diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index 551af60..5cceed2 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -872,7 +872,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) continue; } - /* Window Size */ + /* Window Size */ if(strcasecompare(option_keyword, "WS")) { if(sscanf(option_arg, "%hu%*[xX]%hu", &tn->subopt_wsx, &tn->subopt_wsy) == 2) @@ -899,11 +899,9 @@ static CURLcode check_telnet_options(struct connectdata *conn) result = CURLE_UNKNOWN_TELNET_OPTION; break; } - else { - failf(data, "Syntax error in telnet option: %s", head->data); - result = CURLE_TELNET_OPTION_SYNTAX; - break; - } + failf(data, "Syntax error in telnet option: %s", head->data); + result = CURLE_TELNET_OPTION_SYNTAX; + break; } if(result) { @@ -1016,7 +1014,7 @@ static void sendsuboption(struct connectdata *conn, int option) CURL_SB_ACCUM(tn, CURL_IAC); CURL_SB_ACCUM(tn, CURL_SB); CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS); - /* We must deal either with litte or big endien processors */ + /* We must deal either with litte or big endian processors */ /* Window size must be sent according to the 'network order' */ x=htons(tn->subopt_wsx); y=htons(tn->subopt_wsy); @@ -1186,7 +1184,7 @@ CURLcode telrcv(struct connectdata *conn, * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get - * into an infinate loop here. So, instead, we terminate the + * into an infinite loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); @@ -1326,7 +1324,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) #ifdef USE_WINSOCK /* ** This functionality only works with WinSock >= 2.0. So, - ** make sure have it. + ** make sure we have it. */ result = check_wsock2(data); if(result) @@ -1416,28 +1414,29 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* Keep on listening and act on events */ while(keepon) { + const DWORD buf_size = (DWORD)CURL_BUFSIZE(data->set.buffer_size); waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); switch(waitret) { case WAIT_TIMEOUT: { for(;;) { if(data->set.is_fread_set) { + size_t n; /* read from user-supplied method */ - result = (int)data->state.fread_func(buf, 1, BUFSIZE - 1, - data->state.in); - if(result == CURL_READFUNC_ABORT) { + n = data->state.fread_func(buf, 1, BUFSIZE - 1, data->state.in); + if(n == CURL_READFUNC_ABORT) { keepon = FALSE; result = CURLE_READ_ERROR; break; } - if(result == CURL_READFUNC_PAUSE) + if(n == CURL_READFUNC_PAUSE) break; - if(result == 0) /* no bytes */ + if(n == 0) /* no bytes */ break; - readfile_read = result; /* fall thru with number of bytes read */ + readfile_read = (DWORD)n; /* fall thru with number of bytes read */ } else { /* read from stdin */ @@ -1451,7 +1450,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(!readfile_read) break; - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1470,7 +1469,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_OBJECT_0 + 1: { - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1593,7 +1592,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(result == CURLE_AGAIN) break; /* returned not-zero, this an error */ - else if(result) { + if(result) { keepon = FALSE; break; } diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c index f2f8347..098b1bb 100644 --- a/Utilities/cmcurl/lib/tftp.c +++ b/Utilities/cmcurl/lib/tftp.c @@ -359,7 +359,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, failf(data, "invalid blocksize value in OACK packet"); return CURLE_TFTP_ILLEGAL; } - else if(blksize > TFTP_BLKSIZE_MAX) { + if(blksize > TFTP_BLKSIZE_MAX) { failf(data, "%s (%d)", "blksize is larger than max supported", TFTP_BLKSIZE_MAX); return CURLE_TFTP_ILLEGAL; @@ -1189,7 +1189,7 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event) state->state = TFTP_STATE_FIN; return 0; } - else if(current > state->rx_time+state->retry_time) { + if(current > state->rx_time+state->retry_time) { if(event) *event = TFTP_EVENT_TIMEOUT; time(&state->rx_time); /* update even though we received nothing */ @@ -1223,7 +1223,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) failf(data, "TFTP response timeout"); return CURLE_OPERATION_TIMEDOUT; } - else if(event != TFTP_EVENT_NONE) { + if(event != TFTP_EVENT_NONE) { result = tftp_state_machine(state, event); if(result) return result; diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c index f3b207a..0d6036b 100644 --- a/Utilities/cmcurl/lib/timeval.c +++ b/Utilities/cmcurl/lib/timeval.c @@ -139,8 +139,7 @@ double curlx_tvdiff_secs(struct timeval newer, struct timeval older) if(newer.tv_sec != older.tv_sec) return (double)(newer.tv_sec-older.tv_sec)+ (double)(newer.tv_usec-older.tv_usec)/1000000.0; - else - return (double)(newer.tv_usec-older.tv_usec)/1000000.0; + return (double)(newer.tv_usec-older.tv_usec)/1000000.0; } /* return the number of seconds in the given input timeval struct */ diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index 750fb04..1f6d26d 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -117,7 +117,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) *nreadp = 0; return CURLE_ABORTED_BY_CALLBACK; } - else if(nread == CURL_READFUNC_PAUSE) { + if(nread == CURL_READFUNC_PAUSE) { + struct SingleRequest *k = &data->req; if(conn->handler->flags & PROTOPT_NONETWORK) { /* protocols that work without network cannot be paused. This is @@ -126,16 +127,15 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) failf(data, "Read callback asked for PAUSE when not supported!"); return CURLE_READ_ERROR; } - else { - struct SingleRequest *k = &data->req; - /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ - k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ - if(data->req.upload_chunky) { + + /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ + k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ + if(data->req.upload_chunky) { /* Back out the preallocation done above */ - data->req.upload_fromhere -= (8 + 2); - } - *nreadp = 0; + data->req.upload_fromhere -= (8 + 2); } + *nreadp = 0; + return CURLE_OK; /* nothing was read */ } else if((size_t)nread > buffersize) { @@ -642,7 +642,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res)); return CURLE_RECV_ERROR; } - else if(CHUNKE_STOP == res) { + if(CHUNKE_STOP == res) { size_t dataleft; /* we're done reading chunks! */ k->keepon &= ~KEEP_RECV; /* read no more */ @@ -918,7 +918,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data, /* this is a paused transfer */ break; } - else if(nread<=0) { + if(nread<=0) { result = done_sending(conn, k); if(result) return result; @@ -1192,7 +1192,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, k->size - k->bytecount); return CURLE_PARTIAL_FILE; } - else if(!(data->set.opt_no_body) && + if(!(data->set.opt_no_body) && k->chunk && (conn->chunk.state != CHUNK_STOP)) { /* @@ -1356,13 +1356,12 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) if(data->set.wildcardmatch) { struct WildcardData *wc = &data->wildcard; - if(!wc->filelist) { + if(wc->state < CURLWC_INIT) { result = Curl_wildcard_init(wc); /* init wildcard structures */ if(result) return CURLE_OUT_OF_MEMORY; } } - } return result; @@ -1795,7 +1794,7 @@ CURLcode Curl_follow(struct Curl_easy *data, break; case 303: /* See Other */ - /* Disable both types of POSTs, unless the user explicitely + /* Disable both types of POSTs, unless the user explicitly asks for POST after POST */ if(data->set.httpreq != HTTPREQ_GET && !(data->set.keep_post & CURL_REDIR_POST_303)) { @@ -1843,12 +1842,17 @@ CURLcode Curl_retry_request(struct connectdata *conn, return CURLE_OK; if((data->req.bytecount + data->req.headerbytecount == 0) && - conn->bits.reuse && - (data->set.rtspreq != RTSPREQ_RECEIVE)) { - /* We didn't get a single byte when we attempted to re-use a - connection. This might happen if the connection was left alive when we - were done using it before, but that was closed when we wanted to use it - again. Bad luck. Retry the same request on a fresh connect! */ + conn->bits.reuse && + (!data->set.opt_no_body + || (conn->handler->protocol & PROTO_FAMILY_HTTP)) && + (data->set.rtspreq != RTSPREQ_RECEIVE)) { + /* We got no data, we attempted to re-use a connection. For HTTP this + can be a retry so we try again regardless if we expected a body. + For other protocols we only try again only if we expected a body. + + This might happen if the connection was left alive when we were + done using it before, but that was closed when we wanted to read from + it again. Bad luck. Retry the same request on a fresh connect! */ infof(conn->data, "Connection died, retrying a fresh connect\n"); *url = strdup(conn->data->change.url); if(!*url) diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index 7944d7b..caa28f5 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -411,10 +411,7 @@ CURLcode Curl_close(struct Curl_easy *data) /* Destroy the timeout list that is held in the easy handle. It is /normally/ done by curl_multi_remove_handle() but this is "just in case" */ - if(data->state.timeoutlist) { - Curl_llist_destroy(data->state.timeoutlist, NULL); - data->state.timeoutlist = NULL; - } + Curl_llist_destroy(&data->state.timeoutlist, NULL); data->magic = 0; /* force a clear AFTER the possibly enforced removal from the multi handle, since that function uses the magic @@ -452,6 +449,7 @@ CURLcode Curl_close(struct Curl_easy *data) } data->change.url = NULL; + Curl_safefree(data->state.buffer); Curl_safefree(data->state.headerbuff); Curl_flush_cookies(data, 1); @@ -548,7 +546,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) #endif set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth type */ - set->general_ssl.sessionid = TRUE; /* session ID caching enabled by + set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by default */ set->proxy_ssl = set->ssl; @@ -576,14 +574,19 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); if(result) return result; + + result = setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE); + if(result) + return result; #endif #if defined(CURL_CA_PATH) result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); if(result) return result; - result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], - (char *) CURL_CA_PATH); + result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); + if(result) + return result; #endif set->wildcardmatch = FALSE; @@ -641,6 +644,12 @@ CURLcode Curl_open(struct Curl_easy **curl) /* We do some initial setup here, all those fields that can't be just 0 */ + data->state.buffer = malloc(BUFSIZE + 1); + if(!data->state.buffer) { + DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n")); + result = CURLE_OUT_OF_MEMORY; + } + data->state.headerbuff = malloc(HEADERSIZE); if(!data->state.headerbuff) { DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); @@ -660,9 +669,6 @@ CURLcode Curl_open(struct Curl_easy **curl) data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ - - data->wildcard.state = CURLWC_INIT; - data->wildcard.filelist = NULL; data->set.fnmatch = ZERO_NULL; data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ @@ -671,6 +677,7 @@ CURLcode Curl_open(struct Curl_easy **curl) if(result) { Curl_resolver_cleanup(data->state.resolver); + free(data->state.buffer); free(data->state.headerbuff); Curl_freeset(data); free(data); @@ -682,6 +689,9 @@ CURLcode Curl_open(struct Curl_easy **curl) return result; } +#define C_SSLVERSION_VALUE(x) (x & 0xffff) +#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) + CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, va_list param) { @@ -914,7 +924,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * implementations are lame. */ #ifdef USE_SSL - data->set.ssl.primary.version = va_arg(param, long); + arg = va_arg(param, long); + data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg); + data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg); #else result = CURLE_UNKNOWN_OPTION; #endif @@ -925,7 +937,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, * implementations are lame. */ #ifdef USE_SSL - data->set.proxy_ssl.primary.version = va_arg(param, long); + arg = va_arg(param, long); + data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg); + data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg); #else result = CURLE_UNKNOWN_OPTION; #endif @@ -2217,8 +2231,12 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, /* This does not work on windows. */ result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif break; case CURLOPT_PROXY_CAPATH: +#ifdef have_curlssl_ca_path /* not supported by all backends */ /* * Set CA path info for SSL connection proxy. Specify directory name of the * CA certificates which have been prepared using openssl c_rehash utility. @@ -2268,9 +2286,20 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, */ data->set.buffer_size = va_arg(param, long); - if((data->set.buffer_size> (BUFSIZE -1)) || - (data->set.buffer_size < 1)) - data->set.buffer_size = 0; /* huge internal default */ + if(data->set.buffer_size > MAX_BUFSIZE) + data->set.buffer_size = MAX_BUFSIZE; /* huge internal default */ + else if(data->set.buffer_size < 1) + data->set.buffer_size = BUFSIZE; + + /* Resize only if larger than default buffer size. */ + if(data->set.buffer_size > BUFSIZE) { + data->state.buffer = realloc(data->state.buffer, + data->set.buffer_size + 1); + if(!data->state.buffer) { + DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); + result = CURLE_OUT_OF_MEMORY; + } + } break; @@ -2470,8 +2499,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.general_ssl.sessionid = (0 != va_arg(param, long)) ? + data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid; break; #ifdef USE_LIBSSH2 @@ -2814,6 +2844,12 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: + data->set.abstract_unix_socket = FALSE; + result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; + case CURLOPT_ABSTRACT_UNIX_SOCKET: + data->set.abstract_unix_socket = TRUE; result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], va_arg(param, char *)); break; @@ -2853,6 +2889,9 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, case CURLOPT_CONNECT_TO: data->set.connect_to = va_arg(param, struct curl_slist *); break; + case CURLOPT_SUPPRESS_CONNECT_HEADERS: + data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE; + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; @@ -2957,11 +2996,8 @@ static void conn_free(struct connectdata *conn) conn_reset_all_postponed_data(conn); - Curl_llist_destroy(conn->send_pipe, NULL); - Curl_llist_destroy(conn->recv_pipe, NULL); - - conn->send_pipe = NULL; - conn->recv_pipe = NULL; + Curl_llist_destroy(&conn->send_pipe, NULL); + Curl_llist_destroy(&conn->recv_pipe, NULL); Curl_safefree(conn->localdev); Curl_free_primary_ssl_config(&conn->ssl_config); @@ -3001,9 +3037,9 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) * are other users of it */ if(!conn->bits.close && - (conn->send_pipe->size + conn->recv_pipe->size)) { + (conn->send_pipe.size + conn->recv_pipe.size)) { DEBUGF(infof(data, "Curl_disconnect, usecounter: %d\n", - conn->send_pipe->size + conn->recv_pipe->size)); + conn->send_pipe.size + conn->recv_pipe.size)); return CURLE_OK; } @@ -3029,7 +3065,6 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) free_fixed_hostname(&conn->host); free_fixed_hostname(&conn->conn_to_host); - free_fixed_hostname(&conn->proxy); free_fixed_hostname(&conn->http_proxy.host); free_fixed_hostname(&conn->socks_proxy.host); @@ -3037,8 +3072,8 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) /* Indicate to all handles on the pipe that we're dead */ if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) { - signalPipeClose(conn->send_pipe, TRUE); - signalPipeClose(conn->recv_pipe, TRUE); + signalPipeClose(&conn->send_pipe, TRUE); + signalPipeClose(&conn->recv_pipe, TRUE); } conn_free(conn); @@ -3143,9 +3178,9 @@ void Curl_getoff_all_pipelines(struct Curl_easy *data, bool send_head = (conn->writechannel_inuse && Curl_sendpipe_head(data, conn)); - if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head) + if(Curl_removeHandleFromPipeline(data, &conn->recv_pipe) && recv_head) Curl_pipeline_leave_read(conn); - if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head) + if(Curl_removeHandleFromPipeline(data, &conn->send_pipe) && send_head) Curl_pipeline_leave_write(conn); } @@ -3206,7 +3241,7 @@ Curl_oldest_idle_connection(struct Curl_easy *data) bundle = he->ptr; - curr = bundle->conn_list->head; + curr = bundle->conn_list.head; while(curr) { conn = curr->ptr; @@ -3234,9 +3269,7 @@ proxy_info_matches(const struct proxy_info* data, { if((data->proxytype == needle->proxytype) && (data->port == needle->port) && - Curl_safe_strcasecompare(data->host.name, needle->host.name) && - Curl_safe_strcasecompare(data->user, needle->user) && - Curl_safe_strcasecompare(data->passwd, needle->passwd)) + Curl_safe_strcasecompare(data->host.name, needle->host.name)) return TRUE; return FALSE; @@ -3265,7 +3298,7 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data, now = Curl_tvnow(); - curr = bundle->conn_list->head; + curr = bundle->conn_list.head; while(curr) { conn = curr->ptr; @@ -3293,7 +3326,7 @@ find_oldest_idle_connection_in_bundle(struct Curl_easy *data, static bool disconnect_if_dead(struct connectdata *conn, struct Curl_easy *data) { - size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size; + size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size; if(!pipeLen && !conn->inuse) { /* The check for a dead socket makes sense only if there are no handles in pipeline and the connection isn't already marked in @@ -3406,19 +3439,14 @@ ConnectionExists(struct Curl_easy *data, max_pipeline_length(data->multi):0; size_t best_pipe_len = max_pipe_len; struct curl_llist_element *curr; - const char *hostname; - - if(needle->bits.conn_to_host) - hostname = needle->conn_to_host.name; - else - hostname = needle->host.name; infof(data, "Found bundle for host %s: %p [%s]\n", - hostname, (void *)bundle, - (bundle->multiuse== BUNDLE_PIPELINING? - "can pipeline": - (bundle->multiuse== BUNDLE_MULTIPLEX? - "can multiplex":"serially"))); + (needle->bits.conn_to_host ? needle->conn_to_host.name : + needle->host.name), (void *)bundle, + (bundle->multiuse == BUNDLE_PIPELINING ? + "can pipeline" : + (bundle->multiuse == BUNDLE_MULTIPLEX ? + "can multiplex" : "serially"))); /* We can't pipe if we don't know anything about the server */ if(canPipeline) { @@ -3445,7 +3473,7 @@ ConnectionExists(struct Curl_easy *data, } } - curr = bundle->conn_list->head; + curr = bundle->conn_list.head; while(curr) { bool match = FALSE; size_t pipeLen; @@ -3460,7 +3488,7 @@ ConnectionExists(struct Curl_easy *data, if(disconnect_if_dead(check, data)) continue; - pipeLen = check->send_pipe->size + check->recv_pipe->size; + pipeLen = check->send_pipe.size + check->recv_pipe.size; if(canPipeline) { if(check->bits.protoconnstart && check->bits.close) @@ -3468,8 +3496,8 @@ ConnectionExists(struct Curl_easy *data, if(!check->bits.multiplex) { /* If not multiplexing, make sure the pipe has only GET requests */ - struct Curl_easy* sh = gethandleathead(check->send_pipe); - struct Curl_easy* rh = gethandleathead(check->recv_pipe); + struct Curl_easy* sh = gethandleathead(&check->send_pipe); + struct Curl_easy* rh = gethandleathead(&check->recv_pipe); if(sh) { if(!IsPipeliningPossible(sh, check)) continue; @@ -3507,7 +3535,7 @@ ConnectionExists(struct Curl_easy *data, infof(data, "Connection #%ld isn't open enough, can't reuse\n", check->connection_id); #ifdef DEBUGBUILD - if(check->recv_pipe->size > 0) { + if(check->recv_pipe.size > 0) { infof(data, "BAD! Unconnected #%ld has a non-empty recv pipeline!\n", check->connection_id); @@ -3523,6 +3551,8 @@ ConnectionExists(struct Curl_easy *data, continue; if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) continue; + if(needle->abstract_unix_socket != check->abstract_unix_socket) + continue; } else if(check->unix_domain_socket) continue; @@ -3644,7 +3674,7 @@ ConnectionExists(struct Curl_easy *data, check->connection_id)); continue; } - else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { + if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) { foundPendingCandidate = TRUE; DEBUGF(infof(data, "Connection #%ld has not started SSL connect, " @@ -3797,17 +3827,19 @@ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex) if(conn->bits.socksproxy) { #ifndef CURL_DISABLE_PROXY - const char * const host = conn->bits.conn_to_host ? - conn->conn_to_host.name : - conn->bits.httpproxy ? + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + const char * const host = conn->bits.httpproxy ? conn->http_proxy.host.name : + conn->bits.conn_to_host ? + conn->conn_to_host.name : sockindex == SECONDARYSOCKET ? conn->secondaryhostname : conn->host.name; - const int port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->bits.httpproxy ? - (int)conn->http_proxy.port : - sockindex == SECONDARYSOCKET ? - conn->secondary_port : conn->remote_port; + const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port : + sockindex == SECONDARYSOCKET ? conn->secondary_port : + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; conn->bits.socksproxy_connecting = TRUE; switch(conn->socks_proxy.proxytype) { case CURLPROXY_SOCKS5: @@ -3845,7 +3877,8 @@ void Curl_verboseconnect(struct connectdata *conn) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", conn->bits.socksproxy ? conn->socks_proxy.host.dispname : conn->bits.httpproxy ? conn->http_proxy.host.dispname : - conn->host.dispname, + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname, conn->ip_addr_str, conn->port, conn->connection_id); } #endif @@ -3968,7 +4001,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, } /* - * Helpers for IDNA convertions. + * Helpers for IDNA conversions. */ static bool is_ASCII_name(const char *hostname) { @@ -4010,7 +4043,15 @@ static void fix_hostname(struct connectdata *conn, struct hostname *host) #ifdef USE_LIBIDN2 if(idn2_check_version(IDN2_VERSION)) { char *ace_hostname = NULL; - int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, 0); +#if IDN2_VERSION_NUMBER >= 0x00140000 + /* IDN2_NFC_INPUT: Normalize input string using normalization form C. + IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional + processing. */ + int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL; +#else + int flags = IDN2_NFC_INPUT; +#endif + int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags); if(rc == IDN2_OK) { host->encalloc = (char *)ace_hostname; /* change the name pointer to point to the encoded hostname */ @@ -4084,7 +4125,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */ conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ - conn->remote_port = -1; /* unknown */ + conn->remote_port = -1; /* unknown at this point */ #if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ @@ -4141,8 +4182,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; + conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; + conn->proxy_ssl_config.verifystatus = + data->set.proxy_ssl.primary.verifystatus; conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; @@ -4165,10 +4209,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) } /* Initialize the pipeline lists */ - conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor); - if(!conn->send_pipe || !conn->recv_pipe) - goto error; + Curl_llist_init(&conn->send_pipe, (curl_llist_dtor) llist_dtor); + Curl_llist_init(&conn->recv_pipe, (curl_llist_dtor) llist_dtor); #ifdef HAVE_GSSAPI conn->data_prot = PROT_CLEAR; @@ -4191,11 +4233,8 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) return conn; error: - Curl_llist_destroy(conn->send_pipe, NULL); - Curl_llist_destroy(conn->recv_pipe, NULL); - - conn->send_pipe = NULL; - conn->recv_pipe = NULL; + Curl_llist_destroy(&conn->send_pipe, NULL); + Curl_llist_destroy(&conn->recv_pipe, NULL); free(conn->master_buffer); free(conn->localdev); @@ -4258,11 +4297,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, char *fragment; char *path = data->state.path; char *query; + int i; int rc; - char protobuf[16] = ""; const char *protop = ""; CURLcode result; bool rebuild_url = FALSE; + bool url_has_scheme = FALSE; + char protobuf[16]; *prot_missing = FALSE; @@ -4281,10 +4322,47 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, * proxy -- and we don't know if we will need to use SSL until we parse the * url ... ************************************************************/ - if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]", - protobuf, path)) && - strcasecompare(protobuf, "file")) { - if(path[0] == '/' && path[1] == '/') { + if(data->change.url[0] == ':') { + failf(data, "Bad URL, colon is first character"); + return CURLE_URL_MALFORMAT; + } + + /* Make sure we don't mistake a drive letter for a scheme, for example: + curld --proto-default file c:/foo/bar.txt */ + if((('a' <= data->change.url[0] && data->change.url[0] <= 'z') || + ('A' <= data->change.url[0] && data->change.url[0] <= 'Z')) && + data->change.url[1] == ':' && data->set.str[STRING_DEFAULT_PROTOCOL] && + strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) { + ; /* do nothing */ + } + else { /* check for a scheme */ + for(i = 0; i < 16 && data->change.url[i]; ++i) { + if(data->change.url[i] == '/') + break; + if(data->change.url[i] == ':') { + url_has_scheme = TRUE; + break; + } + } + } + + /* handle the file: scheme */ + if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) || + (!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] && + strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) { + bool path_has_drive = FALSE; + + if(url_has_scheme) + rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path); + else + rc = sscanf(data->change.url, "%[^\n]", path); + + if(rc != 1) { + failf(data, "Bad URL"); + return CURLE_URL_MALFORMAT; + } + + if(url_has_scheme && path[0] == '/' && path[1] == '/') { /* Allow omitted hostname (e.g. file:/<path>). This is not strictly * speaking a valid file: URL by RFC 1738, but treating file:/<path> as * file://localhost/<path> is similar to how other schemes treat missing @@ -4294,18 +4372,25 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, memory areas overlap! */ memmove(path, path + 2, strlen(path + 2)+1); } + + /* the path may start with a drive letter. for backwards compatibility + we skip some processing on those paths. */ + path_has_drive = (('a' <= path[0] && path[0] <= 'z') || + ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':'; + /* * we deal with file://<host>/<path> differently since it supports no * hostname other than "localhost" and "127.0.0.1", which is unique among * the URL protocols specified in RFC 1738 */ - if(path[0] != '/') { + if(path[0] != '/' && !path_has_drive) { /* the URL includes a host name, it must match "localhost" or "127.0.0.1" to be valid */ char *ptr; if(!checkprefix("localhost/", path) && !checkprefix("127.0.0.1/", path)) { - failf(data, "Valid host name with slash missing in URL"); + failf(data, "Invalid file://hostname/, " + "expected localhost or 127.0.0.1 or none"); return CURLE_URL_MALFORMAT; } ptr = &path[9]; /* now points to the slash after the host */ @@ -4332,7 +4417,17 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, /* This cannot be made with strcpy, as the memory chunks overlap! */ memmove(path, ptr, strlen(ptr)+1); + + path_has_drive = (('a' <= path[0] && path[0] <= 'z') || + ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':'; + } + +#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) + if(path_has_drive) { + failf(data, "File drive letters are only accepted in MSDOS/Windows."); + return CURLE_URL_MALFORMAT; } +#endif protop = "file"; /* protocol string */ } @@ -4342,7 +4437,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, path[0]=0; rc = sscanf(data->change.url, - "%15[^\n:]:%3[/]%[^\n/?#]%[^\n]", + "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]", protobuf, slashbuf, conn->host.name, path); if(2 == rc) { failf(data, "Bad URL"); @@ -4527,6 +4622,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, data->change.url_alloc = TRUE; /* free this later */ } + result = findprotocol(data, conn, protop); + if(result) + return result; + /* * Parse the login details from the URL and strip them out of * the host name @@ -4613,8 +4712,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, * conn->host.name is B * data->state.path is /C */ - - return findprotocol(data, conn, protop); + return CURLE_OK; } /* @@ -4783,6 +4881,7 @@ static bool check_noproxy(const char *name, const char *no_proxy) return FALSE; } +#ifndef CURL_DISABLE_HTTP /**************************************************************** * Detect what (if any) proxy to use. Remember that this selects a host * name and is not limited to HTTP proxies only. @@ -4792,7 +4891,6 @@ static char *detect_proxy(struct connectdata *conn) { char *proxy = NULL; -#ifndef CURL_DISABLE_HTTP /* If proxy was not specified, we check for default proxy environment * variables, to enable i.e Lynx compliance: * @@ -4810,65 +4908,50 @@ static char *detect_proxy(struct connectdata *conn) * For compatibility, the all-uppercase versions of these variables are * checked if the lowercase versions don't exist. */ - char *no_proxy=NULL; char proxy_env[128]; + const char *protop = conn->handler->scheme; + char *envp = proxy_env; + char *prox; - no_proxy=curl_getenv("no_proxy"); - if(!no_proxy) - no_proxy=curl_getenv("NO_PROXY"); - - if(!check_noproxy(conn->host.name, no_proxy)) { - /* It was not listed as without proxy */ - const char *protop = conn->handler->scheme; - char *envp = proxy_env; - char *prox; + /* Now, build <protocol>_proxy and check for such a one to use */ + while(*protop) + *envp++ = (char)tolower((int)*protop++); - /* Now, build <protocol>_proxy and check for such a one to use */ - while(*protop) - *envp++ = (char)tolower((int)*protop++); + /* append _proxy */ + strcpy(envp, "_proxy"); - /* append _proxy */ - strcpy(envp, "_proxy"); + /* read the protocol proxy: */ + prox=curl_getenv(proxy_env); - /* read the protocol proxy: */ + /* + * We don't try the uppercase version of HTTP_PROXY because of + * security reasons: + * + * When curl is used in a webserver application + * environment (cgi or php), this environment variable can + * be controlled by the web server user by setting the + * http header 'Proxy:' to some value. + * + * This can cause 'internal' http/ftp requests to be + * arbitrarily redirected by any external attacker. + */ + if(!prox && !strcasecompare("http_proxy", proxy_env)) { + /* There was no lowercase variable, try the uppercase version: */ + Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); prox=curl_getenv(proxy_env); + } - /* - * We don't try the uppercase version of HTTP_PROXY because of - * security reasons: - * - * When curl is used in a webserver application - * environment (cgi or php), this environment variable can - * be controlled by the web server user by setting the - * http header 'Proxy:' to some value. - * - * This can cause 'internal' http/ftp requests to be - * arbitrarily redirected by any external attacker. - */ - if(!prox && !strcasecompare("http_proxy", proxy_env)) { - /* There was no lowercase variable, try the uppercase version: */ - Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); - prox=curl_getenv(proxy_env); - } - - if(prox) - proxy = prox; /* use this */ - else { - proxy = curl_getenv("all_proxy"); /* default proxy to use */ - if(!proxy) - proxy=curl_getenv("ALL_PROXY"); - } - } /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified - non-proxy */ - free(no_proxy); - -#else /* !CURL_DISABLE_HTTP */ - - (void)conn; -#endif /* CURL_DISABLE_HTTP */ + if(prox) + proxy = prox; /* use this */ + else { + proxy = curl_getenv("all_proxy"); /* default proxy to use */ + if(!proxy) + proxy=curl_getenv("ALL_PROXY"); + } return proxy; } +#endif /* CURL_DISABLE_HTTP */ /* * If this is supposed to use a proxy, we need to figure out the proxy @@ -5032,15 +5115,19 @@ static CURLcode parse_proxy(struct Curl_easy *data, with reserved characters like ':' in them. */ Curl_safefree(proxyinfo->user); proxyinfo->user = curl_easy_unescape(data, proxyuser, 0, NULL); + Curl_safefree(proxyuser); - if(!proxyinfo->user) + if(!proxyinfo->user) { + Curl_safefree(proxypasswd); return CURLE_OUT_OF_MEMORY; + } Curl_safefree(proxyinfo->passwd); if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) proxyinfo->passwd = curl_easy_unescape(data, proxypasswd, 0, NULL); else proxyinfo->passwd = strdup(""); + Curl_safefree(proxypasswd); if(!proxyinfo->passwd) return CURLE_OUT_OF_MEMORY; @@ -5097,6 +5184,168 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data, NULL, FALSE); return result; } + +/* create_conn helper to parse and init proxy values. to be called after unix + socket init but before any proxy vars are evaluated. */ +static CURLcode create_conn_helper_init_proxy(struct connectdata *conn) +{ + char *proxy = NULL; + char *socksproxy = NULL; + char *no_proxy = NULL; + CURLcode result = CURLE_OK; + struct Curl_easy *data = conn->data; + + /************************************************************* + * Extract the user and password from the authentication string + *************************************************************/ + if(conn->bits.proxy_user_passwd) { + result = parse_proxy_auth(data, conn); + if(result) + goto out; + } + + /************************************************************* + * Detect what (if any) proxy to use + *************************************************************/ + if(data->set.str[STRING_PROXY]) { + proxy = strdup(data->set.str[STRING_PROXY]); + /* if global proxy is set, this is it */ + if(NULL == proxy) { + failf(data, "memory shortage"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + if(data->set.str[STRING_PRE_PROXY]) { + socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); + /* if global socks proxy is set, this is it */ + if(NULL == socksproxy) { + failf(data, "memory shortage"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } + } + + no_proxy = curl_getenv("no_proxy"); + if(!no_proxy) + no_proxy = curl_getenv("NO_PROXY"); + + if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY]) || + (!data->set.str[STRING_NOPROXY] && + check_noproxy(conn->host.name, no_proxy))) { + Curl_safefree(proxy); + Curl_safefree(socksproxy); + } + else if(!proxy && !socksproxy) +#ifndef CURL_DISABLE_HTTP + /* if the host is not in the noproxy list, detect proxy. */ + proxy = detect_proxy(conn); +#else /* !CURL_DISABLE_HTTP */ + proxy = NULL; +#endif /* CURL_DISABLE_HTTP */ + + Curl_safefree(no_proxy); + +#ifdef USE_UNIX_SOCKETS + /* For the time being do not mix proxy and unix domain sockets. See #1274 */ + if(proxy && conn->unix_domain_socket) { + free(proxy); + proxy = NULL; + } +#endif + + if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { + free(proxy); /* Don't bother with an empty proxy string or if the + protocol doesn't work with network */ + proxy = NULL; + } + if(socksproxy && (!*socksproxy || + (conn->handler->flags & PROTOPT_NONETWORK))) { + free(socksproxy); /* Don't bother with an empty socks proxy string or if + the protocol doesn't work with network */ + socksproxy = NULL; + } + + /*********************************************************************** + * If this is supposed to use a proxy, we need to figure out the proxy host + * name, proxy type and port number, so that we can re-use an existing + * connection that may exist registered to the same proxy host. + ***********************************************************************/ + if(proxy || socksproxy) { + if(proxy) { + result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); + Curl_safefree(proxy); /* parse_proxy copies the proxy string */ + if(result) + goto out; + } + + if(socksproxy) { + result = parse_proxy(data, conn, socksproxy, + conn->socks_proxy.proxytype); + /* parse_proxy copies the socks proxy string */ + Curl_safefree(socksproxy); + if(result) + goto out; + } + + if(conn->http_proxy.host.rawalloc) { +#ifdef CURL_DISABLE_HTTP + /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ + result = CURLE_UNSUPPORTED_PROTOCOL; + goto out; +#else + /* force this connection's protocol to become HTTP if not already + compatible - if it isn't tunneling through */ + if(!(conn->handler->protocol & PROTO_FAMILY_HTTP) && + !conn->bits.tunnel_proxy) + conn->handler = &Curl_handler_http; + + conn->bits.httpproxy = TRUE; +#endif + } + else { + conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ + conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ + } + + if(conn->socks_proxy.host.rawalloc) { + if(!conn->http_proxy.host.rawalloc) { + /* once a socks proxy */ + if(!conn->socks_proxy.user) { + conn->socks_proxy.user = conn->http_proxy.user; + conn->http_proxy.user = NULL; + Curl_safefree(conn->socks_proxy.passwd); + conn->socks_proxy.passwd = conn->http_proxy.passwd; + conn->http_proxy.passwd = NULL; + } + } + conn->bits.socksproxy = TRUE; + } + else + conn->bits.socksproxy = FALSE; /* not a socks proxy */ + } + else { + conn->bits.socksproxy = FALSE; + conn->bits.httpproxy = FALSE; + } + conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; + + if(!conn->bits.proxy) { + /* we aren't using the proxy after all... */ + conn->bits.proxy = FALSE; + conn->bits.httpproxy = FALSE; + conn->bits.socksproxy = FALSE; + conn->bits.proxy_user_passwd = FALSE; + conn->bits.tunnel_proxy = FALSE; + } + +out: + + free(socksproxy); + free(proxy); + return result; +} #endif /* CURL_DISABLE_PROXY */ /* @@ -5137,6 +5386,7 @@ static CURLcode parse_url_login(struct Curl_easy *data, DEBUGASSERT(!**user); DEBUGASSERT(!**passwd); DEBUGASSERT(!**options); + DEBUGASSERT(conn->handler); if(!ptr) goto out; @@ -5155,9 +5405,12 @@ static CURLcode parse_url_login(struct Curl_easy *data, if(data->set.use_netrc == CURL_NETRC_REQUIRED) goto out; - /* We could use the login information in the URL so extract it */ + /* We could use the login information in the URL so extract it. Only parse + options if the handler says we should. */ result = parse_login_details(login, ptr - login - 1, - &userp, &passwdp, &optionsp); + &userp, &passwdp, + (conn->handler->flags & PROTOPT_URLOPTIONS)? + &optionsp:NULL); if(result) goto out; @@ -5387,7 +5640,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data, } #endif - portptr = strrchr(conn->host.name, ':'); + portptr = strchr(conn->host.name, ':'); } if(data->set.use_port && data->state.allow_port) { @@ -5442,15 +5695,16 @@ static CURLcode parse_remote_port(struct Curl_easy *data, return CURLE_URL_MALFORMAT; } - else if(rest != &portptr[1]) { + if(rest[0]) { + failf(data, "Port number ended with '%c'", rest[0]); + return CURLE_URL_MALFORMAT; + } + + if(rest != &portptr[1]) { *portptr = '\0'; /* cut off the name there */ conn->remote_port = curlx_ultous(port); } else { - if(rest[0]) { - failf(data, "Illegal port number"); - return CURLE_URL_MALFORMAT; - } /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just use the default port. Firefox and Chrome both do that. */ @@ -5584,6 +5838,10 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data, char *portptr; int port = -1; +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + *hostname_result = NULL; *port_result = -1; @@ -5749,14 +6007,11 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, return result; if(host && *host) { - bool ipv6host; conn->conn_to_host.rawalloc = host; conn->conn_to_host.name = host; conn->bits.conn_to_host = TRUE; - ipv6host = strchr(host, ':') != NULL; - infof(data, "Connecting to hostname: %s%s%s\n", - ipv6host ? "[" : "", host, ipv6host ? "]" : ""); + infof(data, "Connecting to hostname: %s\n", host); } else { /* no "connect to host" */ @@ -5816,8 +6071,9 @@ static CURLcode resolve_server(struct Curl_easy *data, if(!hostaddr) result = CURLE_OUT_OF_MEMORY; else { - int longpath=0; - hostaddr->addr = Curl_unix2addr(path, &longpath); + bool longpath = FALSE; + hostaddr->addr = Curl_unix2addr(path, &longpath, + conn->abstract_unix_socket); if(hostaddr->addr) hostaddr->inuse++; else { @@ -5847,7 +6103,7 @@ static CURLcode resolve_server(struct Curl_easy *data, if(conn->bits.conn_to_port) conn->port = conn->conn_to_port; else - conn->port = conn->remote_port; /* it is the same port */ + conn->port = conn->remote_port; /* Resolve target host right on */ rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, @@ -5903,11 +6159,9 @@ static void reuse_conn(struct connectdata *old_conn, { free_fixed_hostname(&old_conn->http_proxy.host); free_fixed_hostname(&old_conn->socks_proxy.host); - free_fixed_hostname(&old_conn->proxy); free(old_conn->http_proxy.host.rawalloc); free(old_conn->socks_proxy.host.rawalloc); - free(old_conn->proxy.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ @@ -5962,7 +6216,6 @@ static void reuse_conn(struct connectdata *old_conn, Curl_persistconninfo(conn); conn_reset_all_postponed_data(old_conn); /* free buffers */ - conn_reset_all_postponed_data(conn); /* reset unprocessed data */ /* re-use init */ conn->bits.reuse = TRUE; /* yes, we're re-using here */ @@ -5975,11 +6228,8 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->socks_proxy.passwd); Curl_safefree(old_conn->localdev); - Curl_llist_destroy(old_conn->send_pipe, NULL); - Curl_llist_destroy(old_conn->recv_pipe, NULL); - - old_conn->send_pipe = NULL; - old_conn->recv_pipe = NULL; + Curl_llist_destroy(&old_conn->send_pipe, NULL); + Curl_llist_destroy(&old_conn->recv_pipe, NULL); Curl_safefree(old_conn->master_buffer); @@ -6016,8 +6266,6 @@ static CURLcode create_conn(struct Curl_easy *data, char *passwd = NULL; char *options = NULL; bool reuse; - char *proxy = NULL; - char *socksproxy = NULL; bool prot_missing = FALSE; bool connections_available = TRUE; bool force_reuse = FALSE; @@ -6161,147 +6409,24 @@ static CURLcode create_conn(struct Curl_easy *data, } } -#ifndef CURL_DISABLE_PROXY - /************************************************************* - * Extract the user and password from the authentication string - *************************************************************/ - if(conn->bits.proxy_user_passwd) { - result = parse_proxy_auth(data, conn); - if(result) - goto out; - } - - /************************************************************* - * Detect what (if any) proxy to use - *************************************************************/ - if(data->set.str[STRING_PROXY]) { - proxy = strdup(data->set.str[STRING_PROXY]); - /* if global proxy is set, this is it */ - if(NULL == proxy) { - failf(data, "memory shortage"); - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - - if(data->set.str[STRING_PRE_PROXY]) { - socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); - /* if global socks proxy is set, this is it */ - if(NULL == socksproxy) { - failf(data, "memory shortage"); - result = CURLE_OUT_OF_MEMORY; - goto out; - } - } - - if(data->set.str[STRING_NOPROXY] && - check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { - Curl_safefree(proxy); - Curl_safefree(socksproxy); - } - else if(!proxy && !socksproxy) - proxy = detect_proxy(conn); - #ifdef USE_UNIX_SOCKETS if(data->set.str[STRING_UNIX_SOCKET_PATH]) { - if(proxy) { - free(proxy); /* Unix domain sockets cannot be proxied, so disable it */ - proxy = NULL; - } conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); if(conn->unix_domain_socket == NULL) { result = CURLE_OUT_OF_MEMORY; goto out; } + conn->abstract_unix_socket = data->set.abstract_unix_socket; } #endif - if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { - free(proxy); /* Don't bother with an empty proxy string or if the - protocol doesn't work with network */ - proxy = NULL; - } - if(socksproxy && (!*socksproxy || - (conn->handler->flags & PROTOPT_NONETWORK))) { - free(socksproxy); /* Don't bother with an empty socks proxy string or if - the protocol doesn't work with network */ - socksproxy = NULL; - } - - /*********************************************************************** - * If this is supposed to use a proxy, we need to figure out the proxy host - * name, proxy type and port number, so that we can re-use an existing - * connection that may exist registered to the same proxy host. - ***********************************************************************/ - if(proxy || socksproxy) { - if(proxy) { - result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); - Curl_safefree(proxy); /* parse_proxy copies the proxy string */ - if(result) - goto out; - } - - if(socksproxy) { - result = parse_proxy(data, conn, socksproxy, - conn->socks_proxy.proxytype); - /* parse_proxy copies the socks proxy string */ - Curl_safefree(socksproxy); - if(result) - goto out; - } - - if(conn->http_proxy.host.rawalloc) { -#ifdef CURL_DISABLE_HTTP - /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ - result = CURLE_UNSUPPORTED_PROTOCOL; - goto out; -#else - /* force this connection's protocol to become HTTP if not already - compatible - if it isn't tunneling through */ - if(!(conn->handler->protocol & PROTO_FAMILY_HTTP) && - !conn->bits.tunnel_proxy) - conn->handler = &Curl_handler_http; - - conn->bits.httpproxy = TRUE; + /* After the unix socket init but before the proxy vars are used, parse and + initialize the proxy vars */ +#ifndef CURL_DISABLE_PROXY + result = create_conn_helper_init_proxy(conn); + if(result) + goto out; #endif - } - else { - conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ - conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ - } - - if(conn->socks_proxy.host.rawalloc) { - if(!conn->http_proxy.host.rawalloc) { - /* once a socks proxy */ - if(!conn->socks_proxy.user) { - conn->socks_proxy.user = conn->http_proxy.user; - conn->http_proxy.user = NULL; - Curl_safefree(conn->socks_proxy.passwd); - conn->socks_proxy.passwd = conn->http_proxy.passwd; - conn->http_proxy.passwd = NULL; - } - } - conn->bits.socksproxy = TRUE; - } - else - conn->bits.socksproxy = FALSE; /* not a socks proxy */ - } - else { - conn->bits.socksproxy = FALSE; - conn->bits.httpproxy = FALSE; - } - conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; - - if(!conn->bits.proxy) { - /* we aren't using the proxy after all... */ - conn->bits.proxy = FALSE; - conn->bits.httpproxy = FALSE; - conn->bits.socksproxy = FALSE; - conn->bits.proxy_user_passwd = FALSE; - conn->bits.tunnel_proxy = FALSE; - } - -#endif /* CURL_DISABLE_PROXY */ /************************************************************* * If the protocol is using SSL and HTTP proxy is used, we set @@ -6340,12 +6465,14 @@ static CURLcode create_conn(struct Curl_easy *data, fix_hostname(conn, &conn->host); if(conn->bits.conn_to_host) fix_hostname(conn, &conn->conn_to_host); - if(conn->proxy.name && *conn->proxy.name) - fix_hostname(conn, &conn->proxy); + if(conn->bits.httpproxy) + fix_hostname(conn, &conn->http_proxy.host); + if(conn->bits.socksproxy) + fix_hostname(conn, &conn->socks_proxy.host); /************************************************************* * Check whether the host and the "connect to host" are equal. - * Do this after the hostnames have been IDN-fixed . + * Do this after the hostnames have been IDN-fixed. *************************************************************/ if(conn->bits.conn_to_host && strcasecompare(conn->conn_to_host.name, conn->host.name)) { @@ -6501,7 +6628,7 @@ static CURLcode create_conn(struct Curl_easy *data, /* If we found a reusable connection, we may still want to open a new connection if we are pipelining. */ if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) { - size_t pipelen = conn_temp->send_pipe->size + conn_temp->recv_pipe->size; + size_t pipelen = conn_temp->send_pipe.size + conn_temp->recv_pipe.size; if(pipelen > 0) { infof(data, "Found connection %ld, with requests in the pipe (%zu)\n", conn_temp->connection_id, pipelen); @@ -6661,13 +6788,11 @@ static CURLcode create_conn(struct Curl_easy *data, *************************************************************/ result = resolve_server(data, conn, async); - out: +out: free(options); free(passwd); free(user); - free(socksproxy); - free(proxy); return result; } @@ -6771,7 +6896,7 @@ CURLcode Curl_connect(struct Curl_easy *data, if(!result) { /* no error */ - if((*in_connect)->send_pipe->size || (*in_connect)->recv_pipe->size) + if((*in_connect)->send_pipe.size || (*in_connect)->recv_pipe.size) /* pipelining */ *protocol_done = TRUE; else if(!*asyncp) { diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index 0271d26..3c94553 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -136,8 +136,10 @@ #undef realloc #endif /* USE_AXTLS */ -#ifdef USE_SCHANNEL +#if defined(USE_SCHANNEL) || defined(USE_WINDOWS_SSPI) #include "curl_sspi.h" +#endif +#ifdef USE_SCHANNEL #include <schnlsp.h> #include <schannel.h> #endif @@ -201,6 +203,9 @@ /* Download buffer size, keep it fairly big for speed reasons */ #undef BUFSIZE #define BUFSIZE CURL_MAX_WRITE_SIZE +#undef MAX_BUFSIZE +#define MAX_BUFSIZE CURL_MAX_READ_SIZE +#define CURL_BUFSIZE(x) ((x)?(x):(BUFSIZE)) /* Initial size of the buffer to store headers in, it'll be enlarged in case of need. */ @@ -311,7 +316,7 @@ struct ssl_connect_data { PRFileDesc *handle; char *client_nickname; struct Curl_easy *data; - struct curl_llist *obj_list; + struct curl_llist obj_list; PK11GenericObject *obj_clicert; #elif defined(USE_GSKIT) gsk_handle handle; @@ -345,6 +350,7 @@ struct ssl_connect_data { struct ssl_primary_config { long version; /* what version the client wants to use */ + long version_max; /* max supported version the client wants to use*/ bool verifypeer; /* set TRUE if this is desired */ bool verifyhost; /* set TRUE if CN/SAN must match hostname */ bool verifystatus; /* set TRUE if certificate status must be checked */ @@ -354,6 +360,7 @@ struct ssl_primary_config { char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ + bool sessionid; /* cache session IDs or not */ }; struct ssl_config_data { @@ -383,7 +390,6 @@ struct ssl_config_data { }; struct ssl_general_config { - bool sessionid; /* cache session IDs or not */ size_t max_ssl_sessions; /* SSL session id cache size */ }; @@ -405,6 +411,7 @@ struct digestdata { #if defined(USE_WINDOWS_SSPI) BYTE *input_token; size_t input_token_len; + CtxtHandle *http_context; #else char *nonce; char *cnonce; @@ -842,6 +849,8 @@ struct Curl_handler { request instead of per connection */ #define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ #define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ +#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field + of the URL */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -931,7 +940,6 @@ struct connectdata { char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ - struct hostname proxy; struct proxy_info socks_proxy; struct proxy_info http_proxy; @@ -1050,10 +1058,10 @@ struct connectdata { handle */ bool writechannel_inuse; /* whether the write channel is in use by an easy handle */ - struct curl_llist *send_pipe; /* List of handles waiting to - send on this pipeline */ - struct curl_llist *recv_pipe; /* List of handles waiting to read - their responses on this pipeline */ + struct curl_llist send_pipe; /* List of handles waiting to send on this + pipeline */ + struct curl_llist recv_pipe; /* List of handles waiting to read their + responses on this pipeline */ char *master_buffer; /* The master buffer allocated on-demand; used for pipelining. */ size_t read_pos; /* Current read position in the master buffer */ @@ -1133,6 +1141,7 @@ struct connectdata { #ifdef USE_UNIX_SOCKETS char *unix_domain_socket; + bool abstract_unix_socket; #endif }; @@ -1274,8 +1283,8 @@ struct auth { this resource */ bool done; /* TRUE when the auth phase is done and ready to do the *actual* request */ - bool multi; /* TRUE if this is not yet authenticated but within the auth - multipass negotiation */ + bool multipass; /* TRUE if this is not yet authenticated but within the + auth multipass negotiation */ bool iestyle; /* TRUE if digest should be done IE-style or FALSE if it should be RFC compliant */ }; @@ -1285,6 +1294,19 @@ struct Curl_http2_dep { struct Curl_easy *data; }; +/* + * This struct is for holding data that was attemped to get sent to the user's + * callback but is held due to pausing. One instance per type (BOTH, HEADER, + * BODY). + */ +struct tempbuf { + char *buf; /* allocated buffer to keep data in when a write callback + returns to make the connection paused */ + size_t len; /* size of the 'tempwrite' allocated buffer */ + int type; /* type of the 'tempwrite' buffer as a bitmask that is used with + Curl_client_write() */ +}; + struct UrlState { /* Points to the connection cache */ @@ -1303,9 +1325,9 @@ struct UrlState { char *headerbuff; /* allocated buffer to store headers in */ size_t headersize; /* size of the allocation */ - char buffer[BUFSIZE+1]; /* download buffer */ + char *buffer; /* download buffer */ char uploadbuffer[BUFSIZE+1]; /* upload buffer */ - curl_off_t current_speed; /* the ProgressShow() funcion sets this, + curl_off_t current_speed; /* the ProgressShow() function sets this, bytes / second */ bool this_is_a_follow; /* this is a followed Location: request */ @@ -1318,11 +1340,8 @@ struct UrlState { int first_remote_port; /* remote port of the first (not followed) request */ struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ long sessionage; /* number of the most recent session */ - char *tempwrite; /* allocated buffer to keep data in when a write - callback returns to make the connection paused */ - size_t tempwritesize; /* size of the 'tempwrite' allocated buffer */ - int tempwritetype; /* type of the 'tempwrite' buffer as a bitmask that is - used with Curl_client_write() */ + unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */ + struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */ char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */ bool errorbuf; /* Set to TRUE if the error buffer is already filled in. This must be set to FALSE every time _easy_perform() is @@ -1355,7 +1374,7 @@ struct UrlState { #endif /* USE_OPENSSL */ struct timeval expiretime; /* set this with Curl_expire() only */ struct Curl_tree timenode; /* for the splay stuff */ - struct curl_llist *timeoutlist; /* list of pending timeouts */ + struct curl_llist timeoutlist; /* list of pending timeouts */ /* a place to store the most recently set FTP entrypath */ char *most_recent_ftp_entrypath; @@ -1638,7 +1657,6 @@ struct UserDefined { struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ struct ssl_general_config general_ssl; /* general user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ - curl_proxytype socks_proxytype; /* what kind of socks proxy that is in use */ long dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ void *private_data; /* application-private data */ @@ -1748,12 +1766,16 @@ struct UserDefined { bool pipewait; /* wait for pipe/multiplex status before starting a new connection */ long expect_100_timeout; /* in milliseconds */ + bool suppress_connect_headers; /* suppress proxy CONNECT response headers + from user callbacks */ struct Curl_easy *stream_depends_on; bool stream_depends_e; /* set or don't set the Exclusive bit */ int stream_weight; struct Curl_http2_dep *stream_dependents; + + bool abstract_unix_socket; }; struct Names { diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c index 7d9200a..31d25cf 100644 --- a/Utilities/cmcurl/lib/vauth/digest.c +++ b/Utilities/cmcurl/lib/vauth/digest.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -237,7 +237,7 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value) * auth_decode_digest_md5_message() * * This is used internally to decode an already encoded DIGEST-MD5 challenge - * message into the seperate attributes. + * message into the separate attributes. * * Parameters: * @@ -366,7 +366,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; char *spn = NULL; - /* Decode the challange message */ + /* Decode the challenge message */ result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), realm, sizeof(realm), algorithm, sizeof(algorithm), @@ -502,7 +502,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* * Curl_auth_decode_digest_http_message() * - * This is used to decode a HTTP DIGEST challenge message into the seperate + * This is used to decode a HTTP DIGEST challenge message into the separate * attributes. * * Parameters: diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c index b9ceb12..0bd9444 100644 --- a/Utilities/cmcurl/lib/vauth/digest_sspi.c +++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>. - * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -320,7 +320,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, /* * Curl_auth_decode_digest_http_message() * - * This is used to decode a HTTP DIGEST challenge message into the seperate + * This is used to decode a HTTP DIGEST challenge message into the separate * attributes. * * Parameters: @@ -335,13 +335,44 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, { size_t chlglen = strlen(chlg); - /* We had an input token before and we got another one now. This means we - provided bad credentials in the previous request. */ - if(digest->input_token) - return CURLE_BAD_CONTENT_ENCODING; + /* We had an input token before so if there's another one now that means we + provided bad credentials in the previous request or it's stale. */ + if(digest->input_token) { + bool stale = false; + const char *p = chlg; + + /* Check for the 'stale' directive */ + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + while(*p && ISSPACE(*p)) + p++; + + if(!Curl_auth_digest_get_pair(p, value, content, &p)) + break; + + if(Curl_strcasecompare(value, "stale") + && Curl_strcasecompare(content, "true")) { + stale = true; + break; + } + + while(*p && ISSPACE(*p)) + p++; + + if(',' == *p) + p++; + } + + if(stale) + Curl_auth_digest_cleanup(digest); + else + return CURLE_LOGIN_DENIED; + } - /* Simply store the challenge for use later */ - digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); + /* Store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); if(!digest->input_token) return CURLE_OUT_OF_MEMORY; @@ -379,21 +410,13 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, char **outptr, size_t *outlen) { size_t token_max; - CredHandle credentials; - CtxtHandle context; char *resp; BYTE *output_token; + size_t output_token_len = 0; PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf[3]; - SecBuffer resp_buf; + SecBuffer chlg_buf[5]; SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - TCHAR *spn; (void) data; @@ -408,123 +431,168 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, /* Release the package buffer as it is not required anymore */ s_pSecFn->FreeContextBuffer(SecurityPackage); - if(userp && *userp) { - /* Populate our identity structure */ - if(Curl_create_sspi_identity(userp, passwdp, &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Populate our identity domain */ - if(Curl_override_sspi_http_realm((const char *) digest->input_token, - &identity)) - return CURLE_OUT_OF_MEMORY; + /* Allocate the output buffer according to the max token size as indicated + by the security package */ + output_token = malloc(token_max); + if(!output_token) { + return CURLE_OUT_OF_MEMORY; + } - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; + if(digest->http_context) { + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 5; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = NULL; + chlg_buf[0].cbBuffer = 0; + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = (void *) uripath; + chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); + chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[3].pvBuffer = NULL; + chlg_buf[3].cbBuffer = 0; + chlg_buf[4].BufferType = SECBUFFER_PADDING; + chlg_buf[4].pvBuffer = output_token; + chlg_buf[4].cbBuffer = curlx_uztoul(token_max); + + status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); + if(status == SEC_E_OK) + output_token_len = chlg_buf[4].cbBuffer; + else { /* delete the context so a new one can be made */ + infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n", + (long)status); + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } } - else - /* Use the current Windows user */ - p_identity = NULL; - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); + if(!digest->http_context) { + CredHandle credentials; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer resp_buf; + SecBufferDesc resp_desc; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + TCHAR *spn; + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } - return CURLE_LOGIN_DENIED; - } + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char *) digest->input_token, + &identity)) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } - /* Allocate the output buffer according to the max token size as indicated - by the security package */ - output_token = malloc(token_max); - if(!output_token) { - s_pSecFn->FreeCredentialsHandle(&credentials); + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(output_token); - Curl_sspi_free_identity(p_identity); + return CURLE_LOGIN_DENIED; + } - return CURLE_OUT_OF_MEMORY; - } + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + spn = Curl_convert_UTF8_to_tchar((char *) uripath); + if(!spn) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); - /* Setup the challenge "input" security buffer if present */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 3; - chlg_desc.pBuffers = chlg_buf; - chlg_buf[0].BufferType = SECBUFFER_TOKEN; - chlg_buf[0].pvBuffer = digest->input_token; - chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); - chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[1].pvBuffer = (void *) request; - chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); - chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[2].pvBuffer = NULL; - chlg_buf[2].cbBuffer = 0; + return CURLE_OUT_OF_MEMORY; + } - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); + /* Allocate our new context handle */ + digest->http_context = calloc(1, sizeof(CtxtHandle)); + if(!digest->http_context) + return CURLE_OUT_OF_MEMORY; - spn = Curl_convert_UTF8_to_tchar((char *) uripath); - if(!spn) { - s_pSecFn->FreeCredentialsHandle(&credentials); + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, + digest->http_context, + &resp_desc, &attrs, &expiry); + Curl_unicodefree(spn); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); - Curl_sspi_free_identity(p_identity); - free(output_token); + Curl_safefree(digest->http_context); - return CURLE_OUT_OF_MEMORY; - } + return CURLE_OUT_OF_MEMORY; + } - /* Generate our reponse message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, - spn, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, &context, - &resp_desc, &attrs, &expiry); - Curl_unicodefree(spn); + output_token_len = resp_buf.cbBuffer; - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { s_pSecFn->FreeCredentialsHandle(&credentials); - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_OUT_OF_MEMORY; } - resp = malloc(resp_buf.cbBuffer + 1); + resp = malloc(output_token_len + 1); if(!resp) { - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - Curl_sspi_free_identity(p_identity); free(output_token); return CURLE_OUT_OF_MEMORY; } - /* Copy the generated reponse */ - memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); - resp[resp_buf.cbBuffer] = 0x00; + /* Copy the generated response */ + memcpy(resp, output_token, output_token_len); + resp[output_token_len] = 0; /* Return the response */ *outptr = resp; - *outlen = resp_buf.cbBuffer; - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); + *outlen = output_token_len; /* Free the response buffer */ free(output_token); @@ -549,6 +617,12 @@ void Curl_auth_digest_cleanup(struct digestdata *digest) /* Reset any variables */ digest->input_token_len = 0; + + /* Delete security context */ + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } } #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c index c754fae..560ecc5 100644 --- a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>. * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which @@ -68,7 +68,7 @@ bool Curl_auth_is_gssapi_supported(void) * passdwp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in[ - The host name. - * mutual_auth [in] - Flag specifing whether or not mutual authentication + * mutual_auth [in] - Flag specifying whether or not mutual authentication * is enabled. * chlg64 [in] - Pointer to the optional base64 encoded challenge * message. diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c index 151794e..1b4cef4 100644 --- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -74,7 +74,7 @@ bool Curl_auth_is_gssapi_supported(void) * passdwp [in] - The user's password. * service [in] - The service type such as http, smtp, pop or imap. * host [in] - The host name. - * mutual_auth [in] - Flag specifing whether or not mutual authentication + * mutual_auth [in] - Flag specifying whether or not mutual authentication * is enabled. * chlg64 [in] - The optional base64 encoded challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c index b4d345d..d02eec4 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm.c +++ b/Utilities/cmcurl/lib/vauth/ntlm.c @@ -27,7 +27,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -394,7 +394,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, /* Clean up any former leftovers and initialise to defaults */ Curl_auth_ntlm_cleanup(ntlm); -#if USE_NTRESPONSES && USE_NTLM2SESSION +#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY #else #define NTLM2FLAG 0 @@ -509,7 +509,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, unsigned char ntlmbuf[NTLM_BUFSIZE]; int lmrespoff; unsigned char lmresp[24]; /* fixed-size */ -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES int ntrespoff; unsigned int ntresplen = 24; unsigned char ntresp[24]; /* fixed-size */ @@ -552,7 +552,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, hostlen = strlen(host); } -#if USE_NTRESPONSES && USE_NTLM_V2 +#if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2) if(ntlm->target_info_len) { unsigned char ntbuffer[0x18]; unsigned int entropy[2]; @@ -590,7 +590,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, else #endif -#if USE_NTRESPONSES && USE_NTLM2SESSION +#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION) /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { unsigned char ntbuffer[0x18]; @@ -630,12 +630,12 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, #endif { -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES unsigned char ntbuffer[0x18]; #endif unsigned char lmbuffer[0x18]; -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) return result; @@ -651,7 +651,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* A safer but less compatible alternative is: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ + * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */ } if(unicode) { @@ -661,7 +661,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, } lmrespoff = 64; /* size of the message header */ -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES ntrespoff = lmrespoff + 0x18; domoff = ntrespoff + ntresplen; #else @@ -721,7 +721,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, SHORTPAIR(lmrespoff), 0x0, 0x0, -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES SHORTPAIR(ntresplen), /* NT-response length, twice */ SHORTPAIR(ntresplen), SHORTPAIR(ntrespoff), @@ -768,7 +768,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); }); -#if USE_NTRESPONSES +#ifdef USE_NTRESPONSES if(size < (NTLM_BUFSIZE - ntresplen)) { DEBUGASSERT(size == (size_t)ntrespoff); memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen); diff --git a/Utilities/cmcurl/lib/vauth/ntlm.h b/Utilities/cmcurl/lib/vauth/ntlm.h index b14e7a5..f906a3c 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm.h +++ b/Utilities/cmcurl/lib/vauth/ntlm.h @@ -32,7 +32,7 @@ /* Stuff only required for curl_ntlm_msgs.c */ #ifdef BUILDING_CURL_NTLM_MSGS_C -/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ +/* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */ #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) /* Indicates that Unicode strings are supported for use in security buffer diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c index 5fa95e2..a6797cd 100644 --- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c @@ -34,6 +34,7 @@ #include "warnless.h" #include "curl_multibyte.h" #include "sendf.h" +#include "strerror.h" /* The last #include files should be: */ #include "curl_memory.h" @@ -224,6 +225,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, free(chlg); if(GSS_ERROR(nego->status)) { + failf(data, "InitializeSecurityContext failed: %s", + Curl_sspi_strerror(data->easy_conn, nego->status)); return CURLE_OUT_OF_MEMORY; } diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c index ff4634e..f0e3766 100644 --- a/Utilities/cmcurl/lib/vtls/axtls.c +++ b/Utilities/cmcurl/lib/vtls/axtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>. - * Copyright (C) 2010 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -156,6 +156,12 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) same connection */ return CURLE_OK; + if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { + failf(data, "axtls does not support CURL_SSLVERSION_MAX"); + return CURLE_SSL_CONNECT_ERROR; + } + + /* axTLS only supports TLSv1 */ /* check to see if we've been told to use an explicit SSL/TLS version */ switch(SSL_CONN_CONFIG(version)) { @@ -256,7 +262,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) * 2) setting up callbacks. these seem gnutls specific */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { const uint8_t *ssl_sessionid; size_t ssl_idsize; @@ -267,13 +273,13 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* we got a session id, use it! */ infof(data, "SSL re-using session ID\n"); ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], - ssl_sessionid, (uint8_t)ssl_idsize); + ssl_sessionid, (uint8_t)ssl_idsize, NULL); } Curl_ssl_sessionid_unlock(conn); } if(!ssl) - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); + ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL); conn->ssl[sockindex].ssl = ssl; return CURLE_OK; @@ -386,9 +392,9 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) conn->send[sockindex] = axtls_send; /* Put our freshly minted SSL session in cache */ - if(data->set.general_ssl.sessionid) { - const uint8_t *ssl_sessionid = ssl_get_session_id_size(ssl); - size_t ssl_idsize = ssl_get_session_id(ssl); + if(SSL_SET_OPTION(primary.sessionid)) { + const uint8_t *ssl_sessionid = ssl_get_session_id(ssl); + size_t ssl_idsize = ssl_get_session_id_size(ssl); Curl_ssl_sessionid_lock(conn); if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize, sockindex) != CURLE_OK) @@ -680,9 +686,9 @@ size_t Curl_axtls_version(char *buffer, size_t size) return snprintf(buffer, size, "axTLS/%s", ssl_version()); } -int Curl_axtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_axtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { static bool ssl_seeded = FALSE; (void)data; @@ -694,7 +700,7 @@ int Curl_axtls_random(struct Curl_easy *data, RNG_initialize(); } get_random((int)length, entropy); - return 0; + return CURLE_OK; } #endif /* USE_AXTLS */ diff --git a/Utilities/cmcurl/lib/vtls/axtls.h b/Utilities/cmcurl/lib/vtls/axtls.h index b16d051..53797ea 100644 --- a/Utilities/cmcurl/lib/vtls/axtls.h +++ b/Utilities/cmcurl/lib/vtls/axtls.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu <ehu@directv.com> - * Copyright (C) 2010 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -42,9 +42,9 @@ void Curl_axtls_session_free(void *ptr); size_t Curl_axtls_version(char *buffer, size_t size); int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); int Curl_axtls_check_cxn(struct connectdata *conn); -int Curl_axtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_axtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); /* Set the API backend definition to axTLS */ #define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c index fc4dde4..5f51ad5 100644 --- a/Utilities/cmcurl/lib/vtls/cyassl.c +++ b/Utilities/cmcurl/lib/vtls/cyassl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -134,6 +134,7 @@ cyassl_connect_step1(struct connectdata *conn, int sockindex) { char error_buffer[CYASSL_MAX_ERROR_SZ]; + char *ciphers; struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; @@ -148,6 +149,11 @@ cyassl_connect_step1(struct connectdata *conn, if(conssl->state == ssl_connection_complete) return CURLE_OK; + if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) { + failf(data, "CyaSSL does not support to set maximum SSL/TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } + /* check to see if we've been told to use an explicit SSL/TLS version */ switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: @@ -229,6 +235,15 @@ cyassl_connect_step1(struct connectdata *conn, break; } + ciphers = SSL_CONN_CONFIG(cipher_list); + if(ciphers) { + if(!SSL_CTX_set_cipher_list(conssl->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s\n", ciphers); + } + #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { @@ -383,7 +398,7 @@ cyassl_connect_step1(struct connectdata *conn, #endif /* HAVE_ALPN */ /* Check if there's a cached ID we can/should use here! */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); @@ -581,7 +596,13 @@ cyassl_connect_step2(struct connectdata *conn, #endif /* HAVE_ALPN */ conssl->connecting_state = ssl_connect_3; +#if (LIBCYASSL_VERSION_HEX >= 0x03009010) + infof(data, "SSL connection using %s / %s\n", + wolfSSL_get_version(conssl->handle), + wolfSSL_get_cipher_name(conssl->handle)); +#else infof(data, "SSL connected\n"); +#endif return CURLE_OK; } @@ -597,7 +618,7 @@ cyassl_connect_step3(struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { bool incache; SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -720,7 +741,9 @@ void Curl_cyassl_session_free(void *ptr) size_t Curl_cyassl_version(char *buffer, size_t size) { -#ifdef WOLFSSL_VERSION +#if LIBCYASSL_VERSION_HEX >= 0x03006000 + return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version()); +#elif defined(WOLFSSL_VERSION) return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION); #elif defined(CYASSL_VERSION) return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); @@ -772,7 +795,7 @@ cyassl_connect_common(struct connectdata *conn, struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; + time_t timeout_ms; int what; /* check if the connection has already been established */ @@ -901,19 +924,19 @@ Curl_cyassl_connect(struct connectdata *conn, return CURLE_OK; } -int Curl_cyassl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_cyassl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { RNG rng; (void)data; if(InitRng(&rng)) - return 1; + return CURLE_FAILED_INIT; if(length > UINT_MAX) - return 1; + return CURLE_FAILED_INIT; if(RNG_GenerateBlock(&rng, entropy, (unsigned)length)) - return 1; - return 0; + return CURLE_FAILED_INIT; + return CURLE_OK; } void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ diff --git a/Utilities/cmcurl/lib/vtls/cyassl.h b/Utilities/cmcurl/lib/vtls/cyassl.h index 508dfaa..f47719e 100644 --- a/Utilities/cmcurl/lib/vtls/cyassl.h +++ b/Utilities/cmcurl/lib/vtls/cyassl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,15 +51,15 @@ int Curl_cyassl_init(void); CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -int Curl_cyassl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_cyassl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t unused); -/* Set the API backend definition to Schannel */ +/* Set the API backend definition to CyaSSL */ #define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL /* this backend supports CURLOPT_SSL_CTX_* */ diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.c b/Utilities/cmcurl/lib/vtls/darwinssl.c index a43e391..5533dfe 100644 --- a/Utilities/cmcurl/lib/vtls/darwinssl.c +++ b/Utilities/cmcurl/lib/vtls/darwinssl.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. - * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -219,6 +219,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection, return ortn; } +#ifndef CURL_DISABLE_VERBOSE_STRINGS CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { switch(cipher) { @@ -776,6 +777,7 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) } return "TLS_NULL_WITH_NULL_NULL"; } +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ #if CURL_BUILD_MAC CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) @@ -885,12 +887,13 @@ static OSStatus CopyIdentityWithLabel(char *label, SecIdentityRef *out_cert_and_key) { OSStatus status = errSecItemNotFound; + +#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS CFArrayRef keys_list; CFIndex keys_list_count; CFIndex i; CFStringRef common_name; -#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. kSecClassIdentity was introduced in Lion. If both exist, let's use them to find the certificate. */ @@ -929,28 +932,35 @@ static OSStatus CopyIdentityWithLabel(char *label, if(status == noErr) { keys_list_count = CFArrayGetCount(keys_list); *out_cert_and_key = NULL; + status = 1; for(i=0; i<keys_list_count; i++) { OSStatus err = noErr; SecCertificateRef cert = NULL; - *out_cert_and_key = + SecIdentityRef identity = (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i); - err = SecIdentityCopyCertificate(*out_cert_and_key, &cert); + err = SecIdentityCopyCertificate(identity, &cert); if(err == noErr) { +#if CURL_BUILD_IOS + common_name = SecCertificateCopySubjectSummary(cert); +#elif CURL_BUILD_MAC_10_7 SecCertificateCopyCommonName(cert, &common_name); +#endif if(CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) { CFRelease(cert); CFRelease(common_name); + CFRetain(identity); + *out_cert_and_key = identity; status = noErr; break; } CFRelease(common_name); } - *out_cert_and_key = NULL; - status = 1; CFRelease(cert); } } + if(keys_list) + CFRelease(keys_list); CFRelease(query_dict); CFRelease(label_cf); } @@ -1034,6 +1044,109 @@ CF_INLINE bool is_file(const char *filename) return false; } +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS +static CURLcode darwinssl_version_from_curl(long *darwinver, long ssl_version) +{ + switch(ssl_version) { + case CURL_SSLVERSION_TLSv1_0: + *darwinver = kTLSProtocol1; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1: + *darwinver = kTLSProtocol11; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2: + *darwinver = kTLSProtocol12; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } + return CURLE_SSL_CONNECT_ERROR; +} +#endif + +static CURLcode +set_ssl_version_min_max(struct connectdata *conn, int sockindex) +{ + struct Curl_easy *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_version = CURL_SSLVERSION_TLSv1_0; + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version << 16; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + +#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS + if(SSLSetProtocolVersionMax != NULL) { + SSLProtocol darwin_ver_min = kTLSProtocol1; + SSLProtocol darwin_ver_max = kTLSProtocol1; + CURLcode result = darwinssl_version_from_curl(&darwin_ver_min, + ssl_version); + if(result) { + failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); + return result; + } + result = darwinssl_version_from_curl(&darwin_ver_max, + ssl_version_max >> 16); + if(result) { + failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); + return result; + } + + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, darwin_ver_min); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, darwin_ver_max); + return result; + } + else { +#if CURL_SUPPORT_MAC_10_8 + long i = ssl_version; + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocolAll, + false); + for(; i <= (ssl_version_max >> 16); i++) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1_1: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, + true); + break; + case CURL_SSLVERSION_TLSv1_2: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "DarwinSSL: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + } + } + return CURLE_OK; +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ + failf(data, "DarwinSSL: cannot set SSL protocol"); + return CURLE_SSL_CONNECT_ERROR; +} + + static CURLcode darwinssl_connect_step1(struct connectdata *conn, int sockindex) { @@ -1103,20 +1216,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); break; case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1); - break; case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11); - break; case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "DarwinSSL: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(conn, sockindex); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv3: err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); if(err != noErr) { @@ -1157,23 +1265,15 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, true); break; case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol1, - true); - break; case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol11, - true); - break; case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol12, - true); - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "DarwinSSL: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(conn, sockindex); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv3: err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocol3, @@ -1199,6 +1299,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* CURL_SUPPORT_MAC_10_8 */ } #else + if(conn->ssl_config.version_max != CURL_SSLVERSION_MAX_NONE) { + failf(data, "Your version of the OS does not support to set maximum" + " SSL/TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: @@ -1385,18 +1490,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ - if(ssl_cafile) { + if(ssl_cafile && verifypeer) { bool is_cert_file = is_file(ssl_cafile); if(!is_cert_file) { failf(data, "SSL: can't load CA certificate file %s", ssl_cafile); return CURLE_SSL_CACERT_BADFILE; } - if(!verifypeer) { - failf(data, "SSL: CA certificate set, but certificate verification " - "is disabled"); - return CURLE_SSL_CONNECT_ERROR; - } } /* Configure hostname check. SNI is used if available. @@ -1420,6 +1520,9 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, "the OS.\n"); } } + else { + infof(data, "WARNING: disabling hostname validation also disables SNI.\n"); + } /* Disable cipher suites that ST supports but are not safe. These ciphers are unlikely to be used in any case since ST gives other ciphers a much @@ -1541,7 +1644,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ /* Check if there's a cached ID we can/should use here! */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { char *ssl_sessionid; size_t ssl_sessionid_len; @@ -1921,7 +2024,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* The below is errSSLServerAuthCompleted; it's not defined in Leopard's headers */ case -9841: - if(SSL_CONN_CONFIG(CAfile)) { + if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { int res = verify_cert(SSL_CONN_CONFIG(CAfile), data, connssl->ssl_ctx); if(res != CURLE_OK) @@ -2034,9 +2137,11 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) } } -static CURLcode -darwinssl_connect_step3(struct connectdata *conn, - int sockindex) +#ifndef CURL_DISABLE_VERBOSE_STRINGS +/* This should be called during step3 of the connection at the earliest */ +static void +show_verbose_server_cert(struct connectdata *conn, + int sockindex) { struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -2048,9 +2153,9 @@ darwinssl_connect_step3(struct connectdata *conn, CFIndex i, count; SecTrustRef trust = NULL; - /* There is no step 3! - * Well, okay, if verbose mode is on, let's print the details of the - * server certificates. */ + if(!connssl->ssl_ctx) + return; + #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS #pragma unused(server_certs) @@ -2147,6 +2252,23 @@ darwinssl_connect_step3(struct connectdata *conn, CFRelease(server_certs); } #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ +} +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ + +static CURLcode +darwinssl_connect_step3(struct connectdata *conn, + int sockindex) +{ + struct Curl_easy *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + /* There is no step 3! + * Well, okay, if verbose mode is on, let's print the details of the + * server certificates. */ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(data->set.verbose) + show_verbose_server_cert(conn, sockindex); +#endif connssl->connecting_state = ssl_connect_done; return CURLE_OK; @@ -2424,8 +2546,8 @@ bool Curl_darwinssl_data_pending(const struct connectdata *conn, return false; } -int Curl_darwinssl_random(unsigned char *entropy, - size_t length) +CURLcode Curl_darwinssl_random(unsigned char *entropy, + size_t length) { /* arc4random_buf() isn't available on cats older than Lion, so let's do this manually for the benefit of the older cats. */ @@ -2439,7 +2561,7 @@ int Curl_darwinssl_random(unsigned char *entropy, random_number >>= 8; } i = random_number = 0; - return 0; + return CURLE_OK; } void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.h b/Utilities/cmcurl/lib/vtls/darwinssl.h index 8b185b6..4bd41ca 100644 --- a/Utilities/cmcurl/lib/vtls/darwinssl.h +++ b/Utilities/cmcurl/lib/vtls/darwinssl.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. - * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -42,8 +42,8 @@ int Curl_darwinssl_check_cxn(struct connectdata *conn); bool Curl_darwinssl_data_pending(const struct connectdata *conn, int connindex); -int Curl_darwinssl_random(unsigned char *entropy, - size_t length); +CURLcode Curl_darwinssl_random(unsigned char *entropy, + size_t length); void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index a0d462b..bf75bdd 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -320,7 +320,7 @@ static CURLcode set_ciphers(struct connectdata *conn, /* We allocate GSKit buffers of the same size as the input string: since GSKit tokens are always shorter than their cipher names, allocated buffers - will always be large enough to accomodate the result. */ + will always be large enough to accommodate the result. */ l = strlen(cipherlist) + 1; memset((char *) ciphers, 0, sizeof ciphers); for(i = 0; i < CURL_GSKPROTO_LAST; i++) { @@ -748,6 +748,40 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, return (ssize_t) nread; } +static CURLcode +set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn) +{ + struct Curl_easy *data = conn->data; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + long i = ssl_version; + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_TLSv1_2; + break; + } + for(; i <= (ssl_version_max >> 16); ++i) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + *protoflags |= CURL_GSKPROTO_TLSV10_MASK; + break; + case CURL_SSLVERSION_TLSv1_1: + *protoflags |= CURL_GSKPROTO_TLSV11_MASK; + break; + case CURL_SSLVERSION_TLSv1_2: + *protoflags |= CURL_GSKPROTO_TLSV11_MASK; + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "GSKit: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + } + } + + return CURLE_OK; +} static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) { @@ -764,7 +798,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: conn->host.name; const char *sni; - unsigned int protoflags; + unsigned int protoflags = 0; long timeout; Qso_OverlappedIO_t commarea; int sockpair[2]; @@ -849,17 +883,13 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; break; case CURL_SSLVERSION_TLSv1_0: - protoflags = CURL_GSKPROTO_TLSV10_MASK; - break; case CURL_SSLVERSION_TLSv1_1: - protoflags = CURL_GSKPROTO_TLSV11_MASK; - break; case CURL_SSLVERSION_TLSv1_2: - protoflags = CURL_GSKPROTO_TLSV12_MASK; - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "GSKit: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + result = set_ssl_version_min_max(&protoflags, conn); + if(result != CURLE_OK) + return result; + break; default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index 0e308cb..0230778 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -92,11 +92,11 @@ static bool gtls_inited = FALSE; # define GNUTLS_MAPS_WINSOCK_ERRORS 1 # endif -# if (GNUTLS_VERSION_NUMBER >= 0x030200) +# if HAVE_GNUTLS_ALPN_SET_PROTOCOLS # define HAS_ALPN # endif -# if (GNUTLS_VERSION_NUMBER >= 0x03020d) +# if HAVE_GNUTLS_OCSP_REQ_INIT # define HAS_OCSP # endif @@ -278,7 +278,7 @@ static CURLcode handshake(struct connectdata *conn, struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gnutls_session_t session = conn->ssl[sockindex].session; curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; + time_t timeout_ms; int rc; int what; @@ -314,7 +314,7 @@ static CURLcode handshake(struct connectdata *conn, return CURLE_OK; else if(timeout_ms) { /* timeout */ - failf(data, "SSL connection timeout at %ld", timeout_ms); + failf(data, "SSL connection timeout at %ld", (long)timeout_ms); return CURLE_OPERATION_TIMEDOUT; } } @@ -375,11 +375,106 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type) return -1; } +#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT +static CURLcode +set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn) +{ + struct Curl_easy *data = conn->data; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + long i = ssl_version; + long protocol_priority_idx = 0; + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version << 16; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + for(; i <= (ssl_version_max >> 16) && + protocol_priority_idx < list_size; ++i) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0; + break; + case CURL_SSLVERSION_TLSv1_1: + protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1; + break; + case CURL_SSLVERSION_TLSv1_2: + protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2; + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "GnuTLS: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + } + } + return CURLE_OK; +} +#else +#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" +/* If GnuTLS was compiled without support for SRP it will error out if SRP is + requested in the priority string, so treat it specially + */ +#define GNUTLS_SRP "+SRP" + +static CURLcode +set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn) +{ + struct Curl_easy *data = conn->data; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + if(ssl_version == CURL_SSLVERSION_TLSv1_3 || + ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) { + failf(data, "GnuTLS: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + } + if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { + ssl_version_max = ssl_version << 16; + } + switch(ssl_version | ssl_version_max) { + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:" GNUTLS_SRP; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2: + case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:" GNUTLS_SRP; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2: + case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2: + case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT: + *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" + "+VERS-TLS1.2:" GNUTLS_SRP; + return CURLE_OK; + } + + failf(data, "GnuTLS: cannot set ssl protocol"); + return CURLE_SSL_CONNECT_ERROR; +} +#endif + static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { struct Curl_easy *data = conn->data; + unsigned int init_flags; gnutls_session_t session; int rc; bool sni = TRUE; /* default is SNI enabled */ @@ -405,13 +500,8 @@ gtls_connect_step1(struct connectdata *conn, GNUTLS_CIPHER_3DES_CBC, }; static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 }; - static int protocol_priority[] = { 0, 0, 0, 0 }; + int protocol_priority[] = { 0, 0, 0, 0 }; #else -#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509" -/* If GnuTLS was compiled without support for SRP it will error out if SRP is - requested in the priority string, so treat it specially - */ -#define GNUTLS_SRP "+SRP" const char *prioritylist; const char *err = NULL; #endif @@ -526,7 +616,14 @@ gtls_connect_step1(struct connectdata *conn, } /* Initialize TLS session as a client */ - rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); + init_flags = GNUTLS_CLIENT; + +#if defined(GNUTLS_NO_TICKETS) + /* Disable TLS session tickets */ + init_flags |= GNUTLS_NO_TICKETS; +#endif + + rc = gnutls_init(&conn->ssl[sockindex].session, init_flags); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; @@ -568,7 +665,7 @@ gtls_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } - switch(SSL_CONN_CONFIG(version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv3: protocol_priority[0] = GNUTLS_SSL3; break; @@ -579,17 +676,16 @@ gtls_connect_step1(struct connectdata *conn, protocol_priority[2] = GNUTLS_TLS1_2; break; case CURL_SSLVERSION_TLSv1_0: - protocol_priority[0] = GNUTLS_TLS1_0; - break; case CURL_SSLVERSION_TLSv1_1: - protocol_priority[0] = GNUTLS_TLS1_1; - break; case CURL_SSLVERSION_TLSv1_2: - protocol_priority[0] = GNUTLS_TLS1_2; - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(protocol_priority, + sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv2: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; @@ -617,20 +713,15 @@ gtls_connect_step1(struct connectdata *conn, prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP; break; case CURL_SSLVERSION_TLSv1_0: - prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.0:" GNUTLS_SRP; - break; case CURL_SSLVERSION_TLSv1_1: - prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.1:" GNUTLS_SRP; - break; case CURL_SSLVERSION_TLSv1_2: - prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" - "+VERS-TLS1.2:" GNUTLS_SRP; - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "GnuTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(&prioritylist, conn); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv2: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; @@ -782,7 +873,7 @@ gtls_connect_step1(struct connectdata *conn, /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid; size_t ssl_idsize; @@ -882,7 +973,9 @@ gtls_connect_step3(struct connectdata *conn, gnutls_datum_t proto; #endif CURLcode result = CURLE_OK; +#ifndef CURL_DISABLE_VERBOSE_STRINGS gnutls_protocol_t version = gnutls_protocol_get_version(session); +#endif const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; @@ -1311,7 +1404,7 @@ gtls_connect_step3(struct connectdata *conn, conn->recv[sockindex] = gtls_recv; conn->send[sockindex] = gtls_send; - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { /* we always unconditionally get the session id here, as even if we already got it from the cache and asked to use it in the connection, it might've been rejected and then a new one is in use now and we need to @@ -1625,19 +1718,21 @@ static int Curl_gtls_seed(struct Curl_easy *data) #endif /* data might be NULL! */ -int Curl_gtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_gtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { #if defined(USE_GNUTLS_NETTLE) + int rc; (void)data; - gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); + rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); + return rc?CURLE_FAILED_INIT:CURLE_OK; #elif defined(USE_GNUTLS) if(data) Curl_gtls_seed(data); /* Initiate the seed if not already done */ gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); #endif - return 0; + return CURLE_OK; } void Curl_gtls_md5sum(unsigned char *tmp, /* input */ diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h index 6531201..462c048 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.h +++ b/Utilities/cmcurl/lib/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -43,9 +43,9 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex); void Curl_gtls_session_free(void *ptr); size_t Curl_gtls_version(char *buffer, size_t size); int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); -int Curl_gtls_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_gtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); void Curl_gtls_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index 8bcaddd..3ffa957 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> - * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -157,6 +157,71 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = static Curl_recv mbed_recv; static Curl_send mbed_send; +static CURLcode mbedtls_version_from_curl(int *mbedver, long version) +{ + switch(version) { + case CURL_SSLVERSION_TLSv1_0: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_2; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } + return CURLE_SSL_CONNECT_ERROR; +} + +static CURLcode +set_ssl_version_min_max(struct connectdata *conn, int sockindex) +{ + struct Curl_easy *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; + int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + CURLcode result = CURLE_OK; + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_version = CURL_SSLVERSION_TLSv1_0; + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version << 16; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version); + if(result) { + failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); + return result; + } + result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16); + if(result) { + failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); + return result; + } + + mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ver_min); + mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, + mbedtls_ver_max); + + return result; +} + static CURLcode mbed_connect_step1(struct connectdata *conn, int sockindex) @@ -333,29 +398,15 @@ mbed_connect_step1(struct connectdata *conn, infof(data, "mbedTLS: Set SSL version to SSLv3\n"); break; case CURL_SSLVERSION_TLSv1_0: - mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_1); - mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_1); - infof(data, "mbedTLS: Set SSL version to TLS 1.0\n"); - break; case CURL_SSLVERSION_TLSv1_1: - mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_2); - mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_2); - infof(data, "mbedTLS: Set SSL version to TLS 1.1\n"); - break; case CURL_SSLVERSION_TLSv1_2: - mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_3); - mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, - MBEDTLS_SSL_MINOR_VERSION_3); - infof(data, "mbedTLS: Set SSL version to TLS 1.2\n"); - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "mbedTLS: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(conn, sockindex); + if(result != CURLE_OK) + return result; + break; + } default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; @@ -373,8 +424,13 @@ mbed_connect_step1(struct connectdata *conn, mbedtls_ssl_conf_ciphersuites(&connssl->config, mbedtls_ssl_list_ciphersuites()); +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + mbedtls_ssl_conf_session_tickets(&connssl->config, + MBEDTLS_SSL_SESSION_TICKETS_DISABLED); +#endif + /* Check if there's a cached ID we can/should use here! */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { void *old_session = NULL; Curl_ssl_sessionid_lock(conn); @@ -439,6 +495,16 @@ mbed_connect_step1(struct connectdata *conn, mbedtls_debug_set_threshold(4); #endif + /* give application a chance to interfere with mbedTLS set up. */ + if(data->set.ssl.fsslctx) { + ret = (*data->set.ssl.fsslctx)(data, &connssl->config, + data->set.ssl.fsslctxp); + if(ret) { + failf(data, "error signaled by ssl ctx callback"); + return ret; + } + } + connssl->connecting_state = ssl_connect_2; return CURLE_OK; @@ -618,7 +684,7 @@ mbed_connect_step3(struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { int ret; mbedtls_ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -631,6 +697,7 @@ mbed_connect_step3(struct connectdata *conn, ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid); if(ret) { + free(our_ssl_sessionid); failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); return CURLE_SSL_CONNECT_ERROR; } @@ -729,6 +796,55 @@ size_t Curl_mbedtls_version(char *buffer, size_t size) (version>>16)&0xff, (version>>8)&0xff); } +CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, + size_t length) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + int ret = -1; + char errorbuf[128]; + mbedtls_entropy_context ctr_entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_init(&ctr_entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + errorbuf[0]=0; + + ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, + &ctr_entropy, NULL, 0); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n", + -ret, errorbuf); + } + else { + ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } + } + + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&ctr_entropy); + + return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; +#elif defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state hs; + mbedtls_havege_init(&hs); + mbedtls_havege_random(&hs, entropy, length); + mbedtls_havege_free(&hs); + return CURLE_OK; +#else + return CURLE_NOT_BUILT_IN; +#endif +} + static CURLcode mbed_connect_common(struct connectdata *conn, int sockindex, @@ -883,9 +999,7 @@ void Curl_mbedtls_cleanup(void) int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) { - mbedtls_ssl_context *ssl = - (mbedtls_ssl_context *)&conn->ssl[sockindex].ssl; - return ssl->in_msglen != 0; + return mbedtls_ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0; } #endif /* USE_MBEDTLS */ diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.h b/Utilities/cmcurl/lib/vtls/mbedtls.h index 1021d54..71d17a4 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.h +++ b/Utilities/cmcurl/lib/vtls/mbedtls.h @@ -50,9 +50,15 @@ void Curl_mbedtls_session_free(void *ptr); size_t Curl_mbedtls_version(char *buffer, size_t size); int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); +CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, + size_t length); + /* this backends supports CURLOPT_PINNEDPUBLICKEY */ #define have_curlssl_pinnedpubkey 1 +/* this backend supports CURLOPT_SSL_CTX_* */ +#define have_curlssl_ssl_ctx 1 + /* API setup for mbedTLS */ #define curlssl_init() Curl_mbedtls_init() #define curlssl_cleanup() Curl_mbedtls_cleanup() @@ -70,11 +76,7 @@ int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); #define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y) #define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS #define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0) - -/* This might cause libcurl to use a weeker random! - TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that -*/ -#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) +#define curlssl_random(x,y,z) Curl_mbedtls_random(x, y, z) #endif /* USE_MBEDTLS */ #endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index ba8d582..89a16d3 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,7 +56,8 @@ #include <base64.h> #include <cert.h> #include <prerror.h> -#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */ +#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */ +#include <private/pprio.h> /* for PR_ImportTCPSocket */ #define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH) @@ -77,11 +78,10 @@ /* enough to fit the string "PEM Token #[0|1]" */ #define SLOTSIZE 13 -PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd); static PRLock *nss_initlock = NULL; static PRLock *nss_crllock = NULL; static PRLock *nss_findslot_lock = NULL; -static struct curl_llist *nss_crl_list = NULL; +static struct curl_llist nss_crl_list; static NSSInitContext *nss_context = NULL; static volatile int initialized = 0; @@ -365,9 +365,9 @@ static char *dup_nickname(struct Curl_easy *data, const char *str) static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name) { PK11SlotInfo *slot; - PR_Lock(nss_initlock); + PR_Lock(nss_findslot_lock); slot = PK11_FindSlotByName(slot_name); - PR_Unlock(nss_initlock); + PR_Unlock(nss_findslot_lock); return slot; } @@ -401,7 +401,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename, - strlen(filename) + 1); + (CK_ULONG)strlen(filename) + 1); if(CKO_CERTIFICATE == obj_class) { CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse); @@ -413,7 +413,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, if(!obj) return result; - if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) { + if(!Curl_llist_insert_next(&ssl->obj_list, ssl->obj_list.tail, obj)) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } @@ -496,7 +496,7 @@ static CURLcode nss_cache_crl(SECItem *crl_der) PR_Lock(nss_crllock); /* store the CRL item so that we can free it in Curl_nss_cleanup() */ - if(!Curl_llist_insert_next(nss_crl_list, nss_crl_list->tail, crl_der)) { + if(!Curl_llist_insert_next(&nss_crl_list, nss_crl_list.tail, crl_der)) { SECITEM_FreeItem(crl_der, PR_TRUE); PR_Unlock(nss_crllock); return CURLE_OUT_OF_MEMORY; @@ -1227,9 +1227,7 @@ static CURLcode nss_init(struct Curl_easy *data) return CURLE_OK; /* list of all CRL items we need to destroy in Curl_nss_cleanup() */ - nss_crl_list = Curl_llist_alloc(nss_destroy_crl_item); - if(!nss_crl_list) - return CURLE_OUT_OF_MEMORY; + Curl_llist_init(&nss_crl_list, nss_destroy_crl_item); /* First we check if $SSL_DIR points to a valid dir */ cert_dir = getenv("SSL_DIR"); @@ -1336,8 +1334,7 @@ void Curl_nss_cleanup(void) } /* destroy all CRL items */ - Curl_llist_destroy(nss_crl_list, NULL); - nss_crl_list = NULL; + Curl_llist_destroy(&nss_crl_list, NULL); PR_Unlock(nss_initlock); @@ -1385,8 +1382,7 @@ static void nss_close(struct ssl_connect_data *connssl) connssl->client_nickname = NULL; /* destroy all NSS objects in order to avoid failure of NSS shutdown */ - Curl_llist_destroy(connssl->obj_list, NULL); - connssl->obj_list = NULL; + Curl_llist_destroy(&connssl->obj_list, NULL); connssl->obj_clicert = NULL; if(connssl->handle) { @@ -1512,78 +1508,108 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, return CURLE_OK; } -static CURLcode nss_init_sslver(SSLVersionRange *sslver, - struct Curl_easy *data, - struct connectdata *conn) +static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version) { - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_DEFAULT: - /* map CURL_SSLVERSION_DEFAULT to NSS default */ - if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess) - return CURLE_SSL_CONNECT_ERROR; - /* ... but make sure we use at least TLSv1.0 according to libcurl API */ - if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0) - sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; - return CURLE_OK; - + switch(version) { case CURL_SSLVERSION_TLSv1: - sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */ #ifdef SSL_LIBRARY_VERSION_TLS_1_2 - sslver->max = SSL_LIBRARY_VERSION_TLS_1_2; + *nssver = SSL_LIBRARY_VERSION_TLS_1_2; #elif defined SSL_LIBRARY_VERSION_TLS_1_1 - sslver->max = SSL_LIBRARY_VERSION_TLS_1_1; + *nssver = SSL_LIBRARY_VERSION_TLS_1_1; #else - sslver->max = SSL_LIBRARY_VERSION_TLS_1_0; + *nssver = SSL_LIBRARY_VERSION_TLS_1_0; #endif return CURLE_OK; case CURL_SSLVERSION_SSLv2: - sslver->min = SSL_LIBRARY_VERSION_2; - sslver->max = SSL_LIBRARY_VERSION_2; + *nssver = SSL_LIBRARY_VERSION_2; return CURLE_OK; case CURL_SSLVERSION_SSLv3: - sslver->min = SSL_LIBRARY_VERSION_3_0; - sslver->max = SSL_LIBRARY_VERSION_3_0; + *nssver = SSL_LIBRARY_VERSION_3_0; return CURLE_OK; case CURL_SSLVERSION_TLSv1_0: - sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; - sslver->max = SSL_LIBRARY_VERSION_TLS_1_0; + *nssver = SSL_LIBRARY_VERSION_TLS_1_0; return CURLE_OK; case CURL_SSLVERSION_TLSv1_1: #ifdef SSL_LIBRARY_VERSION_TLS_1_1 - sslver->min = SSL_LIBRARY_VERSION_TLS_1_1; - sslver->max = SSL_LIBRARY_VERSION_TLS_1_1; + *nssver = SSL_LIBRARY_VERSION_TLS_1_1; return CURLE_OK; +#else + return CURLE_SSL_CONNECT_ERROR; #endif - break; case CURL_SSLVERSION_TLSv1_2: #ifdef SSL_LIBRARY_VERSION_TLS_1_2 - sslver->min = SSL_LIBRARY_VERSION_TLS_1_2; - sslver->max = SSL_LIBRARY_VERSION_TLS_1_2; + *nssver = SSL_LIBRARY_VERSION_TLS_1_2; return CURLE_OK; +#else + return CURLE_SSL_CONNECT_ERROR; #endif - break; case CURL_SSLVERSION_TLSv1_3: #ifdef SSL_LIBRARY_VERSION_TLS_1_3 - sslver->min = SSL_LIBRARY_VERSION_TLS_1_3; - sslver->max = SSL_LIBRARY_VERSION_TLS_1_3; + *nssver = SSL_LIBRARY_VERSION_TLS_1_3; return CURLE_OK; +#else + return CURLE_SSL_CONNECT_ERROR; #endif - break; default: - failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } +} + +static CURLcode nss_init_sslver(SSLVersionRange *sslver, + struct Curl_easy *data, + struct connectdata *conn) +{ + CURLcode result; + const long min = SSL_CONN_CONFIG(version); + const long max = SSL_CONN_CONFIG(version_max); + + /* map CURL_SSLVERSION_DEFAULT to NSS default */ + if(min == CURL_SSLVERSION_DEFAULT || max == CURL_SSLVERSION_MAX_DEFAULT) { + /* map CURL_SSLVERSION_DEFAULT to NSS default */ + if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess) + return CURLE_SSL_CONNECT_ERROR; + /* ... but make sure we use at least TLSv1.0 according to libcurl API */ + if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0) + sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; + } + + switch(min) { + case CURL_SSLVERSION_DEFAULT: + break; + case CURL_SSLVERSION_TLSv1: + sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; + break; + default: + result = nss_sslver_from_curl(&sslver->min, min); + if(result) { + failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); + return result; + } + if(max == CURL_SSLVERSION_MAX_NONE) + sslver->max = sslver->min; + } + + switch(max) { + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + break; + default: + result = nss_sslver_from_curl(&sslver->max, max >> 16); + if(result) { + failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); + return result; + } + } - failf(data, "TLS minor version cannot be set"); - return CURLE_SSL_CONNECT_ERROR; + return CURLE_OK; } static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, @@ -1606,19 +1632,19 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, } /* cleanup on connection failure */ - Curl_llist_destroy(connssl->obj_list, NULL); - connssl->obj_list = NULL; + Curl_llist_destroy(&connssl->obj_list, NULL); return curlerr; } -/* Switch the SSL socket into non-blocking mode. */ -static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl, - struct Curl_easy *data) +/* Switch the SSL socket into blocking or non-blocking mode. */ +static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, + struct Curl_easy *data, + bool blocking) { static PRSocketOptionData sock_opt; sock_opt.option = PR_SockOpt_Nonblocking; - sock_opt.value.non_blocking = PR_TRUE; + sock_opt.value.non_blocking = !blocking; if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS) return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); @@ -1647,9 +1673,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) connssl->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ - connssl->obj_list = Curl_llist_alloc(nss_destroy_object); - if(!connssl->obj_list) - return CURLE_OUT_OF_MEMORY; + Curl_llist_init(&connssl->obj_list, nss_destroy_object); /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); @@ -1696,7 +1720,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; /* do not use SSL cache if disabled or we are not going to verify peer */ - ssl_no_cache = (data->set.general_ssl.sessionid + ssl_no_cache = (SSL_SET_OPTION(primary.sessionid) && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; @@ -1746,9 +1770,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess) goto error; - if(SSL_CONN_CONFIG(verifypeer)) { + { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); - if(rv) { + if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer)) + /* not a fatal error because we are not going to verify the peer */ + infof(data, "warning: CA certificates failed to load\n"); + else if(rv) { result = rv; goto error; } @@ -1933,8 +1960,8 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) /* check timeout situation */ - const long time_left = Curl_timeleft(data, NULL, TRUE); - if(time_left < 0L) { + const time_t time_left = Curl_timeleft(data, NULL, TRUE); + if(time_left < 0) { failf(data, "timed out before SSL handshake"); result = CURLE_OPERATION_TIMEDOUT; goto error; @@ -2007,16 +2034,14 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, /* we do not expect CURLE_AGAIN from nss_setup_connect() */ return result; - if(!blocking) { - /* in non-blocking mode, set NSS non-blocking mode before handshake */ - result = nss_set_nonblock(connssl, data); - if(result) - return result; - } - connssl->connecting_state = ssl_connect_2; } + /* enable/disable blocking mode before handshake */ + result = nss_set_blocking(connssl, data, blocking); + if(result) + return result; + result = nss_do_connect(conn, sockindex); switch(result) { case CURLE_OK: @@ -2032,7 +2057,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, if(blocking) { /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ - result = nss_set_nonblock(connssl, data); + result = nss_set_blocking(connssl, data, /* blocking */ FALSE); if(result) return result; } @@ -2138,17 +2163,17 @@ int Curl_nss_seed(struct Curl_easy *data) } /* data might be NULL */ -int Curl_nss_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_nss_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { Curl_nss_seed(data); /* Initiate the seed if not already done */ if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) /* signal a failure */ - return -1; + return CURLE_FAILED_INIT; - return 0; + return CURLE_OK; } void Curl_nss_md5sum(unsigned char *tmp, /* input */ diff --git a/Utilities/cmcurl/lib/vtls/nssg.h b/Utilities/cmcurl/lib/vtls/nssg.h index fd94003..8c46929 100644 --- a/Utilities/cmcurl/lib/vtls/nssg.h +++ b/Utilities/cmcurl/lib/vtls/nssg.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,9 +47,9 @@ int Curl_nss_seed(struct Curl_easy *data); /* initialize NSS library if not already */ CURLcode Curl_nss_force_init(struct Curl_easy *data); -int Curl_nss_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_nss_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); void Curl_nss_md5sum(unsigned char *tmp, /* input */ size_t tmplen, diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index d92e713..58a014a 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,7 +55,9 @@ #include <openssl/ssl.h> #include <openssl/rand.h> #include <openssl/x509v3.h> +#ifndef OPENSSL_NO_DSA #include <openssl/dsa.h> +#endif #include <openssl/dh.h> #include <openssl/err.h> #include <openssl/md5.h> @@ -156,10 +158,56 @@ static unsigned long OpenSSL_version_num(void) * Number of bytes to read from the random number seed file. This must be * a finite value (because some entropy "files" like /dev/urandom have * an infinite length), but must be large enough to provide enough - * entopy to properly seed OpenSSL's PRNG. + * entropy to properly seed OpenSSL's PRNG. */ #define RAND_LOAD_LENGTH 1024 +static const char *SSL_ERROR_to_str(int err) +{ + switch(err) { + case SSL_ERROR_NONE: + return "SSL_ERROR_NONE"; + case SSL_ERROR_SSL: + return "SSL_ERROR_SSL"; + case SSL_ERROR_WANT_READ: + return "SSL_ERROR_WANT_READ"; + case SSL_ERROR_WANT_WRITE: + return "SSL_ERROR_WANT_WRITE"; + case SSL_ERROR_WANT_X509_LOOKUP: + return "SSL_ERROR_WANT_X509_LOOKUP"; + case SSL_ERROR_SYSCALL: + return "SSL_ERROR_SYSCALL"; + case SSL_ERROR_ZERO_RETURN: + return "SSL_ERROR_ZERO_RETURN"; + case SSL_ERROR_WANT_CONNECT: + return "SSL_ERROR_WANT_CONNECT"; + case SSL_ERROR_WANT_ACCEPT: + return "SSL_ERROR_WANT_ACCEPT"; +#if defined(SSL_ERROR_WANT_ASYNC) + case SSL_ERROR_WANT_ASYNC: + return "SSL_ERROR_WANT_ASYNC"; +#endif +#if defined(SSL_ERROR_WANT_ASYNC_JOB) + case SSL_ERROR_WANT_ASYNC_JOB: + return "SSL_ERROR_WANT_ASYNC_JOB"; +#endif +#if defined(SSL_ERROR_WANT_EARLY) + case SSL_ERROR_WANT_EARLY: + return "SSL_ERROR_WANT_EARLY"; +#endif + default: + return "SSL_ERROR unknown"; + } +} + +/* Return error string for last OpenSSL error + */ +static char *ossl_strerror(unsigned long error, char *buf, size_t size) +{ + ERR_error_string_n(error, buf, size); + return buf; +} + static int passwd_callback(char *buf, int num, int encrypting, void *global_passwd) { @@ -335,6 +383,7 @@ int cert_stuff(struct connectdata *conn, char *key_passwd) { struct Curl_easy *data = conn->data; + char error_buffer[256]; int file_type = do_file_type(cert_type); @@ -360,7 +409,8 @@ int cert_stuff(struct connectdata *conn, "could not load PEM client certificate, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", - ERR_error_string(ERR_get_error(), NULL) ); + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); return 0; } break; @@ -376,7 +426,8 @@ int cert_stuff(struct connectdata *conn, "could not load ASN1 client certificate, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", - ERR_error_string(ERR_get_error(), NULL) ); + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); return 0; } break; @@ -405,7 +456,8 @@ int cert_stuff(struct connectdata *conn, 0, ¶ms, NULL, 1)) { failf(data, "ssl engine cannot load client cert with id" " '%s' [%s]", cert_file, - ERR_error_string(ERR_get_error(), NULL)); + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); return 0; } @@ -461,7 +513,8 @@ int cert_stuff(struct connectdata *conn, failf(data, "could not parse PKCS12 file, check password, " OSSL_PACKAGE " error %s", - ERR_error_string(ERR_get_error(), NULL) ); + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); PKCS12_free(p12); return 0; } @@ -472,7 +525,8 @@ int cert_stuff(struct connectdata *conn, failf(data, "could not load PKCS12 client certificate, " OSSL_PACKAGE " error %s", - ERR_error_string(ERR_get_error(), NULL) ); + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); goto fail; } @@ -493,21 +547,19 @@ int cert_stuff(struct connectdata *conn, /* * Note that sk_X509_pop() is used below to make sure the cert is * removed from the stack properly before getting passed to - * SSL_CTX_add_extra_chain_cert(). Previously we used - * sk_X509_value() instead, but then we'd clean it in the subsequent - * sk_X509_pop_free() call. + * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously + * we used sk_X509_value() instead, but then we'd clean it in the + * subsequent sk_X509_pop_free() call. */ X509 *x = sk_X509_pop(ca); - if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { + if(!SSL_CTX_add_client_CA(ctx, x)) { X509_free(x); - failf(data, "cannot add certificate to certificate chain"); + failf(data, "cannot add certificate to client CA list"); goto fail; } - /* SSL_CTX_add_client_CA() seems to work with either sk_* function, - * presumably because it duplicates what we pass to it. - */ - if(!SSL_CTX_add_client_CA(ctx, x)) { - failf(data, "cannot add certificate to client CA list"); + if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { + X509_free(x); + failf(data, "cannot add certificate to certificate chain"); goto fail; } } @@ -541,6 +593,7 @@ int cert_stuff(struct connectdata *conn, if(!key_file) /* cert & key can only be in PEM case in the same file */ key_file=cert_file; + /* FALLTHROUGH */ case SSL_FILETYPE_ASN1: if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { failf(data, "unable to set private key file: '%s' type %s", @@ -664,17 +717,6 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) #endif } -/* Return error string for last OpenSSL error - */ -static char *ossl_strerror(unsigned long error, char *buf, size_t size) -{ - /* OpenSSL 0.9.6 and later has a function named - ERR_error_string_n() that takes the size of the buffer as a - third argument */ - ERR_error_string_n(error, buf, size); - return buf; -} - /** * Global SSL init * @@ -776,7 +818,7 @@ int Curl_ossl_check_cxn(struct connectdata *conn) (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); if(nread == 0) return 0; /* connection has been closed */ - else if(nread == 1) + if(nread == 1) return 1; /* connection still in place */ else if(nread == -1) { int err = SOCKERRNO; @@ -981,8 +1023,10 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) default: /* openssl/ssl.h says "look at error stack/return value/errno" */ sslerror = ERR_get_error(); - failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d", - ossl_strerror(sslerror, buf, sizeof(buf)), + failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d", + (sslerror ? + ossl_strerror(sslerror, buf, sizeof(buf)) : + SSL_ERROR_to_str(err)), SOCKERRNO); done = 1; break; @@ -1609,7 +1653,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, #ifdef HAS_NPN /* - * in is a list of lenght prefixed strings. this function has to select + * in is a list of length prefixed strings. this function has to select * the protocol we want to use from the list and write its string into out. */ @@ -1693,6 +1737,85 @@ get_ssl_version_txt(SSL *ssl) return "unknown"; } +static CURLcode +set_ssl_version_min_max(long *ctx_options, struct connectdata *conn, + int sockindex) +{ +#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION) + /* convoluted #if condition just to avoid compiler warnings on unused + variable */ + struct Curl_easy *data = conn->data; +#endif + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + + if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) { + ssl_version_max = ssl_version << 16; + } + + switch(ssl_version) { + case CURL_SSLVERSION_TLSv1_3: +#ifdef TLS1_3_VERSION + { + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION); + *ctx_options |= SSL_OP_NO_TLSv1_2; + } +#else + (void)sockindex; + failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); + return CURLE_NOT_BUILT_IN; +#endif + case CURL_SSLVERSION_TLSv1_2: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1_1; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); + return CURLE_NOT_BUILT_IN; +#endif + /* FALLTHROUGH */ + case CURL_SSLVERSION_TLSv1_1: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); + return CURLE_NOT_BUILT_IN; +#endif + /* FALLTHROUGH */ + case CURL_SSLVERSION_TLSv1_0: + *ctx_options |= SSL_OP_NO_SSLv2; + *ctx_options |= SSL_OP_NO_SSLv3; + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_TLSv1_0: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1_1; +#endif + /* FALLTHROUGH */ + case CURL_SSLVERSION_MAX_TLSv1_1: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL + *ctx_options |= SSL_OP_NO_TLSv1_2; +#endif + /* FALLTHROUGH */ + case CURL_SSLVERSION_MAX_TLSv1_2: + case CURL_SSLVERSION_MAX_DEFAULT: +#ifdef TLS1_3_VERSION + *ctx_options |= SSL_OP_NO_TLSv1_3; +#endif + break; + case CURL_SSLVERSION_MAX_TLSv1_3: +#ifdef TLS1_3_VERSION + break; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); + return CURLE_NOT_BUILT_IN; +#endif + } + return CURLE_OK; +} + static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; @@ -1702,9 +1825,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) X509_LOOKUP *lookup = NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - long ctx_options; + long ctx_options = 0; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME bool sni; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -1723,8 +1848,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) const char * const ssl_capath = SSL_CONN_CONFIG(CApath); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : - conn->host.name; + char error_buffer[256]; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); @@ -1790,7 +1914,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(!connssl->ctx) { failf(data, "SSL: couldn't create a context: %s", - ERR_error_string(ERR_peek_error(), NULL)); + ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer))); return CURLE_OUT_OF_MEMORY; } @@ -1889,60 +2013,13 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) break; case CURL_SSLVERSION_TLSv1_0: - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_SSLv3; -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_TLSv1_1; - ctx_options |= SSL_OP_NO_TLSv1_2; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif -#endif - break; - case CURL_SSLVERSION_TLSv1_1: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_SSLv3; - ctx_options |= SSL_OP_NO_TLSv1; - ctx_options |= SSL_OP_NO_TLSv1_2; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif - break; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); - return CURLE_NOT_BUILT_IN; -#endif - case CURL_SSLVERSION_TLSv1_2: -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_SSLv3; - ctx_options |= SSL_OP_NO_TLSv1; - ctx_options |= SSL_OP_NO_TLSv1_1; -#ifdef TLS1_3_VERSION - ctx_options |= SSL_OP_NO_TLSv1_3; -#endif - break; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); - return CURLE_NOT_BUILT_IN; -#endif - case CURL_SSLVERSION_TLSv1_3: -#ifdef TLS1_3_VERSION - SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION); - ctx_options |= SSL_OP_NO_SSLv2; - ctx_options |= SSL_OP_NO_SSLv3; - ctx_options |= SSL_OP_NO_TLSv1; - ctx_options |= SSL_OP_NO_TLSv1_1; - ctx_options |= SSL_OP_NO_TLSv1_2; + result = set_ssl_version_min_max(&ctx_options, conn, sockindex); + if(result != CURLE_OK) + return result; break; -#else - failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); - return CURLE_NOT_BUILT_IN; -#endif case CURL_SSLVERSION_SSLv2: #ifndef OPENSSL_NO_SSL2 @@ -2056,12 +2133,10 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } - else { - /* Just continue with a warning if no strict certificate verification - is required. */ - infof(data, "error setting certificate verify locations," - " continuing anyway:\n"); - } + /* Just continue with a warning if no strict certificate verification + is required. */ + infof(data, "error setting certificate verify locations," + " continuing anyway:\n"); } else { /* Everything is fine. */ @@ -2091,12 +2166,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) failf(data, "error loading CRL file: %s", ssl_crlfile); return CURLE_SSL_CRL_BADFILE; } - else { - /* Everything is fine. */ - infof(data, "successfully load CRL file:\n"); - X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), - X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); - } + /* Everything is fine. */ + infof(data, "successfully load CRL file:\n"); + X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + infof(data, " CRLfile: %s\n", ssl_crlfile); } @@ -2161,7 +2235,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #endif /* Check if there's a cached ID we can/should use here! */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { void *ssl_sessionid = NULL; Curl_ssl_sessionid_lock(conn); @@ -2170,7 +2244,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) if(!SSL_set_session(connssl->handle, ssl_sessionid)) { Curl_ssl_sessionid_unlock(conn); failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(ERR_get_error(), NULL)); + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); return CURLE_SSL_CONNECT_ERROR; } /* Informational message */ @@ -2190,7 +2265,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) else if(!SSL_set_fd(connssl->handle, (int)sockfd)) { /* pass the raw socket into the SSL layers */ failf(data, "SSL: SSL_set_fd failed: %s", - ERR_error_string(ERR_get_error(), NULL)); + ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer))); return CURLE_SSL_CONNECT_ERROR; } @@ -2224,15 +2299,14 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) connssl->connecting_state = ssl_connect_2_reading; return CURLE_OK; } - else if(SSL_ERROR_WANT_WRITE == detail) { + if(SSL_ERROR_WANT_WRITE == detail) { connssl->connecting_state = ssl_connect_2_writing; return CURLE_OK; } else { /* untreated error */ unsigned long errdetail; - char error_buffer[256]=""; /* OpenSSL documents that this must be at - least 256 bytes long. */ + char error_buffer[256]=""; CURLcode result; long lerr; int lib; @@ -2280,8 +2354,8 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; - failf(data, "Unknown SSL protocol error in connection to %s:%ld ", - hostname, port); + failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ", + SSL_ERROR_to_str(detail), hostname, port); return result; } @@ -2554,44 +2628,25 @@ static CURLcode get_cert_chain(struct connectdata *conn, { const BIGNUM *n; const BIGNUM *e; - const BIGNUM *d; - const BIGNUM *p; - const BIGNUM *q; - const BIGNUM *dmp1; - const BIGNUM *dmq1; - const BIGNUM *iqmp; - RSA_get0_key(rsa, &n, &e, &d); - RSA_get0_factors(rsa, &p, &q); - RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + RSA_get0_key(rsa, &n, &e, NULL); BN_print(mem, n); push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); - print_pubkey_BN(rsa, d, i); - print_pubkey_BN(rsa, p, i); - print_pubkey_BN(rsa, q, i); - print_pubkey_BN(rsa, dmp1, i); - print_pubkey_BN(rsa, dmq1, i); - print_pubkey_BN(rsa, iqmp, i); } #else BIO_printf(mem, "%d", BN_num_bits(rsa->n)); push_certinfo("RSA Public Key", i); print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); - print_pubkey_BN(rsa, d, i); - print_pubkey_BN(rsa, p, i); - print_pubkey_BN(rsa, q, i); - print_pubkey_BN(rsa, dmp1, i); - print_pubkey_BN(rsa, dmq1, i); - print_pubkey_BN(rsa, iqmp, i); #endif break; } case EVP_PKEY_DSA: { +#ifndef OPENSSL_NO_DSA DSA *dsa; #ifdef HAVE_OPAQUE_EVP_PKEY dsa = EVP_PKEY_get0_DSA(pubkey); @@ -2603,25 +2658,23 @@ static CURLcode get_cert_chain(struct connectdata *conn, const BIGNUM *p; const BIGNUM *q; const BIGNUM *g; - const BIGNUM *priv_key; const BIGNUM *pub_key; DSA_get0_pqg(dsa, &p, &q, &g); - DSA_get0_key(dsa, &pub_key, &priv_key); + DSA_get0_key(dsa, &pub_key, NULL); print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, priv_key, i); print_pubkey_BN(dsa, pub_key, i); } #else print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, priv_key, i); print_pubkey_BN(dsa, pub_key, i); #endif +#endif /* !OPENSSL_NO_DSA */ break; } case EVP_PKEY_DH: @@ -2637,20 +2690,17 @@ static CURLcode get_cert_chain(struct connectdata *conn, const BIGNUM *p; const BIGNUM *q; const BIGNUM *g; - const BIGNUM *priv_key; const BIGNUM *pub_key; DH_get0_pqg(dh, &p, &q, &g); - DH_get0_key(dh, &pub_key, &priv_key); + DH_get0_key(dh, &pub_key, NULL); print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, q, i); print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, priv_key, i); print_pubkey_BN(dh, pub_key, i); } #else print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, g, i); - print_pubkey_BN(dh, priv_key, i); print_pubkey_BN(dh, pub_key, i); #endif break; @@ -2915,7 +2965,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { bool incache; SSL_SESSION *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -3037,16 +3087,14 @@ static CURLcode ossl_connect_common(struct connectdata *conn, failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); return CURLE_SSL_CONNECT_ERROR; } - else if(0 == what) { + if(0 == what) { if(nonblocking) { *done = FALSE; return CURLE_OK; } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } + /* timeout */ + failf(data, "SSL connection timeout"); + return CURLE_OPERATION_TIMEDOUT; } /* socket is readable or writable */ } @@ -3116,8 +3164,7 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) (conn->proxy_ssl[connindex].handle && 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ? TRUE : FALSE; - else - return FALSE; + return FALSE; } static ssize_t ossl_send(struct connectdata *conn, @@ -3129,8 +3176,7 @@ static ssize_t ossl_send(struct connectdata *conn, /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ int err; - char error_buffer[256]; /* OpenSSL documents that this must be at least 256 - bytes long. */ + char error_buffer[256]; unsigned long sslerror; int memlen; int rc; @@ -3176,7 +3222,8 @@ static ssize_t ossl_send(struct connectdata *conn, return -1; } /* a true error */ - failf(conn->data, "SSL_write() return error %d", err); + failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d", + SSL_ERROR_to_str(err), SOCKERRNO); *curlcode = CURLE_SEND_ERROR; return -1; } @@ -3190,8 +3237,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { - char error_buffer[256]; /* OpenSSL documents that this must be at - least 256 bytes long. */ + char error_buffer[256]; unsigned long sslerror; ssize_t nread; int buffsize; @@ -3221,8 +3267,10 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ if((nread < 0) || sslerror) { /* If the return code was negative or there actually is an error in the queue */ - failf(conn->data, "SSL read: %s, errno %d", - ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)), + failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d", + (sslerror ? + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)) : + SSL_ERROR_to_str(err)), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; @@ -3272,19 +3320,21 @@ size_t Curl_ossl_version(char *buffer, size_t size) } /* can be called with data == NULL */ -int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, - size_t length) +CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, + size_t length) { + int rc; if(data) { if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */ - return 1; /* couldn't seed for some reason */ + return CURLE_FAILED_INIT; /* couldn't seed for some reason */ } else { if(!rand_enough()) - return 1; + return CURLE_FAILED_INIT; } - RAND_bytes(entropy, curlx_uztosi(length)); - return 0; /* 0 as in no problem */ + /* RAND_bytes() returns 1 on success, 0 otherwise. */ + rc = RAND_bytes(entropy, curlx_uztosi(length)); + return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); } void Curl_ossl_md5sum(unsigned char *tmp, /* input */ diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h index cff1e90..b9648d5 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.h +++ b/Utilities/cmcurl/lib/vtls/openssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -66,8 +66,8 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex); /* return 0 if a find random is filled in */ -int Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, - size_t length); +CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, + size_t length); void Curl_ossl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum /* output */, diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c index 4bba3e3..669091c 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl.c +++ b/Utilities/cmcurl/lib/vtls/polarssl.c @@ -140,6 +140,68 @@ static void polarssl_debug(void *context, int level, const char *line) static Curl_recv polarssl_recv; static Curl_send polarssl_send; +static CURLcode polarssl_version_from_curl(int *polarver, long ssl_version) +{ + switch(ssl_version) { + case CURL_SSLVERSION_TLSv1_0: + *polarver = SSL_MINOR_VERSION_1; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_1: + *polarver = SSL_MINOR_VERSION_2; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_2: + *polarver = SSL_MINOR_VERSION_3; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } + return CURLE_SSL_CONNECT_ERROR; +} + +static CURLcode +set_ssl_version_min_max(struct connectdata *conn, int sockindex) +{ + struct Curl_easy *data = conn->data; + struct ssl_connect_data* connssl = &conn->ssl[sockindex]; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + int ssl_min_ver = SSL_MINOR_VERSION_1; + int ssl_max_ver = SSL_MINOR_VERSION_1; + CURLcode result = CURLE_OK; + + switch(ssl_version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + ssl_version = CURL_SSLVERSION_TLSv1_0; + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version << 16; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + + result = polarssl_version_from_curl(&ssl_min_ver, ssl_version); + if(result) { + failf(data, "unsupported min version passed via CURLOPT_SSLVERSION"); + return result; + } + result = polarssl_version_from_curl(&ssl_max_ver, ssl_version_max >> 16); + if(result) { + failf(data, "unsupported max version passed via CURLOPT_SSLVERSION"); + return result; + } + + ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver); + ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver); + + return result; +} static CURLcode polarssl_connect_step1(struct connectdata *conn, @@ -287,29 +349,15 @@ polarssl_connect_step1(struct connectdata *conn, infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n"); break; case CURL_SSLVERSION_TLSv1_0: - ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_1); - ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_1); - infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.0\n"); - break; case CURL_SSLVERSION_TLSv1_1: - ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_2); - ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_2); - infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.1\n"); - break; case CURL_SSLVERSION_TLSv1_2: - ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_3); - ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, - SSL_MINOR_VERSION_3); - infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n"); - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "PolarSSL: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + CURLcode result = set_ssl_version_min_max(conn, sockindex); + if(result != CURLE_OK) + return result; + break; + } default: failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; @@ -327,7 +375,7 @@ polarssl_connect_step1(struct connectdata *conn, ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); /* Check if there's a cached ID we can/should use here! */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { void *old_session = NULL; Curl_ssl_sessionid_lock(conn); @@ -555,7 +603,7 @@ polarssl_connect_step3(struct connectdata *conn, DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { int ret; ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; @@ -564,7 +612,7 @@ polarssl_connect_step3(struct connectdata *conn, if(!our_ssl_sessionid) return CURLE_OUT_OF_MEMORY; - ssl_session_init(our_ssl_sessionid); + memset(our_ssl_sessionid, 0, sizeof(ssl_session)); ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid); if(ret) { @@ -816,4 +864,10 @@ void Curl_polarssl_cleanup(void) (void)Curl_polarsslthreadlock_thread_cleanup(); } + +int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex) +{ + return ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0; +} + #endif /* USE_POLARSSL */ diff --git a/Utilities/cmcurl/lib/vtls/polarssl.h b/Utilities/cmcurl/lib/vtls/polarssl.h index 7098b24..47af7b4 100644 --- a/Utilities/cmcurl/lib/vtls/polarssl.h +++ b/Utilities/cmcurl/lib/vtls/polarssl.h @@ -31,6 +31,7 @@ /* Called on first use PolarSSL, setup threading if supported */ int Curl_polarssl_init(void); void Curl_polarssl_cleanup(void); +int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex); CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex); @@ -69,7 +70,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); #define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_polarssl_version #define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_data_pending(x,y) Curl_polarssl_data_pending(x, y) #define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0) /* This might cause libcurl to use a weeker random! diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index ac8b705..c9b5132 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -7,7 +7,7 @@ * * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de> * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com> - * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -103,6 +103,41 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, } static CURLcode +set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn) +{ + struct Curl_easy *data = conn->data; + long ssl_version = SSL_CONN_CONFIG(version); + long ssl_version_max = SSL_CONN_CONFIG(version_max); + long i = ssl_version; + + switch(ssl_version_max) { + case CURL_SSLVERSION_MAX_NONE: + ssl_version_max = ssl_version << 16; + break; + case CURL_SSLVERSION_MAX_DEFAULT: + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; + } + for(; i <= (ssl_version_max >> 16); ++i) { + switch(i) { + case CURL_SSLVERSION_TLSv1_0: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_1: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_2: + schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "Schannel: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + } + } + return CURLE_OK; +} + +static CURLcode schannel_connect_step1(struct connectdata *conn, int sockindex) { ssize_t written = -1; @@ -124,12 +159,20 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) #endif TCHAR *host_name; CURLcode result; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", hostname, conn->remote_port); + if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT, + VERSION_LESS_THAN_EQUAL)) { + /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and + algorithms that may not be supported by all servers. */ + infof(data, "schannel: WinSSL version is old and may not be able to " + "connect to some servers due to lack of SNI, algorithms, etc.\n"); + } + #ifdef HAS_ALPN /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. Also it doesn't seem to be supported for Wine, see curl bug #983. */ @@ -145,7 +188,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) connssl->cred = NULL; /* check for an existing re-usable credential handle */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { Curl_ssl_sessionid_lock(conn); if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { connssl->cred = old_cred; @@ -197,7 +240,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; infof(data, "schannel: verifyhost setting prevents Schannel from " "comparing the supplied target name with the subject " - "names in server certificates. Also disables SNI.\n"); + "names in server certificates.\n"); } switch(conn->ssl_config.version) { @@ -208,17 +251,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) SP_PROT_TLS1_2_CLIENT; break; case CURL_SSLVERSION_TLSv1_0: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT; - break; case CURL_SSLVERSION_TLSv1_1: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_1_CLIENT; - break; case CURL_SSLVERSION_TLSv1_2: - schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; - break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "Schannel: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + { + result = set_ssl_version_min_max(&schannel_cred, conn); + if(result != CURLE_OK) + return result; + break; + } case CURL_SSLVERSION_SSLv3: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; break; @@ -415,7 +456,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) TCHAR *host_name; CURLcode result; bool doread; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; @@ -649,8 +690,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SECURITY_STATUS sspi_status = SEC_E_OK; CERT_CONTEXT *ccert_context = NULL; +#ifndef CURL_DISABLE_VERBOSE_STRINGS const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; +#endif #ifdef HAS_ALPN SecPkgContext_ApplicationProtocol alpn_result; #endif @@ -714,7 +757,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) #endif /* save the current session data for possible re-use */ - if(data->set.general_ssl.sessionid) { + if(SSL_SET_OPTION(primary.sessionid)) { bool incache; struct curl_schannel_cred *old_cred = NULL; @@ -1391,7 +1434,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) */ struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name; infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", @@ -1516,21 +1559,21 @@ size_t Curl_schannel_version(char *buffer, size_t size) return size; } -int Curl_schannel_random(unsigned char *entropy, size_t length) +CURLcode Curl_schannel_random(unsigned char *entropy, size_t length) { HCRYPTPROV hCryptProv = 0; if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return 1; + return CURLE_FAILED_INIT; if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { CryptReleaseContext(hCryptProv, 0UL); - return 1; + return CURLE_FAILED_INIT; } CryptReleaseContext(hCryptProv, 0UL); - return 0; + return CURLE_OK; } #ifdef _WIN32_WCE diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h index 8a4991e..8627c63 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.h +++ b/Utilities/cmcurl/lib/vtls/schannel.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al. - * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -92,7 +92,7 @@ int Curl_schannel_init(void); void Curl_schannel_cleanup(void); size_t Curl_schannel_version(char *buffer, size_t size); -int Curl_schannel_random(unsigned char *entropy, size_t length); +CURLcode Curl_schannel_random(unsigned char *entropy, size_t length); /* Set the API backend definition to Schannel */ #define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index b808e1c..d5d0971 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -95,6 +95,7 @@ Curl_ssl_config_matches(struct ssl_primary_config* data, struct ssl_primary_config* needle) { if((data->version == needle->version) && + (data->version_max == needle->version_max) && (data->verifypeer == needle->verifypeer) && (data->verifyhost == needle->verifyhost) && Curl_safe_strcasecompare(data->CApath, needle->CApath) && @@ -113,6 +114,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, dest->verifyhost = source->verifyhost; dest->verifypeer = source->verifypeer; dest->version = source->version; + dest->version_max = source->version_max; CLONE_STRING(CAfile); CLONE_STRING(CApath); @@ -120,6 +122,9 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, CLONE_STRING(egdsocket); CLONE_STRING(random_file); CLONE_STRING(clientcert); + + /* Disable dest sessionid cache if a client cert is used, CVE-2016-5419. */ + dest->sessionid = (dest->clientcert ? false : source->sessionid); return TRUE; } @@ -173,11 +178,24 @@ void Curl_ssl_cleanup(void) static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ - if((data->set.ssl.primary.version < 0) - || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) { + const long sslver = data->set.ssl.primary.version; + if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) { failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); return FALSE; } + + switch(data->set.ssl.primary.version_max) { + case CURL_SSLVERSION_MAX_NONE: + case CURL_SSLVERSION_MAX_DEFAULT: + break; + + default: + if((data->set.ssl.primary.version_max >> 16) < sslver) { + failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION"); + return FALSE; + } + } + return TRUE; } @@ -286,16 +304,16 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? - &conn->proxy_ssl_config : - &conn->ssl_config; + &conn->proxy_ssl_config : + &conn->ssl_config; const char * const name = isProxy ? conn->http_proxy.host.name : - conn->host.name; + conn->host.name; int port = isProxy ? (int)conn->port : conn->remote_port; *ssl_sessionid = NULL; - DEBUGASSERT(data->set.general_ssl.sessionid); + DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); - if(!data->set.general_ssl.sessionid) + if(!SSL_SET_OPTION(primary.sessionid)) /* session ID re-use is disabled */ return TRUE; @@ -394,10 +412,10 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, long *general_age; const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? - &conn->proxy_ssl_config : - &conn->ssl_config; + &conn->proxy_ssl_config : + &conn->ssl_config; - DEBUGASSERT(data->set.general_ssl.sessionid); + DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); if(!clone_host) @@ -447,7 +465,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ - /* free it if there's one already present */ + /* free it if there's one already present */ free(store->name); free(store->conn_to_host); store->name = clone_host; /* clone host name */ @@ -484,9 +502,9 @@ void Curl_ssl_close_all(struct Curl_easy *data) curlssl_close_all(data); } -#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_DARWINSSL) || defined(USE_NSS) -/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. */ +#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ + defined(USE_MBEDTLS) int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { @@ -500,7 +518,7 @@ int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_WRITESOCK(0); } - else if(connssl->connecting_state == ssl_connect_2_reading) { + if(connssl->connecting_state == ssl_connect_2_reading) { /* read mode */ socks[0] = conn->sock[FIRSTSOCKET]; return GETSOCK_READSOCK(0); @@ -510,15 +528,15 @@ int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, } #else int Curl_ssl_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) + curl_socket_t *socks, + int numsocks) { (void)conn; (void)socks; (void)numsocks; return GETSOCK_BLANK; } -/* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */ +/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */ #endif void Curl_ssl_close(struct connectdata *conn, int sockindex) @@ -703,12 +721,7 @@ CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { - int rc = curlssl_random(data, entropy, length); - if(rc) { - failf(data, "PRNG seeding failed"); - return CURLE_FAILED_INIT; /* possibly weird return code */ - } - return CURLE_OK; + return curlssl_random(data, entropy, length); } /* diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c index 0c4472e..fb085c8 100644 --- a/Utilities/cmcurl/lib/warnless.c +++ b/Utilities/cmcurl/lib/warnless.c @@ -183,12 +183,15 @@ curl_off_t curlx_uztoso(size_t uznum) #ifdef __INTEL_COMPILER # pragma warning(push) # pragma warning(disable:810) /* conversion may lose significant bits */ +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable:4310) /* cast truncates constant value */ #endif DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT); return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT); -#ifdef __INTEL_COMPILER +#if defined(__INTEL_COMPILER) || defined(_MSC_VER) # pragma warning(pop) #endif } diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c index dbbe45f..af45c79 100644 --- a/Utilities/cmcurl/lib/wildcard.c +++ b/Utilities/cmcurl/lib/wildcard.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,13 +32,9 @@ CURLcode Curl_wildcard_init(struct WildcardData *wc) { - DEBUGASSERT(wc->filelist == NULL); - /* now allocate only wc->filelist, everything else - will be allocated if it is needed. */ - wc->filelist = Curl_llist_alloc(Curl_fileinfo_dtor); - if(!wc->filelist) {; - return CURLE_OUT_OF_MEMORY; - } + Curl_llist_init(&wc->filelist, Curl_fileinfo_dtor); + wc->state = CURLWC_INIT; + return CURLE_OK; } @@ -54,10 +50,8 @@ void Curl_wildcard_dtor(struct WildcardData *wc) } DEBUGASSERT(wc->tmp == NULL); - if(wc->filelist) { - Curl_llist_destroy(wc->filelist, NULL); - wc->filelist = NULL; - } + Curl_llist_destroy(&wc->filelist, NULL); + free(wc->path); wc->path = NULL; diff --git a/Utilities/cmcurl/lib/wildcard.h b/Utilities/cmcurl/lib/wildcard.h index 7f61cd1..8a5e4b7 100644 --- a/Utilities/cmcurl/lib/wildcard.h +++ b/Utilities/cmcurl/lib/wildcard.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,9 +24,12 @@ #include <curl/curl.h> +#include "llist.h" + /* list of wildcard process states */ typedef enum { - CURLWC_INIT = 0, + CURLWC_CLEAR = 0, + CURLWC_INIT = 1, CURLWC_MATCHING, /* library is trying to get list of addresses for downloading */ CURLWC_DOWNLOADING, @@ -44,7 +47,7 @@ struct WildcardData { curl_wildcard_states state; char *path; /* path to the directory, where we trying wildcard-match */ char *pattern; /* wildcard pattern */ - struct curl_llist *filelist; /* llist with struct Curl_fileinfo */ + struct curl_llist filelist; /* llist with struct Curl_fileinfo */ void *tmp; /* pointer to protocol specific temporary data */ curl_wildcard_tmp_dtor tmp_dtor; void *customptr; /* for CURLOPT_CHUNK_DATA pointer */ |