diff --git a/DEPENDENCIES b/DEPENDENCIES index 3bd6763d..52809cd1 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -2,4 +2,4 @@ vendorpull https://github.com/sourcemeta/vendorpull dea311b5bfb53b6926a414026795 core https://github.com/sourcemeta/core 7a18592f4b77e9932571436fbee69b34551a566a jsonbinpack https://github.com/sourcemeta/jsonbinpack 61a04d9d304343d8c206972225393f7ae0d5b603 blaze https://github.com/sourcemeta/blaze c0beb606def90d0cfadff1187bfa50443493eb9d -curl https://github.com/curl/curl curl-8_14_0 +curl https://github.com/curl/curl curl-8_15_0 diff --git a/vendor/curl/include/curl/curl.h b/vendor/curl/include/curl/curl.h index 128d1d3d..7ef5b993 100644 --- a/vendor/curl/include/curl/curl.h +++ b/vendor/curl/include/curl/curl.h @@ -158,11 +158,11 @@ typedef enum { CURLSSLBACKEND_POLARSSL CURL_DEPRECATED(7.69.0, "") = 6, CURLSSLBACKEND_WOLFSSL = 7, CURLSSLBACKEND_SCHANNEL = 8, - CURLSSLBACKEND_SECURETRANSPORT = 9, + CURLSSLBACKEND_SECURETRANSPORT CURL_DEPRECATED(8.15.0, "") = 9, CURLSSLBACKEND_AXTLS CURL_DEPRECATED(7.61.0, "") = 10, CURLSSLBACKEND_MBEDTLS = 11, CURLSSLBACKEND_MESALINK CURL_DEPRECATED(7.82.0, "") = 12, - CURLSSLBACKEND_BEARSSL = 13, + CURLSSLBACKEND_BEARSSL CURL_DEPRECATED(8.15.0, "") = 13, CURLSSLBACKEND_RUSTLS = 14 } curl_sslbackend; @@ -645,20 +645,7 @@ typedef enum { CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */ CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */ CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */ - CURL_LAST, /* never use! */ - - CURLE_RESERVED115 = 115, /* 115-126 - used in tests */ - CURLE_RESERVED116 = 116, - CURLE_RESERVED117 = 117, - CURLE_RESERVED118 = 118, - CURLE_RESERVED119 = 119, - CURLE_RESERVED120 = 120, - CURLE_RESERVED121 = 121, - CURLE_RESERVED122 = 122, - CURLE_RESERVED123 = 123, - CURLE_RESERVED124 = 124, - CURLE_RESERVED125 = 125, - CURLE_RESERVED126 = 126 + CURL_LAST /* never use! */ } CURLcode; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all @@ -943,31 +930,31 @@ typedef enum { have introduced work-arounds for this flaw but those work-arounds sometimes make the SSL communication fail. To regain functionality with those broken servers, a user can this way allow the vulnerability back. */ -#define CURLSSLOPT_ALLOW_BEAST (1<<0) +#define CURLSSLOPT_ALLOW_BEAST (1L<<0) /* - NO_REVOKE tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. */ -#define CURLSSLOPT_NO_REVOKE (1<<1) +#define CURLSSLOPT_NO_REVOKE (1L<<1) /* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain if possible. The OpenSSL backend has this ability. */ -#define CURLSSLOPT_NO_PARTIALCHAIN (1<<2) +#define CURLSSLOPT_NO_PARTIALCHAIN (1L<<2) /* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline checks and ignore missing revocation list for those SSL backends where such behavior is present. */ -#define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3) +#define CURLSSLOPT_REVOKE_BEST_EFFORT (1L<<3) /* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of operating system. Currently implemented under MS-Windows. */ -#define CURLSSLOPT_NATIVE_CA (1<<4) +#define CURLSSLOPT_NATIVE_CA (1L<<4) /* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use a client certificate for authentication. (Schannel) */ -#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5) +#define CURLSSLOPT_AUTO_CLIENT_CERT (1L<<5) /* If possible, send data using TLS 1.3 early data */ -#define CURLSSLOPT_EARLYDATA (1<<6) +#define CURLSSLOPT_EARLYDATA (1L<<6) /* The default connection attempt delay in milliseconds for happy eyeballs. CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document @@ -1967,7 +1954,8 @@ typedef enum { CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232), /* Set if we should enable TLS false start. */ - CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233), + CURLOPTDEPRECATED(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233, + 8.15.0, "Has no function"), /* Do not squash dot-dot sequences */ CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234), @@ -2301,10 +2289,10 @@ typedef enum { /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host name resolves addresses using more than one IP protocol version, this option might be handy to force libcurl to use a specific IP version. */ -#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP +#define CURL_IPRESOLVE_WHATEVER 0L /* default, uses addresses to all IP versions that your system allows */ -#define CURL_IPRESOLVE_V4 1 /* uses only IPv4 addresses/connections */ -#define CURL_IPRESOLVE_V6 2 /* uses only IPv6 addresses/connections */ +#define CURL_IPRESOLVE_V4 1L /* uses only IPv4 addresses/connections */ +#define CURL_IPRESOLVE_V6 2L /* uses only IPv6 addresses/connections */ /* Convenient "aliases" */ #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER @@ -2813,17 +2801,17 @@ struct curl_slist { * *before* curl_global_init(). * * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The - * backend can also be specified via the name parameter (passing -1 as id). - * If both id and name are specified, the name will be ignored. If neither id - * nor name are specified, the function will fail with - * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the - * NULL-terminated list of available backends. + * backend can also be specified via the name parameter (passing -1 as id). If + * both id and name are specified, the name will be ignored. If neither id nor + * name are specified, the function will fail with CURLSSLSET_UNKNOWN_BACKEND + * and set the "avail" pointer to the NULL-terminated list of available + * backends. * * Upon success, the function returns CURLSSLSET_OK. * * If the specified SSL backend is not available, the function returns - * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated - * list of available SSL backends. + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a + * NULL-terminated list of available SSL backends. * * The SSL backend can be set only once. If it has already been set, a * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. diff --git a/vendor/curl/include/curl/curlver.h b/vendor/curl/include/curl/curlver.h index 5515d32e..b3fc29b9 100644 --- a/vendor/curl/include/curl/curlver.h +++ b/vendor/curl/include/curl/curlver.h @@ -32,12 +32,12 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.14.0-DEV" +#define LIBCURL_VERSION "8.15.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 14 +#define LIBCURL_VERSION_MINOR 15 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier @@ -59,7 +59,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x080e00 +#define LIBCURL_VERSION_NUM 0x080f00 /* * This is the date and time when the full source package was created. The diff --git a/vendor/curl/include/curl/system.h b/vendor/curl/include/curl/system.h index f1c2719c..ebcdc5e4 100644 --- a/vendor/curl/include/curl/system.h +++ b/vendor/curl/include/curl/system.h @@ -329,7 +329,7 @@ defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ defined(__XTENSA__) || \ - (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" @@ -357,11 +357,11 @@ #else /* generic "safe guess" on old 32-bit style */ -# define CURL_TYPEOF_CURL_OFF_T long -# define CURL_FORMAT_CURL_OFF_T "ld" -# define CURL_FORMAT_CURL_OFF_TU "lu" -# define CURL_SUFFIX_CURL_OFF_T L -# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T int #endif @@ -399,52 +399,4 @@ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; #endif -/* - * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow - * these to be visible and exported by the external libcurl interface API, - * while also making them visible to the library internals, simply including - * curl_setup.h, without actually needing to include curl.h internally. - * If some day this section would grow big enough, all this should be moved - * to its own header file. - */ - -/* - * Figure out if we can use the ## preprocessor operator, which is supported - * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ - * or __cplusplus so we need to carefully check for them too. - */ - -#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ - defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ - defined(__POCC__) || defined(__HIGHC__) || \ - defined(__ILEC400__) - /* This compiler is believed to have an ISO compatible preprocessor */ -#define CURL_ISOCPP -#else - /* This compiler is believed NOT to have an ISO compatible preprocessor */ -#undef CURL_ISOCPP -#endif - -/* - * Macros for minimum-width signed and unsigned curl_off_t integer constants. - */ - -#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) -# define CURLINC_OFF_T_C_HLPR2(x) x -# define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x) -# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ - CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) -# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ - CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) -#else -# ifdef CURL_ISOCPP -# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix -# else -# define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix -# endif -# define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix) -# define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) -# define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) -#endif - #endif /* CURLINC_SYSTEM_H */ diff --git a/vendor/curl/include/curl/typecheck-gcc.h b/vendor/curl/include/curl/typecheck-gcc.h index 64152696..ca0c0ef9 100644 --- a/vendor/curl/include/curl/typecheck-gcc.h +++ b/vendor/curl/include/curl/typecheck-gcc.h @@ -178,7 +178,7 @@ _curl_easy_getinfo_err_curl_slist(); \ if(curlcheck_tlssessioninfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ - _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ + _curl_easy_getinfo_err_curl_tlssessioninfo(); \ if(curlcheck_certinfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_certinfo *)) \ _curl_easy_getinfo_err_curl_certinfo(); \ @@ -295,7 +295,7 @@ CURLWARNING(_curl_easy_getinfo_err_double, "curl_easy_getinfo expects a pointer to double") CURLWARNING(_curl_easy_getinfo_err_curl_slist, "curl_easy_getinfo expects a pointer to 'struct curl_slist *'") -CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, +CURLWARNING(_curl_easy_getinfo_err_curl_tlssessioninfo, "curl_easy_getinfo expects a pointer to " "'struct curl_tlssessioninfo *'") CURLWARNING(_curl_easy_getinfo_err_curl_certinfo, diff --git a/vendor/curl/lib/altsvc.c b/vendor/curl/lib/altsvc.c index 8a29ca46..59476d73 100644 --- a/vendor/curl/lib/altsvc.c +++ b/vendor/curl/lib/altsvc.c @@ -32,7 +32,6 @@ #include "urldata.h" #include "altsvc.h" #include "curl_get_line.h" -#include "strcase.h" #include "parsedate.h" #include "sendf.h" #include "curlx/warnless.h" @@ -190,7 +189,7 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) char dbuf[MAX_ALTSVC_DATELEN + 1]; time_t expires; - /* The date parser works on a null terminated string. The maximum length + /* The date parser works on a null-terminated string. The maximum length is upheld by curlx_str_quotedword(). */ memcpy(dbuf, curlx_str(&date), curlx_strlen(&date)); dbuf[curlx_strlen(&date)] = 0; @@ -416,7 +415,7 @@ static bool hostcompare(const char *host, const char *check) if(hlen != clen) /* they cannot match if they have different lengths */ return FALSE; - return strncasecompare(host, check, hlen); + return curl_strnequal(host, check, hlen); } /* altsvc_flush() removes all alternatives for this source origin from the @@ -487,8 +486,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, DEBUGASSERT(asi); /* initial check for "clear" */ - if(!curlx_str_until(&p, &alpn, MAX_ALTSVC_LINE, ';') && - !curlx_str_single(&p, ';')) { + if(!curlx_str_cspn(&p, &alpn, ";\n\r")) { curlx_str_trimblanks(&alpn); /* "clear" is a magic keyword */ if(curlx_str_casecompare(&alpn, "clear")) { @@ -666,4 +664,8 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi, return FALSE; } +#if defined(DEBUGBUILD) || defined(UNITTESTS) +#undef time +#endif + #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_ALTSVC */ diff --git a/vendor/curl/lib/asyn-ares.c b/vendor/curl/lib/asyn-ares.c index 10f870a1..007f1d71 100644 --- a/vendor/curl/lib/asyn-ares.c +++ b/vendor/curl/lib/asyn-ares.c @@ -48,6 +48,7 @@ #endif #include "urldata.h" +#include "cfilters.h" #include "sendf.h" #include "hostip.h" #include "hash.h" @@ -451,8 +452,7 @@ CURLcode Curl_async_await(struct Curl_easy *data, /* Operation complete, if the lookup was successful we now have the entry in the cache. */ data->state.async.done = TRUE; - if(entry) - *entry = data->state.async.dns; + *entry = data->state.async.dns; if(result) ares_cancel(ares->channel); @@ -758,7 +758,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, (pf == PF_UNSPEC) ? "A+AAAA" : ((pf == PF_INET) ? "A" : "AAAA")); hints.ai_family = pf; - hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ? + hints.ai_socktype = + (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; /* Since the service is a numerical one, set the hint flags * accordingly to save a call to getservbyname in inside C-Ares diff --git a/vendor/curl/lib/asyn-thrdd.c b/vendor/curl/lib/asyn-thrdd.c index b71bd133..1ede8688 100644 --- a/vendor/curl/lib/asyn-thrdd.c +++ b/vendor/curl/lib/asyn-thrdd.c @@ -55,13 +55,13 @@ #endif #include "urldata.h" +#include "cfilters.h" #include "sendf.h" #include "hostip.h" #include "hash.h" #include "share.h" #include "url.h" #include "multiif.h" -#include "inet_ntop.h" #include "curl_threads.h" #include "strdup.h" @@ -423,6 +423,7 @@ static bool async_thrdd_init(struct Curl_easy *data, data->state.async.done = FALSE; data->state.async.port = port; data->state.async.ip_version = ip_version; + free(data->state.async.hostname); data->state.async.hostname = strdup(hostname); if(!data->state.async.hostname) goto err_exit; @@ -595,16 +596,15 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, if(!result) { struct Curl_https_rrinfo *lhrr; lhrr = Curl_httpsrr_dup_move(&thrdd->rr.hinfo); - if(!lhrr) { - async_thrdd_destroy(data); - return CURLE_OUT_OF_MEMORY; - } - data->state.async.dns->hinfo = lhrr; + if(!lhrr) + result = CURLE_OUT_OF_MEMORY; + else + data->state.async.dns->hinfo = lhrr; } } #endif - if(!result && data->state.async.dns) - result = Curl_dnscache_add(data, data->state.async.dns); + if(!result && data->state.async.dns) + result = Curl_dnscache_add(data, data->state.async.dns); } if(!result && !data->state.async.dns) @@ -742,7 +742,8 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; - hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ? + hints.ai_socktype = + (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; /* fire up a new resolver thread! */ diff --git a/vendor/curl/lib/bufq.c b/vendor/curl/lib/bufq.c index 724d62f3..8783619e 100644 --- a/vendor/curl/lib/bufq.c +++ b/vendor/curl/lib/bufq.c @@ -86,44 +86,26 @@ static size_t chunk_read(struct buf_chunk *chunk, } } -static size_t chunk_unwrite(struct buf_chunk *chunk, size_t len) -{ - size_t n = chunk->w_offset - chunk->r_offset; - DEBUGASSERT(chunk->w_offset >= chunk->r_offset); - if(!n) { - return 0; - } - else if(n <= len) { - chunk->r_offset = chunk->w_offset = 0; - return n; - } - else { - chunk->w_offset -= len; - return len; - } -} - -static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len, - Curl_bufq_reader *reader, - void *reader_ctx, CURLcode *err) +static CURLcode chunk_slurpn(struct buf_chunk *chunk, size_t max_len, + Curl_bufq_reader *reader, + void *reader_ctx, size_t *pnread) { unsigned char *p = &chunk->x.data[chunk->w_offset]; size_t n = chunk->dlen - chunk->w_offset; /* free amount */ - ssize_t nread; + CURLcode result; + *pnread = 0; DEBUGASSERT(chunk->dlen >= chunk->w_offset); - if(!n) { - *err = CURLE_AGAIN; - return -1; - } + if(!n) + return CURLE_AGAIN; if(max_len && n > max_len) n = max_len; - nread = reader(reader_ctx, p, n, err); - if(nread > 0) { - DEBUGASSERT((size_t)nread <= n); - chunk->w_offset += nread; + result = reader(reader_ctx, p, n, pnread); + if(!result) { + DEBUGASSERT(*pnread <= n); + chunk->w_offset += *pnread; } - return nread; + return result; } static void chunk_peek(const struct buf_chunk *chunk, @@ -357,49 +339,6 @@ static void prune_head(struct bufq *q) } } -static struct buf_chunk *chunk_prev(struct buf_chunk *head, - struct buf_chunk *chunk) -{ - while(head) { - if(head == chunk) - return NULL; - if(head->next == chunk) - return head; - head = head->next; - } - return NULL; -} - -static void prune_tail(struct bufq *q) -{ - struct buf_chunk *chunk; - - while(q->tail && chunk_is_empty(q->tail)) { - chunk = q->tail; - q->tail = chunk_prev(q->head, chunk); - if(q->tail) - q->tail->next = NULL; - if(q->head == chunk) - q->head = q->tail; - if(q->pool) { - bufcp_put(q->pool, chunk); - --q->chunk_count; - } - else if((q->chunk_count > q->max_chunks) || - (q->opts & BUFQ_OPT_NO_SPARES)) { - /* SOFT_LIMIT allowed us more than max. free spares until - * we are at max again. Or free them if we are configured - * to not use spares. */ - free(chunk); - --q->chunk_count; - } - else { - chunk->next = q->spare; - q->spare = chunk; - } - } -} - static struct buf_chunk *get_non_full_tail(struct bufq *q) { struct buf_chunk *chunk; @@ -421,90 +360,60 @@ static struct buf_chunk *get_non_full_tail(struct bufq *q) return chunk; } -ssize_t Curl_bufq_write(struct bufq *q, - const unsigned char *buf, size_t len, - CURLcode *err) +CURLcode Curl_bufq_write(struct bufq *q, + const unsigned char *buf, size_t len, + size_t *pnwritten) { struct buf_chunk *tail; - ssize_t nwritten = 0; size_t n; DEBUGASSERT(q->max_chunks > 0); + *pnwritten = 0; while(len) { tail = get_non_full_tail(q); if(!tail) { - if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) { - *err = CURLE_OUT_OF_MEMORY; - return -1; - } + if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) + /* should have gotten a tail, but did not */ + return CURLE_OUT_OF_MEMORY; break; } n = chunk_append(tail, buf, len); if(!n) break; - nwritten += n; + *pnwritten += n; buf += n; len -= n; } - if(nwritten == 0 && len) { - *err = CURLE_AGAIN; - return -1; - } - *err = CURLE_OK; - return nwritten; + return (!*pnwritten && len) ? CURLE_AGAIN : CURLE_OK; } CURLcode Curl_bufq_cwrite(struct bufq *q, const char *buf, size_t len, size_t *pnwritten) { - ssize_t n; - CURLcode result; - n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result); - *pnwritten = (n < 0) ? 0 : (size_t)n; - return result; -} - -CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len) -{ - while(len && q->tail) { - len -= chunk_unwrite(q->tail, len); - prune_tail(q); - } - return len ? CURLE_AGAIN : CURLE_OK; + return Curl_bufq_write(q, (const unsigned char *)buf, len, pnwritten); } -ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, - CURLcode *err) +CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, + size_t *pnread) { - ssize_t nread = 0; - size_t n; - - *err = CURLE_OK; + *pnread = 0; while(len && q->head) { - n = chunk_read(q->head, buf, len); + size_t n = chunk_read(q->head, buf, len); if(n) { - nread += n; + *pnread += n; buf += n; len -= n; } prune_head(q); } - if(nread == 0) { - *err = CURLE_AGAIN; - return -1; - } - return nread; + return (!*pnread) ? CURLE_AGAIN : CURLE_OK; } CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len, size_t *pnread) { - ssize_t n; - CURLcode result; - n = Curl_bufq_read(q, (unsigned char *)buf, len, &result); - *pnread = (n < 0) ? 0 : (size_t)n; - return result; + return Curl_bufq_read(q, (unsigned char *)buf, len, pnread); } bool Curl_bufq_peek(struct bufq *q, @@ -556,156 +465,139 @@ void Curl_bufq_skip(struct bufq *q, size_t amount) } } -ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, - void *writer_ctx, CURLcode *err) +CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, + void *writer_ctx, size_t *pwritten) { const unsigned char *buf; size_t blen; - ssize_t nwritten = 0; + CURLcode result = CURLE_OK; + *pwritten = 0; while(Curl_bufq_peek(q, &buf, &blen)) { - ssize_t chunk_written; + size_t chunk_written; - chunk_written = writer(writer_ctx, buf, blen, err); - if(chunk_written < 0) { - if(!nwritten || *err != CURLE_AGAIN) { - /* blocked on first write or real error, fail */ - nwritten = -1; + result = writer(writer_ctx, buf, blen, &chunk_written); + if(result) { + if((result == CURLE_AGAIN) && *pwritten) { + /* blocked on subsequent write, report success */ + result = CURLE_OK; } break; } if(!chunk_written) { - if(!nwritten) { + if(!*pwritten) { /* treat as blocked */ - *err = CURLE_AGAIN; - nwritten = -1; + result = CURLE_AGAIN; } break; } - Curl_bufq_skip(q, (size_t)chunk_written); - nwritten += chunk_written; + *pwritten += chunk_written; + Curl_bufq_skip(q, chunk_written); } - return nwritten; + return result; } -ssize_t Curl_bufq_write_pass(struct bufq *q, - const unsigned char *buf, size_t len, - Curl_bufq_writer *writer, void *writer_ctx, - CURLcode *err) +CURLcode Curl_bufq_write_pass(struct bufq *q, + const unsigned char *buf, size_t len, + Curl_bufq_writer *writer, void *writer_ctx, + size_t *pwritten) { - ssize_t nwritten = 0, n; + CURLcode result = CURLE_OK; + size_t n; - *err = CURLE_OK; + *pwritten = 0; while(len) { if(Curl_bufq_is_full(q)) { /* try to make room in case we are full */ - n = Curl_bufq_pass(q, writer, writer_ctx, err); - if(n < 0) { - if(*err != CURLE_AGAIN) { + result = Curl_bufq_pass(q, writer, writer_ctx, &n); + if(result) { + if(result != CURLE_AGAIN) { /* real error, fail */ - return -1; + return result; } /* would block, bufq is full, give up */ break; } } - /* Add whatever is remaining now to bufq */ - n = Curl_bufq_write(q, buf, len, err); - if(n < 0) { - if(*err != CURLE_AGAIN) { + /* Add to bufq as much as there is room for */ + result = Curl_bufq_write(q, buf, len, &n); + if(result) { + if(result != CURLE_AGAIN) /* real error, fail */ - return -1; - } - /* no room in bufq */ - break; + return result; + if((result == CURLE_AGAIN) && *pwritten) + /* we did write successfully before */ + result = CURLE_OK; + return result; } - /* edge case of writer returning 0 (and len is >0) - * break or we might enter an infinite loop here */ - if(n == 0) + else if(n == 0) + /* edge case of writer returning 0 (and len is >0) + * break or we might enter an infinite loop here */ break; - /* Maybe only part of `data` has been added, continue to loop */ - buf += (size_t)n; - len -= (size_t)n; - nwritten += (size_t)n; + /* Track what we added to bufq */ + buf += n; + len -= n; + *pwritten += n; } - if(!nwritten && len) { - *err = CURLE_AGAIN; - return -1; - } - *err = CURLE_OK; - return nwritten; + return (!*pwritten && len) ? CURLE_AGAIN : CURLE_OK; } -ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len, - Curl_bufq_reader *reader, void *reader_ctx, - CURLcode *err) +CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len, + Curl_bufq_reader *reader, void *reader_ctx, + size_t *pnread) { struct buf_chunk *tail = NULL; - ssize_t nread; - *err = CURLE_AGAIN; + *pnread = 0; tail = get_non_full_tail(q); if(!tail) { - if(q->chunk_count < q->max_chunks) { - *err = CURLE_OUT_OF_MEMORY; - return -1; - } + if(q->chunk_count < q->max_chunks) + return CURLE_OUT_OF_MEMORY; /* full, blocked */ - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } - nread = chunk_slurpn(tail, max_len, reader, reader_ctx, err); - if(nread < 0) { - return -1; - } - else if(nread == 0) { - /* eof */ - *err = CURLE_OK; - } - return nread; + return chunk_slurpn(tail, max_len, reader, reader_ctx, pnread); } /** * Read up to `max_len` bytes and append it to the end of the buffer queue. * if `max_len` is 0, no limit is imposed and the call behaves exactly * the same as `Curl_bufq_slurp()`. - * Returns the total amount of buf read (may be 0) or -1 on other - * reader errors. - * Note that even in case of a -1 chunks may have been read and + * Returns the total amount of buf read (may be 0) in `pnread` or error + * Note that even in case of an error chunks may have been read and * the buffer queue will have different length than before. */ -static ssize_t bufq_slurpn(struct bufq *q, size_t max_len, - Curl_bufq_reader *reader, void *reader_ctx, - CURLcode *err) +static CURLcode bufq_slurpn(struct bufq *q, size_t max_len, + Curl_bufq_reader *reader, void *reader_ctx, + size_t *pnread) { - ssize_t nread = 0, n; + CURLcode result; - *err = CURLE_AGAIN; + *pnread = 0; while(1) { - - n = Curl_bufq_sipn(q, max_len, reader, reader_ctx, err); - if(n < 0) { - if(!nread || *err != CURLE_AGAIN) { + size_t n; + result = Curl_bufq_sipn(q, max_len, reader, reader_ctx, &n); + if(result) { + if(!*pnread || result != CURLE_AGAIN) { /* blocked on first read or real error, fail */ - nread = -1; + return result; } - else - *err = CURLE_OK; + result = CURLE_OK; break; } else if(n == 0) { /* eof */ - *err = CURLE_OK; + result = CURLE_OK; break; } - nread += (size_t)n; + *pnread += n; if(max_len) { - DEBUGASSERT((size_t)n <= max_len); - max_len -= (size_t)n; + DEBUGASSERT(n <= max_len); + max_len -= n; if(!max_len) break; } @@ -713,11 +605,11 @@ static ssize_t bufq_slurpn(struct bufq *q, size_t max_len, if(q->tail && !chunk_is_full(q->tail)) break; } - return nread; + return result; } -ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, - void *reader_ctx, CURLcode *err) +CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, + void *reader_ctx, size_t *pnread) { - return bufq_slurpn(q, 0, reader, reader_ctx, err); + return bufq_slurpn(q, 0, reader, reader_ctx, pnread); } diff --git a/vendor/curl/lib/bufq.h b/vendor/curl/lib/bufq.h index 60059deb..7cd1826a 100644 --- a/vendor/curl/lib/bufq.h +++ b/vendor/curl/lib/bufq.h @@ -163,31 +163,22 @@ bool Curl_bufq_is_full(const struct bufq *q); /** * Write buf to the end of the buffer queue. The buf is copied * and the amount of copied bytes is returned. - * A return code of -1 indicates an error, setting `err` to the - * cause. An err of CURLE_AGAIN is returned if the buffer queue is full. + * CURLE_AGAIN is returned if the buffer queue is full. */ -ssize_t Curl_bufq_write(struct bufq *q, - const unsigned char *buf, size_t len, - CURLcode *err); - -CURLcode Curl_bufq_cwrite(struct bufq *q, - const char *buf, size_t len, +CURLcode Curl_bufq_write(struct bufq *q, + const unsigned char *buf, size_t len, size_t *pnwritten); -/** - * Remove `len` bytes from the end of the buffer queue again. - * Returns CURLE_AGAIN if less than `len` bytes were in the queue. - */ -CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len); +CURLcode Curl_bufq_cwrite(struct bufq *q, + const char *buf, size_t len, + size_t *pnwritten); /** * Read buf from the start of the buffer queue. The buf is copied * and the amount of copied bytes is returned. - * A return code of -1 indicates an error, setting `err` to the - * cause. An err of CURLE_AGAIN is returned if the buffer queue is empty. */ -ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, - CURLcode *err); +CURLcode Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len, + size_t *pnread); CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len, size_t *pnread); @@ -214,9 +205,9 @@ bool Curl_bufq_peek_at(struct bufq *q, size_t offset, */ void Curl_bufq_skip(struct bufq *q, size_t amount); -typedef ssize_t Curl_bufq_writer(void *writer_ctx, - const unsigned char *buf, size_t len, - CURLcode *err); +typedef CURLcode Curl_bufq_writer(void *writer_ctx, + const unsigned char *buf, size_t len, + size_t *pwritten); /** * Passes the chunks in the buffer queue to the writer and returns * the amount of buf written. A writer may return -1 and CURLE_AGAIN @@ -226,24 +217,23 @@ typedef ssize_t Curl_bufq_writer(void *writer_ctx, * Note that in case of a -1 chunks may have been written and * the buffer queue will have different length than before. */ -ssize_t Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, - void *writer_ctx, CURLcode *err); +CURLcode Curl_bufq_pass(struct bufq *q, Curl_bufq_writer *writer, + void *writer_ctx, size_t *pwritten); -typedef ssize_t Curl_bufq_reader(void *reader_ctx, - unsigned char *buf, size_t len, - CURLcode *err); +typedef CURLcode Curl_bufq_reader(void *reader_ctx, + unsigned char *buf, size_t len, + size_t *pnread); /** * Read date and append it to the end of the buffer queue until the * reader returns blocking or the queue is full. A reader returns - * -1 and CURLE_AGAIN to indicate blocking. - * Returns the total amount of buf read (may be 0) or -1 on other - * reader errors. - * Note that in case of a -1 chunks may have been read and + * CURLE_AGAIN to indicate blocking. + * Returns the total amount of buf read (may be 0) in `pnread` on success. + * Note that in case of an error chunks may have been read and * the buffer queue will have different length than before. */ -ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, - void *reader_ctx, CURLcode *err); +CURLcode Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, + void *reader_ctx, size_t *pnread); /** * Read *once* up to `max_len` bytes and append it to the buffer. @@ -251,9 +241,9 @@ ssize_t Curl_bufq_slurp(struct bufq *q, Curl_bufq_reader *reader, * Returns the total amount of buf read (may be 0) or -1 on other * reader errors. */ -ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len, - Curl_bufq_reader *reader, void *reader_ctx, - CURLcode *err); +CURLcode Curl_bufq_sipn(struct bufq *q, size_t max_len, + Curl_bufq_reader *reader, void *reader_ctx, + size_t *pnread); /** * Write buf to the end of the buffer queue. @@ -262,9 +252,9 @@ ssize_t Curl_bufq_sipn(struct bufq *q, size_t max_len, * on or is placed into the buffer, depending on `len` and current * amount buffered, chunk size, etc. */ -ssize_t Curl_bufq_write_pass(struct bufq *q, - const unsigned char *buf, size_t len, - Curl_bufq_writer *writer, void *writer_ctx, - CURLcode *err); +CURLcode Curl_bufq_write_pass(struct bufq *q, + const unsigned char *buf, size_t len, + Curl_bufq_writer *writer, void *writer_ctx, + size_t *pwritten); #endif /* HEADER_CURL_BUFQ_H */ diff --git a/vendor/curl/lib/cf-h1-proxy.c b/vendor/curl/lib/cf-h1-proxy.c index df6f5754..4aac877f 100644 --- a/vendor/curl/lib/cf-h1-proxy.c +++ b/vendor/curl/lib/cf-h1-proxy.c @@ -252,7 +252,7 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf, size_t request_len = curlx_dyn_len(&ts->request_data); size_t blen = request_len; CURLcode result = CURLE_OK; - ssize_t nwritten; + size_t nwritten; if(blen <= ts->nsent) goto out; /* we are done */ @@ -260,16 +260,15 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf, blen -= ts->nsent; buf += ts->nsent; - nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &result); - if(nwritten < 0) { - if(result == CURLE_AGAIN) { + result = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &nwritten); + if(result) { + if(result == CURLE_AGAIN) result = CURLE_OK; - } goto out; } - DEBUGASSERT(blen >= (size_t)nwritten); - ts->nsent += (size_t)nwritten; + DEBUGASSERT(blen >= nwritten); + ts->nsent += nwritten; Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten); out: @@ -375,11 +374,8 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, error = SELECT_OK; *done = FALSE; - if(!Curl_conn_data_pending(data, cf->sockindex)) - return CURLE_OK; - while(ts->keepon) { - ssize_t nread; + size_t nread; char byte; /* Read one byte at a time to avoid a race condition. Wait at most one @@ -397,7 +393,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, break; } - if(nread <= 0) { + if(!nread) { if(data->set.proxyauth && data->state.authproxy.avail && data->state.aptr.proxyuserpwd) { /* proxy auth was requested and there was proxy auth available, @@ -687,8 +683,8 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, } static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { struct h1_tunnel_state *ts = cf->ctx; @@ -741,7 +737,6 @@ struct Curl_cftype Curl_cft_h1_proxy = { cf_h1_proxy_connect, cf_h1_proxy_close, Curl_cf_def_shutdown, - Curl_cf_http_proxy_get_host, cf_h1_proxy_adjust_pollset, Curl_cf_def_data_pending, Curl_cf_def_send, @@ -749,7 +744,7 @@ struct Curl_cftype Curl_cft_h1_proxy = { Curl_cf_def_cntrl, Curl_cf_def_conn_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + Curl_cf_http_proxy_query, }; CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at, diff --git a/vendor/curl/lib/cf-h2-proxy.c b/vendor/curl/lib/cf-h2-proxy.c index d3bc4b07..8a853f6b 100644 --- a/vendor/curl/lib/cf-h2-proxy.c +++ b/vendor/curl/lib/cf-h2-proxy.c @@ -28,6 +28,7 @@ #include #include "urldata.h" +#include "url.h" #include "cfilters.h" #include "connect.h" #include "curl_trc.h" @@ -80,7 +81,7 @@ struct tunnel_stream { }; static CURLcode tunnel_stream_init(struct Curl_cfilter *cf, - struct tunnel_stream *ts) + struct tunnel_stream *ts) { const char *hostname; int port; @@ -218,58 +219,28 @@ static void drain_tunnel(struct Curl_cfilter *cf, struct tunnel_stream *tunnel) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - unsigned char bits; - (void)cf; - bits = CURL_CSELECT_IN; if(!tunnel->closed && !tunnel->reset && !Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) - bits |= CURL_CSELECT_OUT; - if(data->state.select_bits != bits) { - CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x", - tunnel->stream_id, bits); - data->state.select_bits = bits; - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } -} - -static ssize_t proxy_nw_in_reader(void *reader_ctx, - unsigned char *buf, size_t buflen, - CURLcode *err) -{ - struct Curl_cfilter *cf = reader_ctx; - ssize_t nread; - - if(cf) { - struct Curl_easy *data = CF_DATA_CURRENT(cf); - nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); - CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %zd, %d", - buflen, nread, *err); - } - else { - nread = 0; - } - return nread; + Curl_multi_mark_dirty(data); } -static ssize_t proxy_h2_nw_out_writer(void *writer_ctx, - const unsigned char *buf, size_t buflen, - CURLcode *err) +static CURLcode proxy_h2_nw_out_writer(void *writer_ctx, + const unsigned char *buf, size_t buflen, + size_t *pnwritten) { struct Curl_cfilter *cf = writer_ctx; - ssize_t nwritten; - + *pnwritten = 0; if(cf) { struct Curl_easy *data = CF_DATA_CURRENT(cf); - nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen, - FALSE, err); - CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d", - buflen, nwritten, *err); - } - else { - nwritten = 0; + CURLcode result; + result = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen, + FALSE, pnwritten); + CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %d, %zu", + buflen, result, *pnwritten); + return result; } - return nwritten; + return CURLE_FAILED_INIT; } static int proxy_h2_client_new(struct Curl_cfilter *cf, @@ -297,8 +268,8 @@ static int proxy_h2_client_new(struct Curl_cfilter *cf, } static ssize_t on_session_send(nghttp2_session *h2, - const uint8_t *buf, size_t blen, - int flags, void *userp); + const uint8_t *buf, size_t blen, + int flags, void *userp); static int proxy_h2_on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, void *userp); @@ -414,16 +385,16 @@ static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - ssize_t nwritten; + size_t nwritten; CURLcode result; (void)data; if(Curl_bufq_is_empty(&ctx->outbufq)) return CURLE_OK; - nwritten = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf, - &result); - if(nwritten < 0) { + result = Curl_bufq_pass(&ctx->outbufq, proxy_h2_nw_out_writer, cf, + &nwritten); + if(result) { if(result == CURLE_AGAIN) { CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN", Curl_bufq_len(&ctx->outbufq)); @@ -479,7 +450,7 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf, { struct cf_h2_proxy_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; - ssize_t nread; + size_t nread; /* Process network input buffer fist */ if(!Curl_bufq_is_empty(&ctx->inbufq)) { @@ -496,10 +467,10 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf, Curl_bufq_is_empty(&ctx->inbufq) && /* and we consumed our input */ !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) { - nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result); - CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d", - Curl_bufq_len(&ctx->inbufq), nread, result); - if(nread < 0) { + result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread); + CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %d, %zu", + Curl_bufq_len(&ctx->inbufq), result, nread); + if(result) { if(result != CURLE_AGAIN) { failf(data, "Failed receiving HTTP2 data"); return result; @@ -547,17 +518,18 @@ static ssize_t on_session_send(nghttp2_session *h2, struct Curl_cfilter *cf = userp; struct cf_h2_proxy_ctx *ctx = cf->ctx; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten; + size_t nwritten; CURLcode result = CURLE_OK; (void)h2; (void)flags; DEBUGASSERT(data); - nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, - proxy_h2_nw_out_writer, cf, &result); - if(nwritten < 0) { + result = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, + proxy_h2_nw_out_writer, cf, &nwritten); + if(result) { if(result == CURLE_AGAIN) { + ctx->nw_out_blocked = 1; return NGHTTP2_ERR_WOULDBLOCK; } failf(data, "Failed sending HTTP2 data"); @@ -567,7 +539,8 @@ static ssize_t on_session_send(nghttp2_session *h2, if(!nwritten) return NGHTTP2_ERR_WOULDBLOCK; - return nwritten; + return (nwritten > SSIZE_T_MAX) ? + NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten; } #ifndef CURL_DISABLE_VERBOSE_STRINGS @@ -817,7 +790,7 @@ static ssize_t tunnel_send_callback(nghttp2_session *session, struct Curl_easy *data = CF_DATA_CURRENT(cf); struct tunnel_stream *ts; CURLcode result; - ssize_t nread; + size_t nread; (void)source; (void)data; @@ -831,8 +804,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session, return NGHTTP2_ERR_CALLBACK_FAILURE; DEBUGASSERT(ts == &ctx->tunnel); - nread = Curl_bufq_read(&ts->sendbuf, buf, length, &result); - if(nread < 0) { + result = Curl_bufq_read(&ts->sendbuf, buf, length, &nread); + if(result) { if(result != CURLE_AGAIN) return NGHTTP2_ERR_CALLBACK_FAILURE; return NGHTTP2_ERR_DEFERRED; @@ -842,7 +815,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session, CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd", ts->stream_id, nread); - return nread; + return (nread > SSIZE_T_MAX) ? + NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nread; } static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, @@ -851,7 +825,7 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, { struct Curl_cfilter *cf = userp; struct cf_h2_proxy_ctx *ctx = cf->ctx; - ssize_t nwritten; + size_t nwritten; CURLcode result; (void)flags; @@ -861,14 +835,15 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags, if(stream_id != ctx->tunnel.stream_id) return NGHTTP2_ERR_CALLBACK_FAILURE; - nwritten = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &result); - if(nwritten < 0) { + result = Curl_bufq_write(&ctx->tunnel.recvbuf, mem, len, &nwritten); + if(result) { if(result != CURLE_AGAIN) return NGHTTP2_ERR_CALLBACK_FAILURE; #ifdef DEBUGBUILD nwritten = 0; #endif } + /* tunnel.recbuf has soft limit, any success MUST add all data */ DEBUGASSERT((size_t)nwritten == len); return 0; } @@ -1277,212 +1252,179 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf, } } -static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf, - struct Curl_easy *data, - CURLcode *err) +static CURLcode h2_handle_tunnel_close(struct Curl_cfilter *cf, + struct Curl_easy *data, + size_t *pnread) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - ssize_t rv = 0; + *pnread = 0; if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) { CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new " "connection", ctx->tunnel.stream_id); connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */ - *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ - return -1; + return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ } else if(ctx->tunnel.error != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)", ctx->tunnel.stream_id, nghttp2_http2_strerror(ctx->tunnel.error), ctx->tunnel.error); - *err = CURLE_HTTP2_STREAM; - return -1; + return CURLE_HTTP2_STREAM; } else if(ctx->tunnel.reset) { failf(data, "HTTP/2 stream %u was reset", ctx->tunnel.stream_id); - *err = CURLE_RECV_ERROR; - return -1; + return CURLE_RECV_ERROR; } - *err = CURLE_OK; - rv = 0; - CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> %zd, %d", - ctx->tunnel.stream_id, rv, *err); - return rv; + CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> 0", + ctx->tunnel.stream_id); + return CURLE_OK; } -static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - ssize_t nread = -1; - - *err = CURLE_AGAIN; - if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) { - nread = Curl_bufq_read(&ctx->tunnel.recvbuf, - (unsigned char *)buf, len, err); - if(nread < 0) - goto out; - DEBUGASSERT(nread > 0); - } + CURLcode result = CURLE_AGAIN; - if(nread < 0) { + *pnread = 0; + if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) + result = Curl_bufq_cread(&ctx->tunnel.recvbuf, buf, len, pnread); + else { if(ctx->tunnel.closed) { - nread = h2_handle_tunnel_close(cf, data, err); + result = h2_handle_tunnel_close(cf, data, pnread); } else if(ctx->tunnel.reset || (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || (ctx->rcvd_goaway && ctx->last_stream_id < ctx->tunnel.stream_id)) { - *err = CURLE_RECV_ERROR; - nread = -1; + result = CURLE_RECV_ERROR; } - } - else if(nread == 0) { - *err = CURLE_AGAIN; - nread = -1; + else + result = CURLE_AGAIN; } -out: - CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %zd, %d", - ctx->tunnel.stream_id, len, nread, *err); - return nread; + CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %d, %zu", + ctx->tunnel.stream_id, len, result, *pnread); + return result; } -static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode cf_h2_proxy_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t len, + size_t *pnread) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - ssize_t nread = -1; struct cf_call_data save; CURLcode result; + *pnread = 0; + CF_DATA_SAVE(save, cf, data); + if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) { - *err = CURLE_RECV_ERROR; - return -1; + result = CURLE_RECV_ERROR; + goto out; } - CF_DATA_SAVE(save, cf, data); if(Curl_bufq_is_empty(&ctx->tunnel.recvbuf)) { - *err = proxy_h2_progress_ingress(cf, data); - if(*err) + result = proxy_h2_progress_ingress(cf, data); + if(result) goto out; } - nread = tunnel_recv(cf, data, buf, len, err); + result = tunnel_recv(cf, data, buf, len, pnread); - if(nread > 0) { - CURL_TRC_CF(data, cf, "[%d] increase window by %zd", - ctx->tunnel.stream_id, nread); - nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread); + if(!result) { + CURL_TRC_CF(data, cf, "[%d] increase window by %zu", + ctx->tunnel.stream_id, *pnread); + nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, *pnread); } - result = proxy_h2_progress_egress(cf, data); - if(result && (result != CURLE_AGAIN)) { - *err = result; - nread = -1; - } + result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data)); out: if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) && - (nread >= 0 || *err == CURLE_AGAIN)) { + (!result || (result == CURLE_AGAIN))) { /* data pending and no fatal error to report. Need to trigger * draining to avoid stalling when no socket events happen. */ drain_tunnel(cf, data, &ctx->tunnel); } - CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d", - ctx->tunnel.stream_id, len, nread, *err); + CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu", + ctx->tunnel.stream_id, len, result, *pnread); CF_DATA_RESTORE(cf, save); - return nread; + return result; } -static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_h2_proxy_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_h2_proxy_ctx *ctx = cf->ctx; struct cf_call_data save; int rv; - ssize_t nwritten; CURLcode result; (void)eos; + *pnwritten = 0; + CF_DATA_SAVE(save, cf, data); + if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) { - *err = CURLE_SEND_ERROR; - return -1; + result = CURLE_SEND_ERROR; + goto out; } - CF_DATA_SAVE(save, cf, data); if(ctx->tunnel.closed) { - nwritten = -1; - *err = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; goto out; } - else { - nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err); - if(nwritten < 0 && (*err != CURLE_AGAIN)) - goto out; - } + + result = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, pnwritten); + CURL_TRC_CF(data, cf, "cf_send(), bufq_write %d, %zd", result, *pnwritten); + if(result && (result != CURLE_AGAIN)) + goto out; if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) { /* req body data is buffered, resume the potentially suspended stream */ rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id); if(nghttp2_is_fatal(rv)) { - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } } - result = proxy_h2_progress_ingress(cf, data); - if(result) { - *err = result; - nwritten = -1; - goto out; - } - - /* Call the nghttp2 send loop and flush to write ALL buffered data, - * headers and/or request body completely out to the network */ - result = proxy_h2_progress_egress(cf, data); - if(result && (result != CURLE_AGAIN)) { - *err = result; - nwritten = -1; - goto out; - } + result = Curl_1st_fatal(result, proxy_h2_progress_ingress(cf, data)); + result = Curl_1st_fatal(result, proxy_h2_progress_egress(cf, data)); - if(proxy_h2_should_close_session(ctx)) { + if(!result && proxy_h2_should_close_session(ctx)) { /* nghttp2 thinks this session is done. If the stream has not been * closed, this is an error state for out transfer */ if(ctx->tunnel.closed) { - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; } else { CURL_TRC_CF(data, cf, "[0] send: nothing to do in this session"); - *err = CURLE_HTTP2; - nwritten = -1; + result = CURLE_HTTP2; } } out: if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) && - (nwritten >= 0 || *err == CURLE_AGAIN)) { + (!result || (result == CURLE_AGAIN))) { /* data pending and no fatal error to report. Need to trigger * draining to avoid stalling when no socket events happen. */ drain_tunnel(cf, data, &ctx->tunnel); } - CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, " + CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, " "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)", - ctx->tunnel.stream_id, len, nwritten, *err, + ctx->tunnel.stream_id, len, result, *pnwritten, nghttp2_session_get_stream_remote_window_size( ctx->h2, ctx->tunnel.stream_id), nghttp2_session_get_remote_window_size(ctx->h2), Curl_bufq_len(&ctx->tunnel.sendbuf), Curl_bufq_len(&ctx->outbufq)); CF_DATA_RESTORE(cf, save); - return nwritten; + return result; } static CURLcode cf_h2_proxy_flush(struct Curl_cfilter *cf, @@ -1533,11 +1475,11 @@ static bool proxy_h2_connisalive(struct Curl_cfilter *cf, not in use by any other transfer, there should not be any data here, only "protocol frames" */ CURLcode result; - ssize_t nread = -1; + size_t nread; *input_pending = FALSE; - nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result); - if(nread != -1) { + result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread); + if(!result) { if(proxy_h2_process_pending_input(cf, data, &result) < 0) /* immediate error, considered dead */ alive = FALSE; @@ -1559,15 +1501,16 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf, bool *input_pending) { struct cf_h2_proxy_ctx *ctx = cf->ctx; - CURLcode result; + bool alive; struct cf_call_data save; + *input_pending = FALSE; CF_DATA_SAVE(save, cf, data); - result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending)); + alive = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending)); CURL_TRC_CF(data, cf, "[0] conn alive -> %d, input_pending=%d", - result, *input_pending); + alive, *input_pending); CF_DATA_RESTORE(cf, save); - return result; + return alive; } static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf, @@ -1577,6 +1520,10 @@ static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf, struct cf_h2_proxy_ctx *ctx = cf->ctx; switch(query) { + case CF_QUERY_HOST_PORT: + *pres1 = (int)cf->conn->http_proxy.port; + *((const char **)pres2) = cf->conn->http_proxy.host.name; + return CURLE_OK; case CF_QUERY_NEED_FLUSH: { if(!Curl_bufq_is_empty(&ctx->outbufq) || !Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) { @@ -1624,7 +1571,6 @@ struct Curl_cftype Curl_cft_h2_proxy = { cf_h2_proxy_connect, cf_h2_proxy_close, cf_h2_proxy_shutdown, - Curl_cf_http_proxy_get_host, cf_h2_proxy_adjust_pollset, cf_h2_proxy_data_pending, cf_h2_proxy_send, diff --git a/vendor/curl/lib/cf-haproxy.c b/vendor/curl/lib/cf-haproxy.c index 7bc12dbb..6183ca2c 100644 --- a/vendor/curl/lib/cf-haproxy.c +++ b/vendor/curl/lib/cf-haproxy.c @@ -131,17 +131,17 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, case HAPROXY_SEND: len = curlx_dyn_len(&ctx->data_out); if(len > 0) { - ssize_t nwritten; - nwritten = Curl_conn_cf_send(cf->next, data, - curlx_dyn_ptr(&ctx->data_out), len, FALSE, - &result); - if(nwritten < 0) { + size_t nwritten; + result = Curl_conn_cf_send(cf->next, data, + curlx_dyn_ptr(&ctx->data_out), len, FALSE, + &nwritten); + if(result) { if(result != CURLE_AGAIN) goto out; result = CURLE_OK; nwritten = 0; } - curlx_dyn_tail(&ctx->data_out, len - (size_t)nwritten); + curlx_dyn_tail(&ctx->data_out, len - nwritten); if(curlx_dyn_len(&ctx->data_out) > 0) { result = CURLE_OK; goto out; @@ -197,7 +197,6 @@ struct Curl_cftype Curl_cft_haproxy = { cf_haproxy_connect, cf_haproxy_close, Curl_cf_def_shutdown, - Curl_cf_def_get_host, cf_haproxy_adjust_pollset, Curl_cf_def_data_pending, Curl_cf_def_send, diff --git a/vendor/curl/lib/cf-https-connect.c b/vendor/curl/lib/cf-https-connect.c index c677f12f..b89ed80e 100644 --- a/vendor/curl/lib/cf-https-connect.c +++ b/vendor/curl/lib/cf-https-connect.c @@ -55,6 +55,7 @@ struct cf_hc_baller { CURLcode result; struct curltime started; int reply_ms; + unsigned char transport; enum alpnid alpn_id; BIT(shutdown); }; @@ -117,17 +118,20 @@ struct cf_hc_ctx { CURLcode result; /* overall result */ struct cf_hc_baller ballers[2]; size_t baller_count; - unsigned int soft_eyeballs_timeout_ms; - unsigned int hard_eyeballs_timeout_ms; + timediff_t soft_eyeballs_timeout_ms; + timediff_t hard_eyeballs_timeout_ms; }; static void cf_hc_baller_assign(struct cf_hc_baller *b, - enum alpnid alpn_id) + enum alpnid alpn_id, + unsigned char def_transport) { b->alpn_id = alpn_id; + b->transport = def_transport; switch(b->alpn_id) { case ALPN_h3: b->name = "h3"; + b->transport = TRNSPRT_QUIC; break; case ALPN_h2: b->name = "h2"; @@ -218,6 +222,7 @@ static CURLcode baller_connected(struct Curl_cfilter *cf, winner->name, (int)curlx_timediff(curlx_now(), winner->started)); + /* install the winning filter below this one. */ cf->next = winner->cf; winner->cf = NULL; @@ -268,15 +273,16 @@ static bool time_to_start_next(struct Curl_cfilter *cf, } elapsed_ms = curlx_timediff(now, ctx->started); if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) { - CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting %s", + CURL_TRC_CF(data, cf, "hard timeout of %" FMT_TIMEDIFF_T "ms reached, " + "starting %s", ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name); return TRUE; } if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) { if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) { - CURL_TRC_CF(data, cf, "soft timeout of %dms reached, %s has not " - "seen any data, starting %s", + CURL_TRC_CF(data, cf, "soft timeout of %" FMT_TIMEDIFF_T "ms reached, " + "%s has not seen any data, starting %s", ctx->soft_eyeballs_timeout_ms, ctx->ballers[idx - 1].name, ctx->ballers[idx].name); return TRUE; @@ -311,11 +317,11 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, DEBUGASSERT(!ctx->ballers[i].cf); CURL_TRC_CF(data, cf, "connect, init"); ctx->started = now; - cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport); + cf_hc_baller_init(&ctx->ballers[0], cf, data, ctx->ballers[0].transport); if(ctx->baller_count > 1) { Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS); - CURL_TRC_CF(data, cf, "set next attempt to start in %ums", - ctx->soft_eyeballs_timeout_ms); + CURL_TRC_CF(data, cf, "set next attempt to start in %" FMT_TIMEDIFF_T + "ms", ctx->soft_eyeballs_timeout_ms); } ctx->state = CF_HC_CONNECT; FALLTHROUGH(); @@ -330,7 +336,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, } if(time_to_start_next(cf, data, 1, now)) { - cf_hc_baller_init(&ctx->ballers[1], cf, data, cf->conn->transport); + cf_hc_baller_init(&ctx->ballers[1], cf, data, ctx->ballers[1].transport); } if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) { @@ -423,8 +429,8 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf, } static void cf_hc_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { if(!cf->connected) { struct cf_hc_ctx *ctx = cf->ctx; @@ -561,7 +567,6 @@ struct Curl_cftype Curl_cft_http_connect = { cf_hc_connect, cf_hc_close, cf_hc_shutdown, - Curl_cf_def_get_host, cf_hc_adjust_pollset, cf_hc_data_pending, Curl_cf_def_send, @@ -574,7 +579,8 @@ struct Curl_cftype Curl_cft_http_connect = { static CURLcode cf_hc_create(struct Curl_cfilter **pcf, struct Curl_easy *data, - enum alpnid *alpnids, size_t alpn_count) + enum alpnid *alpnids, size_t alpn_count, + unsigned char def_transport) { struct Curl_cfilter *cf = NULL; struct cf_hc_ctx *ctx; @@ -596,7 +602,7 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf, goto out; } for(i = 0; i < alpn_count; ++i) - cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]); + cf_hc_baller_assign(&ctx->ballers[i], alpnids[i], def_transport); for(; i < CURL_ARRAYSIZE(ctx->ballers); ++i) ctx->ballers[i].alpn_id = ALPN_none; ctx->baller_count = alpn_count; @@ -616,13 +622,14 @@ static CURLcode cf_hc_create(struct Curl_cfilter **pcf, static CURLcode cf_http_connect_add(struct Curl_easy *data, struct connectdata *conn, int sockindex, - enum alpnid *alpn_ids, size_t alpn_count) + enum alpnid *alpn_ids, size_t alpn_count, + unsigned char def_transport) { struct Curl_cfilter *cf; CURLcode result = CURLE_OK; DEBUGASSERT(data); - result = cf_hc_create(&cf, data, alpn_ids, alpn_count); + result = cf_hc_create(&cf, data, alpn_ids, alpn_count, def_transport); if(result) goto out; Curl_conn_cf_add(data, conn, sockindex, cf); @@ -658,7 +665,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data, if(conn->bits.tls_enable_alpn) { #ifdef USE_HTTPSRR - /* Is there a HTTPSRR use its ALPNs here. + /* Is there an HTTPSRR use its ALPNs here. * We are here after having selected a connection to a host+port and * can no longer change that. Any HTTPSRR advice for other hosts and ports * we need to ignore. */ @@ -679,7 +686,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data, continue; switch(alpn) { case ALPN_h3: - if(Curl_conn_may_http3(data, conn)) + if(Curl_conn_may_http3(data, conn, conn->transport_wanted)) break; /* not possible */ if(data->state.http_neg.allowed & CURL_HTTP_V3x) { CURL_TRC_CF(data, cf, "adding h3 via HTTPS-RR"); @@ -708,7 +715,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data, if((alpn_count < CURL_ARRAYSIZE(alpn_ids)) && (data->state.http_neg.wanted & CURL_HTTP_V3x) && !cf_https_alpns_contain(ALPN_h3, alpn_ids, alpn_count)) { - result = Curl_conn_may_http3(data, conn); + result = Curl_conn_may_http3(data, conn, conn->transport_wanted); if(!result) { CURL_TRC_CF(data, cf, "adding wanted h3"); alpn_ids[alpn_count++] = ALPN_h3; @@ -733,7 +740,9 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data, /* If we identified ALPNs to use, install our filter. Otherwise, * install nothing, so our call will use a default connect setup. */ if(alpn_count) { - result = cf_http_connect_add(data, conn, sockindex, alpn_ids, alpn_count); + result = cf_http_connect_add(data, conn, sockindex, + alpn_ids, alpn_count, + conn->transport_wanted); } out: diff --git a/vendor/curl/lib/cf-socket.c b/vendor/curl/lib/cf-socket.c index e3197720..273258fe 100644 --- a/vendor/curl/lib/cf-socket.c +++ b/vendor/curl/lib/cf-socket.c @@ -73,7 +73,6 @@ #include "url.h" /* for Curl_safefree() */ #include "multiif.h" #include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "inet_ntop.h" #include "curlx/inet_pton.h" #include "progress.h" #include "curlx/warnless.h" @@ -395,10 +394,10 @@ static CURLcode socket_open(struct Curl_easy *data, * */ CURLcode Curl_socket_open(struct Curl_easy *data, - const struct Curl_addrinfo *ai, - struct Curl_sockaddr_ex *addr, - int transport, - curl_socket_t *sockfd) + const struct Curl_addrinfo *ai, + struct Curl_sockaddr_ex *addr, + int transport, + curl_socket_t *sockfd) { struct Curl_sockaddr_ex dummy; CURLcode result; @@ -996,8 +995,6 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data) cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD; socket_close(data, cf->conn, !ctx->accepted, ctx->sock); ctx->sock = CURL_SOCKET_BAD; - if(ctx->active && cf->sockindex == FIRSTSOCKET) - cf->conn->remote_addr = NULL; ctx->active = FALSE; memset(&ctx->started_at, 0, sizeof(ctx->started_at)); memset(&ctx->connected_at, 0, sizeof(ctx->connected_at)); @@ -1095,7 +1092,7 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf, } static CURLcode cf_socket_open(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_socket_ctx *ctx = cf->ctx; int error = 0; @@ -1378,22 +1375,9 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, return result; } -static void cf_socket_get_host(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char **phost, - const char **pdisplay_host, - int *pport) -{ - struct cf_socket_ctx *ctx = cf->ctx; - (void)data; - *phost = cf->conn->host.name; - *pdisplay_host = cf->conn->host.dispname; - *pport = ctx->ip.remote_port; -} - static void cf_socket_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_socket_ctx *ctx = cf->ctx; @@ -1420,17 +1404,6 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf, } } -static bool cf_socket_data_pending(struct Curl_cfilter *cf, - const struct Curl_easy *data) -{ - struct cf_socket_ctx *ctx = cf->ctx; - int readable; - - (void)data; - readable = SOCKET_READABLE(ctx->sock, 0); - return readable > 0 && (readable & CURL_CSELECT_IN); -} - #ifdef USE_WINSOCK #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY @@ -1457,17 +1430,18 @@ static void win_update_sndbuf_size(struct cf_socket_ctx *ctx) #endif /* USE_WINSOCK */ -static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_socket_ctx *ctx = cf->ctx; curl_socket_t fdsave; ssize_t nwritten; size_t orig_len = len; + CURLcode result = CURLE_OK; (void)eos; /* unused */ - *err = CURLE_OK; + *pnwritten = 0; fdsave = cf->conn->sock[cf->sockindex]; cf->conn->sock[cf->sockindex] = ctx->sock; @@ -1478,10 +1452,8 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, Curl_rand_bytes(data, FALSE, &c, 1); if(c >= ((100-ctx->wblock_percent)*256/100)) { CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len); - *err = CURLE_AGAIN; - nwritten = -1; cf->conn->sock[cf->sockindex] = fdsave; - return nwritten; + return CURLE_AGAIN; } } if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) { @@ -1496,15 +1468,14 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */ if(cf->conn->bits.tcp_fastopen) { nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN, - &cf->conn->remote_addr->curl_sa_addr, - cf->conn->remote_addr->addrlen); + &ctx->addr.curl_sa_addr, ctx->addr.addrlen); cf->conn->bits.tcp_fastopen = FALSE; } else #endif nwritten = swrite(ctx->sock, buf, len); - if(-1 == nwritten) { + if(nwritten < 0) { int sockerr = SOCKERRNO; if( @@ -1521,36 +1492,38 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, #endif ) { /* this is just a case of EWOULDBLOCK */ - *err = CURLE_AGAIN; + result = CURLE_AGAIN; } else { char buffer[STRERROR_LEN]; failf(data, "Send failure: %s", Curl_strerror(sockerr, buffer, sizeof(buffer))); data->state.os_errno = sockerr; - *err = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } } + else + *pnwritten = (size_t)nwritten; #if defined(USE_WINSOCK) - if(!*err) + if(!result) win_update_sndbuf_size(ctx); #endif - CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d", - orig_len, (int)nwritten, *err); + CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, %zu", + orig_len, result, *pnwritten); cf->conn->sock[cf->sockindex] = fdsave; - return nwritten; + return result; } -static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { struct cf_socket_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; ssize_t nread; - *err = CURLE_OK; - + *pnread = 0; #ifdef DEBUGBUILD /* simulate network blocking/partial reads */ if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) { @@ -1558,8 +1531,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, Curl_rand(data, &c, 1); if(c >= ((100-ctx->rblock_percent)*256/100)) { CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len); - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } } if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) { @@ -1570,10 +1542,9 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, } #endif - *err = CURLE_OK; nread = sread(ctx->sock, buf, len); - if(-1 == nread) { + if(nread < 0) { int sockerr = SOCKERRNO; if( @@ -1589,25 +1560,25 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data, #endif ) { /* this is just a case of EWOULDBLOCK */ - *err = CURLE_AGAIN; + result = CURLE_AGAIN; } else { char buffer[STRERROR_LEN]; - failf(data, "Recv failure: %s", Curl_strerror(sockerr, buffer, sizeof(buffer))); data->state.os_errno = sockerr; - *err = CURLE_RECV_ERROR; + result = CURLE_RECV_ERROR; } } + else + *pnread = (size_t)nread; - CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread, - *err); - if(nread > 0 && !ctx->got_first_byte) { + CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, %zu", len, result, *pnread); + if(!result && !ctx->got_first_byte) { ctx->first_byte_at = curlx_now(); ctx->got_first_byte = TRUE; } - return nread; + return result; } static void cf_socket_update_data(struct Curl_cfilter *cf, @@ -1631,7 +1602,6 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data) set_local_ip(cf, data); if(cf->sockindex == FIRSTSOCKET) { cf->conn->primary = ctx->ip; - cf->conn->remote_addr = &ctx->addr; #ifdef USE_IPV6 cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6); #endif @@ -1713,6 +1683,15 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf, DEBUGASSERT(pres2); *((curl_socket_t *)pres2) = ctx->sock; return CURLE_OK; + case CF_QUERY_TRANSPORT: + DEBUGASSERT(pres1); + *pres1 = ctx->transport; + return CURLE_OK; + case CF_QUERY_REMOTE_ADDR: + DEBUGASSERT(pres2); + *((const struct Curl_sockaddr_ex **)pres2) = cf->connected ? + &ctx->addr : NULL; + return CURLE_OK; case CF_QUERY_CONNECT_REPLY_MS: if(ctx->got_first_byte) { timediff_t ms = curlx_timediff(ctx->first_byte_at, ctx->started_at); @@ -1763,9 +1742,8 @@ struct Curl_cftype Curl_cft_tcp = { cf_tcp_connect, cf_socket_close, cf_socket_shutdown, - cf_socket_get_host, cf_socket_adjust_pollset, - cf_socket_data_pending, + Curl_cf_def_data_pending, cf_socket_send, cf_socket_recv, cf_socket_cntrl, @@ -1918,9 +1896,8 @@ struct Curl_cftype Curl_cft_udp = { cf_udp_connect, cf_socket_close, cf_socket_shutdown, - cf_socket_get_host, cf_socket_adjust_pollset, - cf_socket_data_pending, + Curl_cf_def_data_pending, cf_socket_send, cf_socket_recv, cf_socket_cntrl, @@ -1973,9 +1950,8 @@ struct Curl_cftype Curl_cft_unix = { cf_tcp_connect, cf_socket_close, cf_socket_shutdown, - cf_socket_get_host, cf_socket_adjust_pollset, - cf_socket_data_pending, + Curl_cf_def_data_pending, cf_socket_send, cf_socket_recv, cf_socket_cntrl, @@ -2020,7 +1996,7 @@ CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf, } static timediff_t cf_tcp_accept_timeleft(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_socket_ctx *ctx = cf->ctx; timediff_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; @@ -2194,9 +2170,8 @@ struct Curl_cftype Curl_cft_tcp_accept = { cf_tcp_accept_connect, cf_socket_close, cf_socket_shutdown, - cf_socket_get_host, cf_socket_adjust_pollset, - cf_socket_data_pending, + Curl_cf_def_data_pending, cf_socket_send, cf_socket_recv, cf_socket_cntrl, @@ -2222,7 +2197,7 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data, result = CURLE_OUT_OF_MEMORY; goto out; } - ctx->transport = conn->transport; + ctx->transport = TRNSPRT_TCP; ctx->sock = *s; ctx->listening = TRUE; ctx->accepted = FALSE; diff --git a/vendor/curl/lib/cf-socket.h b/vendor/curl/lib/cf-socket.h index d3e35098..90daf079 100644 --- a/vendor/curl/lib/cf-socket.h +++ b/vendor/curl/lib/cf-socket.h @@ -68,10 +68,10 @@ CURLcode Curl_parse_interface(const char *input, * */ CURLcode Curl_socket_open(struct Curl_easy *data, - const struct Curl_addrinfo *ai, - struct Curl_sockaddr_ex *addr, - int transport, - curl_socket_t *sockfd); + const struct Curl_addrinfo *ai, + struct Curl_sockaddr_ex *addr, + int transport, + curl_socket_t *sockfd); int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, curl_socket_t sock); diff --git a/vendor/curl/lib/cfilters.c b/vendor/curl/lib/cfilters.c index a9de86a4..01f1e282 100644 --- a/vendor/curl/lib/cfilters.c +++ b/vendor/curl/lib/cfilters.c @@ -67,22 +67,9 @@ CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf, static void conn_report_connect_stats(struct Curl_easy *data, struct connectdata *conn); -void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data, - const char **phost, const char **pdisplay_host, - int *pport) -{ - if(cf->next) - cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport); - else { - *phost = cf->conn->host.name; - *pdisplay_host = cf->conn->host.dispname; - *pport = cf->conn->primary.remote_port; - } -} - void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { /* NOP */ (void)cf; @@ -97,21 +84,23 @@ bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, cf->next->cft->has_data_pending(cf->next, data) : FALSE; } -ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, +CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, bool eos, - CURLcode *err) + size_t *pnwritten) { - return cf->next ? - cf->next->cft->do_send(cf->next, data, buf, len, eos, err) : - CURLE_RECV_ERROR; + if(cf->next) + return cf->next->cft->do_send(cf->next, data, buf, len, eos, pnwritten); + *pnwritten = 0; + return CURLE_RECV_ERROR; } -ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { - return cf->next ? - cf->next->cft->do_recv(cf->next, data, buf, len, err) : - CURLE_SEND_ERROR; + if(cf->next) + return cf->next->cft->do_recv(cf->next, data, buf, len, pnread); + *pnread = 0; + return CURLE_SEND_ERROR; } bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf, @@ -234,52 +223,102 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done) return result; } -ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf, - size_t len, CURLcode *code) +CURLcode Curl_cf_recv(struct Curl_easy *data, int num, char *buf, + size_t len, size_t *pnread) { struct Curl_cfilter *cf; DEBUGASSERT(data); DEBUGASSERT(data->conn); - *code = CURLE_OK; cf = data->conn->cfilter[num]; - while(cf && !cf->connected) { + while(cf && !cf->connected) cf = cf->next; - } - if(cf) { - ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code); - DEBUGASSERT(nread >= 0 || *code); - DEBUGASSERT(nread < 0 || !*code); - return nread; - } + if(cf) + return cf->cft->do_recv(cf, data, buf, len, pnread); failf(data, "recv: no filter connected"); - *code = CURLE_FAILED_INIT; - return -1; + DEBUGASSERT(0); + *pnread = 0; + return CURLE_FAILED_INIT; } -ssize_t Curl_cf_send(struct Curl_easy *data, int num, - const void *mem, size_t len, bool eos, - CURLcode *code) +CURLcode Curl_cf_send(struct Curl_easy *data, int num, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { struct Curl_cfilter *cf; DEBUGASSERT(data); DEBUGASSERT(data->conn); - *code = CURLE_OK; cf = data->conn->cfilter[num]; - while(cf && !cf->connected) { + while(cf && !cf->connected) cf = cf->next; - } if(cf) { - ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, eos, code); - DEBUGASSERT(nwritten >= 0 || *code); - DEBUGASSERT(nwritten < 0 || !*code || !len); - return nwritten; + return cf->cft->do_send(cf, data, mem, len, eos, pnwritten); } failf(data, "send: no filter connected"); DEBUGASSERT(0); - *code = CURLE_FAILED_INIT; - return -1; + *pnwritten = 0; + return CURLE_FAILED_INIT; +} + +struct cf_io_ctx { + struct Curl_easy *data; + struct Curl_cfilter *cf; +}; + +static CURLcode cf_bufq_reader(void *writer_ctx, + unsigned char *buf, size_t blen, + size_t *pnread) +{ + struct cf_io_ctx *io = writer_ctx; + return Curl_conn_cf_recv(io->cf, io->data, (char *)buf, blen, pnread); +} + +CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct bufq *bufq, + size_t maxlen, + size_t *pnread) +{ + struct cf_io_ctx io; + + if(!cf || !data) { + *pnread = 0; + return CURLE_BAD_FUNCTION_ARGUMENT; + } + io.data = data; + io.cf = cf; + return Curl_bufq_sipn(bufq, maxlen, cf_bufq_reader, &io, pnread); +} + +static CURLcode cf_bufq_writer(void *writer_ctx, + const unsigned char *buf, size_t buflen, + size_t *pnwritten) +{ + struct cf_io_ctx *io = writer_ctx; + return Curl_conn_cf_send(io->cf, io->data, (const char *)buf, + buflen, FALSE, pnwritten); +} + +CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct bufq *bufq, + const unsigned char *buf, size_t blen, + size_t *pnwritten) +{ + struct cf_io_ctx io; + + if(!cf || !data) { + *pnwritten = 0; + return CURLE_BAD_FUNCTION_ARGUMENT; + } + io.data = data; + io.cf = cf; + if(buf && blen) + return Curl_bufq_write_pass(bufq, buf, blen, cf_bufq_writer, &io, + pnwritten); + else + return Curl_bufq_pass(bufq, cf_bufq_writer, &io, pnwritten); } CURLcode Curl_cf_create(struct Curl_cfilter **pcf, @@ -381,23 +420,23 @@ void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data) cf->cft->do_close(cf, data); } -ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { if(cf) - return cf->cft->do_send(cf, data, buf, len, eos, err); - *err = CURLE_SEND_ERROR; - return -1; + return cf->cft->do_send(cf, data, buf, len, eos, pnwritten); + *pnwritten = 0; + return CURLE_SEND_ERROR; } -ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { if(cf) - return cf->cft->do_recv(cf, data, buf, len, err); - *err = CURLE_RECV_ERROR; - return -1; + return cf->cft->do_recv(cf, data, buf, len, pnread); + *pnread = 0; + return CURLE_RECV_ERROR; } CURLcode Curl_conn_connect(struct Curl_easy *data, @@ -497,6 +536,11 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, return result; } +bool Curl_conn_is_setup(struct connectdata *conn, int sockindex) +{ + return (conn->cfilter[sockindex] != NULL); +} + bool Curl_conn_is_connected(struct connectdata *conn, int sockindex) { struct Curl_cfilter *cf; @@ -536,6 +580,19 @@ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE; } +bool Curl_conn_get_ssl_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + struct curl_tlssessioninfo *info) +{ + if(Curl_conn_is_ssl(conn, sockindex)) { + struct Curl_cfilter *cf = conn->cfilter[sockindex]; + CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO, + NULL, (void *)info) : CURLE_UNKNOWN_OPTION; + return !result; + } + return FALSE; +} + bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) { struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; @@ -549,6 +606,13 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) return FALSE; } +unsigned char Curl_conn_get_transport(struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; + return Curl_conn_cf_get_transport(cf, data); +} + unsigned char Curl_conn_http_version(struct Curl_easy *data, struct connectdata *conn) { @@ -673,31 +737,35 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf, return Curl_poll(pfds, npfds, timeout_ms); } -void Curl_conn_get_host(struct Curl_easy *data, int sockindex, - const char **phost, const char **pdisplay_host, - int *pport) +void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex, + const char **phost, int *pport) { - struct Curl_cfilter *cf; + struct Curl_cfilter *cf, *cf_proxy = NULL; DEBUGASSERT(data->conn); cf = data->conn->cfilter[sockindex]; - if(cf) { - cf->cft->get_host(cf, data, phost, pdisplay_host, pport); + /* Find the "lowest" tunneling proxy filter that has not connected yet. */ + while(cf && !cf->connected) { + if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) == + (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) + cf_proxy = cf; + cf = cf->next; } - else { - /* Some filter ask during shutdown for this, mainly for debugging - * purposes. We hand out the defaults, however this is not always - * accurate, as the connection might be tunneled, etc. But all that - * state is already gone here. */ + /* cf_proxy (!= NULL) is not connected yet. It is talking + * to an interim host and any authentication or other things apply + * to this interim host and port. */ + if(!cf_proxy || cf_proxy->cft->query(cf_proxy, data, CF_QUERY_HOST_PORT, + pport, CURL_UNCONST(phost))) { + /* Everything connected or query unsuccessful, the overall + * connection's destination is the answer */ *phost = data->conn->host.name; - *pdisplay_host = data->conn->host.dispname; *pport = data->conn->remote_port; } } CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) + struct Curl_easy *data, + int event, int arg1, void *arg2) { (void)cf; (void)data; @@ -733,6 +801,26 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf, return CURL_SOCKET_BAD; } +unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + int transport = 0; + if(cf && !cf->cft->query(cf, data, CF_QUERY_TRANSPORT, &transport, NULL)) + return (unsigned char)transport; + return (unsigned char)(data->conn ? data->conn->transport_wanted : 0); +} + +static const struct Curl_sockaddr_ex * +cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data) +{ + const struct Curl_sockaddr_ex *remote_addr = NULL; + if(cf && + !cf->cft->query(cf, data, CF_QUERY_REMOTE_ADDR, NULL, + CURL_UNCONST(&remote_addr))) + return remote_addr; + return NULL; +} + CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf, struct Curl_easy *data, int *is_ipv6, struct ip_quadruple *ipquad) @@ -755,6 +843,13 @@ curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex) return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD; } +const struct Curl_sockaddr_ex * +Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex) +{ + struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL; + return cf ? cf_get_remote_addr(cf, data) : NULL; +} + void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex) { if(data->conn) { @@ -873,8 +968,8 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data, } size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) + struct connectdata *conn, + int sockindex) { CURLcode result; int n = 0; @@ -907,17 +1002,14 @@ int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd) } CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex, - char *buf, size_t blen, ssize_t *n) + char *buf, size_t blen, size_t *pnread) { - CURLcode result = CURLE_OK; - ssize_t nread; - + DEBUGASSERT(data); DEBUGASSERT(data->conn); - nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result); - DEBUGASSERT(nread >= 0 || result); - DEBUGASSERT(nread < 0 || !result); - *n = (nread >= 0) ? (size_t)nread : 0; - return result; + if(data && data->conn && data->conn->recv[sockindex]) + return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread); + *pnread = 0; + return CURLE_FAILED_INIT; } CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, @@ -925,15 +1017,10 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, size_t *pnwritten) { size_t write_len = blen; - ssize_t nwritten; - CURLcode result = CURLE_OK; - struct connectdata *conn; - DEBUGASSERT(sockindex >= 0 && sockindex < 2); - DEBUGASSERT(pnwritten); DEBUGASSERT(data); DEBUGASSERT(data->conn); - conn = data->conn; + DEBUGASSERT(sockindex >= 0 && sockindex < 2); #ifdef DEBUGBUILD if(write_len) { /* Allow debug builds to override this logic to force short sends @@ -948,11 +1035,11 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, #endif if(write_len != blen) eos = FALSE; - nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos, - &result); - DEBUGASSERT((nwritten >= 0) || result); - *pnwritten = (nwritten < 0) ? 0 : (size_t)nwritten; - return result; + if(data && data->conn && data->conn->send[sockindex]) + return data->conn->send[sockindex](data, sockindex, buf, write_len, eos, + pnwritten); + *pnwritten = 0; + return CURLE_FAILED_INIT; } void Curl_pollset_reset(struct Curl_easy *data, @@ -969,8 +1056,8 @@ void Curl_pollset_reset(struct Curl_easy *data, * */ void Curl_pollset_change(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - int add_flags, int remove_flags) + struct easy_pollset *ps, curl_socket_t sock, + int add_flags, int remove_flags) { unsigned int i; @@ -1080,3 +1167,16 @@ void Curl_pollset_check(struct Curl_easy *data, } *pwant_read = *pwant_write = FALSE; } + +bool Curl_pollset_want_read(struct Curl_easy *data, + struct easy_pollset *ps, + curl_socket_t sock) +{ + unsigned int i; + (void)data; + for(i = 0; i < ps->num; ++i) { + if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN)) + return TRUE; + } + return FALSE; +} diff --git a/vendor/curl/lib/cfilters.h b/vendor/curl/lib/cfilters.h index 646aabf3..39d906d6 100644 --- a/vendor/curl/lib/cfilters.h +++ b/vendor/curl/lib/cfilters.h @@ -26,11 +26,13 @@ #include "curlx/timediff.h" +struct bufq; struct Curl_cfilter; struct Curl_easy; struct Curl_dns_entry; struct connectdata; struct ip_quadruple; +struct curl_tlssessioninfo; /* Callback to destroy resources held by this filter instance. * Implementations MUST NOT chain calls to cf->next. @@ -53,23 +55,6 @@ typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done); -/* Return the hostname and port the connection goes to. - * This may change with the connection state of filters when tunneling - * is involved. - * @param cf the filter to ask - * @param data the easy handle currently active - * @param phost on return, points to the relevant, real hostname. - * this is owned by the connection. - * @param pdisplay_host on return, points to the printable hostname. - * this is owned by the connection. - * @param pport on return, contains the port number - */ -typedef void Curl_cft_get_host(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char **phost, - const char **pdisplay_host, - int *pport); - struct easy_pollset; /* Passing in an easy_pollset for monitoring of sockets, let @@ -102,18 +87,18 @@ typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf, typedef bool Curl_cft_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data); -typedef ssize_t Curl_cft_send(struct Curl_cfilter *cf, +typedef CURLcode Curl_cft_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* transfer */ const void *buf, /* data to write */ size_t len, /* amount to write */ bool eos, /* last chunk */ - CURLcode *err); /* error to return */ + size_t *pnwritten); /* how much sent */ -typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf, +typedef CURLcode Curl_cft_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* transfer */ char *buf, /* store data here */ size_t len, /* amount to read */ - CURLcode *err); /* error to return */ + size_t *pnread); /* how much received */ typedef bool Curl_cft_conn_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -166,6 +151,13 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, * - CF_QUERY_NEED_FLUSH: TRUE iff any of the filters have unsent data * - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the * ip quadruple + * - CF_QUERY_HOST_PORT: the remote hostname and port a filter talks to + * - CF_QUERY_SSL_INFO: fill out the passed curl_tlssessioninfo with the + * internal from the SSL secured connection when + * available. + * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX + * when available, or the same internal pointer + * when the TLS stack does not differentiate. */ /* query res1 res2 */ #define CF_QUERY_MAX_CONCURRENT 1 /* number - */ @@ -177,6 +169,13 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, #define CF_QUERY_NEED_FLUSH 7 /* TRUE/FALSE - */ #define CF_QUERY_IP_INFO 8 /* TRUE/FALSE struct ip_quadruple */ #define CF_QUERY_HTTP_VERSION 9 /* number (10/11/20/30) - */ +/* pass in a `const struct Curl_sockaddr_ex **` as `pres2`. Gets set + * to NULL when not connected. */ +#define CF_QUERY_REMOTE_ADDR 10 /* - `Curl_sockaddr_ex *` */ +#define CF_QUERY_HOST_PORT 11 /* port const char * */ +#define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */ +#define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */ +#define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */ /** * Query the cfilter for properties. Filters ignorant of a query will @@ -213,7 +212,6 @@ struct Curl_cftype { Curl_cft_connect *do_connect; /* establish connection */ Curl_cft_close *do_close; /* close conn */ Curl_cft_shutdown *do_shutdown; /* shutdown conn */ - Curl_cft_get_host *get_host; /* host filter talks to */ Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */ Curl_cft_data_pending *has_data_pending;/* conn has data pending */ Curl_cft_send *do_send; /* send data */ @@ -241,19 +239,16 @@ void Curl_cf_def_destroy_this(struct Curl_cfilter *cf, /* Default implementations for the type functions, implementing pass-through * the filter chain. */ -void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data, - const char **phost, const char **pdisplay_host, - int *pport); void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, struct easy_pollset *ps); bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data); -ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, +CURLcode Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, bool eos, - CURLcode *err); -ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err); + size_t *pnwritten); +CURLcode Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread); CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf, struct Curl_easy *data, int event, int arg1, void *arg2); @@ -326,11 +321,11 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done); void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data); -ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err); -ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err); +CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten); +CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread); CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf, struct Curl_easy *data, bool ignore_result, @@ -356,6 +351,9 @@ CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf, bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, struct Curl_easy *data); +unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, + struct Curl_easy *data); + #define CURL_CF_SSL_DEFAULT -1 #define CURL_CF_SSL_DISABLE 0 #define CURL_CF_SSL_ENABLE 1 @@ -370,6 +368,11 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex, bool blocking, bool *done); +/** + * Check if a filter chain at `sockindex` for connection `conn` exists. + */ +bool Curl_conn_is_setup(struct connectdata *conn, int sockindex); + /** * Check if the filter chain at `sockindex` for connection `conn` is * completely connected. @@ -390,6 +393,15 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex); */ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex); +/* + * Fill `info` with information about the TLS instance securing + * the connection when available, otherwise e.g. when + * Curl_conn_is_ssl() is FALSE, return FALSE. + */ +bool Curl_conn_get_ssl_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + struct curl_tlssessioninfo *info); + /** * Connection provides multiplexing of easy handles at `socketindex`. */ @@ -402,6 +414,10 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex); unsigned char Curl_conn_http_version(struct Curl_easy *data, struct connectdata *conn); +/* Get the TRNSPRT_* the connection is using */ +unsigned char Curl_conn_get_transport(struct Curl_easy *data, + struct connectdata *conn); + /** * Close the filter chain at `sockindex` for connection `data->conn`. * Filters remain in place and may be connected again afterwards. @@ -439,13 +455,17 @@ CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex); */ curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex); +/* Return a pointer to the connected socket address or NULL. */ +const struct Curl_sockaddr_ex * +Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex); + /** * Tell filters to forget about the socket at sockindex. */ void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex); /** - * Adjust the pollset for the filter chain startgin at `cf`. + * Adjust the pollset for the filter chain starting at `cf`. */ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -470,20 +490,41 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf, /** * Receive data through the filter chain at `sockindex` for connection * `data->conn`. Copy at most `len` bytes into `buf`. Return the - * actual number of bytes copied or a negative value on error. - * The error code is placed into `*code`. + * actual number of bytes copied in `*pnread`or an error. */ -ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf, - size_t len, CURLcode *code); +CURLcode Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf, + size_t len, size_t *pnread); /** * Send `len` bytes of data from `buf` through the filter chain `sockindex` * at connection `data->conn`. Return the actual number of bytes written - * or a negative value on error. - * The error code is placed into `*code`. + * in `*pnwritten` or on error. + */ +CURLcode Curl_cf_send(struct Curl_easy *data, int sockindex, + const void *buf, size_t len, bool eos, + size_t *pnwritten); + +/** + * Receive bytes from connection filter `cf` into `bufq`. + * Convenience wrappter around `Curl_bufq_sipn()`, + * so users do not have to implement a callback. */ -ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex, - const void *buf, size_t len, bool eos, CURLcode *code); +CURLcode Curl_cf_recv_bufq(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct bufq *bufq, + size_t maxlen, + size_t *pnread); + +/** + * Send bytes in `bufq` using connection filter `cf`. + * A convenience wrapper around `Curl_bufq_write_pass()`, + * so users do not have to implement a callback. + */ +CURLcode Curl_cf_send_bufq(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct bufq *bufq, + const unsigned char *buf, size_t blen, + size_t *pnwritten); /** * Notify connection filters that they need to setup data for @@ -530,9 +571,17 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data, #ifdef UNITTESTS void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data); #endif -void Curl_conn_get_host(struct Curl_easy *data, int sockindex, - const char **phost, const char **pdisplay_host, - int *pport); + +/** + * Get the remote hostname and port that the connection is currently + * talking to (or will talk to). + * Once connected or before connect starts, + * it is `conn->host.name` and `conn->remote_port`. + * During connect, when tunneling proxies are involved (http or socks), + * it will be the name and port the proxy currently negotiates with. + */ +void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex, + const char **phost, int *pport); /** * Get the maximum number of parallel transfers the connection @@ -562,7 +611,7 @@ int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd); */ CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf, size_t buffersize, - ssize_t *pnread); + size_t *pnread); /* * Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET. @@ -616,6 +665,13 @@ void Curl_pollset_check(struct Curl_easy *data, struct easy_pollset *ps, curl_socket_t sock, bool *pwant_read, bool *pwant_write); +/** + * Return TRUE if the pollset contains socket with CURL_POLL_IN. + */ +bool Curl_pollset_want_read(struct Curl_easy *data, + struct easy_pollset *ps, + curl_socket_t sock); + /** * Types and macros used to keep the current easy handle in filter calls, * allowing for nested invocations. See #10336. diff --git a/vendor/curl/lib/config-mac.h b/vendor/curl/lib/config-mac.h index 1a902b89..6da544fe 100644 --- a/vendor/curl/lib/config-mac.h +++ b/vendor/curl/lib/config-mac.h @@ -43,7 +43,6 @@ #define USE_MANUAL 1 #define HAVE_NETINET_IN_H 1 -#define HAVE_SYS_SOCKET_H 1 #define HAVE_NETDB_H 1 #define HAVE_ARPA_INET_H 1 #define HAVE_UNISTD_H 1 @@ -51,9 +50,7 @@ #define HAVE_SYS_TYPES_H 1 #define HAVE_GETTIMEOFDAY 1 #define HAVE_FCNTL_H 1 -#define HAVE_SYS_STAT_H 1 #define HAVE_UTIME_H 1 -#define HAVE_SYS_TIME_H 1 #define HAVE_SYS_UTIME_H 1 #define HAVE_SYS_IOCTL_H 1 #define HAVE_ALARM 1 diff --git a/vendor/curl/lib/config-os400.h b/vendor/curl/lib/config-os400.h index 4316c58a..064338ed 100644 --- a/vendor/curl/lib/config-os400.h +++ b/vendor/curl/lib/config-os400.h @@ -158,18 +158,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H -/* Define if you have the header file. */ -#define HAVE_SYS_SOCKET_H - /* Define if you have the header file. */ #undef HAVE_SYS_SOCKIO_H -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TIME_H - /* Define if you have the header file. */ #define HAVE_SYS_TYPES_H diff --git a/vendor/curl/lib/config-plan9.h b/vendor/curl/lib/config-plan9.h index 857b7866..68d0cf7f 100644 --- a/vendor/curl/lib/config-plan9.h +++ b/vendor/curl/lib/config-plan9.h @@ -113,9 +113,6 @@ #define HAVE_SYS_IOCTL_H 1 #define HAVE_SYS_PARAM_H 1 #define HAVE_SYS_RESOURCE_H 1 -#define HAVE_SYS_SOCKET_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TYPES_H 1 #define HAVE_SYS_UN_H 1 #define HAVE_TERMIOS_H 1 diff --git a/vendor/curl/lib/config-riscos.h b/vendor/curl/lib/config-riscos.h index b8aaa5d4..3158c984 100644 --- a/vendor/curl/lib/config-riscos.h +++ b/vendor/curl/lib/config-riscos.h @@ -144,18 +144,9 @@ /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H -/* Define if you have the header file. */ -#define HAVE_SYS_SOCKET_H - /* Define if you have the header file. */ #undef HAVE_SYS_SOCKIO_H -/* Define if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define if you have the header file. */ -#define HAVE_SYS_TIME_H - /* Define if you have the header file. */ #define HAVE_SYS_TYPES_H @@ -186,9 +177,6 @@ /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS -/* Define for large files, on AIX-style hosts. */ -#undef _LARGE_FILES - /* Define to empty if `const' does not conform to ANSI C. */ #undef const diff --git a/vendor/curl/lib/config-win32.h b/vendor/curl/lib/config-win32.h index f62f5bec..68377025 100644 --- a/vendor/curl/lib/config-win32.h +++ b/vendor/curl/lib/config-win32.h @@ -28,6 +28,58 @@ /* Hand crafted config file for Windows */ /* ================================================================ */ +#ifndef UNDER_CE + +/* Define some minimum and default build targets for Visual Studio */ +#ifdef _MSC_VER + /* VS2012 default target settings and minimum build target check. */ +# if _MSC_VER >= 1700 + /* The minimum and default build targets for VS2012 are Vista and 8, + respectively, unless Update 1 is installed and the v110_xp toolset + is chosen. */ +# ifdef _USING_V110_SDK71_ +# define VS2012_MIN_TARGET 0x0501 /* XP */ +# define VS2012_DEF_TARGET 0x0501 /* XP */ +# else +# define VS2012_MIN_TARGET 0x0600 /* Vista */ +# define VS2012_DEF_TARGET 0x0602 /* 8 */ +# endif + +# ifndef _WIN32_WINNT +# define _WIN32_WINNT VS2012_DEF_TARGET +# endif +# ifndef WINVER +# define WINVER VS2012_DEF_TARGET +# endif +# if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET) +# ifdef _USING_V110_SDK71_ +# error VS2012 does not support build targets prior to Windows XP +# else +# error VS2012 does not support build targets prior to Windows Vista +# endif +# endif + /* Default target settings and minimum build target check for + VS2008 and VS2010 */ +# else +# define VS2008_MIN_TARGET 0x0501 /* XP */ + /* VS2008 default build target is Windows Vista (0x0600). + We override default target to be Windows XP. */ +# define VS2008_DEF_TARGET 0x0501 /* XP */ + +# ifndef _WIN32_WINNT +# define _WIN32_WINNT VS2008_DEF_TARGET +# endif +# ifndef WINVER +# define WINVER VS2008_DEF_TARGET +# endif +# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) +# error VS2008 does not support build targets prior to Windows XP +# endif +# endif +#endif /* _MSC_VER */ + +#endif /* UNDER_CE */ + /* ---------------------------------------------------------------- */ /* HEADER FILES */ /* ---------------------------------------------------------------- */ @@ -74,20 +126,9 @@ /* Define if you have the header file. */ /* #define HAVE_SYS_SELECT_H 1 */ -/* Define if you have the header file. */ -/* #define HAVE_SYS_SOCKET_H 1 */ - /* Define if you have the header file. */ /* #define HAVE_SYS_SOCKIO_H 1 */ -/* Define if you have the header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define if you have the header file. */ -#ifdef __MINGW32__ -#define HAVE_SYS_TIME_H 1 -#endif - /* Define if you have the header file. */ #define HAVE_SYS_TYPES_H 1 @@ -225,9 +266,9 @@ /* Vista */ #if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600) && !defined(UNDER_CE) -/* Define to 1 if you have a IPv6 capable working inet_ntop function. */ +/* Define to 1 if you have an IPv6 capable working inet_ntop function. */ #define HAVE_INET_NTOP 1 -/* Define to 1 if you have a IPv6 capable working inet_pton function. */ +/* Define to 1 if you have an IPv6 capable working inet_pton function. */ #define HAVE_INET_PTON 1 #endif @@ -307,72 +348,6 @@ # endif #endif -#ifndef UNDER_CE - -/* Define some minimum and default build targets for Visual Studio */ -#ifdef _MSC_VER - /* Officially, Microsoft's Windows SDK versions 6.X does not support Windows - 2000 as a supported build target. VS2008 default installations provides - an embedded Windows SDK v6.0A along with the claim that Windows 2000 is a - valid build target for VS2008. Popular belief is that binaries built with - VS2008 using Windows SDK versions v6.X and Windows 2000 as a build target - are functional. */ -# define VS2008_MIN_TARGET 0x0500 - - /* The minimum build target for VS2012 is Vista unless Update 1 is installed - and the v110_xp toolset is chosen. */ -# ifdef _USING_V110_SDK71_ -# define VS2012_MIN_TARGET 0x0501 -# else -# define VS2012_MIN_TARGET 0x0600 -# endif - - /* VS2008 default build target is Windows Vista. We override default target - to be Windows XP. */ -# define VS2008_DEF_TARGET 0x0501 - - /* VS2012 default build target is Windows Vista unless Update 1 is installed - and the v110_xp toolset is chosen. */ -# ifdef _USING_V110_SDK71_ -# define VS2012_DEF_TARGET 0x0501 -# else -# define VS2012_DEF_TARGET 0x0600 -# endif -#endif - -/* VS2008 default target settings and minimum build target check. */ -#if defined(_MSC_VER) && (_MSC_VER <= 1600) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2008_DEF_TARGET -# endif -# ifndef WINVER -# define WINVER VS2008_DEF_TARGET -# endif -# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) -# error VS2008 does not support Windows build targets prior to Windows 2000 -# endif -#endif - -/* VS2012 default target settings and minimum build target check. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1700) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2012_DEF_TARGET -# endif -# ifndef WINVER -# define WINVER VS2012_DEF_TARGET -# endif -# if (_WIN32_WINNT < VS2012_MIN_TARGET) || (WINVER < VS2012_MIN_TARGET) -# ifdef _USING_V110_SDK71_ -# error VS2012 does not support Windows build targets prior to Windows XP -# else -# error VS2012 does not support Windows build targets prior to Windows \ -Vista -# endif -# endif -#endif - -#endif /* UNDER_CE */ - /* Windows XP is required for freeaddrinfo, getaddrinfo */ #ifndef UNDER_CE #define HAVE_FREEADDRINFO 1 diff --git a/vendor/curl/lib/conncache.c b/vendor/curl/lib/conncache.c index f5e2ea87..fd6776e3 100644 --- a/vendor/curl/lib/conncache.c +++ b/vendor/curl/lib/conncache.c @@ -42,7 +42,6 @@ #include "sigpipe.h" #include "connect.h" #include "select.h" -#include "strcase.h" #include "curlx/strparse.h" #include "uint-table.h" diff --git a/vendor/curl/lib/conncache.h b/vendor/curl/lib/conncache.h index 1314b65c..ac07111a 100644 --- a/vendor/curl/lib/conncache.h +++ b/vendor/curl/lib/conncache.h @@ -106,7 +106,7 @@ typedef bool Curl_cpool_done_match_cb(bool result, void *userdata); * Find a connection in the pool matching `destination`. * All callbacks are invoked while the pool's lock is held. * @param data current transfer - * @param destination match agaonst `conn->destination` in pool + * @param destination match against `conn->destination` in pool * @param conn_cb must be present, called for each connection in the * bundle until it returns TRUE * @return combined result of last conn_db and result_cb or FALSE if no diff --git a/vendor/curl/lib/connect.c b/vendor/curl/lib/connect.c index 1dcdde3f..ac16c339 100644 --- a/vendor/curl/lib/connect.c +++ b/vendor/curl/lib/connect.c @@ -66,7 +66,7 @@ #include "url.h" /* for Curl_safefree() */ #include "multiif.h" #include "sockaddr.h" /* required for Curl_sockaddr_storage */ -#include "inet_ntop.h" +#include "curlx/inet_ntop.h" #include "curlx/inet_pton.h" #include "vtls/vtls.h" /* for vtsl cfilters */ #include "progress.h" @@ -78,7 +78,6 @@ #include "vquic/vquic.h" /* for quic cfilters */ #include "http_proxy.h" #include "socks.h" -#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -90,15 +89,15 @@ enum alpnid Curl_alpn2alpnid(const char *name, size_t len) { if(len == 2) { - if(strncasecompare(name, "h1", 2)) + if(curl_strnequal(name, "h1", 2)) return ALPN_h1; - if(strncasecompare(name, "h2", 2)) + if(curl_strnequal(name, "h2", 2)) return ALPN_h2; - if(strncasecompare(name, "h3", 2)) + if(curl_strnequal(name, "h3", 2)) return ALPN_h3; } else if(len == 8) { - if(strncasecompare(name, "http/1.1", 8)) + if(curl_strnequal(name, "http/1.1", 8)) return ALPN_h1; } return ALPN_none; /* unknown, probably rubbish input */ @@ -172,11 +171,11 @@ void Curl_shutdown_start(struct Curl_easy *data, int sockindex, } data->conn->shutdown.start[sockindex] = *nowp; data->conn->shutdown.timeout_ms = (timeout_ms > 0) ? - (unsigned int)timeout_ms : + (timediff_t)timeout_ms : ((data->set.shutdowntimeout > 0) ? data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS); /* Set a timer, unless we operate on the admin handle */ - if(data->mid && data->conn->shutdown.timeout_ms) + if(data->mid && (data->conn->shutdown.timeout_ms > 0)) Curl_expire_ex(data, nowp, data->conn->shutdown.timeout_ms, EXPIRE_SHUTDOWN); } @@ -187,7 +186,8 @@ timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex, struct curltime now; timediff_t left_ms; - if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms) + if(!conn->shutdown.start[sockindex].tv_sec || + (conn->shutdown.timeout_ms <= 0)) return 0; /* not started or no limits */ if(!nowp) { @@ -254,8 +254,8 @@ addr_next_match(const struct Curl_addrinfo *addr, int family) return NULL; } -/* retrieves ip address and port from a sockaddr structure. - note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */ +/* retrieves ip address and port from a sockaddr structure. note it calls + curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, char *addr, int *port) { @@ -272,7 +272,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, switch(sa->sa_family) { case AF_INET: si = (struct sockaddr_in *)(void *) sa; - if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) { + if(curlx_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) { unsigned short us_port = ntohs(si->sin_port); *port = us_port; return TRUE; @@ -281,7 +281,8 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, #ifdef USE_IPV6 case AF_INET6: si6 = (struct sockaddr_in6 *)(void *) sa; - if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) { + if(curlx_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, + MAX_IPADR_LEN)) { unsigned short us_port = ntohs(si6->sin6_port); *port = us_port; return TRUE; @@ -389,7 +390,6 @@ struct eyeballer { expire_id timeout_id; /* ID for Curl_expire() */ CURLcode result; int error; - BIT(rewinded); /* if we rewinded the addr list */ BIT(has_started); /* attempts have started */ BIT(is_done); /* out of addresses/time */ BIT(connected); /* cf has connected */ @@ -455,7 +455,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer, } static void baller_close(struct eyeballer *baller, - struct Curl_easy *data) + struct Curl_easy *data) { if(baller && baller->cf) { Curl_conn_cf_discard_chain(&baller->cf, data); @@ -463,7 +463,7 @@ static void baller_close(struct eyeballer *baller, } static void baller_free(struct eyeballer *baller, - struct Curl_easy *data) + struct Curl_easy *data) { if(baller) { baller_close(baller, data); @@ -473,7 +473,6 @@ static void baller_free(struct eyeballer *baller, static void baller_rewind(struct eyeballer *baller) { - baller->rewinded = TRUE; baller->addr = baller->first; baller->inconclusive = FALSE; } @@ -682,7 +681,7 @@ static CURLcode is_connected(struct Curl_cfilter *cf, /* next attempt was started */ CURL_TRC_CF(data, cf, "%s trying next", baller->name); ++ongoing; - Curl_expire(data, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); } } } @@ -832,7 +831,7 @@ static CURLcode start_connect(struct Curl_cfilter *cf, addr1 = addr_first_match(dns->addr, ai_family1); /* no ip address families, probably AF_UNIX or something, use the * address family given to us */ - if(!addr1 && !addr0 && dns->addr) { + if(!addr1 && !addr0 && dns->addr) { ai_family0 = dns->addr->ai_family; addr0 = addr_first_match(dns->addr, ai_family0); } @@ -932,8 +931,8 @@ static CURLcode cf_he_shutdown(struct Curl_cfilter *cf, } static void cf_he_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_he_ctx *ctx = cf->ctx; size_t i; @@ -993,11 +992,11 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf, struct ip_quadruple ipquad; int is_ipv6; if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) { - const char *host, *disphost; + const char *host; int port; - cf->next->cft->get_host(cf->next, data, &host, &disphost, &port); + Curl_conn_get_current_host(data, cf->sockindex, &host, &port); CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u", - disphost, ipquad.remote_ip, ipquad.remote_port); + host, ipquad.remote_ip, ipquad.remote_port); } } data->info.numconnects++; /* to track the # of connections made */ @@ -1046,8 +1045,8 @@ static bool cf_he_data_pending(struct Curl_cfilter *cf, } static struct curltime get_max_baller_time(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query) + struct Curl_easy *data, + int query) { struct cf_he_ctx *ctx = cf->ctx; struct curltime t, tmax; @@ -1134,7 +1133,6 @@ struct Curl_cftype Curl_cft_happy_eyeballs = { cf_he_connect, cf_he_close, cf_he_shutdown, - Curl_cf_def_get_host, cf_he_adjust_pollset, cf_he_data_pending, Curl_cf_def_send, @@ -1398,7 +1396,6 @@ struct Curl_cftype Curl_cft_setup = { cf_setup_connect, cf_setup_close, Curl_cf_def_shutdown, - Curl_cf_def_get_host, Curl_cf_def_adjust_pollset, Curl_cf_def_data_pending, Curl_cf_def_send, @@ -1518,7 +1515,8 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, /* Still no cfilter set, apply default. */ if(!conn->cfilter[sockindex]) { - result = cf_setup_add(data, conn, sockindex, conn->transport, ssl_mode); + result = cf_setup_add(data, conn, sockindex, + conn->transport_wanted, ssl_mode); if(result) goto out; } diff --git a/vendor/curl/lib/content_encoding.c b/vendor/curl/lib/content_encoding.c index f2e77eed..9ea4a047 100644 --- a/vendor/curl/lib/content_encoding.c +++ b/vendor/curl/lib/content_encoding.c @@ -52,7 +52,6 @@ #include "http.h" #include "content_encoding.h" #include "strdup.h" -#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -343,7 +342,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data, } static void gzip_do_close(struct Curl_easy *data, - struct Curl_cwriter *writer) + struct Curl_cwriter *writer) { struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ @@ -464,7 +463,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data, } static void brotli_do_close(struct Curl_easy *data, - struct Curl_cwriter *writer) + struct Curl_cwriter *writer) { struct brotli_writer *bp = (struct brotli_writer *) writer; (void) data; @@ -567,7 +566,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data, } static void zstd_do_close(struct Curl_easy *data, - struct Curl_cwriter *writer) + struct Curl_cwriter *writer) { struct zstd_writer *zp = (struct zstd_writer *) writer; (void)data; @@ -636,7 +635,7 @@ void Curl_all_content_encodings(char *buf, size_t blen) for(cep = general_unencoders; *cep; cep++) { ce = *cep; - if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) + if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) len += strlen(ce->name) + 2; } @@ -648,7 +647,7 @@ void Curl_all_content_encodings(char *buf, size_t blen) char *p = buf; for(cep = general_unencoders; *cep; cep++) { ce = *cep; - if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) { + if(!curl_strequal(ce->name, CONTENT_ENCODING_DEFAULT)) { strcpy(p, ce->name); p += strlen(p); *p++ = ','; @@ -688,7 +687,7 @@ static CURLcode error_do_write(struct Curl_easy *data, } static void error_do_close(struct Curl_easy *data, - struct Curl_cwriter *writer) + struct Curl_cwriter *writer) { (void) data; (void) writer; @@ -713,8 +712,8 @@ static const struct Curl_cwtype *find_unencode_writer(const char *name, if(phase == CURL_CW_TRANSFER_DECODE) { for(cep = transfer_unencoders; *cep; cep++) { const struct Curl_cwtype *ce = *cep; - if((strncasecompare(name, ce->name, len) && !ce->name[len]) || - (ce->alias && strncasecompare(name, ce->alias, len) + if((curl_strnequal(name, ce->name, len) && !ce->name[len]) || + (ce->alias && curl_strnequal(name, ce->alias, len) && !ce->alias[len])) return ce; } @@ -722,8 +721,8 @@ static const struct Curl_cwtype *find_unencode_writer(const char *name, /* look among the general decoders */ for(cep = general_unencoders; *cep; cep++) { const struct Curl_cwtype *ce = *cep; - if((strncasecompare(name, ce->name, len) && !ce->name[len]) || - (ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len])) + if((curl_strnequal(name, ce->name, len) && !ce->name[len]) || + (ce->alias && curl_strnequal(name, ce->alias, len) && !ce->alias[len])) return ce; } return NULL; @@ -761,12 +760,12 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, CURL_TRC_WRITE(data, "looking for %s decoder: %.*s", is_transfer ? "transfer" : "content", (int)namelen, name); is_chunked = (is_transfer && (namelen == 7) && - strncasecompare(name, "chunked", 7)); + curl_strnequal(name, "chunked", 7)); /* if we skip the decoding in this phase, do not look further. * Exception is "chunked" transfer-encoding which always must happen */ if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) || (!is_transfer && data->set.http_ce_skip)) { - bool is_identity = strncasecompare(name, "identity", 8); + bool is_identity = curl_strnequal(name, "identity", 8); /* not requested, ignore */ CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s", (int)namelen, name); diff --git a/vendor/curl/lib/cookie.c b/vendor/curl/lib/cookie.c index 1a8426ca..9221871e 100644 --- a/vendor/curl/lib/cookie.c +++ b/vendor/curl/lib/cookie.c @@ -135,9 +135,9 @@ static bool cookie_tailmatch(const char *cookie_domain, if(hostname_len < cookie_domain_len) return FALSE; - if(!strncasecompare(cookie_domain, - hostname + hostname_len-cookie_domain_len, - cookie_domain_len)) + if(!curl_strnequal(cookie_domain, + hostname + hostname_len-cookie_domain_len, + cookie_domain_len)) return FALSE; /* @@ -409,7 +409,7 @@ static void remove_expired(struct CookieInfo *ci) /* Make sure domain contains a dot or is localhost. */ static bool bad_domain(const char *domain, size_t len) { - if((len == 9) && strncasecompare(domain, "localhost", 9)) + if((len == 9) && curl_strnequal(domain, "localhost", 9)) return FALSE; else { /* there must be a dot present, but that dot must not be a trailing dot */ @@ -815,7 +815,7 @@ parse_netscape(struct Cookie *co, * domain can access the variable. Set TRUE when the cookie says * .example.com and to false when the domain is complete www.example.com */ - co->tailmatch = !!strncasecompare(ptr, "TRUE", len); + co->tailmatch = !!curl_strnequal(ptr, "TRUE", len); break; case 2: /* The file format allows the path field to remain not filled in */ @@ -842,7 +842,7 @@ parse_netscape(struct Cookie *co, FALLTHROUGH(); case 3: co->secure = FALSE; - if(strncasecompare(ptr, "TRUE", len)) { + if(curl_strnequal(ptr, "TRUE", len)) { if(secure || ci->running) co->secure = TRUE; else @@ -859,9 +859,9 @@ parse_netscape(struct Cookie *co, return CERR_OUT_OF_MEMORY; else { /* For Netscape file format cookies we check prefix on the name */ - if(strncasecompare("__Secure-", co->name, 9)) + if(curl_strnequal("__Secure-", co->name, 9)) co->prefix_secure = TRUE; - else if(strncasecompare("__Host-", co->name, 7)) + else if(curl_strnequal("__Host-", co->name, 7)) co->prefix_host = TRUE; } break; @@ -917,7 +917,7 @@ is_public_suffix(struct Curl_easy *data, Curl_psl_release(data); } else - infof(data, "libpsl problem, rejecting cookie for satety"); + infof(data, "libpsl problem, rejecting cookie for safety"); } if(!acceptable) { @@ -954,7 +954,7 @@ replace_existing(struct Curl_easy *data, bool matching_domains = FALSE; if(clist->domain && co->domain) { - if(strcasecompare(clist->domain, co->domain)) + if(curl_strequal(clist->domain, co->domain)) /* The domains are identical */ matching_domains = TRUE; } @@ -981,7 +981,7 @@ replace_existing(struct Curl_easy *data, else cllen = strlen(clist->spath); - if(strncasecompare(clist->spath, co->spath, cllen)) { + if(curl_strnequal(clist->spath, co->spath, cllen)) { infof(data, "cookie '%s' for domain '%s' dropped, would " "overlay an existing cookie", co->name, co->domain); return CERR_BAD_SECURE; @@ -993,7 +993,7 @@ replace_existing(struct Curl_easy *data, /* the names are identical */ if(clist->domain && co->domain) { - if(strcasecompare(clist->domain, co->domain) && + if(curl_strequal(clist->domain, co->domain) && (clist->tailmatch == co->tailmatch)) /* The domains are identical */ replace_old = TRUE; @@ -1005,7 +1005,7 @@ replace_existing(struct Curl_easy *data, /* the domains were identical */ if(clist->spath && co->spath && - !strcasecompare(clist->spath, co->spath)) + !curl_strequal(clist->spath, co->spath)) replace_old = FALSE; else if(!clist->spath != !co->spath) replace_old = FALSE; @@ -1337,7 +1337,7 @@ int Curl_cookie_getlist(struct Curl_easy *data, if(!co->domain || (co->tailmatch && !is_ip && cookie_tailmatch(co->domain, strlen(co->domain), host)) || - ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { + ((!co->tailmatch || is_ip) && curl_strequal(host, co->domain)) ) { /* * the right part of the host matches the domain stuff in the * cookie data diff --git a/vendor/curl/lib/cshutdn.c b/vendor/curl/lib/cshutdn.c index f05b87d2..c8b40dc3 100644 --- a/vendor/curl/lib/cshutdn.c +++ b/vendor/curl/lib/cshutdn.c @@ -40,7 +40,6 @@ #include "sigpipe.h" #include "connect.h" #include "select.h" -#include "strcase.h" #include "curlx/strparse.h" /* The last 3 #include files should be in this order */ @@ -54,12 +53,6 @@ static void cshutdn_run_conn_handler(struct Curl_easy *data, { if(!conn->bits.shutdown_handler) { - /* Cleanup NTLM connection-related data */ - Curl_http_auth_cleanup_ntlm(conn); - - /* Cleanup NEGOTIATE connection-related data */ - Curl_http_auth_cleanup_negotiate(conn); - if(conn->handler && conn->handler->disconnect) { /* Some disconnect handlers do a blocking wait on server responses. * FTP/IMAP/SMTP and SFTP are among them. When using the internal @@ -121,8 +114,8 @@ static void cshutdn_run_once(struct Curl_easy *data, } void Curl_cshutdn_run_once(struct Curl_easy *data, - struct connectdata *conn, - bool *done) + struct connectdata *conn, + bool *done) { DEBUGASSERT(!data->conn); Curl_attach_connection(data, conn); @@ -219,8 +212,8 @@ bool Curl_cshutdn_close_oldest(struct Curl_easy *data, #define NUM_POLLS_ON_STACK 10 static CURLcode cshutdn_wait(struct cshutdn *cshutdn, - struct Curl_easy *data, - int timeout_ms) + struct Curl_easy *data, + int timeout_ms) { struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; struct curl_pollfds cpfds; @@ -241,7 +234,7 @@ static CURLcode cshutdn_wait(struct cshutdn *cshutdn, static void cshutdn_perform(struct cshutdn *cshutdn, - struct Curl_easy *data) + struct Curl_easy *data) { struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list); struct Curl_llist_node *enext; @@ -402,8 +395,8 @@ size_t Curl_cshutdn_dest_count(struct Curl_easy *data, static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn, - struct Curl_easy *data, - struct connectdata *conn) + struct Curl_easy *data, + struct connectdata *conn) { CURLMcode mresult; @@ -418,8 +411,8 @@ static CURLMcode cshutdn_update_ev(struct cshutdn *cshutdn, void Curl_cshutdn_add(struct cshutdn *cshutdn, - struct connectdata *conn, - size_t conns_in_pool) + struct connectdata *conn, + size_t conns_in_pool) { struct Curl_easy *data = cshutdn->multi->admin; size_t max_total = (cshutdn->multi->max_total_connections > 0) ? @@ -451,8 +444,8 @@ void Curl_cshutdn_add(struct cshutdn *cshutdn, static void cshutdn_multi_socket(struct cshutdn *cshutdn, - struct Curl_easy *data, - curl_socket_t s) + struct Curl_easy *data, + curl_socket_t s) { struct Curl_llist_node *e; struct connectdata *conn; diff --git a/vendor/curl/lib/curl_addrinfo.c b/vendor/curl/lib/curl_addrinfo.c index ad1769fd..b131c747 100644 --- a/vendor/curl/lib/curl_addrinfo.c +++ b/vendor/curl/lib/curl_addrinfo.c @@ -218,7 +218,7 @@ Curl_getaddrinfo_ex(const char *nodename, * * This function returns a pointer to the first element of a newly allocated * Curl_addrinfo struct linked list filled with the data of a given hostent. - * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6 + * Curl_addrinfo is meant to work like the addrinfo struct does for an IPv6 * stack, but usable also for IPv4, all hosts and environments. * * The memory allocated by this function *MUST* be free'd later on calling @@ -468,7 +468,7 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, sa_un = (void *) ai->ai_addr; sa_un->sun_family = AF_UNIX; - /* sun_path must be able to store the NUL-terminated path */ + /* sun_path must be able to store the null-terminated path */ path_len = strlen(path) + 1; if(path_len > sizeof(sa_un->sun_path)) { free(ai); diff --git a/vendor/curl/lib/curl_des.c b/vendor/curl/lib/curl_des.c index 15836f58..a202dd3f 100644 --- a/vendor/curl/lib/curl_des.c +++ b/vendor/curl/lib/curl_des.c @@ -26,7 +26,6 @@ #if defined(USE_CURL_NTLM_CORE) && \ (defined(USE_GNUTLS) || \ - defined(USE_SECTRANSP) || \ defined(USE_OS400CRYPTO) || \ defined(USE_WIN32_CRYPTO)) diff --git a/vendor/curl/lib/curl_des.h b/vendor/curl/lib/curl_des.h index 2dd498da..c50aaf45 100644 --- a/vendor/curl/lib/curl_des.h +++ b/vendor/curl/lib/curl_des.h @@ -28,7 +28,6 @@ #if defined(USE_CURL_NTLM_CORE) && \ (defined(USE_GNUTLS) || \ - defined(USE_SECTRANSP) || \ defined(USE_OS400CRYPTO) || \ defined(USE_WIN32_CRYPTO)) diff --git a/vendor/curl/lib/curl_get_line.c b/vendor/curl/lib/curl_get_line.c index 2bb57492..4b1c6c3e 100644 --- a/vendor/curl/lib/curl_get_line.c +++ b/vendor/curl/lib/curl_get_line.c @@ -32,6 +32,15 @@ /* The last #include file should be: */ #include "memdebug.h" +static int appendnl(struct dynbuf *buf) +{ + CURLcode result = curlx_dyn_addn(buf, "\n", 1); + if(result) + /* too long line or out of memory */ + return 0; /* error */ + return 1; /* all good */ +} + /* * Curl_get_line() makes sure to only return complete whole lines that end * newlines. @@ -43,9 +52,10 @@ int Curl_get_line(struct dynbuf *buf, FILE *input) curlx_dyn_reset(buf); while(1) { char *b = fgets(buffer, sizeof(buffer), input); + size_t rlen; if(b) { - size_t rlen = strlen(b); + rlen = strlen(b); if(!rlen) break; @@ -59,19 +69,24 @@ int Curl_get_line(struct dynbuf *buf, FILE *input) /* end of the line */ return 1; /* all good */ - else if(feof(input)) { + else if(feof(input)) /* append a newline */ - result = curlx_dyn_addn(buf, "\n", 1); - if(result) - /* too long line or out of memory */ - return 0; /* error */ + return appendnl(buf); + } + else { + rlen = curlx_dyn_len(buf); + if(rlen) { + b = curlx_dyn_ptr(buf); + + if(b[rlen-1] != '\n') + /* append a newline */ + return appendnl(buf); + return 1; /* all good */ } + else + break; } - else if(curlx_dyn_len(buf)) - return 1; /* all good */ - else - break; } return 0; } diff --git a/vendor/curl/lib/curl_gssapi.c b/vendor/curl/lib/curl_gssapi.c index f83701ad..46902180 100644 --- a/vendor/curl/lib/curl_gssapi.c +++ b/vendor/curl/lib/curl_gssapi.c @@ -52,17 +52,260 @@ gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = { 9, CURL_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02") }; -OM_uint32 Curl_gss_init_sec_context( - struct Curl_easy *data, - OM_uint32 *minor_status, - gss_ctx_id_t *context, - gss_name_t target_name, - gss_OID mech_type, - gss_channel_bindings_t input_chan_bindings, - gss_buffer_t input_token, - gss_buffer_t output_token, - const bool mutual_auth, - OM_uint32 *ret_flags) +#ifdef DEBUGBUILD +enum min_err_code { + STUB_GSS_OK = 0, + STUB_GSS_NO_MEMORY, + STUB_GSS_INVALID_ARGS, + STUB_GSS_INVALID_CREDS, + STUB_GSS_INVALID_CTX, + STUB_GSS_SERVER_ERR, + STUB_GSS_NO_MECH, + STUB_GSS_LAST +}; + +/* libcurl is also passing this struct to these functions, which are not yet + * stubbed: + * gss_inquire_context() + * gss_unwrap() + * gss_wrap() + */ +struct stub_gss_ctx_id_t_desc { + enum { STUB_GSS_NONE, STUB_GSS_KRB5, STUB_GSS_NTLM1, STUB_GSS_NTLM3 } sent; + int have_krb5; + int have_ntlm; + OM_uint32 flags; + char creds[250]; +}; + +static OM_uint32 +stub_gss_init_sec_context(OM_uint32 *min, + gss_cred_id_t initiator_cred_handle, + struct stub_gss_ctx_id_t_desc **context, + gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + gss_buffer_desc *input_token, + gss_OID *actual_mech_type, + gss_buffer_desc *output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + struct stub_gss_ctx_id_t_desc *ctx = NULL; + + /* The token will be encoded in base64 */ + size_t length = sizeof(ctx->creds) * 3 / 4; + size_t used = 0; + char *token = NULL; + const char *creds = NULL; + + (void)initiator_cred_handle; + (void)mech_type; + (void)time_req; + (void)input_chan_bindings; + (void)actual_mech_type; + + if(!min) + return GSS_S_FAILURE; + + *min = 0; + + if(!context || !target_name || !output_token) { + *min = STUB_GSS_INVALID_ARGS; + return GSS_S_FAILURE; + } + + creds = getenv("CURL_STUB_GSS_CREDS"); + if(!creds || strlen(creds) >= sizeof(ctx->creds)) { + *min = STUB_GSS_INVALID_CREDS; + return GSS_S_FAILURE; + } + + ctx = *context; + if(ctx && strcmp(ctx->creds, creds)) { + *min = STUB_GSS_INVALID_CREDS; + return GSS_S_FAILURE; + } + + output_token->length = 0; + output_token->value = NULL; + + if(input_token && input_token->length) { + if(!ctx) { + *min = STUB_GSS_INVALID_CTX; + return GSS_S_FAILURE; + } + + /* Server response, either D (RA==) or C (Qw==) */ + if(((char *) input_token->value)[0] == 'D') { + /* Done */ + switch(ctx->sent) { + case STUB_GSS_KRB5: + case STUB_GSS_NTLM3: + if(ret_flags) + *ret_flags = ctx->flags; + if(time_rec) + *time_rec = GSS_C_INDEFINITE; + return GSS_S_COMPLETE; + default: + *min = STUB_GSS_SERVER_ERR; + return GSS_S_FAILURE; + } + } + + if(((char *) input_token->value)[0] != 'C') { + /* We only support Done or Continue */ + *min = STUB_GSS_SERVER_ERR; + return GSS_S_FAILURE; + } + + /* Continue */ + switch(ctx->sent) { + case STUB_GSS_KRB5: + /* We sent KRB5 and it failed, let's try NTLM */ + if(ctx->have_ntlm) { + ctx->sent = STUB_GSS_NTLM1; + break; + } + else { + *min = STUB_GSS_SERVER_ERR; + return GSS_S_FAILURE; + } + case STUB_GSS_NTLM1: + ctx->sent = STUB_GSS_NTLM3; + break; + default: + *min = STUB_GSS_SERVER_ERR; + return GSS_S_FAILURE; + } + } + else { + if(ctx) { + *min = STUB_GSS_INVALID_CTX; + return GSS_S_FAILURE; + } + + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + *min = STUB_GSS_NO_MEMORY; + return GSS_S_FAILURE; + } + + if(strstr(creds, "KRB5")) + ctx->have_krb5 = 1; + + if(strstr(creds, "NTLM")) + ctx->have_ntlm = 1; + + if(ctx->have_krb5) + ctx->sent = STUB_GSS_KRB5; + else if(ctx->have_ntlm) + ctx->sent = STUB_GSS_NTLM1; + else { + free(ctx); + *min = STUB_GSS_NO_MECH; + return GSS_S_FAILURE; + } + + strcpy(ctx->creds, creds); + ctx->flags = req_flags; + } + + /* To avoid memdebug macro replacement, wrap the name in parentheses to call + the original version. It is freed via the GSS API gss_release_buffer(). */ + token = (malloc)(length); + if(!token) { + free(ctx); + *min = STUB_GSS_NO_MEMORY; + return GSS_S_FAILURE; + } + + { + gss_buffer_desc target_desc; + gss_OID name_type = GSS_C_NO_OID; + OM_uint32 minor_status; + OM_uint32 major_status; + major_status = gss_display_name(&minor_status, target_name, + &target_desc, &name_type); + if(GSS_ERROR(major_status)) { + (free)(token); + free(ctx); + *min = STUB_GSS_NO_MEMORY; + return GSS_S_FAILURE; + } + + if(strlen(creds) + target_desc.length + 5 >= sizeof(ctx->creds)) { + (free)(token); + free(ctx); + *min = STUB_GSS_NO_MEMORY; + return GSS_S_FAILURE; + } + + /* Token format: creds:target:type:padding */ + used = msnprintf(token, length, "%s:%.*s:%d:", creds, + (int)target_desc.length, (const char *)target_desc.value, + ctx->sent); + + gss_release_buffer(&minor_status, &target_desc); + } + + if(used >= length) { + (free)(token); + free(ctx); + *min = STUB_GSS_NO_MEMORY; + return GSS_S_FAILURE; + } + + /* Overwrite null-terminator */ + memset(token + used, 'A', length - used); + + *context = ctx; + + output_token->value = token; + output_token->length = length; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +stub_gss_delete_sec_context(OM_uint32 *min, + struct stub_gss_ctx_id_t_desc **context, + gss_buffer_t output_token) +{ + (void)output_token; + + if(!min) + return GSS_S_FAILURE; + + if(!context) { + *min = STUB_GSS_INVALID_CTX; + return GSS_S_FAILURE; + } + if(!*context) { + *min = STUB_GSS_INVALID_CTX; + return GSS_S_FAILURE; + } + + free(*context); + *context = NULL; + *min = 0; + + return GSS_S_COMPLETE; +} +#endif /* DEBUGBUILD */ + +OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, + OM_uint32 *minor_status, + gss_ctx_id_t *context, + gss_name_t target_name, + gss_OID mech_type, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + const bool mutual_auth, + OM_uint32 *ret_flags) { OM_uint32 req_flags = GSS_C_REPLAY_FLAG; @@ -74,13 +317,30 @@ OM_uint32 Curl_gss_init_sec_context( req_flags |= GSS_C_DELEG_POLICY_FLAG; #else infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " - "compiled in"); + "compiled in"); #endif } if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) req_flags |= GSS_C_DELEG_FLAG; +#ifdef DEBUGBUILD + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_init_sec_context(minor_status, + GSS_C_NO_CREDENTIAL, /* cred_handle */ + (struct stub_gss_ctx_id_t_desc **)context, + target_name, + mech_type, + req_flags, + 0, /* time_req */ + input_chan_bindings, + input_token, + NULL, /* actual_mech_type */ + output_token, + ret_flags, + NULL /* time_rec */); +#endif /* DEBUGBUILD */ + return gss_init_sec_context(minor_status, GSS_C_NO_CREDENTIAL, /* cred_handle */ context, @@ -96,6 +356,20 @@ OM_uint32 Curl_gss_init_sec_context( NULL /* time_rec */); } +OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, + gss_ctx_id_t *context, + gss_buffer_t output_token) +{ +#ifdef DEBUGBUILD + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_delete_sec_context(min, + (struct stub_gss_ctx_id_t_desc **)context, + output_token); +#endif /* DEBUGBUILD */ + + return gss_delete_sec_context(min, context, output_token); +} + #define GSS_LOG_BUFFER_LEN 1024 static size_t display_gss_error(OM_uint32 status, int type, char *buf, size_t len) { diff --git a/vendor/curl/lib/curl_gssapi.h b/vendor/curl/lib/curl_gssapi.h index 7b9a534e..2659f234 100644 --- a/vendor/curl/lib/curl_gssapi.h +++ b/vendor/curl/lib/curl_gssapi.h @@ -32,17 +32,20 @@ extern gss_OID_desc Curl_spnego_mech_oid; extern gss_OID_desc Curl_krb5_mech_oid; /* Common method for using GSS-API */ -OM_uint32 Curl_gss_init_sec_context( - struct Curl_easy *data, - OM_uint32 *minor_status, - gss_ctx_id_t *context, - gss_name_t target_name, - gss_OID mech_type, - gss_channel_bindings_t input_chan_bindings, - gss_buffer_t input_token, - gss_buffer_t output_token, - const bool mutual_auth, - OM_uint32 *ret_flags); +OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, + OM_uint32 *minor_status, + gss_ctx_id_t *context, + gss_name_t target_name, + gss_OID mech_type, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + const bool mutual_auth, + OM_uint32 *ret_flags); + +OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, + gss_ctx_id_t *context_handle, + gss_buffer_t output_token); /* Helper to log a GSS-API error status */ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, diff --git a/vendor/curl/lib/curl_memory.h b/vendor/curl/lib/curl_memory.h index bc3e944f..b4536c1b 100644 --- a/vendor/curl/lib/curl_memory.h +++ b/vendor/curl/lib/curl_memory.h @@ -57,7 +57,6 @@ #ifdef HEADER_CURL_MEMDEBUG_H /* cleanup after memdebug.h */ -#ifdef MEMDEBUG_NODEFINES #ifdef CURLDEBUG #undef strdup @@ -69,28 +68,28 @@ #undef recv #ifdef _WIN32 -# ifdef UNICODE -# undef wcsdup -# undef _wcsdup -# undef _tcsdup -# else -# undef _tcsdup -# endif +#undef _tcsdup #endif #undef socket #undef accept +#ifdef HAVE_ACCEPT4 +#undef accept4 +#endif #ifdef HAVE_SOCKETPAIR #undef socketpair #endif /* sclose is probably already defined, redefine it! */ #undef sclose +#define sclose(x) CURL_SCLOSE(x) #undef fopen +#ifdef CURL_FOPEN +#define fopen(fname, mode) CURL_FOPEN(fname, mode) +#endif #undef fdopen #undef fclose -#endif /* MEMDEBUG_NODEFINES */ #endif /* CURLDEBUG */ #undef HEADER_CURL_MEMDEBUG_H @@ -122,9 +121,6 @@ extern curl_free_callback Curl_cfree; extern curl_realloc_callback Curl_crealloc; extern curl_strdup_callback Curl_cstrdup; extern curl_calloc_callback Curl_ccalloc; -#if defined(_WIN32) && defined(UNICODE) -extern curl_wcsdup_callback Curl_cwcsdup; -#endif #ifndef CURLDEBUG @@ -149,18 +145,13 @@ extern curl_wcsdup_callback Curl_cwcsdup; #define free(ptr) Curl_cfree(ptr) #ifdef _WIN32 -# ifdef UNICODE -# undef wcsdup -# define wcsdup(ptr) Curl_cwcsdup(ptr) -# undef _wcsdup -# define _wcsdup(ptr) Curl_cwcsdup(ptr) -# undef _tcsdup -# define _tcsdup(ptr) Curl_cwcsdup(ptr) -# else -# undef _tcsdup -# define _tcsdup(ptr) Curl_cstrdup(ptr) -# endif +#undef _tcsdup +#ifdef UNICODE +#define _tcsdup(ptr) Curl_wcsdup(ptr) +#else +#define _tcsdup(ptr) Curl_cstrdup(ptr) #endif +#endif /* _WIN32 */ #endif /* CURLDEBUG */ #endif /* HEADER_CURL_MEMORY_H */ diff --git a/vendor/curl/lib/curl_ntlm_core.c b/vendor/curl/lib/curl_ntlm_core.c index d6cd44d9..c3595317 100644 --- a/vendor/curl/lib/curl_ntlm_core.c +++ b/vendor/curl/lib/curl_ntlm_core.c @@ -40,9 +40,8 @@ 3. USE_GNUTLS 4. - 5. USE_MBEDTLS - 6. USE_SECTRANSP - 7. USE_OS400CRYPTO - 8. USE_WIN32_CRYPTO + 6. USE_OS400CRYPTO + 7. USE_WIN32_CRYPTO This ensures that: - the same SSL branch gets activated throughout this source @@ -107,11 +106,6 @@ # include -#elif defined(USE_SECTRANSP) - -# include -# include - #elif defined(USE_OS400CRYPTO) # include "cipher.mih" /* mih/cipher */ #elif defined(USE_WIN32_CRYPTO) @@ -209,29 +203,6 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; } -#elif defined(USE_SECTRANSP) - -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - char key[8]; - size_t out_len; - CCCryptorStatus err; - - /* Expand the 56-bit key to 64 bits */ - extend_key_56_to_64(key_56, key); - - /* Set the key parity to odd */ - Curl_des_set_odd_parity((unsigned char *) key, sizeof(key)); - - /* Perform the encryption */ - err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key, - kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out, - 8 /* outbuflen */, &out_len); - - return err == kCCSuccess; -} - #elif defined(USE_OS400CRYPTO) static bool encrypt_des(const unsigned char *in, unsigned char *out, @@ -339,8 +310,8 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, des_encrypt(&des, 8, results + 8, plaintext); setup_des_key(keys + 14, &des); des_encrypt(&des, 8, results + 16, plaintext); -#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \ - || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_OS400CRYPTO) || \ + defined(USE_WIN32_CRYPTO) encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results + 8, keys + 7); encrypt_des(plaintext, results + 16, keys + 14); @@ -387,8 +358,8 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password, des_encrypt(&des, 8, lmbuffer, magic); setup_des_key(pw + 7, &des); des_encrypt(&des, 8, lmbuffer + 8, magic); -#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \ - || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_OS400CRYPTO) || \ + defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); #endif @@ -466,7 +437,7 @@ struct ms_filetime { static void time2filetime(struct ms_filetime *ft, time_t t) { #if SIZEOF_TIME_T > 4 - t = (t + CURL_OFF_T_C(11644473600)) * 10000000; + t = (t + (curl_off_t)11644473600) * 10000000; ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF); ft->dwHighDateTime = (unsigned int) (t >> 32); #else diff --git a/vendor/curl/lib/curl_ntlm_core.h b/vendor/curl/lib/curl_ntlm_core.h index e2e4b1bd..7571ad54 100644 --- a/vendor/curl/lib/curl_ntlm_core.h +++ b/vendor/curl/lib/curl_ntlm_core.h @@ -28,6 +28,10 @@ #if defined(USE_CURL_NTLM_CORE) +#include "vauth/vauth.h" + +struct ntlmdata; + /* Helpers to generate function byte arguments in little endian order */ #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)) #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \ diff --git a/vendor/curl/lib/curl_rtmp.c b/vendor/curl/lib/curl_rtmp.c index 62632c1e..0be1f7c7 100644 --- a/vendor/curl/lib/curl_rtmp.c +++ b/vendor/curl/lib/curl_rtmp.c @@ -326,51 +326,54 @@ static CURLcode rtmp_disconnect(struct Curl_easy *data, return CURLE_OK; } -static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf, - size_t len, CURLcode *err) +static CURLcode rtmp_recv(struct Curl_easy *data, int sockindex, char *buf, + size_t len, size_t *pnread) { struct connectdata *conn = data->conn; RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN); + CURLcode result = CURLE_OK; ssize_t nread; (void)sockindex; /* unused */ - if(!r) { - *err = CURLE_FAILED_INIT; - return -1; - } + *pnread = 0; + if(!r) + return CURLE_FAILED_INIT; nread = RTMP_Read(r, buf, curlx_uztosi(len)); if(nread < 0) { if(r->m_read.status == RTMP_READ_COMPLETE || r->m_read.status == RTMP_READ_EOF) { data->req.size = data->req.bytecount; - nread = 0; } else - *err = CURLE_RECV_ERROR; + result = CURLE_RECV_ERROR; } - return nread; + else + *pnread = (size_t)nread; + + return result; } -static ssize_t rtmp_send(struct Curl_easy *data, int sockindex, - const void *buf, size_t len, bool eos, CURLcode *err) +static CURLcode rtmp_send(struct Curl_easy *data, int sockindex, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct connectdata *conn = data->conn; RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN); - ssize_t num; + ssize_t nwritten; (void)sockindex; /* unused */ (void)eos; /* unused */ - if(!r) { - *err = CURLE_FAILED_INIT; - return -1; - } + *pnwritten = 0; + if(!r) + return CURLE_FAILED_INIT; - num = RTMP_Write(r, (const char *)buf, curlx_uztosi(len)); - if(num < 0) - *err = CURLE_SEND_ERROR; + nwritten = RTMP_Write(r, (const char *)buf, curlx_uztosi(len)); + if(nwritten < 0) + return CURLE_SEND_ERROR; - return num; + *pnwritten = (size_t)nwritten; + return CURLE_OK; } void Curl_rtmp_version(char *version, size_t len) diff --git a/vendor/curl/lib/curl_sasl.c b/vendor/curl/lib/curl_sasl.c index 4fcbaac2..766de44b 100644 --- a/vendor/curl/lib/curl_sasl.c +++ b/vendor/curl/lib/curl_sasl.c @@ -76,44 +76,6 @@ static const struct { { ZERO_NULL, 0, 0 } }; -/* - * Curl_sasl_cleanup() - * - * This is used to cleanup any libraries or curl modules used by the sasl - * functions. - * - * Parameters: - * - * conn [in] - The connection data. - * authused [in] - The authentication mechanism used. - */ -void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused) -{ - (void)conn; - (void)authused; - -#if defined(USE_KERBEROS5) - /* Cleanup the gssapi structure */ - if(authused == SASL_MECH_GSSAPI) { - Curl_auth_cleanup_gssapi(&conn->krb5); - } -#endif - -#if defined(USE_GSASL) - /* Cleanup the GSASL structure */ - if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) { - Curl_auth_gsasl_cleanup(&conn->gsasl); - } -#endif - -#if defined(USE_NTLM) - /* Cleanup the NTLM structure */ - if(authused == SASL_MECH_NTLM) { - Curl_auth_cleanup_ntlm(&conn->ntlm); - } -#endif -} - /* * Curl_sasl_decode_mech() * @@ -334,6 +296,241 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data) return FALSE; } +struct sasl_ctx { + struct SASL *sasl; + struct connectdata *conn; + const char *user; + unsigned short enabledmechs; + const char *mech; + saslstate state1; + saslstate state2; + struct bufref resp; + CURLcode result; +}; + +static bool sasl_choose_external(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + if((sctx->enabledmechs & SASL_MECH_EXTERNAL) && !sctx->conn->passwd[0]) { + sctx->mech = SASL_MECH_STRING_EXTERNAL; + sctx->state1 = SASL_EXTERNAL; + sctx->sasl->authused = SASL_MECH_EXTERNAL; + + if(sctx->sasl->force_ir || data->set.sasl_ir) + Curl_auth_create_external_message(sctx->conn->user, &sctx->resp); + return TRUE; + } + return FALSE; +} + +#ifdef USE_KERBEROS5 +static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + if(sctx->user && + (sctx->enabledmechs & SASL_MECH_GSSAPI) && + Curl_auth_is_gssapi_supported() && + Curl_auth_user_contains_domain(sctx->conn->user)) { + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sctx->sasl->params->service; + + sctx->sasl->mutual_auth = FALSE; + sctx->mech = SASL_MECH_STRING_GSSAPI; + sctx->state1 = SASL_GSSAPI; + sctx->state2 = SASL_GSSAPI_TOKEN; + sctx->sasl->authused = SASL_MECH_GSSAPI; + + if(sctx->sasl->force_ir || data->set.sasl_ir) { + struct kerberos5data *krb5 = Curl_auth_krb5_get(sctx->conn); + sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY : + Curl_auth_create_gssapi_user_message(data, sctx->conn->user, + sctx->conn->passwd, + service, sctx->conn->host.name, + sctx->sasl->mutual_auth, NULL, + krb5, &sctx->resp); + } + return TRUE; + } + return FALSE; +} +#endif /* USE_KERBEROS5 */ + +#ifdef USE_GSASL +static bool sasl_choose_gsasl(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + struct gsasldata *gsasl; + struct bufref nullmsg; + + if(sctx->user && + (sctx->enabledmechs & (SASL_MECH_SCRAM_SHA_256|SASL_MECH_SCRAM_SHA_1))) { + gsasl = Curl_auth_gsasl_get(sctx->conn); + if(!gsasl) { + sctx->result = CURLE_OUT_OF_MEMORY; + return TRUE; /* attempted, but failed */ + } + + if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_256) && + Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256, + gsasl)) { + sctx->mech = SASL_MECH_STRING_SCRAM_SHA_256; + sctx->sasl->authused = SASL_MECH_SCRAM_SHA_256; + } + else if((sctx->enabledmechs & SASL_MECH_SCRAM_SHA_1) && + Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1, + gsasl)) { + sctx->mech = SASL_MECH_STRING_SCRAM_SHA_1; + sctx->sasl->authused = SASL_MECH_SCRAM_SHA_1; + } + else + return FALSE; + + Curl_bufref_init(&nullmsg); + sctx->state1 = SASL_GSASL; + sctx->state2 = SASL_GSASL; + sctx->result = Curl_auth_gsasl_start(data, sctx->conn->user, + sctx->conn->passwd, gsasl); + if(!sctx->result && (sctx->sasl->force_ir || data->set.sasl_ir)) + sctx->result = Curl_auth_gsasl_token(data, &nullmsg, gsasl, &sctx->resp); + return TRUE; + } + return FALSE; +} + +#endif /* USE_GSASL */ + +#ifndef CURL_DISABLE_DIGEST_AUTH +static bool sasl_choose_digest(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + (void)data; + if(!sctx->user) + return FALSE; + else if((sctx->enabledmechs & SASL_MECH_DIGEST_MD5) && + Curl_auth_is_digest_supported()) { + sctx->mech = SASL_MECH_STRING_DIGEST_MD5; + sctx->state1 = SASL_DIGESTMD5; + sctx->sasl->authused = SASL_MECH_DIGEST_MD5; + return TRUE; + } + else if(sctx->enabledmechs & SASL_MECH_CRAM_MD5) { + sctx->mech = SASL_MECH_STRING_CRAM_MD5; + sctx->state1 = SASL_CRAMMD5; + sctx->sasl->authused = SASL_MECH_CRAM_MD5; + return TRUE; + } + return FALSE; +} +#endif /* !CURL_DISABLE_DIGEST_AUTH */ + +#ifdef USE_NTLM +static bool sasl_choose_ntlm(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + if(!sctx->user) + return FALSE; + else if((sctx->enabledmechs & SASL_MECH_NTLM) && + Curl_auth_is_ntlm_supported()) { + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sctx->sasl->params->service; + const char *hostname; + int port; + + Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port); + + sctx->mech = SASL_MECH_STRING_NTLM; + sctx->state1 = SASL_NTLM; + sctx->state2 = SASL_NTLM_TYPE2MSG; + sctx->sasl->authused = SASL_MECH_NTLM; + + if(sctx->sasl->force_ir || data->set.sasl_ir) { + struct ntlmdata *ntlm = Curl_auth_ntlm_get(sctx->conn, FALSE); + sctx->result = !ntlm ? CURLE_OUT_OF_MEMORY : + Curl_auth_create_ntlm_type1_message(data, + sctx->conn->user, + sctx->conn->passwd, + service, hostname, + ntlm, &sctx->resp); + } + return TRUE; + } + return FALSE; +} +#endif /* USE_NTLM */ + +static bool sasl_choose_oauth(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + const char *oauth_bearer = data->set.str[STRING_BEARER]; + + if(sctx->user && oauth_bearer && + (sctx->enabledmechs & SASL_MECH_OAUTHBEARER)) { + const char *hostname; + int port; + Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port); + + sctx->mech = SASL_MECH_STRING_OAUTHBEARER; + sctx->state1 = SASL_OAUTH2; + sctx->state2 = SASL_OAUTH2_RESP; + sctx->sasl->authused = SASL_MECH_OAUTHBEARER; + + if(sctx->sasl->force_ir || data->set.sasl_ir) + sctx->result = + Curl_auth_create_oauth_bearer_message(sctx->conn->user, + hostname, port, + oauth_bearer, &sctx->resp); + return TRUE; + } + return FALSE; +} + +static bool sasl_choose_oauth2(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + const char *oauth_bearer = data->set.str[STRING_BEARER]; + + if(sctx->user && oauth_bearer && + (sctx->enabledmechs & SASL_MECH_XOAUTH2)) { + sctx->mech = SASL_MECH_STRING_XOAUTH2; + sctx->state1 = SASL_OAUTH2; + sctx->sasl->authused = SASL_MECH_XOAUTH2; + + if(sctx->sasl->force_ir || data->set.sasl_ir) + sctx->result = Curl_auth_create_xoauth_bearer_message(sctx->conn->user, + oauth_bearer, + &sctx->resp); + return TRUE; + } + return FALSE; +} + +static bool sasl_choose_plain(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + if(sctx->user && (sctx->enabledmechs & SASL_MECH_PLAIN)) { + sctx->mech = SASL_MECH_STRING_PLAIN; + sctx->state1 = SASL_PLAIN; + sctx->sasl->authused = SASL_MECH_PLAIN; + + if(sctx->sasl->force_ir || data->set.sasl_ir) + sctx->result = + Curl_auth_create_plain_message(sctx->conn->sasl_authzid, + sctx->conn->user, sctx->conn->passwd, + &sctx->resp); + return TRUE; + } + return FALSE; +} + +static bool sasl_choose_login(struct Curl_easy *data, struct sasl_ctx *sctx) +{ + if(sctx->user && (sctx->enabledmechs & SASL_MECH_LOGIN)) { + sctx->mech = SASL_MECH_STRING_LOGIN; + sctx->state1 = SASL_LOGIN; + sctx->state2 = SASL_LOGIN_PASSWD; + sctx->sasl->authused = SASL_MECH_LOGIN; + + if(sctx->sasl->force_ir || data->set.sasl_ir) + Curl_auth_create_login_message(sctx->conn->user, &sctx->resp); + return TRUE; + } + return FALSE; +} + /* * Curl_sasl_start() * @@ -342,185 +539,66 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data) CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, bool force_ir, saslprogress *progress) { - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - unsigned short enabledmechs; - const char *mech = NULL; - struct bufref resp; - saslstate state1 = SASL_STOP; - saslstate state2 = SASL_FINAL; - const char *hostname, *disp_hostname; - int port; -#if defined(USE_KERBEROS5) || defined(USE_NTLM) - const char *service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - sasl->params->service; -#endif - const char *oauth_bearer = data->set.str[STRING_BEARER]; - struct bufref nullmsg; + struct sasl_ctx sctx; - Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port); - Curl_bufref_init(&nullmsg); - Curl_bufref_init(&resp); sasl->force_ir = force_ir; /* Latch for future use */ sasl->authused = 0; /* No mechanism used yet */ - enabledmechs = sasl->authmechs & sasl->prefmech; *progress = SASL_IDLE; + memset(&sctx, 0, sizeof(sctx)); + sctx.sasl = sasl; + sctx.conn = data->conn; + sctx.user = data->state.aptr.user; + Curl_bufref_init(&sctx.resp); + sctx.enabledmechs = sasl->authmechs & sasl->prefmech; + sctx.state1 = SASL_STOP; + sctx.state2 = SASL_FINAL; + /* Calculate the supported authentication mechanism, by decreasing order of security, as well as the initial response where appropriate */ - if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) { - mech = SASL_MECH_STRING_EXTERNAL; - state1 = SASL_EXTERNAL; - sasl->authused = SASL_MECH_EXTERNAL; - - if(force_ir || data->set.sasl_ir) - Curl_auth_create_external_message(conn->user, &resp); - } - else if(data->state.aptr.user) { + if(sasl_choose_external(data, &sctx) || #if defined(USE_KERBEROS5) - if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && - Curl_auth_user_contains_domain(conn->user)) { - sasl->mutual_auth = FALSE; - mech = SASL_MECH_STRING_GSSAPI; - state1 = SASL_GSSAPI; - state2 = SASL_GSSAPI_TOKEN; - sasl->authused = SASL_MECH_GSSAPI; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_gssapi_user_message(data, conn->user, - conn->passwd, - service, - conn->host.name, - sasl->mutual_auth, - NULL, &conn->krb5, - &resp); - } - else + sasl_choose_krb5(data, &sctx) || #endif #ifdef USE_GSASL - if((enabledmechs & SASL_MECH_SCRAM_SHA_256) && - Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256, - &conn->gsasl)) { - mech = SASL_MECH_STRING_SCRAM_SHA_256; - sasl->authused = SASL_MECH_SCRAM_SHA_256; - state1 = SASL_GSASL; - state2 = SASL_GSASL; - - result = Curl_auth_gsasl_start(data, conn->user, - conn->passwd, &conn->gsasl); - if(result == CURLE_OK && (force_ir || data->set.sasl_ir)) - result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp); - } - else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) && - Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1, - &conn->gsasl)) { - mech = SASL_MECH_STRING_SCRAM_SHA_1; - sasl->authused = SASL_MECH_SCRAM_SHA_1; - state1 = SASL_GSASL; - state2 = SASL_GSASL; - - result = Curl_auth_gsasl_start(data, conn->user, - conn->passwd, &conn->gsasl); - if(result == CURLE_OK && (force_ir || data->set.sasl_ir)) - result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp); - } - else + sasl_choose_gsasl(data, &sctx) || #endif #ifndef CURL_DISABLE_DIGEST_AUTH - if((enabledmechs & SASL_MECH_DIGEST_MD5) && - Curl_auth_is_digest_supported()) { - mech = SASL_MECH_STRING_DIGEST_MD5; - state1 = SASL_DIGESTMD5; - sasl->authused = SASL_MECH_DIGEST_MD5; - } - else if(enabledmechs & SASL_MECH_CRAM_MD5) { - mech = SASL_MECH_STRING_CRAM_MD5; - state1 = SASL_CRAMMD5; - sasl->authused = SASL_MECH_CRAM_MD5; - } - else + sasl_choose_digest(data, &sctx) || #endif #ifdef USE_NTLM - if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { - mech = SASL_MECH_STRING_NTLM; - state1 = SASL_NTLM; - state2 = SASL_NTLM_TYPE2MSG; - sasl->authused = SASL_MECH_NTLM; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_ntlm_type1_message(data, - conn->user, conn->passwd, - service, - hostname, - &conn->ntlm, &resp); - } - else + sasl_choose_ntlm(data, &sctx) || #endif - if((enabledmechs & SASL_MECH_OAUTHBEARER) && oauth_bearer) { - mech = SASL_MECH_STRING_OAUTHBEARER; - state1 = SASL_OAUTH2; - state2 = SASL_OAUTH2_RESP; - sasl->authused = SASL_MECH_OAUTHBEARER; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_oauth_bearer_message(conn->user, - hostname, - port, - oauth_bearer, - &resp); - } - else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) { - mech = SASL_MECH_STRING_XOAUTH2; - state1 = SASL_OAUTH2; - sasl->authused = SASL_MECH_XOAUTH2; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_xoauth_bearer_message(conn->user, - oauth_bearer, - &resp); - } - else if(enabledmechs & SASL_MECH_PLAIN) { - mech = SASL_MECH_STRING_PLAIN; - state1 = SASL_PLAIN; - sasl->authused = SASL_MECH_PLAIN; - - if(force_ir || data->set.sasl_ir) - result = Curl_auth_create_plain_message(conn->sasl_authzid, - conn->user, conn->passwd, - &resp); - } - else if(enabledmechs & SASL_MECH_LOGIN) { - mech = SASL_MECH_STRING_LOGIN; - state1 = SASL_LOGIN; - state2 = SASL_LOGIN_PASSWD; - sasl->authused = SASL_MECH_LOGIN; - - if(force_ir || data->set.sasl_ir) - Curl_auth_create_login_message(conn->user, &resp); - } + sasl_choose_oauth(data, &sctx) || + sasl_choose_oauth2(data, &sctx) || + sasl_choose_plain(data, &sctx) || + sasl_choose_login(data, &sctx)) { + /* selected, either we have a mechanism or a failure */ + DEBUGASSERT(sctx.mech || sctx.result); } - if(!result && mech) { - sasl->curmech = mech; - if(Curl_bufref_ptr(&resp)) - result = build_message(sasl, &resp); + if(!sctx.result && sctx.mech) { + sasl->curmech = sctx.mech; + if(Curl_bufref_ptr(&sctx.resp)) + sctx.result = build_message(sasl, &sctx.resp); if(sasl->params->maxirlen && - strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen) - Curl_bufref_free(&resp); + strlen(sctx.mech) + Curl_bufref_len(&sctx.resp) > + sasl->params->maxirlen) + Curl_bufref_free(&sctx.resp); - if(!result) - result = sasl->params->sendauth(data, mech, &resp); + if(!sctx.result) + sctx.result = sasl->params->sendauth(data, sctx.mech, &sctx.resp); - if(!result) { + if(!sctx.result) { *progress = SASL_INPROGRESS; - sasl_state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1); + sasl_state(sasl, data, Curl_bufref_ptr(&sctx.resp) ? + sctx.state2 : sctx.state1); } } - Curl_bufref_free(&resp); - return result; + Curl_bufref_free(&sctx.resp); + return sctx.result; } /* @@ -535,7 +613,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, struct connectdata *conn = data->conn; saslstate newstate = SASL_FINAL; struct bufref resp; - const char *hostname, *disp_hostname; + const char *hostname; int port; #if defined(USE_KERBEROS5) || defined(USE_NTLM) \ || !defined(CURL_DISABLE_DIGEST_AUTH) @@ -546,7 +624,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, const char *oauth_bearer = data->set.str[STRING_BEARER]; struct bufref serverdata; - Curl_conn_get_host(data, FIRSTSOCKET, &hostname, &disp_hostname, &port); + Curl_conn_get_current_host(data, FIRSTSOCKET, &hostname, &port); Curl_bufref_init(&serverdata); Curl_bufref_init(&resp); *progress = SASL_INPROGRESS; @@ -587,8 +665,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, #ifdef USE_GSASL case SASL_GSASL: result = get_server_message(sasl, data, &serverdata); - if(!result) - result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp); + if(!result) { + struct gsasldata *gsasl = Curl_auth_gsasl_get(conn); + result = !gsasl ? CURLE_OUT_OF_MEMORY : + Curl_auth_gsasl_token(data, &serverdata, gsasl, &resp); + } if(!result && Curl_bufref_len(&resp) > 0) newstate = SASL_GSASL; break; @@ -615,50 +696,57 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, #endif #ifdef USE_NTLM - case SASL_NTLM: + case SASL_NTLM: { /* Create the type-1 message */ - result = Curl_auth_create_ntlm_type1_message(data, - conn->user, conn->passwd, - service, hostname, - &conn->ntlm, &resp); + struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE); + result = !ntlm ? CURLE_OUT_OF_MEMORY : + Curl_auth_create_ntlm_type1_message(data, + conn->user, conn->passwd, + service, hostname, + ntlm, &resp); newstate = SASL_NTLM_TYPE2MSG; break; - case SASL_NTLM_TYPE2MSG: + } + case SASL_NTLM_TYPE2MSG: { /* Decode the type-2 message */ - result = get_server_message(sasl, data, &serverdata); + struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, FALSE); + result = !ntlm ? CURLE_FAILED_INIT : + get_server_message(sasl, data, &serverdata); if(!result) - result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, - &conn->ntlm); + result = Curl_auth_decode_ntlm_type2_message(data, &serverdata, ntlm); if(!result) result = Curl_auth_create_ntlm_type3_message(data, conn->user, - conn->passwd, &conn->ntlm, + conn->passwd, ntlm, &resp); break; + } #endif #if defined(USE_KERBEROS5) - case SASL_GSSAPI: - result = Curl_auth_create_gssapi_user_message(data, conn->user, - conn->passwd, - service, - conn->host.name, + case SASL_GSSAPI: { + struct kerberos5data *krb5 = Curl_auth_krb5_get(conn); + result = !krb5 ? CURLE_OUT_OF_MEMORY : + Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, + service, conn->host.name, sasl->mutual_auth, NULL, - &conn->krb5, - &resp); + krb5, &resp); newstate = SASL_GSSAPI_TOKEN; break; + } case SASL_GSSAPI_TOKEN: result = get_server_message(sasl, data, &serverdata); if(!result) { - if(sasl->mutual_auth) { + struct kerberos5data *krb5 = Curl_auth_krb5_get(conn); + if(!krb5) + result = CURLE_OUT_OF_MEMORY; + else if(sasl->mutual_auth) { /* Decode the user token challenge and create the optional response message */ result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, NULL, NULL, sasl->mutual_auth, &serverdata, - &conn->krb5, - &resp); + krb5, &resp); newstate = SASL_GSSAPI_NO_DATA; } else @@ -666,19 +754,22 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, result = Curl_auth_create_gssapi_security_message(data, conn->sasl_authzid, &serverdata, - &conn->krb5, - &resp); + krb5, &resp); } break; case SASL_GSSAPI_NO_DATA: /* Decode the security challenge and create the response message */ result = get_server_message(sasl, data, &serverdata); - if(!result) - result = Curl_auth_create_gssapi_security_message(data, - conn->sasl_authzid, - &serverdata, - &conn->krb5, - &resp); + if(!result) { + struct kerberos5data *krb5 = Curl_auth_krb5_get(conn); + if(!krb5) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_auth_create_gssapi_security_message(data, + conn->sasl_authzid, + &serverdata, + krb5, &resp); + } break; #endif diff --git a/vendor/curl/lib/curl_sasl.h b/vendor/curl/lib/curl_sasl.h index 59983f7c..0674d56f 100644 --- a/vendor/curl/lib/curl_sasl.h +++ b/vendor/curl/lib/curl_sasl.h @@ -135,10 +135,6 @@ struct SASL { (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ !memcmp(line, mech, wordlen)) -/* This is used to cleanup any libraries or curl modules used by the sasl - functions */ -void Curl_sasl_cleanup(struct connectdata *conn, unsigned short authused); - /* Convert a mechanism name to a token */ unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len); diff --git a/vendor/curl/lib/curl_setup.h b/vendor/curl/lib/curl_setup.h index 1d484c61..4dc46f7a 100644 --- a/vendor/curl/lib/curl_setup.h +++ b/vendor/curl/lib/curl_setup.h @@ -224,46 +224,46 @@ #ifdef HTTP_ONLY # ifndef CURL_DISABLE_DICT -# define CURL_DISABLE_DICT +# define CURL_DISABLE_DICT # endif # ifndef CURL_DISABLE_FILE -# define CURL_DISABLE_FILE +# define CURL_DISABLE_FILE # endif # ifndef CURL_DISABLE_FTP -# define CURL_DISABLE_FTP +# define CURL_DISABLE_FTP # endif # ifndef CURL_DISABLE_GOPHER -# define CURL_DISABLE_GOPHER +# define CURL_DISABLE_GOPHER # endif # ifndef CURL_DISABLE_IMAP -# define CURL_DISABLE_IMAP +# define CURL_DISABLE_IMAP # endif # ifndef CURL_DISABLE_LDAP -# define CURL_DISABLE_LDAP +# define CURL_DISABLE_LDAP # endif # ifndef CURL_DISABLE_LDAPS -# define CURL_DISABLE_LDAPS +# define CURL_DISABLE_LDAPS # endif # ifndef CURL_DISABLE_MQTT -# define CURL_DISABLE_MQTT +# define CURL_DISABLE_MQTT # endif # ifndef CURL_DISABLE_POP3 -# define CURL_DISABLE_POP3 +# define CURL_DISABLE_POP3 # endif # ifndef CURL_DISABLE_RTSP -# define CURL_DISABLE_RTSP +# define CURL_DISABLE_RTSP # endif # ifndef CURL_DISABLE_SMB -# define CURL_DISABLE_SMB +# define CURL_DISABLE_SMB # endif # ifndef CURL_DISABLE_SMTP -# define CURL_DISABLE_SMTP +# define CURL_DISABLE_SMTP # endif # ifndef CURL_DISABLE_TELNET -# define CURL_DISABLE_TELNET +# define CURL_DISABLE_TELNET # endif # ifndef CURL_DISABLE_TFTP -# define CURL_DISABLE_TFTP +# define CURL_DISABLE_TFTP # endif #endif @@ -470,62 +470,46 @@ #include #endif -/* - * Large file (>2Gb) support using Win32 functions. - */ - -#ifdef USE_WIN32_LARGE_FILES +#ifdef _WIN32 # ifdef HAVE_IO_H # include # endif # include # include -# undef lseek -# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) -# undef fstat -# define fstat(fdes,stp) _fstati64(fdes, stp) -# undef stat -# define stat(fname,stp) curlx_win32_stat(fname, stp) -# define struct_stat struct _stati64 -# define LSEEK_ERROR (__int64)-1 -# define open curlx_win32_open -# define fopen(fname,mode) curlx_win32_fopen(fname, mode) - int curlx_win32_open(const char *filename, int oflag, ...); - int curlx_win32_stat(const char *path, struct_stat *buffer); - FILE *curlx_win32_fopen(const char *filename, const char *mode); -#endif - -#ifdef __DJGPP__ -/* Requires DJGPP 2.04 */ -# include -# undef lseek -# define lseek(fdes,offset,whence) llseek(fdes, offset, whence) -# define LSEEK_ERROR (offset_t)-1 -#endif - -/* - * Small file (<2Gb) support using Win32 functions. - */ - -#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES) -# ifdef HAVE_IO_H -# include +# ifdef USE_WIN32_LARGE_FILES + /* Large file (>2Gb) support using Win32 functions. */ +# undef lseek +# define lseek(fdes, offset, whence) _lseeki64(fdes, offset, whence) +# undef fstat +# define fstat(fdes,stp) _fstati64(fdes, stp) +# undef stat +# define struct_stat struct _stati64 +# define LSEEK_ERROR (__int64)-1 +# else + /* Small file (<2Gb) support using Win32 functions. */ +# ifndef UNDER_CE +# undef lseek +# define lseek(fdes, offset, whence) _lseek(fdes, (long)offset, whence) +# define fstat(fdes, stp) _fstat(fdes, stp) +# define struct_stat struct _stat +# endif +# define LSEEK_ERROR (long)-1 # endif -# include -# include # ifndef UNDER_CE -# undef lseek -# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) -# define fstat(fdes,stp) _fstat(fdes, stp) -# define stat(fname,stp) curlx_win32_stat(fname, stp) -# define struct_stat struct _stat -# define open curlx_win32_open -# define fopen(fname,mode) curlx_win32_fopen(fname, mode) int curlx_win32_stat(const char *path, struct_stat *buffer); int curlx_win32_open(const char *filename, int oflag, ...); FILE *curlx_win32_fopen(const char *filename, const char *mode); +# define stat(fname, stp) curlx_win32_stat(fname, stp) +# define open curlx_win32_open +# define CURL_FOPEN(fname, mode) curlx_win32_fopen(fname, mode) +# define fopen(fname, mode) CURL_FOPEN(fname, mode) # endif -# define LSEEK_ERROR (long)-1 +#elif defined(__DJGPP__) + /* Requires DJGPP 2.04 */ +# include +# undef lseek +# define lseek(fdes,offset,whence) llseek(fdes, offset, whence) +# define LSEEK_ERROR (offset_t)-1 #endif #ifndef struct_stat @@ -582,7 +566,7 @@ # endif # endif # ifndef SIZEOF_OFF_T -# define SIZEOF_OFF_T 4 +# define SIZEOF_OFF_T 4 # endif #endif @@ -590,9 +574,9 @@ #error "too small curl_off_t" #else /* assume SIZEOF_CURL_OFF_T == 8 */ -# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) +# define CURL_OFF_T_MAX 0x7FFFFFFFFFFFFFFF #endif -#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1)) +#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - 1) #if (SIZEOF_CURL_OFF_T != 8) # error "curl_off_t must be exactly 64 bits" @@ -677,12 +661,8 @@ # define select(n,r,w,x,t) select_s(n,r,w,x,t) # define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z)) # include -# ifdef word -# undef word -# endif -# ifdef byte -# undef byte -# endif +# undef word +# undef byte # endif /* MSDOS */ @@ -739,8 +719,8 @@ #endif #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \ - defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ - defined(USE_BEARSSL) || defined(USE_RUSTLS) + defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ + defined(USE_RUSTLS) #define USE_SSL /* SSL support has been enabled */ #endif @@ -775,7 +755,7 @@ /* Single point where USE_NTLM definition might be defined */ #ifndef CURL_DISABLE_NTLM # if defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \ - defined(USE_GNUTLS) || defined(USE_SECTRANSP) || \ + defined(USE_GNUTLS) || \ defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \ (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT)) # define USE_CURL_NTLM_CORE diff --git a/vendor/curl/lib/curl_setup_once.h b/vendor/curl/lib/curl_setup_once.h index c1051e0f..bec45de8 100644 --- a/vendor/curl/lib/curl_setup_once.h +++ b/vendor/curl/lib/curl_setup_once.h @@ -41,11 +41,9 @@ #include #endif -#ifdef HAVE_SYS_STAT_H #include -#endif -#ifdef HAVE_SYS_TIME_H +#if !defined(_WIN32) || defined(__MINGW32__) #include #endif @@ -96,7 +94,7 @@ # endif #endif -#ifdef HAVE_SYS_SOCKET_H +#ifndef _WIN32 #include #endif @@ -197,17 +195,19 @@ struct timeval { */ #ifdef HAVE_CLOSESOCKET -# define sclose(x) closesocket((x)) +# define CURL_SCLOSE(x) closesocket((x)) #elif defined(HAVE_CLOSESOCKET_CAMEL) -# define sclose(x) CloseSocket((x)) +# define CURL_SCLOSE(x) CloseSocket((x)) #elif defined(MSDOS) /* Watt-32 */ -# define sclose(x) close_s((x)) +# define CURL_SCLOSE(x) close_s((x)) #elif defined(USE_LWIPSOCK) -# define sclose(x) lwip_close((x)) +# define CURL_SCLOSE(x) lwip_close((x)) #else -# define sclose(x) close((x)) +# define CURL_SCLOSE(x) close((x)) #endif +#define sclose(x) CURL_SCLOSE(x) + /* * Stack-independent version of fcntl() on sockets: */ diff --git a/vendor/curl/lib/curl_sha512_256.c b/vendor/curl/lib/curl_sha512_256.c index 2d8a23f1..81bfddc7 100644 --- a/vendor/curl/lib/curl_sha512_256.c +++ b/vendor/curl/lib/curl_sha512_256.c @@ -34,9 +34,7 @@ * * GnuTLS * * wolfSSL * * Schannel SSPI - * * Secure Transport (Darwin) * * mbedTLS - * * BearSSL * * Rustls * Skip the backend if it does not support the required algorithm */ diff --git a/vendor/curl/lib/curl_sspi.c b/vendor/curl/lib/curl_sspi.c index 6516db56..5f19e960 100644 --- a/vendor/curl/lib/curl_sspi.c +++ b/vendor/curl/lib/curl_sspi.c @@ -28,6 +28,7 @@ #include #include "curl_sspi.h" +#include "strdup.h" #include "curlx/multibyte.h" #include "system_win32.h" #include "curlx/version_win32.h" @@ -37,23 +38,6 @@ #include "curl_memory.h" #include "memdebug.h" -/* We use our own typedef here since some headers might lack these */ -typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID); - -/* See definition of SECURITY_ENTRYPOINT in sspi.h */ -#ifdef UNICODE -# ifdef UNDER_CE -# define SECURITYENTRYPOINT L"InitSecurityInterfaceW" -# else -# define SECURITYENTRYPOINT "InitSecurityInterfaceW" -# endif -#else -# define SECURITYENTRYPOINT "InitSecurityInterfaceA" -#endif - -/* Handle of security.dll or secur32.dll, depending on Windows version */ -HMODULE Curl_hSecDll = NULL; - /* Pointer to SSPI dispatch table */ PSecurityFunctionTable Curl_pSecFn = NULL; @@ -76,31 +60,14 @@ PSecurityFunctionTable Curl_pSecFn = NULL; */ CURLcode Curl_sspi_global_init(void) { - INITSECURITYINTERFACE_FN pInitSecurityInterface; - /* If security interface is not yet initialized try to do this */ - if(!Curl_hSecDll) { - /* Security Service Provider Interface (SSPI) functions are located in - * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP - * have both these DLLs (security.dll forwards calls to secur32.dll) */ - - /* Load SSPI dll into the address space of the calling process */ - if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL)) - Curl_hSecDll = Curl_load_library(TEXT("security.dll")); - else - Curl_hSecDll = Curl_load_library(TEXT("secur32.dll")); - if(!Curl_hSecDll) - return CURLE_FAILED_INIT; - - /* Get address of the InitSecurityInterfaceA function from the SSPI dll */ - pInitSecurityInterface = - CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN, - (GetProcAddress(Curl_hSecDll, SECURITYENTRYPOINT))); - if(!pInitSecurityInterface) - return CURLE_FAILED_INIT; - + if(!Curl_pSecFn) { /* Get pointer to Security Service Provider Interface dispatch table */ - Curl_pSecFn = pInitSecurityInterface(); +#ifdef __MINGW32CE__ + Curl_pSecFn = InitSecurityInterfaceW(); +#else + Curl_pSecFn = InitSecurityInterface(); +#endif if(!Curl_pSecFn) return CURLE_FAILED_INIT; } @@ -119,9 +86,7 @@ CURLcode Curl_sspi_global_init(void) */ void Curl_sspi_global_cleanup(void) { - if(Curl_hSecDll) { - FreeLibrary(Curl_hSecDll); - Curl_hSecDll = NULL; + if(Curl_pSecFn) { Curl_pSecFn = NULL; } } @@ -129,7 +94,7 @@ void Curl_sspi_global_cleanup(void) /* * Curl_create_sspi_identity() * - * This is used to populate a SSPI identity structure based on the supplied + * This is used to populate an SSPI identity structure based on the supplied * username and password. * * Parameters: @@ -221,7 +186,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, /* * Curl_sspi_free_identity() * - * This is used to free the contents of a SSPI identifier structure. + * This is used to free the contents of an SSPI identifier structure. * * Parameters: * diff --git a/vendor/curl/lib/curl_sspi.h b/vendor/curl/lib/curl_sspi.h index cafdb8d3..540cdfd1 100644 --- a/vendor/curl/lib/curl_sspi.h +++ b/vendor/curl/lib/curl_sspi.h @@ -45,7 +45,7 @@ CURLcode Curl_sspi_global_init(void); void Curl_sspi_global_cleanup(void); -/* This is used to populate the domain in a SSPI identity structure */ +/* This is used to populate the domain in an SSPI identity structure */ CURLcode Curl_override_sspi_http_realm(const char *chlg, SEC_WINNT_AUTH_IDENTITY *identity); @@ -57,7 +57,6 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); /* Forward-declaration of global variables defined in curl_sspi.c */ -extern HMODULE Curl_hSecDll; extern PSecurityFunctionTable Curl_pSecFn; /* Provide some definitions missing in old headers */ diff --git a/vendor/curl/lib/curl_trc.c b/vendor/curl/lib/curl_trc.c index 566cdc53..334b6e2a 100644 --- a/vendor/curl/lib/curl_trc.c +++ b/vendor/curl/lib/curl_trc.c @@ -31,7 +31,6 @@ #include "easyif.h" #include "cfilters.h" #include "multiif.h" -#include "strcase.h" #include "cf-socket.h" #include "connect.h" @@ -206,7 +205,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat, const char *opt_id, int opt_id_idx, - const char * const fmt, va_list ap) CURL_PRINTF(5, 0); + const char * const fmt, va_list ap) CURL_PRINTF(5, 0); static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat, diff --git a/vendor/curl/lib/curlx/.checksrc b/vendor/curl/lib/curlx/.checksrc new file mode 100644 index 00000000..22ca8e0b --- /dev/null +++ b/vendor/curl/lib/curlx/.checksrc @@ -0,0 +1,5 @@ +banfunc snprintf +banfunc sscanf +banfunc strerror +banfunc strtol +banfunc vsnprint diff --git a/vendor/curl/lib/curlx/base64.c b/vendor/curl/lib/curlx/base64.c index 80624cc2..92ebc57e 100644 --- a/vendor/curl/lib/curlx/base64.c +++ b/vendor/curl/lib/curlx/base64.c @@ -61,9 +61,9 @@ static const unsigned char decodetable[] = /* * curlx_base64_decode() * - * Given a base64 NUL-terminated string at src, decode it and return a - * pointer in *outptr to a newly allocated memory area holding decoded - * data. Size of decoded data is returned in variable pointed by outlen. + * Given a base64 null-terminated string at src, decode it and return a + * pointer in *outptr to a newly allocated memory area holding decoded data. + * Size of decoded data is returned in variable pointed by outlen. * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. @@ -247,7 +247,7 @@ static CURLcode base64_encode(const char *table64, * encoded data. Size of encoded data is returned in variable pointed by * outlen. * - * Input length of 0 indicates input buffer holds a NUL-terminated string. + * Input length of 0 indicates input buffer holds a null-terminated string. * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. @@ -269,7 +269,7 @@ CURLcode curlx_base64_encode(const char *inputbuff, size_t insize, * encoded data. Size of encoded data is returned in variable pointed by * outlen. * - * Input length of 0 indicates input buffer holds a NUL-terminated string. + * Input length of 0 indicates input buffer holds a null-terminated string. * * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. diff --git a/vendor/curl/lib/vtls/bearssl.h b/vendor/curl/lib/curlx/binmode.h similarity index 64% rename from vendor/curl/lib/vtls/bearssl.h rename to vendor/curl/lib/curlx/binmode.h index 8bb254f7..3f356edd 100644 --- a/vendor/curl/lib/vtls/bearssl.h +++ b/vendor/curl/lib/curlx/binmode.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_BEARSSL_H -#define HEADER_CURL_BEARSSL_H +#ifndef HEADER_CURL_TOOL_BINMODE_H +#define HEADER_CURL_TOOL_BINMODE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) Michael Forney, + * Copyright (C) Daniel Stenberg, , 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,12 +23,17 @@ * SPDX-License-Identifier: curl * ***************************************************************************/ - #include "../curl_setup.h" -#ifdef USE_BEARSSL - -extern const struct Curl_ssl Curl_ssl_bearssl; +#if (defined(HAVE_SETMODE) || defined(HAVE__SETMODE)) && defined(O_BINARY) +/* Requires io.h and/or fcntl.h when available */ +#ifdef HAVE__SETMODE +# define CURLX_SET_BINMODE(stream) (void)_setmode(fileno(stream), O_BINARY) +#else +# define CURLX_SET_BINMODE(stream) (void)setmode(fileno(stream), O_BINARY) +#endif +#else +# define CURLX_SET_BINMODE(stream) (void)stream; Curl_nop_stmt +#endif -#endif /* USE_BEARSSL */ -#endif /* HEADER_CURL_BEARSSL_H */ +#endif /* HEADER_CURL_TOOL_BINMODE_H */ diff --git a/vendor/curl/lib/curlx/curlx.h b/vendor/curl/lib/curlx/curlx.h index 983c7b5c..9f7bd3a9 100644 --- a/vendor/curl/lib/curlx/curlx.h +++ b/vendor/curl/lib/curlx/curlx.h @@ -31,6 +31,9 @@ * be. */ +#include "binmode.h" +/* "binmode.h" provides macro CURLX_SET_BINMODE() */ + #include "nonblock.h" /* "nonblock.h" provides curlx_nonblock() */ @@ -65,10 +68,16 @@ #include "timeval.h" #include "timediff.h" +#include "wait.h" +/* for curlx_wait_ms */ + #include "winapi.h" /* for curlx_winapi_strerror */ #include "inet_pton.h" /* for curlx_inet_pton */ +#include "inet_ntop.h" +/* for curlx_inet_ntop */ + #endif /* HEADER_CURL_CURLX_H */ diff --git a/vendor/curl/lib/inet_ntop.c b/vendor/curl/lib/curlx/inet_ntop.c similarity index 86% rename from vendor/curl/lib/inet_ntop.c rename to vendor/curl/lib/curlx/inet_ntop.c index a1a34891..e5ff45cb 100644 --- a/vendor/curl/lib/inet_ntop.c +++ b/vendor/curl/lib/curlx/inet_ntop.c @@ -20,7 +20,7 @@ * Original code by Paul Vixie. "curlified" by Gisle Vanem. */ -#include "curl_setup.h" +#include "../curl_setup.h" #ifndef HAVE_INET_NTOP @@ -35,7 +35,6 @@ #endif #include "inet_ntop.h" -#include "curl_printf.h" #define IN6ADDRSZ 16 /* #define INADDRSZ 4 */ @@ -56,7 +55,7 @@ * Returns `dst' (as a const) * Note: * - uses no statics - * - takes a unsigned char* not an in_addr as input + * - takes an unsigned char* not an in_addr as input */ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size) { @@ -65,8 +64,9 @@ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size) DEBUGASSERT(size >= 16); - tmp[0] = '\0'; - (void)msnprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", + /* this sprintf() does not overflow the buffer. Avoids snprintf to work more + widely. Avoids the msnprintf family to work as a curlx function. */ + (void)(sprintf)(tmp, "%d.%d.%d.%d", ((int)((unsigned char)src[0])) & 0xff, ((int)((unsigned char)src[1])) & 0xff, ((int)((unsigned char)src[2])) & 0xff, @@ -162,7 +162,21 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size) tp += strlen(tp); break; } - tp += msnprintf(tp, 5, "%x", words[i]); + else { + /* Lower-case digits. Can't use the set from mprintf.c since this + needs to work as a curlx function */ + static const unsigned char ldigits[] = "0123456789abcdef"; + + unsigned int w = words[i]; + /* output lowercase 16bit hex number but ignore leading zeroes */ + if(w & 0xf000) + *tp++ = ldigits[(w & 0xf000) >> 12]; + if(w & 0xff00) + *tp++ = ldigits[(w & 0x0f00) >> 8]; + if(w & 0xfff0) + *tp++ = ldigits[(w & 0x00f0) >> 4]; + *tp++ = ldigits[(w & 0x000f)]; + } } /* Was it a trailing run of 0x00's? @@ -196,7 +210,7 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size) * code. This is to avoid losing the actual last Winsock error. When this * function returns NULL, check errno not SOCKERRNO. */ -char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) +char *curlx_inet_ntop(int af, const void *src, char *buf, size_t size) { switch(af) { case AF_INET: diff --git a/vendor/curl/lib/inet_ntop.h b/vendor/curl/lib/curlx/inet_ntop.h similarity index 86% rename from vendor/curl/lib/inet_ntop.h rename to vendor/curl/lib/curlx/inet_ntop.h index 9923daae..68f8c8d1 100644 --- a/vendor/curl/lib/inet_ntop.h +++ b/vendor/curl/lib/curlx/inet_ntop.h @@ -24,26 +24,26 @@ * ***************************************************************************/ -#include "curl_setup.h" +#include "../curl_setup.h" -char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size); +char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size); #ifdef HAVE_INET_NTOP #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_SOCKET_H +#ifndef _WIN32 #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef __AMIGA__ -#define Curl_inet_ntop(af,addr,buf,size) \ +#define curlx_inet_ntop(af,addr,buf,size) \ (char *)inet_ntop(af, CURL_UNCONST(addr), (unsigned char *)buf, \ (curl_socklen_t)(size)) #else -#define Curl_inet_ntop(af,addr,buf,size) \ +#define curlx_inet_ntop(af,addr,buf,size) \ inet_ntop(af, addr, buf, (curl_socklen_t)(size)) #endif #endif diff --git a/vendor/curl/lib/curlx/inet_pton.h b/vendor/curl/lib/curlx/inet_pton.h index a9dc4308..610b329f 100644 --- a/vendor/curl/lib/curlx/inet_pton.h +++ b/vendor/curl/lib/curlx/inet_pton.h @@ -32,7 +32,7 @@ int curlx_inet_pton(int, const char *, void *); #ifdef HAVE_NETINET_IN_H #include #endif -#ifdef HAVE_SYS_SOCKET_H +#ifndef _WIN32 #include #endif #ifdef HAVE_ARPA_INET_H diff --git a/vendor/curl/lib/curlx/strparse.c b/vendor/curl/lib/curlx/strparse.c index b8b2a14d..ecdf5b96 100644 --- a/vendor/curl/lib/curlx/strparse.c +++ b/vendor/curl/lib/curlx/strparse.c @@ -23,7 +23,10 @@ ***************************************************************************/ #include "strparse.h" -#include "../strcase.h" + +#ifndef WITHOUT_LIBCURL +#include /* for curl_strnequal() */ +#endif void curlx_str_init(struct Curl_str *out) { @@ -40,7 +43,7 @@ void curlx_str_assign(struct Curl_str *out, const char *str, size_t len) /* Get a word until the first DELIM or end of string. At least one byte long. return non-zero on error */ int curlx_str_until(const char **linep, struct Curl_str *out, - const size_t max, char delim) + const size_t max, char delim) { const char *s = *linep; size_t len = 0; @@ -64,7 +67,7 @@ int curlx_str_until(const char **linep, struct Curl_str *out, /* Get a word until the first space or end of string. At least one byte long. return non-zero on error */ int curlx_str_word(const char **linep, struct Curl_str *out, - const size_t max) + const size_t max) { return curlx_str_until(linep, out, max, ' '); } @@ -72,7 +75,7 @@ int curlx_str_word(const char **linep, struct Curl_str *out, /* Get a word until a newline byte or end of string. At least one byte long. return non-zero on error */ int curlx_str_untilnl(const char **linep, struct Curl_str *out, - const size_t max) + const size_t max) { const char *s = *linep; size_t len = 0; @@ -96,7 +99,7 @@ int curlx_str_untilnl(const char **linep, struct Curl_str *out, /* Get a "quoted" word. No escaping possible. return non-zero on error */ int curlx_str_quotedword(const char **linep, struct Curl_str *out, - const size_t max) + const size_t max) { const char *s = *linep; size_t len = 0; @@ -238,7 +241,7 @@ int curlx_str_newline(const char **linep) int curlx_str_casecompare(struct Curl_str *str, const char *check) { size_t clen = check ? strlen(check) : 0; - return ((str->len == clen) && strncasecompare(str->str, check, clen)); + return ((str->len == clen) && curl_strnequal(str->str, check, clen)); } #endif diff --git a/vendor/curl/lib/curlx/strparse.h b/vendor/curl/lib/curlx/strparse.h index 17bfdb80..6a0bf28d 100644 --- a/vendor/curl/lib/curlx/strparse.h +++ b/vendor/curl/lib/curlx/strparse.h @@ -55,17 +55,17 @@ int curlx_str_word(const char **linep, struct Curl_str *out, const size_t max); /* Get a word until the first DELIM or end of string return non-zero on error */ int curlx_str_until(const char **linep, struct Curl_str *out, const size_t max, - char delim); + char delim); /* Get a word until a newline byte or end of string. At least one byte long. return non-zero on error */ int curlx_str_untilnl(const char **linep, struct Curl_str *out, - const size_t max); + const size_t max); /* Get a "quoted" word. No escaping possible. return non-zero on error */ int curlx_str_quotedword(const char **linep, struct Curl_str *out, - const size_t max); + const size_t max); /* Advance over a single character. return non-zero on error */ diff --git a/vendor/curl/lib/curlx/wait.c b/vendor/curl/lib/curlx/wait.c new file mode 100644 index 00000000..f568fb69 --- /dev/null +++ b/vendor/curl/lib/curlx/wait.c @@ -0,0 +1,97 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "../curl_setup.h" + +#ifndef HAVE_SELECT +#error "We cannot compile without select() support." +#endif + +#include + +#ifdef HAVE_SYS_SELECT_H +#include +#elif defined(HAVE_UNISTD_H) +#include +#endif + +#ifdef MSDOS +#include /* delay() */ +#endif + +#include "timediff.h" +#include "wait.h" + +/* + * Internal function used for waiting a specific amount of ms in + * Curl_socket_check() and Curl_poll() when no file descriptor is provided to + * wait on, just being used to delay execution. Winsock select() and poll() + * timeout mechanisms need a valid socket descriptor in a not null file + * descriptor set to work. Waiting indefinitely with this function is not + * allowed, a zero or negative timeout value will return immediately. Timeout + * resolution, accuracy, as well as maximum supported value is system + * dependent, neither factor is a critical issue for the intended use of this + * function in the library. + * + * Return values: + * -1 = system call error, or invalid timeout value + * 0 = specified timeout has elapsed, or interrupted + */ +int curlx_wait_ms(timediff_t timeout_ms) +{ + int r = 0; + + if(!timeout_ms) + return 0; + if(timeout_ms < 0) { + SET_SOCKERRNO(SOCKEINVAL); + return -1; + } +#if defined(MSDOS) + delay((unsigned int)timeout_ms); +#elif defined(_WIN32) + /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */ +#if TIMEDIFF_T_MAX >= ULONG_MAX + if(timeout_ms >= ULONG_MAX) + timeout_ms = ULONG_MAX-1; + /* do not use ULONG_MAX, because that is equal to INFINITE */ +#endif + Sleep((DWORD)timeout_ms); +#else + /* avoid using poll() for this since it behaves incorrectly with no sockets + on Apple operating systems */ + { + struct timeval pending_tv; + r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms)); + } +#endif /* _WIN32 */ + if(r) { + if((r == -1) && (SOCKERRNO == SOCKEINTR)) + /* make EINTR from select or poll not a "lethal" error */ + r = 0; + else + r = -1; + } + return r; +} diff --git a/vendor/curl/lib/vtls/sectransp.h b/vendor/curl/lib/curlx/wait.h similarity index 80% rename from vendor/curl/lib/vtls/sectransp.h rename to vendor/curl/lib/curlx/wait.h index c82dc184..208bc20a 100644 --- a/vendor/curl/lib/vtls/sectransp.h +++ b/vendor/curl/lib/curlx/wait.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_SECTRANSP_H -#define HEADER_CURL_SECTRANSP_H +#ifndef HEADER_CURL_WAIT_H +#define HEADER_CURL_WAIT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,6 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) Nick Zitzmann, . * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which @@ -24,11 +23,9 @@ * SPDX-License-Identifier: curl * ***************************************************************************/ -#include "../curl_setup.h" -#ifdef USE_SECTRANSP +#include "../curl_setup.h" -extern const struct Curl_ssl Curl_ssl_sectransp; +int curlx_wait_ms(timediff_t timeout_ms); -#endif /* USE_SECTRANSP */ -#endif /* HEADER_CURL_SECTRANSP_H */ +#endif /* HEADER_CURL_WAIT_H */ diff --git a/vendor/curl/lib/curlx/warnless.c b/vendor/curl/lib/curlx/warnless.c index 5ca92450..c6cb7c6e 100644 --- a/vendor/curl/lib/curlx/warnless.c +++ b/vendor/curl/lib/curlx/warnless.c @@ -35,11 +35,6 @@ #endif /* __INTEL_COMPILER && __unix__ */ -#ifdef _WIN32 -#undef read -#undef write -#endif - #include #define CURL_MASK_UCHAR ((unsigned char)~0) @@ -295,21 +290,3 @@ size_t curlx_sitouz(int sinum) # pragma warning(pop) #endif } - -#ifdef _WIN32 - -ssize_t curlx_read(int fd, void *buf, size_t count) -{ - return (ssize_t)read(fd, buf, curlx_uztoui(count)); -} - -ssize_t curlx_write(int fd, const void *buf, size_t count) -{ - return (ssize_t)write(fd, buf, curlx_uztoui(count)); -} - -#endif /* _WIN32 */ - -/* Ensure that warnless.h redefinitions continue to have an effect - in "unity" builds. */ -#undef HEADER_CURL_WARNLESS_H_REDEFS diff --git a/vendor/curl/lib/curlx/warnless.h b/vendor/curl/lib/curlx/warnless.h index c78b6116..0a0c6080 100644 --- a/vendor/curl/lib/curlx/warnless.h +++ b/vendor/curl/lib/curlx/warnless.h @@ -57,24 +57,11 @@ unsigned short curlx_uitous(unsigned int uinum); size_t curlx_sitouz(int sinum); -#ifdef _WIN32 - -ssize_t curlx_read(int fd, void *buf, size_t count); - -ssize_t curlx_write(int fd, const void *buf, size_t count); - -#endif /* _WIN32 */ - -#endif /* HEADER_CURL_WARNLESS_H */ - -#ifndef HEADER_CURL_WARNLESS_H_REDEFS -#define HEADER_CURL_WARNLESS_H_REDEFS - #ifdef _WIN32 #undef read -#define read(fd, buf, count) curlx_read(fd, buf, count) +#define read(fd, buf, count) (ssize_t)_read(fd, buf, curlx_uztoui(count)) #undef write -#define write(fd, buf, count) curlx_write(fd, buf, count) +#define write(fd, buf, count) (ssize_t)_write(fd, buf, curlx_uztoui(count)) #endif -#endif /* HEADER_CURL_WARNLESS_H_REDEFS */ +#endif /* HEADER_CURL_WARNLESS_H */ diff --git a/vendor/curl/lib/cw-out.c b/vendor/curl/lib/cw-out.c index 097ef85e..ee7dc65d 100644 --- a/vendor/curl/lib/cw-out.c +++ b/vendor/curl/lib/cw-out.c @@ -31,6 +31,7 @@ #include "headers.h" #include "multiif.h" #include "sendf.h" +#include "transfer.h" #include "cw-out.h" #include "cw-pause.h" @@ -234,11 +235,9 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx, failf(data, "Write callback asked for PAUSE when not supported"); return CURLE_WRITE_ERROR; } - /* mark the connection as RECV paused */ - data->req.keepon |= KEEP_RECV_PAUSE; ctx->paused = TRUE; CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client"); - break; + return Curl_xfer_pause_recv(data, TRUE); } else if(CURL_WRITEFUNC_ERROR == nwritten) { failf(data, "client returned ERROR on write of %zu bytes", wlen); diff --git a/vendor/curl/lib/dict.c b/vendor/curl/lib/dict.c index 637f349e..7f13e6f7 100644 --- a/vendor/curl/lib/dict.c +++ b/vendor/curl/lib/dict.c @@ -60,7 +60,6 @@ #include "progress.h" #include "dict.h" #include "curl_printf.h" -#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -198,9 +197,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) if(result) return result; - if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || - strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || - strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || + curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || + curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { word = strchr(path, ':'); if(word) { @@ -245,9 +244,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) } Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */ } - else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || - strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || - strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || + curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || + curl_strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { word = strchr(path, ':'); if(word) { diff --git a/vendor/curl/lib/doh.c b/vendor/curl/lib/doh.c index e2d3d6ee..f96ae082 100644 --- a/vendor/curl/lib/doh.c +++ b/vendor/curl/lib/doh.c @@ -257,7 +257,7 @@ static void doh_probe_done(struct Curl_easy *data, if(!dohp->pending) { /* DoH completed, run the transfer picking up the results */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); } } } @@ -377,8 +377,6 @@ static CURLcode doh_probe_run(struct Curl_easy *data, options should be added to check doh proxy insecure separately, CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER. */ - if(data->set.ssl.falsestart) - ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L); if(data->set.str[STRING_SSL_CAFILE]) { ERROR_CHECK_SETOPT(CURLOPT_CAINFO, data->set.str[STRING_SSL_CAFILE]); @@ -590,7 +588,7 @@ static void doh_store_a(const unsigned char *doh, int index, } static void doh_store_aaaa(const unsigned char *doh, int index, - struct dohentry *d) + struct dohentry *d) { /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { @@ -921,7 +919,7 @@ static void doh_show(struct Curl_easy *data, * This function returns a pointer to the first element of a newly allocated * Curl_addrinfo struct linked list filled with the data from a set of DoH * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for - * a IPv6 stack, but usable also for IPv4, all hosts and environments. + * an IPv6 stack, but usable also for IPv4, all hosts and environments. * * The memory allocated by this function *MUST* be free'd later on calling * Curl_freeaddrinfo(). For each successful call to this function there diff --git a/vendor/curl/lib/dynhds.c b/vendor/curl/lib/dynhds.c index 5c52d741..dcb9193a 100644 --- a/vendor/curl/lib/dynhds.c +++ b/vendor/curl/lib/dynhds.c @@ -150,7 +150,7 @@ struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds, const char *name, size_t i; for(i = 0; i < dynhds->hds_len; ++i) { if(dynhds->hds[i]->namelen == namelen && - strncasecompare(dynhds->hds[i]->name, name, namelen)) { + curl_strnequal(dynhds->hds[i]->name, name, namelen)) { return dynhds->hds[i]; } } @@ -297,7 +297,7 @@ size_t Curl_dynhds_count_name(struct dynhds *dynhds, size_t i; for(i = 0; i < dynhds->hds_len; ++i) { if((namelen == dynhds->hds[i]->namelen) && - strncasecompare(name, dynhds->hds[i]->name, namelen)) + curl_strnequal(name, dynhds->hds[i]->name, namelen)) ++n; } } @@ -325,7 +325,7 @@ size_t Curl_dynhds_remove(struct dynhds *dynhds, size_t i, len; for(i = 0; i < dynhds->hds_len; ++i) { if((namelen == dynhds->hds[i]->namelen) && - strncasecompare(name, dynhds->hds[i]->name, namelen)) { + curl_strnequal(name, dynhds->hds[i]->name, namelen)) { ++n; --dynhds->hds_len; dynhds->strs_len -= (dynhds->hds[i]->namelen + diff --git a/vendor/curl/lib/dynhds.h b/vendor/curl/lib/dynhds.h index 7cd5da47..e533dcc3 100644 --- a/vendor/curl/lib/dynhds.h +++ b/vendor/curl/lib/dynhds.h @@ -32,7 +32,7 @@ struct dynbuf; /** * A single header entry. - * `name` and `value` are non-NULL and always NUL terminated. + * `name` and `value` are non-NULL and always null-terminated. */ struct dynhds_entry { char *name; @@ -113,7 +113,7 @@ size_t Curl_dynhds_count_name(struct dynhds *dynhds, const char *name, size_t namelen); /** - * Return how often the given 0-terminated name appears in `dynhds`. + * Return how often the given null-terminated name appears in `dynhds`. * Names are case-insensitive. */ size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name); diff --git a/vendor/curl/lib/easy.c b/vendor/curl/lib/easy.c index 3f867862..9c1f1c69 100644 --- a/vendor/curl/lib/easy.c +++ b/vendor/curl/lib/easy.c @@ -67,6 +67,7 @@ #include "amigaos.h" #include "macos.h" #include "curlx/warnless.h" +#include "curlx/wait.h" #include "sigpipe.h" #include "vssh/ssh.h" #include "setopt.h" @@ -128,9 +129,6 @@ curl_free_callback Curl_cfree = (curl_free_callback)free; curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; -#if defined(_WIN32) && defined(UNICODE) -curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup; -#endif #if defined(_MSC_VER) && defined(_DLL) # pragma warning(pop) @@ -156,9 +154,6 @@ static CURLcode global_init(long flags, bool memoryfuncs) Curl_crealloc = (curl_realloc_callback)realloc; Curl_cstrdup = (curl_strdup_callback)system_strdup; Curl_ccalloc = (curl_calloc_callback)calloc; -#if defined(_WIN32) && defined(UNICODE) - Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; -#endif } if(Curl_trc_init()) { @@ -611,7 +606,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) #endif pollrc = 0; if(ev->ms > 0) - Curl_wait_ms(ev->ms); + curlx_wait_ms(ev->ms); } ev->msbump = FALSE; /* reset here */ @@ -733,7 +728,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi) /* - * easy_perform() is the external interface that performs a blocking + * easy_perform() is the internal interface that performs a blocking * transfer as previously setup. * * CONCEPT: This function creates a multi handle, adds the easy handle to it, @@ -1128,13 +1123,12 @@ void curl_easy_reset(CURL *d) */ CURLcode curl_easy_pause(CURL *d, int action) { - struct SingleRequest *k; CURLcode result = CURLE_OK; - int oldstate; - int newstate; bool recursive = FALSE; - bool keep_changed, unpause_read, not_all_paused; + bool changed = FALSE; struct Curl_easy *data = d; + bool recv_paused, recv_paused_new; + bool send_paused, send_paused_new; if(!GOOD_EASY_HANDLE(data) || !data->conn) /* crazy input, do not continue */ @@ -1142,62 +1136,37 @@ CURLcode curl_easy_pause(CURL *d, int action) if(Curl_is_in_callback(data)) recursive = TRUE; - k = &data->req; - oldstate = k->keepon & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE); - - /* first switch off both pause bits then set the new pause bits */ - newstate = (k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) | - ((action & CURLPAUSE_RECV) ? KEEP_RECV_PAUSE : 0) | - ((action & CURLPAUSE_SEND) ? KEEP_SEND_PAUSE : 0); - - keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate); - not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != - (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE); - unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) && - (data->mstate == MSTATE_PERFORMING || - data->mstate == MSTATE_RATELIMITING)); - /* Unpausing writes is detected on the next run in - * transfer.c:Curl_sendrecv(). This is because this may result - * in a transfer error if the application's callbacks fail */ - - /* Set the new keepon state, so it takes effect no matter what error - * may happen afterwards. */ - k->keepon = newstate; + + recv_paused = Curl_xfer_recv_is_paused(data); + recv_paused_new = (action & CURLPAUSE_RECV); + send_paused = Curl_xfer_send_is_paused(data); + send_paused_new = (action & CURLPAUSE_SEND); + + if(send_paused != send_paused_new) { + changed = TRUE; + result = Curl_1st_err(result, Curl_xfer_pause_send(data, send_paused_new)); + } + + if(recv_paused != recv_paused_new) { + changed = TRUE; + result = Curl_1st_err(result, Curl_xfer_pause_recv(data, recv_paused_new)); + } /* If not completely pausing both directions now, run again in any case. */ - if(not_all_paused) { + if(!Curl_xfer_is_blocked(data)) { Curl_expire(data, 0, EXPIRE_RUN_NOW); /* reset the too-slow time keeper */ data->state.keeps_speed.tv_sec = 0; - /* Simulate socket events on next run for unpaused directions */ - if(!(newstate & KEEP_SEND_PAUSE)) - data->state.select_bits |= CURL_CSELECT_OUT; - if(!(newstate & KEEP_RECV_PAUSE)) - data->state.select_bits |= CURL_CSELECT_IN; /* On changes, tell application to update its timers. */ - if(keep_changed && data->multi) { - if(Curl_update_timer(data->multi)) { + if(changed && data->multi) { + if(Curl_update_timer(data->multi) && !result) result = CURLE_ABORTED_BY_CALLBACK; - goto out; - } } } - if(unpause_read) { - result = Curl_creader_unpause(data); - if(result) - goto out; - } - - if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) { - Curl_conn_ev_data_pause(data, FALSE); - result = Curl_cwriter_unpause(data); - } - -out: - if(!result && !data->state.done && keep_changed && data->multi) + if(!result && changed && !data->state.done && data->multi) /* pause/unpausing may result in multi event changes */ - if(Curl_multi_ev_assess_xfer(data->multi, data)) + if(Curl_multi_ev_assess_xfer(data->multi, data) && !result) result = CURLE_ABORTED_BY_CALLBACK; if(recursive) @@ -1241,7 +1210,6 @@ static CURLcode easy_connection(struct Curl_easy *data, CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n) { CURLcode result; - ssize_t n1; struct connectdata *c; struct Curl_easy *data = d; @@ -1258,13 +1226,7 @@ CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n) Curl_attach_connection(data, c); *n = 0; - result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1); - - if(result) - return result; - - *n = (size_t)n1; - return CURLE_OK; + return Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, n); } #ifndef CURL_DISABLE_WEBSOCKETS diff --git a/vendor/curl/lib/easygetopt.c b/vendor/curl/lib/easygetopt.c index 5d30d39a..01131216 100644 --- a/vendor/curl/lib/easygetopt.c +++ b/vendor/curl/lib/easygetopt.c @@ -1,9 +1,9 @@ /*************************************************************************** * _ _ ____ _ - * Project ___| | | | _ | | + * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ - * ___|___/|_| ______| + * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * @@ -23,7 +23,6 @@ ***************************************************************************/ #include "curl_setup.h" -#include "strcase.h" #include "easyoptions.h" #ifndef CURL_DISABLE_GETOPTIONS @@ -37,7 +36,7 @@ static const struct curl_easyoption *lookup(const char *name, CURLoption id) const struct curl_easyoption *o = &Curl_easyopts[0]; do { if(name) { - if(strcasecompare(o->name, name)) + if(curl_strequal(o->name, name)) return o; } else { diff --git a/vendor/curl/lib/escape.c b/vendor/curl/lib/escape.c index 3cd906dc..a292ba3b 100644 --- a/vendor/curl/lib/escape.c +++ b/vendor/curl/lib/escape.c @@ -85,7 +85,7 @@ char *curl_easy_escape(CURL *data, const char *string, else { /* encode it */ unsigned char out[3]={'%'}; - Curl_hexbyte(&out[1], in, FALSE); + Curl_hexbyte(&out[1], in); if(curlx_dyn_addn(&d, out, 3)) return NULL; } @@ -212,7 +212,8 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ DEBUGASSERT(src && len && (olen >= 3)); if(src && len && (olen >= 3)) { while(len-- && (olen >= 3)) { - Curl_hexbyte(out, *src, TRUE); + out[0] = Curl_ldigits[*src >> 4]; + out[1] = Curl_ldigits[*src & 0x0F]; ++src; out += 2; olen -= 2; @@ -225,14 +226,11 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ /* Curl_hexbyte * - * Output a single unsigned char as a two-digit hex number, lowercase or - * uppercase + * Output a single unsigned char as a two-digit UPPERCASE hex number. */ void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */ - unsigned char val, - bool lowercase) + unsigned char val) { - const unsigned char *t = lowercase ? Curl_ldigits : Curl_udigits; - dest[0] = t[val >> 4]; - dest[1] = t[val & 0x0F]; + dest[0] = Curl_udigits[val >> 4]; + dest[1] = Curl_udigits[val & 0x0F]; } diff --git a/vendor/curl/lib/escape.h b/vendor/curl/lib/escape.h index 1f2bac8f..a43fc38e 100644 --- a/vendor/curl/lib/escape.h +++ b/vendor/curl/lib/escape.h @@ -42,7 +42,6 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */ unsigned char *out, size_t olen); /* output buffer size */ void Curl_hexbyte(unsigned char *dest, /* must fit two bytes */ - unsigned char val, - bool lowercase); + unsigned char val); #endif /* HEADER_CURL_ESCAPE_H */ diff --git a/vendor/curl/lib/formdata.c b/vendor/curl/lib/formdata.c index 2aa8eee9..5a4b52ea 100644 --- a/vendor/curl/lib/formdata.c +++ b/vendor/curl/lib/formdata.c @@ -34,7 +34,6 @@ struct Curl_easy; #include "urldata.h" /* for struct Curl_easy */ #include "mime.h" #include "vtls/vtls.h" -#include "strcase.h" #include "sendf.h" #include "strdup.h" #include "rand.h" diff --git a/vendor/curl/lib/ftp.c b/vendor/curl/lib/ftp.c index 04c0ad7b..06c486bc 100644 --- a/vendor/curl/lib/ftp.c +++ b/vendor/curl/lib/ftp.c @@ -60,7 +60,7 @@ #include "cf-socket.h" #include "connect.h" #include "strerror.h" -#include "inet_ntop.h" +#include "curlx/inet_ntop.h" #include "curlx/inet_pton.h" #include "select.h" #include "parsedate.h" /* for the week day and month names */ @@ -114,12 +114,14 @@ static const char * const ftp_state_names[]={ "QUOTE", "RETR_PREQUOTE", "STOR_PREQUOTE", + "LIST_PREQUOTE", "POSTQUOTE", "CWD", "MKD", "MDTM", "TYPE", "LIST_TYPE", + "RETR_LIST_TYPE", "RETR_TYPE", "STOR_TYPE", "SIZE", @@ -765,7 +767,12 @@ static CURLcode ftp_state_user(struct Curl_easy *data, static CURLcode ftp_state_pwd(struct Curl_easy *data, struct ftp_conn *ftpc) { - CURLcode result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD"); + CURLcode result; +#ifdef DEBUGBUILD + if(!data->id && getenv("CURL_FTP_PWD_STOP")) + return CURLE_OK; +#endif + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PWD"); if(!result) ftp_state(data, ftpc, FTP_PWD); @@ -978,6 +985,12 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, port_min = port_max = 0; if(addrlen) { + const struct Curl_sockaddr_ex *remote_addr = + Curl_conn_get_remote_addr(data, FIRSTSOCKET); + + DEBUGASSERT(remote_addr); + if(!remote_addr) + goto out; DEBUGASSERT(addr); if(addrlen >= sizeof(ipstr)) goto out; @@ -985,9 +998,9 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, ipstr[addrlen] = 0; /* attempt to get the address of the given interface name */ - switch(Curl_if2ip(conn->remote_addr->family, + switch(Curl_if2ip(remote_addr->family, #ifdef USE_IPV6 - Curl_ipv6_scope(&conn->remote_addr->curl_sa_addr), + Curl_ipv6_scope(&remote_addr->curl_sa_addr), conn->scope_id, #endif ipstr, hbuf, sizeof(hbuf))) { @@ -1020,11 +1033,11 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, switch(sa->sa_family) { #ifdef USE_IPV6 case AF_INET6: - r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); + r = curlx_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf)); break; #endif default: - r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); + r = curlx_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf)); break; } if(!r) { @@ -1052,7 +1065,8 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, /* step 2, create a socket for the requested address */ error = 0; for(ai = res; ai; ai = ai->ai_next) { - if(Curl_socket_open(data, ai, NULL, conn->transport, &portsock)) { + if(Curl_socket_open(data, ai, NULL, + Curl_conn_get_transport(data, conn), &portsock)) { error = SOCKERRNO; continue; } @@ -1146,7 +1160,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, #ifdef USE_IPV6 if(!conn->bits.ftp_use_eprt && conn->bits.ipv6) - /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the + /* EPRT is disabled but we are connected to an IPv6 host, so we ignore the request and enable EPRT again! */ conn->bits.ftp_use_eprt = TRUE; #endif @@ -1245,7 +1259,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, } data->conn->bits.do_more = FALSE; Curl_pgrsTime(data, TIMER_STARTACCEPT); - Curl_expire(data, data->set.accepttimeout ? + Curl_expire(data, (data->set.accepttimeout > 0) ? data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, EXPIRE_FTP_ACCEPT); } @@ -1278,7 +1292,7 @@ static CURLcode ftp_state_use_pasv(struct Curl_easy *data, #ifdef PF_INET6 if(!conn->bits.ftp_use_epsv && conn->bits.ipv6) - /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the + /* EPSV is disabled but we are connected to an IPv6 host, so we ignore the request and enable EPSV again! */ conn->bits.ftp_use_epsv = TRUE; #endif @@ -1448,6 +1462,14 @@ static CURLcode ftp_state_list(struct Curl_easy *data, return result; } +static CURLcode ftp_state_list_prequote(struct Curl_easy *data, + struct ftp_conn *ftpc, + struct FTP *ftp) +{ + /* We have sent the TYPE, now we must send the list of prequote strings */ + return ftp_state_quote(data, ftpc, ftp, TRUE, FTP_LIST_PREQUOTE); +} + static CURLcode ftp_state_retr_prequote(struct Curl_easy *data, struct ftp_conn *ftpc, struct FTP *ftp) @@ -1636,6 +1658,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, break; case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: + case FTP_LIST_PREQUOTE: item = data->set.prequote; break; case FTP_POSTQUOTE: @@ -1725,6 +1748,10 @@ static CURLcode ftp_state_quote(struct Curl_easy *data, break; case FTP_POSTQUOTE: break; + case FTP_LIST_PREQUOTE: + ftp_state(data, ftpc, FTP_LIST_TYPE); + result = ftp_state_list(data, ftpc, ftp); + break; } } @@ -1752,8 +1779,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data, infof(data, "Failed EPSV attempt. Disabling EPSV"); /* disable it for next transfer */ conn->bits.ftp_use_epsv = FALSE; - Curl_conn_close(data, SECONDARYSOCKET); - Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET); + close_secondarysocket(data, ftpc); data->state.errorbuf = FALSE; /* allow error message to get rewritten */ result = Curl_pp_sendf(data, &ftpc->pp, "%s", "PASV"); @@ -2199,6 +2225,8 @@ static CURLcode ftp_state_type_resp(struct Curl_easy *data, result = ftp_state_retr_prequote(data, ftpc, ftp); else if(instate == FTP_STOR_TYPE) result = ftp_state_stor_prequote(data, ftpc, ftp); + else if(instate == FTP_RETR_LIST_TYPE) + result = ftp_state_list_prequote(data, ftpc, ftp); return result; } @@ -2716,8 +2744,8 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, #endif if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { - /* We do not have a SSL/TLS control connection yet, but FTPS is - requested. Try a FTPS connection now */ + /* We do not have an SSL/TLS control connection yet, but FTPS is + requested. Try an FTPS connection now */ ftpc->count3 = 0; switch(data->set.ftpsslauth) { @@ -2962,7 +2990,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; /* Check for special servers here. */ - if(strcasecompare(os, "OS/400")) { + if(curl_strequal(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); if(result) { @@ -3003,6 +3031,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, case FTP_POSTQUOTE: case FTP_RETR_PREQUOTE: case FTP_STOR_PREQUOTE: + case FTP_LIST_PREQUOTE: if((ftpcode >= 400) && !ftpc->count2) { /* failure response code, and not allowed to fail */ failf(data, "QUOT command failed with %03d", ftpcode); @@ -3072,6 +3101,7 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, case FTP_LIST_TYPE: case FTP_RETR_TYPE: case FTP_STOR_TYPE: + case FTP_RETR_LIST_TYPE: result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state); break; @@ -3126,8 +3156,8 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, /* called repeatedly until done from multi.c */ static CURLcode ftp_statemach(struct Curl_easy *data, - struct ftp_conn *ftpc, - bool *done) + struct ftp_conn *ftpc, + bool *done) { CURLcode result = Curl_pp_statemach(data, &ftpc->pp, FALSE, FALSE); @@ -3322,7 +3352,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */ #endif - if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { + if(Curl_conn_is_setup(conn, SECONDARYSOCKET)) { if(!result && ftpc->dont_check && data->req.maxdownload > 0) { /* partial download completed */ result = Curl_pp_sendf(data, pp, "%s", "ABOR"); @@ -3676,7 +3706,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) if(result) ; - else if(data->state.list_only || !ftpc->file) { + else if((data->state.list_only || !ftpc->file) && + !(data->set.prequote)) { /* The specified path ends with a slash, and therefore we think this is a directory that is requested, use LIST. But before that we need to set ASCII transfer mode. */ @@ -3690,8 +3721,14 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) /* otherwise just fall through */ } else { - result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, - FTP_RETR_TYPE); + if(data->set.prequote && !ftpc->file) { + result = ftp_nb_type(data, ftpc, ftp, TRUE, + FTP_RETR_LIST_TYPE); + } + else { + result = ftp_nb_type(data, ftpc, ftp, data->state.prefer_ascii, + FTP_RETR_TYPE); + } if(result) return result; } @@ -4118,7 +4155,7 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, will try to send the QUIT command, otherwise it will just return. */ ftpc->shutdown = TRUE; - if(dead_connection) + if(dead_connection || Curl_pp_needs_flush(data, &ftpc->pp)) ftpc->ctl_valid = FALSE; /* The FTP session may or may not have been allocated/setup at this point! */ diff --git a/vendor/curl/lib/ftp.h b/vendor/curl/lib/ftp.h index c31aa932..52661981 100644 --- a/vendor/curl/lib/ftp.h +++ b/vendor/curl/lib/ftp.h @@ -62,12 +62,14 @@ enum { FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ FTP_RETR_PREQUOTE, FTP_STOR_PREQUOTE, + FTP_LIST_PREQUOTE, FTP_POSTQUOTE, FTP_CWD, /* change dir */ FTP_MKD, /* if the dir did not exist */ FTP_MDTM, /* to figure out the datestamp */ FTP_TYPE, /* to set type when doing a head-like request */ FTP_LIST_TYPE, /* set type when about to do a dir list */ + FTP_RETR_LIST_TYPE, FTP_RETR_TYPE, /* set type when about to RETR a file */ FTP_STOR_TYPE, /* set type when about to STOR a file */ FTP_SIZE, /* get the remote file's size for head-like request */ diff --git a/vendor/curl/lib/ftplistparser.c b/vendor/curl/lib/ftplistparser.c index 70939d6a..360f7ae4 100644 --- a/vendor/curl/lib/ftplistparser.c +++ b/vendor/curl/lib/ftplistparser.c @@ -396,407 +396,500 @@ static CURLcode unix_filetype(const char c, curlfiletype *t) return CURLE_OK; } -static CURLcode parse_unix(struct Curl_easy *data, - struct ftp_parselist_data *parser, - struct fileinfo *infop, - const char c) +static CURLcode parse_unix_totalsize(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) { - struct curl_fileinfo *finfo = &infop->info; size_t len = curlx_dyn_len(&infop->buf); char *mem = curlx_dyn_ptr(&infop->buf); - CURLcode result = CURLE_OK; - - switch(parser->state.UNIX.main) { - case PL_UNIX_TOTALSIZE: - switch(parser->state.UNIX.sub.total_dirsize) { - case PL_UNIX_TOTALSIZE_INIT: - if(c == 't') { - parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; - parser->item_length++; - } - else { - parser->state.UNIX.main = PL_UNIX_FILETYPE; - /* continue to fall through */ - } - break; - case PL_UNIX_TOTALSIZE_READING: + switch(parser->state.UNIX.sub.total_dirsize) { + case PL_UNIX_TOTALSIZE_INIT: + if(c == 't') { + parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING; parser->item_length++; - if(c == '\r') { - parser->item_length--; - if(len) - curlx_dyn_setlen(&infop->buf, --len); - } - else if(c == '\n') { - mem[parser->item_length - 1] = 0; - if(!strncmp("total ", mem, 6)) { - const char *endptr = mem + 6; - /* here we can deal with directory size, pass the leading - whitespace and then the digits */ - curlx_str_passblanks(&endptr); - while(ISDIGIT(*endptr)) - endptr++; - if(*endptr) { - return CURLE_FTP_BAD_FILE_LIST; - } - parser->state.UNIX.main = PL_UNIX_FILETYPE; - curlx_dyn_reset(&infop->buf); - } - else + } + else { + parser->state.UNIX.main = PL_UNIX_FILETYPE; + /* continue to fall through */ + } + break; + case PL_UNIX_TOTALSIZE_READING: + parser->item_length++; + if(c == '\r') { + parser->item_length--; + if(len) + curlx_dyn_setlen(&infop->buf, --len); + } + else if(c == '\n') { + mem[parser->item_length - 1] = 0; + if(!strncmp("total ", mem, 6)) { + const char *endptr = mem + 6; + /* here we can deal with directory size, pass the leading + whitespace and then the digits */ + curlx_str_passblanks(&endptr); + while(ISDIGIT(*endptr)) + endptr++; + if(*endptr) { return CURLE_FTP_BAD_FILE_LIST; - + } + parser->state.UNIX.main = PL_UNIX_FILETYPE; + curlx_dyn_reset(&infop->buf); } - break; + else + return CURLE_FTP_BAD_FILE_LIST; + } - if(parser->state.UNIX.main != PL_UNIX_FILETYPE) - break; - FALLTHROUGH(); - case PL_UNIX_FILETYPE: - result = unix_filetype(c, &finfo->filetype); - if(result) - return result; - parser->state.UNIX.main = PL_UNIX_PERMISSION; - parser->item_length = 0; - parser->item_offset = 1; break; - case PL_UNIX_PERMISSION: - parser->item_length++; - if((parser->item_length <= 9) && !strchr("rwx-tTsS", c)) + } + return CURLE_OK; +} + +static CURLcode parse_unix_permission(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + char *mem = curlx_dyn_ptr(&infop->buf); + parser->item_length++; + if((parser->item_length <= 9) && !strchr("rwx-tTsS", c)) + return CURLE_FTP_BAD_FILE_LIST; + + else if(parser->item_length == 10) { + unsigned int perm; + if(c != ' ') return CURLE_FTP_BAD_FILE_LIST; - else if(parser->item_length == 10) { - unsigned int perm; - if(c != ' ') - return CURLE_FTP_BAD_FILE_LIST; + mem[10] = 0; /* terminate permissions */ + perm = ftp_pl_get_permission(mem + parser->item_offset); + if(perm & FTP_LP_MALFORMATED_PERM) + return CURLE_FTP_BAD_FILE_LIST; - mem[10] = 0; /* terminate permissions */ - perm = ftp_pl_get_permission(mem + parser->item_offset); - if(perm & FTP_LP_MALFORMATED_PERM) - return CURLE_FTP_BAD_FILE_LIST; + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; + parser->file_data->info.perm = perm; + parser->offsets.perm = parser->item_offset; - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM; - parser->file_data->info.perm = perm; - parser->offsets.perm = parser->item_offset; + parser->item_length = 0; + parser->state.UNIX.main = PL_UNIX_HLINKS; + parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; + } + return CURLE_OK; +} - parser->item_length = 0; - parser->state.UNIX.main = PL_UNIX_HLINKS; - parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE; +static CURLcode parse_unix_hlinks(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + + switch(parser->state.UNIX.sub.hlinks) { + case PL_UNIX_HLINKS_PRESPACE: + if(c != ' ') { + if(ISDIGIT(c) && len) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; + } + else + return CURLE_FTP_BAD_FILE_LIST; } break; - case PL_UNIX_HLINKS: - switch(parser->state.UNIX.sub.hlinks) { - case PL_UNIX_HLINKS_PRESPACE: - if(c != ' ') { - if(ISDIGIT(c) && len) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER; - } - else - return CURLE_FTP_BAD_FILE_LIST; + case PL_UNIX_HLINKS_NUMBER: + parser->item_length ++; + if(c == ' ') { + const char *p = &mem[parser->item_offset]; + curl_off_t hlinks; + mem[parser->item_offset + parser->item_length - 1] = 0; + + if(!curlx_str_number(&p, &hlinks, LONG_MAX)) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; + parser->file_data->info.hardlinks = (long)hlinks; } - break; - case PL_UNIX_HLINKS_NUMBER: - parser->item_length ++; - if(c == ' ') { - const char *p = &mem[parser->item_offset]; - curl_off_t hlinks; - mem[parser->item_offset + parser->item_length - 1] = 0; + parser->item_length = 0; + parser->item_offset = 0; + parser->state.UNIX.main = PL_UNIX_USER; + parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; + } + else if(!ISDIGIT(c)) + return CURLE_FTP_BAD_FILE_LIST; - if(!curlx_str_number(&p, &hlinks, LONG_MAX)) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT; - parser->file_data->info.hardlinks = (long)hlinks; - } - parser->item_length = 0; - parser->item_offset = 0; - parser->state.UNIX.main = PL_UNIX_USER; - parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE; - } - else if(!ISDIGIT(c)) - return CURLE_FTP_BAD_FILE_LIST; + break; + } + return CURLE_OK; +} - break; +static CURLcode parse_unix_user(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + switch(parser->state.UNIX.sub.user) { + case PL_UNIX_USER_PRESPACE: + if(c != ' ' && len) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; } break; - case PL_UNIX_USER: - switch(parser->state.UNIX.sub.user) { - case PL_UNIX_USER_PRESPACE: - if(c != ' ' && len) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING; - } - break; - case PL_UNIX_USER_PARSING: - parser->item_length++; - if(c == ' ') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.user = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_GROUP; - parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; - parser->item_offset = 0; - parser->item_length = 0; - } - break; + case PL_UNIX_USER_PARSING: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.user = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_GROUP; + parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE; + parser->item_offset = 0; + parser->item_length = 0; } break; - case PL_UNIX_GROUP: - switch(parser->state.UNIX.sub.group) { - case PL_UNIX_GROUP_PRESPACE: - if(c != ' ' && len) { + } + return CURLE_OK; +} + +static CURLcode parse_unix_group(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + switch(parser->state.UNIX.sub.group) { + case PL_UNIX_GROUP_PRESPACE: + if(c != ' ' && len) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; + } + break; + case PL_UNIX_GROUP_NAME: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.group = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_SIZE; + parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; + parser->item_offset = 0; + parser->item_length = 0; + } + break; + } + return CURLE_OK; +} + +static CURLcode parse_unix_size(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + switch(parser->state.UNIX.sub.size) { + case PL_UNIX_SIZE_PRESPACE: + if(c != ' ') { + if(ISDIGIT(c) && len) { parser->item_offset = len - 1; parser->item_length = 1; - parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME; + parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; } - break; - case PL_UNIX_GROUP_NAME: - parser->item_length++; - if(c == ' ') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.group = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_SIZE; - parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE; - parser->item_offset = 0; - parser->item_length = 0; - } - break; + else + return CURLE_FTP_BAD_FILE_LIST; } break; - case PL_UNIX_SIZE: - switch(parser->state.UNIX.sub.size) { - case PL_UNIX_SIZE_PRESPACE: - if(c != ' ') { - if(ISDIGIT(c) && len) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER; + case PL_UNIX_SIZE_NUMBER: + parser->item_length++; + if(c == ' ') { + const char *p = mem + parser->item_offset; + curl_off_t fsize; + mem[parser->item_offset + parser->item_length - 1] = 0; + if(!curlx_str_numblanks(&p, &fsize)) { + if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) { + parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; + parser->file_data->info.size = fsize; } - else - return CURLE_FTP_BAD_FILE_LIST; + parser->item_length = 0; + parser->item_offset = 0; + parser->state.UNIX.main = PL_UNIX_TIME; + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; } - break; - case PL_UNIX_SIZE_NUMBER: - parser->item_length++; - if(c == ' ') { - const char *p = mem + parser->item_offset; - curl_off_t fsize; - mem[parser->item_offset + parser->item_length - 1] = 0; - if(!curlx_str_numblanks(&p, &fsize)) { - if(p[0] == '\0' && fsize != CURL_OFF_T_MAX) { - parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE; - parser->file_data->info.size = fsize; - } - parser->item_length = 0; - parser->item_offset = 0; - parser->state.UNIX.main = PL_UNIX_TIME; - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1; - } + } + else if(!ISDIGIT(c)) + return CURLE_FTP_BAD_FILE_LIST; + + break; + } + return CURLE_OK; +} + +static CURLcode parse_unix_time(struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + struct curl_fileinfo *finfo = &infop->info; + + switch(parser->state.UNIX.sub.time) { + case PL_UNIX_TIME_PREPART1: + if(c != ' ') { + if(ISALNUM(c) && len) { + parser->item_offset = len -1; + parser->item_length = 1; + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; } - else if(!ISDIGIT(c)) + else return CURLE_FTP_BAD_FILE_LIST; - - break; } break; - case PL_UNIX_TIME: - switch(parser->state.UNIX.sub.time) { - case PL_UNIX_TIME_PREPART1: - if(c != ' ') { - if(ISALNUM(c) && len) { - parser->item_offset = len -1; - parser->item_length = 1; - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1; - } - else - return CURLE_FTP_BAD_FILE_LIST; - } - break; - case PL_UNIX_TIME_PART1: - parser->item_length++; - if(c == ' ') - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; + case PL_UNIX_TIME_PART1: + parser->item_length++; + if(c == ' ') + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2; - else if(!ISALNUM(c) && c != '.') - return CURLE_FTP_BAD_FILE_LIST; + else if(!ISALNUM(c) && c != '.') + return CURLE_FTP_BAD_FILE_LIST; - break; - case PL_UNIX_TIME_PREPART2: - parser->item_length++; - if(c != ' ') { - if(ISALNUM(c)) - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; - else - return CURLE_FTP_BAD_FILE_LIST; - } - break; - case PL_UNIX_TIME_PART2: - parser->item_length++; - if(c == ' ') - parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; - else if(!ISALNUM(c) && c != '.') + break; + case PL_UNIX_TIME_PREPART2: + parser->item_length++; + if(c != ' ') { + if(ISALNUM(c)) + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2; + else return CURLE_FTP_BAD_FILE_LIST; - break; - case PL_UNIX_TIME_PREPART3: - parser->item_length++; - if(c != ' ') { - if(ISALNUM(c)) - parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; - else - return CURLE_FTP_BAD_FILE_LIST; - } - break; - case PL_UNIX_TIME_PART3: - parser->item_length++; - if(c == ' ') { - mem[parser->item_offset + parser->item_length -1] = 0; - parser->offsets.time = parser->item_offset; - if(finfo->filetype == CURLFILETYPE_SYMLINK) { - parser->state.UNIX.main = PL_UNIX_SYMLINK; - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; - } - else { - parser->state.UNIX.main = PL_UNIX_FILENAME; - parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; - } - } - else if(!ISALNUM(c) && c != '.' && c != ':') + } + break; + case PL_UNIX_TIME_PART2: + parser->item_length++; + if(c == ' ') + parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3; + else if(!ISALNUM(c) && c != '.') + return CURLE_FTP_BAD_FILE_LIST; + break; + case PL_UNIX_TIME_PREPART3: + parser->item_length++; + if(c != ' ') { + if(ISALNUM(c)) + parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3; + else return CURLE_FTP_BAD_FILE_LIST; - break; } break; - case PL_UNIX_FILENAME: - switch(parser->state.UNIX.sub.filename) { - case PL_UNIX_FILENAME_PRESPACE: - if(c != ' ' && len) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; - } - break; - case PL_UNIX_FILENAME_NAME: - parser->item_length++; - if(c == '\r') - parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; - - else if(c == '\n') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.filename = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_FILETYPE; - result = ftp_pl_insert_finfo(data, infop); - if(result) - return result; + case PL_UNIX_TIME_PART3: + parser->item_length++; + if(c == ' ') { + mem[parser->item_offset + parser->item_length -1] = 0; + parser->offsets.time = parser->item_offset; + if(finfo->filetype == CURLFILETYPE_SYMLINK) { + parser->state.UNIX.main = PL_UNIX_SYMLINK; + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE; } - break; - case PL_UNIX_FILENAME_WINDOWSEOL: - if(c == '\n') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.filename = parser->item_offset; - parser->state.UNIX.main = PL_UNIX_FILETYPE; - result = ftp_pl_insert_finfo(data, infop); - if(result) - return result; + else { + parser->state.UNIX.main = PL_UNIX_FILENAME; + parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE; } - else - return CURLE_FTP_BAD_FILE_LIST; + } + else if(!ISALNUM(c) && c != '.' && c != ':') + return CURLE_FTP_BAD_FILE_LIST; + break; + } + return CURLE_OK; +} - break; +static CURLcode parse_unix_filename(struct Curl_easy *data, + struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + CURLcode result = CURLE_OK; + + switch(parser->state.UNIX.sub.filename) { + case PL_UNIX_FILENAME_PRESPACE: + if(c != ' ' && len) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME; } break; - case PL_UNIX_SYMLINK: - switch(parser->state.UNIX.sub.symlink) { - case PL_UNIX_SYMLINK_PRESPACE: - if(c != ' ' && len) { - parser->item_offset = len - 1; - parser->item_length = 1; - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - } - break; - case PL_UNIX_SYMLINK_NAME: - parser->item_length++; - if(c == ' ') - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; + case PL_UNIX_FILENAME_NAME: + parser->item_length++; + if(c == '\r') + parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL; + + else if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.filename = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_FILETYPE; + result = ftp_pl_insert_finfo(data, infop); + } + break; + case PL_UNIX_FILENAME_WINDOWSEOL: + if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.filename = parser->item_offset; + parser->state.UNIX.main = PL_UNIX_FILETYPE; + result = ftp_pl_insert_finfo(data, infop); + } + else + result = CURLE_FTP_BAD_FILE_LIST; + break; + } + return result; +} - else if(c == '\r' || c == '\n') - return CURLE_FTP_BAD_FILE_LIST; +static CURLcode parse_unix_symlink(struct Curl_easy *data, + struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + size_t len = curlx_dyn_len(&infop->buf); + char *mem = curlx_dyn_ptr(&infop->buf); + CURLcode result = CURLE_OK; - break; - case PL_UNIX_SYMLINK_PRETARGET1: - parser->item_length++; - if(c == '-') - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; + switch(parser->state.UNIX.sub.symlink) { + case PL_UNIX_SYMLINK_PRESPACE: + if(c != ' ' && len) { + parser->item_offset = len - 1; + parser->item_length = 1; + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + } + break; + case PL_UNIX_SYMLINK_NAME: + parser->item_length++; + if(c == ' ') + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1; - else if(c == '\r' || c == '\n') - return CURLE_FTP_BAD_FILE_LIST; - else - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - break; - case PL_UNIX_SYMLINK_PRETARGET2: - parser->item_length++; - if(c == '>') - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; - else if(c == '\r' || c == '\n') - return CURLE_FTP_BAD_FILE_LIST; - else - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + else if(c == '\r' || c == '\n') + return CURLE_FTP_BAD_FILE_LIST; - break; - case PL_UNIX_SYMLINK_PRETARGET3: - parser->item_length++; - if(c == ' ') { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; - /* now place where is symlink following */ - mem[parser->item_offset + parser->item_length - 4] = 0; - parser->offsets.filename = parser->item_offset; - parser->item_length = 0; - parser->item_offset = 0; - } - else if(c == '\r' || c == '\n') - return CURLE_FTP_BAD_FILE_LIST; - else - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - break; - case PL_UNIX_SYMLINK_PRETARGET4: - if(c != '\r' && c != '\n' && len) { - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; - parser->item_offset = len - 1; - parser->item_length = 1; - } - else - return CURLE_FTP_BAD_FILE_LIST; + break; + case PL_UNIX_SYMLINK_PRETARGET1: + parser->item_length++; + if(c == '-') + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2; - break; - case PL_UNIX_SYMLINK_TARGET: - parser->item_length++; - if(c == '\r') - parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; + else if(c == '\r' || c == '\n') + return CURLE_FTP_BAD_FILE_LIST; + else + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + break; + case PL_UNIX_SYMLINK_PRETARGET2: + parser->item_length++; + if(c == '>') + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3; + else if(c == '\r' || c == '\n') + return CURLE_FTP_BAD_FILE_LIST; + else + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; - else if(c == '\n') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.symlink_target = parser->item_offset; - result = ftp_pl_insert_finfo(data, infop); - if(result) - return result; + break; + case PL_UNIX_SYMLINK_PRETARGET3: + parser->item_length++; + if(c == ' ') { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4; + /* now place where is symlink following */ + mem[parser->item_offset + parser->item_length - 4] = 0; + parser->offsets.filename = parser->item_offset; + parser->item_length = 0; + parser->item_offset = 0; + } + else if(c == '\r' || c == '\n') + return CURLE_FTP_BAD_FILE_LIST; + else + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME; + break; + case PL_UNIX_SYMLINK_PRETARGET4: + if(c != '\r' && c != '\n' && len) { + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET; + parser->item_offset = len - 1; + parser->item_length = 1; + } + else + return CURLE_FTP_BAD_FILE_LIST; - parser->state.UNIX.main = PL_UNIX_FILETYPE; - } - break; - case PL_UNIX_SYMLINK_WINDOWSEOL: - if(c == '\n') { - mem[parser->item_offset + parser->item_length - 1] = 0; - parser->offsets.symlink_target = parser->item_offset; - result = ftp_pl_insert_finfo(data, infop); - if(result) - return result; + break; + case PL_UNIX_SYMLINK_TARGET: + parser->item_length++; + if(c == '\r') + parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL; - parser->state.UNIX.main = PL_UNIX_FILETYPE; - } - else - return CURLE_FTP_BAD_FILE_LIST; + else if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.symlink_target = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) + break; + + parser->state.UNIX.main = PL_UNIX_FILETYPE; + } + break; + case PL_UNIX_SYMLINK_WINDOWSEOL: + if(c == '\n') { + mem[parser->item_offset + parser->item_length - 1] = 0; + parser->offsets.symlink_target = parser->item_offset; + result = ftp_pl_insert_finfo(data, infop); + if(result) + break; + + parser->state.UNIX.main = PL_UNIX_FILETYPE; + } + else + result = CURLE_FTP_BAD_FILE_LIST; + + break; + } + return result; +} + +static CURLcode parse_unix(struct Curl_easy *data, + struct ftp_parselist_data *parser, + struct fileinfo *infop, + const char c) +{ + struct curl_fileinfo *finfo = &infop->info; + CURLcode result = CURLE_OK; + switch(parser->state.UNIX.main) { + case PL_UNIX_TOTALSIZE: + result = parse_unix_totalsize(parser, infop, c); + if(result) break; + if(parser->state.UNIX.main != PL_UNIX_FILETYPE) + break; + FALLTHROUGH(); + case PL_UNIX_FILETYPE: + result = unix_filetype(c, &finfo->filetype); + if(!result) { + parser->state.UNIX.main = PL_UNIX_PERMISSION; + parser->item_length = 0; + parser->item_offset = 1; } break; + case PL_UNIX_PERMISSION: + result = parse_unix_permission(parser, infop, c); + break; + case PL_UNIX_HLINKS: + result = parse_unix_hlinks(parser, infop, c); + break; + case PL_UNIX_USER: + result = parse_unix_user(parser, infop, c); + break; + case PL_UNIX_GROUP: + result = parse_unix_group(parser, infop, c); + break; + case PL_UNIX_SIZE: + result = parse_unix_size(parser, infop, c); + break; + case PL_UNIX_TIME: + result = parse_unix_time(parser, infop, c); + break; + case PL_UNIX_FILENAME: + result = parse_unix_filename(data, parser, infop, c); + break; + case PL_UNIX_SYMLINK: + result = parse_unix_symlink(data, parser, infop, c); + break; } - return CURLE_OK; + return result; } static CURLcode parse_winnt(struct Curl_easy *data, diff --git a/vendor/curl/lib/getinfo.c b/vendor/curl/lib/getinfo.c index 388646bf..7ff78d2d 100644 --- a/vendor/curl/lib/getinfo.c +++ b/vendor/curl/lib/getinfo.c @@ -28,6 +28,7 @@ #include "urldata.h" #include "getinfo.h" +#include "cfilters.h" #include "vtls/vtls.h" #include "connect.h" /* Curl_getconnectinfo() */ #include "progress.h" @@ -579,19 +580,14 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **) param_slistp; struct curl_tlssessioninfo *tsi = &data->tsi; -#ifdef USE_SSL - struct connectdata *conn = data->conn; -#endif + /* we are exposing a pointer to internal memory with unknown + * lifetime here. */ *tsip = tsi; - tsi->backend = Curl_ssl_backend(); - tsi->internals = NULL; - -#ifdef USE_SSL - if(conn && tsi->backend != CURLSSLBACKEND_NONE) { - tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0); + if(!Curl_conn_get_ssl_info(data, data->conn, FIRSTSOCKET, tsi)) { + tsi->backend = Curl_ssl_backend(); + tsi->internals = NULL; } -#endif } break; default: diff --git a/vendor/curl/lib/hash.c b/vendor/curl/lib/hash.c index 8d13aae4..89f47ed7 100644 --- a/vendor/curl/lib/hash.c +++ b/vendor/curl/lib/hash.c @@ -353,7 +353,7 @@ size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num) } size_t curlx_str_key_compare(void *k1, size_t key1_len, - void *k2, size_t key2_len) + void *k2, size_t key2_len) { if((key1_len == key2_len) && !memcmp(k1, k2, key1_len)) return 1; diff --git a/vendor/curl/lib/hash.h b/vendor/curl/lib/hash.h index 314b811e..fcd92db6 100644 --- a/vendor/curl/lib/hash.h +++ b/vendor/curl/lib/hash.h @@ -99,7 +99,7 @@ void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user, int (*comp)(void *, void *)); size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num); size_t curlx_str_key_compare(void *k1, size_t key1_len, void *k2, - size_t key2_len); + size_t key2_len); void Curl_hash_start_iterate(struct Curl_hash *hash, struct Curl_hash_iterator *iter); struct Curl_hash_element * diff --git a/vendor/curl/lib/headers.c b/vendor/curl/lib/headers.c index ec3ac747..426d0e57 100644 --- a/vendor/curl/lib/headers.c +++ b/vendor/curl/lib/headers.c @@ -26,7 +26,6 @@ #include "urldata.h" #include "strdup.h" -#include "strcase.h" #include "sendf.h" #include "headers.h" #include "curlx/strparse.h" @@ -88,7 +87,7 @@ CURLHcode curl_easy_header(CURL *easy, /* we need a first round to count amount of this header */ for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) { hs = Curl_node_elem(e); - if(strcasecompare(hs->name, name) && + if(curl_strequal(hs->name, name) && (hs->type & type) && (hs->request == request)) { amount++; @@ -107,7 +106,7 @@ CURLHcode curl_easy_header(CURL *easy, else { for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) { hs = Curl_node_elem(e); - if(strcasecompare(hs->name, name) && + if(curl_strequal(hs->name, name) && (hs->type & type) && (hs->request == request) && (match++ == nameindex)) { @@ -173,7 +172,7 @@ struct curl_header *curl_easy_nextheader(CURL *easy, the index for the currently selected entry */ for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) { struct Curl_header_store *check = Curl_node_elem(e); - if(strcasecompare(hs->name, check->name) && + if(curl_strequal(hs->name, check->name) && (check->request == request) && (check->type & type)) amount++; @@ -217,7 +216,7 @@ static CURLcode namevalue(char *header, size_t hlen, unsigned int type, /* skip all trailing space letters */ while((end > header) && ISBLANK(*end)) - *end-- = 0; /* nul terminate */ + *end-- = 0; /* null-terminate */ return CURLE_OK; } @@ -323,7 +322,7 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, if(!hs) return CURLE_OUT_OF_MEMORY; memcpy(hs->buffer, header, hlen); - hs->buffer[hlen] = 0; /* nul terminate */ + hs->buffer[hlen] = 0; /* null-terminate */ result = namevalue(hs->buffer, hlen, type, &name, &value); if(!result) { diff --git a/vendor/curl/lib/hostip.c b/vendor/curl/lib/hostip.c index ca6724ed..191aaeb8 100644 --- a/vendor/curl/lib/hostip.c +++ b/vendor/curl/lib/hostip.c @@ -54,7 +54,7 @@ #include "rand.h" #include "share.h" #include "url.h" -#include "inet_ntop.h" +#include "curlx/inet_ntop.h" #include "curlx/inet_pton.h" #include "multiif.h" #include "doh.h" @@ -145,14 +145,14 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf, case AF_INET: { const struct sockaddr_in *sa4 = (const void *)ai->ai_addr; const struct in_addr *ipaddr4 = &sa4->sin_addr; - (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize); + (void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize); break; } #ifdef USE_IPV6 case AF_INET6: { const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr; const struct in6_addr *ipaddr6 = &sa6->sin6_addr; - (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize); + (void)curlx_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize); break; } #endif @@ -505,6 +505,8 @@ Curl_dnscache_mk_entry(struct Curl_easy *data, return NULL; } } +#else + (void)data; #endif if(!hostlen) hostlen = strlen(hostname); @@ -730,7 +732,7 @@ static bool tailmatch(const char *full, size_t flen, { if(plen > flen) return FALSE; - return strncasecompare(part, &full[flen - plen], plen); + return curl_strnequal(part, &full[flen - plen], plen); } static struct Curl_addrinfo * @@ -872,8 +874,8 @@ CURLcode Curl_resolv(struct Curl_easy *data, goto error; if(!is_ipaddr && - (strcasecompare(hostname, "localhost") || - strcasecompare(hostname, "localhost.") || + (curl_strequal(hostname, "localhost") || + curl_strequal(hostname, "localhost.") || tailmatch(hostname, hostname_len, STRCONST(".localhost")) || tailmatch(hostname, hostname_len, STRCONST(".localhost.")))) { addr = get_localhost(port, hostname); diff --git a/vendor/curl/lib/hostip6.c b/vendor/curl/lib/hostip6.c index 35cc2d73..ce7f5050 100644 --- a/vendor/curl/lib/hostip6.c +++ b/vendor/curl/lib/hostip6.c @@ -44,6 +44,7 @@ #endif #include "urldata.h" +#include "cfilters.h" #include "sendf.h" #include "hostip.h" #include "hash.h" @@ -104,7 +105,8 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; - hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ? + hints.ai_socktype = + (Curl_conn_get_transport(data, data->conn) == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; #ifndef USE_RESOLVE_ON_IPS diff --git a/vendor/curl/lib/hsts.c b/vendor/curl/lib/hsts.c index ccfc55dd..91f32276 100644 --- a/vendor/curl/lib/hsts.c +++ b/vendor/curl/lib/hsts.c @@ -33,7 +33,6 @@ #include "llist.h" #include "hsts.h" #include "curl_get_line.h" -#include "strcase.h" #include "sendf.h" #include "parsedate.h" #include "fopen.h" @@ -155,7 +154,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, do { curlx_str_passblanks(&p); - if(strncasecompare("max-age", p, 7)) { + if(curl_strnequal("max-age", p, 7)) { bool quoted = FALSE; int rc; @@ -185,7 +184,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, } gotma = TRUE; } - else if(strncasecompare("includesubdomains", p, 17)) { + else if(curl_strnequal("includesubdomains", p, 17)) { if(gotinc) return CURLE_BAD_FUNCTION_ARGUMENT; subdomains = TRUE; @@ -272,15 +271,15 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, if((subdomain && sts->includeSubDomains) && (ntail < hlen)) { size_t offs = hlen - ntail; if((hostname[offs-1] == '.') && - strncasecompare(&hostname[offs], sts->host, ntail) && + curl_strnequal(&hostname[offs], sts->host, ntail) && (ntail > blen)) { /* save the tail match with the longest tail */ bestsub = sts; blen = ntail; } } - /* avoid strcasecompare because the host name is not null terminated */ - if((hlen == ntail) && strncasecompare(hostname, sts->host, hlen)) + /* avoid curl_strequal because the host name is not null-terminated */ + if((hlen == ntail) && curl_strnequal(hostname, sts->host, hlen)) return sts; } } @@ -430,7 +429,7 @@ static CURLcode hsts_add(struct hsts *h, const char *line) time_t expires; const char *hp = curlx_str(&host); - /* The date parser works on a null terminated string. The maximum length + /* The date parser works on a null-terminated string. The maximum length is upheld by curlx_str_quotedword(). */ memcpy(dbuf, curlx_str(&date), curlx_strlen(&date)); dbuf[curlx_strlen(&date)] = 0; @@ -581,4 +580,8 @@ void Curl_hsts_loadfiles(struct Curl_easy *data) } } +#if defined(DEBUGBUILD) || defined(UNITTESTS) +#undef time +#endif + #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ diff --git a/vendor/curl/lib/http.c b/vendor/curl/lib/http.c index 8c593f5a..e5a06962 100644 --- a/vendor/curl/lib/http.c +++ b/vendor/curl/lib/http.c @@ -232,7 +232,7 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data, connkeep(conn, "HTTP default"); if(data->state.http_neg.wanted == CURL_HTTP_V3x) { /* only HTTP/3, needs to work */ - CURLcode result = Curl_conn_may_http3(data, conn); + CURLcode result = Curl_conn_may_http3(data, conn, conn->transport_wanted); if(result) return result; } @@ -259,7 +259,7 @@ char *Curl_checkProxyheaders(struct Curl_easy *data, for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; head; head = head->next) { - if(strncasecompare(head->data, thisheader, thislen) && + if(curl_strnequal(head->data, thisheader, thislen) && Curl_headersep(head->data[thislen])) return head->data; } @@ -862,7 +862,7 @@ static bool authcmp(const char *auth, const char *line) { /* the auth string must not have an alnum following */ size_t n = strlen(auth); - return strncasecompare(auth, line, n) && !ISALNUM(line[n]); + return curl_strnequal(auth, line, n) && !ISALNUM(line[n]); } #endif @@ -1176,6 +1176,8 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, bool reachedmax = FALSE; char *follow_url = NULL; CURLUcode uc; + CURLcode rewind_result; + bool switch_to_get = FALSE; DEBUGASSERT(type != FOLLOW_NONE); @@ -1333,7 +1335,7 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, data->state.url = follow_url; data->state.url_alloc = TRUE; - Curl_req_soft_reset(&data->req, data); + rewind_result = Curl_req_soft_reset(&data->req, data); infof(data, "Issue another request to this URL: '%s'", data->state.url); if((data->set.http_follow_mode == CURLFOLLOW_FIRSTONLY) && data->set.str[STRING_CUSTOMREQUEST] && @@ -1382,8 +1384,10 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, if((data->state.httpreq == HTTPREQ_POST || data->state.httpreq == HTTPREQ_POST_FORM || data->state.httpreq == HTTPREQ_POST_MIME) - && !(data->set.keep_post & CURL_REDIR_POST_301)) + && !(data->set.keep_post & CURL_REDIR_POST_301)) { http_switch_to_get(data, 301); + switch_to_get = TRUE; + } break; case 302: /* Found */ /* (quote from RFC7231, section 6.4.3) @@ -1405,8 +1409,10 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, if((data->state.httpreq == HTTPREQ_POST || data->state.httpreq == HTTPREQ_POST_FORM || data->state.httpreq == HTTPREQ_POST_MIME) - && !(data->set.keep_post & CURL_REDIR_POST_302)) + && !(data->set.keep_post & CURL_REDIR_POST_302)) { http_switch_to_get(data, 302); + switch_to_get = TRUE; + } break; case 303: /* See Other */ @@ -1419,8 +1425,10 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, ((data->state.httpreq != HTTPREQ_POST && data->state.httpreq != HTTPREQ_POST_FORM && data->state.httpreq != HTTPREQ_POST_MIME) || - !(data->set.keep_post & CURL_REDIR_POST_303))) + !(data->set.keep_post & CURL_REDIR_POST_303))) { http_switch_to_get(data, 303); + switch_to_get = TRUE; + } break; case 304: /* Not Modified */ /* 304 means we did a conditional request and it was "Not modified". @@ -1437,6 +1445,12 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, */ break; } + + /* When rewind of upload data failed and we are not switching to GET, + * we need to fail the follow, as we cannot send the data again. */ + if(rewind_result && !switch_to_get) + return rewind_result; + Curl_pgrsTime(data, TIMER_REDIRECT); Curl_pgrsResetTransferSizes(data); @@ -1468,7 +1482,7 @@ Curl_compareheader(const char *headerline, /* line to check */ DEBUGASSERT(header); DEBUGASSERT(content); - if(!strncasecompare(headerline, header, hlen)) + if(!curl_strnequal(headerline, header, hlen)) return FALSE; /* does not start with header */ /* pass the header */ @@ -1483,7 +1497,7 @@ Curl_compareheader(const char *headerline, /* line to check */ size_t len; p = curlx_str(&val); for(len = curlx_strlen(&val); len >= curlx_strlen(&val); len--, p++) { - if(strncasecompare(p, content, clen)) + if(curl_strnequal(p, content, clen)) return TRUE; /* match! */ } } @@ -1879,7 +1893,7 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn) ptr = Curl_checkheaders(data, STRCONST("Host")); if(ptr && (!data->state.this_is_a_follow || - strcasecompare(data->state.first_host, conn->host.name))) { + curl_strequal(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) /* If we have a given custom Host: header, we extract the hostname in order to possibly use it for cookie reasons later on. We only allow the @@ -1915,7 +1929,7 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn) } #endif - if(!strcasecompare("Host:", ptr)) { + if(!curl_strequal("Host:", ptr)) { aptr->host = aprintf("Host:%s\r\n", &ptr[5]); if(!aptr->host) return CURLE_OUT_OF_MEMORY; @@ -1991,7 +2005,7 @@ static CURLcode http_target(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - if(strcasecompare("http", data->state.up.scheme)) { + if(curl_strequal("http", data->state.up.scheme)) { /* when getting HTTP, we do not want the userinfo the URL */ uc = curl_url_set(h, CURLUPART_USER, NULL, 0); if(uc) { @@ -2020,7 +2034,7 @@ static CURLcode http_target(struct Curl_easy *data, if(result) return result; - if(strcasecompare("ftp", data->state.up.scheme)) { + if(curl_strequal("ftp", data->state.up.scheme)) { if(data->set.proxy_transfer_mode) { /* when doing ftp, append ;type= if not present */ char *type = strstr(path, ";type="); @@ -2429,7 +2443,7 @@ static CURLcode http_cookies(struct Curl_easy *data, data->state.aptr.cookiehost : conn->host.name; const bool secure_context = conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || - strcasecompare("localhost", host) || + curl_strequal("localhost", host) || !strcmp(host, "127.0.0.1") || !strcmp(host, "::1"); Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); @@ -2987,376 +3001,488 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, Curl_compareheader(hd, STRCONST(n), STRCONST(v))) /* - * http_header() parses a single response header. + * http_header_a() parses a single response header starting with A. */ -static CURLcode http_header(struct Curl_easy *data, - const char *hd, size_t hdlen) +static CURLcode http_header_a(struct Curl_easy *data, + const char *hd, size_t hdlen) { - struct connectdata *conn = data->conn; - CURLcode result; - struct SingleRequest *k = &data->req; - const char *v; - - switch(hd[0]) { - case 'a': - case 'A': #ifndef CURL_DISABLE_ALTSVC - v = (data->asi && - (Curl_conn_is_ssl(data->conn, FIRSTSOCKET) || + const char *v; + struct connectdata *conn = data->conn; + v = (data->asi && + (Curl_conn_is_ssl(data->conn, FIRSTSOCKET) || #ifdef DEBUGBUILD - /* allow debug builds to circumvent the HTTPS restriction */ - getenv("CURL_ALTSVC_HTTP") + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_ALTSVC_HTTP") #else - 0 + 0 #endif - )) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL; - if(v) { - /* the ALPN of the current request */ - enum alpnid id = (k->httpversion == 30) ? ALPN_h3 : - (k->httpversion == 20) ? ALPN_h2 : ALPN_h1; - return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name, - curlx_uitous((unsigned int)conn->remote_port)); - } + )) ? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL; + if(v) { + /* the ALPN of the current request */ + struct SingleRequest *k = &data->req; + enum alpnid id = (k->httpversion == 30) ? ALPN_h3 : + (k->httpversion == 20) ? ALPN_h2 : ALPN_h1; + return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name, + curlx_uitous((unsigned int)conn->remote_port)); + } +#else + (void)data; + (void)hd; + (void)hdlen; #endif - break; - case 'c': - case 'C': - /* Check for Content-Length: header lines to get size */ - v = (!k->http_bodyless && !data->set.ignorecl) ? - HD_VAL(hd, hdlen, "Content-Length:") : NULL; - if(v) { - curl_off_t contentlength; - int offt = curlx_str_numblanks(&v, &contentlength); - - if(offt == STRE_OK) { - k->size = contentlength; - k->maxdownload = k->size; - } - else if(offt == STRE_OVERFLOW) { - /* out of range */ - if(data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - streamclose(conn, "overflow content-length"); - infof(data, "Overflow Content-Length: value"); - } - else { - /* negative or just rubbish - bad HTTP */ - failf(data, "Invalid Content-Length: value"); - return CURLE_WEIRD_SERVER_REPLY; - } - return CURLE_OK; - } - v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ? - HD_VAL(hd, hdlen, "Content-Encoding:") : NULL; - if(v) { - /* - * Process Content-Encoding. Look for the values: identity, - * gzip, deflate, compress, x-gzip and x-compress. x-gzip and - * x-compress are the same as gzip and compress. (Sec 3.5 RFC - * 2616). zlib cannot handle compress. However, errors are - * handled further down when the response body is processed - */ - return Curl_build_unencoding_stack(data, v, FALSE); + return CURLE_OK; +} + +/* + * http_header_c() parses a single response header starting with C. + */ +static CURLcode http_header_c(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + struct connectdata *conn = data->conn; + struct SingleRequest *k = &data->req; + const char *v; + + /* Check for Content-Length: header lines to get size */ + v = (!k->http_bodyless && !data->set.ignorecl) ? + HD_VAL(hd, hdlen, "Content-Length:") : NULL; + if(v) { + curl_off_t contentlength; + int offt = curlx_str_numblanks(&v, &contentlength); + + if(offt == STRE_OK) { + k->size = contentlength; + k->maxdownload = k->size; } - /* check for Content-Type: header lines to get the MIME-type */ - v = HD_VAL(hd, hdlen, "Content-Type:"); - if(v) { - char *contenttype = Curl_copy_header_value(hd); - if(!contenttype) - return CURLE_OUT_OF_MEMORY; - if(!*contenttype) - /* ignore empty data */ - free(contenttype); - else { - free(data->info.contenttype); - data->info.contenttype = contenttype; + else if(offt == STRE_OVERFLOW) { + /* out of range */ + if(data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; } - return CURLE_OK; + streamclose(conn, "overflow content-length"); + infof(data, "Overflow Content-Length: value"); } - if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) { - /* - * [RFC 2616, section 8.1.2.1] - * "Connection: close" is HTTP/1.1 language and means that - * the connection will close when this request has been - * served. - */ - streamclose(conn, "Connection: close used"); - return CURLE_OK; - } - if((k->httpversion == 10) && - HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) { - /* - * An HTTP/1.0 reply with the 'Connection: keep-alive' line - * tells us the connection will be kept alive for our - * pleasure. Default action for 1.0 is to close. - * - * [RFC2068, section 19.7.1] */ - connkeep(conn, "Connection keep-alive"); - infof(data, "HTTP/1.0 connection set to keep alive"); - return CURLE_OK; + else { + /* negative or just rubbish - bad HTTP */ + failf(data, "Invalid Content-Length: value"); + return CURLE_WEIRD_SERVER_REPLY; } - v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL; - if(v) { - /* Content-Range: bytes [num]- - Content-Range: bytes: [num]- - Content-Range: [num]- - Content-Range: [asterisk]/[total] - - The second format was added since Sun's webserver - JavaWebServer/1.1.1 obviously sends the header this way! - The third added since some servers use that! - The fourth means the requested range was unsatisfied. - */ - - const char *ptr = v; - - /* Move forward until first digit or asterisk */ - while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') - ptr++; - - /* if it truly stopped on a digit */ - if(ISDIGIT(*ptr)) { - if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) && - (data->state.resume_from == k->offset)) - /* we asked for a resume and we got it */ - k->content_range = TRUE; - } - else if(k->httpcode < 300) - data->state.resume_from = 0; /* get everything */ + return CURLE_OK; + } + v = (!k->http_bodyless && data->set.str[STRING_ENCODING]) ? + HD_VAL(hd, hdlen, "Content-Encoding:") : NULL; + if(v) { + /* + * Process Content-Encoding. Look for the values: identity, + * gzip, deflate, compress, x-gzip and x-compress. x-gzip and + * x-compress are the same as gzip and compress. (Sec 3.5 RFC + * 2616). zlib cannot handle compress. However, errors are + * handled further down when the response body is processed + */ + return Curl_build_unencoding_stack(data, v, FALSE); + } + /* check for Content-Type: header lines to get the MIME-type */ + v = HD_VAL(hd, hdlen, "Content-Type:"); + if(v) { + char *contenttype = Curl_copy_header_value(hd); + if(!contenttype) + return CURLE_OUT_OF_MEMORY; + if(!*contenttype) + /* ignore empty data */ + free(contenttype); + else { + free(data->info.contenttype); + data->info.contenttype = contenttype; } - break; - case 'l': - case 'L': - v = (!k->http_bodyless && - (data->set.timecondition || data->set.get_filetime)) ? - HD_VAL(hd, hdlen, "Last-Modified:") : NULL; - if(v) { - k->timeofdoc = Curl_getdate_capped(v); - if(data->set.get_filetime) - data->info.filetime = k->timeofdoc; - return CURLE_OK; + return CURLE_OK; + } + if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) { + /* + * [RFC 2616, section 8.1.2.1] + * "Connection: close" is HTTP/1.1 language and means that + * the connection will close when this request has been + * served. + */ + streamclose(conn, "Connection: close used"); + return CURLE_OK; + } + if((k->httpversion == 10) && + HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) { + /* + * An HTTP/1.0 reply with the 'Connection: keep-alive' line + * tells us the connection will be kept alive for our + * pleasure. Default action for 1.0 is to close. + * + * [RFC2068, section 19.7.1] */ + connkeep(conn, "Connection keep-alive"); + infof(data, "HTTP/1.0 connection set to keep alive"); + return CURLE_OK; + } + v = !k->http_bodyless ? HD_VAL(hd, hdlen, "Content-Range:") : NULL; + if(v) { + /* Content-Range: bytes [num]- + Content-Range: bytes: [num]- + Content-Range: [num]- + Content-Range: [asterisk]/[total] + + The second format was added since Sun's webserver + JavaWebServer/1.1.1 obviously sends the header this way! + The third added since some servers use that! + The fourth means the requested range was unsatisfied. + */ + + const char *ptr = v; + + /* Move forward until first digit or asterisk */ + while(*ptr && !ISDIGIT(*ptr) && *ptr != '*') + ptr++; + + /* if it truly stopped on a digit */ + if(ISDIGIT(*ptr)) { + if(!curlx_str_number(&ptr, &k->offset, CURL_OFF_T_MAX) && + (data->state.resume_from == k->offset)) + /* we asked for a resume and we got it */ + k->content_range = TRUE; } - if((k->httpcode >= 300 && k->httpcode < 400) && - HD_IS(hd, hdlen, "Location:") && - !data->req.location) { - /* this is the URL that the server advises us to use instead */ - char *location = Curl_copy_header_value(hd); - if(!location) - return CURLE_OUT_OF_MEMORY; - if(!*location) - /* ignore empty data */ - free(location); - else { - data->req.location = location; + else if(k->httpcode < 300) + data->state.resume_from = 0; /* get everything */ + } + return CURLE_OK; +} - if(data->set.http_follow_mode) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->req.location); /* clone */ - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; +/* + * http_header_l() parses a single response header starting with L. + */ +static CURLcode http_header_l(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + struct connectdata *conn = data->conn; + struct SingleRequest *k = &data->req; + const char *v = (!k->http_bodyless && + (data->set.timecondition || data->set.get_filetime)) ? + HD_VAL(hd, hdlen, "Last-Modified:") : NULL; + if(v) { + k->timeofdoc = Curl_getdate_capped(v); + if(data->set.get_filetime) + data->info.filetime = k->timeofdoc; + return CURLE_OK; + } + if((k->httpcode >= 300 && k->httpcode < 400) && + HD_IS(hd, hdlen, "Location:") && + !data->req.location) { + /* this is the URL that the server advises us to use instead */ + char *location = Curl_copy_header_value(hd); + if(!location) + return CURLE_OUT_OF_MEMORY; + if(!*location) + /* ignore empty data */ + free(location); + else { + data->req.location = location; - /* some cases of POST and PUT etc needs to rewind the data - stream at this point */ - result = http_perhapsrewind(data, conn); - if(result) - return result; + if(data->set.http_follow_mode) { + CURLcode result; + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->req.location); /* clone */ + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; - /* mark the next request as a followed location: */ - data->state.this_is_a_follow = TRUE; - } + /* some cases of POST and PUT etc needs to rewind the data + stream at this point */ + result = http_perhapsrewind(data, conn); + if(result) + return result; + + /* mark the next request as a followed location: */ + data->state.this_is_a_follow = TRUE; } } - break; - case 'p': - case 'P': + } + return CURLE_OK; +} + +/* + * http_header_p() parses a single response header starting with P. + */ +static CURLcode http_header_p(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + struct SingleRequest *k = &data->req; + #ifndef CURL_DISABLE_PROXY - v = HD_VAL(hd, hdlen, "Proxy-Connection:"); - if(v) { - if((k->httpversion == 10) && conn->bits.httpproxy && - HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) { - /* - * When an HTTP/1.0 reply comes when using a proxy, the - * 'Proxy-Connection: keep-alive' line tells us the - * connection will be kept alive for our pleasure. - * Default action for 1.0 is to close. - */ - connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */ - infof(data, "HTTP/1.0 proxy connection set to keep alive"); - } - else if((k->httpversion == 11) && conn->bits.httpproxy && - HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) { - /* - * We get an HTTP/1.1 response from a proxy and it says it will - * close down after this transfer. - */ - connclose(conn, "Proxy-Connection: asked to close after done"); - infof(data, "HTTP/1.1 proxy connection set close"); - } - return CURLE_OK; + const char *v = HD_VAL(hd, hdlen, "Proxy-Connection:"); + if(v) { + struct connectdata *conn = data->conn; + if((k->httpversion == 10) && conn->bits.httpproxy && + HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) { + /* + * When an HTTP/1.0 reply comes when using a proxy, the + * 'Proxy-Connection: keep-alive' line tells us the + * connection will be kept alive for our pleasure. + * Default action for 1.0 is to close. + */ + connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */ + infof(data, "HTTP/1.0 proxy connection set to keep alive"); } -#endif - if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) { - char *auth = Curl_copy_header_value(hd); - if(!auth) - return CURLE_OUT_OF_MEMORY; - result = Curl_http_input_auth(data, TRUE, auth); - free(auth); - return result; + else if((k->httpversion == 11) && conn->bits.httpproxy && + HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) { + /* + * We get an HTTP/1.1 response from a proxy and it says it will + * close down after this transfer. + */ + connclose(conn, "Proxy-Connection: asked to close after done"); + infof(data, "HTTP/1.1 proxy connection set close"); } + return CURLE_OK; + } +#endif + if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) { + char *auth = Curl_copy_header_value(hd); + CURLcode result; + if(!auth) + return CURLE_OUT_OF_MEMORY; + result = Curl_http_input_auth(data, TRUE, auth); + free(auth); + return result; + } #ifdef USE_SPNEGO - if(HD_IS(hd, hdlen, "Persistent-Auth:")) { - struct negotiatedata *negdata = &conn->negotiate; - struct auth *authp = &data->state.authhost; - if(authp->picked == CURLAUTH_NEGOTIATE) { - char *persistentauth = Curl_copy_header_value(hd); - if(!persistentauth) - return CURLE_OUT_OF_MEMORY; - negdata->noauthpersist = !!checkprefix("false", persistentauth); - negdata->havenoauthpersist = TRUE; - infof(data, "Negotiate: noauthpersist -> %d, header part: %s", - negdata->noauthpersist, persistentauth); - free(persistentauth); - } + if(HD_IS(hd, hdlen, "Persistent-Auth:")) { + struct connectdata *conn = data->conn; + struct negotiatedata *negdata = Curl_auth_nego_get(conn, FALSE); + struct auth *authp = &data->state.authhost; + if(!negdata) + return CURLE_OUT_OF_MEMORY; + if(authp->picked == CURLAUTH_NEGOTIATE) { + char *persistentauth = Curl_copy_header_value(hd); + if(!persistentauth) + return CURLE_OUT_OF_MEMORY; + negdata->noauthpersist = !!checkprefix("false", persistentauth); + negdata->havenoauthpersist = TRUE; + infof(data, "Negotiate: noauthpersist -> %d, header part: %s", + negdata->noauthpersist, persistentauth); + free(persistentauth); } + } #endif - break; - case 'r': - case 'R': - v = HD_VAL(hd, hdlen, "Retry-After:"); - if(v) { - /* Retry-After = HTTP-date / delay-seconds */ - curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date; - curlx_str_passblanks(&v); - - /* try it as a date first, because a date can otherwise start with and - get treated as a number */ - date = Curl_getdate_capped(v); - - if((time_t)-1 != date) { - time_t current = time(NULL); - if(date >= current) - /* convert date to number of seconds into the future */ - retry_after = date - current; - } - else - /* Try it as a decimal number */ - curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX); - /* limit to 6 hours max. this is not documented so that it can be changed - in the future if necessary. */ - if(retry_after > 21600) - retry_after = 21600; - data->info.retry_after = retry_after; - return CURLE_OK; - } - break; - case 's': - case 'S': -#if !defined(CURL_DISABLE_COOKIES) - v = (data->cookies && data->state.cookie_engine) ? - HD_VAL(hd, hdlen, "Set-Cookie:") : NULL; - if(v) { - /* If there is a custom-set Host: name, use it here, or else use - * real peer hostname. */ - const char *host = data->state.aptr.cookiehost ? - data->state.aptr.cookiehost : conn->host.name; - const bool secure_context = - conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || - strcasecompare("localhost", host) || - !strcmp(host, "127.0.0.1") || - !strcmp(host, "::1"); + return CURLE_OK; +} - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, - CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host, - data->state.up.path, secure_context); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - return CURLE_OK; +/* + * http_header_r() parses a single response header starting with R. + */ +static CURLcode http_header_r(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + const char *v = HD_VAL(hd, hdlen, "Retry-After:"); + if(v) { + /* Retry-After = HTTP-date / delay-seconds */ + curl_off_t retry_after = 0; /* zero for unknown or "now" */ + time_t date; + curlx_str_passblanks(&v); + + /* try it as a date first, because a date can otherwise start with and + get treated as a number */ + date = Curl_getdate_capped(v); + + if((time_t)-1 != date) { + time_t current = time(NULL); + if(date >= current) + /* convert date to number of seconds into the future */ + retry_after = date - current; } + else + /* Try it as a decimal number, ignore errors */ + (void)curlx_str_number(&v, &retry_after, CURL_OFF_T_MAX); + /* limit to 6 hours max. this is not documented so that it can be changed + in the future if necessary. */ + if(retry_after > 21600) + retry_after = 21600; + data->info.retry_after = retry_after; + } + return CURLE_OK; +} + +/* + * http_header_s() parses a single response header starting with S. + */ +static CURLcode http_header_s(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ +#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_HSTS) + struct connectdata *conn = data->conn; + const char *v; +#else + (void)data; + (void)hd; + (void)hdlen; +#endif + +#if !defined(CURL_DISABLE_COOKIES) + v = (data->cookies && data->state.cookie_engine) ? + HD_VAL(hd, hdlen, "Set-Cookie:") : NULL; + if(v) { + /* If there is a custom-set Host: name, use it here, or else use + * real peer hostname. */ + const char *host = data->state.aptr.cookiehost ? + data->state.aptr.cookiehost : conn->host.name; + const bool secure_context = + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || + curl_strequal("localhost", host) || + !strcmp(host, "127.0.0.1") || + !strcmp(host, "::1"); + + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, + CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host, + data->state.up.path, secure_context); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + return CURLE_OK; + } #endif #ifndef CURL_DISABLE_HSTS - /* If enabled, the header is incoming and this is over HTTPS */ - v = (data->hsts && - (Curl_conn_is_ssl(conn, FIRSTSOCKET) || + /* If enabled, the header is incoming and this is over HTTPS */ + v = (data->hsts && + (Curl_conn_is_ssl(conn, FIRSTSOCKET) || #ifdef DEBUGBUILD - /* allow debug builds to circumvent the HTTPS restriction */ - getenv("CURL_HSTS_HTTP") + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_HSTS_HTTP") #else - 0 + 0 #endif - ) - ) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL; - if(v) { - CURLcode check = - Curl_hsts_parse(data->hsts, conn->host.name, v); - if(check) - infof(data, "Illegal STS header skipped"); + ) + ) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL; + if(v) { + CURLcode check = + Curl_hsts_parse(data->hsts, conn->host.name, v); + if(check) + infof(data, "Illegal STS header skipped"); #ifdef DEBUGBUILD - else - infof(data, "Parsed STS header fine (%zu entries)", - Curl_llist_count(&data->hsts->list)); + else + infof(data, "Parsed STS header fine (%zu entries)", + Curl_llist_count(&data->hsts->list)); #endif - } + } #endif + + return CURLE_OK; +} + +/* + * http_header_t() parses a single response header starting with T. + */ +static CURLcode http_header_t(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + struct connectdata *conn = data->conn; + struct SingleRequest *k = &data->req; + + /* RFC 9112, ch. 6.1 + * "Transfer-Encoding MAY be sent in a response to a HEAD request or + * in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a + * GET request, neither of which includes a message body, to indicate + * that the origin server would have applied a transfer coding to the + * message body if the request had been an unconditional GET." + * + * Read: in these cases the 'Transfer-Encoding' does not apply + * to any data following the response headers. Do not add any decoders. + */ + const char *v = (!k->http_bodyless && + (data->state.httpreq != HTTPREQ_HEAD) && + (k->httpcode != 304)) ? + HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL; + if(v) { + /* One or more encodings. We check for chunked and/or a compression + algorithm. */ + CURLcode result = Curl_build_unencoding_stack(data, v, TRUE); + if(result) + return result; + if(!k->chunk && data->set.http_transfer_encoding) { + /* if this is not chunked, only close can signal the end of this + * transfer as Content-Length is said not to be trusted for + * transfer-encoding! */ + connclose(conn, "HTTP/1.1 transfer-encoding without chunks"); + k->ignore_cl = TRUE; + } + return CURLE_OK; + } + v = HD_VAL(hd, hdlen, "Trailer:"); + if(v) { + data->req.resp_trailer = TRUE; + return CURLE_OK; + } + return CURLE_OK; +} + +/* + * http_header_w() parses a single response header starting with W. + */ +static CURLcode http_header_w(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + struct SingleRequest *k = &data->req; + CURLcode result = CURLE_OK; + + if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) { + char *auth = Curl_copy_header_value(hd); + if(!auth) + return CURLE_OUT_OF_MEMORY; + result = Curl_http_input_auth(data, FALSE, auth); + free(auth); + } + return result; +} + +/* + * http_header() parses a single response header. + */ +static CURLcode http_header(struct Curl_easy *data, + const char *hd, size_t hdlen) +{ + CURLcode result = CURLE_OK; + + switch(hd[0]) { + case 'a': + case 'A': + result = http_header_a(data, hd, hdlen); + break; + case 'c': + case 'C': + result = http_header_c(data, hd, hdlen); + break; + case 'l': + case 'L': + result = http_header_l(data, hd, hdlen); + break; + case 'p': + case 'P': + result = http_header_p(data, hd, hdlen); + break; + case 'r': + case 'R': + result = http_header_r(data, hd, hdlen); + break; + case 's': + case 'S': + result = http_header_s(data, hd, hdlen); break; case 't': case 'T': - /* RFC 9112, ch. 6.1 - * "Transfer-Encoding MAY be sent in a response to a HEAD request or - * in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a - * GET request, neither of which includes a message body, to indicate - * that the origin server would have applied a transfer coding to the - * message body if the request had been an unconditional GET." - * - * Read: in these cases the 'Transfer-Encoding' does not apply - * to any data following the response headers. Do not add any decoders. - */ - v = (!k->http_bodyless && - (data->state.httpreq != HTTPREQ_HEAD) && - (k->httpcode != 304)) ? - HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL; - if(v) { - /* One or more encodings. We check for chunked and/or a compression - algorithm. */ - result = Curl_build_unencoding_stack(data, v, TRUE); - if(result) - return result; - if(!k->chunk && data->set.http_transfer_encoding) { - /* if this is not chunked, only close can signal the end of this - * transfer as Content-Length is said not to be trusted for - * transfer-encoding! */ - connclose(conn, "HTTP/1.1 transfer-encoding without chunks"); - k->ignore_cl = TRUE; - } - return CURLE_OK; - } - v = HD_VAL(hd, hdlen, "Trailer:"); - if(v) { - data->req.resp_trailer = TRUE; - return CURLE_OK; - } + result = http_header_t(data, hd, hdlen); break; case 'w': case 'W': - if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) { - char *auth = Curl_copy_header_value(hd); - if(!auth) - return CURLE_OUT_OF_MEMORY; - result = Curl_http_input_auth(data, FALSE, auth); - free(auth); - return result; - } + result = http_header_w(data, hd, hdlen); break; } - if(conn->handler->protocol & CURLPROTO_RTSP) { - result = Curl_rtsp_parseheader(data, hd); - if(result) - return result; + if(!result) { + struct connectdata *conn = data->conn; + if(conn->handler->protocol & CURLPROTO_RTSP) + result = Curl_rtsp_parseheader(data, hd); } - return CURLE_OK; + return result; } /* @@ -3624,7 +3750,7 @@ static CURLcode http_on_response(struct Curl_easy *data, /* We expect more response from HTTP/2 later */ k->header = TRUE; k->headerline = 0; /* restart the header line counter */ - k->httpversion_sent = 20; /* It's a HTTP/2 request now */ + k->httpversion_sent = 20; /* It's an HTTP/2 request now */ /* Any remaining `buf` bytes are already HTTP/2 and passed to * be processed. */ result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen); @@ -3836,9 +3962,8 @@ static CURLcode http_on_response(struct Curl_easy *data, out: if(last_hd) { /* if not written yet, write it now */ - CURLcode r2 = http_write_header(data, last_hd, last_hd_len); - if(!result) - result = r2; + result = Curl_1st_err( + result, http_write_header(data, last_hd, last_hd_len)); } return result; } @@ -4460,7 +4585,7 @@ static bool h2_permissible_field(struct dynhds_entry *e) if(e->namelen < H2_NON_FIELD[i].namelen) return TRUE; if(e->namelen == H2_NON_FIELD[i].namelen && - strcasecompare(H2_NON_FIELD[i].name, e->name)) + curl_strequal(H2_NON_FIELD[i].name, e->name)) return FALSE; } return TRUE; @@ -4551,7 +4676,7 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, e = Curl_dynhds_getn(&req->headers, i); /* "TE" is special in that it is only permissible when it * has only value "trailers". RFC 9113 ch. 8.2.2 */ - if(e->namelen == 2 && strcasecompare("TE", e->name)) { + if(e->namelen == 2 && curl_strequal("TE", e->name)) { if(http_TE_has_token(e->value, "trailers")) result = Curl_dynhds_add(h2_headers, e->name, e->namelen, "trailers", sizeof("trailers") - 1); diff --git a/vendor/curl/lib/http1.c b/vendor/curl/lib/http1.c index a0ec2556..537e6db2 100644 --- a/vendor/curl/lib/http1.c +++ b/vendor/curl/lib/http1.c @@ -209,7 +209,7 @@ static CURLcode start_req(struct h1_req_parser *parser, path = target; path_len = target_len; - /* URL parser wants 0-termination */ + /* URL parser wants null-termination */ if(target_len >= sizeof(tmp)) goto out; memcpy(tmp, target, target_len); diff --git a/vendor/curl/lib/http2.c b/vendor/curl/lib/http2.c index dd82aa96..36dca426 100644 --- a/vendor/curl/lib/http2.c +++ b/vendor/curl/lib/http2.c @@ -36,7 +36,6 @@ #include "sendf.h" #include "select.h" #include "curlx/base64.h" -#include "strcase.h" #include "multiif.h" #include "url.h" #include "urlapi-int.h" @@ -205,6 +204,9 @@ static void cf_h2_ctx_close(struct cf_h2_ctx *ctx) } } +static CURLcode nw_out_flush(struct Curl_cfilter *cf, + struct Curl_easy *data); + static CURLcode h2_progress_egress(struct Curl_cfilter *cf, struct Curl_easy *data); @@ -374,27 +376,6 @@ static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf, } #endif /* !NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */ -/* - * Mark this transfer to get "drained". - */ -static void drain_stream(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct h2_stream_ctx *stream) -{ - unsigned char bits; - - (void)cf; - bits = CURL_CSELECT_IN; - if(!stream->closed && - (!stream->body_eos || !Curl_bufq_is_empty(&stream->sendbuf))) - bits |= CURL_CSELECT_OUT; - if(stream->closed || (data->state.select_bits != bits)) { - CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x", - stream->id, bits); - data->state.select_bits = bits; - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } -} static CURLcode http2_data_setup(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -449,8 +430,10 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) flush_egress = TRUE; } - if(flush_egress) - nghttp2_session_send(ctx->h2); + if(flush_egress) { + (void)nghttp2_session_send(ctx->h2); + (void)nw_out_flush(cf, data); + } } Curl_uint_hash_remove(&ctx->streams, data->mid); @@ -480,33 +463,6 @@ static int h2_client_new(struct Curl_cfilter *cf, return rc; } -static ssize_t nw_in_reader(void *reader_ctx, - unsigned char *buf, size_t buflen, - CURLcode *err) -{ - struct Curl_cfilter *cf = reader_ctx; - struct Curl_easy *data = CF_DATA_CURRENT(cf); - - return Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err); -} - -static ssize_t nw_out_writer(void *writer_ctx, - const unsigned char *buf, size_t buflen, - CURLcode *err) -{ - struct Curl_cfilter *cf = writer_ctx; - struct Curl_easy *data = CF_DATA_CURRENT(cf); - - if(data) { - ssize_t nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, - buflen, FALSE, err); - if(nwritten > 0) - CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten); - return nwritten; - } - return 0; -} - static ssize_t send_callback(nghttp2_session *h2, const uint8_t *mem, size_t length, int flags, void *userp); @@ -727,12 +683,12 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data, not in use by any other transfer, there should not be any data here, only "protocol frames" */ CURLcode result; - ssize_t nread = -1; + size_t nread; *input_pending = FALSE; - nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result); - if(nread != -1) { - CURL_TRC_CF(data, cf, "%zd bytes stray data read before trying " + result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread); + if(!result) { + CURL_TRC_CF(data, cf, "%zu bytes stray data read before trying " "h2 connection", nread); if(h2_process_pending_input(cf, data, &result) < 0) /* immediate error, considered dead */ @@ -785,15 +741,16 @@ static CURLcode nw_out_flush(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_h2_ctx *ctx = cf->ctx; - ssize_t nwritten; + size_t nwritten; CURLcode result; (void)data; if(Curl_bufq_is_empty(&ctx->outbufq)) return CURLE_OK; - nwritten = Curl_bufq_pass(&ctx->outbufq, nw_out_writer, cf, &result); - if(nwritten < 0) { + result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, NULL, 0, + &nwritten); + if(result) { if(result == CURLE_AGAIN) { CURL_TRC_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN", Curl_bufq_len(&ctx->outbufq)); @@ -816,7 +773,7 @@ static ssize_t send_callback(nghttp2_session *h2, struct Curl_cfilter *cf = userp; struct cf_h2_ctx *ctx = cf->ctx; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten; + size_t nwritten; CURLcode result = CURLE_OK; (void)h2; @@ -824,11 +781,12 @@ static ssize_t send_callback(nghttp2_session *h2, DEBUGASSERT(data); if(!cf->connected) - nwritten = Curl_bufq_write(&ctx->outbufq, buf, blen, &result); + result = Curl_bufq_write(&ctx->outbufq, buf, blen, &nwritten); else - nwritten = Curl_bufq_write_pass(&ctx->outbufq, buf, blen, - nw_out_writer, cf, &result); - if(nwritten < 0) { + result = Curl_cf_send_bufq(cf->next, data, &ctx->outbufq, buf, blen, + &nwritten); + + if(result) { if(result == CURLE_AGAIN) { ctx->nw_out_blocked = 1; return NGHTTP2_ERR_WOULDBLOCK; @@ -841,7 +799,8 @@ static ssize_t send_callback(nghttp2_session *h2, ctx->nw_out_blocked = 1; return NGHTTP2_ERR_WOULDBLOCK; } - return nwritten; + return (nwritten > SSIZE_T_MAX) ? + NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten; } @@ -1191,7 +1150,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, if(stream->status_code / 100 != 1) { stream->resp_hds_complete = TRUE; } - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); break; case NGHTTP2_PUSH_PROMISE: rv = push_promise(cf, data, &frame->push_promise); @@ -1214,12 +1173,12 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, if(frame->rst_stream.error_code) { stream->reset = TRUE; } - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); break; case NGHTTP2_WINDOW_UPDATE: if(CURL_WANT_SEND(data) && Curl_bufq_is_empty(&stream->sendbuf)) { /* need more data, force processing of transfer */ - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); } else if(!Curl_bufq_is_empty(&stream->sendbuf)) { /* resume the potentially suspended stream */ @@ -1245,7 +1204,7 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf, stream->id, NGHTTP2_STREAM_CLOSED); stream->closed = TRUE; } - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); } return CURLE_OK; } @@ -1394,11 +1353,8 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, * window and *assume* that we treat this like a WINDOW_UPDATE. Some * servers send an explicit WINDOW_UPDATE, but not all seem to do that. * To be safe, we UNHOLD a stream in order not to stall. */ - if(CURL_WANT_SEND(data)) { - struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data); - if(stream) - drain_stream(cf, data, stream); - } + if(CURL_WANT_SEND(data)) + Curl_multi_mark_dirty(data); } break; } @@ -1543,7 +1499,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, stream_id, nghttp2_http2_strerror(error_code), error_code); else CURL_TRC_CF(data_s, cf, "[%d] CLOSED", stream_id); - drain_stream(cf, data_s, stream); + Curl_multi_mark_dirty(data_s); /* remove `data_s` from the nghttp2 stream */ rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); @@ -1641,9 +1597,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, if(!check) /* no memory */ return NGHTTP2_ERR_CALLBACK_FAILURE; - if(!strcasecompare(check, (const char *)value) && + if(!curl_strequal(check, (const char *)value) && ((cf->conn->remote_port != cf->conn->given->defport) || - !strcasecompare(cf->conn->host.name, (const char *)value))) { + !curl_strequal(cf->conn->host.name, (const char *)value))) { /* This is push is not for the same authority that was asked for in * the URL. RFC 7540 section 8.2 says: "A client MUST treat a * PUSH_PROMISE for which the server is not authoritative as a stream @@ -1737,7 +1693,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, } /* if we receive data for another handle, wake that up */ if(CF_DATA_CURRENT(cf) != data_s) - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data_s); CURL_TRC_CF(data_s, cf, "[%d] status: HTTP/2 %03d", stream->id, stream->status_code); @@ -1764,7 +1720,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, } /* if we receive data for another handle, wake that up */ if(CF_DATA_CURRENT(cf) != data_s) - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data_s); CURL_TRC_CF(data_s, cf, "[%d] header: %.*s: %.*s", stream->id, (int)namelen, name, (int)valuelen, value); @@ -1785,6 +1741,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session, struct h2_stream_ctx *stream = NULL; CURLcode result; ssize_t nread; + size_t n; (void)source; (void)cf; @@ -1803,12 +1760,14 @@ static ssize_t req_body_read_callback(nghttp2_session *session, if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; - nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result); - if(nread < 0) { + result = Curl_bufq_read(&stream->sendbuf, buf, length, &n); + if(result) { if(result != CURLE_AGAIN) return NGHTTP2_ERR_CALLBACK_FAILURE; nread = 0; } + else + nread = (ssize_t)n; CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d", stream_id, length, stream->body_eos, nread, result); @@ -1874,20 +1833,20 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, return result; } -static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct h2_stream_ctx *stream, - CURLcode *err) +static CURLcode http2_handle_stream_close(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h2_stream_ctx *stream, + size_t *pnlen) { - ssize_t rv = 0; + CURLcode result; + *pnlen = 0; if(stream->error == NGHTTP2_REFUSED_STREAM) { CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new " "connection", stream->id); connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */ data->state.refused_stream = TRUE; - *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ - return -1; + return CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */ } else if(stream->error != NGHTTP2_NO_ERROR) { if(stream->resp_hds_complete && data->req.no_body) { @@ -1896,27 +1855,23 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, stream->id, nghttp2_http2_strerror(stream->error), stream->error); stream->close_handled = TRUE; - *err = CURLE_OK; - goto out; + return CURLE_OK; } failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)", stream->id, nghttp2_http2_strerror(stream->error), stream->error); - *err = CURLE_HTTP2_STREAM; - return -1; + return CURLE_HTTP2_STREAM; } else if(stream->reset) { failf(data, "HTTP/2 stream %u was reset", stream->id); - *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2; - return -1; + return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2; } if(!stream->bodystarted) { failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " " all response header fields, treated as error", stream->id); - *err = CURLE_HTTP2_STREAM; - return -1; + return CURLE_HTTP2_STREAM; } if(Curl_dynhds_count(&stream->resp_trailers)) { @@ -1924,37 +1879,36 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, struct dynbuf dbuf; size_t i; - *err = CURLE_OK; + result = CURLE_OK; curlx_dyn_init(&dbuf, DYN_TRAILERS); for(i = 0; i < Curl_dynhds_count(&stream->resp_trailers); ++i) { e = Curl_dynhds_getn(&stream->resp_trailers, i); if(!e) break; curlx_dyn_reset(&dbuf); - *err = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a", + result = curlx_dyn_addf(&dbuf, "%.*s: %.*s\x0d\x0a", (int)e->namelen, e->name, (int)e->valuelen, e->value); - if(*err) + if(result) break; Curl_debug(data, CURLINFO_HEADER_IN, curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf)); - *err = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER, - curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf)); - if(*err) + result = Curl_client_write(data, CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER, + curlx_dyn_ptr(&dbuf), curlx_dyn_len(&dbuf)); + if(result) break; } curlx_dyn_free(&dbuf); - if(*err) + if(result) goto out; } stream->close_handled = TRUE; - *err = CURLE_OK; - rv = 0; + result = CURLE_OK; out: - CURL_TRC_CF(data, cf, "handle_stream_close -> %zd, %d", rv, *err); - return rv; + CURL_TRC_CF(data, cf, "handle_stream_close -> %d, %zu", result, *pnlen); + return result; } static int sweight_wanted(const struct Curl_easy *data) @@ -1997,7 +1951,7 @@ static void h2_pri_spec(struct cf_h2_ctx *ctx, * Flush any out data pending in the network buffer. */ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data); @@ -2037,36 +1991,36 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf, return nw_out_flush(cf, data); } -static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - struct h2_stream_ctx *stream, - char *buf, size_t len, CURLcode *err) +static CURLcode stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + struct h2_stream_ctx *stream, + char *buf, size_t len, size_t *pnread) { struct cf_h2_ctx *ctx = cf->ctx; - ssize_t nread = -1; + CURLcode result = CURLE_AGAIN; (void)buf; - *err = CURLE_AGAIN; + (void)len; + *pnread = 0; + if(stream->xfer_result) { CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id); - *err = stream->xfer_result; - nread = -1; + result = stream->xfer_result; } else if(stream->closed) { CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id); - nread = http2_handle_stream_close(cf, data, stream, err); + result = http2_handle_stream_close(cf, data, stream, pnread); } else if(stream->reset || (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) || (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) { CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id); - *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2; - nread = -1; + result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP2; } - if(nread < 0 && *err != CURLE_AGAIN) - CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d", - stream->id, len, nread, *err); - return nread; + if(result && (result != CURLE_AGAIN)) + CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %d, %zu", + stream->id, len, result, *pnread); + return result; } static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, @@ -2076,7 +2030,7 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream; CURLcode result = CURLE_OK; - ssize_t nread; + size_t nread; if(should_close_session(ctx)) { CURL_TRC_CF(data, cf, "progress ingress, session is closed"); @@ -2102,12 +2056,12 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, * this may leave data in underlying buffers that will not * be consumed. */ if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data)) - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); break; } - nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result); - if(nread < 0) { + result = Curl_cf_recv_bufq(cf->next, data, &ctx->inbufq, 0, &nread); + if(result) { if(result != CURLE_AGAIN) { failf(data, "Failed receiving HTTP2 data: %d(%s)", result, curl_easy_strerror(result)); @@ -2121,9 +2075,8 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, break; } else { - CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread); - data_max_bytes = (data_max_bytes > (size_t)nread) ? - (data_max_bytes - (size_t)nread) : 0; + CURL_TRC_CF(data, cf, "[0] ingress: read %zu bytes", nread); + data_max_bytes = (data_max_bytes > nread) ? (data_max_bytes - nread) : 0; } if(h2_process_pending_input(cf, data, &result)) @@ -2140,15 +2093,15 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf, return CURLE_OK; } -static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data); - ssize_t nread = -1; - CURLcode result; + CURLcode result, r2; struct cf_call_data save; + *pnread = 0; if(!stream) { /* Abnormal call sequence: either this transfer has never opened a stream * (unlikely) or the transfer has been done, cleaned up its resources, but @@ -2156,51 +2109,49 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, * is for such a case. */ failf(data, "http/2 recv on a transfer never opened " "or already cleared, mid=%u", data->mid); - *err = CURLE_HTTP2; - return -1; + return CURLE_HTTP2; } CF_DATA_SAVE(save, cf, data); - nread = stream_recv(cf, data, stream, buf, len, err); - if(nread < 0 && *err != CURLE_AGAIN) + result = stream_recv(cf, data, stream, buf, len, pnread); + if(result && (result != CURLE_AGAIN)) goto out; - if(nread < 0) { - *err = h2_progress_ingress(cf, data, len); - if(*err) + if(result) { + result = h2_progress_ingress(cf, data, len); + if(result) goto out; - nread = stream_recv(cf, data, stream, buf, len, err); + result = stream_recv(cf, data, stream, buf, len, pnread); } - if(nread > 0) { + if(*pnread > 0) { /* Now that we transferred this to the upper layer, we report * the actual amount of DATA consumed to the H2 session, so * that it adjusts stream flow control */ - nghttp2_session_consume(ctx->h2, stream->id, (size_t)nread); + nghttp2_session_consume(ctx->h2, stream->id, *pnread); if(stream->closed) { CURL_TRC_CF(data, cf, "[%d] DRAIN closed stream", stream->id); - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); } } out: - result = h2_progress_egress(cf, data); - if(result == CURLE_AGAIN) { + r2 = h2_progress_egress(cf, data); + if(r2 == CURLE_AGAIN) { /* pending data to send, need to be called again. Ideally, we * monitor the socket for POLLOUT, but when not SENDING * any more, we force processing of the transfer. */ if(!CURL_WANT_SEND(data)) - drain_stream(cf, data, stream); + Curl_multi_mark_dirty(data); } - else if(result) { - *err = result; - nread = -1; + else if(r2) { + result = r2; } - CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, " + CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %d, %zu, " "window=%d/%d, connection %d/%d", - stream->id, len, nread, *err, + stream->id, len, result, *pnread, nghttp2_session_get_stream_effective_recv_data_length( ctx->h2, stream->id), nghttp2_session_get_stream_effective_local_window_size( @@ -2209,7 +2160,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, HTTP2_HUGE_WINDOW_SIZE); CF_DATA_RESTORE(cf, save); - return nread; + return result; } static ssize_t cf_h2_body_send(struct Curl_cfilter *cf, @@ -2219,7 +2170,7 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf, CURLcode *err) { struct cf_h2_ctx *ctx = cf->ctx; - ssize_t nwritten; + size_t nwritten; if(stream->closed) { if(stream->resp_hds_complete) { @@ -2241,11 +2192,11 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf, return -1; } - nwritten = Curl_bufq_write(&stream->sendbuf, buf, blen, err); - if(nwritten < 0) + *err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten); + if(*err) return -1; - if(eos && (blen == (size_t)nwritten)) + if(eos && (blen == nwritten)) stream->body_eos = TRUE; if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) { @@ -2256,13 +2207,13 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf, return -1; } } - return nwritten; + return (ssize_t)nwritten; } -static ssize_t h2_submit(struct h2_stream_ctx **pstream, - struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, - bool eos, CURLcode *err) +static CURLcode h2_submit(struct h2_stream_ctx **pstream, + struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, + bool eos, size_t *pnwritten) { struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream = NULL; @@ -2274,36 +2225,34 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream, int32_t stream_id; nghttp2_priority_spec pri_spec; ssize_t nwritten; + CURLcode result = CURLE_OK; + *pnwritten = 0; Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); - *err = http2_data_setup(cf, data, &stream); - if(*err) { - nwritten = -1; + result = http2_data_setup(cf, data, &stream); + if(result) goto out; - } - nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result); if(nwritten < 0) goto out; + *pnwritten = (size_t)nwritten; if(!stream->h1.done) { /* need more data */ goto out; } DEBUGASSERT(stream->h1.req); - *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); - if(*err) { - nwritten = -1; + result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(result) goto out; - } /* no longer needed */ Curl_h1_req_parse_free(&stream->h1); nva = Curl_dynhds_to_nva(&h2_headers, &nheader); if(!nva) { - *err = CURLE_OUT_OF_MEMORY; - nwritten = -1; + result = CURLE_OUT_OF_MEMORY; goto out; } @@ -2329,8 +2278,7 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream, if(stream_id < 0) { CURL_TRC_CF(data, cf, "send: nghttp2_submit_request error (%s)%u", nghttp2_strerror(stream_id), stream_id); - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } @@ -2357,48 +2305,46 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream, stream->id = stream_id; - body = (const char *)buf + nwritten; - bodylen = len - nwritten; + body = (const char *)buf + *pnwritten; + bodylen = len - *pnwritten; if(bodylen || eos) { - ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, err); + ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &result); if(n >= 0) - nwritten += n; - else if(*err == CURLE_AGAIN) - *err = CURLE_OK; - else if(*err != CURLE_AGAIN) { - *err = CURLE_SEND_ERROR; - nwritten = -1; - goto out; + *pnwritten += n; + else if(result == CURLE_AGAIN) + result = CURLE_OK; + else { + result = CURLE_SEND_ERROR; } } out: - CURL_TRC_CF(data, cf, "[%d] submit -> %zd, %d", - stream ? stream->id : -1, nwritten, *err); + CURL_TRC_CF(data, cf, "[%d] submit -> %d, %zu", + stream ? stream->id : -1, result, *pnwritten); Curl_safefree(nva); *pstream = stream; Curl_dynhds_free(&h2_headers); - return nwritten; + return result; } -static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_h2_ctx *ctx = cf->ctx; struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data); struct cf_call_data save; ssize_t nwritten; - CURLcode result; + CURLcode result = CURLE_OK, r2; CF_DATA_SAVE(save, cf, data); + *pnwritten = 0; if(!stream || stream->id == -1) { - nwritten = h2_submit(&stream, cf, data, buf, len, eos, err); - if(nwritten < 0) { + result = h2_submit(&stream, cf, data, buf, len, eos, pnwritten); + if(result) goto out; - } DEBUGASSERT(stream); } else if(stream->body_eos) { @@ -2407,35 +2353,35 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, * to trigger flushing again. * If this works, we report to have written `len` bytes. */ DEBUGASSERT(eos); - nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, err); + nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, &result); CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d", - stream->id, nwritten, *err, eos); + stream->id, nwritten, result, eos); if(nwritten < 0) { goto out; } - nwritten = len; + *pnwritten = len; } else { - nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, err); + nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, &result); CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d", - stream->id, len, nwritten, *err, eos); + stream->id, len, nwritten, result, eos); + if(nwritten >= 0) + *pnwritten = (size_t)nwritten; } /* Call the nghttp2 send loop and flush to write ALL buffered data, * headers and/or request body completely out to the network */ - result = h2_progress_egress(cf, data); + r2 = h2_progress_egress(cf, data); /* if the stream has been closed in egress handling (nghttp2 does that * when it does not like the headers, for example */ if(stream && stream->closed) { infof(data, "stream %u closed", stream->id); - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } - else if(result && (result != CURLE_AGAIN)) { - *err = result; - nwritten = -1; + else if(r2 && (r2 != CURLE_AGAIN)) { + result = r2; goto out; } @@ -2443,21 +2389,20 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* nghttp2 thinks this session is done. If the stream has not been * closed, this is an error state for out transfer */ if(stream && stream->closed) { - nwritten = http2_handle_stream_close(cf, data, stream, err); + result = http2_handle_stream_close(cf, data, stream, pnwritten); } else { CURL_TRC_CF(data, cf, "send: nothing to do in this session"); - *err = CURLE_HTTP2; - nwritten = -1; + result = CURLE_HTTP2; } } out: if(stream) { - CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, " + CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %d, %zu, " "eos=%d, h2 windows %d-%d (stream-conn), " "buffers %zu-%zu (stream-conn)", - stream->id, len, nwritten, *err, + stream->id, len, result, *pnwritten, stream->body_eos, nghttp2_session_get_stream_remote_window_size( ctx->h2, stream->id), @@ -2466,14 +2411,14 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, Curl_bufq_len(&ctx->outbufq)); } else { - CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %zd, %d, " + CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zu, " "connection-window=%d, nw_send_buffer(%zu)", - len, nwritten, *err, + len, result, *pnwritten, nghttp2_session_get_remote_window_size(ctx->h2), Curl_bufq_len(&ctx->outbufq)); } CF_DATA_RESTORE(cf, save); - return nwritten; + return result; } static CURLcode cf_h2_flush(struct Curl_cfilter *cf, @@ -2716,8 +2661,7 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf, * not. We may have already buffered and exhausted the new window * by operating on things in flight during the handling of other * transfers. */ - drain_stream(cf, data, stream); - Curl_expire(data, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); } CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id, pause ? "" : "un"); @@ -2769,15 +2713,16 @@ static bool cf_h2_is_alive(struct Curl_cfilter *cf, bool *input_pending) { struct cf_h2_ctx *ctx = cf->ctx; - CURLcode result; + bool alive; struct cf_call_data save; + *input_pending = FALSE; CF_DATA_SAVE(save, cf, data); - result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending)); + alive = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending)); CURL_TRC_CF(data, cf, "conn alive -> %d, input_pending=%d", - result, *input_pending); + alive, *input_pending); CF_DATA_RESTORE(cf, save); - return result; + return alive; } static CURLcode cf_h2_keep_alive(struct Curl_cfilter *cf, @@ -2805,7 +2750,7 @@ static CURLcode cf_h2_query(struct Curl_cfilter *cf, DEBUGASSERT(pres1); CF_DATA_SAVE(save, cf, data); - if(nghttp2_session_check_request_allowed(ctx->h2) == 0) { + if(!ctx->h2 || !nghttp2_session_check_request_allowed(ctx->h2)) { /* the limit is what we have in use right now */ effective_max = CONN_ATTACHED(cf->conn); } @@ -2848,7 +2793,6 @@ struct Curl_cftype Curl_cft_nghttp2 = { cf_h2_connect, cf_h2_close, cf_h2_shutdown, - Curl_cf_def_get_host, cf_h2_adjust_pollset, cf_h2_data_pending, cf_h2_send, @@ -3001,17 +2945,17 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, /* Remaining data from the protocol switch reply is already using * the switched protocol, ie. HTTP/2. We add that to the network * inbufq. */ - ssize_t copied; + size_t copied; - copied = Curl_bufq_write(&ctx->inbufq, - (const unsigned char *)mem, nread, &result); - if(copied < 0) { + result = Curl_bufq_write(&ctx->inbufq, + (const unsigned char *)mem, nread, &copied); + if(result) { failf(data, "error on copying HTTP Upgrade response: %d", result); return CURLE_RECV_ERROR; } - if((size_t)copied < nread) { + if(copied < nread) { failf(data, "connection buffer size could not take all data " - "from HTTP Upgrade response header: copied=%zd, datalen=%zu", + "from HTTP Upgrade response header: copied=%zu, datalen=%zu", copied, nread); return CURLE_HTTP2; } diff --git a/vendor/curl/lib/http_aws_sigv4.c b/vendor/curl/lib/http_aws_sigv4.c index aa8945d3..92c0c1ff 100644 --- a/vendor/curl/lib/http_aws_sigv4.c +++ b/vendor/curl/lib/http_aws_sigv4.c @@ -9,7 +9,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -133,7 +133,7 @@ static void trim_headers(struct curl_slist *head) else *store++ = *value++; } - *store = 0; /* null terminate */ + *store = 0; /* null-terminate */ } } @@ -537,8 +537,8 @@ static int compare_func(const void *a, const void *b) } UNITTEST CURLcode canon_path(const char *q, size_t len, - struct dynbuf *new_path, - bool do_uri_encode) + struct dynbuf *new_path, + bool do_uri_encode) { CURLcode result = CURLE_OK; diff --git a/vendor/curl/lib/http_aws_sigv4.h b/vendor/curl/lib/http_aws_sigv4.h index 7d3a3d94..9747c948 100644 --- a/vendor/curl/lib/http_aws_sigv4.h +++ b/vendor/curl/lib/http_aws_sigv4.h @@ -11,7 +11,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is diff --git a/vendor/curl/lib/http_chunks.h b/vendor/curl/lib/http_chunks.h index 0461c80f..b84e479f 100644 --- a/vendor/curl/lib/http_chunks.h +++ b/vendor/curl/lib/http_chunks.h @@ -49,7 +49,7 @@ typedef enum { POST_CR state. */ CHUNK_DATA, - /* POSTLF should get a CR and then a LF and nothing else, then move back to + /* POSTLF should get a CR and then an LF and nothing else, then move back to HEX as the CRLF combination marks the end of a chunk. A missing CR is no big deal. */ CHUNK_POSTLF, @@ -64,7 +64,7 @@ typedef enum { CHUNK_TRAILER, /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR. - Next char must be a LF */ + Next char must be an LF */ CHUNK_TRAILER_CR, /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be diff --git a/vendor/curl/lib/http_negotiate.c b/vendor/curl/lib/http_negotiate.c index 5bec3b39..2c0b7e16 100644 --- a/vendor/curl/lib/http_negotiate.c +++ b/vendor/curl/lib/http_negotiate.c @@ -39,6 +39,20 @@ #include "curl_memory.h" #include "memdebug.h" + +static void http_auth_nego_reset(struct connectdata *conn, + struct negotiatedata *neg_ctx, + bool proxy) +{ + if(proxy) + conn->proxy_negotiate_state = GSS_AUTHNONE; + else + conn->http_negotiate_state = GSS_AUTHNONE; + if(neg_ctx) + Curl_auth_cleanup_spnego(neg_ctx); +} + + CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, bool proxy, const char *header) { @@ -62,7 +76,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; host = conn->http_proxy.host.name; - neg_ctx = &conn->proxyneg; state = conn->proxy_negotiate_state; #else return CURLE_NOT_BUILT_IN; @@ -74,10 +87,13 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : "HTTP"; host = conn->host.name; - neg_ctx = &conn->negotiate; state = conn->http_negotiate_state; } + neg_ctx = Curl_auth_nego_get(conn, proxy); + if(!neg_ctx) + return CURLE_OUT_OF_MEMORY; + /* Not set means empty */ if(!userp) userp = ""; @@ -94,12 +110,12 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, if(!len) { if(state == GSS_AUTHSUCC) { infof(data, "Negotiate auth restarted"); - Curl_http_auth_cleanup_negotiate(conn); + http_auth_nego_reset(conn, neg_ctx, proxy); } else if(state != GSS_AUTHNONE) { /* The server rejected our authentication and has not supplied any more negotiation mechanisms */ - Curl_http_auth_cleanup_negotiate(conn); + http_auth_nego_reset(conn, neg_ctx, proxy); return CURLE_LOGIN_DENIED; } } @@ -116,7 +132,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, result = Curl_ssl_get_channel_binding( data, FIRSTSOCKET, &neg_ctx->channel_binding_data); if(result) { - Curl_http_auth_cleanup_negotiate(conn); + http_auth_nego_reset(conn, neg_ctx, proxy); return result; } } @@ -134,7 +150,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, #endif if(result) - Curl_http_auth_cleanup_negotiate(conn); + http_auth_nego_reset(conn, neg_ctx, proxy); return result; } @@ -152,7 +168,6 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data, if(proxy) { #ifndef CURL_DISABLE_PROXY - neg_ctx = &conn->proxyneg; authp = &data->state.authproxy; state = &conn->proxy_negotiate_state; #else @@ -160,10 +175,12 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data, #endif } else { - neg_ctx = &conn->negotiate; authp = &data->state.authhost; state = &conn->http_negotiate_state; } + neg_ctx = Curl_auth_nego_get(conn, proxy); + if(!neg_ctx) + return CURLE_OUT_OF_MEMORY; authp->done = FALSE; @@ -184,7 +201,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data, if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) { infof(data, "Curl_output_negotiate, " "no persistent authentication: cleanup existing context"); - Curl_http_auth_cleanup_negotiate(conn); + http_auth_nego_reset(conn, neg_ctx, proxy); } if(!neg_ctx->context) { result = Curl_input_negotiate(data, conn, proxy, "Negotiate"); @@ -249,13 +266,4 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data, return CURLE_OK; } -void Curl_http_auth_cleanup_negotiate(struct connectdata *conn) -{ - conn->http_negotiate_state = GSS_AUTHNONE; - conn->proxy_negotiate_state = GSS_AUTHNONE; - - Curl_auth_cleanup_spnego(&conn->negotiate); - Curl_auth_cleanup_spnego(&conn->proxyneg); -} - #endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/vendor/curl/lib/http_negotiate.h b/vendor/curl/lib/http_negotiate.h index 76d83561..ad7c43d8 100644 --- a/vendor/curl/lib/http_negotiate.h +++ b/vendor/curl/lib/http_negotiate.h @@ -34,10 +34,6 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, CURLcode Curl_output_negotiate(struct Curl_easy *data, struct connectdata *conn, bool proxy); -void Curl_http_auth_cleanup_negotiate(struct connectdata *conn); - -#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */ -#define Curl_http_auth_cleanup_negotiate(x) #endif #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ diff --git a/vendor/curl/lib/http_ntlm.c b/vendor/curl/lib/http_ntlm.c index e6a3b175..0dff8f3a 100644 --- a/vendor/curl/lib/http_ntlm.c +++ b/vendor/curl/lib/http_ntlm.c @@ -60,17 +60,18 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data, header */ { /* point to the correct struct with this */ - struct ntlmdata *ntlm; curlntlm *state; CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; - ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state; if(checkprefix("NTLM", header)) { - header += strlen("NTLM"); + struct ntlmdata *ntlm = Curl_auth_ntlm_get(conn, proxy); + if(!ntlm) + return CURLE_FAILED_INIT; + header += strlen("NTLM"); curlx_str_passblanks(&header); if(*header) { unsigned char *hdr; @@ -93,11 +94,11 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data, else { if(*state == NTLMSTATE_LAST) { infof(data, "NTLM auth restarted"); - Curl_http_auth_cleanup_ntlm(conn); + Curl_auth_ntlm_remove(conn, proxy); } else if(*state == NTLMSTATE_TYPE3) { infof(data, "NTLM handshake rejected"); - Curl_http_auth_cleanup_ntlm(conn); + Curl_auth_ntlm_remove(conn, proxy); *state = NTLMSTATE_NONE; return CURLE_REMOTE_ACCESS_DENIED; } @@ -150,7 +151,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; hostname = conn->http_proxy.host.name; - ntlm = &conn->proxyntlm; state = &conn->proxy_ntlm_state; authp = &data->state.authproxy; #else @@ -164,10 +164,12 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : "HTTP"; hostname = conn->host.name; - ntlm = &conn->ntlm; state = &conn->http_ntlm_state; authp = &data->state.authhost; } + ntlm = Curl_auth_ntlm_get(conn, proxy); + if(!ntlm) + return CURLE_OUT_OF_MEMORY; authp->done = FALSE; /* not set means empty */ @@ -178,10 +180,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) passwdp = ""; #ifdef USE_WINDOWS_SSPI - if(!Curl_hSecDll) { + if(!Curl_pSecFn) { /* not thread safe and leaks - use curl_global_init() to avoid */ CURLcode err = Curl_sspi_global_init(); - if(!Curl_hSecDll) + if(!Curl_pSecFn) return err; } #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS @@ -200,9 +202,8 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ - result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, - service, hostname, - ntlm, &ntlmmsg); + result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp, service, + hostname, ntlm, &ntlmmsg); if(!result) { DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0); result = curlx_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg), @@ -258,10 +259,4 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) return result; } -void Curl_http_auth_cleanup_ntlm(struct connectdata *conn) -{ - Curl_auth_cleanup_ntlm(&conn->ntlm); - Curl_auth_cleanup_ntlm(&conn->proxyntlm); -} - #endif /* !CURL_DISABLE_HTTP && USE_NTLM */ diff --git a/vendor/curl/lib/http_ntlm.h b/vendor/curl/lib/http_ntlm.h index c1cf0570..b38ff82d 100644 --- a/vendor/curl/lib/http_ntlm.h +++ b/vendor/curl/lib/http_ntlm.h @@ -35,10 +35,6 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy, /* this is for creating NTLM header output */ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy); -void Curl_http_auth_cleanup_ntlm(struct connectdata *conn); - -#else /* !CURL_DISABLE_HTTP && USE_NTLM */ -#define Curl_http_auth_cleanup_ntlm(x) #endif #endif /* HEADER_CURL_HTTP_NTLM_H */ diff --git a/vendor/curl/lib/http_proxy.c b/vendor/curl/lib/http_proxy.c index 3df6329c..6f435a86 100644 --- a/vendor/curl/lib/http_proxy.c +++ b/vendor/curl/lib/http_proxy.c @@ -38,7 +38,6 @@ #include "cf-h1-proxy.h" #include "cf-h2-proxy.h" #include "connect.h" -#include "strcase.h" #include "vtls/vtls.h" #include "transfer.h" #include "multiif.h" @@ -53,7 +52,7 @@ static bool hd_name_eq(const char *n1, size_t n1len, const char *n2, size_t n2len) { - return (n1len == n2len) ? strncasecompare(n1, n2, n1len) : FALSE; + return (n1len == n2len) ? curl_strnequal(n1, n2, n1len) : FALSE; } static CURLcode dynhds_add_custom(struct Curl_easy *data, @@ -383,21 +382,21 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, return result; } -void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char **phost, - const char **pdisplay_host, - int *pport) +CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) { - (void)data; - if(!cf->connected) { - *phost = cf->conn->http_proxy.host.name; - *pdisplay_host = cf->conn->http_proxy.host.dispname; - *pport = (int)cf->conn->http_proxy.port; - } - else { - cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport); + switch(query) { + case CF_QUERY_HOST_PORT: + *pres1 = (int)cf->conn->http_proxy.port; + *((const char **)pres2) = cf->conn->http_proxy.host.name; + return CURLE_OK; + default: + break; } + return cf->next ? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; } static void http_proxy_cf_destroy(struct Curl_cfilter *cf, @@ -443,7 +442,6 @@ struct Curl_cftype Curl_cft_http_proxy = { http_proxy_cf_connect, http_proxy_cf_close, Curl_cf_def_shutdown, - Curl_cf_http_proxy_get_host, Curl_cf_def_adjust_pollset, Curl_cf_def_data_pending, Curl_cf_def_send, @@ -451,7 +449,7 @@ struct Curl_cftype Curl_cft_http_proxy = { Curl_cf_def_cntrl, Curl_cf_def_conn_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + Curl_cf_http_proxy_query, }; CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at, diff --git a/vendor/curl/lib/http_proxy.h b/vendor/curl/lib/http_proxy.h index 2e91ff20..e6ab2bac 100644 --- a/vendor/curl/lib/http_proxy.h +++ b/vendor/curl/lib/http_proxy.h @@ -48,18 +48,16 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq, /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) -void Curl_cf_http_proxy_get_host(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char **phost, - const char **pdisplay_host, - int *pport); +CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2); CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at, struct Curl_easy *data); extern struct Curl_cftype Curl_cft_http_proxy; -#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */ +#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */ #define IS_HTTPS_PROXY(t) (((t) == CURLPROXY_HTTPS) || \ ((t) == CURLPROXY_HTTPS2)) diff --git a/vendor/curl/lib/if2ip.c b/vendor/curl/lib/if2ip.c index 6da68efd..d6852908 100644 --- a/vendor/curl/lib/if2ip.c +++ b/vendor/curl/lib/if2ip.c @@ -52,8 +52,7 @@ # include #endif -#include "inet_ntop.h" -#include "strcase.h" +#include "curlx/inet_ntop.h" #include "if2ip.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -117,7 +116,7 @@ if2ip_result_t Curl_if2ip(int af, for(iface = head; iface != NULL; iface = iface->ifa_next) { if(iface->ifa_addr) { if(iface->ifa_addr->sa_family == af) { - if(strcasecompare(iface->ifa_name, interf)) { + if(curl_strequal(iface->ifa_name, interf)) { void *addr; const char *ip; char scope[12] = ""; @@ -162,13 +161,13 @@ if2ip_result_t Curl_if2ip(int af, addr = &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr; res = IF2IP_FOUND; - ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr)); + ip = curlx_inet_ntop(af, addr, ipstr, sizeof(ipstr)); msnprintf(buf, buf_size, "%s%s", ip, scope); break; } } else if((res == IF2IP_NOT_FOUND) && - strcasecompare(iface->ifa_name, interf)) { + curl_strequal(iface->ifa_name, interf)) { res = IF2IP_AF_NOT_SUPPORTED; } } @@ -235,7 +234,7 @@ if2ip_result_t Curl_if2ip(int af, s = (struct sockaddr_in *)(void *)&req.ifr_addr; memcpy(&in, &s->sin_addr, sizeof(in)); - r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size); + r = curlx_inet_ntop(s->sin_family, &in, buf, buf_size); sclose(dummy); if(!r) diff --git a/vendor/curl/lib/imap.c b/vendor/curl/lib/imap.c index 4b2e6087..f25176bb 100644 --- a/vendor/curl/lib/imap.c +++ b/vendor/curl/lib/imap.c @@ -302,7 +302,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd) /* Does the command name match and is it followed by a space character or at the end of line? */ - if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && + if(line + cmd_len <= end && curl_strnequal(line, cmd, cmd_len) && (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) return TRUE; @@ -358,16 +358,16 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn, case IMAP_LIST: if((!imap->custom && !imap_matchresp(line, len, "LIST")) || (imap->custom && !imap_matchresp(line, len, imap->custom) && - (!strcasecompare(imap->custom, "STORE") || + (!curl_strequal(imap->custom, "STORE") || !imap_matchresp(line, len, "FETCH")) && - !strcasecompare(imap->custom, "SELECT") && - !strcasecompare(imap->custom, "EXAMINE") && - !strcasecompare(imap->custom, "SEARCH") && - !strcasecompare(imap->custom, "EXPUNGE") && - !strcasecompare(imap->custom, "LSUB") && - !strcasecompare(imap->custom, "UID") && - !strcasecompare(imap->custom, "GETQUOTAROOT") && - !strcasecompare(imap->custom, "NOOP"))) + !curl_strequal(imap->custom, "SELECT") && + !curl_strequal(imap->custom, "EXAMINE") && + !curl_strequal(imap->custom, "SEARCH") && + !curl_strequal(imap->custom, "EXPUNGE") && + !curl_strequal(imap->custom, "LSUB") && + !curl_strequal(imap->custom, "UID") && + !curl_strequal(imap->custom, "GETQUOTAROOT") && + !curl_strequal(imap->custom, "NOOP"))) return FALSE; break; @@ -1032,7 +1032,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ - /* Do we have a untagged response? */ + /* Do we have an untagged response? */ if(imapcode == '*') { line += 2; @@ -1239,7 +1239,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, else if(imapcode == IMAP_RESP_OK) { /* Check if the UIDVALIDITY has been specified and matches */ if(imap->uidvalidity && imapc->mailbox_uidvalidity && - !strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity)) { + !curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity)) { failf(data, "Mailbox UIDVALIDITY has changed"); result = CURLE_REMOTE_FILE_NOT_FOUND; } @@ -1347,9 +1347,6 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, else { /* IMAP download */ data->req.maxdownload = size; - /* force a recv/send check of this connection, as the data might've been - read off the socket already */ - data->state.select_bits = CURL_CSELECT_IN; Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE); } } @@ -1693,9 +1690,9 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected, /* Determine if the requested mailbox (with the same UIDVALIDITY if set) has already been selected on this connection */ if(imap->mailbox && imapc->mailbox && - strcasecompare(imap->mailbox, imapc->mailbox) && + curl_strequal(imap->mailbox, imapc->mailbox) && (!imap->uidvalidity || !imapc->mailbox_uidvalidity || - strcasecompare(imap->uidvalidity, imapc->mailbox_uidvalidity))) + curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity))) selected = TRUE; /* Start the first command in the DO phase */ @@ -1780,18 +1777,14 @@ static CURLcode imap_disconnect(struct Curl_easy *data, (void)data; if(imapc) { /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the + bad in any way (pingpong has pending data to send), + sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ - - /* The IMAP session may or may not have been allocated/setup at this - point! */ - if(!dead_connection && conn->bits.protoconnstart) { + if(!dead_connection && conn->bits.protoconnstart && + !Curl_pp_needs_flush(data, &imapc->pp)) { if(!imap_perform_logout(data, imapc)) (void)imap_block_statemach(data, imapc, TRUE); /* ignore errors */ } - - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, imapc->sasl.authused); } return CURLE_OK; } @@ -2079,12 +2072,12 @@ static CURLcode imap_parse_url_options(struct connectdata *conn, while(*ptr && *ptr != ';') ptr++; - if(strncasecompare(key, "AUTH=+LOGIN", 11)) { + if(curl_strnequal(key, "AUTH=+LOGIN", 11)) { /* User prefers plaintext LOGIN over any SASL, including SASL LOGIN */ prefer_login = TRUE; imapc->sasl.prefmech = SASL_AUTH_NONE; } - else if(strncasecompare(key, "AUTH=", 5)) { + else if(curl_strnequal(key, "AUTH=", 5)) { prefer_login = FALSE; result = Curl_sasl_parse_url_auth_option(&imapc->sasl, value, ptr - value); @@ -2189,35 +2182,35 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data, PARTIAL) stripping of the trailing slash character if it is present. Note: Unknown parameters trigger a URL_MALFORMAT error. */ - if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { + if(curl_strequal(name, "UIDVALIDITY") && !imap->uidvalidity) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uidvalidity = value; value = NULL; } - else if(strcasecompare(name, "UID") && !imap->uid) { + else if(curl_strequal(name, "UID") && !imap->uid) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uid = value; value = NULL; } - else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) { + else if(curl_strequal(name, "MAILINDEX") && !imap->mindex) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->mindex = value; value = NULL; } - else if(strcasecompare(name, "SECTION") && !imap->section) { + else if(curl_strequal(name, "SECTION") && !imap->section) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->section = value; value = NULL; } - else if(strcasecompare(name, "PARTIAL") && !imap->partial) { + else if(curl_strequal(name, "PARTIAL") && !imap->partial) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; diff --git a/vendor/curl/lib/krb5.c b/vendor/curl/lib/krb5.c index 9ebba4e3..b5effa2a 100644 --- a/vendor/curl/lib/krb5.c +++ b/vendor/curl/lib/krb5.c @@ -56,7 +56,6 @@ #include "transfer.h" #include "curl_krb5.h" #include "curlx/warnless.h" -#include "strcase.h" #include "strdup.h" /* The last 3 #include files should be in this order */ @@ -215,12 +214,14 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) gss_ctx_id_t *context = app_data; struct gss_channel_bindings_struct chan; size_t base64_sz = 0; - struct sockaddr_in *remote_addr = - (struct sockaddr_in *)CURL_UNCONST(&conn->remote_addr->curl_sa_addr); + const struct Curl_sockaddr_ex *remote_addr = + Curl_conn_get_remote_addr(data, FIRSTSOCKET); + struct sockaddr_in *remote_in_addr = remote_addr ? + (struct sockaddr_in *)CURL_UNCONST(&remote_addr->curl_sa_addr) : NULL; char *stringp; struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - if(!ftpc) + if(!ftpc || !remote_in_addr) return -2; if(getsockname(conn->sock[FIRSTSOCKET], @@ -232,7 +233,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn) chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr; chan.acceptor_addrtype = GSS_C_AF_INET; chan.acceptor_address.length = l - 4; - chan.acceptor_address.value = &remote_addr->sin_addr.s_addr; + chan.acceptor_address.value = &remote_in_addr->sin_addr.s_addr; chan.application_data.length = 0; chan.application_data.value = NULL; @@ -384,7 +385,8 @@ static void krb5_end(void *app_data) OM_uint32 min; gss_ctx_id_t *context = app_data; if(*context != GSS_C_NO_CONTEXT) { - OM_uint32 maj = gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER); + OM_uint32 maj = Curl_gss_delete_sec_context(&min, context, + GSS_C_NO_BUFFER); (void)maj; DEBUGASSERT(maj == GSS_S_COMPLETE); } @@ -479,19 +481,18 @@ socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len) { char *to_p = to; CURLcode result; - ssize_t nread = 0; + size_t nread = 0; while(len > 0) { result = Curl_conn_recv(data, sockindex, to_p, len, &nread); - if(nread > 0) { - len -= nread; - to_p += nread; - } - else { - if(result == CURLE_AGAIN) - continue; + if(result == CURLE_AGAIN) + continue; + if(result) return result; - } + if(nread > len) + return CURLE_RECV_ERROR; + len -= nread; + to_p += nread; } return CURLE_OK; } @@ -523,8 +524,8 @@ socket_write(struct Curl_easy *data, int sockindex, const void *to, return CURLE_OK; } -static CURLcode read_data(struct Curl_easy *data, int sockindex, - struct krb5buffer *buf) +static CURLcode krb5_read_data(struct Curl_easy *data, int sockindex, + struct krb5buffer *buf) { struct connectdata *conn = data->conn; int len; @@ -579,52 +580,49 @@ buffer_read(struct krb5buffer *buf, void *data, size_t len) } /* Matches Curl_recv signature */ -static ssize_t sec_recv(struct Curl_easy *data, int sockindex, - char *buffer, size_t len, CURLcode *err) +static CURLcode sec_recv(struct Curl_easy *data, int sockindex, + char *buffer, size_t len, size_t *pnread) { - size_t bytes_read; - size_t total_read = 0; struct connectdata *conn = data->conn; - - *err = CURLE_OK; + CURLcode result = CURLE_OK; + size_t bytes_read; /* Handle clear text response. */ - if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) { - ssize_t nread; - *err = Curl_conn_recv(data, sockindex, buffer, len, &nread); - return nread; - } + if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) + return Curl_conn_recv(data, sockindex, buffer, len, pnread); if(conn->in_buffer.eof_flag) { conn->in_buffer.eof_flag = 0; - return 0; + *pnread = 0; + return CURLE_OK; } bytes_read = buffer_read(&conn->in_buffer, buffer, len); - len -= bytes_read; - total_read += bytes_read; buffer += bytes_read; + len -= bytes_read; + *pnread += bytes_read; while(len > 0) { - if(read_data(data, sockindex, &conn->in_buffer)) - return -1; + result = krb5_read_data(data, sockindex, &conn->in_buffer); + if(result) + return result; if(curlx_dyn_len(&conn->in_buffer.buf) == 0) { - if(bytes_read > 0) + if(*pnread > 0) conn->in_buffer.eof_flag = 1; - return bytes_read; + return result; } bytes_read = buffer_read(&conn->in_buffer, buffer, len); - len -= bytes_read; - total_read += bytes_read; buffer += bytes_read; + len -= bytes_read; + *pnread += bytes_read; } - return total_read; + return result; } /* Send |length| bytes from |from| to the |sockindex| socket taking care of encoding and negotiating with the server. |from| can be NULL. */ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, - int sockindex, const char *from, int length) + int sockindex, const char *from, size_t length) { int bytes, htonl_bytes; /* 32-bit integers for htonl */ char *buffer = NULL; @@ -642,8 +640,8 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, else prot_level = conn->command_prot; } - bytes = conn->mech->encode(conn->app_data, from, length, (int)prot_level, - (void **)&buffer); + bytes = conn->mech->encode(conn->app_data, from, (int)length, + (int)prot_level, (void **)&buffer); if(!buffer || bytes <= 0) return; /* error */ @@ -677,34 +675,36 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn, free(buffer); } -static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn, - int sockindex, const char *buffer, size_t length) +static CURLcode sec_write(struct Curl_easy *data, int sockindex, + const char *buffer, size_t length, + size_t *pnwritten) { - ssize_t tx = 0, len = conn->buffer_size; + struct connectdata *conn = data->conn; + size_t len = conn->buffer_size; + *pnwritten = 0; if(len <= 0) len = length; while(length) { - if(length < (size_t)len) + if(length < len) len = length; - do_sec_send(data, conn, sockindex, buffer, curlx_sztosi(len)); + /* WTF: this ignores all errors writing to the socket */ + do_sec_send(data, conn, sockindex, buffer, len); length -= len; buffer += len; - tx += len; + *pnwritten += len; } - return tx; + return CURLE_OK; } /* Matches Curl_send signature */ -static ssize_t sec_send(struct Curl_easy *data, int sockindex, - const void *buffer, size_t len, bool eos, - CURLcode *err) +static CURLcode sec_send(struct Curl_easy *data, int sockindex, + const void *buffer, size_t len, bool eos, + size_t *pnwritten) { - struct connectdata *conn = data->conn; (void)eos; /* unused */ - *err = CURLE_OK; - return sec_write(data, conn, sockindex, buffer, len); + return sec_write(data, sockindex, buffer, len, pnwritten); } int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, diff --git a/vendor/curl/lib/ldap.c b/vendor/curl/lib/ldap.c index c1be2f4b..40e72af0 100644 --- a/vendor/curl/lib/ldap.c +++ b/vendor/curl/lib/ldap.c @@ -88,7 +88,6 @@ #include "escape.h" #include "progress.h" #include "transfer.h" -#include "strcase.h" #include "curlx/strparse.h" #include "curl_ldap.h" #include "curlx/multibyte.h" @@ -393,7 +392,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) if(conn->ssl_config.verifypeer) { /* OpenLDAP SDK supports BASE64 files. */ if((data->set.ssl.cert_type) && - (!strcasecompare(data->set.ssl.cert_type, "PEM"))) { + (!curl_strequal(data->set.ssl.cert_type, "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type"); result = CURLE_SSL_CERTPROBLEM; goto quit; @@ -748,15 +747,15 @@ static void _ldap_trace(const char *fmt, ...) */ static int str2scope(const char *p) { - if(strcasecompare(p, "one")) + if(curl_strequal(p, "one")) return LDAP_SCOPE_ONELEVEL; - if(strcasecompare(p, "onetree")) + if(curl_strequal(p, "onetree")) return LDAP_SCOPE_ONELEVEL; - if(strcasecompare(p, "base")) + if(curl_strequal(p, "base")) return LDAP_SCOPE_BASE; - if(strcasecompare(p, "sub")) + if(curl_strequal(p, "sub")) return LDAP_SCOPE_SUBTREE; - if(strcasecompare(p, "subtree")) + if(curl_strequal(p, "subtree")) return LDAP_SCOPE_SUBTREE; return -1; } @@ -801,7 +800,7 @@ static int _ldap_url_parse2(struct Curl_easy *data, if(!data || !data->state.up.path || data->state.up.path[0] != '/' || - !strncasecompare("LDAP", data->state.up.scheme, 4)) + !curl_strnequal("LDAP", data->state.up.scheme, 4)) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; diff --git a/vendor/curl/lib/llist.c b/vendor/curl/lib/llist.c index 82934425..c9a7d4a8 100644 --- a/vendor/curl/lib/llist.c +++ b/vendor/curl/lib/llist.c @@ -181,7 +181,8 @@ void *Curl_node_take_elem(struct Curl_llist_node *e) /* * @unittest: 1300 */ -void +UNITTEST void Curl_node_uremove(struct Curl_llist_node *, void *); +UNITTEST void Curl_node_uremove(struct Curl_llist_node *e, void *user) { struct Curl_llist *list; diff --git a/vendor/curl/lib/llist.h b/vendor/curl/lib/llist.h index 597c0e00..0a2bc9a6 100644 --- a/vendor/curl/lib/llist.h +++ b/vendor/curl/lib/llist.h @@ -57,7 +57,6 @@ void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_node *, const void *, struct Curl_llist_node *node); void Curl_llist_append(struct Curl_llist *, const void *, struct Curl_llist_node *node); -void Curl_node_uremove(struct Curl_llist_node *, void *); void Curl_node_remove(struct Curl_llist_node *); void Curl_llist_destroy(struct Curl_llist *, void *); @@ -76,7 +75,7 @@ size_t Curl_llist_count(struct Curl_llist *list); void *Curl_node_elem(struct Curl_llist_node *n); /* Remove the node from the list and return the custom data - * from a Curl_llist_node. Will NOT incoke a registered `dtor`. */ + * from a Curl_llist_node. Will NOT invoke a registered `dtor`. */ void *Curl_node_take_elem(struct Curl_llist_node *); /* Curl_node_next() returns the next element in a list from a given diff --git a/vendor/curl/lib/memdebug.c b/vendor/curl/lib/memdebug.c index b351726b..bdcdcbb9 100644 --- a/vendor/curl/lib/memdebug.c +++ b/vendor/curl/lib/memdebug.c @@ -30,8 +30,6 @@ #include "urldata.h" -#define MEMDEBUG_NODEFINES /* do not redefine the standard functions */ - /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -70,7 +68,7 @@ static void curl_dbg_cleanup(void) if(curl_dbg_logfile && curl_dbg_logfile != stderr && curl_dbg_logfile != stdout) { - fclose(curl_dbg_logfile); + (fclose)(curl_dbg_logfile); } curl_dbg_logfile = NULL; } @@ -80,7 +78,11 @@ void curl_dbg_memdebug(const char *logname) { if(!curl_dbg_logfile) { if(logname && *logname) - curl_dbg_logfile = fopen(logname, FOPEN_WRITETEXT); +#ifdef CURL_FOPEN + curl_dbg_logfile = CURL_FOPEN(logname, FOPEN_WRITETEXT); +#else + curl_dbg_logfile = (fopen)(logname, FOPEN_WRITETEXT); +#endif else curl_dbg_logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC @@ -302,14 +304,14 @@ void curl_dbg_free(void *ptr, int line, const char *source) } curl_socket_t curl_dbg_socket(int domain, int type, int protocol, - int line, const char *source) + int line, const char *source) { curl_socket_t sockfd; if(countcheck("socket", line, source)) return CURL_SOCKET_BAD; - sockfd = socket(domain, type, protocol); + sockfd = (socket)(domain, type, protocol); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d socket() = %" FMT_SOCKET_T "\n", @@ -326,7 +328,7 @@ SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, SEND_TYPE_RETV rc; if(countcheck("send", line, source)) return -1; - rc = send(sockfd, buf, len, flags); + rc = (send)(sockfd, buf, len, flags); if(source) curl_dbg_log("SEND %s:%d send(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); @@ -340,7 +342,7 @@ RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, RECV_TYPE_RETV rc; if(countcheck("recv", line, source)) return -1; - rc = recv(sockfd, buf, len, flags); + rc = (recv)(sockfd, buf, len, flags); if(source) curl_dbg_log("RECV %s:%d recv(%lu) = %ld\n", source, line, (unsigned long)len, (long)rc); @@ -349,10 +351,10 @@ RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, RECV_TYPE_ARG2 buf, #ifdef HAVE_SOCKETPAIR int curl_dbg_socketpair(int domain, int type, int protocol, - curl_socket_t socket_vector[2], - int line, const char *source) + curl_socket_t socket_vector[2], + int line, const char *source) { - int res = socketpair(domain, type, protocol, socket_vector); + int res = (socketpair)(domain, type, protocol, socket_vector); if(source && (0 == res)) curl_dbg_log("FD %s:%d socketpair() = " @@ -364,12 +366,12 @@ int curl_dbg_socketpair(int domain, int type, int protocol, #endif curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, - int line, const char *source) + int line, const char *source) { struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; - curl_socket_t sockfd = accept(s, addr, addrlen); + curl_socket_t sockfd = (accept)(s, addr, addrlen); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n", @@ -386,7 +388,7 @@ curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr, void *saddrlen, struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; - curl_socket_t sockfd = accept4(s, addr, addrlen, flags); + curl_socket_t sockfd = (accept4)(s, addr, addrlen, flags); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n", @@ -407,7 +409,7 @@ void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source) /* this is our own defined way to close sockets on *ALL* platforms */ int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source) { - int res = sclose(sockfd); + int res = CURL_SCLOSE(sockfd); curl_dbg_mark_sclose(sockfd, line, source); return res; } @@ -416,7 +418,12 @@ ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, int line, const char *source) { - FILE *res = fopen(file, mode); + FILE *res; +#ifdef CURL_FOPEN + res = CURL_FOPEN(file, mode); +#else + res = (fopen)(file, mode); +#endif if(source) curl_dbg_log("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", @@ -429,7 +436,7 @@ ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, int line, const char *source) { - FILE *res = fdopen(filedes, mode); + FILE *res = (fdopen)(filedes, mode); if(source) curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", source, line, filedes, mode, (void *)res); @@ -446,7 +453,7 @@ int curl_dbg_fclose(FILE *file, int line, const char *source) curl_dbg_log("FILE %s:%d fclose(%p)\n", source, line, (void *)file); - res = fclose(file); + res = (fclose)(file); return res; } @@ -469,7 +476,7 @@ void curl_dbg_log(const char *format, ...) nchars = (int)sizeof(buf) - 1; if(nchars > 0) - fwrite(buf, 1, (size_t)nchars, curl_dbg_logfile); + (fwrite)(buf, 1, (size_t)nchars, curl_dbg_logfile); } #endif /* CURLDEBUG */ diff --git a/vendor/curl/lib/memdebug.h b/vendor/curl/lib/memdebug.h index 11b250de..03b04b12 100644 --- a/vendor/curl/lib/memdebug.h +++ b/vendor/curl/lib/memdebug.h @@ -56,8 +56,6 @@ # define ALLOC_SIZE2(n, s) #endif -#define CURL_MT_LOGFNAME_BUFSIZE 512 - /* Avoid redundant redeclaration warnings with modern compilers, when including this header multiple times. */ #ifndef HEADER_CURL_MEMDEBUG_H_EXTERNS @@ -126,8 +124,6 @@ CURL_EXTERN ALLOC_FUNC #endif /* HEADER_CURL_MEMDEBUG_H_EXTERNS */ -#ifndef MEMDEBUG_NODEFINES - /* Set this symbol on the command-line, recompile all lib-sources */ #undef strdup #define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) @@ -145,34 +141,29 @@ CURL_EXTERN ALLOC_FUNC #define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__) #ifdef _WIN32 -# ifdef UNICODE -# undef wcsdup -# define wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) -# undef _wcsdup -# define _wcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) -# undef _tcsdup -# define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) -# else -# undef _tcsdup -# define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) -# endif +#undef _tcsdup +#ifdef UNICODE +#define _tcsdup(ptr) curl_dbg_wcsdup(ptr, __LINE__, __FILE__) +#else +#define _tcsdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__) #endif +#endif /* _WIN32 */ #undef socket -#define socket(domain,type,protocol)\ - curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) +#define socket(domain,type,protocol) \ + curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) #undef accept /* for those with accept as a macro */ -#define accept(sock,addr,len)\ - curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) +#define accept(sock,addr,len) \ + curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) #ifdef HAVE_ACCEPT4 #undef accept4 /* for those with accept4 as a macro */ -#define accept4(sock,addr,len,flags)\ - curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__) +#define accept4(sock,addr,len,flags) \ + curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__) #endif #ifdef HAVE_SOCKETPAIR -#define socketpair(domain,type,protocol,socket_vector)\ - curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \ - __LINE__, __FILE__) +#define socketpair(domain,type,protocol,socket_vector) \ + curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \ + __LINE__, __FILE__) #endif /* sclose is probably already defined, redefine it! */ @@ -185,10 +176,9 @@ CURL_EXTERN ALLOC_FUNC #define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) #undef fdopen #define fdopen(file,mode) curl_dbg_fdopen(file,mode,__LINE__,__FILE__) +#undef fclose #define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) -#endif /* MEMDEBUG_NODEFINES */ - #endif /* CURLDEBUG */ /* diff --git a/vendor/curl/lib/mime.c b/vendor/curl/lib/mime.c index c90c3489..06cd221a 100644 --- a/vendor/curl/lib/mime.c +++ b/vendor/curl/lib/mime.c @@ -32,6 +32,7 @@ struct Curl_easy; #include "curlx/warnless.h" #include "urldata.h" #include "sendf.h" +#include "transfer.h" #include "strdup.h" #include "curlx/base64.h" @@ -45,7 +46,6 @@ struct Curl_easy; #include "rand.h" #include "slist.h" -#include "strcase.h" #include "curlx/dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -67,12 +67,12 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, /* Encoders. */ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part); + curl_mimepart *part); static curl_off_t encoder_nop_size(curl_mimepart *part); static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part); + curl_mimepart *part); static curl_off_t encoder_base64_size(curl_mimepart *part); static size_t encoder_qp_read(char *buffer, size_t size, bool ateof, curl_mimepart *part); @@ -335,7 +335,7 @@ static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len) { char *value = NULL; - if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':') + if(curl_strnequal(hdr->data, lbl, len) && hdr->data[len] == ':') for(value = hdr->data + len + 1; *value == ' '; value++) ; return value; @@ -433,7 +433,7 @@ static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, /* Base64 content encoder. */ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, - curl_mimepart *part) + curl_mimepart *part) { struct mime_encoder_state *st = &part->encstate; size_t cursize = 0; @@ -1478,7 +1478,7 @@ CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) return CURLE_OK; /* Removing current encoder. */ for(mep = encoders; mep->name; mep++) - if(strcasecompare(encoding, mep->name)) { + if(curl_strequal(encoding, mep->name)) { part->encoder = mep; result = CURLE_OK; } @@ -1742,7 +1742,7 @@ const char *Curl_mime_contenttype(const char *filename) for(i = 0; i < CURL_ARRAYSIZE(ctts); i++) { size_t len2 = strlen(ctts[i].extension); - if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension)) + if(len1 >= len2 && curl_strequal(nameend - len2, ctts[i].extension)) return ctts[i].type; } } @@ -1752,7 +1752,7 @@ const char *Curl_mime_contenttype(const char *filename) static bool content_type_match(const char *contenttype, const char *target, size_t len) { - if(contenttype && strncasecompare(contenttype, target, len)) + if(contenttype && curl_strnequal(contenttype, target, len)) switch(contenttype[len]) { case '\0': case '\t': @@ -1825,7 +1825,7 @@ CURLcode Curl_mime_prepare_headers(struct Curl_easy *data, if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) { if(!disposition) if(part->filename || part->name || - (contenttype && !strncasecompare(contenttype, "multipart/", 10))) + (contenttype && !curl_strnequal(contenttype, "multipart/", 10))) disposition = DISPOSITION_DEFAULT; if(disposition && curl_strequal(disposition, "attachment") && !part->name && !part->filename) @@ -1962,6 +1962,7 @@ static CURLcode cr_mime_read(struct Curl_easy *data, size_t *pnread, bool *peos) { struct cr_mime_ctx *ctx = reader->ctx; + CURLcode result = CURLE_OK; size_t nread; char tmp[256]; @@ -1990,15 +1991,12 @@ static CURLcode cr_mime_read(struct Curl_easy *data, } if(!Curl_bufq_is_empty(&ctx->tmpbuf)) { - CURLcode result = CURLE_OK; - ssize_t n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, - &result); - if(n < 0) { + result = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &nread); + if(result) { ctx->errored = TRUE; ctx->error_result = result; return result; } - nread = (size_t)n; } else if(blen <= 4) { /* Curl_mime_read() may go into an infinite loop when reading @@ -2008,22 +2006,20 @@ static CURLcode cr_mime_read(struct Curl_easy *data, CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen); nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part); if(nread <= sizeof(tmp)) { - CURLcode result = CURLE_OK; - ssize_t n = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, - &result); - if(n < 0) { + size_t n; + result = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread, &n); + if(result) { ctx->errored = TRUE; ctx->error_result = result; return result; } /* stored it, read again */ - n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &result); - if(n < 0) { + result = Curl_bufq_cread(&ctx->tmpbuf, buf, blen, &nread); + if(result) { ctx->errored = TRUE; ctx->error_result = result; return result; } - nread = (size_t)n; } } else @@ -2051,14 +2047,15 @@ static CURLcode cr_mime_read(struct Curl_easy *data, *peos = FALSE; ctx->errored = TRUE; ctx->error_result = CURLE_ABORTED_BY_CALLBACK; - return CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; + break; case CURL_READFUNC_PAUSE: /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ CURL_TRC_READ(data, "cr_mime_read(len=%zu), paused by callback", blen); - data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ *pnread = 0; *peos = FALSE; + result = Curl_xfer_pause_send(data, TRUE); break; /* nothing was read */ case STOP_FILLING: @@ -2068,7 +2065,8 @@ static CURLcode cr_mime_read(struct Curl_easy *data, *peos = FALSE; ctx->errored = TRUE; ctx->error_result = CURLE_READ_ERROR; - return CURLE_READ_ERROR; + result = CURLE_READ_ERROR; + break; default: if(nread > blen) { @@ -2090,8 +2088,8 @@ static CURLcode cr_mime_read(struct Curl_easy *data, CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T ", read=%"FMT_OFF_T") -> %d, %zu, %d", - blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos); - return CURLE_OK; + blen, ctx->total_len, ctx->read_len, result, *pnread, *peos); + return result; } static bool cr_mime_needs_rewind(struct Curl_easy *data, diff --git a/vendor/curl/lib/mqtt.c b/vendor/curl/lib/mqtt.c index 77e73346..90f857dc 100644 --- a/vendor/curl/lib/mqtt.c +++ b/vendor/curl/lib/mqtt.c @@ -240,7 +240,7 @@ static int mqtt_encode_len(char *buf, size_t len) /* add the passwd to the CONNECT packet */ static int add_passwd(const char *passwd, const size_t plen, - char *pkt, const size_t start, int remain_pos) + char *pkt, const size_t start, int remain_pos) { /* magic number that need to be set properly */ const size_t conn_flags_pos = remain_pos + 8; @@ -428,14 +428,13 @@ static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes) if(rlen < nbytes) { unsigned char readbuf[1024]; - ssize_t nread; + size_t nread; DEBUGASSERT(nbytes - rlen < sizeof(readbuf)); result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread); if(result) return result; - DEBUGASSERT(nread >= 0); - if(curlx_dyn_addn(&mq->recvbuf, readbuf, (size_t)nread)) + if(curlx_dyn_addn(&mq->recvbuf, readbuf, nread)) return CURLE_OUT_OF_MEMORY; rlen = curlx_dyn_len(&mq->recvbuf); } @@ -703,7 +702,7 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done) { CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; - ssize_t nread; + size_t nread; size_t remlen; struct mqtt_conn *mqtt = Curl_conn_meta_get(conn, CURL_META_MQTT_CONN); struct MQTT *mq = Curl_meta_get(data, CURL_META_MQTT_EASY); @@ -868,7 +867,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) { struct MQTT *mq = Curl_meta_get(data, CURL_META_MQTT_EASY); CURLcode result = CURLE_OK; - ssize_t nread; + size_t nread; unsigned char recvbyte; struct mqtt_conn *mqtt = Curl_conn_meta_get(data->conn, CURL_META_MQTT_CONN); diff --git a/vendor/curl/lib/multi.c b/vendor/curl/lib/multi.c index 792b3051..b3a7938e 100644 --- a/vendor/curl/lib/multi.c +++ b/vendor/curl/lib/multi.c @@ -42,6 +42,7 @@ #include "http.h" #include "select.h" #include "curlx/warnless.h" +#include "curlx/wait.h" #include "speedcheck.h" #include "conncache.h" #include "multihandle.h" @@ -234,6 +235,7 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, Curl_multi_ev_init(multi, ev_hashsize); Curl_uint_tbl_init(&multi->xfers, NULL); Curl_uint_bset_init(&multi->process); + Curl_uint_bset_init(&multi->dirty); Curl_uint_bset_init(&multi->pending); Curl_uint_bset_init(&multi->msgsent); Curl_hash_init(&multi->proto_hash, 23, @@ -246,6 +248,7 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, if(Curl_uint_bset_resize(&multi->process, xfer_table_size) || Curl_uint_bset_resize(&multi->pending, xfer_table_size) || + Curl_uint_bset_resize(&multi->dirty, xfer_table_size) || Curl_uint_bset_resize(&multi->msgsent, xfer_table_size) || Curl_uint_tbl_resize(&multi->xfers, xfer_table_size)) goto error; @@ -268,20 +271,22 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, Curl_cpool_init(&multi->cpool, multi->admin, NULL, chashsize); +#ifdef USE_SSL if(Curl_ssl_scache_create(sesssize, 2, &multi->ssl_scache)) goto error; +#else + (void)sesssize; +#endif #ifdef USE_WINSOCK multi->wsa_event = WSACreateEvent(); if(multi->wsa_event == WSA_INVALID_EVENT) goto error; -#else -#ifdef ENABLE_WAKEUP +#elif defined(ENABLE_WAKEUP) if(wakeup_create(multi->wakeup_pair, TRUE) < 0) { multi->wakeup_pair[0] = CURL_SOCKET_BAD; multi->wakeup_pair[1] = CURL_SOCKET_BAD; } -#endif #endif return multi; @@ -293,13 +298,16 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, Curl_dnscache_destroy(&multi->dnscache); Curl_cpool_destroy(&multi->cpool); Curl_cshutdn_destroy(&multi->cshutdn, multi->admin); +#ifdef USE_SSL Curl_ssl_scache_destroy(multi->ssl_scache); +#endif if(multi->admin) { multi->admin->multi = NULL; Curl_close(&multi->admin); } Curl_uint_bset_destroy(&multi->process); + Curl_uint_bset_destroy(&multi->dirty); Curl_uint_bset_destroy(&multi->pending); Curl_uint_bset_destroy(&multi->msgsent); Curl_uint_tbl_destroy(&multi->xfers); @@ -335,33 +343,57 @@ static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data) static CURLMcode multi_xfers_add(struct Curl_multi *multi, struct Curl_easy *data) { - /* We want `multi->xfers` to have "sufficient" free rows, so that we do - * have to reuse the `mid` from a just removed easy right away. - * Since uint_tbl and uint_bset is quite memory efficient, - * regard less than 25% free as insufficient. - * (for low capacities, e.g. multi_easy, 4 or less). */ unsigned int capacity = Curl_uint_tbl_capacity(&multi->xfers); - unsigned int unused = capacity - Curl_uint_tbl_count(&multi->xfers); - unsigned int min_unused = CURLMAX(capacity >> 2, 4); + unsigned int new_size = 0; + /* Prepare to make this into a CURLMOPT_MAX_TRANSFERS, because some + * applications may want to prevent a run-away of their memory use. */ + /* UINT_MAX is our "invalid" id, do not let the table grow up to that. */ + const unsigned int max_capacity = UINT_MAX - 1; + + if(capacity < max_capacity) { + /* We want `multi->xfers` to have "sufficient" free rows, so that we do + * have to reuse the `mid` from a just removed easy right away. + * Since uint_tbl and uint_bset are quite memory efficient, + * regard less than 25% free as insufficient. + * (for low capacities, e.g. multi_easy, 4 or less). */ + unsigned int used = Curl_uint_tbl_count(&multi->xfers); + unsigned int unused = capacity - used; + unsigned int min_unused = CURLMAX(capacity >> 2, 4); + if(unused <= min_unused) { + /* Make sure the uint arithmetic here works on the corner + * cases where we are close to max_capacity or UINT_MAX */ + if((min_unused >= max_capacity) || + ((max_capacity - min_unused) <= capacity) || + ((UINT_MAX - min_unused - 63) <= capacity)) { + new_size = max_capacity; /* can not be larger than this */ + } + else { + /* make it a 64 multiple, since our bitsets frow by that and + * small (easy_multi) grows to at least 64 on first resize. */ + new_size = (((used + min_unused) + 63) / 64) * 64; + } + } + } - if(unused <= min_unused) { - /* make it a 64 multiple, since our bitsets frow by that and - * small (easy_multi) grows to at least 64 on first resize. */ - unsigned int newsize = ((capacity + min_unused) + 63) / 64; + if(new_size > capacity) { /* Grow the bitsets first. Should one fail, we do not need * to downsize the already resized ones. The sets continue * to work properly when larger than the table, but not * the other way around. */ - if(Curl_uint_bset_resize(&multi->process, newsize) || - Curl_uint_bset_resize(&multi->pending, newsize) || - Curl_uint_bset_resize(&multi->msgsent, newsize) || - Curl_uint_tbl_resize(&multi->xfers, newsize)) + CURL_TRC_M(data, "increasing xfer table size to %u", new_size); + if(Curl_uint_bset_resize(&multi->process, new_size) || + Curl_uint_bset_resize(&multi->dirty, new_size) || + Curl_uint_bset_resize(&multi->pending, new_size) || + Curl_uint_bset_resize(&multi->msgsent, new_size) || + Curl_uint_tbl_resize(&multi->xfers, new_size)) return CURLM_OUT_OF_MEMORY; - CURL_TRC_M(data, "increased xfer table size to %u", newsize); } - /* Insert the easy into the table now that MUST have room for it */ + + /* Insert the easy into the table now */ if(!Curl_uint_tbl_add(&multi->xfers, data, &data->mid)) { - DEBUGASSERT(0); + /* MUST only happen when table is full */ + DEBUGASSERT(Curl_uint_tbl_capacity(&multi->xfers) <= + Curl_uint_tbl_count(&multi->xfers)); return CURLM_OUT_OF_MEMORY; } return CURLM_OK; @@ -399,6 +431,7 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d) return CURLM_ABORTED_BY_CALLBACK; multi->dead = FALSE; Curl_uint_bset_clear(&multi->process); + Curl_uint_bset_clear(&multi->dirty); Curl_uint_bset_clear(&multi->pending); Curl_uint_bset_clear(&multi->msgsent); } @@ -588,7 +621,7 @@ static CURLcode multi_done(struct Curl_easy *data, after an error was detected */ bool premature) { - CURLcode result, r2; + CURLcode result; struct connectdata *conn = data->conn; struct multi_done_ctx mdctx; @@ -637,9 +670,7 @@ static CURLcode multi_done(struct Curl_easy *data, } /* Make sure that transfer client writes are really done now. */ - r2 = Curl_xfer_write_done(data, premature); - if(r2 && !result) - result = r2; + result = Curl_1st_err(result, Curl_xfer_write_done(data, premature)); /* Inform connection filters that this transfer is done */ Curl_conn_ev_data_done(data, premature); @@ -793,6 +824,7 @@ CURLMcode curl_multi_remove_handle(CURLM *m, CURL *d) DEBUGASSERT(Curl_uint_tbl_contains(&multi->xfers, mid)); Curl_uint_tbl_remove(&multi->xfers, mid); Curl_uint_bset_remove(&multi->process, mid); + Curl_uint_bset_remove(&multi->dirty, mid); Curl_uint_bset_remove(&multi->pending, mid); Curl_uint_bset_remove(&multi->msgsent, mid); data->multi = NULL; @@ -1037,11 +1069,25 @@ void Curl_multi_getsock(struct Curl_easy *data, break; } + + /* Unblocked and waiting to receive with buffered input. + * Make transfer run again at next opportunity. */ + if(!Curl_xfer_is_blocked(data) && + ((Curl_pollset_want_read(data, ps, data->conn->sock[FIRSTSOCKET]) && + Curl_conn_data_pending(data, FIRSTSOCKET)) || + (Curl_pollset_want_read(data, ps, data->conn->sock[SECONDARYSOCKET]) && + Curl_conn_data_pending(data, SECONDARYSOCKET)))) { + CURL_TRC_M(data, "%s pollset[] has POLLIN, but there is still " + "buffered input to consume -> mark as dirty", caller); + Curl_multi_mark_dirty(data); + } + switch(ps->num) { case 0: CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)", caller, Curl_llist_count(&data->state.timeoutlist), - Curl_creader_is_paused(data), Curl_cwriter_is_paused(data)); + Curl_xfer_send_is_paused(data), + Curl_xfer_recv_is_paused(data)); break; case 1: CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu", @@ -1165,6 +1211,7 @@ CURLMcode curl_multi_waitfds(CURLM *m, if(!data) { DEBUGASSERT(0); Curl_uint_bset_remove(&multi->process, mid); + Curl_uint_bset_remove(&multi->dirty, mid); continue; } Curl_multi_getsock(data, &ps, "curl_multi_waitfds"); @@ -1217,6 +1264,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; struct curl_pollfds cpfds; unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */ + struct Curl_easy *data = NULL; CURLMcode result = CURLM_OK; unsigned int mid; @@ -1242,11 +1290,12 @@ static CURLMcode multi_wait(struct Curl_multi *multi, /* Add the curl handles to our pollfds first */ if(Curl_uint_bset_first(&multi->process, &mid)) { do { - struct Curl_easy *data = Curl_multi_get_easy(multi, mid); struct easy_pollset ps; + data = Curl_multi_get_easy(multi, mid); if(!data) { DEBUGASSERT(0); Curl_uint_bset_remove(&multi->process, mid); + Curl_uint_bset_remove(&multi->dirty, mid); continue; } Curl_multi_getsock(data, &ps, "multi_wait"); @@ -1319,6 +1368,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi, if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms)) timeout_ms = (int)timeout_internal; + if(data) + CURL_TRC_M(data, "multi_wait(fds=%d, timeout=%d) tinternal=%ld", + cpfds.n, timeout_ms, timeout_internal); #if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK) if(cpfds.n || use_wakeup) { #else @@ -1440,7 +1492,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, timeout */ else if(sleep_ms < 0) sleep_ms = timeout_ms; - Curl_wait_ms(sleep_ms); + curlx_wait_ms(sleep_ms); } } @@ -1945,12 +1997,6 @@ static CURLMcode state_performing(struct Curl_easy *data, } } } - else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) { - /* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer does - not get stuck on this transfer at the expense of other concurrent - transfers */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } free(newurl); *resultp = result; return rc; @@ -2214,6 +2260,7 @@ static CURLMcode state_connect(struct Curl_multi *multi, multistate(data, MSTATE_PENDING); /* move from process to pending set */ Curl_uint_bset_remove(&multi->process, data->mid); + Curl_uint_bset_remove(&multi->dirty, data->mid); Curl_uint_bset_add(&multi->pending, data->mid); *resultp = CURLE_OK; return rc; @@ -2275,6 +2322,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multi_warn_debug(multi, data); + /* transfer runs now, clear the dirty bit. This may be set + * again during processing, triggering a re-run later. */ + Curl_uint_bset_remove(&multi->dirty, data->mid); + do { /* A "stream" here is a logical stream if the protocol can handle that (HTTP/2), or the full connection for older protocols */ @@ -2641,6 +2692,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* remove from the other sets, add to msgsent */ Curl_uint_bset_remove(&multi->process, data->mid); + Curl_uint_bset_remove(&multi->dirty, data->mid); Curl_uint_bset_remove(&multi->pending, data->mid); Curl_uint_bset_add(&multi->msgsent, data->mid); --multi->xfers_alive; @@ -2678,6 +2730,7 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles) if(!data) { DEBUGASSERT(0); Curl_uint_bset_remove(&multi->process, mid); + Curl_uint_bset_remove(&multi->dirty, mid); continue; } if(data != multi->admin) { @@ -2756,7 +2809,7 @@ CURLMcode curl_multi_cleanup(CURLM *m) #ifdef DEBUGBUILD if(mid != data->mid) { CURL_TRC_M(data, "multi_cleanup: still present with mid=%u, " - "but unexpected data->mid=%u\n", mid, data->mid); + "but unexpected data->mid=%u\n", mid, data->mid); DEBUGASSERT(0); } #endif @@ -2797,7 +2850,9 @@ CURLMcode curl_multi_cleanup(CURLM *m) Curl_hash_destroy(&multi->proto_hash); Curl_dnscache_destroy(&multi->dnscache); Curl_psl_destroy(&multi->psl); +#ifdef USE_SSL Curl_ssl_scache_destroy(multi->ssl_scache); +#endif #ifdef USE_WINSOCK WSACloseEvent(multi->wsa_event); @@ -2818,6 +2873,7 @@ CURLMcode curl_multi_cleanup(CURLM *m) } #endif Curl_uint_bset_destroy(&multi->process); + Curl_uint_bset_destroy(&multi->dirty); Curl_uint_bset_destroy(&multi->pending); Curl_uint_bset_destroy(&multi->msgsent); Curl_uint_tbl_destroy(&multi->xfers); @@ -2941,12 +2997,11 @@ struct multi_run_ctx { bool run_cpool; }; -static CURLMcode multi_run_expired(struct multi_run_ctx *mrc) +static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc) { struct Curl_multi *multi = mrc->multi; struct Curl_easy *data = NULL; struct Curl_tree *t = NULL; - CURLMcode result = CURLM_OK; /* * The loop following here will go on as long as there are expire-times left @@ -2958,33 +3013,64 @@ static CURLMcode multi_run_expired(struct multi_run_ctx *mrc) extracts a matching node if there is one */ multi->timetree = Curl_splaygetbest(mrc->now, multi->timetree, &t); if(!t) - goto out; + return; data = Curl_splayget(t); /* assign this for next loop */ if(!data) continue; (void)add_next_timeout(mrc->now, multi, data); - if(data == multi->admin) { - mrc->run_cpool = TRUE; - continue; - } + Curl_multi_mark_dirty(data); + } +} - mrc->run_xfers++; - sigpipe_apply(data, &mrc->pipe_st); - result = multi_runsingle(multi, &mrc->now, data); +static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc) +{ + struct Curl_multi *multi = mrc->multi; + CURLMcode result = CURLM_OK; + unsigned int mid; - if(CURLM_OK >= result) { - /* reassess event handling of data */ - result = Curl_multi_ev_assess_xfer(multi, data); - if(result) - goto out; + if(Curl_uint_bset_first(&multi->dirty, &mid)) { + do { + struct Curl_easy *data = Curl_multi_get_easy(multi, mid); + if(data) { + CURL_TRC_M(data, "multi_run_dirty"); + + if(data == multi->admin) { + Curl_uint_bset_remove(&multi->dirty, mid); + mrc->run_cpool = TRUE; + continue; + } + else if(!Curl_uint_bset_contains(&multi->process, mid)) { + /* We are no longer processing this transfer */ + Curl_uint_bset_remove(&multi->dirty, mid); + continue; + } + + mrc->run_xfers++; + sigpipe_apply(data, &mrc->pipe_st); + /* runsingle() clears the dirty mid */ + result = multi_runsingle(multi, &mrc->now, data); + + if(CURLM_OK >= result) { + /* reassess event handling of data */ + result = Curl_multi_ev_assess_xfer(multi, data); + if(result) + goto out; + } + } + else { + CURL_TRC_M(multi->admin, "multi_run_dirty, %u no longer found", mid); + Curl_uint_bset_remove(&multi->dirty, mid); + } } + while(Curl_uint_bset_next(&multi->dirty, mid, &mid)); } out: return result; } + static CURLMcode multi_socket(struct Curl_multi *multi, bool checkall, curl_socket_t s, @@ -3013,7 +3099,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi, } if(s != CURL_SOCKET_TIMEOUT) { - Curl_multi_ev_expire_xfers(multi, s, &mrc.now, &mrc.run_cpool); + /* Mark all transfers of that socket as dirty */ + Curl_multi_ev_dirty_xfers(multi, s, &mrc.run_cpool); } else { /* Asked to run due to time-out. Clear the 'last_expire_ts' variable to @@ -3025,7 +3112,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi, mrc.run_cpool = TRUE; } - result = multi_run_expired(&mrc); + multi_mark_expired_as_dirty(&mrc); + result = multi_run_dirty(&mrc); if(result) goto out; @@ -3036,7 +3124,8 @@ static CURLMcode multi_socket(struct Curl_multi *multi, * Do that only once or it might be unfair to transfers on other * sockets. */ mrc.now = curlx_now(); - result = multi_run_expired(&mrc); + multi_mark_expired_as_dirty(&mrc); + result = multi_run_dirty(&mrc); } out: @@ -3164,6 +3253,29 @@ CURLMcode curl_multi_socket_all(CURLM *m, int *running_handles) return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles); } + +static bool multi_has_dirties(struct Curl_multi *multi) +{ + unsigned int mid; + if(Curl_uint_bset_first(&multi->dirty, &mid)) { + do { + struct Curl_easy *data = Curl_multi_get_easy(multi, mid); + if(data) { + if(Curl_uint_bset_contains(&multi->process, mid)) + return TRUE; + /* We are no longer processing this transfer */ + Curl_uint_bset_remove(&multi->dirty, mid); + } + else { + CURL_TRC_M(multi->admin, "dirty transfer %u no longer found", mid); + Curl_uint_bset_remove(&multi->dirty, mid); + } + } + while(Curl_uint_bset_next(&multi->dirty, mid, &mid)); + } + return FALSE; +} + static CURLMcode multi_timeout(struct Curl_multi *multi, struct curltime *expire_time, long *timeout_ms) @@ -3175,13 +3287,18 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, return CURLM_OK; } - if(multi->timetree) { + if(multi_has_dirties(multi)) { + *expire_time = curlx_now(); + *timeout_ms = 0; + return CURLM_OK; + } + else if(multi->timetree) { /* we have a tree of expire times */ struct curltime now = curlx_now(); /* splay the lowest to the bottom */ multi->timetree = Curl_splay(tv_zero, multi->timetree); - /* this will not return NULL from a non-emtpy tree, but some compilers + /* this will not return NULL from a non-empty tree, but some compilers * are not convinced of that. Analyzers are hard. */ *expire_time = multi->timetree ? multi->timetree->key : tv_zero; @@ -3196,6 +3313,10 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, *timeout_ms = (long)diff; } else { + if(multi->timetree) { + struct Curl_easy *data = Curl_splayget(multi->timetree); + CURL_TRC_M(data, "multi_timeout() says this has expired"); + } /* 0 means immediately */ *timeout_ms = 0; } @@ -3419,6 +3540,9 @@ void Curl_expire_ex(struct Curl_easy *data, Curl_splayset(&data->state.timenode, data); multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree, &data->state.timenode); + if(data->id >= 0) + CURL_TRC_M(data, "set expire[%d] in %" FMT_TIMEDIFF_T "ns", + id, curlx_timediff_us(set, *nowp)); } /* @@ -3762,9 +3886,15 @@ unsigned int Curl_multi_xfers_running(struct Curl_multi *multi) return multi->xfers_alive; } +void Curl_multi_mark_dirty(struct Curl_easy *data) +{ + if(data->multi && data->mid != UINT_MAX) + Curl_uint_bset_add(&data->multi->dirty, data->mid); +} + #ifdef DEBUGBUILD static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid, - void *entry) + void *entry) { struct Curl_easy *data = entry; diff --git a/vendor/curl/lib/multi_ev.c b/vendor/curl/lib/multi_ev.c index 6d01cca2..0b4c4728 100644 --- a/vendor/curl/lib/multi_ev.c +++ b/vendor/curl/lib/multi_ev.c @@ -303,7 +303,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, CURLMcode mresult; /* The transfer `data` reports in `ps` the sockets it is interested - * in and which combinatino of CURL_POLL_IN/CURL_POLL_OUT it wants + * in and which combination of CURL_POLL_IN/CURL_POLL_OUT it wants * to have monitored for events. * There can be more than 1 transfer interested in the same socket * and 1 transfer might be interested in more than 1 socket. @@ -563,10 +563,9 @@ CURLMcode Curl_multi_ev_assign(struct Curl_multi *multi, return CURLM_OK; } -void Curl_multi_ev_expire_xfers(struct Curl_multi *multi, - curl_socket_t s, - const struct curltime *nowp, - bool *run_cpool) +void Curl_multi_ev_dirty_xfers(struct Curl_multi *multi, + curl_socket_t s, + bool *run_cpool) { struct mev_sh_entry *entry; @@ -586,9 +585,11 @@ void Curl_multi_ev_expire_xfers(struct Curl_multi *multi, do { data = Curl_multi_get_easy(multi, mid); if(data) { - /* Expire with out current now, so we will get it below when - * asking the splaytree for expired transfers. */ - Curl_expire_ex(data, nowp, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); + } + else { + CURL_TRC_M(multi->admin, "socket transfer %u no longer found", mid); + Curl_uint_spbset_remove(&entry->xfers, mid); } } while(Curl_uint_spbset_next(&entry->xfers, mid, &mid)); diff --git a/vendor/curl/lib/multi_ev.h b/vendor/curl/lib/multi_ev.h index 06be842f..20c1aeac 100644 --- a/vendor/curl/lib/multi_ev.h +++ b/vendor/curl/lib/multi_ev.h @@ -61,11 +61,10 @@ CURLMcode Curl_multi_ev_assess_conn(struct Curl_multi *multi, struct Curl_easy *data, struct connectdata *conn); -/* Expire all transfers tied to the given socket */ -void Curl_multi_ev_expire_xfers(struct Curl_multi *multi, - curl_socket_t s, - const struct curltime *nowp, - bool *run_cpool); +/* Mark all transfers tied to the given socket as dirty */ +void Curl_multi_ev_dirty_xfers(struct Curl_multi *multi, + curl_socket_t s, + bool *run_cpool); /* Socket will be closed, forget anything we know about it. */ void Curl_multi_ev_socket_done(struct Curl_multi *multi, diff --git a/vendor/curl/lib/multihandle.h b/vendor/curl/lib/multihandle.h index 04db02f0..4bf2dd81 100644 --- a/vendor/curl/lib/multihandle.h +++ b/vendor/curl/lib/multihandle.h @@ -98,6 +98,7 @@ struct Curl_multi { struct uint_tbl xfers; /* transfers added to this multi */ /* Each transfer's mid may be present in at most one of these */ struct uint_bset process; /* transfer being processed */ + struct uint_bset dirty; /* transfer to be run NOW, e.g. ASAP. */ struct uint_bset pending; /* transfers in waiting (conn limit etc.) */ struct uint_bset msgsent; /* transfers done with message for application */ diff --git a/vendor/curl/lib/multiif.h b/vendor/curl/lib/multiif.h index eae634ab..1ba0d0f8 100644 --- a/vendor/curl/lib/multiif.h +++ b/vendor/curl/lib/multiif.h @@ -36,7 +36,7 @@ bool Curl_expire_clear(struct Curl_easy *data); void Curl_expire_done(struct Curl_easy *data, expire_id id); CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT; void Curl_attach_connection(struct Curl_easy *data, - struct connectdata *conn); + struct connectdata *conn); void Curl_detach_connection(struct Curl_easy *data); bool Curl_multiplex_wanted(const struct Curl_multi *multi); void Curl_set_in_callback(struct Curl_easy *data, bool value); @@ -106,7 +106,7 @@ void Curl_multi_getsock(struct Curl_easy *data, * CURLE_AGAIN if the buffer is borrowed already. */ CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data, - char **pbuf, size_t *pbuflen); + char **pbuf, size_t *pbuflen); /** * Release the borrowed buffer. All references into the buffer become * invalid after this. @@ -173,4 +173,8 @@ struct Curl_easy *Curl_multi_get_easy(struct Curl_multi *multi, /* Get the # of transfers current in process/pending. */ unsigned int Curl_multi_xfers_running(struct Curl_multi *multi); +/* Mark a transfer as dirty, e.g. to be rerun at earliest convenience. + * A cheap operation, can be done many times repeatedly. */ +void Curl_multi_mark_dirty(struct Curl_easy *data); + #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/vendor/curl/lib/netrc.c b/vendor/curl/lib/netrc.c index 7df3f17f..bf53fc01 100644 --- a/vendor/curl/lib/netrc.c +++ b/vendor/curl/lib/netrc.c @@ -229,12 +229,12 @@ static NETRCcode parsenetrc(struct store_netrc *store, switch(state) { case NOTHING: - if(strcasecompare("macdef", tok)) + if(curl_strequal("macdef", tok)) /* Define a macro. A macro is defined with the specified name; its contents begin with the next .netrc line and continue until a null line (consecutive new-line characters) is encountered. */ state = MACDEF; - else if(strcasecompare("machine", tok)) { + else if(curl_strequal("machine", tok)) { /* the next tok is the machine name, this is in itself the delimiter that starts the stuff entered for this machine, after this we need to search for 'login' and 'password'. */ @@ -246,7 +246,7 @@ static NETRCcode parsenetrc(struct store_netrc *store, if(!specific_login) Curl_safefree(login); } - else if(strcasecompare("default", tok)) { + else if(curl_strequal("default", tok)) { state = HOSTVALID; retcode = NETRC_OK; /* we did find our host */ } @@ -256,7 +256,7 @@ static NETRCcode parsenetrc(struct store_netrc *store, state = NOTHING; break; case HOSTFOUND: - if(strcasecompare(host, tok)) { + if(curl_strequal(host, tok)) { /* and yes, this is our host! */ state = HOSTVALID; retcode = NETRC_OK; /* we did find our host */ @@ -293,11 +293,11 @@ static NETRCcode parsenetrc(struct store_netrc *store, found |= FOUND_PASSWORD; keyword = NONE; } - else if(strcasecompare("login", tok)) + else if(curl_strequal("login", tok)) keyword = LOGIN; - else if(strcasecompare("password", tok)) + else if(curl_strequal("password", tok)) keyword = PASSWORD; - else if(strcasecompare("machine", tok)) { + else if(curl_strequal("machine", tok)) { /* a new machine here */ if(found & FOUND_PASSWORD) { done = TRUE; @@ -310,7 +310,7 @@ static NETRCcode parsenetrc(struct store_netrc *store, if(!specific_login) Curl_safefree(login); } - else if(strcasecompare("default", tok)) { + else if(curl_strequal("default", tok)) { state = HOSTVALID; retcode = NETRC_OK; /* we did find our host */ Curl_safefree(password); diff --git a/vendor/curl/lib/noproxy.c b/vendor/curl/lib/noproxy.c index 0ecd8e17..306cd6d1 100644 --- a/vendor/curl/lib/noproxy.c +++ b/vendor/curl/lib/noproxy.c @@ -26,8 +26,8 @@ #ifndef CURL_DISABLE_PROXY +#include /* for curl_strnequal() */ #include "curlx/inet_pton.h" -#include "strcase.h" #include "noproxy.h" #include "curlx/strparse.h" @@ -205,12 +205,12 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy) */ if(tokenlen == namelen) /* case A, exact match */ - match = strncasecompare(token, name, namelen); + match = curl_strnequal(token, name, namelen); else if(tokenlen < namelen) { /* case B, tailmatch domain */ match = (name[namelen - tokenlen - 1] == '.') && - strncasecompare(token, name + (namelen - tokenlen), - tokenlen); + curl_strnequal(token, name + (namelen - tokenlen), + tokenlen); } /* case C passes through, not a match */ break; @@ -234,7 +234,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy) /* if the bits variable gets a crazy value here, that is fine as the value will then be rejected in the cidr function */ bits = (unsigned int)atoi(slash + 1); - *slash = 0; /* null terminate there */ + *slash = 0; /* null-terminate there */ } if(type == TYPE_IPV6) match = Curl_cidr6_match(name, check, bits); diff --git a/vendor/curl/lib/openldap.c b/vendor/curl/lib/openldap.c index 6343c40c..e4714b55 100644 --- a/vendor/curl/lib/openldap.c +++ b/vendor/curl/lib/openldap.c @@ -941,7 +941,6 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, ldap_unbind_ext(li->ld, NULL, NULL); li->ld = NULL; } - Curl_sasl_cleanup(conn, li->sasl.authused); } return CURLE_OK; } @@ -1048,8 +1047,8 @@ static CURLcode client_write(struct Curl_easy *data, return result; } -static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, - size_t len, CURLcode *err) +static CURLcode oldap_recv(struct Curl_easy *data, int sockindex, char *buf, + size_t len, size_t *pnread) { struct connectdata *conn = data->conn; struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN); @@ -1067,10 +1066,9 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, (void)len; (void)buf; (void)sockindex; - if(!li || !lr) { - *err = CURLE_FAILED_INIT; - return -1; - } + *pnread = 0; + if(!li || !lr) + return CURLE_FAILED_INIT; rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg); if(rc < 0) { @@ -1078,11 +1076,9 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, result = CURLE_RECV_ERROR; } - *err = result; - /* error or timed out */ if(!msg) - return -1; + return result; result = CURLE_OK; @@ -1210,8 +1206,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, } ldap_msgfree(msg); - *err = result; - return result ? -1 : 0; + return result; } #ifdef USE_SSL @@ -1258,15 +1253,17 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) if(conn) { struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN); CURLcode err = CURLE_RECV_ERROR; + size_t nread; if(!li) { SET_SOCKERRNO(SOCKEINVAL); return -1; } - ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err); - if(ret < 0 && err == CURLE_AGAIN) { + err = (li->recv)(data, FIRSTSOCKET, buf, len, &nread); + if(err == CURLE_AGAIN) { SET_SOCKERRNO(SOCKEWOULDBLOCK); } + ret = err ? -1 : (ber_slen_t)nread; } } return ret; @@ -1281,15 +1278,17 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) if(conn) { struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN); CURLcode err = CURLE_SEND_ERROR; + size_t nwritten; if(!li) { SET_SOCKERRNO(SOCKEINVAL); return -1; } - ret = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &err); - if(ret < 0 && err == CURLE_AGAIN) { + err = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &nwritten); + if(err == CURLE_AGAIN) { SET_SOCKERRNO(SOCKEWOULDBLOCK); } + ret = err ? -1 : (ber_slen_t)nwritten; } } return ret; diff --git a/vendor/curl/lib/parsedate.c b/vendor/curl/lib/parsedate.c index 7e0c6910..65730d6c 100644 --- a/vendor/curl/lib/parsedate.c +++ b/vendor/curl/lib/parsedate.c @@ -80,7 +80,6 @@ #include #include -#include "strcase.h" #include "curlx/warnless.h" #include "parsedate.h" #include "curlx/strparse.h" @@ -224,7 +223,7 @@ static int checkday(const char *check, size_t len) for(i = 0; i < 7; i++) { size_t ilen = strlen(what[0]); if((ilen == len) && - strncasecompare(check, what[0], len)) + curl_strnequal(check, what[0], len)) return i; what++; } @@ -239,7 +238,7 @@ static int checkmonth(const char *check, size_t len) return -1; /* not a month */ for(i = 0; i < 12; i++) { - if(strncasecompare(check, what[0], 3)) + if(curl_strnequal(check, what[0], 3)) return i; what++; } @@ -259,7 +258,7 @@ static int checktz(const char *check, size_t len) for(i = 0; i < CURL_ARRAYSIZE(tz); i++) { size_t ilen = strlen(what->name); if((ilen == len) && - strncasecompare(check, what->name, len)) + curl_strnequal(check, what->name, len)) return what->offset*60; what++; } diff --git a/vendor/curl/lib/pingpong.c b/vendor/curl/lib/pingpong.c index c5513f60..a661a028 100644 --- a/vendor/curl/lib/pingpong.c +++ b/vendor/curl/lib/pingpong.c @@ -52,7 +52,7 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data, struct pingpong *pp, bool disconnecting) { timediff_t timeout_ms; /* in milliseconds */ - timediff_t response_time = (data->set.server_response_timeout) ? + timediff_t response_time = (data->set.server_response_timeout > 0) ? data->set.server_response_timeout : pp->response_time; struct curltime now = curlx_now(); @@ -65,7 +65,7 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data, full response to arrive before we bail out */ timeout_ms = response_time - curlx_timediff(now, pp->response); - if(data->set.timeout && !disconnecting) { + if((data->set.timeout > 0) && !disconnecting) { /* if timeout is requested, find out how much overall remains */ timediff_t timeout2_ms = Curl_timeleft(data, &now, FALSE); /* pick the lowest number */ @@ -116,11 +116,15 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data, else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET)) /* We are receiving and there is data ready in the SSL library */ rc = 1; - else + else { + DEBUGF(infof(data, "pp_statematch, select, timeout=%" FMT_TIMEDIFF_T + ", sendleft=%zu", + timeout_ms, pp->sendleft)); rc = Curl_socket_check(pp->sendleft ? CURL_SOCKET_BAD : sock, /* reading */ CURL_SOCKET_BAD, pp->sendleft ? sock : CURL_SOCKET_BAD, /* writing */ interval_ms); + } if(block) { /* if we did not wait, we do not have to spend time on this now */ @@ -266,7 +270,7 @@ static CURLcode pingpong_read(struct Curl_easy *data, int sockindex, char *buffer, size_t buflen, - ssize_t *nread) + size_t *nread) { CURLcode result; #ifdef HAVE_GSSAPI @@ -294,7 +298,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, { struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; - ssize_t gotbytes; + size_t gotbytes; char buffer[900]; *code = 0; /* 0 for errors or not done */ @@ -321,7 +325,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, if(result) return result; - if(gotbytes <= 0) { + if(!gotbytes) { failf(data, "response reading failed (errno: %d)", SOCKERRNO); return CURLE_RECV_ERROR; } diff --git a/vendor/curl/lib/pingpong.h b/vendor/curl/lib/pingpong.h index 0665b836..c6d0a56f 100644 --- a/vendor/curl/lib/pingpong.h +++ b/vendor/curl/lib/pingpong.h @@ -59,7 +59,7 @@ struct pingpong { struct dynbuf recvbuf; size_t overflow; /* number of bytes left after a final response line */ size_t nfinal; /* number of bytes in the final response line, which - after a match is first in the receice buffer */ + after a match is first in the receive buffer */ /* Function pointers the protocols MUST implement and provide for the pingpong layer to function */ diff --git a/vendor/curl/lib/pop3.c b/vendor/curl/lib/pop3.c index 852834ec..514c4b8f 100644 --- a/vendor/curl/lib/pop3.c +++ b/vendor/curl/lib/pop3.c @@ -66,7 +66,6 @@ #include "socks.h" #include "pingpong.h" #include "pop3.h" -#include "strcase.h" #include "vtls/vtls.h" #include "cfilters.h" #include "connect.h" @@ -285,7 +284,7 @@ static bool pop3_is_multiline(const char *cmdline) { size_t i; for(i = 0; i < CURL_ARRAYSIZE(pop3cmds); ++i) { - if(strncasecompare(pop3cmds[i].name, cmdline, pop3cmds[i].nlen)) { + if(curl_strnequal(pop3cmds[i].name, cmdline, pop3cmds[i].nlen)) { if(!cmdline[pop3cmds[i].nlen]) return pop3cmds[i].multiline; else if(cmdline[pop3cmds[i].nlen] == ' ') @@ -874,7 +873,7 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, line = curlx_dyn_ptr(&pop3c->pp.recvbuf); len = pop3c->pp.nfinal; - /* Do we have a untagged continuation response? */ + /* Do we have an untagged continuation response? */ if(pop3code == '*') { /* Does the server support the STLS capability? */ if(len >= 4 && !memcmp(line, "STLS", 4)) @@ -1450,7 +1449,8 @@ static CURLcode pop3_disconnect(struct Curl_easy *data, bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ - if(!dead_connection && conn->bits.protoconnstart) { + if(!dead_connection && conn->bits.protoconnstart && + !Curl_pp_needs_flush(data, &pop3c->pp)) { if(!pop3_perform_quit(data, conn)) (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */ } @@ -1458,9 +1458,6 @@ static CURLcode pop3_disconnect(struct Curl_easy *data, /* Disconnect from the server */ Curl_pp_disconnect(&pop3c->pp); - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, pop3c->sasl.authused); - /* Cleanup our connection based variables */ Curl_safefree(pop3c->apoptimestamp); @@ -1593,11 +1590,11 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strncasecompare(key, "AUTH=", 5)) { + if(curl_strnequal(key, "AUTH=", 5)) { result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, value, ptr - value); - if(result && strncasecompare(value, "+APOP", ptr - value)) { + if(result && curl_strnequal(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; pop3c->sasl.prefmech = SASL_AUTH_NONE; result = CURLE_OK; diff --git a/vendor/curl/lib/progress.c b/vendor/curl/lib/progress.c index 8e6d98f0..746805f2 100644 --- a/vendor/curl/lib/progress.c +++ b/vendor/curl/lib/progress.c @@ -44,18 +44,18 @@ static void time2str(char *r, curl_off_t seconds) strcpy(r, "--:--:--"); return; } - h = seconds / CURL_OFF_T_C(3600); - if(h <= CURL_OFF_T_C(99)) { - curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60); - curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60)); + h = seconds / 3600; + if(h <= 99) { + curl_off_t m = (seconds - (h * 3600)) / 60; + curl_off_t s = (seconds - (h * 3600)) - (m * 60); msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, h, m, s); } else { /* this equals to more than 99 hours, switch to a more suitable output format to fit within the limits. */ - curl_off_t d = seconds / CURL_OFF_T_C(86400); - h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600); - if(d <= CURL_OFF_T_C(999)) + curl_off_t d = seconds / 86400; + h = (seconds - (d * 86400)) / 3600; + if(d <= 999) msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h); else msnprintf(r, 9, "%7" FMT_OFF_T "d", d); @@ -67,39 +67,39 @@ static void time2str(char *r, curl_off_t seconds) Add suffix k, M, G when suitable... */ static char *max5data(curl_off_t bytes, char *max5) { -#define ONE_KILOBYTE CURL_OFF_T_C(1024) -#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE) -#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE) -#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE) -#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE) +#define ONE_KILOBYTE (curl_off_t)1024 +#define ONE_MEGABYTE (1024 * ONE_KILOBYTE) +#define ONE_GIGABYTE (1024 * ONE_MEGABYTE) +#define ONE_TERABYTE (1024 * ONE_GIGABYTE) +#define ONE_PETABYTE (1024 * ONE_TERABYTE) - if(bytes < CURL_OFF_T_C(100000)) + if(bytes < 100000) msnprintf(max5, 6, "%5" FMT_OFF_T, bytes); - else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE) + else if(bytes < 10000 * ONE_KILOBYTE) msnprintf(max5, 6, "%4" FMT_OFF_T "k", bytes/ONE_KILOBYTE); - else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE) + else if(bytes < 100 * ONE_MEGABYTE) /* 'XX.XM' is good as long as we are less than 100 megs */ msnprintf(max5, 6, "%2" FMT_OFF_T ".%0" FMT_OFF_T "M", bytes/ONE_MEGABYTE, - (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); + (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/10) ); - else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) + else if(bytes < 10000 * ONE_MEGABYTE) /* 'XXXXM' is good until we are at 10000MB or above */ msnprintf(max5, 6, "%4" FMT_OFF_T "M", bytes/ONE_MEGABYTE); - else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE) + else if(bytes < 100 * ONE_GIGABYTE) /* 10000 MB - 100 GB, we show it as XX.XG */ msnprintf(max5, 6, "%2" FMT_OFF_T ".%0" FMT_OFF_T "G", bytes/ONE_GIGABYTE, - (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) ); + (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/10) ); - else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE) + else if(bytes < 10000 * ONE_GIGABYTE) /* up to 10000GB, display without decimal: XXXXG */ msnprintf(max5, 6, "%4" FMT_OFF_T "G", bytes/ONE_GIGABYTE); - else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE) + else if(bytes < 10000 * ONE_TERABYTE) /* up to 10000TB, display without decimal: XXXXT */ msnprintf(max5, 6, "%4" FMT_OFF_T "T", bytes/ONE_TERABYTE); @@ -296,7 +296,7 @@ timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d, * stay below 'limit'. */ if(size < CURL_OFF_T_MAX/1000) - minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / speed_limit); + minimum = (timediff_t) (1000 * size / speed_limit); else { minimum = (timediff_t) (size / speed_limit); if(minimum < TIMEDIFF_T_MAX/1000) @@ -455,7 +455,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now) /* Calculate the average speed the last 'span_ms' milliseconds */ amount = p->speeder[nowindex]- p->speeder[checkindex]; - if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */) + if(amount > (0xffffffff/1000)) /* the 'amount' value is bigger than would fit in 32 bits if multiplied with 1000, so we use the double math for this */ p->current_speed = (curl_off_t) @@ -463,7 +463,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now) else /* the 'amount' value is small enough to fit within 32 bits even when multiplied with 1000 */ - p->current_speed = amount*CURL_OFF_T_C(1000)/span_ms; + p->current_speed = amount * 1000/span_ms; } else /* the first second we use the average */ @@ -482,9 +482,9 @@ struct pgrs_estimate { static curl_off_t pgrs_est_percent(curl_off_t total, curl_off_t cur) { - if(total > CURL_OFF_T_C(10000)) - return cur / (total/CURL_OFF_T_C(100)); - else if(total > CURL_OFF_T_C(0)) + if(total > 10000) + return cur / (total / 100); + else if(total > 0) return (cur*100) / total; return 0; } @@ -495,7 +495,7 @@ static void pgrs_estimates(struct pgrs_dir *d, { est->secs = 0; est->percent = 0; - if(total_known && (d->speed > CURL_OFF_T_C(0))) { + if(total_known && (d->speed > 0)) { est->secs = d->total_size / d->speed; est->percent = pgrs_est_percent(d->total_size, d->cur_size); } diff --git a/vendor/curl/lib/rand.c b/vendor/curl/lib/rand.c index c0368dd7..72545e08 100644 --- a/vendor/curl/lib/rand.c +++ b/vendor/curl/lib/rand.c @@ -103,8 +103,8 @@ CURLcode Curl_win32_random(unsigned char *entropy, size_t length) #if !defined(USE_SSL) /* ---- possibly non-cryptographic version following ---- */ static CURLcode weak_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) /* always 4, size of int */ + unsigned char *entropy, + size_t length) /* always 4, size of int */ { unsigned int r; DEBUGASSERT(length == sizeof(int)); diff --git a/vendor/curl/lib/request.c b/vendor/curl/lib/request.c index f937a7f4..0d9b23ef 100644 --- a/vendor/curl/lib/request.c +++ b/vendor/curl/lib/request.c @@ -338,20 +338,18 @@ static CURLcode req_flush(struct Curl_easy *data) return CURLE_OK; } -static ssize_t add_from_client(void *reader_ctx, - unsigned char *buf, size_t buflen, - CURLcode *err) +static CURLcode add_from_client(void *reader_ctx, + unsigned char *buf, size_t buflen, + size_t *pnread) { struct Curl_easy *data = reader_ctx; - size_t nread; + CURLcode result; bool eos; - *err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos); - if(*err) - return -1; - if(eos) + result = Curl_client_read(data, (char *)buf, buflen, pnread, &eos); + if(!result && eos) data->req.eos_read = TRUE; - return (ssize_t)nread; + return result; } static CURLcode req_send_buffer_add(struct Curl_easy *data, @@ -359,13 +357,12 @@ static CURLcode req_send_buffer_add(struct Curl_easy *data, size_t hds_len) { CURLcode result = CURLE_OK; - ssize_t n; - n = Curl_bufq_write(&data->req.sendbuf, - (const unsigned char *)buf, blen, &result); - if(n < 0) + size_t n; + result = Curl_bufq_cwrite(&data->req.sendbuf, buf, blen, &n); + if(result) return result; /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */ - DEBUGASSERT((size_t)n == blen); + DEBUGASSERT(n == blen); data->req.sendbuf_hds_len += hds_len; return CURLE_OK; } @@ -435,11 +432,12 @@ CURLcode Curl_req_send_more(struct Curl_easy *data) /* Fill our send buffer if more from client can be read. */ if(!data->req.upload_aborted && !data->req.eos_read && - !(data->req.keepon & KEEP_SEND_PAUSE) && + !Curl_xfer_send_is_paused(data) && !Curl_bufq_is_full(&data->req.sendbuf)) { - ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0, - add_from_client, data, &result); - if(nread < 0 && result != CURLE_AGAIN) + size_t nread; + result = Curl_bufq_sipn(&data->req.sendbuf, 0, + add_from_client, data, &nread); + if(result && result != CURLE_AGAIN) return result; } diff --git a/vendor/curl/lib/select.c b/vendor/curl/lib/select.c index ee239b73..2353c474 100644 --- a/vendor/curl/lib/select.c +++ b/vendor/curl/lib/select.c @@ -36,75 +36,19 @@ #include #endif -#ifdef MSDOS -#include /* delay() */ -#endif - #include #include "urldata.h" #include "connect.h" #include "select.h" #include "curlx/timediff.h" +#include "curlx/wait.h" #include "curlx/warnless.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -/* - * Internal function used for waiting a specific amount of ms in - * Curl_socket_check() and Curl_poll() when no file descriptor is provided to - * wait on, just being used to delay execution. Winsock select() and poll() - * timeout mechanisms need a valid socket descriptor in a not null file - * descriptor set to work. Waiting indefinitely with this function is not - * allowed, a zero or negative timeout value will return immediately. Timeout - * resolution, accuracy, as well as maximum supported value is system - * dependent, neither factor is a critical issue for the intended use of this - * function in the library. - * - * Return values: - * -1 = system call error, or invalid timeout value - * 0 = specified timeout has elapsed, or interrupted - */ -int Curl_wait_ms(timediff_t timeout_ms) -{ - int r = 0; - - if(!timeout_ms) - return 0; - if(timeout_ms < 0) { - SET_SOCKERRNO(SOCKEINVAL); - return -1; - } -#if defined(MSDOS) - delay((unsigned int)timeout_ms); -#elif defined(_WIN32) - /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */ -#if TIMEDIFF_T_MAX >= ULONG_MAX - if(timeout_ms >= ULONG_MAX) - timeout_ms = ULONG_MAX-1; - /* do not use ULONG_MAX, because that is equal to INFINITE */ -#endif - Sleep((DWORD)timeout_ms); -#else - /* avoid using poll() for this since it behaves incorrectly with no sockets - on Apple operating systems */ - { - struct timeval pending_tv; - r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms)); - } -#endif /* _WIN32 */ - if(r) { - if((r == -1) && (SOCKERRNO == SOCKEINTR)) - /* make EINTR from select or poll not a "lethal" error */ - r = 0; - else - r = -1; - } - return r; -} - #ifndef HAVE_POLL /* * This is a wrapper around select() to aid in Windows compatibility. A @@ -132,7 +76,7 @@ static int our_select(curl_socket_t maxfd, /* highest socket number */ (!fds_write || fds_write->fd_count == 0) && (!fds_err || fds_err->fd_count == 0)) { /* no sockets, just wait */ - return Curl_wait_ms(timeout_ms); + return curlx_wait_ms(timeout_ms); } #endif @@ -194,7 +138,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ - return Curl_wait_ms(timeout_ms); + return curlx_wait_ms(timeout_ms); } /* Avoid initial timestamp, avoid curlx_now() call, when elapsed @@ -289,7 +233,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms) } if(fds_none) { /* no sockets, just wait */ - return Curl_wait_ms(timeout_ms); + return curlx_wait_ms(timeout_ms); } /* Avoid initial timestamp, avoid curlx_now() call, when elapsed diff --git a/vendor/curl/lib/select.h b/vendor/curl/lib/select.h index 10968fab..e9cec600 100644 --- a/vendor/curl/lib/select.h +++ b/vendor/curl/lib/select.h @@ -82,7 +82,6 @@ int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); -int Curl_wait_ms(timediff_t timeout_ms); /* With Winsock the valid range is [0..INVALID_SOCKET-1] according to diff --git a/vendor/curl/lib/sendf.c b/vendor/curl/lib/sendf.c index feb4598b..339a8773 100644 --- a/vendor/curl/lib/sendf.c +++ b/vendor/curl/lib/sendf.c @@ -38,6 +38,7 @@ #include "urldata.h" #include "sendf.h" +#include "transfer.h" #include "cfilters.h" #include "connect.h" #include "content_encoding.h" @@ -176,8 +177,8 @@ void Curl_creader_set_rewind(struct Curl_easy *data, bool enable) /* Write data using an unencoding writer stack. */ CURLcode Curl_cwriter_write(struct Curl_easy *data, - struct Curl_cwriter *writer, int type, - const char *buf, size_t nbytes) + struct Curl_cwriter *writer, int type, + const char *buf, size_t nbytes) { if(!writer) return CURLE_WRITE_ERROR; @@ -376,9 +377,9 @@ static const struct Curl_cwtype cw_raw = { /* Create an unencoding writer stage using the given handler. */ CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter, - struct Curl_easy *data, - const struct Curl_cwtype *cwt, - Curl_cwriter_phase phase) + struct Curl_easy *data, + const struct Curl_cwtype *cwt, + Curl_cwriter_phase phase) { struct Curl_cwriter *writer = NULL; CURLcode result = CURLE_OUT_OF_MEMORY; @@ -403,7 +404,7 @@ CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter, } void Curl_cwriter_free(struct Curl_easy *data, - struct Curl_cwriter *writer) + struct Curl_cwriter *writer) { if(writer) { writer->cwt->do_close(data, writer); @@ -660,6 +661,7 @@ static CURLcode cr_in_read(struct Curl_easy *data, size_t *pnread, bool *peos) { struct cr_in_ctx *ctx = reader->ctx; + CURLcode result = CURLE_OK; size_t nread; ctx->is_paused = FALSE; @@ -697,7 +699,8 @@ static CURLcode cr_in_read(struct Curl_easy *data, failf(data, "client read function EOF fail, " "only %"FMT_OFF_T"/%"FMT_OFF_T " of needed bytes read", ctx->read_len, ctx->total_len); - return CURLE_READ_ERROR; + result = CURLE_READ_ERROR; + break; } *pnread = 0; *peos = TRUE; @@ -710,7 +713,8 @@ static CURLcode cr_in_read(struct Curl_easy *data, *peos = FALSE; ctx->errored = TRUE; ctx->error_result = CURLE_ABORTED_BY_CALLBACK; - return CURLE_ABORTED_BY_CALLBACK; + result = CURLE_ABORTED_BY_CALLBACK; + break; case CURL_READFUNC_PAUSE: if(data->conn->handler->flags & PROTOPT_NONETWORK) { @@ -718,14 +722,15 @@ static CURLcode cr_in_read(struct Curl_easy *data, actually only FILE:// just now, and it cannot pause since the transfer is not done using the "normal" procedure. */ failf(data, "Read callback asked for PAUSE when not supported"); - return CURLE_READ_ERROR; + result = CURLE_READ_ERROR; + break; } /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */ CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE"); ctx->is_paused = TRUE; - data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */ *pnread = 0; *peos = FALSE; + result = Curl_xfer_pause_send(data, TRUE); break; /* nothing was read */ default: @@ -736,7 +741,8 @@ static CURLcode cr_in_read(struct Curl_easy *data, *peos = FALSE; ctx->errored = TRUE; ctx->error_result = CURLE_READ_ERROR; - return CURLE_READ_ERROR; + result = CURLE_READ_ERROR; + break; } ctx->read_len += nread; if(ctx->total_len >= 0) @@ -747,9 +753,9 @@ static CURLcode cr_in_read(struct Curl_easy *data, } CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"FMT_OFF_T ", read=%"FMT_OFF_T") -> %d, nread=%zu, eos=%d", - blen, ctx->total_len, ctx->read_len, CURLE_OK, + blen, ctx->total_len, ctx->read_len, result, *pnread, *peos); - return CURLE_OK; + return result; } static bool cr_in_needs_rewind(struct Curl_easy *data, @@ -1362,7 +1368,7 @@ static const struct Curl_crtype cr_buf = { }; CURLcode Curl_creader_set_buf(struct Curl_easy *data, - const char *buf, size_t blen) + const char *buf, size_t blen) { CURLcode result; struct Curl_creader *r; diff --git a/vendor/curl/lib/setopt.c b/vendor/curl/lib/setopt.c index dae870a5..1380c33d 100644 --- a/vendor/curl/lib/setopt.c +++ b/vendor/curl/lib/setopt.c @@ -60,6 +60,35 @@ #include "curl_memory.h" #include "memdebug.h" + +static CURLcode setopt_set_timeout_sec(timediff_t *ptimeout_ms, long secs) +{ + if(secs < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; +#if LONG_MAX > (TIMEDIFF_T_MAX/1000) + if(secs > (TIMEDIFF_T_MAX/1000)) { + *ptimeout_ms = TIMEDIFF_T_MAX; + return CURLE_OK; + } +#endif + *ptimeout_ms = (timediff_t)secs * 1000; + return CURLE_OK; +} + +static CURLcode setopt_set_timeout_ms(timediff_t *ptimeout_ms, long ms) +{ + if(ms < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; +#if LONG_MAX > TIMEDIFF_T_MAX + if(ms > TIMEDIFF_T_MAX) { + *ptimeout_ms = TIMEDIFF_T_MAX; + return CURLE_OK; + } +#endif + *ptimeout_ms = (timediff_t)ms; + return CURLE_OK; +} + CURLcode Curl_setstropt(char **charp, const char *s) { /* Release the previous storage at `charp' and replace by a dynamic storage @@ -211,6 +240,7 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val) return CURLE_OK; } +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY) static CURLcode httpauth(struct Curl_easy *data, bool proxy, unsigned long auth) { @@ -255,6 +285,7 @@ static CURLcode httpauth(struct Curl_easy *data, bool proxy, data->set.httpauth = auth; return CURLE_OK; } +#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */ #ifndef CURL_DISABLE_HTTP static CURLcode setopt_HTTP_VERSION(struct Curl_easy *data, long arg) @@ -526,21 +557,15 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * Option that specifies how quickly a server response must be obtained * before it is considered failure. For pingpong protocols. */ - if((arg >= 0) && (arg <= (INT_MAX/1000))) - data->set.server_response_timeout = (unsigned int)arg * 1000; - else - return CURLE_BAD_FUNCTION_ARGUMENT; - break; + return setopt_set_timeout_sec(&data->set.server_response_timeout, arg); + case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: /* * Option that specifies how quickly a server response must be obtained * before it is considered failure. For pingpong protocols. */ - if((arg >= 0) && (arg <= INT_MAX)) - data->set.server_response_timeout = (unsigned int)arg; - else - return CURLE_BAD_FUNCTION_ARGUMENT; - break; + return setopt_set_timeout_ms(&data->set.server_response_timeout, arg); + #ifndef CURL_DISABLE_TFTP case CURLOPT_TFTP_NO_OPTIONS: /* @@ -883,10 +908,8 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, /* * The maximum time for curl to wait for FTP server connect */ - if(uarg > UINT_MAX) - uarg = UINT_MAX; - data->set.accepttimeout = (unsigned int)uarg; - break; + return setopt_set_timeout_ms(&data->set.accepttimeout, arg); + case CURLOPT_WILDCARDMATCH: data->set.wildcard_enabled = enabled; break; @@ -943,33 +966,19 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * The maximum time you allow curl to use for a single transfer * operation. */ - if((arg >= 0) && (arg <= (INT_MAX/1000))) - data->set.timeout = (unsigned int)arg * 1000; - else - return CURLE_BAD_FUNCTION_ARGUMENT; - break; + return setopt_set_timeout_sec(&data->set.timeout, arg); case CURLOPT_TIMEOUT_MS: - if(uarg > UINT_MAX) - uarg = UINT_MAX; - data->set.timeout = (unsigned int)uarg; - break; + return setopt_set_timeout_ms(&data->set.timeout, arg); case CURLOPT_CONNECTTIMEOUT: /* * The maximum time you allow curl to use to connect. */ - if((arg >= 0) && (arg <= (INT_MAX/1000))) - data->set.connecttimeout = (unsigned int)arg * 1000; - else - return CURLE_BAD_FUNCTION_ARGUMENT; - break; + return setopt_set_timeout_sec(&data->set.connecttimeout, arg); case CURLOPT_CONNECTTIMEOUT_MS: - if(uarg > UINT_MAX) - uarg = UINT_MAX; - data->set.connecttimeout = (unsigned int)uarg; - break; + return setopt_set_timeout_ms(&data->set.connecttimeout, arg); case CURLOPT_RESUME_FROM: /* @@ -1074,13 +1083,9 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, break; case CURLOPT_SSL_FALSESTART: /* - * Enable TLS false start. + * No TLS backends support false start anymore. */ - if(!Curl_ssl_false_start()) - return CURLE_NOT_BUILT_IN; - - data->set.ssl.falsestart = enabled; - break; + return CURLE_NOT_BUILT_IN; case CURLOPT_CERTINFO: #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CERTINFO)) @@ -1347,10 +1352,8 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, data->set.suppress_connect_headers = enabled; break; case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: - if(uarg > UINT_MAX) - uarg = UINT_MAX; - data->set.happy_eyeballs_timeout = (unsigned int)uarg; - break; + return setopt_set_timeout_ms(&data->set.happy_eyeballs_timeout, arg); + #ifndef CURL_DISABLE_SHUFFLE_DNS case CURLOPT_DNS_SHUFFLE_ADDRESSES: data->set.dns_shuffle_addresses = enabled; @@ -1366,15 +1369,11 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, data->set.upkeep_interval_ms = arg; break; case CURLOPT_MAXAGE_CONN: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.maxage_conn = arg; - break; + return setopt_set_timeout_sec(&data->set.conn_max_idle_ms, arg); + case CURLOPT_MAXLIFETIME_CONN: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.maxlifetime_conn = arg; - break; + return setopt_set_timeout_sec(&data->set.conn_max_age_ms, arg); + #ifndef CURL_DISABLE_HSTS case CURLOPT_HSTS_CTRL: if(arg & CURLHSTS_ENABLE) { @@ -1877,23 +1876,23 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, if(!ptr) break; - if(strcasecompare(ptr, "ALL")) { + if(curl_strequal(ptr, "ALL")) { /* clear all cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearall(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(strcasecompare(ptr, "SESS")) { + else if(curl_strequal(ptr, "SESS")) { /* clear session cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearsess(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(strcasecompare(ptr, "FLUSH")) { + else if(curl_strequal(ptr, "FLUSH")) { /* flush cookies to file, takes care of the locking */ Curl_flush_cookies(data, FALSE); } - else if(strcasecompare(ptr, "RELOAD")) { + else if(curl_strequal(ptr, "RELOAD")) { /* reload cookies from file */ Curl_cookie_loadfiles(data); break; @@ -2022,7 +2021,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, break; case CURLOPT_SSL_CTX_DATA: /* - * Set a SSL_CTX callback parameter pointer + * Set an SSL_CTX callback parameter pointer */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) { @@ -2557,12 +2556,12 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], ptr); #endif case CURLOPT_TLSAUTH_TYPE: - if(ptr && !strcasecompare(ptr, "SRP")) + if(ptr && !curl_strequal(ptr, "SRP")) return CURLE_BAD_FUNCTION_ARGUMENT; break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_TYPE: - if(ptr && !strcasecompare(ptr, "SRP")) + if(ptr && !curl_strequal(ptr, "SRP")) return CURLE_BAD_FUNCTION_ARGUMENT; break; #endif @@ -2787,7 +2786,7 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, break; case CURLOPT_SSL_CTX_FUNCTION: /* - * Set a SSL_CTX callback + * Set an SSL_CTX callback */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) { diff --git a/vendor/curl/lib/setup-vms.h b/vendor/curl/lib/setup-vms.h index d74f4ad6..0fd5e542 100644 --- a/vendor/curl/lib/setup-vms.h +++ b/vendor/curl/lib/setup-vms.h @@ -374,11 +374,9 @@ static struct passwd *vms_getpwuid(uid_t uid) #ifdef HAVE_NETDB_H #include #ifndef AI_NUMERICHOST -#ifdef USE_IPV6 #undef USE_IPV6 #endif #endif -#endif /* VAX symbols are always in uppercase */ #ifdef __VAX diff --git a/vendor/curl/lib/setup-win32.h b/vendor/curl/lib/setup-win32.h index 35fe513a..02177a7a 100644 --- a/vendor/curl/lib/setup-win32.h +++ b/vendor/curl/lib/setup-win32.h @@ -30,10 +30,10 @@ /* ---------------------------------------------------------------- */ #ifdef USE_WATT32 # include +# include # undef byte # undef word # define HAVE_SYS_IOCTL_H -# define HAVE_SYS_SOCKET_H # define HAVE_NETINET_IN_H # define HAVE_NETDB_H # define HAVE_ARPA_INET_H @@ -82,9 +82,6 @@ # include # include # include -# ifdef UNICODE - typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); -# endif #endif /* diff --git a/vendor/curl/lib/smb.c b/vendor/curl/lib/smb.c index c8d03ddb..3eee1646 100644 --- a/vendor/curl/lib/smb.c +++ b/vendor/curl/lib/smb.c @@ -543,7 +543,7 @@ static CURLcode smb_recv_message(struct Curl_easy *data, void **msg) { char *buf = smbc->recv_buf; - ssize_t bytes_read; + size_t bytes_read; size_t nbt_size; size_t msg_size; size_t len = MAX_MESSAGE_SIZE - smbc->got; @@ -723,7 +723,7 @@ static CURLcode smb_send_setup(struct Curl_easy *data) "%s%c" /* OS */ "%s", /* client name */ smbc->user, 0, smbc->domain, 0, CURL_OS, 0, CLIENTNAME); - p++; /* count the final null termination */ + p++; /* count the final null-termination */ DEBUGASSERT(byte_count == (size_t)(p - msg.bytes)); msg.byte_count = smb_swap16((unsigned short)byte_count); @@ -754,7 +754,7 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data, "%s%c" /* share */ "%s", /* service */ conn->host.name, smbc->share, 0, SERVICENAME); - p++; /* count the final null termination */ + p++; /* count the final null-termination */ DEBUGASSERT(byte_count == (size_t)(p - msg.bytes)); msg.byte_count = smb_swap16((unsigned short)byte_count); @@ -999,8 +999,8 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done) */ static void get_posix_time(time_t *out, curl_off_t timestamp) { - if(timestamp >= CURL_OFF_T_C(116444736000000000)) { - timestamp -= CURL_OFF_T_C(116444736000000000); + if(timestamp >= (curl_off_t)116444736000000000) { + timestamp -= (curl_off_t)116444736000000000; timestamp /= 10000000; #if SIZEOF_TIME_T < SIZEOF_CURL_OFF_T if(timestamp > TIME_T_MAX) diff --git a/vendor/curl/lib/smtp.c b/vendor/curl/lib/smtp.c index cccb9f38..d2adf43a 100644 --- a/vendor/curl/lib/smtp.c +++ b/vendor/curl/lib/smtp.c @@ -68,7 +68,6 @@ #include "mime.h" #include "socks.h" #include "smtp.h" -#include "strcase.h" #include "vtls/vtls.h" #include "cfilters.h" #include "connect.h" @@ -483,7 +482,7 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data, result, ssldone)); if(!result && ssldone) { smtpc->ssldone = ssldone; - /* perform EHLO now, changes smpt->state out of SMTP_UPGRADETLS */ + /* perform EHLO now, changes smtp->state out of SMTP_UPGRADETLS */ result = smtp_perform_ehlo(data, smtpc); } out: @@ -601,7 +600,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data, * * smtp_perform_command() * - * Sends a SMTP based command. + * Sends an SMTP based command. */ static CURLcode smtp_perform_command(struct Curl_easy *data, struct smtp_conn *smtpc, @@ -1036,7 +1035,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data, if(smtpcode != 1) { if(data->set.use_ssl && !Curl_conn_is_ssl(data->conn, FIRSTSOCKET)) { - /* We do not have a SSL/TLS connection yet, but SSL is requested */ + /* We do not have an SSL/TLS connection yet, but SSL is requested */ if(smtpc->tls_supported) /* Switch to TLS connection now */ result = smtp_perform_starttls(data, smtpc); @@ -1625,13 +1624,12 @@ static CURLcode smtp_disconnect(struct Curl_easy *data, bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ - if(!dead_connection && conn->bits.protoconnstart) { + if(!dead_connection && conn->bits.protoconnstart && + !Curl_pp_needs_flush(data, &smtpc->pp)) { if(!smtp_perform_quit(data, smtpc)) (void)smtp_block_statemach(data, smtpc, TRUE); /* ignore on QUIT */ } - /* Cleanup the SASL module */ - Curl_sasl_cleanup(conn, smtpc->sasl.authused); CURL_TRC_SMTP(data, "smtp_disconnect(), finished"); return CURLE_OK; } @@ -1776,7 +1774,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn, while(*ptr && *ptr != ';') ptr++; - if(strncasecompare(key, "AUTH=", 5)) + if(curl_strnequal(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, value, ptr - value); else @@ -2007,7 +2005,7 @@ static CURLcode cr_eob_read(struct Curl_easy *data, eob = &SMTP_EOB[2]; break; case 3: - /* ended with '\r\n.', we should escpe the last '.' */ + /* ended with '\r\n.', we should escape the last '.' */ eob = "." SMTP_EOB; break; default: diff --git a/vendor/curl/lib/socks.c b/vendor/curl/lib/socks.c index 18cefe8b..7d25ef52 100644 --- a/vendor/curl/lib/socks.c +++ b/vendor/curl/lib/socks.c @@ -81,7 +81,7 @@ enum connect_t { struct socks_state { enum connect_t state; - ssize_t outstanding; /* send this many bytes more */ + size_t outstanding; /* send this many bytes more */ unsigned char buffer[CURL_SOCKS_BUF_SIZE]; unsigned char *outp; /* send from this pointer */ @@ -101,54 +101,41 @@ struct socks_state { int Curl_blockread_all(struct Curl_cfilter *cf, struct Curl_easy *data, /* transfer */ char *buf, /* store read data here */ - ssize_t buffersize, /* max amount to read */ - ssize_t *n) /* amount bytes read */ + size_t blen, /* space in buf */ + size_t *pnread) /* amount bytes read */ { - ssize_t nread = 0; - ssize_t allread = 0; - int result; - CURLcode err = CURLE_OK; + size_t nread = 0; + CURLcode err; - *n = 0; + *pnread = 0; for(;;) { timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { /* we already got the timeout */ - result = CURLE_OPERATION_TIMEDOUT; - break; + return CURLE_OPERATION_TIMEDOUT; } if(!timeout_ms) timeout_ms = TIMEDIFF_T_MAX; if(SOCKET_READABLE(cf->conn->sock[cf->sockindex], timeout_ms) <= 0) { - result = ~CURLE_OK; - break; + return ~CURLE_OK; } - nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err); - if(nread <= 0) { - result = (int)err; - if(CURLE_AGAIN == err) - continue; - if(err) { - break; - } + err = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); + if(CURLE_AGAIN == err) + continue; + else if(err) + return (int)err; + + if(blen == nread) { + *pnread += nread; + return CURLE_OK; } + if(!nread) /* EOF */ + return ~CURLE_OK; - if(buffersize == nread) { - allread += nread; - *n = allread; - result = CURLE_OK; - break; - } - if(!nread) { - result = ~CURLE_OK; - break; - } - - buffersize -= nread; buf += nread; - allread += nread; + blen -= nread; + *pnread += nread; } - return result; } #endif @@ -213,24 +200,25 @@ static CURLproxycode socks_state_send(struct Curl_cfilter *cf, CURLproxycode failcode, const char *description) { - ssize_t nwritten; + size_t nwritten; CURLcode result; - nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp, - sx->outstanding, FALSE, &result); - if(nwritten <= 0) { - if(CURLE_AGAIN == result) { + result = Curl_conn_cf_send(cf->next, data, (char *)sx->outp, + sx->outstanding, FALSE, &nwritten); + if(result) { + if(CURLE_AGAIN == result) return CURLPX_OK; - } - else if(CURLE_OK == result) { - /* connection closed */ - failf(data, "connection to proxy closed"); - return CURLPX_CLOSED; - } + failf(data, "Failed to send %s: %s", description, curl_easy_strerror(result)); return failcode; } + else if(!nwritten) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLPX_CLOSED; + } + DEBUGASSERT(sx->outstanding >= nwritten); /* not done, remain in state */ sx->outstanding -= nwritten; @@ -244,24 +232,24 @@ static CURLproxycode socks_state_recv(struct Curl_cfilter *cf, CURLproxycode failcode, const char *description) { - ssize_t nread; + size_t nread; CURLcode result; - nread = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp, - sx->outstanding, &result); - if(nread <= 0) { - if(CURLE_AGAIN == result) { + result = Curl_conn_cf_recv(cf->next, data, (char *)sx->outp, + sx->outstanding, &nread); + if(result) { + if(CURLE_AGAIN == result) return CURLPX_OK; - } - else if(CURLE_OK == result) { - /* connection closed */ - failf(data, "connection to proxy closed"); - return CURLPX_CLOSED; - } + failf(data, "SOCKS: Failed receiving %s: %s", description, curl_easy_strerror(result)); return failcode; } + else if(!nread) { + /* connection closed */ + failf(data, "connection to proxy closed"); + return CURLPX_CLOSED; + } /* remain in reading state */ DEBUGASSERT(sx->outstanding >= nread); sx->outstanding -= nread; @@ -394,7 +382,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, /* * This is currently not supporting "Identification Protocol (RFC1413)". */ - socksreq[8] = 0; /* ensure empty userid is NUL-terminated */ + socksreq[8] = 0; /* ensure empty userid is null-terminated */ if(sx->proxy_user) { size_t plen = strlen(sx->proxy_user); if(plen > 255) { @@ -1158,8 +1146,8 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, } static void socks_cf_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { struct socks_state *sx = cf->ctx; @@ -1199,21 +1187,25 @@ static void socks_proxy_cf_destroy(struct Curl_cfilter *cf, socks_proxy_cf_free(cf); } -static void socks_cf_get_host(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char **phost, - const char **pdisplay_host, - int *pport) +static CURLcode socks_cf_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) { - (void)data; - if(!cf->connected) { - *phost = cf->conn->socks_proxy.host.name; - *pdisplay_host = cf->conn->http_proxy.host.dispname; - *pport = (int)cf->conn->socks_proxy.port; - } - else { - cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport); + struct socks_state *sx = cf->ctx; + + if(sx) { + switch(query) { + case CF_QUERY_HOST_PORT: + *pres1 = sx->remote_port; + *((const char **)pres2) = sx->hostname; + return CURLE_OK; + default: + break; + } } + return cf->next ? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; } struct Curl_cftype Curl_cft_socks_proxy = { @@ -1224,7 +1216,6 @@ struct Curl_cftype Curl_cft_socks_proxy = { socks_proxy_cf_connect, socks_proxy_cf_close, Curl_cf_def_shutdown, - socks_cf_get_host, socks_cf_adjust_pollset, Curl_cf_def_data_pending, Curl_cf_def_send, @@ -1232,7 +1223,7 @@ struct Curl_cftype Curl_cft_socks_proxy = { Curl_cf_def_cntrl, Curl_cf_def_conn_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + socks_cf_query, }; CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at, diff --git a/vendor/curl/lib/socks.h b/vendor/curl/lib/socks.h index a3adcc6e..d6079631 100644 --- a/vendor/curl/lib/socks.h +++ b/vendor/curl/lib/socks.h @@ -40,8 +40,8 @@ int Curl_blockread_all(struct Curl_cfilter *cf, struct Curl_easy *data, char *buf, - ssize_t buffersize, - ssize_t *n); + size_t blen, + size_t *pnread); #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) /* diff --git a/vendor/curl/lib/socks_gssapi.c b/vendor/curl/lib/socks_gssapi.c index 697e301b..f23a1ae6 100644 --- a/vendor/curl/lib/socks_gssapi.c +++ b/vendor/curl/lib/socks_gssapi.c @@ -115,8 +115,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, struct connectdata *conn = cf->conn; curl_socket_t sock = conn->sock[cf->sockindex]; CURLcode code; - ssize_t actualread; - ssize_t nwritten; + size_t actualread; + size_t nwritten; int result; OM_uint32 gss_major_status, gss_minor_status, gss_status; OM_uint32 gss_ret_flags; @@ -199,7 +199,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to initial GSS-API token."); return CURLE_COULDNT_CONNECT; } @@ -210,26 +210,26 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, us_length = htons((unsigned short)gss_send_token.length); memcpy(socksreq + 2, &us_length, sizeof(short)); - nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, - FALSE, &code); + code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, + FALSE, &nwritten); if(code || (4 != nwritten)) { failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } - nwritten = Curl_conn_cf_send(cf->next, data, - (char *)gss_send_token.value, - gss_send_token.length, FALSE, &code); - if(code || ((ssize_t)gss_send_token.length != nwritten)) { + code = Curl_conn_cf_send(cf->next, data, + (char *)gss_send_token.value, + gss_send_token.length, FALSE, &nwritten); + if(code || (gss_send_token.length != nwritten)) { failf(data, "Failed to send GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_send_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -254,7 +254,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API authentication response."); gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -263,7 +263,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, failf(data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -271,7 +271,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, failf(data, "Invalid GSS-API authentication response type (%d %d).", socksreq[0], socksreq[1]); gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -285,7 +285,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, "Could not allocate memory for GSS-API authentication " "response token."); gss_release_name(&gss_status, &server); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } @@ -296,7 +296,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, failf(data, "Failed to receive GSS-API authentication token."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -311,7 +311,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, NULL, NULL, NULL); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_inquire_context")) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); failf(data, "Failed to determine username."); return CURLE_COULDNT_CONNECT; @@ -320,7 +320,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, &gss_send_token, NULL); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_display_name")) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); failf(data, "Failed to determine username."); @@ -328,7 +328,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } user = malloc(gss_send_token.length + 1); if(!user) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); gss_release_name(&gss_status, &gss_client_name); gss_release_buffer(&gss_status, &gss_send_token); return CURLE_OUT_OF_MEMORY; @@ -397,7 +397,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, gss_send_token.length = 1; gss_send_token.value = Curl_memdup(&gss_enc, 1); if(!gss_send_token.value) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } @@ -408,7 +408,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) { gss_release_buffer(&gss_status, &gss_send_token); gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to wrap GSS-API encryption value into token."); return CURLE_COULDNT_CONNECT; } @@ -418,33 +418,32 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, memcpy(socksreq + 2, &us_length, sizeof(short)); } - nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, - &code); - if(code || (4 != nwritten)) { + code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, + &nwritten); + if(code || (4 != nwritten)) { failf(data, "Failed to send GSS-API encryption request."); gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); - nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, - &code); - if(code || ( 1 != nwritten)) { + code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, + &nwritten); + if(code || (1 != nwritten)) { failf(data, "Failed to send GSS-API encryption type."); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } } else { - nwritten = Curl_conn_cf_send(cf->next, data, - (char *)gss_w_token.value, - gss_w_token.length, FALSE, &code); - if(code || ((ssize_t)gss_w_token.length != nwritten)) { + code = Curl_conn_cf_send(cf->next, data, (char *)gss_w_token.value, + gss_w_token.length, FALSE, &nwritten); + if(code || (gss_w_token.length != nwritten)) { failf(data, "Failed to send GSS-API encryption type."); gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } gss_release_buffer(&gss_status, &gss_w_token); @@ -453,7 +452,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive GSS-API encryption response."); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -461,14 +460,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%d %d).", socksreq[0], socksreq[1]); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } if(socksreq[1] != 2) { /* status / message type */ failf(data, "Invalid GSS-API encryption response type (%d %d).", socksreq[0], socksreq[1]); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -478,7 +477,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, gss_recv_token.length = us_length; gss_recv_token.value = malloc(gss_recv_token.length); if(!gss_recv_token.value) { - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(cf, data, (char *)gss_recv_token.value, @@ -487,7 +486,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(result || (actualread != us_length)) { failf(data, "Failed to receive GSS-API encryption type."); gss_release_buffer(&gss_status, &gss_recv_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -499,7 +498,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) { gss_release_buffer(&gss_status, &gss_recv_token); gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); failf(data, "Failed to unwrap GSS-API encryption value into token."); return CURLE_COULDNT_CONNECT; } @@ -509,7 +508,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, failf(data, "Invalid GSS-API encryption response length (%zu).", gss_w_token.length); gss_release_buffer(&gss_status, &gss_w_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -521,7 +520,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, failf(data, "Invalid GSS-API encryption response length (%zu).", gss_recv_token.length); gss_release_buffer(&gss_status, &gss_recv_token); - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; } @@ -538,7 +537,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, conn->socks5_gssapi_enctype = socksreq[0]; if(socksreq[0] == 0) - gss_delete_sec_context(&gss_status, &gss_context, NULL); + Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_OK; } diff --git a/vendor/curl/lib/socks_sspi.c b/vendor/curl/lib/socks_sspi.c index 1f0846dd..82147562 100644 --- a/vendor/curl/lib/socks_sspi.c +++ b/vendor/curl/lib/socks_sspi.c @@ -69,8 +69,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, struct connectdata *conn = cf->conn; curl_socket_t sock = conn->sock[cf->sockindex]; CURLcode code; - ssize_t actualread; - ssize_t written; + size_t actualread; + size_t written; int result; /* Needs GSS-API authentication */ SECURITY_STATUS status; @@ -207,8 +207,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, us_length = htons((unsigned short)sspi_send_token.cbBuffer); memcpy(socksreq + 2, &us_length, sizeof(short)); - written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, - &code); + code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, + &written); if(code || (4 != written)) { failf(data, "Failed to send SSPI authentication request."); free(service_name); @@ -221,10 +221,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, return CURLE_COULDNT_CONNECT; } - written = Curl_conn_cf_send(cf->next, data, - (char *)sspi_send_token.pvBuffer, - sspi_send_token.cbBuffer, FALSE, &code); - if(code || (sspi_send_token.cbBuffer != (size_t)written)) { + code = Curl_conn_cf_send(cf->next, data, + (char *)sspi_send_token.pvBuffer, + sspi_send_token.cbBuffer, FALSE, &written); + if(code || (sspi_send_token.cbBuffer != written)) { failf(data, "Failed to send SSPI authentication token."); free(service_name); if(sspi_send_token.pvBuffer) @@ -478,8 +478,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, memcpy(socksreq + 2, &us_length, sizeof(short)); } - written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, - &code); + code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, + &written); if(code || (4 != written)) { failf(data, "Failed to send SSPI encryption request."); if(sspi_send_token.pvBuffer) @@ -490,8 +490,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); - written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, - &code); + code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, + &written); if(code || (1 != written)) { failf(data, "Failed to send SSPI encryption type."); Curl_pSecFn->DeleteSecurityContext(&sspi_context); @@ -499,9 +499,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } } else { - written = Curl_conn_cf_send(cf->next, data, - (char *)sspi_send_token.pvBuffer, - sspi_send_token.cbBuffer, FALSE, &code); + code = Curl_conn_cf_send(cf->next, data, + (char *)sspi_send_token.pvBuffer, + sspi_send_token.cbBuffer, FALSE, &written); if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI encryption type."); if(sspi_send_token.pvBuffer) diff --git a/vendor/curl/lib/speedcheck.c b/vendor/curl/lib/speedcheck.c index 16d7d725..b063e5d4 100644 --- a/vendor/curl/lib/speedcheck.c +++ b/vendor/curl/lib/speedcheck.c @@ -27,6 +27,7 @@ #include #include "urldata.h" #include "sendf.h" +#include "transfer.h" #include "multiif.h" #include "speedcheck.h" @@ -41,7 +42,7 @@ void Curl_speedinit(struct Curl_easy *data) CURLcode Curl_speedcheck(struct Curl_easy *data, struct curltime now) { - if(data->req.keepon & KEEP_RECV_PAUSE) + if(Curl_xfer_recv_is_paused(data)) /* A paused transfer is not qualified for speed checks */ return CURLE_OK; diff --git a/vendor/curl/lib/strcase.c b/vendor/curl/lib/strcase.c index 841949ec..ee5b9072 100644 --- a/vendor/curl/lib/strcase.c +++ b/vendor/curl/lib/strcase.c @@ -85,7 +85,7 @@ char Curl_raw_tolower(char in) /* Copy an upper case version of the string from src to dest. The * strings may overlap. No more than n characters of the string are copied * (including any NUL) and the destination string will NOT be - * NUL-terminated if that limit is reached. + * null-terminated if that limit is reached. */ void Curl_strntoupper(char *dest, const char *src, size_t n) { @@ -100,7 +100,7 @@ void Curl_strntoupper(char *dest, const char *src, size_t n) /* Copy a lower case version of the string from src to dest. The * strings may overlap. No more than n characters of the string are copied * (including any NUL) and the destination string will NOT be - * NUL-terminated if that limit is reached. + * null-terminated if that limit is reached. */ void Curl_strntolower(char *dest, const char *src, size_t n) { @@ -112,7 +112,7 @@ void Curl_strntolower(char *dest, const char *src, size_t n) } while(*src++ && --n); } -/* Compare case-sensitive NUL-terminated strings, taking care of possible +/* Compare case-sensitive null-terminated strings, taking care of possible * null pointers. Return true if arguments match. */ bool Curl_safecmp(char *a, char *b) diff --git a/vendor/curl/lib/strcase.h b/vendor/curl/lib/strcase.h index 8c50bbcb..915c9969 100644 --- a/vendor/curl/lib/strcase.h +++ b/vendor/curl/lib/strcase.h @@ -26,18 +26,6 @@ #include -/* - * Only "raw" case insensitive strings. This is meant to be locale independent - * and only compare strings we know are safe for this. - * - * The function is capable of comparing a-z case insensitively. - * - * Result is 1 if text matches and 0 if not. - */ - -#define strcasecompare(a,b) curl_strequal(a,b) -#define strncasecompare(a,b,c) curl_strnequal(a,b,c) - char Curl_raw_toupper(char in); char Curl_raw_tolower(char in); diff --git a/vendor/curl/lib/strdup.c b/vendor/curl/lib/strdup.c index 9fceaea8..69c41a5e 100644 --- a/vendor/curl/lib/strdup.c +++ b/vendor/curl/lib/strdup.c @@ -104,7 +104,7 @@ void *Curl_memdup(const void *src, size_t length) * Curl_memdup0(source, length) * * Copies the 'source' string to a newly allocated buffer (that is returned). - * Copies 'length' bytes then adds a null terminator. + * Copies 'length' bytes then adds a null-terminator. * * Returns the new pointer or NULL on failure. * diff --git a/vendor/curl/lib/strequal.c b/vendor/curl/lib/strequal.c index d1ba9150..fb6be51d 100644 --- a/vendor/curl/lib/strequal.c +++ b/vendor/curl/lib/strequal.c @@ -65,6 +65,15 @@ static int ncasecompare(const char *first, const char *second, size_t max) return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); } +/* + * Only "raw" case insensitive strings. This is meant to be locale independent + * and only compare strings we know are safe for this. + * + * The function is capable of comparing a-z case insensitively. + * + * Result is 1 if text matches and 0 if not. + */ + /* --- public function --- */ int curl_strequal(const char *first, const char *second) { diff --git a/vendor/curl/lib/strerror.c b/vendor/curl/lib/strerror.c index 9cf93dd6..90694882 100644 --- a/vendor/curl/lib/strerror.c +++ b/vendor/curl/lib/strerror.c @@ -317,36 +317,7 @@ curl_easy_strerror(CURLcode error) return "ECH attempted but failed"; /* error codes not used by current libcurl */ - case CURLE_OBSOLETE20: - case CURLE_OBSOLETE24: - case CURLE_OBSOLETE29: - case CURLE_OBSOLETE32: - case CURLE_OBSOLETE34: - case CURLE_OBSOLETE40: - case CURLE_OBSOLETE41: - case CURLE_OBSOLETE44: - case CURLE_OBSOLETE46: - case CURLE_OBSOLETE50: - case CURLE_OBSOLETE51: - case CURLE_OBSOLETE57: - case CURLE_OBSOLETE62: - case CURLE_OBSOLETE75: - case CURLE_OBSOLETE76: - - /* error codes used by curl tests */ - case CURLE_RESERVED115: - case CURLE_RESERVED116: - case CURLE_RESERVED117: - case CURLE_RESERVED118: - case CURLE_RESERVED119: - case CURLE_RESERVED120: - case CURLE_RESERVED121: - case CURLE_RESERVED122: - case CURLE_RESERVED123: - case CURLE_RESERVED124: - case CURLE_RESERVED125: - case CURLE_RESERVED126: - case CURL_LAST: + default: break; } /* diff --git a/vendor/curl/lib/system_win32.c b/vendor/curl/lib/system_win32.c index b1fd12be..a890a0ea 100644 --- a/vendor/curl/lib/system_win32.c +++ b/vendor/curl/lib/system_win32.c @@ -36,12 +36,17 @@ #include "curl_memory.h" #include "memdebug.h" +#ifndef HAVE_IF_NAMETOINDEX /* Handle of iphlpapp.dll */ static HMODULE s_hIpHlpApiDll = NULL; /* Pointer to the if_nametoindex function */ IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL; +/* This is used to dynamically load DLLs */ +static HMODULE curl_load_library(LPCTSTR filename); +#endif + /* Curl_win32_init() performs Win32 global initialization */ CURLcode Curl_win32_init(long flags) { @@ -90,7 +95,8 @@ CURLcode Curl_win32_init(long flags) } #endif - s_hIpHlpApiDll = Curl_load_library(TEXT("iphlpapi.dll")); +#ifndef HAVE_IF_NAMETOINDEX + s_hIpHlpApiDll = curl_load_library(TEXT("iphlpapi.dll")); if(s_hIpHlpApiDll) { /* Get the address of the if_nametoindex function */ #ifdef UNDER_CE @@ -106,6 +112,7 @@ CURLcode Curl_win32_init(long flags) if(pIfNameToIndex) Curl_if_nametoindex = pIfNameToIndex; } +#endif /* curlx_verify_windows_version must be called during init at least once because it has its own initialization routine. */ @@ -123,11 +130,13 @@ CURLcode Curl_win32_init(long flags) /* Curl_win32_cleanup() is the opposite of Curl_win32_init() */ void Curl_win32_cleanup(long init_flags) { +#ifndef HAVE_IF_NAMETOINDEX if(s_hIpHlpApiDll) { FreeLibrary(s_hIpHlpApiDll); s_hIpHlpApiDll = NULL; Curl_if_nametoindex = NULL; } +#endif #ifdef USE_WINDOWS_SSPI Curl_sspi_global_cleanup(); @@ -140,11 +149,13 @@ void Curl_win32_cleanup(long init_flags) } } -#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) +#ifndef HAVE_IF_NAMETOINDEX + +#ifndef LOAD_WITH_ALTERED_SEARCH_PATH #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 #endif -#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) +#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif @@ -163,7 +174,7 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); #endif /* - * Curl_load_library() + * curl_load_library() * * This is used to dynamically load DLLs using the most secure method available * for the version of Windows that we are running on. @@ -176,7 +187,7 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); * * Returns the handle of the module on success; otherwise NULL. */ -HMODULE Curl_load_library(LPCTSTR filename) +static HMODULE curl_load_library(LPCTSTR filename) { #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) HMODULE hModule = NULL; @@ -214,7 +225,7 @@ HMODULE Curl_load_library(LPCTSTR filename) /* Attempt to get the Windows system path */ UINT systemdirlen = GetSystemDirectory(NULL, 0); if(systemdirlen) { - /* Allocate space for the full DLL path (Room for the null terminator + /* Allocate space for the full DLL path (Room for the null-terminator is included in systemdirlen) */ size_t filenamelen = _tcslen(filename); TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen)); @@ -228,7 +239,6 @@ HMODULE Curl_load_library(LPCTSTR filename) hModule = pLoadLibraryEx ? pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : LoadLibrary(path); - } free(path); } @@ -240,5 +250,6 @@ HMODULE Curl_load_library(LPCTSTR filename) return NULL; #endif } +#endif /* !HAVE_IF_NAMETOINDEX */ #endif /* _WIN32 */ diff --git a/vendor/curl/lib/system_win32.h b/vendor/curl/lib/system_win32.h index b8333c64..6bf89d3d 100644 --- a/vendor/curl/lib/system_win32.h +++ b/vendor/curl/lib/system_win32.h @@ -36,14 +36,13 @@ extern bool Curl_isVistaOrGreater; CURLcode Curl_win32_init(long flags); void Curl_win32_cleanup(long init_flags); +#ifndef HAVE_IF_NAMETOINDEX /* We use our own typedef here since some headers might lack this */ typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *); /* This is used instead of if_nametoindex if available on Windows */ extern IF_NAMETOINDEX_FN Curl_if_nametoindex; - -/* This is used to dynamically load DLLs */ -HMODULE Curl_load_library(LPCTSTR filename); +#endif #else /* _WIN32 */ #define Curl_win32_init(x) CURLE_OK #endif /* !_WIN32 */ diff --git a/vendor/curl/lib/telnet.c b/vendor/curl/lib/telnet.c index 737db36d..bd599dec 100644 --- a/vendor/curl/lib/telnet.c +++ b/vendor/curl/lib/telnet.c @@ -57,7 +57,6 @@ #include "system_win32.h" #include "arpa_telnet.h" #include "select.h" -#include "strcase.h" #include "curlx/warnless.h" #include "curlx/strparse.h" @@ -171,7 +170,7 @@ static void sendsuboption(struct Curl_easy *data, static CURLcode telnet_do(struct Curl_easy *data, bool *done); static CURLcode telnet_done(struct Curl_easy *data, - CURLcode, bool premature); + CURLcode, bool premature); static CURLcode send_telnet_data(struct Curl_easy *data, struct TELNET *tn, char *buffer, ssize_t nread); @@ -839,7 +838,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, switch(olen) { case 5: /* Terminal type */ - if(strncasecompare(option, "TTYPE", 5)) { + if(curl_strnequal(option, "TTYPE", 5)) { tn->subopt_ttype = arg; tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; break; @@ -849,7 +848,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, case 8: /* Display variable */ - if(strncasecompare(option, "XDISPLOC", 8)) { + if(curl_strnequal(option, "XDISPLOC", 8)) { tn->subopt_xdisploc = arg; tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; break; @@ -859,7 +858,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, case 7: /* Environment variable */ - if(strncasecompare(option, "NEW_ENV", 7)) { + if(curl_strnequal(option, "NEW_ENV", 7)) { beg = curl_slist_append(tn->telnet_vars, arg); if(!beg) { result = CURLE_OUT_OF_MEMORY; @@ -874,7 +873,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, case 2: /* Window Size */ - if(strncasecompare(option, "WS", 2)) { + if(curl_strnequal(option, "WS", 2)) { const char *p = arg; curl_off_t x = 0; curl_off_t y = 0; @@ -896,7 +895,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data, case 6: /* To take care or not of the 8th bit in data exchange */ - if(strncasecompare(option, "BINARY", 6)) { + if(curl_strnequal(option, "BINARY", 6)) { int binary_option = atoi(arg); if(binary_option != 1) { tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; @@ -1314,8 +1313,8 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) int poll_cnt; curl_off_t total_dl = 0; curl_off_t total_ul = 0; + ssize_t snread; #endif - ssize_t nread; struct curltime now; bool keepon = TRUE; char buffer[4*1024]; @@ -1464,6 +1463,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } if(events.lNetworkEvents & FD_READ) { /* read data from network */ + size_t nread; result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread); /* read would have blocked. Loop again */ if(result == CURLE_AGAIN) @@ -1475,7 +1475,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } /* returned zero but actually received 0 or less here, the server closed the connection and we bail out */ - else if(nread <= 0) { + else if(!nread) { keepon = FALSE; break; } @@ -1550,6 +1550,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) default: /* read! */ if(pfd[0].revents & POLLIN) { /* read data from network */ + size_t nread; result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread); /* read would have blocked. Loop again */ if(result == CURLE_AGAIN) @@ -1567,7 +1568,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } /* returned zero but actually received 0 or less here, the server closed the connection and we bail out */ - else if(nread <= 0) { + else if(!nread) { keepon = FALSE; break; } @@ -1590,34 +1591,34 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done) } } - nread = 0; + snread = 0; if(poll_cnt == 2) { if(pfd[1].revents & POLLIN) { /* read from in file */ - nread = read(pfd[1].fd, buffer, sizeof(buffer)); + snread = read(pfd[1].fd, buffer, sizeof(buffer)); } } else { /* read from user-supplied method */ - nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), + snread = (int)data->state.fread_func(buffer, 1, sizeof(buffer), data->state.in); - if(nread == CURL_READFUNC_ABORT) { + if(snread == CURL_READFUNC_ABORT) { keepon = FALSE; break; } - if(nread == CURL_READFUNC_PAUSE) + if(snread == CURL_READFUNC_PAUSE) break; } - if(nread > 0) { - result = send_telnet_data(data, tn, buffer, nread); + if(snread > 0) { + result = send_telnet_data(data, tn, buffer, snread); if(result) { keepon = FALSE; break; } - total_ul += nread; + total_ul += snread; Curl_pgrsSetUploadCounter(data, total_ul); } - else if(nread < 0) + else if(snread < 0) keepon = FALSE; break; diff --git a/vendor/curl/lib/tftp.c b/vendor/curl/lib/tftp.c index e9f4e68e..5ea986db 100644 --- a/vendor/curl/lib/tftp.c +++ b/vendor/curl/lib/tftp.c @@ -48,6 +48,7 @@ #include "urldata.h" #include +#include "cfilters.h" #include "cf-socket.h" #include "transfer.h" #include "sendf.h" @@ -429,6 +430,7 @@ static CURLcode tftp_send_first(struct tftp_conn *state, const char *mode = "octet"; char *filename; struct Curl_easy *data = state->data; + const struct Curl_sockaddr_ex *remote_addr = NULL; CURLcode result = CURLE_OK; /* Set ASCII mode if -B flag was used */ @@ -525,10 +527,14 @@ static CURLcode tftp_send_first(struct tftp_conn *state, #else #define CURL_SENDTO_ARG5(x) (x) #endif + remote_addr = Curl_conn_get_remote_addr(data, FIRSTSOCKET); + if(!remote_addr) + return CURLE_FAILED_INIT; + senddata = sendto(state->sockfd, (void *)state->spacket.data, (SEND_TYPE_ARG3)sbytes, 0, - CURL_SENDTO_ARG5(&data->conn->remote_addr->curl_sa_addr), - (curl_socklen_t)data->conn->remote_addr->addrlen); + CURL_SENDTO_ARG5(&remote_addr->curl_sa_addr), + (curl_socklen_t)remote_addr->addrlen); if(senddata != (ssize_t)sbytes) { char buffer[STRERROR_LEN]; failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); @@ -955,6 +961,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) int blksize; int need_blksize; struct connectdata *conn = data->conn; + const struct Curl_sockaddr_ex *remote_addr = NULL; blksize = TFTP_BLKSIZE_DEFAULT; @@ -998,8 +1005,13 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */ state->requested_blksize = blksize; + remote_addr = Curl_conn_get_remote_addr(data, FIRSTSOCKET); + DEBUGASSERT(remote_addr); + if(!remote_addr) + return CURLE_FAILED_INIT; + ((struct sockaddr *)&state->local_addr)->sa_family = - (CURL_SA_FAMILY_T)(conn->remote_addr->family); + (CURL_SA_FAMILY_T)(remote_addr->family); tftp_set_timeouts(state); @@ -1018,7 +1030,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done) * IPv4 and IPv6... */ int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, - (curl_socklen_t)conn->remote_addr->addrlen); + (curl_socklen_t)remote_addr->addrlen); if(rc) { char buffer[STRERROR_LEN]; failf(data, "bind() failed; %s", @@ -1357,7 +1369,7 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data, { char *type; - conn->transport = TRNSPRT_UDP; + conn->transport_wanted = TRNSPRT_UDP; /* TFTP URLs support an extension like ";mode=" that * we will try to get now! */ diff --git a/vendor/curl/lib/transfer.c b/vendor/curl/lib/transfer.c index ef7d7f19..15a61f69 100644 --- a/vendor/curl/lib/transfer.c +++ b/vendor/curl/lib/transfer.c @@ -79,7 +79,6 @@ #include "connect.h" #include "http2.h" #include "mime.h" -#include "strcase.h" #include "hsts.h" #include "setopt.h" #include "headers.h" @@ -106,7 +105,7 @@ char *Curl_checkheaders(const struct Curl_easy *data, DEBUGASSERT(thisheader[thislen-1] != ':'); for(head = data->set.headers; head; head = head->next) { - if(strncasecompare(head->data, thisheader, thislen) && + if(curl_strnequal(head->data, thisheader, thislen) && Curl_headersep(head->data[thislen]) ) return head->data; } @@ -115,7 +114,7 @@ char *Curl_checkheaders(const struct Curl_easy *data, } #endif -static int data_pending(struct Curl_easy *data) +static int data_pending(struct Curl_easy *data, bool rcvd_eagain) { struct connectdata *conn = data->conn; @@ -124,8 +123,9 @@ static int data_pending(struct Curl_easy *data) /* in the case of libssh2, we can never be really sure that we have emptied its internal buffers so we MUST always try until we get EAGAIN back */ - return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) || - Curl_conn_data_pending(data, FIRSTSOCKET); + return (!rcvd_eagain && + conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP)) || + Curl_conn_data_pending(data, FIRSTSOCKET); } /* @@ -210,7 +210,7 @@ static ssize_t xfer_recv_resp(struct Curl_easy *data, bool eos_reliable, CURLcode *err) { - ssize_t nread; + size_t nread; DEBUGASSERT(blen > 0); /* If we are reading BODY data and the connection does NOT handle EOF @@ -251,8 +251,7 @@ static ssize_t xfer_recv_resp(struct Curl_easy *data, } DEBUGF(infof(data, "sendrecv_dl: we are done")); } - DEBUGASSERT(nread >= 0); - return nread; + return (ssize_t)nread; } /* @@ -271,6 +270,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, int maxloops = 10; curl_off_t total_received = 0; bool is_multiplex = FALSE; + bool rcvd_eagain = FALSE; result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen); if(result) @@ -303,23 +303,25 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, bytestoread = (size_t)data->set.max_recv_speed; } + rcvd_eagain = FALSE; nread = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result); if(nread < 0) { if(CURLE_AGAIN != result) goto out; /* real error */ + rcvd_eagain = TRUE; result = CURLE_OK; if(data->req.download_done && data->req.no_body && !data->req.resp_trailer) { DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, " "not waiting for EOS")); nread = 0; - /* continue as if we read the EOS */ + /* continue as if we received the EOS */ } else break; /* get out of loop */ } - /* We only get a 0-length read on EndOfStream */ + /* We only get a 0-length receive at the end of the response */ blen = (size_t)nread; is_eos = (blen == 0); *didwhat |= KEEP_RECV; @@ -355,12 +357,12 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, } while(maxloops--); - if((maxloops <= 0) || data_pending(data)) { - /* did not read until EAGAIN or there is still pending data, mark as - read-again-please */ - data->state.select_bits = CURL_CSELECT_IN; - if((k->keepon & KEEP_SENDBITS) == KEEP_SEND) - data->state.select_bits |= CURL_CSELECT_OUT; + if(!Curl_xfer_is_blocked(data) && + (!rcvd_eagain || data_pending(data, rcvd_eagain))) { + /* Did not read until EAGAIN or there is still data pending + * in buffers. Mark as read-again via simulated SELECT results. */ + Curl_multi_mark_dirty(data); + CURL_TRC_M(data, "sendrecv_dl() no EAGAIN/pending data, mark as dirty"); } if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && @@ -396,24 +398,6 @@ static CURLcode sendrecv_ul(struct Curl_easy *data, int *didwhat) return CURLE_OK; } -static int select_bits_paused(struct Curl_easy *data, int select_bits) -{ - /* See issue #11982: we really need to be careful not to progress - * a transfer direction when that direction is paused. Not all parts - * of our state machine are handling PAUSED transfers correctly. So, we - * do not want to go there. - * NOTE: we are only interested in PAUSE, not HOLD. */ - - /* if there is data in a direction not paused, return false */ - if(((select_bits & CURL_CSELECT_IN) && - !(data->req.keepon & KEEP_RECV_PAUSE)) || - ((select_bits & CURL_CSELECT_OUT) && - !(data->req.keepon & KEEP_SEND_PAUSE))) - return FALSE; - - return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)); -} - /* * Curl_sendrecv() is the low-level function to be called when data is to * be read and written to/from the connection. @@ -425,14 +409,9 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp) int didwhat = 0; DEBUGASSERT(nowp); - if(data->state.select_bits) { - if(select_bits_paused(data, data->state.select_bits)) { - /* leave the bits unchanged, so they'll tell us what to do when - * this transfer gets unpaused. */ - result = CURLE_OK; - goto out; - } - data->state.select_bits = 0; + if(Curl_xfer_is_blocked(data)) { + result = CURLE_OK; + goto out; } /* We go ahead and do a read if we have a readable socket or if the stream @@ -948,7 +927,7 @@ CURLcode Curl_xfer_send(struct Curl_easy *data, CURLcode Curl_xfer_recv(struct Curl_easy *data, char *buf, size_t blen, - ssize_t *pnrcvd) + size_t *pnrcvd) { int sockindex; @@ -974,9 +953,48 @@ bool Curl_xfer_is_blocked(struct Curl_easy *data) bool want_send = ((data)->req.keepon & KEEP_SEND); bool want_recv = ((data)->req.keepon & KEEP_RECV); if(!want_send) - return want_recv && Curl_cwriter_is_paused(data); + return want_recv && Curl_xfer_recv_is_paused(data); else if(!want_recv) - return want_send && Curl_creader_is_paused(data); + return want_send && Curl_xfer_send_is_paused(data); else - return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data); + return Curl_xfer_recv_is_paused(data) && Curl_xfer_send_is_paused(data); +} + +bool Curl_xfer_send_is_paused(struct Curl_easy *data) +{ + return (data->req.keepon & KEEP_SEND_PAUSE); +} + +bool Curl_xfer_recv_is_paused(struct Curl_easy *data) +{ + return (data->req.keepon & KEEP_RECV_PAUSE); +} + +CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable) +{ + CURLcode result = CURLE_OK; + if(enable) { + data->req.keepon |= KEEP_SEND_PAUSE; + } + else { + data->req.keepon &= ~KEEP_SEND_PAUSE; + if(Curl_creader_is_paused(data)) + result = Curl_creader_unpause(data); + } + return result; +} + +CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable) +{ + CURLcode result = CURLE_OK; + if(enable) { + data->req.keepon |= KEEP_RECV_PAUSE; + } + else { + data->req.keepon &= ~KEEP_RECV_PAUSE; + if(Curl_cwriter_is_paused(data)) + result = Curl_cwriter_unpause(data); + } + Curl_conn_ev_data_pause(data, enable); + return result; } diff --git a/vendor/curl/lib/transfer.h b/vendor/curl/lib/transfer.h index bfc42188..92278226 100644 --- a/vendor/curl/lib/transfer.h +++ b/vendor/curl/lib/transfer.h @@ -59,7 +59,7 @@ bool Curl_xfer_write_is_paused(struct Curl_easy *data); /** * Write a single "header" line from a server response. - * @param hd0 the 0-terminated, single header line + * @param hd0 the null-terminated, single header line * @param hdlen the length of the header line * @param is_eos TRUE iff this is the end of the response */ @@ -132,16 +132,23 @@ CURLcode Curl_xfer_send(struct Curl_easy *data, */ CURLcode Curl_xfer_recv(struct Curl_easy *data, char *buf, size_t blen, - ssize_t *pnrcvd); + size_t *pnrcvd); CURLcode Curl_xfer_send_close(struct Curl_easy *data); CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done); -/** - * Return TRUE iff the transfer is not done, but further progress +/* Return TRUE if the transfer is not done, but further progress * is blocked. For example when it is only receiving and its writer - * is PAUSED. - */ + * is PAUSED. */ bool Curl_xfer_is_blocked(struct Curl_easy *data); +/* Query if send/recv for transfer is paused. */ +bool Curl_xfer_send_is_paused(struct Curl_easy *data); +bool Curl_xfer_recv_is_paused(struct Curl_easy *data); + +/* Enable/Disable pausing of send/recv for the transfer. */ +CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable); +CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable); + + #endif /* HEADER_CURL_TRANSFER_H */ diff --git a/vendor/curl/lib/uint-bset.c b/vendor/curl/lib/uint-bset.c index 2560b373..e612c390 100644 --- a/vendor/curl/lib/uint-bset.c +++ b/vendor/curl/lib/uint-bset.c @@ -45,7 +45,8 @@ void Curl_uint_bset_init(struct uint_bset *bset) CURLcode Curl_uint_bset_resize(struct uint_bset *bset, unsigned int nmax) { - unsigned int nslots = (nmax + 63) / 64; + unsigned int nslots = (nmax < (UINT_MAX-63)) ? + ((nmax + 63) / 64) : (UINT_MAX / 64); DEBUGASSERT(bset->init == CURL_UINT_BSET_MAGIC); if(nslots != bset->nslots) { @@ -60,6 +61,7 @@ CURLcode Curl_uint_bset_resize(struct uint_bset *bset, unsigned int nmax) } bset->slots = slots; bset->nslots = nslots; + bset->first_slot_used = 0; } return CURLE_OK; } @@ -72,14 +74,13 @@ void Curl_uint_bset_destroy(struct uint_bset *bset) memset(bset, 0, sizeof(*bset)); } - -unsigned int Curl_uint_bset_capacity(struct uint_bset *bset) +#ifdef UNITTESTS +UNITTEST unsigned int Curl_uint_bset_capacity(struct uint_bset *bset) { return bset->nslots * 64; } - -unsigned int Curl_uint_bset_count(struct uint_bset *bset) +UNITTEST unsigned int Curl_uint_bset_count(struct uint_bset *bset) { unsigned int i; unsigned int n = 0; @@ -89,12 +90,12 @@ unsigned int Curl_uint_bset_count(struct uint_bset *bset) } return n; } - +#endif bool Curl_uint_bset_empty(struct uint_bset *bset) { unsigned int i; - for(i = 0; i < bset->nslots; ++i) { + for(i = bset->first_slot_used; i < bset->nslots; ++i) { if(bset->slots[i]) return FALSE; } @@ -104,8 +105,10 @@ bool Curl_uint_bset_empty(struct uint_bset *bset) void Curl_uint_bset_clear(struct uint_bset *bset) { - if(bset->nslots) + if(bset->nslots) { memset(bset->slots, 0, bset->nslots * sizeof(curl_uint64_t)); + bset->first_slot_used = UINT_MAX; + } } @@ -115,6 +118,8 @@ bool Curl_uint_bset_add(struct uint_bset *bset, unsigned int i) if(islot >= bset->nslots) return FALSE; bset->slots[islot] |= ((curl_uint64_t)1 << (i % 64)); + if(islot < bset->first_slot_used) + bset->first_slot_used = islot; return TRUE; } @@ -139,13 +144,14 @@ bool Curl_uint_bset_contains(struct uint_bset *bset, unsigned int i) bool Curl_uint_bset_first(struct uint_bset *bset, unsigned int *pfirst) { unsigned int i; - for(i = 0; i < bset->nslots; ++i) { + for(i = bset->first_slot_used; i < bset->nslots; ++i) { if(bset->slots[i]) { *pfirst = (i * 64) + CURL_CTZ64(bset->slots[i]); + bset->first_slot_used = i; return TRUE; } } - *pfirst = UINT_MAX; /* a value we cannot store */ + bset->first_slot_used = *pfirst = UINT_MAX; return FALSE; } @@ -183,11 +189,11 @@ unsigned int Curl_popcount64(curl_uint64_t x) /* Compute the "Hamming Distance" between 'x' and 0, * which is the number of set bits in 'x'. * See: https://en.wikipedia.org/wiki/Hamming_weight */ - const curl_uint64_t m1 = CURL_OFF_TU_C(0x5555555555555555); /* 0101+ */ - const curl_uint64_t m2 = CURL_OFF_TU_C(0x3333333333333333); /* 00110011+ */ - const curl_uint64_t m4 = CURL_OFF_TU_C(0x0f0f0f0f0f0f0f0f); /* 00001111+ */ + const curl_uint64_t m1 = 0x5555555555555555LL; /* 0101+ */ + const curl_uint64_t m2 = 0x3333333333333333LL; /* 00110011+ */ + const curl_uint64_t m4 = 0x0f0f0f0f0f0f0f0fLL; /* 00001111+ */ /* 1 + 256^1 + 256^2 + 256^3 + ... + 256^7 */ - const curl_uint64_t h01 = CURL_OFF_TU_C(0x0101010101010101); + const curl_uint64_t h01 = 0x0101010101010101LL; x -= (x >> 1) & m1; /* replace every 2 bits with bits present */ x = (x & m2) + ((x >> 2) & m2); /* replace every nibble with bits present */ x = (x + (x >> 4)) & m4; /* replace every byte with bits present */ @@ -203,11 +209,11 @@ unsigned int Curl_ctz64(curl_uint64_t x) { /* count trailing zeros in a curl_uint64_t. * divide and conquer to find the number of lower 0 bits */ - const curl_uint64_t ml32 = CURL_OFF_TU_C(0xFFFFFFFF); /* lower 32 bits */ - const curl_uint64_t ml16 = CURL_OFF_TU_C(0x0000FFFF); /* lower 16 bits */ - const curl_uint64_t ml8 = CURL_OFF_TU_C(0x000000FF); /* lower 8 bits */ - const curl_uint64_t ml4 = CURL_OFF_TU_C(0x0000000F); /* lower 4 bits */ - const curl_uint64_t ml2 = CURL_OFF_TU_C(0x00000003); /* lower 2 bits */ + const curl_uint64_t ml32 = 0xFFFFFFFF; /* lower 32 bits */ + const curl_uint64_t ml16 = 0x0000FFFF; /* lower 16 bits */ + const curl_uint64_t ml8 = 0x000000FF; /* lower 8 bits */ + const curl_uint64_t ml4 = 0x0000000F; /* lower 4 bits */ + const curl_uint64_t ml2 = 0x00000003; /* lower 2 bits */ unsigned int n; if(!x) diff --git a/vendor/curl/lib/uint-bset.h b/vendor/curl/lib/uint-bset.h index d998dccd..cc405cc6 100644 --- a/vendor/curl/lib/uint-bset.h +++ b/vendor/curl/lib/uint-bset.h @@ -42,6 +42,7 @@ struct uint_bset { curl_uint64_t *slots; unsigned int nslots; + unsigned int first_slot_used; #ifdef DEBUGBUILD int init; #endif diff --git a/vendor/curl/lib/uint-hash.c b/vendor/curl/lib/uint-hash.c index afeb684d..6c665078 100644 --- a/vendor/curl/lib/uint-hash.c +++ b/vendor/curl/lib/uint-hash.c @@ -107,8 +107,8 @@ static void uint_hash_entry_unlink(struct uint_hash *h, } static void uint_hash_elem_link(struct uint_hash *h, - struct uint_hash_entry **he_anchor, - struct uint_hash_entry *he) + struct uint_hash_entry **he_anchor, + struct uint_hash_entry *he) { he->next = *he_anchor; *he_anchor = he; @@ -206,10 +206,12 @@ static void uint_hash_clear(struct uint_hash *h) } } -void Curl_uint_hash_clear(struct uint_hash *h) +#ifdef UNITTESTS +UNITTEST void Curl_uint_hash_clear(struct uint_hash *h) { uint_hash_clear(h); } +#endif void Curl_uint_hash_destroy(struct uint_hash *h) { diff --git a/vendor/curl/lib/uint-spbset.c b/vendor/curl/lib/uint-spbset.c index 578b9bd0..d12cdcb4 100644 --- a/vendor/curl/lib/uint-spbset.c +++ b/vendor/curl/lib/uint-spbset.c @@ -35,6 +35,9 @@ #define CURL_UINT_SPBSET_MAGIC 0x70737362 #endif +/* Clear the bitset, making it empty. */ +UNITTEST void Curl_uint_spbset_clear(struct uint_spbset *bset); + void Curl_uint_spbset_init(struct uint_spbset *bset) { memset(bset, 0, sizeof(*bset)); @@ -77,7 +80,7 @@ bool Curl_uint_spbset_empty(struct uint_spbset *bset) return TRUE; } -void Curl_uint_spbset_clear(struct uint_spbset *bset) +UNITTEST void Curl_uint_spbset_clear(struct uint_spbset *bset) { struct uint_spbset_chunk *next, *chunk; diff --git a/vendor/curl/lib/uint-spbset.h b/vendor/curl/lib/uint-spbset.h index 571d5675..bd234790 100644 --- a/vendor/curl/lib/uint-spbset.h +++ b/vendor/curl/lib/uint-spbset.h @@ -64,9 +64,6 @@ unsigned int Curl_uint_spbset_count(struct uint_spbset *bset); /* TRUE of bitset is empty */ bool Curl_uint_spbset_empty(struct uint_spbset *bset); -/* Clear the bitset, making it empty. */ -void Curl_uint_spbset_clear(struct uint_spbset *bset); - /* Add the number `i` to the bitset. * Numbers can be added more than once, without making a difference. * Returns FALSE if allocations failed. */ diff --git a/vendor/curl/lib/uint-table.c b/vendor/curl/lib/uint-table.c index d8de1b12..21bcb6e1 100644 --- a/vendor/curl/lib/uint-table.c +++ b/vendor/curl/lib/uint-table.c @@ -34,6 +34,9 @@ #define CURL_UINT_TBL_MAGIC 0x62757473 #endif +/* Clear the table, making it empty. */ +UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl); + void Curl_uint_tbl_init(struct uint_tbl *tbl, Curl_uint_tbl_entry_dtor *entry_dtor) { @@ -68,7 +71,7 @@ CURLcode Curl_uint_tbl_resize(struct uint_tbl *tbl, unsigned int nrows) { /* we use `tbl->nrows + 1` during iteration, want that to work */ DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); - if(!nrows || (nrows == UINT_MAX)) + if(!nrows) return CURLE_BAD_FUNCTION_ARGUMENT; if(nrows != tbl->nrows) { void **rows = calloc(nrows, sizeof(void *)); @@ -95,8 +98,7 @@ void Curl_uint_tbl_destroy(struct uint_tbl *tbl) memset(tbl, 0, sizeof(*tbl)); } - -void Curl_uint_tbl_clear(struct uint_tbl *tbl) +UNITTEST void Curl_uint_tbl_clear(struct uint_tbl *tbl) { DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); uint_tbl_clear_rows(tbl, 0, tbl->nrows); @@ -130,7 +132,7 @@ bool Curl_uint_tbl_add(struct uint_tbl *tbl, void *entry, unsigned int *pkey) DEBUGASSERT(tbl->init == CURL_UINT_TBL_MAGIC); if(!entry || !pkey) return FALSE; - *pkey = UINT_MAX; /* always invalid */ + *pkey = UINT_MAX; if(tbl->nentries == tbl->nrows) /* full */ return FALSE; diff --git a/vendor/curl/lib/uint-table.h b/vendor/curl/lib/uint-table.h index 2d8e8649..c74ec7ad 100644 --- a/vendor/curl/lib/uint-table.h +++ b/vendor/curl/lib/uint-table.h @@ -34,7 +34,7 @@ struct uint_tbl { void **rows; /* array of void* holding entries */ Curl_uint_tbl_entry_dtor *entry_dtor; unsigned int nrows; /* length of `rows` array */ - unsigned int nentries; /* entris in table */ + unsigned int nentries; /* entries in table */ unsigned int last_key_added; /* UINT_MAX or last key added */ #ifdef DEBUGBUILD int init; @@ -60,9 +60,6 @@ unsigned int Curl_uint_tbl_capacity(struct uint_tbl *tbl); /* Get the number of entries in the table. */ unsigned int Curl_uint_tbl_count(struct uint_tbl *tbl); -/* Clear the table, making it empty. */ -void Curl_uint_tbl_clear(struct uint_tbl *tbl); - /* Get the entry for key or NULL if not present */ void *Curl_uint_tbl_get(struct uint_tbl *tbl, unsigned int key); diff --git a/vendor/curl/lib/url.c b/vendor/curl/lib/url.c index dac24b35..e4f250f5 100644 --- a/vendor/curl/lib/url.c +++ b/vendor/curl/lib/url.c @@ -59,6 +59,10 @@ #error "We cannot compile without socket() support!" #endif +#if defined(HAVE_IF_NAMETOINDEX) && defined(_WIN32) +#include +#endif + #include #include "doh.h" @@ -107,7 +111,6 @@ #include "imap.h" #include "url.h" #include "connect.h" -#include "inet_ntop.h" #include "http_ntlm.h" #include "curl_rtmp.h" #include "gopher.h" @@ -231,22 +234,24 @@ CURLcode Curl_close(struct Curl_easy **datap) data = *datap; *datap = NULL; - /* Detach connection if any is left. This should not be normal, but can be - the case for example with CONNECT_ONLY + recv/send (test 556) */ - Curl_detach_connection(data); - if(!data->state.internal) { - if(data->multi) - /* This handle is still part of a multi handle, take care of this first - and detach this handle from there. */ - curl_multi_remove_handle(data->multi, data); - - if(data->multi_easy) { + if(!data->state.internal && data->multi) { + /* This handle is still part of a multi handle, take care of this first + and detach this handle from there. + This detaches the connection. */ + curl_multi_remove_handle(data->multi, data); + } + else { + /* Detach connection if any is left. This should not be normal, but can be + the case for example with CONNECT_ONLY + recv/send (test 556) */ + Curl_detach_connection(data); + if(!data->state.internal && data->multi_easy) { /* when curl_easy_perform() is used, it creates its own multi handle to use and this is the one */ curl_multi_cleanup(data->multi_easy); data->multi_easy = NULL; } } + DEBUGASSERT(!data->conn || data->state.internal); Curl_expire_clear(data); /* shut off any timers left */ @@ -422,13 +427,11 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) /* Set the default CA cert bundle/path detected/specified at build time. * - * If Schannel or Secure Transport is the selected SSL backend then these - * locations are ignored. We allow setting CA location for Schannel and - * Secure Transport when explicitly specified by the user via - * CURLOPT_CAINFO / --cacert. + * If Schannel is the selected SSL backend then these locations are ignored. + * We allow setting CA location for Schannel when explicitly specified by + * the user via CURLOPT_CAINFO / --cacert. */ - if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL && - Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) { + if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) { #ifdef CURL_CA_BUNDLE result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); if(result) @@ -472,8 +475,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->happy_eyeballs_timeout = CURL_HET_DEFAULT; set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ - set->maxage_conn = 118; - set->maxlifetime_conn = 0; + set->conn_max_idle_ms = 118 * 1000; + set->conn_max_age_ms = 0; set->http09_allowed = FALSE; set->httpwant = CURL_HTTP_VERSION_NONE ; @@ -640,7 +643,7 @@ proxy_info_matches(const struct proxy_info *data, { if((data->proxytype == needle->proxytype) && (data->port == needle->port) && - strcasecompare(data->host.name, needle->host.name)) + curl_strequal(data->host.name, needle->host.name)) return TRUE; return FALSE; @@ -670,36 +673,36 @@ socks_proxy_info_matches(const struct proxy_info *data, #define socks_proxy_info_matches(x,y) FALSE #endif -/* A connection has to have been idle for a shorter time than 'maxage_conn' +/* A connection has to have been idle for less than 'conn_max_idle_ms' (the success rate is just too low after this), or created less than - 'maxlifetime_conn' ago, to be subject for reuse. */ - + 'conn_max_age_ms' ago, to be subject for reuse. */ static bool conn_maxage(struct Curl_easy *data, struct connectdata *conn, struct curltime now) { - timediff_t idletime, lifetime; - - idletime = curlx_timediff(now, conn->lastused); - idletime /= 1000; /* integer seconds is fine */ - - if(idletime > data->set.maxage_conn) { - infof(data, "Too old connection (%" FMT_TIMEDIFF_T - " seconds idle), disconnect it", idletime); - return TRUE; + timediff_t age_ms; + + if(data->set.conn_max_idle_ms) { + age_ms = curlx_timediff(now, conn->lastused); + if(age_ms > data->set.conn_max_idle_ms) { + infof(data, "Too old connection (%" FMT_TIMEDIFF_T + " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it", + age_ms, data->set.conn_max_idle_ms); + return TRUE; + } } - lifetime = curlx_timediff(now, conn->created); - lifetime /= 1000; /* integer seconds is fine */ - - if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) { - infof(data, - "Too old connection (%" FMT_TIMEDIFF_T - " seconds since creation), disconnect it", lifetime); - return TRUE; + if(data->set.conn_max_age_ms) { + age_ms = curlx_timediff(now, conn->created); + if(age_ms > data->set.conn_max_age_ms) { + infof(data, + "Too old connection (created %" FMT_TIMEDIFF_T + " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it", + age_ms, data->set.conn_max_age_ms); + return TRUE; + } } - return FALSE; } @@ -1125,7 +1128,7 @@ static bool url_match_destination(struct connectdata *conn, || !m->needle->bits.httpproxy || m->needle->bits.tunnel_proxy #endif ) { - if(!strcasecompare(m->needle->handler->scheme, conn->handler->scheme)) { + if(!curl_strequal(m->needle->handler->scheme, conn->handler->scheme)) { /* `needle` and `conn` do not have the same scheme... */ if(get_protocol_family(conn->handler) != m->needle->handler->protocol) { /* and `conn`s protocol family is not the protocol `needle` wants. @@ -1135,21 +1138,21 @@ static bool url_match_destination(struct connectdata *conn, /* We are in an IMAPS vs IMAP like case. We expect `conn` to have SSL */ if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { DEBUGF(infof(m->data, - "Connection #%" FMT_OFF_T " has compatible protocol famiy, " + "Connection #%" FMT_OFF_T " has compatible protocol family, " "but no SSL, no match", conn->connection_id)); return FALSE; } } /* If needle has "conn_to_*" set, conn must match this */ - if((m->needle->bits.conn_to_host && !strcasecompare( + if((m->needle->bits.conn_to_host && !curl_strequal( m->needle->conn_to_host.name, conn->conn_to_host.name)) || (m->needle->bits.conn_to_port && m->needle->conn_to_port != conn->conn_to_port)) return FALSE; /* hostname and port must match */ - if(!strcasecompare(m->needle->host.name, conn->host.name) || + if(!curl_strequal(m->needle->host.name, conn->host.name) || m->needle->remote_port != conn->remote_port) return FALSE; } @@ -1461,7 +1464,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) #endif conn->ip_version = data->set.ipver; conn->connect_only = data->set.connect_only; - conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ + conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */ /* Initialize the attached xfers bitset */ Curl_uint_spbset_init(&conn->xfers_attached); @@ -1711,7 +1714,7 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, } h = protocols[c % 67]; - if(h && strncasecompare(scheme, h->scheme, len) && !h->scheme[len]) + if(h && curl_strnequal(scheme, h->scheme, len) && !h->scheme[len]) return h; } return NULL; @@ -1795,10 +1798,10 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data, #if defined(HAVE_IF_NAMETOINDEX) || defined(_WIN32) /* Zone identifier is not numeric */ unsigned int scopeidx = 0; -#ifdef _WIN32 - scopeidx = Curl_if_nametoindex(zoneid); -#else +#ifdef HAVE_IF_NAMETOINDEX scopeidx = if_nametoindex(zoneid); +#else + scopeidx = Curl_if_nametoindex(zoneid); #endif if(!scopeidx) { #ifndef CURL_DISABLE_VERBOSE_STRINGS @@ -1885,7 +1888,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, uc = curl_url_get(uh, CURLUPART_HOST, &data->state.up.hostname, 0); if(uc) { - if(!strcasecompare("file", data->state.up.scheme)) + if(!curl_strequal("file", data->state.up.scheme)) return CURLE_OUT_OF_MEMORY; } else if(strlen(data->state.up.hostname) > MAX_URL_LEN) { @@ -1922,7 +1925,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, #ifndef CURL_DISABLE_HSTS /* HSTS upgrade */ - if(data->hsts && strcasecompare("http", data->state.up.scheme)) { + if(data->hsts && curl_strequal("http", data->state.up.scheme)) { /* This MUST use the IDN decoded name */ if(Curl_hsts(data->hsts, conn->host.name, strlen(conn->host.name), TRUE)) { char *url; @@ -2016,7 +2019,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, uc = curl_url_get(uh, CURLUPART_PORT, &data->state.up.port, CURLU_DEFAULT_PORT); if(uc) { - if(!strcasecompare("file", data->state.up.scheme)) + if(!curl_strequal("file", data->state.up.scheme)) return CURLE_OUT_OF_MEMORY; } else { @@ -2195,7 +2198,7 @@ static char *detect_proxy(struct Curl_easy *data, * This can cause 'internal' http/ftp requests to be * arbitrarily redirected by any external attacker. */ - if(!proxy && !strcasecompare("http_proxy", proxy_env)) { + if(!proxy && !curl_strequal("http_proxy", proxy_env)) { /* There was no lowercase variable, try the uppercase version: */ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); proxy = curl_getenv(proxy_env); @@ -2204,10 +2207,10 @@ static char *detect_proxy(struct Curl_easy *data, if(!proxy) { #ifndef CURL_DISABLE_WEBSOCKETS /* websocket proxy fallbacks */ - if(strcasecompare("ws_proxy", proxy_env)) { + if(curl_strequal("ws_proxy", proxy_env)) { proxy = curl_getenv("http_proxy"); } - else if(strcasecompare("wss_proxy", proxy_env)) { + else if(curl_strequal("wss_proxy", proxy_env)) { proxy = curl_getenv("https_proxy"); if(!proxy) proxy = curl_getenv("HTTPS_PROXY"); @@ -2274,22 +2277,22 @@ static CURLcode parse_proxy(struct Curl_easy *data, goto error; } - if(strcasecompare("https", scheme)) { + if(curl_strequal("https", scheme)) { if(proxytype != CURLPROXY_HTTPS2) proxytype = CURLPROXY_HTTPS; else proxytype = CURLPROXY_HTTPS2; } - else if(strcasecompare("socks5h", scheme)) + else if(curl_strequal("socks5h", scheme)) proxytype = CURLPROXY_SOCKS5_HOSTNAME; - else if(strcasecompare("socks5", scheme)) + else if(curl_strequal("socks5", scheme)) proxytype = CURLPROXY_SOCKS5; - else if(strcasecompare("socks4a", scheme)) + else if(curl_strequal("socks4a", scheme)) proxytype = CURLPROXY_SOCKS4A; - else if(strcasecompare("socks4", scheme) || - strcasecompare("socks", scheme)) + else if(curl_strequal("socks4", scheme) || + curl_strequal("socks", scheme)) proxytype = CURLPROXY_SOCKS4; - else if(strcasecompare("http", scheme)) + else if(curl_strequal("http", scheme)) ; /* leave it as HTTP or HTTP/1.0 */ else { /* Any other xxx:// reject! */ @@ -2390,7 +2393,7 @@ static CURLcode parse_proxy(struct Curl_easy *data, goto error; } #ifdef USE_UNIX_SOCKETS - if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) { + if(sockstype && curl_strequal(UNIX_SOCKET_PREFIX, host)) { uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE); if(uc) { result = CURLE_OUT_OF_MEMORY; @@ -2757,16 +2760,20 @@ static CURLcode parse_remote_port(struct Curl_easy *data, return CURLE_OK; } +#ifndef CURL_DISABLE_NETRC static bool str_has_ctrl(const char *input) { - const unsigned char *str = (const unsigned char *)input; - while(*str) { - if(*str < 0x20) - return TRUE; - str++; + if(input) { + const unsigned char *str = (const unsigned char *)input; + while(*str) { + if(*str < 0x20) + return TRUE; + str++; + } } return FALSE; } +#endif /* * Override the login details from the URL with that in the CURLOPT_USERPWD @@ -3062,8 +3069,8 @@ static CURLcode parse_connect_to_string(struct Curl_easy *data, if(!hostname_to_match) return CURLE_OUT_OF_MEMORY; hostname_to_match_len = strlen(hostname_to_match); - host_match = strncasecompare(ptr, hostname_to_match, - hostname_to_match_len); + host_match = curl_strnequal(ptr, hostname_to_match, + hostname_to_match_len); free(hostname_to_match); ptr += hostname_to_match_len; @@ -3228,7 +3235,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, neg->wanted = neg->allowed = CURL_HTTP_V2x; break; case ALPN_h3: - conn->transport = TRNSPRT_QUIC; + conn->transport_wanted = TRNSPRT_QUIC; neg->wanted = neg->allowed = CURL_HTTP_V3x; break; default: /* should not be possible */ @@ -3305,7 +3312,7 @@ static CURLcode resolve_server(struct Curl_easy *data, if(unix_path) { /* This only works if previous transport is TRNSPRT_TCP. Check it? */ - conn->transport = TRNSPRT_UNIX; + conn->transport_wanted = TRNSPRT_UNIX; return resolve_unix(data, conn, unix_path, pdns); } } @@ -3596,7 +3603,7 @@ static CURLcode create_conn(struct Curl_easy *data, * Do this after the hostnames have been IDN-converted. *************************************************************/ if(conn->bits.conn_to_host && - strcasecompare(conn->conn_to_host.name, conn->host.name)) { + curl_strequal(conn->conn_to_host.name, conn->host.name)) { conn->bits.conn_to_host = FALSE; } @@ -4094,3 +4101,17 @@ void *Curl_conn_meta_get(struct connectdata *conn, const char *key) { return Curl_hash_pick(&conn->meta_hash, CURL_UNCONST(key), strlen(key) + 1); } + +CURLcode Curl_1st_err(CURLcode r1, CURLcode r2) +{ + return r1 ? r1 : r2; +} + +CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2) +{ + if(r1 && (r1 != CURLE_AGAIN)) + return r1; + if(r2 && (r2 != CURLE_AGAIN)) + return r2; + return r1; +} diff --git a/vendor/curl/lib/url.h b/vendor/curl/lib/url.h index 7aba98db..bd4060c8 100644 --- a/vendor/curl/lib/url.h +++ b/vendor/curl/lib/url.h @@ -101,6 +101,19 @@ CURLcode Curl_conn_upkeep(struct Curl_easy *data, struct connectdata *conn, struct curltime *now); +/** + * Always eval all arguments, return the first result != CURLE_OK. + * A non-short-circuit evaluation. + */ +CURLcode Curl_1st_err(CURLcode r1, CURLcode r2); + +/** + * Always eval all arguments, return the first + * result != (CURLE_OK|CURLE_AGAIN) or `r1`. + * A non-short-circuit evaluation. + */ +CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2); + #if defined(USE_HTTP2) || defined(USE_HTTP3) void Curl_data_priority_clear_state(struct Curl_easy *data); #else diff --git a/vendor/curl/lib/urlapi.c b/vendor/curl/lib/urlapi.c index 6a7ab1a5..c266fd3e 100644 --- a/vendor/curl/lib/urlapi.c +++ b/vendor/curl/lib/urlapi.c @@ -31,7 +31,7 @@ #include "escape.h" #include "curl_ctype.h" #include "curlx/inet_pton.h" -#include "inet_ntop.h" +#include "curlx/inet_ntop.h" #include "strdup.h" #include "idn.h" #include "curlx/strparse.h" @@ -164,7 +164,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url, } else if((*iptr < ' ') || (*iptr >= 0x7f)) { unsigned char out[3]={'%'}; - Curl_hexbyte(&out[1], *iptr, TRUE); + Curl_hexbyte(&out[1], *iptr); result = curlx_dyn_addn(o, out, 3); } else { @@ -513,7 +513,7 @@ static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname, hostname[hlen] = 0; /* end the address there */ if(1 != curlx_inet_pton(AF_INET6, hostname, dest)) return CURLUE_BAD_IPV6; - if(Curl_inet_ntop(AF_INET6, dest, hostname, hlen)) { + if(curlx_inet_ntop(AF_INET6, dest, hostname, hlen)) { hlen = strlen(hostname); /* might be shorter now */ hostname[hlen + 1] = 0; } @@ -1320,18 +1320,221 @@ CURLU *curl_url_dup(const CURLU *in) return NULL; } +#ifndef USE_IDN +#define host_decode(x,y) CURLUE_LACKS_IDN +#define host_encode(x,y) CURLUE_LACKS_IDN +#else +static CURLUcode host_decode(const char *host, char **allochost) +{ + CURLcode result = Curl_idn_decode(host, allochost); + if(result) + return (result == CURLE_OUT_OF_MEMORY) ? + CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; + return CURLUE_OK; +} + +static CURLUcode host_encode(const char *host, char **allochost) +{ + CURLcode result = Curl_idn_encode(host, allochost); + if(result) + return (result == CURLE_OUT_OF_MEMORY) ? + CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; + return CURLUE_OK; +} +#endif + +static CURLUcode urlget_format(const CURLU *u, CURLUPart what, + const char *ptr, char **part, + bool plusdecode, unsigned int flags) +{ + size_t partlen = strlen(ptr); + bool urldecode = (flags & CURLU_URLDECODE) ? 1 : 0; + bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0; + bool punycode = (flags & CURLU_PUNYCODE) && (what == CURLUPART_HOST); + bool depunyfy = (flags & CURLU_PUNY2IDN) && (what == CURLUPART_HOST); + *part = Curl_memdup0(ptr, partlen); + if(!*part) + return CURLUE_OUT_OF_MEMORY; + if(plusdecode) { + /* convert + to space */ + char *plus = *part; + size_t i = 0; + for(i = 0; i < partlen; ++plus, i++) { + if(*plus == '+') + *plus = ' '; + } + } + if(urldecode) { + char *decoded; + size_t dlen; + /* this unconditional rejection of control bytes is documented + API behavior */ + CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, REJECT_CTRL); + free(*part); + if(res) { + *part = NULL; + return CURLUE_URLDECODE; + } + *part = decoded; + partlen = dlen; + } + if(urlencode) { + struct dynbuf enc; + CURLUcode uc; + curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY); + if(uc) + return uc; + free(*part); + *part = curlx_dyn_ptr(&enc); + } + else if(punycode) { + if(!Curl_is_ASCII_name(u->host)) { + char *allochost = NULL; + CURLUcode ret = host_decode(*part, &allochost); + if(ret) + return ret; + free(*part); + *part = allochost; + } + } + else if(depunyfy) { + if(Curl_is_ASCII_name(u->host)) { + char *allochost = NULL; + CURLUcode ret = host_encode(*part, &allochost); + if(ret) + return ret; + free(*part); + *part = allochost; + } + } + + return CURLUE_OK; +} + +static CURLUcode urlget_url(const CURLU *u, char **part, unsigned int flags) +{ + char *url; + const char *scheme; + char *options = u->options; + char *port = u->port; + char *allochost = NULL; + bool show_fragment = + u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY); + bool show_query = (u->query && u->query[0]) || + (u->query_present && flags & CURLU_GET_EMPTY); + bool punycode = (flags & CURLU_PUNYCODE) ? 1 : 0; + bool depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0; + bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0; + char portbuf[7]; + if(u->scheme && curl_strequal("file", u->scheme)) { + url = aprintf("file://%s%s%s%s%s", + u->path, + show_query ? "?": "", + u->query ? u->query : "", + show_fragment ? "#": "", + u->fragment ? u->fragment : ""); + } + else if(!u->host) + return CURLUE_NO_HOST; + else { + const struct Curl_handler *h = NULL; + char schemebuf[MAX_SCHEME_LEN + 5]; + if(u->scheme) + scheme = u->scheme; + else if(flags & CURLU_DEFAULT_SCHEME) + scheme = DEFAULT_SCHEME; + else + return CURLUE_NO_SCHEME; + + h = Curl_get_scheme_handler(scheme); + if(!port && (flags & CURLU_DEFAULT_PORT)) { + /* there is no stored port number, but asked to deliver + a default one for the scheme */ + if(h) { + msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); + port = portbuf; + } + } + else if(port) { + /* there is a stored port number, but asked to inhibit if it matches + the default one for the scheme */ + if(h && (h->defport == u->portnum) && + (flags & CURLU_NO_DEFAULT_PORT)) + port = NULL; + } + + if(h && !(h->flags & PROTOPT_URLOPTIONS)) + options = NULL; + + if(u->host[0] == '[') { + if(u->zoneid) { + /* make it '[ host %25 zoneid ]' */ + struct dynbuf enc; + size_t hostlen = strlen(u->host); + curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(curlx_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host, + u->zoneid)) + return CURLUE_OUT_OF_MEMORY; + allochost = curlx_dyn_ptr(&enc); + } + } + else if(urlencode) { + allochost = curl_easy_escape(NULL, u->host, 0); + if(!allochost) + return CURLUE_OUT_OF_MEMORY; + } + else if(punycode) { + if(!Curl_is_ASCII_name(u->host)) { + CURLUcode ret = host_decode(u->host, &allochost); + if(ret) + return ret; + } + } + else if(depunyfy) { + if(Curl_is_ASCII_name(u->host)) { + CURLUcode ret = host_encode(u->host, &allochost); + if(ret) + return ret; + } + } + + if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme) + msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme); + else + schemebuf[0] = 0; + + url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + schemebuf, + u->user ? u->user : "", + u->password ? ":": "", + u->password ? u->password : "", + options ? ";" : "", + options ? options : "", + (u->user || u->password || options) ? "@": "", + allochost ? allochost : u->host, + port ? ":": "", + port ? port : "", + u->path ? u->path : "/", + show_query ? "?": "", + u->query ? u->query : "", + show_fragment ? "#": "", + u->fragment ? u->fragment : ""); + free(allochost); + } + if(!url) + return CURLUE_OUT_OF_MEMORY; + *part = url; + return CURLUE_OK; +} + CURLUcode curl_url_get(const CURLU *u, CURLUPart what, char **part, unsigned int flags) { const char *ptr; CURLUcode ifmissing = CURLUE_UNKNOWN_PART; char portbuf[7]; - bool urldecode = (flags & CURLU_URLDECODE) ? 1 : 0; - bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0; - bool punycode = FALSE; - bool depunyfy = FALSE; bool plusdecode = FALSE; - (void)flags; if(!u) return CURLUE_BAD_HANDLE; if(!part) @@ -1342,7 +1545,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, case CURLUPART_SCHEME: ptr = u->scheme; ifmissing = CURLUE_NO_SCHEME; - urldecode = FALSE; /* never for schemes */ + flags &= ~CURLU_URLDECODE; /* never for schemes */ if((flags & CURLU_NO_GUESS_SCHEME) && u->guessed_scheme) return CURLUE_NO_SCHEME; break; @@ -1361,8 +1564,6 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, case CURLUPART_HOST: ptr = u->host; ifmissing = CURLUE_NO_HOST; - punycode = (flags & CURLU_PUNYCODE) ? 1 : 0; - depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0; break; case CURLUPART_ZONEID: ptr = u->zoneid; @@ -1371,7 +1572,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, case CURLUPART_PORT: ptr = u->port; ifmissing = CURLUE_NO_PORT; - urldecode = FALSE; /* never for port */ + flags &= ~CURLU_URLDECODE; /* never for port */ if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) { /* there is no stored port number, but asked to deliver a default one for the scheme */ @@ -1398,7 +1599,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, case CURLUPART_QUERY: ptr = u->query; ifmissing = CURLUE_NO_QUERY; - plusdecode = urldecode; + plusdecode = flags & CURLU_URLDECODE; if(ptr && !ptr[0] && !(flags & CURLU_GET_EMPTY)) /* there was a blank query and the user do not ask for it */ ptr = NULL; @@ -1410,219 +1611,31 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what, /* there was a blank fragment and the user asks for it */ ptr = ""; break; - case CURLUPART_URL: { - char *url; - const char *scheme; - char *options = u->options; - char *port = u->port; - char *allochost = NULL; - bool show_fragment = - u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY); - bool show_query = - (u->query && u->query[0]) || - (u->query_present && flags & CURLU_GET_EMPTY); - punycode = (flags & CURLU_PUNYCODE) ? 1 : 0; - depunyfy = (flags & CURLU_PUNY2IDN) ? 1 : 0; - if(u->scheme && strcasecompare("file", u->scheme)) { - url = aprintf("file://%s%s%s%s%s", - u->path, - show_query ? "?": "", - u->query ? u->query : "", - show_fragment ? "#": "", - u->fragment ? u->fragment : ""); - } - else if(!u->host) - return CURLUE_NO_HOST; - else { - const struct Curl_handler *h = NULL; - char schemebuf[MAX_SCHEME_LEN + 5]; - if(u->scheme) - scheme = u->scheme; - else if(flags & CURLU_DEFAULT_SCHEME) - scheme = DEFAULT_SCHEME; - else - return CURLUE_NO_SCHEME; - - h = Curl_get_scheme_handler(scheme); - if(!port && (flags & CURLU_DEFAULT_PORT)) { - /* there is no stored port number, but asked to deliver - a default one for the scheme */ - if(h) { - msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); - port = portbuf; - } - } - else if(port) { - /* there is a stored port number, but asked to inhibit if it matches - the default one for the scheme */ - if(h && (h->defport == u->portnum) && - (flags & CURLU_NO_DEFAULT_PORT)) - port = NULL; - } - - if(h && !(h->flags & PROTOPT_URLOPTIONS)) - options = NULL; - - if(u->host[0] == '[') { - if(u->zoneid) { - /* make it '[ host %25 zoneid ]' */ - struct dynbuf enc; - size_t hostlen = strlen(u->host); - curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); - if(curlx_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host, - u->zoneid)) - return CURLUE_OUT_OF_MEMORY; - allochost = curlx_dyn_ptr(&enc); - } - } - else if(urlencode) { - allochost = curl_easy_escape(NULL, u->host, 0); - if(!allochost) - return CURLUE_OUT_OF_MEMORY; - } - else if(punycode) { - if(!Curl_is_ASCII_name(u->host)) { -#ifndef USE_IDN - return CURLUE_LACKS_IDN; -#else - CURLcode result = Curl_idn_decode(u->host, &allochost); - if(result) - return (result == CURLE_OUT_OF_MEMORY) ? - CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; -#endif - } - } - else if(depunyfy) { - if(Curl_is_ASCII_name(u->host)) { -#ifndef USE_IDN - return CURLUE_LACKS_IDN; -#else - CURLcode result = Curl_idn_encode(u->host, &allochost); - if(result) - /* this is the most likely error */ - return (result == CURLE_OUT_OF_MEMORY) ? - CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; -#endif - } - } - - if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme) - msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme); - else - schemebuf[0] = 0; - - url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - schemebuf, - u->user ? u->user : "", - u->password ? ":": "", - u->password ? u->password : "", - options ? ";" : "", - options ? options : "", - (u->user || u->password || options) ? "@": "", - allochost ? allochost : u->host, - port ? ":": "", - port ? port : "", - u->path ? u->path : "/", - show_query ? "?": "", - u->query ? u->query : "", - show_fragment ? "#": "", - u->fragment ? u->fragment : ""); - free(allochost); - } - if(!url) - return CURLUE_OUT_OF_MEMORY; - *part = url; - return CURLUE_OK; - } + case CURLUPART_URL: + return urlget_url(u, part, flags); default: ptr = NULL; break; } - if(ptr) { - size_t partlen = strlen(ptr); - size_t i = 0; - *part = Curl_memdup0(ptr, partlen); - if(!*part) - return CURLUE_OUT_OF_MEMORY; - if(plusdecode) { - /* convert + to space */ - char *plus = *part; - for(i = 0; i < partlen; ++plus, i++) { - if(*plus == '+') - *plus = ' '; - } - } - if(urldecode) { - char *decoded; - size_t dlen; - /* this unconditional rejection of control bytes is documented - API behavior */ - CURLcode res = Curl_urldecode(*part, 0, &decoded, &dlen, REJECT_CTRL); - free(*part); - if(res) { - *part = NULL; - return CURLUE_URLDECODE; - } - *part = decoded; - partlen = dlen; - } - if(urlencode) { - struct dynbuf enc; - CURLUcode uc; - curlx_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); - uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY); - if(uc) - return uc; - free(*part); - *part = curlx_dyn_ptr(&enc); - } - else if(punycode) { - if(!Curl_is_ASCII_name(u->host)) { -#ifndef USE_IDN - return CURLUE_LACKS_IDN; -#else - char *allochost; - CURLcode result = Curl_idn_decode(*part, &allochost); - if(result) - return (result == CURLE_OUT_OF_MEMORY) ? - CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; - free(*part); - *part = allochost; -#endif - } - } - else if(depunyfy) { - if(Curl_is_ASCII_name(u->host)) { -#ifndef USE_IDN - return CURLUE_LACKS_IDN; -#else - char *allochost; - CURLcode result = Curl_idn_encode(*part, &allochost); - if(result) - return (result == CURLE_OUT_OF_MEMORY) ? - CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME; - free(*part); - *part = allochost; -#endif - } - } + if(ptr) + return urlget_format(u, what, ptr, part, plusdecode, flags); - return CURLUE_OK; - } - else - return ifmissing; + return ifmissing; } static CURLUcode set_url_scheme(CURLU *u, const char *scheme, - unsigned int flags) + unsigned int flags) { - size_t plen = strlen(scheme); + size_t plen = strlen(scheme); + const struct Curl_handler *h = NULL; + if((plen > MAX_SCHEME_LEN) || (plen < 1)) + /* too long or too short */ + return CURLUE_BAD_SCHEME; + /* verify that it is a fine scheme */ + h = Curl_get_scheme_handler(scheme); + if(!h) { const char *s = scheme; - if((plen > MAX_SCHEME_LEN) || (plen < 1)) - /* too long or too short */ - return CURLUE_BAD_SCHEME; - /* verify that it is a fine scheme */ - if(!(flags & CURLU_NON_SUPPORT_SCHEME) && !Curl_get_scheme_handler(scheme)) + if(!(flags & CURLU_NON_SUPPORT_SCHEME)) return CURLUE_UNSUPPORTED_SCHEME; if(ISALPHA(*s)) { /* ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) */ @@ -1635,8 +1648,9 @@ static CURLUcode set_url_scheme(CURLU *u, const char *scheme, } else return CURLUE_BAD_SCHEME; - u->guessed_scheme = FALSE; - return CURLUE_OK; + } + u->guessed_scheme = FALSE; + return CURLUE_OK; } static CURLUcode set_url_port(CURLU *u, const char *provided_port) @@ -1659,7 +1673,7 @@ static CURLUcode set_url_port(CURLU *u, const char *provided_port) } static CURLUcode set_url(CURLU *u, const char *url, size_t part_size, - unsigned int flags) + unsigned int flags) { /* * Allow a new URL to replace the existing (if any) contents. @@ -1696,6 +1710,53 @@ static CURLUcode set_url(CURLU *u, const char *url, size_t part_size, return uc; } +static CURLUcode urlset_clear(CURLU *u, CURLUPart what) +{ + switch(what) { + case CURLUPART_URL: + free_urlhandle(u); + memset(u, 0, sizeof(struct Curl_URL)); + break; + case CURLUPART_SCHEME: + Curl_safefree(u->scheme); + u->guessed_scheme = FALSE; + break; + case CURLUPART_USER: + Curl_safefree(u->user); + break; + case CURLUPART_PASSWORD: + Curl_safefree(u->password); + break; + case CURLUPART_OPTIONS: + Curl_safefree(u->options); + break; + case CURLUPART_HOST: + Curl_safefree(u->host); + break; + case CURLUPART_ZONEID: + Curl_safefree(u->zoneid); + break; + case CURLUPART_PORT: + u->portnum = 0; + Curl_safefree(u->port); + break; + case CURLUPART_PATH: + Curl_safefree(u->path); + break; + case CURLUPART_QUERY: + Curl_safefree(u->query); + u->query_present = FALSE; + break; + case CURLUPART_FRAGMENT: + Curl_safefree(u->fragment); + u->fragment_present = FALSE; + break; + default: + return CURLUE_UNKNOWN_PART; + } + return CURLUE_OK; +} + CURLUcode curl_url_set(CURLU *u, CURLUPart what, const char *part, unsigned int flags) { @@ -1710,57 +1771,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if(!u) return CURLUE_BAD_HANDLE; - if(!part) { + if(!part) /* setting a part to NULL clears it */ - switch(what) { - case CURLUPART_URL: - break; - case CURLUPART_SCHEME: - storep = &u->scheme; - u->guessed_scheme = FALSE; - break; - case CURLUPART_USER: - storep = &u->user; - break; - case CURLUPART_PASSWORD: - storep = &u->password; - break; - case CURLUPART_OPTIONS: - storep = &u->options; - break; - case CURLUPART_HOST: - storep = &u->host; - break; - case CURLUPART_ZONEID: - storep = &u->zoneid; - break; - case CURLUPART_PORT: - u->portnum = 0; - storep = &u->port; - break; - case CURLUPART_PATH: - storep = &u->path; - break; - case CURLUPART_QUERY: - storep = &u->query; - u->query_present = FALSE; - break; - case CURLUPART_FRAGMENT: - storep = &u->fragment; - u->fragment_present = FALSE; - break; - default: - return CURLUE_UNKNOWN_PART; - } - if(storep && *storep) { - Curl_safefree(*storep); - } - else if(!storep) { - free_urlhandle(u); - memset(u, 0, sizeof(struct Curl_URL)); - } - return CURLUE_OK; - } + return urlset_clear(u, what); nalloc = strlen(part); if(nalloc > CURL_MAX_INPUT_LENGTH) @@ -1810,9 +1823,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, storep = &u->fragment; u->fragment_present = TRUE; break; - case CURLUPART_URL: { + case CURLUPART_URL: return set_url(u, part, nalloc, flags); - } default: return CURLUE_UNKNOWN_PART; } @@ -1849,7 +1861,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, } else { unsigned char out[3]={'%'}; - Curl_hexbyte(&out[1], *i, TRUE); + Curl_hexbyte(&out[1], *i); result = curlx_dyn_addn(&enc, out, 3); if(result) return cc2cu(result); diff --git a/vendor/curl/lib/urldata.h b/vendor/curl/lib/urldata.h index 45052e84..e54721dd 100644 --- a/vendor/curl/lib/urldata.h +++ b/vendor/curl/lib/urldata.h @@ -158,20 +158,20 @@ typedef unsigned int curl_prot_t; #include "request.h" #include "netrc.h" -/* return the count of bytes sent, or -1 on error */ -typedef ssize_t (Curl_send)(struct Curl_easy *data, /* transfer */ - int sockindex, /* socketindex */ - const void *buf, /* data to write */ - size_t len, /* max amount to write */ - bool eos, /* last chunk */ - CURLcode *err); /* error to return */ - -/* return the count of bytes read, or -1 on error */ -typedef ssize_t (Curl_recv)(struct Curl_easy *data, /* transfer */ - int sockindex, /* socketindex */ - char *buf, /* store data here */ - size_t len, /* max amount to read */ - CURLcode *err); /* error to return */ +/* On error return, the value of `pnwritten` has no meaning */ +typedef CURLcode (Curl_send)(struct Curl_easy *data, /* transfer */ + int sockindex, /* socketindex */ + const void *buf, /* data to write */ + size_t len, /* amount to send */ + bool eos, /* last chunk */ + size_t *pnwritten); /* how much sent */ + +/* On error return, the value of `pnread` has no meaning */ +typedef CURLcode (Curl_recv)(struct Curl_easy *data, /* transfer */ + int sockindex, /* socketindex */ + char *buf, /* store data here */ + size_t len, /* max amount to read */ + size_t *pnread); /* how much received */ #include "mime.h" #include "imap.h" @@ -295,7 +295,6 @@ struct ssl_config_data { char *key_type; /* format for private key (default: PEM) */ char *key_passwd; /* plain text private key password */ BIT(certinfo); /* gather lots of certificate info */ - BIT(falsestart); BIT(earlydata); /* use tls1.3 early data */ BIT(enable_beast); /* allow this flaw for interoperability's sake */ BIT(no_revoke); /* disable SSL certificate revocation checks */ @@ -357,93 +356,6 @@ typedef enum { GSS_AUTHSUCC } curlnegotiate; -/* Struct used for GSSAPI (Kerberos V5) authentication */ -#if defined(USE_KERBEROS5) -struct kerberos5data { -#if defined(USE_WINDOWS_SSPI) - CredHandle *credentials; - CtxtHandle *context; - TCHAR *spn; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - size_t token_max; - BYTE *output_token; -#else - gss_ctx_id_t context; - gss_name_t spn; -#endif -}; -#endif - -/* Struct used for SCRAM-SHA-1 authentication */ -#ifdef USE_GSASL -#include -struct gsasldata { - Gsasl *ctx; - Gsasl_session *client; -}; -#endif - -/* Struct used for NTLM challenge-response authentication */ -#if defined(USE_NTLM) -struct ntlmdata { -#ifdef USE_WINDOWS_SSPI -/* The sslContext is used for the Schannel bindings. The - * api is available on the Windows 7 SDK and later. - */ -#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS - CtxtHandle *sslContext; -#endif - CredHandle *credentials; - CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - size_t token_max; - BYTE *output_token; - BYTE *input_token; - size_t input_token_len; - TCHAR *spn; -#else - unsigned int flags; - unsigned char nonce[8]; - unsigned int target_info_len; - void *target_info; /* TargetInfo received in the NTLM type-2 message */ -#endif -}; -#endif - -/* Struct used for Negotiate (SPNEGO) authentication */ -#ifdef USE_SPNEGO -struct negotiatedata { -#ifdef HAVE_GSSAPI - OM_uint32 status; - gss_ctx_id_t context; - gss_name_t spn; - gss_buffer_desc output_token; - struct dynbuf channel_binding_data; -#else -#ifdef USE_WINDOWS_SSPI -#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS - CtxtHandle *sslContext; -#endif - DWORD status; - CredHandle *credentials; - CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - TCHAR *spn; - size_t token_max; - BYTE *output_token; - size_t output_token_length; -#endif -#endif - BIT(noauthpersist); - BIT(havenoauthpersist); - BIT(havenegdata); - BIT(havemultiplerequests); -}; -#endif - #ifdef CURL_DISABLE_PROXY #define CONN_IS_PROXIED(x) 0 #else @@ -753,10 +665,6 @@ struct connectdata { * the connection is cleaned up (see Curl_hash_add2()).*/ struct Curl_hash meta_hash; - /* 'remote_addr' is the particular IP we connected to. it is owned, set - * and NULLed by the connected socket filter (if there is one). */ - const struct Curl_sockaddr_ex *remote_addr; - struct hostname host; char *hostname_resolve; /* hostname to resolve to address, allocated */ char *secondaryhostname; /* secondary socket hostname (ftp) */ @@ -788,7 +696,7 @@ struct connectdata { struct Curl_cfilter *cfilter[2]; /* connection filters */ struct { struct curltime start[2]; /* when filter shutdown started */ - unsigned int timeout_ms; /* 0 means no timeout */ + timediff_t timeout_ms; /* 0 means no timeout */ } shutdown; struct ssl_primary_config ssl_config; @@ -823,10 +731,6 @@ struct connectdata { struct sockaddr_in local_addr; #endif -#if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */ - struct kerberos5data krb5; /* variables into the structure definition, */ -#endif /* however, some of them are ftp specific. */ - struct uint_spbset xfers_attached; /* mids of attached transfers */ /* A connection cache from a SHARE might be used in several multi handles. * We MUST not reuse connections that are running in another multi, @@ -841,26 +745,14 @@ struct connectdata { CtxtHandle *sslContext; #endif -#ifdef USE_GSASL - struct gsasldata gsasl; -#endif - #if defined(USE_NTLM) curlntlm http_ntlm_state; curlntlm proxy_ntlm_state; - - struct ntlmdata ntlm; /* NTLM differs from other authentication schemes - because it authenticates connections, not - single requests! */ - struct ntlmdata proxyntlm; /* NTLM data for proxy */ #endif #ifdef USE_SPNEGO curlnegotiate http_negotiate_state; curlnegotiate proxy_negotiate_state; - - struct negotiatedata negotiate; /* state data for host Negotiate auth */ - struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */ #endif #ifdef USE_UNIX_SOCKETS @@ -893,7 +785,10 @@ struct connectdata { #ifndef CURL_DISABLE_PROXY unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */ #endif - unsigned char transport; /* one of the TRNSPRT_* defines */ + unsigned char transport_wanted; /* one of the TRNSPRT_* defines. Not + necessarily the transport the connection ends using due to Alt-Svc + and happy eyeballing. Use `Curl_conn_get_transport() for actual value + once the connection is set up. */ unsigned char ip_version; /* copied from the Curl_easy at creation time */ /* HTTP version last responded with by the server. * 0 at start, then one of 09, 10, 11, etc. */ @@ -1263,9 +1158,6 @@ struct UrlState { #endif unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) is this */ - unsigned char select_bits; /* != 0 -> bitmask of socket events for this - transfer overriding anything the socket may - report */ unsigned int creds_from:2; /* where is the server credentials originating from, see the CREDS_* defines above */ @@ -1515,9 +1407,9 @@ struct UserDefined { #endif void *progress_client; /* pointer to pass to the progress callback */ void *ioctl_client; /* pointer to pass to the ioctl callback */ - long maxage_conn; /* in seconds, max idle time to allow a connection that + timediff_t conn_max_idle_ms; /* max idle time to allow a connection that is to be reused */ - long maxlifetime_conn; /* in seconds, max time since creation to allow a + timediff_t conn_max_age_ms; /* max time since creation to allow a connection that is to be reused */ #ifndef CURL_DISABLE_TFTP long tftp_blksize; /* in bytes, 0 means use default */ @@ -1563,7 +1455,7 @@ struct UserDefined { #endif curl_off_t max_filesize; /* Maximum file size to download */ #ifndef CURL_DISABLE_FTP - unsigned int accepttimeout; /* in milliseconds, 0 means no timeout */ + timediff_t accepttimeout; /* in milliseconds, 0 means no timeout */ unsigned char ftp_filemethod; /* how to get to a file: curl_ftpfile */ unsigned char ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */ unsigned char ftp_ccc; /* FTP CCC options: curl_ftpccc */ @@ -1607,11 +1499,11 @@ struct UserDefined { void *wildcardptr; #endif - unsigned int timeout; /* ms, 0 means no timeout */ - unsigned int connecttimeout; /* ms, 0 means default timeout */ - unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */ - unsigned int server_response_timeout; /* ms, 0 means no timeout */ - unsigned int shutdowntimeout; /* ms, 0 means default timeout */ + timediff_t timeout; /* ms, 0 means no timeout */ + timediff_t connecttimeout; /* ms, 0 means default timeout */ + timediff_t happy_eyeballs_timeout; /* ms, 0 is a valid value */ + timediff_t server_response_timeout; /* ms, 0 means no timeout */ + timediff_t shutdowntimeout; /* ms, 0 means default timeout */ int tcp_keepidle; /* seconds in idle before sending keepalive probe */ int tcp_keepintvl; /* seconds between TCP keepalive probes */ int tcp_keepcnt; /* maximum number of keepalive probes */ diff --git a/vendor/curl/lib/vauth/cleartext.c b/vendor/curl/lib/vauth/cleartext.c index 719abd19..8fc5d41b 100644 --- a/vendor/curl/lib/vauth/cleartext.c +++ b/vendor/curl/lib/vauth/cleartext.c @@ -127,7 +127,7 @@ void Curl_auth_create_login_message(const char *valuep, struct bufref *out) * Returns void. */ void Curl_auth_create_external_message(const char *user, - struct bufref *out) + struct bufref *out) { /* This is the same formatting as the login message */ Curl_auth_create_login_message(user, out); diff --git a/vendor/curl/lib/vauth/digest.c b/vendor/curl/lib/vauth/digest.c index d99dac19..898629a9 100644 --- a/vendor/curl/lib/vauth/digest.c +++ b/vendor/curl/lib/vauth/digest.c @@ -42,7 +42,6 @@ #include "../vtls/vtls.h" #include "../curlx/warnless.h" #include "../curlx/strparse.h" -#include "../strcase.h" #include "../curl_printf.h" #include "../rand.h" @@ -153,7 +152,7 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ /* Convert sha256 or SHA-512/256 chunk to RFC7616 -suitable ASCII string */ static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */ - unsigned char *dest) /* 65 bytes */ + unsigned char *dest) /* 65 bytes */ { int i; for(i = 0; i < 32; i++) @@ -165,7 +164,7 @@ static char *auth_digest_string_quoted(const char *source) { char *dest; const char *s = source; - size_t n = 1; /* null terminator */ + size_t n = 1; /* null-terminator */ /* Calculate size needed */ while(*s) { @@ -510,31 +509,31 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(strcasecompare(value, "nonce")) { + if(curl_strequal(value, "nonce")) { free(digest->nonce); digest->nonce = strdup(content); if(!digest->nonce) return CURLE_OUT_OF_MEMORY; } - else if(strcasecompare(value, "stale")) { - if(strcasecompare(content, "true")) { + else if(curl_strequal(value, "stale")) { + if(curl_strequal(content, "true")) { digest->stale = TRUE; digest->nc = 1; /* we make a new nonce now */ } } - else if(strcasecompare(value, "realm")) { + else if(curl_strequal(value, "realm")) { free(digest->realm); digest->realm = strdup(content); if(!digest->realm) return CURLE_OUT_OF_MEMORY; } - else if(strcasecompare(value, "opaque")) { + else if(curl_strequal(value, "opaque")) { free(digest->opaque); digest->opaque = strdup(content); if(!digest->opaque) return CURLE_OUT_OF_MEMORY; } - else if(strcasecompare(value, "qop")) { + else if(curl_strequal(value, "qop")) { const char *token = content; struct Curl_str out; bool foundAuth = FALSE; @@ -568,28 +567,28 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, return CURLE_OUT_OF_MEMORY; } } - else if(strcasecompare(value, "algorithm")) { + else if(curl_strequal(value, "algorithm")) { free(digest->algorithm); digest->algorithm = strdup(content); if(!digest->algorithm) return CURLE_OUT_OF_MEMORY; - if(strcasecompare(content, "MD5-sess")) + if(curl_strequal(content, "MD5-sess")) digest->algo = ALGO_MD5SESS; - else if(strcasecompare(content, "MD5")) + else if(curl_strequal(content, "MD5")) digest->algo = ALGO_MD5; - else if(strcasecompare(content, "SHA-256")) + else if(curl_strequal(content, "SHA-256")) digest->algo = ALGO_SHA256; - else if(strcasecompare(content, "SHA-256-SESS")) + else if(curl_strequal(content, "SHA-256-SESS")) digest->algo = ALGO_SHA256SESS; - else if(strcasecompare(content, "SHA-512-256")) { + else if(curl_strequal(content, "SHA-512-256")) { #ifdef CURL_HAVE_SHA512_256 digest->algo = ALGO_SHA512_256; #else /* ! CURL_HAVE_SHA512_256 */ return CURLE_NOT_BUILT_IN; #endif /* ! CURL_HAVE_SHA512_256 */ } - else if(strcasecompare(content, "SHA-512-256-SESS")) { + else if(curl_strequal(content, "SHA-512-256-SESS")) { #ifdef CURL_HAVE_SHA512_256 digest->algo = ALGO_SHA512_256SESS; #else /* ! CURL_HAVE_SHA512_256 */ @@ -599,8 +598,8 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, else return CURLE_BAD_CONTENT_ENCODING; } - else if(strcasecompare(value, "userhash")) { - if(strcasecompare(content, "true")) { + else if(curl_strequal(value, "userhash")) { + if(curl_strequal(content, "true")) { digest->userhash = TRUE; } } @@ -771,7 +770,7 @@ static CURLcode auth_create_digest_http_message( if(!hashthis) return CURLE_OUT_OF_MEMORY; - if(digest->qop && strcasecompare(digest->qop, "auth-int")) { + if(digest->qop && curl_strequal(digest->qop, "auth-int")) { /* We do not support auth-int for PUT or POST */ char hashed[65]; char *hashthis2; diff --git a/vendor/curl/lib/vauth/digest_sspi.c b/vendor/curl/lib/vauth/digest_sspi.c index d0182f6f..28d0b359 100644 --- a/vendor/curl/lib/vauth/digest_sspi.c +++ b/vendor/curl/lib/vauth/digest_sspi.c @@ -242,7 +242,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, /* * Curl_override_sspi_http_realm() * - * This is used to populate the domain in a SSPI identity structure + * This is used to populate the domain in an SSPI identity structure * The realm is extracted from the challenge message and used as the * domain if it is not already explicitly set. * @@ -270,7 +270,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(strcasecompare(value, "realm")) { + if(curl_strequal(value, "realm")) { /* Setup identity's domain and length */ domain.tchar_ptr = curlx_convert_UTF8_to_tchar(content); @@ -345,8 +345,8 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, if(!Curl_auth_digest_get_pair(p, value, content, &p)) break; - if(strcasecompare(value, "stale") && - strcasecompare(content, "true")) { + if(curl_strequal(value, "stale") && + curl_strequal(content, "true")) { stale = TRUE; break; } diff --git a/vendor/curl/lib/vauth/krb5_gssapi.c b/vendor/curl/lib/vauth/krb5_gssapi.c index b5590406..78f4be3d 100644 --- a/vendor/curl/lib/vauth/krb5_gssapi.c +++ b/vendor/curl/lib/vauth/krb5_gssapi.c @@ -96,7 +96,6 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, OM_uint32 major_status; OM_uint32 minor_status; OM_uint32 unused_status; - gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; @@ -104,6 +103,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, (void) passwdp; if(!krb5->spn) { + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + /* Generate our SPN */ char *spn = Curl_auth_build_spn(service, NULL, host); if(!spn) @@ -315,7 +316,8 @@ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5) /* Free our security context */ if(krb5->context != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER); + Curl_gss_delete_sec_context(&minor_status, &krb5->context, + GSS_C_NO_BUFFER); krb5->context = GSS_C_NO_CONTEXT; } diff --git a/vendor/curl/lib/vauth/oauth2.c b/vendor/curl/lib/vauth/oauth2.c index 76e77c6a..a84dc60d 100644 --- a/vendor/curl/lib/vauth/oauth2.c +++ b/vendor/curl/lib/vauth/oauth2.c @@ -94,8 +94,8 @@ CURLcode Curl_auth_create_oauth_bearer_message(const char *user, * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, - const char *bearer, - struct bufref *out) + const char *bearer, + struct bufref *out) { /* Generate the message */ char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); diff --git a/vendor/curl/lib/vauth/spnego_gssapi.c b/vendor/curl/lib/vauth/spnego_gssapi.c index b17ee46d..1e576c71 100644 --- a/vendor/curl/lib/vauth/spnego_gssapi.c +++ b/vendor/curl/lib/vauth/spnego_gssapi.c @@ -93,7 +93,6 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, OM_uint32 major_status; OM_uint32 minor_status; OM_uint32 unused_status; - gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; gss_channel_bindings_t chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; @@ -111,6 +110,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, } if(!nego->spn) { + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + /* Generate our SPN */ char *spn = Curl_auth_build_spn(service, NULL, host); if(!spn) @@ -267,7 +268,8 @@ void Curl_auth_cleanup_spnego(struct negotiatedata *nego) /* Free our security context */ if(nego->context != GSS_C_NO_CONTEXT) { - gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER); + Curl_gss_delete_sec_context(&minor_status, &nego->context, + GSS_C_NO_BUFFER); nego->context = GSS_C_NO_CONTEXT; } @@ -276,7 +278,6 @@ void Curl_auth_cleanup_spnego(struct negotiatedata *nego) gss_release_buffer(&minor_status, &nego->output_token); nego->output_token.value = NULL; nego->output_token.length = 0; - } /* Free the SPN */ diff --git a/vendor/curl/lib/vauth/vauth.c b/vendor/curl/lib/vauth/vauth.c index 06de8420..7a85b704 100644 --- a/vendor/curl/lib/vauth/vauth.c +++ b/vendor/curl/lib/vauth/vauth.c @@ -27,10 +27,11 @@ #include #include "vauth.h" +#include "../strdup.h" #include "../urldata.h" -#include "../strcase.h" #include "../curlx/multibyte.h" #include "../curl_printf.h" +#include "../url.h" /* The last #include files should be: */ #include "../curl_memory.h" @@ -39,7 +40,7 @@ /* * Curl_auth_build_spn() * - * This is used to build a SPN string in the following formats: + * This is used to build an SPN string in the following formats: * * service/host@realm (Not currently used) * service/host (Not used by GSS-API) @@ -156,7 +157,121 @@ bool Curl_auth_allowed_to_host(struct Curl_easy *data) return !data->state.this_is_a_follow || data->set.allow_auth_to_other_hosts || (data->state.first_host && - strcasecompare(data->state.first_host, conn->host.name) && + curl_strequal(data->state.first_host, conn->host.name) && (data->state.first_remote_port == conn->remote_port) && (data->state.first_remote_protocol == conn->handler->protocol)); } + +#ifdef USE_NTLM + +static void ntlm_conn_dtor(void *key, size_t klen, void *entry) +{ + struct ntlmdata *ntlm = entry; + (void)key; + (void)klen; + DEBUGASSERT(ntlm); + Curl_auth_cleanup_ntlm(ntlm); + free(ntlm); +} + +struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy) +{ + const char *key = proxy ? CURL_META_NTLM_PROXY_CONN : + CURL_META_NTLM_CONN; + struct ntlmdata *ntlm = Curl_conn_meta_get(conn, key); + if(!ntlm) { + ntlm = calloc(1, sizeof(*ntlm)); + if(!ntlm || + Curl_conn_meta_set(conn, key, ntlm, ntlm_conn_dtor)) + return NULL; + } + return ntlm; +} + +void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy) +{ + Curl_conn_meta_remove(conn, proxy ? + CURL_META_NTLM_PROXY_CONN : CURL_META_NTLM_CONN); +} + +#endif /* USE_NTLM */ + +#ifdef USE_KERBEROS5 + +static void krb5_conn_dtor(void *key, size_t klen, void *entry) +{ + struct kerberos5data *krb5 = entry; + (void)key; + (void)klen; + DEBUGASSERT(krb5); + Curl_auth_cleanup_gssapi(krb5); + free(krb5); +} + +struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn) +{ + struct kerberos5data *krb5 = Curl_conn_meta_get(conn, CURL_META_KRB5_CONN); + if(!krb5) { + krb5 = calloc(1, sizeof(*krb5)); + if(!krb5 || + Curl_conn_meta_set(conn, CURL_META_KRB5_CONN, krb5, krb5_conn_dtor)) + return NULL; + } + return krb5; +} + +#endif /* USE_KERBEROS5 */ + +#ifdef USE_GSASL + +static void gsasl_conn_dtor(void *key, size_t klen, void *entry) +{ + struct gsasldata *gsasl = entry; + (void)key; + (void)klen; + DEBUGASSERT(gsasl); + Curl_auth_gsasl_cleanup(gsasl); + free(gsasl); +} + +struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn) +{ + struct gsasldata *gsasl = Curl_conn_meta_get(conn, CURL_META_GSASL_CONN); + if(!gsasl) { + gsasl = calloc(1, sizeof(*gsasl)); + if(!gsasl || + Curl_conn_meta_set(conn, CURL_META_GSASL_CONN, gsasl, gsasl_conn_dtor)) + return NULL; + } + return gsasl; +} + +#endif /* USE_GSASL */ + +#ifdef USE_SPNEGO + +static void nego_conn_dtor(void *key, size_t klen, void *entry) +{ + struct negotiatedata *nego = entry; + (void)key; + (void)klen; + DEBUGASSERT(nego); + Curl_auth_cleanup_spnego(nego); + free(nego); +} + +struct negotiatedata *Curl_auth_nego_get(struct connectdata *conn, bool proxy) +{ + const char *key = proxy ? CURL_META_NEGO_PROXY_CONN : + CURL_META_NEGO_CONN; + struct negotiatedata *nego = Curl_conn_meta_get(conn, key); + if(!nego) { + nego = calloc(1, sizeof(*nego)); + if(!nego || + Curl_conn_meta_set(conn, key, nego, nego_conn_dtor)) + return NULL; + } + return nego; +} + +#endif /* USE_SPNEGO */ diff --git a/vendor/curl/lib/vauth/vauth.h b/vendor/curl/lib/vauth/vauth.h index d8459880..7d085e33 100644 --- a/vendor/curl/lib/vauth/vauth.h +++ b/vendor/curl/lib/vauth/vauth.h @@ -27,8 +27,10 @@ #include #include "../bufref.h" +#include "../curlx/dynbuf.h" struct Curl_easy; +struct connectdata; #if !defined(CURL_DISABLE_DIGEST_AUTH) struct digestdata; @@ -38,10 +40,6 @@ struct digestdata; struct ntlmdata; #endif -#if defined(USE_KERBEROS5) -struct kerberos5data; -#endif - #if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) struct negotiatedata; #endif @@ -50,7 +48,8 @@ struct negotiatedata; struct gsasldata; #endif -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI +#include "../curl_sspi.h" #define GSS_ERROR(status) ((status) & 0x80000000) #endif @@ -60,7 +59,7 @@ struct gsasldata; */ bool Curl_auth_allowed_to_host(struct Curl_easy *data); -/* This is used to build a SPN string */ +/* This is used to build an SPN string */ #if !defined(USE_WINDOWS_SSPI) char *Curl_auth_build_spn(const char *service, const char *host, const char *realm); @@ -117,9 +116,23 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, /* This is used to clean up the digest specific data */ void Curl_auth_digest_cleanup(struct digestdata *digest); +#else +#define Curl_auth_is_digest_supported() FALSE #endif /* !CURL_DISABLE_DIGEST_AUTH */ #ifdef USE_GSASL + +/* meta key for storing GSASL meta at connection */ +#define CURL_META_GSASL_CONN "meta:auth:gsasl:conn" + +#include +struct gsasldata { + Gsasl *ctx; + Gsasl_session *client; +}; + +struct gsasldata *Curl_auth_gsasl_get(struct connectdata *conn); + /* This is used to evaluate if MECH is supported by gsasl */ bool Curl_auth_gsasl_is_supported(struct Curl_easy *data, const char *mech, @@ -141,9 +154,46 @@ void Curl_auth_gsasl_cleanup(struct gsasldata *digest); #endif #if defined(USE_NTLM) + +/* meta key for storing NTML meta at connection */ +#define CURL_META_NTLM_CONN "meta:auth:ntml:conn" +/* meta key for storing NTML-PROXY meta at connection */ +#define CURL_META_NTLM_PROXY_CONN "meta:auth:ntml-proxy:conn" + +struct ntlmdata { +#ifdef USE_WINDOWS_SSPI +/* The sslContext is used for the Schannel bindings. The + * api is available on the Windows 7 SDK and later. + */ +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + CtxtHandle *sslContext; +#endif + CredHandle *credentials; + CtxtHandle *context; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + size_t token_max; + BYTE *output_token; + BYTE *input_token; + size_t input_token_len; + TCHAR *spn; +#else + unsigned int flags; + unsigned char nonce[8]; + unsigned int target_info_len; + void *target_info; /* TargetInfo received in the NTLM type-2 message */ +#endif +}; + /* This is used to evaluate if NTLM is supported */ bool Curl_auth_is_ntlm_supported(void); +struct ntlmdata *Curl_auth_ntlm_get(struct connectdata *conn, bool proxy); +void Curl_auth_ntlm_remove(struct connectdata *conn, bool proxy); + +/* This is used to clean up the NTLM specific data */ +void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm); + /* This is used to generate a base64 encoded NTLM type-1 message */ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data, const char *userp, @@ -165,8 +215,6 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, struct ntlmdata *ntlm, struct bufref *out); -/* This is used to clean up the NTLM specific data */ -void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm); #else #define Curl_auth_is_ntlm_supported() FALSE #endif /* USE_NTLM */ @@ -184,6 +232,40 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, struct bufref *out); #if defined(USE_KERBEROS5) + +#ifdef HAVE_GSSAPI +# ifdef HAVE_GSSGNU +# include +# elif defined HAVE_GSSAPI_GSSAPI_H +# include +# else +# include +# endif +# ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H +# include +# endif +#endif + +/* meta key for storing KRB5 meta at connection */ +#define CURL_META_KRB5_CONN "meta:auth:krb5:conn" + +struct kerberos5data { +#if defined(USE_WINDOWS_SSPI) + CredHandle *credentials; + CtxtHandle *context; + TCHAR *spn; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + size_t token_max; + BYTE *output_token; +#else + gss_ctx_id_t context; + gss_name_t spn; +#endif +}; + +struct kerberos5data *Curl_auth_krb5_get(struct connectdata *conn); + /* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ bool Curl_auth_is_gssapi_supported(void); @@ -213,10 +295,48 @@ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5); #define Curl_auth_is_gssapi_supported() FALSE #endif /* USE_KERBEROS5 */ -#if defined(USE_SPNEGO) -/* This is used to evaluate if SPNEGO (Negotiate) is supported */ +#ifdef USE_SPNEGO + bool Curl_auth_is_spnego_supported(void); +/* meta key for storing NEGO meta at connection */ +#define CURL_META_NEGO_CONN "meta:auth:nego:conn" +/* meta key for storing NEGO PROXY meta at connection */ +#define CURL_META_NEGO_PROXY_CONN "meta:auth:nego-proxy:conn" + +/* Struct used for Negotiate (SPNEGO) authentication */ +struct negotiatedata { +#ifdef HAVE_GSSAPI + OM_uint32 status; + gss_ctx_id_t context; + gss_name_t spn; + gss_buffer_desc output_token; + struct dynbuf channel_binding_data; +#else +#ifdef USE_WINDOWS_SSPI +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS + CtxtHandle *sslContext; +#endif + DWORD status; + CredHandle *credentials; + CtxtHandle *context; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + TCHAR *spn; + size_t token_max; + BYTE *output_token; + size_t output_token_length; +#endif +#endif + BIT(noauthpersist); + BIT(havenoauthpersist); + BIT(havenegdata); + BIT(havemultiplerequests); +}; + +struct negotiatedata * +Curl_auth_nego_get(struct connectdata *conn, bool proxy); + /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge message */ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, diff --git a/vendor/curl/lib/vquic/curl_msh3.c b/vendor/curl/lib/vquic/curl_msh3.c index cbeb6505..6566447b 100644 --- a/vendor/curl/lib/vquic/curl_msh3.c +++ b/vendor/curl/lib/vquic/curl_msh3.c @@ -83,16 +83,16 @@ static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection, void *IfContext); static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, - void *IfContext); + void *IfContext); static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection, - void *IfContext, - MSH3_REQUEST *Request); + void *IfContext, + MSH3_REQUEST *Request); static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request, void *IfContext, const MSH3_HEADER *Header); static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request, - void *IfContext, uint32_t *Length, - const uint8_t *Data); + void *IfContext, uint32_t *Length, + const uint8_t *Data); static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext, bool Aborted, uint64_t AbortError); static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request, @@ -244,33 +244,17 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) static void drain_stream_from_other_thread(struct Curl_easy *data, struct h3_stream_ctx *stream) { - unsigned char bits; - - /* risky */ - bits = CURL_CSELECT_IN; - if(stream && !stream->upload_done) - bits |= CURL_CSELECT_OUT; - if(data->state.select_bits != bits) { - data->state.select_bits = bits; - /* cannot expire from other thread */ - } + (void)data; + (void)stream; + /* cannot expire from other thread. + here is the disconnect between msh3 and curl */ } static void h3_drain_stream(struct Curl_cfilter *cf, struct Curl_easy *data) { - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - unsigned char bits; - (void)cf; - bits = CURL_CSELECT_IN; - if(stream && !stream->upload_done) - bits |= CURL_CSELECT_OUT; - if(data->state.select_bits != bits) { - data->state.select_bits = bits; - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } + Curl_multi_mark_dirty(data); } static const MSH3_CONNECTION_IF msh3_conn_if = { @@ -294,7 +278,7 @@ static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection, } static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, - void *IfContext) + void *IfContext) { struct Curl_cfilter *cf = IfContext; struct cf_msh3_ctx *ctx = cf->ctx; @@ -307,8 +291,8 @@ static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, } static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection, - void *IfContext, - MSH3_REQUEST *Request) + void *IfContext, + MSH3_REQUEST *Request) { (void)Connection; (void)IfContext; @@ -361,17 +345,16 @@ static CURLcode write_resp_raw(struct Curl_easy *data, struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); CURLcode result = CURLE_OK; - ssize_t nwritten; + size_t nwritten; if(!stream) return CURLE_RECV_ERROR; - nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); - if(nwritten < 0) { + result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten); + if(result) return result; - } - if((size_t)nwritten < memlen) { + if(nwritten < memlen) { /* This MUST not happen. Our recbuf is dimensioned to hold the * full max_stream_window and then some for this very reason. */ DEBUGASSERT(0); @@ -518,40 +501,33 @@ static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request, (void)SendContext; } -static ssize_t recv_closed_stream(struct Curl_cfilter *cf, - struct Curl_easy *data, - CURLcode *err) +static CURLcode recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + size_t *pnread) { struct cf_msh3_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nread = -1; - if(!stream) { - *err = CURLE_RECV_ERROR; - return -1; - } (void)cf; + *pnread = 0; + if(!stream) + return CURLE_RECV_ERROR; + if(stream->reset) { failf(data, "HTTP/3 stream reset by server"); - *err = CURLE_PARTIAL_FILE; - CURL_TRC_CF(data, cf, "cf_recv, was reset -> %d", *err); - goto out; + CURL_TRC_CF(data, cf, "cf_recv, was reset"); + return CURLE_PARTIAL_FILE; } else if(stream->error3) { failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)", (ssize_t)stream->error3); - *err = CURLE_HTTP3; - CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err); - goto out; + CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly"); + return CURLE_HTTP3; } else { - CURL_TRC_CF(data, cf, "cf_recv, closed ok -> %d", *err); + CURL_TRC_CF(data, cf, "cf_recv, closed ok"); } - *err = CURLE_OK; - nread = 0; - -out: - return nread; + return CURLE_OK; } static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data) @@ -571,60 +547,56 @@ static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data) } } -static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { struct cf_msh3_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nread = -1; struct cf_call_data save; + CURLcode result = CURLE_OK; + *pnread = 0; CURL_TRC_CF(data, cf, "cf_recv(len=%zu), stream=%d", len, !!stream); - if(!stream) { - *err = CURLE_RECV_ERROR; - return -1; - } + if(!stream) + return CURLE_RECV_ERROR; CF_DATA_SAVE(save, cf, data); msh3_lock_acquire(&stream->recv_lock); if(stream->recv_error) { failf(data, "request aborted"); - *err = stream->recv_error; + result = stream->recv_error; goto out; } - *err = CURLE_OK; - if(!Curl_bufq_is_empty(&stream->recvbuf)) { - nread = Curl_bufq_read(&stream->recvbuf, - (unsigned char *)buf, len, err); - CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d", - len, nread, *err); - if(nread < 0) + result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread); + CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %d, %zu", + len, result, *pnread); + if(result) goto out; if(stream->closed) h3_drain_stream(cf, data); } else if(stream->closed) { - nread = recv_closed_stream(cf, data, err); + result = recv_closed_stream(cf, data, pnread); goto out; } else { CURL_TRC_CF(data, cf, "req: nothing here, call again"); - *err = CURLE_AGAIN; + result = CURLE_AGAIN; } out: msh3_lock_release(&stream->recv_lock); set_quic_expire(cf, data); CF_DATA_RESTORE(cf, save); - return nread; + return result; } -static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_msh3_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); @@ -634,7 +606,9 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, size_t nheader, i; ssize_t nwritten = -1; struct cf_call_data save; + CURLcode result = CURLE_OK; + *pnwritten = 0; CF_DATA_SAVE(save, cf, data); Curl_h1_req_parse_init(&h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); @@ -648,23 +622,21 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* The first send on the request contains the headers and possibly some data. Parse out the headers and create the request, then if there is any data left over go ahead and send it too. */ - nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, err); + nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, &result); if(nwritten < 0) goto out; DEBUGASSERT(h1.done); DEBUGASSERT(h1.req); + *pnwritten = (size_t)nwritten; - *err = Curl_http_req_to_h2(&h2_headers, h1.req, data); - if(*err) { - nwritten = -1; + result = Curl_http_req_to_h2(&h2_headers, h1.req, data); + if(result) goto out; - } nheader = Curl_dynhds_count(&h2_headers); nva = malloc(sizeof(MSH3_HEADER) * nheader); if(!nva) { - *err = CURLE_OUT_OF_MEMORY; - nwritten = -1; + result = CURLE_OUT_OF_MEMORY; goto out; } @@ -683,11 +655,10 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, MSH3_REQUEST_FLAG_NONE); if(!stream->req) { failf(data, "request open failed"); - *err = CURLE_SEND_ERROR; - goto out; + result = CURLE_SEND_ERROR; } - *err = CURLE_OK; - nwritten = len; + result = CURLE_OK; + *pnwritten = len; goto out; } else { @@ -699,14 +670,14 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf, (uint32_t)len, stream)) { - *err = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; goto out; } /* msh3/msquic will hold onto this memory until the send complete event. How do we make sure curl does not free it until then? */ - *err = CURLE_OK; - nwritten = len; + result = CURLE_OK; + *pnwritten = len; } out: @@ -715,7 +686,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, Curl_h1_req_parse_free(&h1); Curl_dynhds_free(&h2_headers); CF_DATA_RESTORE(cf, save); - return nwritten; + return result; } static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf, @@ -964,8 +935,6 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data) "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]); ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; } - if(cf->sockindex == FIRSTSOCKET) - cf->conn->remote_addr = NULL; } if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) { sclose(ctx->sock[SP_LOCAL]); @@ -1049,7 +1018,6 @@ struct Curl_cftype Curl_cft_http3 = { cf_msh3_connect, cf_msh3_close, Curl_cf_def_shutdown, - Curl_cf_def_get_host, cf_msh3_adjust_pollset, cf_msh3_data_pending, cf_msh3_send, diff --git a/vendor/curl/lib/vquic/curl_ngtcp2.c b/vendor/curl/lib/vquic/curl_ngtcp2.c index f529f7e4..69d54ecc 100644 --- a/vendor/curl/lib/vquic/curl_ngtcp2.c +++ b/vendor/curl/lib/vquic/curl_ngtcp2.c @@ -47,12 +47,12 @@ #endif #include "../urldata.h" +#include "../url.h" #include "../uint-hash.h" #include "../sendf.h" #include "../strdup.h" #include "../rand.h" #include "../multiif.h" -#include "../strcase.h" #include "../cfilters.h" #include "../cf-socket.h" #include "../connect.h" @@ -342,23 +342,6 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) } } -static void h3_drain_stream(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_ngtcp2_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - unsigned char bits; - - (void)cf; - bits = CURL_CSELECT_IN; - if(stream && stream->upload_left && !stream->send_closed) - bits |= CURL_CSELECT_OUT; - if(data->state.select_bits != bits) { - data->state.select_bits = bits; - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } -} - /* ngtcp2 default congestion controller does not perform pacing. Limit the maximum packet burst to MAX_PKT_BURST packets. */ #define MAX_PKT_BURST 10 @@ -391,8 +374,8 @@ static void pktx_init(struct pkt_io_ctx *pktx, } static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, - uint64_t datalen, void *user_data, - void *stream_user_data); + uint64_t datalen, void *user_data, + void *stream_user_data); static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) { @@ -485,6 +468,7 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data) ctx->handshake_at = curlx_now(); ctx->tls_handshake_complete = TRUE; cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + Curl_vquic_report_handshake(&ctx->tls, cf, data); ctx->tls_vrfy_result = Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer); @@ -744,7 +728,7 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow", (curl_int64_t)stream_id); stream->quic_flow_blocked = FALSE; - h3_drain_stream(cf, s_data); + Curl_multi_mark_dirty(s_data); } return 0; } @@ -912,8 +896,8 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, } static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_ngtcp2_ctx *ctx = cf->ctx; bool want_recv, want_send; @@ -971,7 +955,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid, else { CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->id); } - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); return 0; } @@ -1072,7 +1056,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid, if(stream->status_code / 100 != 1) { stream->resp_hds_complete = TRUE; } - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); return 0; } @@ -1293,14 +1277,14 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, } /* incoming data frames on the h3 stream */ -static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t blen, CURLcode *err) +static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t blen, size_t *pnread) { struct cf_ngtcp2_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nread = -1; struct cf_call_data save; struct pkt_io_ctx pktx; + CURLcode result = CURLE_OK; (void)ctx; (void)buf; @@ -1310,7 +1294,7 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGASSERT(ctx); DEBUGASSERT(ctx->qconn); DEBUGASSERT(ctx->h3conn); - *err = CURLE_OK; + *pnread = 0; /* handshake verification failed in callback, do not recv anything */ if(ctx->tls_vrfy_result) @@ -1319,46 +1303,38 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, pktx_init(&pktx, cf, data); if(!stream || ctx->shutdown_started) { - *err = CURLE_RECV_ERROR; + result = CURLE_RECV_ERROR; goto out; } if(cf_progress_ingress(cf, data, &pktx)) { - *err = CURLE_RECV_ERROR; - nread = -1; + result = CURLE_RECV_ERROR; goto out; } if(stream->xfer_result) { CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id); cf_ngtcp2_stream_close(cf, data, stream); - *err = stream->xfer_result; - nread = -1; + result = stream->xfer_result; goto out; } else if(stream->closed) { - nread = recv_closed_stream(cf, data, stream, err); + ssize_t nread = recv_closed_stream(cf, data, stream, &result); + if(nread > 0) + *pnread = (size_t)nread; goto out; } - *err = CURLE_AGAIN; - nread = -1; + result = CURLE_AGAIN; out: - if(cf_progress_egress(cf, data, &pktx)) { - *err = CURLE_SEND_ERROR; - nread = -1; - } - else { - CURLcode result2 = check_and_set_expiry(cf, data, &pktx); - if(result2) { - *err = result2; - nread = -1; - } - } - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d", - stream ? stream->id : -1, blen, nread, *err); + result = Curl_1st_err(result, cf_progress_egress(cf, data, &pktx)); + result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); + + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu", + + stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); - return nread; + return result; } static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id, @@ -1464,10 +1440,10 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id, field list. */ #define AUTHORITY_DST_IDX 3 -static ssize_t h3_stream_open(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *buf, size_t len, - CURLcode *err) +static CURLcode h3_stream_open(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t len, + size_t *pnwritten) { struct cf_ngtcp2_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = NULL; @@ -1480,41 +1456,43 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, ssize_t nwritten = -1; nghttp3_data_reader reader; nghttp3_data_reader *preader = NULL; + CURLcode result; + *pnwritten = 0; Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); - *err = h3_data_setup(cf, data); - if(*err) + result = h3_data_setup(cf, data); + if(result) goto out; stream = H3_STREAM_CTX(ctx, data); DEBUGASSERT(stream); if(!stream) { - *err = CURLE_FAILED_INIT; + result = CURLE_FAILED_INIT; goto out; } - nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result); if(nwritten < 0) goto out; + *pnwritten = (size_t)nwritten; + if(!stream->h1.done) { /* need more data */ goto out; } DEBUGASSERT(stream->h1.req); - *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); - if(*err) { - nwritten = -1; + result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(result) goto out; - } + /* no longer needed */ Curl_h1_req_parse_free(&stream->h1); nheader = Curl_dynhds_count(&h2_headers); nva = malloc(sizeof(nghttp3_nv) * nheader); if(!nva) { - *err = CURLE_OUT_OF_MEMORY; - nwritten = -1; + result = CURLE_OUT_OF_MEMORY; goto out; } @@ -1530,8 +1508,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data); if(rc) { failf(data, "can get bidi streams"); - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } stream->id = (curl_int64_t)sid; @@ -1574,8 +1551,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, "%d (%s)", stream->id, rc, nghttp3_strerror(rc)); break; } - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } @@ -1592,26 +1568,25 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, out: free(nva); Curl_dynhds_free(&h2_headers); - return nwritten; + return result; } -static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_ngtcp2_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t sent = -1; struct cf_call_data save; struct pkt_io_ctx pktx; - CURLcode result; + CURLcode result = CURLE_OK; CF_DATA_SAVE(save, cf, data); DEBUGASSERT(cf->connected); DEBUGASSERT(ctx->qconn); DEBUGASSERT(ctx->h3conn); pktx_init(&pktx, cf, data); - *err = CURLE_OK; + *pnwritten = 0; /* handshake verification failed in callback, do not send anything */ if(ctx->tls_vrfy_result) @@ -1619,19 +1594,18 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, (void)eos; /* use for stream EOF and block handling */ result = cf_progress_ingress(cf, data, &pktx); - if(result) { - *err = result; - } + if(result) + goto out; if(!stream || stream->id < 0) { if(ctx->shutdown_started) { CURL_TRC_CF(data, cf, "cannot open stream on closed connection"); - *err = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; goto out; } - sent = h3_stream_open(cf, data, buf, len, err); - if(sent < 0) { - CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err); + result = h3_stream_open(cf, data, buf, len, pnwritten); + if(result) { + CURL_TRC_CF(data, cf, "failed to open stream -> %d", result); goto out; } stream = H3_STREAM_CTX(ctx, data); @@ -1639,7 +1613,7 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, else if(stream->xfer_result) { CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id); cf_ngtcp2_stream_close(cf, data, stream); - *err = stream->xfer_result; + result = stream->xfer_result; goto out; } else if(stream->closed) { @@ -1651,52 +1625,43 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data, * error situation. */ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data" "on closed stream with response", stream->id); - *err = CURLE_OK; - sent = (ssize_t)len; + result = CURLE_OK; + *pnwritten = len; goto out; } CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) " "-> stream closed", stream->id, len); - *err = CURLE_HTTP3; - sent = -1; + result = CURLE_HTTP3; goto out; } else if(ctx->shutdown_started) { CURL_TRC_CF(data, cf, "cannot send on closed connection"); - *err = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; goto out; } else { - sent = Curl_bufq_write(&stream->sendbuf, buf, len, err); + result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten); CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to " - "sendbuf(len=%zu) -> %zd, %d", - stream->id, len, sent, *err); - if(sent < 0) { + "sendbuf(len=%zu) -> %d, %zu", + stream->id, len, result, *pnwritten); + if(result) goto out; - } - (void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id); } - if(sent > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata) - ctx->earlydata_skip += sent; + if(*pnwritten > 0 && !ctx->tls_handshake_complete && ctx->use_earlydata) + ctx->earlydata_skip += *pnwritten; + DEBUGASSERT(!result); result = cf_progress_egress(cf, data, &pktx); - if(result) { - *err = result; - sent = -1; - } out: - result = check_and_set_expiry(cf, data, &pktx); - if(result) { - *err = result; - sent = -1; - } - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d", - stream ? stream->id : -1, len, sent, *err); + result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); + + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu", + stream ? stream->id : -1, len, result, *pnwritten); CF_DATA_RESTORE(cf, save); - return sent; + return result; } static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen, @@ -1756,9 +1721,9 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf, * Read a network packet to send from ngtcp2 into `buf`. * Return number of bytes written or -1 with *err set. */ -static ssize_t read_pkt_to_send(void *userp, - unsigned char *buf, size_t buflen, - CURLcode *err) +static CURLcode read_pkt_to_send(void *userp, + unsigned char *buf, size_t buflen, + size_t *pnread) { struct pkt_io_ctx *x = userp; struct cf_ngtcp2_ctx *ctx = x->cf->ctx; @@ -1768,7 +1733,9 @@ static ssize_t read_pkt_to_send(void *userp, uint32_t flags; int64_t stream_id; int fin; - ssize_t nwritten = 0, n; + ssize_t n; + + *pnread = 0; veccnt = 0; stream_id = -1; fin = 0; @@ -1780,7 +1747,6 @@ static ssize_t read_pkt_to_send(void *userp, * When ngtcp2 is happy (because it has no other frame that would fit * or it has nothing more to send), it returns the total length * of the assembled packet. This may be 0 if there was nothing to send. */ - *err = CURLE_OK; for(;;) { if(ctx->h3conn && ngtcp2_conn_get_max_data_left(ctx->qconn)) { @@ -1790,8 +1756,7 @@ static ssize_t read_pkt_to_send(void *userp, failf(x->data, "nghttp3_conn_writev_stream returned error: %s", nghttp3_strerror((int)veccnt)); cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt); - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } } @@ -1803,9 +1768,7 @@ static ssize_t read_pkt_to_send(void *userp, (const ngtcp2_vec *)vec, veccnt, x->ts); if(n == 0) { /* nothing to send */ - *err = CURLE_AGAIN; - nwritten = -1; - goto out; + return CURLE_AGAIN; } else if(n < 0) { switch(n) { @@ -1837,9 +1800,7 @@ static ssize_t read_pkt_to_send(void *userp, failf(x->data, "ngtcp2_conn_writev_stream returned error: %s", ngtcp2_strerror((int)n)); cf_ngtcp2_err_set(x->cf, x->data, (int)n); - *err = CURLE_SEND_ERROR; - nwritten = -1; - goto out; + return CURLE_SEND_ERROR; } } @@ -1855,12 +1816,10 @@ static ssize_t read_pkt_to_send(void *userp, if(n > 0) { /* packet assembled, leave */ - nwritten = n; - goto out; + *pnread = (size_t)n; + return CURLE_OK; } } -out: - return nwritten; } static CURLcode cf_progress_egress(struct Curl_cfilter *cf, @@ -1868,7 +1827,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, struct pkt_io_ctx *pktx) { struct cf_ngtcp2_ctx *ctx = cf->ctx; - ssize_t nread; + size_t nread; size_t max_payload_size, path_max_payload_size, max_pktcnt; size_t pktcnt = 0; size_t gsolen = 0; /* this disables gso until we have a clue */ @@ -1893,7 +1852,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, return curlcode; } - /* In UDP, there is a maximum theoretical packet paload length and + /* In UDP, there is a maximum theoretical packet payload length and * a minimum payload length that is "guaranteed" to work. * To detect if this minimum payload can be increased, ngtcp2 sends * now and then a packet payload larger than the minimum. It that @@ -1913,9 +1872,9 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, for(;;) { /* add the next packet to send, if any, to our buffer */ - nread = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, - read_pkt_to_send, pktx, &curlcode); - if(nread < 0) { + curlcode = Curl_bufq_sipn(&ctx->q.sendbuf, max_payload_size, + read_pkt_to_send, pktx, &nread); + if(curlcode) { if(curlcode != CURLE_AGAIN) return curlcode; /* Nothing more to add, flush and leave */ @@ -1934,10 +1893,10 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, if(pktcnt == 0) { /* first packet in buffer. This is either of a known, "good" * payload size or it is a PMTUD. We will see. */ - gsolen = (size_t)nread; + gsolen = nread; } - else if((size_t)nread > gsolen || - (gsolen > path_max_payload_size && (size_t)nread != gsolen)) { + else if(nread > gsolen || + (gsolen > path_max_payload_size && nread != gsolen)) { /* The just added packet is a PMTUD *or* the one(s) before the * just added were PMTUD and the last one is smaller. * Flush the buffer before the last add. */ @@ -1954,7 +1913,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, continue; } - if(++pktcnt >= max_pktcnt || (size_t)nread < gsolen) { + if(++pktcnt >= max_pktcnt || nread < gsolen) { /* Reached MAX_PKT_BURST *or* * the capacity of our buffer *or* * last add was shorter than the previous ones, flush */ @@ -1975,28 +1934,15 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf, return CURLE_OK; } -/* - * Called from transfer.c:data_pending to know if we should keep looping - * to receive more data from the connection. - */ -static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf, - const struct Curl_easy *data) -{ - (void)cf; - (void)data; - return FALSE; -} - static CURLcode h3_data_pause(struct Curl_cfilter *cf, struct Curl_easy *data, bool pause) { /* There seems to exist no API in ngtcp2 to shrink/enlarge the streams * windows. As we do in HTTP/2. */ - if(!pause) { - h3_drain_stream(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } + (void)cf; + if(!pause) + Curl_multi_mark_dirty(data); return CURLE_OK; } @@ -2129,8 +2075,9 @@ static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf, /* Ignore amount written. sendbuf was empty and has always room for * NGTCP2_MAX_UDP_PAYLOAD_SIZE. It can only completely fail, in which * case `result` is set non zero. */ - (void)Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer, - (size_t)nwritten, &result); + size_t n; + result = Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer, + (size_t)nwritten, &n); if(result) { CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, " "aborting shutdown", result); @@ -2702,6 +2649,14 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + if(Curl_vquic_tls_get_ssl_info(&ctx->tls, + (query == CF_QUERY_SSL_INFO), info)) + return CURLE_OK; + break; + } default: break; } @@ -2761,9 +2716,8 @@ struct Curl_cftype Curl_cft_http3 = { cf_ngtcp2_connect, cf_ngtcp2_close, cf_ngtcp2_shutdown, - Curl_cf_def_get_host, cf_ngtcp2_adjust_pollset, - cf_ngtcp2_data_pending, + Curl_cf_def_data_pending, cf_ngtcp2_send, cf_ngtcp2_recv, cf_ngtcp2_data_event, diff --git a/vendor/curl/lib/vquic/curl_ngtcp2.h b/vendor/curl/lib/vquic/curl_ngtcp2.h index 88466252..a4ccef49 100644 --- a/vendor/curl/lib/vquic/curl_ngtcp2.h +++ b/vendor/curl/lib/vquic/curl_ngtcp2.h @@ -52,9 +52,9 @@ struct Curl_cfilter; void Curl_ngtcp2_ver(char *p, size_t len); CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, - struct Curl_easy *data, - struct connectdata *conn, - const struct Curl_addrinfo *ai); + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai); bool Curl_conn_is_ngtcp2(const struct Curl_easy *data, const struct connectdata *conn, diff --git a/vendor/curl/lib/vquic/curl_osslq.c b/vendor/curl/lib/vquic/curl_osslq.c index f942eef8..90fed6c4 100644 --- a/vendor/curl/lib/vquic/curl_osslq.c +++ b/vendor/curl/lib/vquic/curl_osslq.c @@ -37,7 +37,6 @@ #include "../strdup.h" #include "../rand.h" #include "../multiif.h" -#include "../strcase.h" #include "../cfilters.h" #include "../cf-socket.h" #include "../connect.h" @@ -55,6 +54,7 @@ #include "../vtls/vtls.h" #include "../vtls/openssl.h" #include "curl_osslq.h" +#include "../url.h" #include "../curlx/warnless.h" /* The last 3 #include files should be in this order */ @@ -560,7 +560,7 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, } static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data) { struct cf_osslq_ctx *ctx = cf->ctx; @@ -711,31 +711,14 @@ static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf, return NULL; } -static void h3_drain_stream(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_osslq_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - unsigned char bits; - - (void)cf; - bits = CURL_CSELECT_IN; - if(stream && stream->upload_left && !stream->send_closed) - bits |= CURL_CSELECT_OUT; - if(data->state.select_bits != bits) { - data->state.select_bits = bits; - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } -} - static CURLcode h3_data_pause(struct Curl_cfilter *cf, struct Curl_easy *data, bool pause) { + (void)cf; if(!pause) { /* unpaused. make it run again right away */ - h3_drain_stream(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); } return CURLE_OK; } @@ -766,7 +749,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, else { CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->s.id); } - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); return 0; } @@ -783,21 +766,20 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf, struct cf_osslq_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); CURLcode result = CURLE_OK; - ssize_t nwritten; + size_t nwritten; (void)cf; if(!stream) { return CURLE_RECV_ERROR; } - nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); - if(nwritten < 0) { + result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten); + if(result) return result; - } if(!flow) stream->recv_buf_nonflow += (size_t)nwritten; - if((size_t)nwritten < memlen) { + if(nwritten < memlen) { /* This MUST not happen. Our recbuf is dimensioned to hold the * full max_stream_window and then some for this very reason. */ DEBUGASSERT(0); @@ -831,7 +813,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id, stream->download_recvd += (curl_off_t)buflen; CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%" FMT_OFF_T, stream->s.id, buflen, stream->download_recvd); - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); return 0; } @@ -943,7 +925,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid, if(stream->status_code / 100 != 1) { stream->resp_hds_complete = TRUE; } - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); return 0; } @@ -1259,27 +1241,24 @@ struct h3_quic_recv_ctx { struct cf_osslq_stream *s; }; -static ssize_t h3_quic_recv(void *reader_ctx, - unsigned char *buf, size_t len, - CURLcode *err) +static CURLcode h3_quic_recv(void *reader_ctx, + unsigned char *buf, size_t len, + size_t *pnread) { struct h3_quic_recv_ctx *x = reader_ctx; - size_t nread; int rv; - *err = CURLE_OK; - rv = SSL_read_ex(x->s->ssl, buf, len, &nread); + rv = SSL_read_ex(x->s->ssl, buf, len, pnread); if(rv <= 0) { int detail = SSL_get_error(x->s->ssl, rv); if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) { - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } else if(detail == SSL_ERROR_ZERO_RETURN) { CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> EOS", x->s->id); x->s->recvd_eos = TRUE; - return 0; + return CURLE_OK; } else if(SSL_get_stream_read_state(x->s->ssl) == SSL_STREAM_STATE_RESET_REMOTE) { @@ -1292,14 +1271,13 @@ static ssize_t h3_quic_recv(void *reader_ctx, x->s->reset = TRUE; } x->s->recvd_eos = TRUE; - return 0; + return CURLE_OK; } else { - *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR); - return -1; + return cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR); } } - return (ssize_t)nread; + return CURLE_OK; } static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s, @@ -1309,6 +1287,7 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s, struct cf_osslq_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; ssize_t nread; + size_t n; struct h3_quic_recv_ctx x; bool eagain = FALSE; size_t total_recv_len = 0; @@ -1324,8 +1303,8 @@ static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s, (total_recv_len < H3_STREAM_CHUNK_SIZE)) { if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) { while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) { - nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result); - if(nread < 0) { + result = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &n); + if(result) { if(result != CURLE_AGAIN) goto out; result = CURLE_OK; @@ -1566,7 +1545,7 @@ static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf, if(stream) { nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id); stream->s.send_blocked = FALSE; - h3_drain_stream(cf, ctx->curl_items[idx_count]); + Curl_multi_mark_dirty(ctx->curl_items[idx_count]); CURL_TRC_CF(ctx->curl_items[idx_count], cf, "unblocked"); } result_count--; @@ -2009,44 +1988,39 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf, return nwritten; } -static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_osslq_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); struct cf_call_data save; ssize_t nwritten; - CURLcode result; + CURLcode result = CURLE_OK; (void)eos; /* use to end stream */ CF_DATA_SAVE(save, cf, data); DEBUGASSERT(cf->connected); DEBUGASSERT(ctx->tls.ossl.ssl); DEBUGASSERT(ctx->h3.conn); - *err = CURLE_OK; + *pnwritten = 0; result = cf_progress_ingress(cf, data); - if(result) { - *err = result; - nwritten = -1; + if(result) goto out; - } result = cf_progress_egress(cf, data); - if(result) { - *err = result; - nwritten = -1; + if(result) goto out; - } if(!stream || stream->s.id < 0) { - nwritten = h3_stream_open(cf, data, buf, len, err); + nwritten = h3_stream_open(cf, data, buf, len, &result); if(nwritten < 0) { - CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err); + CURL_TRC_CF(data, cf, "failed to open stream -> %d", result); goto out; } stream = H3_STREAM_CTX(ctx, data); + *pnwritten = (size_t)nwritten; } else if(stream->closed) { if(stream->resp_hds_complete) { @@ -2057,56 +2031,48 @@ static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data, * error situation. */ CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data" "on closed stream with response", stream->s.id); - *err = CURLE_OK; - nwritten = (ssize_t)len; + result = CURLE_OK; + *pnwritten = len; goto out; } CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) " "-> stream closed", stream->s.id, len); - *err = CURLE_HTTP3; - nwritten = -1; + result = CURLE_HTTP3; goto out; } else { - nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err); + result = Curl_bufq_write(&stream->sendbuf, buf, len, pnwritten); CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to " - "sendbuf(len=%zu) -> %zd, %d", - stream->s.id, len, nwritten, *err); - if(nwritten < 0) { + "sendbuf(len=%zu) -> %d, %zu", + stream->s.id, len, result, *pnwritten); + if(result) goto out; - } - (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id); } - result = cf_progress_egress(cf, data); - if(result) { - *err = result; - nwritten = -1; - } + result = Curl_1st_err(result, cf_progress_egress(cf, data)); out: - result = check_and_set_expiry(cf, data); - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d", - stream ? stream->s.id : -1, len, nwritten, *err); + result = Curl_1st_err(result, check_and_set_expiry(cf, data)); + + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %d, %zu", + stream ? stream->s.id : -1, len, result, *pnwritten); CF_DATA_RESTORE(cf, save); - return nwritten; + return result; } -static ssize_t recv_closed_stream(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct h3_stream_ctx *stream, - CURLcode *err) +static CURLcode recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h3_stream_ctx *stream, + size_t *pnread) { - ssize_t nread = -1; - (void)cf; + *pnread = 0; if(stream->reset) { failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->s.id); - *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3; - goto out; + return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3; } else if(!stream->resp_hds_complete) { failf(data, @@ -2114,24 +2080,18 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf, " was closed cleanly, but before getting" " all response header fields, treated as error", stream->s.id); - *err = CURLE_HTTP3; - goto out; + return CURLE_HTTP3; } - *err = CURLE_OK; - nread = 0; - -out: - return nread; + return CURLE_OK; } -static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { struct cf_osslq_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nread = -1; struct cf_call_data save; - CURLcode result; + CURLcode result = CURLE_OK; (void)ctx; CF_DATA_SAVE(save, cf, data); @@ -2139,69 +2099,55 @@ static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGASSERT(ctx); DEBUGASSERT(ctx->tls.ossl.ssl); DEBUGASSERT(ctx->h3.conn); - *err = CURLE_OK; + *pnread = 0; if(!stream) { - *err = CURLE_RECV_ERROR; + result = CURLE_RECV_ERROR; goto out; } if(!Curl_bufq_is_empty(&stream->recvbuf)) { - nread = Curl_bufq_read(&stream->recvbuf, - (unsigned char *)buf, len, err); - if(nread < 0) { + result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread); + if(result) { CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) " - "-> %zd, %d", stream->s.id, len, nread, *err); + "-> %d, %zu", stream->s.id, len, result, *pnread); goto out; } } - result = cf_progress_ingress(cf, data); - if(result) { - *err = result; - nread = -1; + result = Curl_1st_err(result, cf_progress_ingress(cf, data)); + if(result) goto out; - } /* recvbuf had nothing before, maybe after progressing ingress? */ - if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) { - nread = Curl_bufq_read(&stream->recvbuf, - (unsigned char *)buf, len, err); - if(nread < 0) { + if(!*pnread && !Curl_bufq_is_empty(&stream->recvbuf)) { + result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread); + if(result) { CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) " - "-> %zd, %d", stream->s.id, len, nread, *err); + "-> %d, %zu", stream->s.id, len, result, *pnread); goto out; } } - if(nread > 0) { - h3_drain_stream(cf, data); + if(*pnread) { + Curl_multi_mark_dirty(data); } else { if(stream->closed) { - nread = recv_closed_stream(cf, data, stream, err); + result = recv_closed_stream(cf, data, stream, pnread); goto out; } - *err = CURLE_AGAIN; - nread = -1; + result = CURLE_AGAIN; } out: - if(cf_progress_egress(cf, data)) { - *err = CURLE_SEND_ERROR; - nread = -1; - } - else { - CURLcode result2 = check_and_set_expiry(cf, data); - if(result2) { - *err = result2; - nread = -1; - } - } - CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d", - stream ? stream->s.id : -1, len, nread, *err); + result = Curl_1st_err(result, cf_progress_egress(cf, data)); + result = Curl_1st_err(result, check_and_set_expiry(cf, data)); + + CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %d, %zu", + stream ? stream->s.id : -1, len, result, *pnread); CF_DATA_RESTORE(cf, save); - return nread; + return result; } /* @@ -2358,8 +2304,9 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, case CF_QUERY_MAX_CONCURRENT: { #ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL /* Added in OpenSSL v3.3.x */ - uint64_t v; - if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC, + uint64_t v = 0; + if(ctx->tls.ossl.ssl && + !SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC, SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) { CURL_TRC_CF(data, cf, "error getting available local bidi streams"); return CURLE_HTTP3; @@ -2370,7 +2317,7 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, #else *pres1 = 100; #endif - CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1); + CURL_TRC_CF(data, cf, "query max_concurrent -> %d", *pres1); return CURLE_OK; } case CF_QUERY_CONNECT_REPLY_MS: @@ -2396,6 +2343,14 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + if(Curl_vquic_tls_get_ssl_info(&ctx->tls, + (query == CF_QUERY_SSL_INFO), info)) + return CURLE_OK; + break; + } default: break; } @@ -2412,7 +2367,6 @@ struct Curl_cftype Curl_cft_http3 = { cf_osslq_connect, cf_osslq_close, cf_osslq_shutdown, - Curl_cf_def_get_host, cf_osslq_adjust_pollset, cf_osslq_data_pending, cf_osslq_send, diff --git a/vendor/curl/lib/vquic/curl_quiche.c b/vendor/curl/lib/vquic/curl_quiche.c index 88065328..920913d2 100644 --- a/vendor/curl/lib/vquic/curl_quiche.c +++ b/vendor/curl/lib/vquic/curl_quiche.c @@ -36,7 +36,6 @@ #include "../sendf.h" #include "../strdup.h" #include "../rand.h" -#include "../strcase.h" #include "../multiif.h" #include "../connect.h" #include "../progress.h" @@ -47,6 +46,7 @@ #include "vquic-tls.h" #include "curl_quiche.h" #include "../transfer.h" +#include "../url.h" #include "../curlx/inet_pton.h" #include "../vtls/openssl.h" #include "../vtls/keylog.h" @@ -237,7 +237,7 @@ static bool cf_quiche_do_resume(struct Curl_cfilter *cf, (void)user_data; if(stream->quic_flow_blocked) { stream->quic_flow_blocked = FALSE; - Curl_expire(sdata, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(sdata); CURL_TRC_CF(sdata, cf, "[%"FMT_PRIu64"] unblock", stream->id); } return TRUE; @@ -250,8 +250,8 @@ static bool cf_quiche_do_expire(struct Curl_cfilter *cf, { (void)stream; (void)user_data; - CURL_TRC_CF(sdata, cf, "conn closed, expire transfer"); - Curl_expire(sdata, 0, EXPIRE_RUN_NOW); + CURL_TRC_CF(sdata, cf, "conn closed, mark as dirty"); + Curl_multi_mark_dirty(sdata); return TRUE; } @@ -307,23 +307,6 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) } } -static void h3_drain_stream(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_quiche_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - unsigned char bits; - - (void)cf; - bits = CURL_CSELECT_IN; - if(stream && !stream->send_closed) - bits |= CURL_CSELECT_OUT; - if(data->state.select_bits != bits) { - data->state.select_bits = bits; - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } -} - static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf, struct Curl_easy *data) { @@ -344,16 +327,16 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf, struct cf_quiche_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); CURLcode result = CURLE_OK; - ssize_t nwritten; + size_t nwritten; (void)cf; if(!stream) return CURLE_RECV_ERROR; - nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result); - if(nwritten < 0) + result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten); + if(result) return result; - if((size_t)nwritten < memlen) { + if(nwritten < memlen) { /* This MUST not happen. Our recbuf is dimensioned to hold the * full max_stream_window and then some for this very reason. */ DEBUGASSERT(0); @@ -407,30 +390,26 @@ static int cb_each_header(uint8_t *name, size_t name_len, return result; } -static ssize_t stream_resp_read(void *reader_ctx, - unsigned char *buf, size_t len, - CURLcode *err) +static CURLcode stream_resp_read(void *reader_ctx, + unsigned char *buf, size_t len, + size_t *pnread) { struct cb_ctx *x = reader_ctx; struct cf_quiche_ctx *ctx = x->cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data); ssize_t nread; - if(!stream) { - *err = CURLE_RECV_ERROR; - return -1; - } + *pnread = 0; + if(!stream) + return CURLE_RECV_ERROR; - nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id, - buf, len); + nread = quiche_h3_recv_body(ctx->h3c, ctx->qconn, stream->id, buf, len); if(nread >= 0) { - *err = CURLE_OK; - return nread; - } - else { - *err = CURLE_AGAIN; - return -1; + *pnread = (size_t)nread; + return CURLE_OK; } + else + return CURLE_AGAIN; } static CURLcode cf_recv_body(struct Curl_cfilter *cf, @@ -438,7 +417,7 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf, { struct cf_quiche_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nwritten; + size_t nread; struct cb_ctx cb_ctx; CURLcode result = CURLE_OK; @@ -454,12 +433,12 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf, cb_ctx.cf = cf; cb_ctx.data = data; - nwritten = Curl_bufq_slurp(&stream->recvbuf, - stream_resp_read, &cb_ctx, &result); + result = Curl_bufq_slurp(&stream->recvbuf, + stream_resp_read, &cb_ctx, &nread); - if(nwritten < 0 && result != CURLE_AGAIN) { - CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zd", - stream->id, nwritten); + if(result && result != CURLE_AGAIN) { + CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zu", + stream->id, nread); failf(data, "Error %d in HTTP/3 response body for stream[%"FMT_PRIu64"]", result, stream->id); stream->closed = TRUE; @@ -562,7 +541,7 @@ static CURLcode cf_quiche_ev_process(struct Curl_cfilter *cf, quiche_h3_event *ev) { CURLcode result = h3_process_event(cf, data, stream, ev); - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); if(result) CURL_TRC_CF(data, cf, "error processing event %s " "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev), @@ -731,27 +710,25 @@ struct read_ctx { quiche_send_info send_info; }; -static ssize_t read_pkt_to_send(void *userp, - unsigned char *buf, size_t buflen, - CURLcode *err) +static CURLcode read_pkt_to_send(void *userp, + unsigned char *buf, size_t buflen, + size_t *pnread) { struct read_ctx *x = userp; struct cf_quiche_ctx *ctx = x->cf->ctx; - ssize_t nwritten; + ssize_t n; - nwritten = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info); - if(nwritten == QUICHE_ERR_DONE) { - *err = CURLE_AGAIN; - return -1; - } + *pnread = 0; + n = quiche_conn_send(ctx->qconn, buf, buflen, &x->send_info); + if(n == QUICHE_ERR_DONE) + return CURLE_AGAIN; - if(nwritten < 0) { - failf(x->data, "quiche_conn_send returned %zd", nwritten); - *err = CURLE_SEND_ERROR; - return -1; + if(n < 0) { + failf(x->data, "quiche_conn_send returned %zd", n); + return CURLE_SEND_ERROR; } - *err = CURLE_OK; - return nwritten; + *pnread = (size_t)n; + return CURLE_OK; } /* @@ -762,7 +739,7 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_quiche_ctx *ctx = cf->ctx; - ssize_t nread; + size_t nread; CURLcode result; curl_int64_t expiry_ns; curl_int64_t timeout_ns; @@ -800,9 +777,9 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, gsolen = quiche_conn_max_send_udp_payload_size(ctx->qconn); for(;;) { /* add the next packet to send, if any, to our buffer */ - nread = Curl_bufq_sipn(&ctx->q.sendbuf, 0, - read_pkt_to_send, &readx, &result); - if(nread < 0) { + result = Curl_bufq_sipn(&ctx->q.sendbuf, 0, + read_pkt_to_send, &readx, &nread); + if(result) { if(result != CURLE_AGAIN) return result; /* Nothing more to add, flush and leave */ @@ -818,7 +795,7 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, } ++pkt_count; - if((size_t)nread < gsolen || pkt_count >= MAX_PKT_BURST) { + if(nread < gsolen || pkt_count >= MAX_PKT_BURST) { result = vquic_send(cf, data, &ctx->q, gsolen); if(result) { if(result == CURLE_AGAIN) { @@ -840,123 +817,105 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf, return result; } -static ssize_t recv_closed_stream(struct Curl_cfilter *cf, - struct Curl_easy *data, - CURLcode *err) +static CURLcode recv_closed_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + size_t *pnread) { struct cf_quiche_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nread = -1; + CURLcode result = CURLE_OK; DEBUGASSERT(stream); + *pnread = 0; if(stream->reset) { failf(data, "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id); - *err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3; + result = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3; CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d", - stream->id, *err); + stream->id, result); } else if(!stream->resp_got_header) { failf(data, "HTTP/3 stream %" FMT_PRIu64 " was closed cleanly, but before " "getting all response header fields, treated as error", stream->id); - /* *err = CURLE_PARTIAL_FILE; */ - *err = CURLE_HTTP3; - CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, closed incomplete" - " -> %d", stream->id, *err); - } - else { - *err = CURLE_OK; - nread = 0; + result = CURLE_HTTP3; } - return nread; + return result; } -static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) +static CURLcode cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { struct cf_quiche_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - ssize_t nread = -1; - CURLcode result; + CURLcode result = CURLE_OK; + *pnread = 0; vquic_ctx_update_time(&ctx->q); - if(!stream) { - *err = CURLE_RECV_ERROR; - return -1; - } + if(!stream) + return CURLE_RECV_ERROR; + if(!Curl_bufq_is_empty(&stream->recvbuf)) { - nread = Curl_bufq_read(&stream->recvbuf, - (unsigned char *)buf, len, err); + result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread); CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) " - "-> %zd, %d", stream->id, len, nread, *err); - if(nread < 0) + "-> %d, %zu", stream->id, len, result, *pnread); + if(result) goto out; } if(cf_process_ingress(cf, data)) { CURL_TRC_CF(data, cf, "cf_recv, error on ingress"); - *err = CURLE_RECV_ERROR; - nread = -1; + result = CURLE_RECV_ERROR; goto out; } /* recvbuf had nothing before, maybe after progressing ingress? */ - if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) { - nread = Curl_bufq_read(&stream->recvbuf, - (unsigned char *)buf, len, err); + if(!*pnread && !Curl_bufq_is_empty(&stream->recvbuf)) { + result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread); CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) " - "-> %zd, %d", stream->id, len, nread, *err); - if(nread < 0) + "-> %d, %zu", stream->id, len, result, *pnread); + if(result) goto out; } - if(nread > 0) { + if(*pnread) { if(stream->closed) - h3_drain_stream(cf, data); + Curl_multi_mark_dirty(data); } else { - if(stream->closed) { - nread = recv_closed_stream(cf, data, err); - goto out; - } + if(stream->closed) + result = recv_closed_stream(cf, data, pnread); else if(quiche_conn_is_draining(ctx->qconn)) { failf(data, "QUIC connection is draining"); - *err = CURLE_HTTP3; - nread = -1; - goto out; + result = CURLE_HTTP3; } - *err = CURLE_AGAIN; - nread = -1; + else + result = CURLE_AGAIN; } out: - result = cf_flush_egress(cf, data); - if(result) { - CURL_TRC_CF(data, cf, "cf_recv, flush egress failed"); - *err = result; - nread = -1; - } - if(nread > 0) - ctx->data_recvd += nread; + result = Curl_1st_err(result, cf_flush_egress(cf, data)); + if(*pnread > 0) + ctx->data_recvd += *pnread; CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] cf_recv(total=%" - FMT_OFF_T ") -> %zd, %d", - stream->id, ctx->data_recvd, nread, *err); - return nread; + FMT_OFF_T ") -> %d, %zu", + stream->id, ctx->data_recvd, result, *pnread); + return result; } -static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct h3_stream_ctx *stream, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_quiche_send_body(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct h3_stream_ctx *stream, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_quiche_ctx *ctx = cf->ctx; ssize_t nwritten; + *pnwritten = 0; nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id, (uint8_t *)CURL_UNCONST(buf), len, eos); if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) { @@ -967,26 +926,22 @@ static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf, "-> window exhausted", stream->id, len); stream->quic_flow_blocked = TRUE; } - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) { CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) " "-> invalid stream state", stream->id, len); - *err = CURLE_HTTP3; - return -1; + return CURLE_HTTP3; } else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) { CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) " "-> exceeds size", stream->id, len); - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } else if(nwritten < 0) { CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) " "-> quiche err %zd", stream->id, len, nwritten); - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } else { if(eos && (len == (size_t)nwritten)) @@ -994,8 +949,8 @@ static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send body(len=%zu, " "eos=%d) -> %zd", stream->id, len, stream->send_closed, nwritten); - *err = CURLE_OK; - return nwritten; + *pnwritten = (size_t)nwritten; + return CURLE_OK; } } @@ -1003,10 +958,10 @@ static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf, field list. */ #define AUTHORITY_DST_IDX 3 -static ssize_t h3_open_stream(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode h3_open_stream(struct Curl_cfilter *cf, + struct Curl_easy *data, + const char *buf, size_t blen, bool eos, + size_t *pnwritten) { struct cf_quiche_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); @@ -1014,13 +969,14 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, curl_int64_t stream3_id; struct dynhds h2_headers; quiche_h3_header *nva = NULL; + CURLcode result = CURLE_OK; ssize_t nwritten; + *pnwritten = 0; if(!stream) { - *err = h3_data_setup(cf, data); - if(*err) { - return -1; - } + result = h3_data_setup(cf, data); + if(result) + return result; stream = H3_STREAM_CTX(ctx, data); DEBUGASSERT(stream); } @@ -1028,7 +984,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); DEBUGASSERT(stream); - nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err); + nwritten = Curl_h1_req_parse_read(&stream->h1, buf, blen, NULL, 0, &result); if(nwritten < 0) goto out; if(!stream->h1.done) { @@ -1037,19 +993,17 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, } DEBUGASSERT(stream->h1.req); - *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); - if(*err) { - nwritten = -1; + result = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data); + if(result) goto out; - } + /* no longer needed */ Curl_h1_req_parse_free(&stream->h1); nheader = Curl_dynhds_count(&h2_headers); nva = malloc(sizeof(quiche_h3_header) * nheader); if(!nva) { - *err = CURLE_OUT_OF_MEMORY; - nwritten = -1; + result = CURLE_OUT_OF_MEMORY; goto out; } @@ -1061,7 +1015,11 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, nva[i].value_len = e->valuelen; } - if(eos && ((size_t)nwritten == len)) + *pnwritten = (size_t)nwritten; + buf += *pnwritten; + blen -= *pnwritten; + + if(eos && !blen) stream->send_closed = TRUE; stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader, @@ -1072,21 +1030,18 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, * exhausted. Which happens frequently and intermittent. */ CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] blocked", stream->id); stream->quic_flow_blocked = TRUE; - *err = CURLE_AGAIN; - nwritten = -1; + result = CURLE_AGAIN; goto out; } else { CURL_TRC_CF(data, cf, "send_request(%s) -> %" FMT_PRIu64, data->state.url, stream3_id); } - *err = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } DEBUGASSERT(!stream->opened); - *err = CURLE_OK; stream->id = stream3_id; stream->opened = TRUE; stream->closed = FALSE; @@ -1102,48 +1057,43 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf, } } - if(nwritten > 0 && ((size_t)nwritten < len)) { - /* after the headers, there was request BODY data */ - size_t hds_len = (size_t)nwritten; - ssize_t bwritten; + if(blen) { /* after the headers, there was request BODY data */ + size_t bwritten; + CURLcode r2 = CURLE_OK; - bwritten = cf_quiche_send_body(cf, data, stream, - buf + hds_len, len - hds_len, eos, err); - if((bwritten < 0) && (CURLE_AGAIN != *err)) { - /* real error, fail */ - nwritten = -1; + r2 = cf_quiche_send_body(cf, data, stream, buf, blen, eos, &bwritten); + if(r2 && (CURLE_AGAIN != r2)) { /* real error, fail */ + result = r2; } else if(bwritten > 0) { - nwritten += bwritten; + *pnwritten += (size_t)bwritten; } } out: free(nva); Curl_dynhds_free(&h2_headers); - return nwritten; + return result; } -static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - CURLcode *err) +static CURLcode cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *buf, size_t len, bool eos, + size_t *pnwritten) { struct cf_quiche_ctx *ctx = cf->ctx; struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); CURLcode result; - ssize_t nwritten; + *pnwritten = 0; vquic_ctx_update_time(&ctx->q); - *err = cf_process_ingress(cf, data); - if(*err) { - nwritten = -1; + result = cf_process_ingress(cf, data); + if(result) goto out; - } if(!stream || !stream->opened) { - nwritten = h3_open_stream(cf, data, buf, len, eos, err); - if(nwritten < 0) + result = h3_open_stream(cf, data, buf, len, eos, pnwritten); + if(result) goto out; stream = H3_STREAM_CTX(ctx, data); } @@ -1159,29 +1109,26 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data, * it would see the response and stop/discard sending on its own- */ CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] discarding data" "on closed stream with response", stream->id); - *err = CURLE_OK; - nwritten = (ssize_t)len; + result = CURLE_OK; + *pnwritten = len; goto out; } CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) " "-> stream closed", stream->id, len); - *err = CURLE_HTTP3; - nwritten = -1; + result = CURLE_HTTP3; goto out; } else { - nwritten = cf_quiche_send_body(cf, data, stream, buf, len, eos, err); + result = cf_quiche_send_body(cf, data, stream, buf, len, eos, pnwritten); } out: - result = cf_flush_egress(cf, data); - if(result) { - *err = result; - nwritten = -1; - } - CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d", - stream ? stream->id : (curl_uint64_t)~0, len, nwritten, *err); - return nwritten; + result = Curl_1st_err(result, cf_flush_egress(cf, data)); + + CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %d, %zu", + stream ? stream->id : (curl_uint64_t)~0, len, + result, *pnwritten); + return result; } static bool stream_is_writeable(struct Curl_cfilter *cf, @@ -1240,9 +1187,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, { /* There seems to exist no API in quiche to shrink/enlarge the streams * windows. As we do in HTTP/2. */ + (void)cf; if(!pause) { - h3_drain_stream(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); } return CURLE_OK; } @@ -1269,13 +1216,13 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); if(stream && !stream->send_closed) { unsigned char body[1]; - ssize_t sent; + size_t sent; stream->send_closed = TRUE; body[0] = 'X'; - sent = cf_quiche_send(cf, data, body, 0, TRUE, &result); - CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %zd, %d", - stream->id, sent, result); + result = cf_quiche_send(cf, data, body, 0, TRUE, &sent); + CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %d, %zu", + stream->id, result, sent); } break; } @@ -1569,7 +1516,7 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, switch(query) { case CF_QUERY_MAX_CONCURRENT: { curl_uint64_t max_streams = CONN_ATTACHED(cf->conn); - if(!ctx->goaway) { + if(!ctx->goaway && ctx->qconn) { max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn); } *pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams; @@ -1601,6 +1548,14 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, case CF_QUERY_HTTP_VERSION: *pres1 = 30; return CURLE_OK; + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + if(Curl_vquic_tls_get_ssl_info(&ctx->tls, + (query == CF_QUERY_SSL_INFO), info)) + return CURLE_OK; + break; + } default: break; } @@ -1654,7 +1609,6 @@ struct Curl_cftype Curl_cft_http3 = { cf_quiche_connect, cf_quiche_close, cf_quiche_shutdown, - Curl_cf_def_get_host, cf_quiche_adjust_pollset, cf_quiche_data_pending, cf_quiche_send, @@ -1707,20 +1661,4 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, return result; } -bool Curl_conn_is_quiche(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex) -{ - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; - - (void)data; - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_http3) - return TRUE; - if(cf->cft->flags & CF_TYPE_IP_CONNECT) - return FALSE; - } - return FALSE; -} - #endif diff --git a/vendor/curl/lib/vquic/curl_quiche.h b/vendor/curl/lib/vquic/curl_quiche.h index 9832687b..b2c76721 100644 --- a/vendor/curl/lib/vquic/curl_quiche.h +++ b/vendor/curl/lib/vquic/curl_quiche.h @@ -41,10 +41,6 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf, struct connectdata *conn, const struct Curl_addrinfo *ai); -bool Curl_conn_is_quiche(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex); - #endif #endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */ diff --git a/vendor/curl/lib/vquic/vquic-tls.c b/vendor/curl/lib/vquic/vquic-tls.c index 2a5be138..8a53c83b 100644 --- a/vendor/curl/lib/vquic/vquic-tls.c +++ b/vendor/curl/lib/vquic/vquic-tls.c @@ -197,4 +197,46 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, } +bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx, + bool give_ssl_ctx, + struct curl_tlssessioninfo *info) +{ +#ifdef USE_OPENSSL + info->backend = CURLSSLBACKEND_OPENSSL; + info->internals = give_ssl_ctx ? + (void *)ctx->ossl.ssl_ctx : (void *)ctx->ossl.ssl; + return TRUE; +#elif defined(USE_GNUTLS) + (void)give_ssl_ctx; /* gnutls always returns its session */ + info->backend = CURLSSLBACKEND_OPENSSL; + info->internals = ctx->gtls.session; + return TRUE; +#elif defined(USE_WOLFSSL) + info->backend = CURLSSLBACKEND_WOLFSSL; + info->internals = give_ssl_ctx ? + (void *)ctx->wssl.ssl_ctx : (void *)ctx->wssl.ssl; + return TRUE; +#else + return FALSE; +#endif +} + +void Curl_vquic_report_handshake(struct curl_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + (void)cf; +#ifdef USE_OPENSSL + (void)cf; + Curl_ossl_report_handshake(data, &ctx->ossl); +#elif defined(USE_GNUTLS) + Curl_gtls_report_handshake(data, &ctx->gtls); +#elif defined(USE_WOLFSSL) + Curl_wssl_report_handshake(data, &ctx->wssl); +#else + (void)data; + (void)ctx; +#endif +} + #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ diff --git a/vendor/curl/lib/vquic/vquic-tls.h b/vendor/curl/lib/vquic/vquic-tls.h index bf29eecc..c694e23e 100644 --- a/vendor/curl/lib/vquic/vquic-tls.h +++ b/vendor/curl/lib/vquic/vquic-tls.h @@ -37,6 +37,7 @@ struct ssl_peer; struct Curl_ssl_session; +struct curl_tlssessioninfo; struct curl_tls_ctx { #ifdef USE_OPENSSL @@ -106,6 +107,14 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, struct Curl_easy *data, struct ssl_peer *peer); +bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx, + bool give_ssl_ctx, + struct curl_tlssessioninfo *info); + +void Curl_vquic_report_handshake(struct curl_tls_ctx *ctx, + struct Curl_cfilter *cf, + struct Curl_easy *data); + #endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */ #endif /* HEADER_CURL_VQUIC_TLS_H */ diff --git a/vendor/curl/lib/vquic/vquic.c b/vendor/curl/lib/vquic/vquic.c index b5dc44f8..691c0d3f 100644 --- a/vendor/curl/lib/vquic/vquic.c +++ b/vendor/curl/lib/vquic/vquic.c @@ -308,7 +308,7 @@ CURLcode vquic_flush(struct Curl_cfilter *cf, struct Curl_easy *data, } CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data, - struct cf_quic_ctx *qctx, size_t gsolen) + struct cf_quic_ctx *qctx, size_t gsolen) { qctx->gsolen = gsolen; return vquic_flush(cf, data, qctx); @@ -703,9 +703,10 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf, } CURLcode Curl_conn_may_http3(struct Curl_easy *data, - const struct connectdata *conn) + const struct connectdata *conn, + unsigned char transport) { - if(conn->transport == TRNSPRT_UNIX) { + if(transport == TRNSPRT_UNIX) { /* cannot do QUIC over a Unix domain socket */ return CURLE_QUIC_CONNECT_ERROR; } @@ -730,10 +731,12 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data, #else /* USE_HTTP3 */ CURLcode Curl_conn_may_http3(struct Curl_easy *data, - const struct connectdata *conn) + const struct connectdata *conn, + unsigned char transport) { (void)conn; (void)data; + (void)transport; DEBUGF(infof(data, "QUIC is not supported in this build")); return CURLE_NOT_BUILT_IN; } diff --git a/vendor/curl/lib/vquic/vquic.h b/vendor/curl/lib/vquic/vquic.h index dbf63b1f..3577a857 100644 --- a/vendor/curl/lib/vquic/vquic.h +++ b/vendor/curl/lib/vquic/vquic.h @@ -54,6 +54,7 @@ extern struct Curl_cftype Curl_cft_http3; #endif /* !USE_HTTP3 */ CURLcode Curl_conn_may_http3(struct Curl_easy *data, - const struct connectdata *conn); + const struct connectdata *conn, + unsigned char transport); #endif /* HEADER_CURL_VQUIC_QUIC_H */ diff --git a/vendor/curl/lib/vquic/vquic_int.h b/vendor/curl/lib/vquic/vquic_int.h index 4641c312..d271368d 100644 --- a/vendor/curl/lib/vquic/vquic_int.h +++ b/vendor/curl/lib/vquic/vquic_int.h @@ -68,7 +68,7 @@ CURLcode vquic_send_blocked_pkts(struct Curl_cfilter *cf, struct cf_quic_ctx *qctx); CURLcode vquic_send(struct Curl_cfilter *cf, struct Curl_easy *data, - struct cf_quic_ctx *qctx, size_t gsolen); + struct cf_quic_ctx *qctx, size_t gsolen); CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data, struct cf_quic_ctx *qctx, size_t gsolen, diff --git a/vendor/curl/lib/vssh/curl_path.c b/vendor/curl/lib/vssh/curl_path.c index 117d2e60..474a5ecb 100644 --- a/vendor/curl/lib/vssh/curl_path.c +++ b/vendor/curl/lib/vssh/curl_path.c @@ -84,6 +84,12 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } } + else { + if(curlx_dyn_add(&npath, "/")) { + free(working_path); + return CURLE_OUT_OF_MEMORY; + } + } } if(curlx_dyn_len(&npath)) { diff --git a/vendor/curl/lib/vssh/libssh.c b/vendor/curl/lib/vssh/libssh.c index 14568e67..3bae943c 100644 --- a/vendor/curl/lib/vssh/libssh.c +++ b/vendor/curl/lib/vssh/libssh.c @@ -58,11 +58,9 @@ #include "../speedcheck.h" #include "../getinfo.h" #include "../strdup.h" -#include "../strcase.h" #include "../vtls/vtls.h" #include "../cfilters.h" #include "../connect.h" -#include "../inet_ntop.h" #include "../parsedate.h" /* for the week day and month names */ #include "../sockaddr.h" /* required for Curl_sockaddr_storage */ #include "../curlx/strparse.h" @@ -71,9 +69,6 @@ #include "../curlx/warnless.h" #include "curl_path.h" -#ifdef HAVE_SYS_STAT_H -#include -#endif #ifdef HAVE_UNISTD_H #include #endif @@ -130,10 +125,6 @@ CURLcode sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done); -static void sftp_quote(struct Curl_easy *data, - struct ssh_conn *sshc, - struct SSHPROTO *sshp); -static void sftp_quote_stat(struct Curl_easy *data, struct ssh_conn *sshc); static int myssh_getsock(struct Curl_easy *data, struct connectdata *conn, curl_socket_t *sock); static void myssh_block2waitfor(struct connectdata *conn, @@ -228,9 +219,9 @@ static CURLcode sftp_error_to_CURLE(int err) } #ifndef DEBUGBUILD -#define myssh_state(x,y,z) myssh_set_state(x,y,z) +#define myssh_to(x,y,z) myssh_set_state(x,y,z) #else -#define myssh_state(x,y,z) myssh_set_state(x,y,z, __LINE__) +#define myssh_to(x,y,z) myssh_set_state(x,y,z, __LINE__) #endif /* @@ -371,7 +362,7 @@ static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) infof(data, "SSH MD5 fingerprint: %s", md5buffer); - if(!strcasecompare(md5buffer, pubkey_md5)) { + if(!curl_strequal(md5buffer, pubkey_md5)) { failf(data, "Denied establishing ssh session: mismatch md5 fingerprint. " "Remote %s is not equal to %s", md5buffer, pubkey_md5); @@ -519,52 +510,302 @@ static int myssh_is_known(struct Curl_easy *data, struct ssh_conn *sshc) return rc; } -#define MOVE_TO_ERROR_STATE(_r) do { \ - myssh_state(data, sshc, SSH_SESSION_DISCONNECT); \ - sshc->actualcode = _r; \ - rc = SSH_ERROR; \ - } while(0) +static int myssh_to_ERROR(struct Curl_easy *data, + struct ssh_conn *sshc, + CURLcode result) +{ + myssh_to(data, sshc, SSH_SESSION_DISCONNECT); + sshc->actualcode = result; + return SSH_ERROR; +} -#define MOVE_TO_SFTP_CLOSE_STATE() do { \ - myssh_state(data, sshc, SSH_SFTP_CLOSE); \ - sshc->actualcode = \ - sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \ - rc = SSH_ERROR; \ - } while(0) +static int myssh_to_SFTP_CLOSE(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->actualcode = + sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); + return SSH_ERROR; +} -#define MOVE_TO_PASSWD_AUTH do { \ - if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \ - rc = SSH_OK; \ - myssh_state(data, sshc, SSH_AUTH_PASS_INIT); \ - } \ - else { \ - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \ - } \ - } while(0) +static int myssh_to_PASSWD_AUTH(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { + myssh_to(data, sshc, SSH_AUTH_PASS_INIT); + return SSH_OK; + } + return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); +} -#define MOVE_TO_KEY_AUTH do { \ - if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \ - rc = SSH_OK; \ - myssh_state(data, sshc, SSH_AUTH_KEY_INIT); \ - } \ - else { \ - MOVE_TO_PASSWD_AUTH; \ - } \ - } while(0) +static int myssh_to_KEY_AUTH(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { + myssh_to(data, sshc, SSH_AUTH_KEY_INIT); + return SSH_OK; + } + return myssh_to_PASSWD_AUTH(data, sshc); +} -#define MOVE_TO_GSSAPI_AUTH do { \ - if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \ - rc = SSH_OK; \ - myssh_state(data, sshc, SSH_AUTH_GSSAPI); \ - } \ - else { \ - MOVE_TO_KEY_AUTH; \ - } \ - } while(0) +static int myssh_to_GSSAPI_AUTH(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { + myssh_to(data, sshc, SSH_AUTH_GSSAPI); + return SSH_OK; + } + return myssh_to_KEY_AUTH(data, sshc); +} -static -int myssh_auth_interactive(struct connectdata *conn, - struct ssh_conn *sshc) +static int myssh_in_SFTP_READDIR_INIT(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + Curl_pgrsSetDownloadSize(data, -1); + if(data->req.no_body) { + myssh_to(data, sshc, SSH_STOP); + return SSH_NO_ERROR; + } + + /* + * This is a directory that we are trying to get, so produce a directory + * listing + */ + sshc->sftp_dir = sftp_opendir(sshc->sftp_session, + sshp->path); + if(!sshc->sftp_dir) { + failf(data, "Could not open directory for reading: %s", + ssh_get_error(sshc->ssh_session)); + return myssh_to_SFTP_CLOSE(data, sshc); + } + myssh_to(data, sshc, SSH_SFTP_READDIR); + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_READDIR(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + CURLcode result = CURLE_OK; + + curlx_dyn_reset(&sshc->readdir_buf); + if(sshc->readdir_attrs) + sftp_attributes_free(sshc->readdir_attrs); + + sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir); + if(sshc->readdir_attrs) { + sshc->readdir_filename = sshc->readdir_attrs->name; + sshc->readdir_longentry = sshc->readdir_attrs->longname; + sshc->readdir_len = strlen(sshc->readdir_filename); + + if(data->set.list_only) { + char *tmpLine; + + tmpLine = aprintf("%s\n", sshc->readdir_filename); + if(!tmpLine) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + return SSH_ERROR; + } + result = Curl_client_write(data, CLIENTWRITE_BODY, + tmpLine, sshc->readdir_len + 1); + free(tmpLine); + + if(result) { + myssh_to(data, sshc, SSH_STOP); + return SSH_NO_ERROR; + } + + } + else { + if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) { + sshc->actualcode = CURLE_OUT_OF_MEMORY; + myssh_to(data, sshc, SSH_STOP); + return SSH_ERROR; + } + + if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && + ((sshc->readdir_attrs->permissions & SSH_S_IFMT) == + SSH_S_IFLNK)) { + sshc->readdir_linkPath = aprintf("%s%s", sshp->path, + sshc->readdir_filename); + + if(!sshc->readdir_linkPath) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + return SSH_ERROR; + } + + myssh_to(data, sshc, SSH_SFTP_READDIR_LINK); + return SSH_NO_ERROR; + } + myssh_to(data, sshc, SSH_SFTP_READDIR_BOTTOM); + return SSH_NO_ERROR; + } + } + else if(sftp_dir_eof(sshc->sftp_dir)) { + myssh_to(data, sshc, SSH_SFTP_READDIR_DONE); + } + else { + failf(data, "Could not open remote directory for reading: %s", + ssh_get_error(sshc->ssh_session)); + return myssh_to_SFTP_CLOSE(data, sshc); + } + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_READDIR_LINK(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->readdir_link_attrs) + sftp_attributes_free(sshc->readdir_link_attrs); + + sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session, + sshc->readdir_linkPath); + if(!sshc->readdir_link_attrs) { + failf(data, "Could not read symlink for reading: %s", + ssh_get_error(sshc->ssh_session)); + return myssh_to_SFTP_CLOSE(data, sshc); + } + + if(!sshc->readdir_link_attrs->name) { + sshc->readdir_tmp = sftp_readlink(sshc->sftp_session, + sshc->readdir_linkPath); + if(!sshc->readdir_tmp) + sshc->readdir_len = 0; + else + sshc->readdir_len = strlen(sshc->readdir_tmp); + sshc->readdir_longentry = NULL; + sshc->readdir_filename = sshc->readdir_tmp; + } + else { + sshc->readdir_len = strlen(sshc->readdir_link_attrs->name); + sshc->readdir_filename = sshc->readdir_link_attrs->name; + sshc->readdir_longentry = sshc->readdir_link_attrs->longname; + } + + Curl_safefree(sshc->readdir_linkPath); + + if(curlx_dyn_addf(&sshc->readdir_buf, " -> %s", + sshc->readdir_filename)) { + /* Not using: + * return myssh_to_SFTP_CLOSE(data, sshc); + * + * as that assumes an sftp related error while + * assigning sshc->actualcode whereas the current + * error is curlx_dyn_addf() related. + */ + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; + return SSH_ERROR; + } + + sftp_attributes_free(sshc->readdir_link_attrs); + sshc->readdir_link_attrs = NULL; + sshc->readdir_filename = NULL; + sshc->readdir_longentry = NULL; + + myssh_to(data, sshc, SSH_SFTP_READDIR_BOTTOM); + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_READDIR_BOTTOM(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + CURLcode result; + + if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1)) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_client_write(data, CLIENTWRITE_BODY, + curlx_dyn_ptr(&sshc->readdir_buf), + curlx_dyn_len(&sshc->readdir_buf)); + + ssh_string_free_char(sshc->readdir_tmp); + sshc->readdir_tmp = NULL; + + if(result) + myssh_to(data, sshc, SSH_STOP); + else + myssh_to(data, sshc, SSH_SFTP_READDIR); + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_READDIR_DONE(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + sftp_closedir(sshc->sftp_dir); + sshc->sftp_dir = NULL; + + /* no data to transfer */ + Curl_xfer_setup_nop(data); + myssh_to(data, sshc, SSH_STOP); + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_QUOTE_STATVFS(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + sftp_statvfs_t statvfs; + + statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1); + if(!statvfs && !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + failf(data, "statvfs command failed: %s", + ssh_get_error(sshc->ssh_session)); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_OK; + } + else if(statvfs) { + #ifdef _MSC_VER + #define CURL_LIBSSH_VFS_SIZE_MASK "I64u" + #else + #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 + #endif + CURLcode result; + char *tmp = aprintf("statvfs:\n" + "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" + "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n", + statvfs->f_bsize, statvfs->f_frsize, + statvfs->f_blocks, statvfs->f_bfree, + statvfs->f_bavail, statvfs->f_files, + statvfs->f_ffree, statvfs->f_favail, + statvfs->f_fsid, statvfs->f_flag, + statvfs->f_namemax); + sftp_statvfs_free(statvfs); + + if(!tmp) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + return SSH_OK; + } + + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + } + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); + return SSH_OK; +} + +static int myssh_auth_interactive(struct connectdata *conn, + struct ssh_conn *sshc) { int rc; int nprompts; @@ -642,11 +883,11 @@ static void myssh_state_init(struct Curl_easy *data, non-blocking */ ssh_set_blocking(sshc->ssh_session, 0); - myssh_state(data, sshc, SSH_S_STARTUP); + myssh_to(data, sshc, SSH_S_STARTUP); } -static int myssh_state_startup(struct Curl_easy *data, - struct ssh_conn *sshc) +static int myssh_in_S_STARTUP(struct Curl_easy *data, + struct ssh_conn *sshc) { struct connectdata *conn = data->conn; int rc = ssh_connect(sshc->ssh_session); @@ -657,16 +898,16 @@ static int myssh_state_startup(struct Curl_easy *data, } else if(rc != SSH_OK) { failf(data, "Failure establishing ssh session"); - MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT); + rc = myssh_to_ERROR(data, sshc, CURLE_FAILED_INIT); } else - myssh_state(data, sshc, SSH_HOSTKEY); + myssh_to(data, sshc, SSH_HOSTKEY); return rc; } -static int myssh_state_authlist(struct Curl_easy *data, - struct ssh_conn *sshc) +static int myssh_in_AUTHLIST(struct Curl_easy *data, + struct ssh_conn *sshc) { int rc; sshc->authed = FALSE; @@ -678,11 +919,11 @@ static int myssh_state_authlist(struct Curl_easy *data, if(rc == SSH_AUTH_SUCCESS) { sshc->authed = TRUE; infof(data, "Authenticated with none"); - myssh_state(data, sshc, SSH_AUTH_DONE); + myssh_to(data, sshc, SSH_AUTH_DONE); return rc; } else if(rc == SSH_AUTH_ERROR) { - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); return rc; } @@ -699,31 +940,31 @@ static int myssh_state_authlist(struct Curl_easy *data, sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD ? "password": ""); if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { - myssh_state(data, sshc, SSH_AUTH_PKEY_INIT); + myssh_to(data, sshc, SSH_AUTH_PKEY_INIT); infof(data, "Authentication using SSH public key file"); } else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { - myssh_state(data, sshc, SSH_AUTH_GSSAPI); + myssh_to(data, sshc, SSH_AUTH_GSSAPI); } else if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { - myssh_state(data, sshc, SSH_AUTH_KEY_INIT); + myssh_to(data, sshc, SSH_AUTH_KEY_INIT); } else if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { - myssh_state(data, sshc, SSH_AUTH_PASS_INIT); + myssh_to(data, sshc, SSH_AUTH_PASS_INIT); } else { /* unsupported authentication method */ - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); } return rc; } -static int myssh_state_auth_pkey_init(struct Curl_easy *data, - struct ssh_conn *sshc) +static int myssh_in_AUTH_PKEY_INIT(struct Curl_easy *data, + struct ssh_conn *sshc) { int rc; if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) { - MOVE_TO_GSSAPI_AUTH; - return 0; + rc = myssh_to_GSSAPI_AUTH(data, sshc); + return rc; } /* Two choices, (1) private key was given on CMD, @@ -736,7 +977,7 @@ static int myssh_state_auth_pkey_init(struct Curl_easy *data, return SSH_AGAIN; if(rc != SSH_OK) { - MOVE_TO_GSSAPI_AUTH; + rc = myssh_to_GSSAPI_AUTH(data, sshc); return rc; } } @@ -748,11 +989,11 @@ static int myssh_state_auth_pkey_init(struct Curl_easy *data, if(rc != SSH_OK) { failf(data, "Could not load private key file %s", data->set.str[STRING_SSH_PRIVATE_KEY]); - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); + rc = myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); return rc; } - myssh_state(data, sshc, SSH_AUTH_PKEY); + myssh_to(data, sshc, SSH_AUTH_PKEY); } else { rc = ssh_userauth_publickey_auto(sshc->ssh_session, NULL, @@ -764,18 +1005,131 @@ static int myssh_state_auth_pkey_init(struct Curl_easy *data, rc = SSH_OK; sshc->authed = TRUE; infof(data, "Completed public key authentication"); - myssh_state(data, sshc, SSH_AUTH_DONE); + myssh_to(data, sshc, SSH_AUTH_DONE); return rc; } - MOVE_TO_GSSAPI_AUTH; + rc = myssh_to_GSSAPI_AUTH(data, sshc); } return rc; } -static int myssh_state_upload_init(struct Curl_easy *data, - struct ssh_conn *sshc, - struct SSHPROTO *sshp) +static int myssh_in_AUTH_PKEY(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + int rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey); + if(rc == SSH_AUTH_AGAIN) + return SSH_AGAIN; + else if(rc == SSH_AUTH_SUCCESS) { + sshc->authed = TRUE; + infof(data, "Completed public key authentication"); + myssh_to(data, sshc, SSH_AUTH_DONE); + return SSH_OK; + } + else { + infof(data, "Failed public key authentication (rc: %d)", rc); + return myssh_to_GSSAPI_AUTH(data, sshc); + } +} + +static int myssh_in_AUTH_GSSAPI(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + int rc; + if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) + return myssh_to_KEY_AUTH(data, sshc); + + rc = ssh_userauth_gssapi(sshc->ssh_session); + if(rc == SSH_AUTH_AGAIN) + return SSH_AGAIN; + + if(rc == SSH_AUTH_SUCCESS) { + sshc->authed = TRUE; + infof(data, "Completed gssapi authentication"); + myssh_to(data, sshc, SSH_AUTH_DONE); + return SSH_OK; + } + + return myssh_to_KEY_AUTH(data, sshc); +} + +static int myssh_in_AUTH_KEY_INIT(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) { + myssh_to(data, sshc, SSH_AUTH_KEY); + return SSH_NO_ERROR; + } + return myssh_to_PASSWD_AUTH(data, sshc); +} + +static int myssh_in_AUTH_KEY(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + /* keyboard-interactive authentication */ + int rc = myssh_auth_interactive(data->conn, sshc); + if(rc == SSH_AGAIN) + return rc; + else if(rc == SSH_OK) { + sshc->authed = TRUE; + infof(data, "completed keyboard interactive authentication"); + myssh_to(data, sshc, SSH_AUTH_DONE); + return SSH_NO_ERROR; + } + else + return myssh_to_PASSWD_AUTH(data, sshc); +} + +static int myssh_in_AUTH_PASS_INIT(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) + return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); + myssh_to(data, sshc, SSH_AUTH_PASS); + return SSH_NO_ERROR; +} + +static int myssh_in_AUTH_PASS(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + int rc = ssh_userauth_password(sshc->ssh_session, NULL, data->conn->passwd); + if(rc == SSH_AUTH_AGAIN) + return SSH_AGAIN; + else if(rc == SSH_AUTH_SUCCESS) { + sshc->authed = TRUE; + infof(data, "Completed password authentication"); + myssh_to(data, sshc, SSH_AUTH_DONE); + return SSH_NO_ERROR; + } + return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); +} + +static int myssh_in_AUTH_DONE(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(!sshc->authed) { + failf(data, "Authentication failure"); + return myssh_to_ERROR(data, sshc, CURLE_LOGIN_DENIED); + } + + /* At this point we have an authenticated ssh session. */ + infof(data, "Authentication complete"); + Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ + data->conn->sockfd = data->conn->sock[FIRSTSOCKET]; + data->conn->writesockfd = CURL_SOCKET_BAD; + + if(data->conn->handler->protocol == CURLPROTO_SFTP) { + myssh_to(data, sshc, SSH_SFTP_INIT); + return SSH_NO_ERROR; + } + infof(data, "SSH CONNECT phase done"); + myssh_to(data, sshc, SSH_STOP); + return SSH_NO_ERROR; +} + +static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) { int flags; int rc = 0; @@ -789,7 +1143,7 @@ static int myssh_state_upload_init(struct Curl_easy *data, curl_off_t size = attrs->size; if(size < 0) { failf(data, "Bad file size (%" FMT_OFF_T ")", size); - MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); + rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); return rc; } data->state.resume_from = attrs->size; @@ -827,11 +1181,11 @@ static int myssh_state_upload_init(struct Curl_easy *data, /* try to create the path remotely */ rc = 0; sshc->secondCreateDirs = 1; - myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_INIT); + myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_INIT); return rc; } else { - MOVE_TO_SFTP_CLOSE_STATE(); + rc = myssh_to_SFTP_CLOSE(data, sshc); return rc; } } @@ -853,7 +1207,7 @@ static int myssh_state_upload_init(struct Curl_easy *data, if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); - MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST); + rc = myssh_to_ERROR(data, sshc, CURLE_FTP_COULDNT_USE_REST); return rc; } /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */ @@ -873,7 +1227,7 @@ static int myssh_state_upload_init(struct Curl_easy *data, /* this checks for greater-than only to make sure that the CURL_READFUNC_ABORT return code still aborts */ failf(data, "Failed to read data"); - MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST); + rc = myssh_to_ERROR(data, sshc, CURLE_FTP_COULDNT_USE_REST); return rc; } } while(passed < data->state.resume_from); @@ -888,7 +1242,7 @@ static int myssh_state_upload_init(struct Curl_easy *data, rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); if(rc) { - MOVE_TO_SFTP_CLOSE_STATE(); + rc = myssh_to_SFTP_CLOSE(data, sshc); return rc; } } @@ -906,24 +1260,39 @@ static int myssh_state_upload_init(struct Curl_easy *data, figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh sftp send function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_OUT; - /* since we do not really wait for anything at this point, we want the - state machine to move on as soon as possible so we set a very short - timeout here */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); + state machine to move on as soon as possible so we mark this as dirty */ + Curl_multi_mark_dirty(data); #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) sshc->sftp_send_state = 0; #endif - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); return rc; } -static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, - struct ssh_conn *sshc) +static int myssh_in_SFTP_DOWNLOAD_INIT(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + /* Work on getting the specified file */ + if(sshc->sftp_file) + sftp_close(sshc->sftp_file); + + sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path, + O_RDONLY, (mode_t)data->set.new_file_perms); + if(!sshc->sftp_file) { + failf(data, "Could not open remote file for reading: %s", + ssh_get_error(sshc->ssh_session)); + + return myssh_to_SFTP_CLOSE(data, sshc); + } + sftp_file_set_nonblocking(sshc->sftp_file); + myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_STAT); + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, + struct ssh_conn *sshc) { curl_off_t size; int rc = 0; @@ -951,7 +1320,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, if(size < 0) { failf(data, "Bad file size (%" FMT_OFF_T ")", size); - MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); + rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); return rc; } if(data->state.use_range) { @@ -961,7 +1330,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, from_t = curlx_str_number(&p, &from, CURL_OFF_T_MAX); if(from_t == STRE_OVERFLOW) { - MOVE_TO_ERROR_STATE(CURLE_RANGE_ERROR); + rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); return rc; } curlx_str_passblanks(&p); @@ -985,7 +1354,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, if(from > size) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", from, size); - MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); + rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); return rc; } if(from > to) { @@ -994,7 +1363,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, } else { if((to - from) == CURL_OFF_T_MAX) { - MOVE_TO_ERROR_STATE(CURLE_RANGE_ERROR); + rc = myssh_to_ERROR(data, sshc, CURLE_RANGE_ERROR); return rc; } size = to - from + 1; @@ -1002,7 +1371,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, rc = sftp_seek64(sshc->sftp_file, from); if(rc) { - MOVE_TO_SFTP_CLOSE_STATE(); + rc = myssh_to_SFTP_CLOSE(data, sshc); return rc; } } @@ -1018,7 +1387,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, if((curl_off_t)size < -data->state.resume_from) { failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", data->state.resume_from, size); - MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); + rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); return rc; } /* download from where? */ @@ -1029,7 +1398,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%" FMT_OFF_T ")", data->state.resume_from, size); - MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME); + rc = myssh_to_ERROR(data, sshc, CURLE_BAD_DOWNLOAD_RESUME); return rc; } } @@ -1041,7 +1410,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, rc = sftp_seek64(sshc->sftp_file, data->state.resume_from); if(rc) { - MOVE_TO_SFTP_CLOSE_STATE(); + rc = myssh_to_SFTP_CLOSE(data, sshc); return rc; } } @@ -1051,7 +1420,7 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, /* no data to transfer */ Curl_xfer_setup_nop(data); infof(data, "File already completely downloaded"); - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); return rc; } Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); @@ -1059,277 +1428,551 @@ static int myssh_state_sftp_dowload_stat(struct Curl_easy *data, /* not set by Curl_xfer_setup to preserve keepon bits */ data->conn->writesockfd = data->conn->sockfd; - /* we want to use the _receiving_ function even when the socket turns - out writableable as the underlying libssh recv function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_IN; - sshc->sftp_recv_state = 0; - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); return rc; } -/* - * ssh_statemach_act() runs the SSH state machine as far as it can without - * blocking and without reaching the end. The data the pointer 'block' points - * to will be set to TRUE if the libssh function returns SSH_AGAIN - * meaning it wants to be called again when the socket is ready - */ -static CURLcode myssh_statemach_act(struct Curl_easy *data, - struct ssh_conn *sshc, - struct SSHPROTO *sshp, - bool *block) +static int myssh_in_SFTP_CLOSE(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) { - CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc = SSH_NO_ERROR, err; - const char *err_msg; - *block = 0; /* we are not blocking by default */ - - do { + if(sshc->sftp_file) { + sftp_close(sshc->sftp_file); + sshc->sftp_file = NULL; + } + Curl_safefree(sshp->path); - switch(sshc->state) { - case SSH_INIT: - myssh_state_init(data, sshc); - FALLTHROUGH(); + DEBUGF(infof(data, "SFTP DONE done")); - case SSH_S_STARTUP: - rc = myssh_state_startup(data, sshc); - if(rc) - break; - FALLTHROUGH(); - case SSH_HOSTKEY: - rc = myssh_is_known(data, sshc); - if(rc != SSH_OK) { - MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION); - break; - } + /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT + After nextstate is executed, the control should come back to + SSH_SFTP_CLOSE to pass the correct result back */ + if(sshc->nextstate != SSH_NO_STATE && + sshc->nextstate != SSH_SFTP_CLOSE) { + myssh_to(data, sshc, sshc->nextstate); + sshc->nextstate = SSH_SFTP_CLOSE; + } + else { + myssh_to(data, sshc, SSH_STOP); + } + return SSH_NO_ERROR; +} - myssh_state(data, sshc, SSH_AUTHLIST); - FALLTHROUGH(); - case SSH_AUTHLIST: - rc = myssh_state_authlist(data, sshc); - break; - case SSH_AUTH_PKEY_INIT: - rc = myssh_state_auth_pkey_init(data, sshc); - break; - case SSH_AUTH_PKEY: - rc = ssh_userauth_publickey(sshc->ssh_session, NULL, sshc->privkey); - if(rc == SSH_AUTH_AGAIN) { - rc = SSH_AGAIN; - break; - } +static int myssh_in_SFTP_SHUTDOWN(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + /* during times we get here due to a broken transfer and then the + sftp_handle might not have been taken down so make sure that is done + before we proceed */ + ssh_set_blocking(sshc->ssh_session, 0); +#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) + if(sshc->sftp_aio) { + sftp_aio_free(sshc->sftp_aio); + sshc->sftp_aio = NULL; + } +#endif - if(rc == SSH_AUTH_SUCCESS) { - sshc->authed = TRUE; - infof(data, "Completed public key authentication"); - myssh_state(data, sshc, SSH_AUTH_DONE); - break; - } - else { - infof(data, "Failed public key authentication (rc: %d)", rc); - MOVE_TO_GSSAPI_AUTH; - } - break; + if(sshc->sftp_file) { + sftp_close(sshc->sftp_file); + sshc->sftp_file = NULL; + } - case SSH_AUTH_GSSAPI: - if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) { - MOVE_TO_KEY_AUTH; - break; - } + if(sshc->sftp_session) { + sftp_free(sshc->sftp_session); + sshc->sftp_session = NULL; + } - rc = ssh_userauth_gssapi(sshc->ssh_session); - if(rc == SSH_AUTH_AGAIN) { - rc = SSH_AGAIN; - break; - } + SSH_STRING_FREE_CHAR(sshc->homedir); - if(rc == SSH_AUTH_SUCCESS) { - rc = SSH_OK; - sshc->authed = TRUE; - infof(data, "Completed gssapi authentication"); - myssh_state(data, sshc, SSH_AUTH_DONE); - break; - } + myssh_to(data, sshc, SSH_SESSION_DISCONNECT); + return SSH_NO_ERROR; +} - MOVE_TO_KEY_AUTH; - break; +static int myssh_in_SFTP_INIT(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + int rc; + ssh_set_blocking(sshc->ssh_session, 1); - case SSH_AUTH_KEY_INIT: - if(data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD) { - myssh_state(data, sshc, SSH_AUTH_KEY); - } - else { - MOVE_TO_PASSWD_AUTH; - } - break; + sshc->sftp_session = sftp_new(sshc->ssh_session); + if(!sshc->sftp_session) { + failf(data, "Failure initializing sftp session: %s", + ssh_get_error(sshc->ssh_session)); + return myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT); + } - case SSH_AUTH_KEY: - /* keyboard-interactive authentication */ - rc = myssh_auth_interactive(conn, sshc); - if(rc == SSH_AGAIN) { - break; - } - if(rc == SSH_OK) { - sshc->authed = TRUE; - infof(data, "completed keyboard interactive authentication"); - myssh_state(data, sshc, SSH_AUTH_DONE); - } - else { - MOVE_TO_PASSWD_AUTH; - } - break; + rc = sftp_init(sshc->sftp_session); + if(rc != SSH_OK) { + failf(data, "Failure initializing sftp session: %s", + ssh_get_error(sshc->ssh_session)); + return myssh_to_ERROR(data, sshc, sftp_error_to_CURLE(SSH_FX_FAILURE)); + } + myssh_to(data, sshc, SSH_SFTP_REALPATH); + return SSH_NO_ERROR; +} - case SSH_AUTH_PASS_INIT: - if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) { - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); - break; - } - myssh_state(data, sshc, SSH_AUTH_PASS); - FALLTHROUGH(); +static int myssh_in_SFTP_REALPATH(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + /* Get the "home" directory */ + sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, "."); + if(!sshc->homedir) + return myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT); + + free(data->state.most_recent_ftp_entrypath); + data->state.most_recent_ftp_entrypath = strdup(sshc->homedir); + if(!data->state.most_recent_ftp_entrypath) + return myssh_to_ERROR(data, sshc, CURLE_OUT_OF_MEMORY); + + /* This is the last step in the SFTP connect phase. Do note that while + we get the homedir here, we get the "workingpath" in the DO action + since the homedir will remain the same between request but the + working path will not. */ + DEBUGF(infof(data, "SSH CONNECT phase done")); + myssh_to(data, sshc, SSH_STOP); + return SSH_NO_ERROR; +} - case SSH_AUTH_PASS: - rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd); - if(rc == SSH_AUTH_AGAIN) { - rc = SSH_AGAIN; - break; - } +static int myssh_in_SFTP_QUOTE_INIT(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + CURLcode result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); + if(result) { + sshc->actualcode = result; + myssh_to(data, sshc, SSH_STOP); + } + else if(data->set.quote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.quote; + myssh_to(data, sshc, SSH_SFTP_QUOTE); + } + else + myssh_to(data, sshc, SSH_SFTP_GETINFO); + return SSH_NO_ERROR; +} - if(rc == SSH_AUTH_SUCCESS) { - sshc->authed = TRUE; - infof(data, "Completed password authentication"); - myssh_state(data, sshc, SSH_AUTH_DONE); - } - else { - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); - } - break; +static int myssh_in_SFTP_POSTQUOTE_INIT(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(data->set.postquote) { + infof(data, "Sending quote commands"); + sshc->quote_item = data->set.postquote; + myssh_to(data, sshc, SSH_SFTP_QUOTE); + } + else { + myssh_to(data, sshc, SSH_STOP); + } + return SSH_NO_ERROR; +} - case SSH_AUTH_DONE: - if(!sshc->authed) { - failf(data, "Authentication failure"); - MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); - break; - } +static int myssh_in_SFTP_QUOTE(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + const char *cp; + CURLcode result; + + /* + * Support some of the "FTP" commands + */ + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + if(curl_strequal("pwd", cmd)) { + /* output debug output if that is requested */ + char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path); + if(!tmp) { + sshc->actualcode = CURLE_OUT_OF_MEMORY; + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + return SSH_NO_ERROR; + } + Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4); + Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp)); + + /* this sends an FTP-like "header" to the header callback so that the + current directory can be read very similar to how it is read when + using ordinary FTP. */ + result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + else + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); + return SSH_NO_ERROR; + } + + /* + * the arguments following the command must be separated from the + * command with a space so we can check for it unconditionally + */ + cp = strchr(cmd, ' '); + if(!cp) { + failf(data, "Syntax error in SFTP command. Supply parameter(s)"); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; + } + + /* + * also, every command takes at least one argument so we get that + * first argument right now + */ + result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error: Bad first parameter"); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return SSH_NO_ERROR; + } - /* - * At this point we have an authenticated ssh session. - */ - infof(data, "Authentication complete"); + /* + * SFTP is a binary protocol, so we do not send text commands + * to the server. Instead, we scan for commands used by + * OpenSSH's sftp program and call the appropriate libssh + * functions. + */ + if(!strncmp(cmd, "chgrp ", 6) || + !strncmp(cmd, "chmod ", 6) || + !strncmp(cmd, "chown ", 6) || + !strncmp(cmd, "atime ", 6) || + !strncmp(cmd, "mtime ", 6)) { + /* attribute change */ + + /* sshc->quote_path1 contains the mode to set */ + /* get the destination */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: " + "Bad second parameter"); + Curl_safefree(sshc->quote_path1); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return SSH_NO_ERROR; + } + sshc->quote_attrs = NULL; + myssh_to(data, sshc, SSH_SFTP_QUOTE_STAT); + return SSH_NO_ERROR; + } + if(!strncmp(cmd, "ln ", 3) || + !strncmp(cmd, "symlink ", 8)) { + /* symbolic linking */ + /* sshc->quote_path1 is the source */ + /* get the destination */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in ln/symlink: Bad second parameter"); + Curl_safefree(sshc->quote_path1); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return SSH_NO_ERROR; + } + myssh_to(data, sshc, SSH_SFTP_QUOTE_SYMLINK); + return SSH_NO_ERROR; + } + else if(!strncmp(cmd, "mkdir ", 6)) { + /* create dir */ + myssh_to(data, sshc, SSH_SFTP_QUOTE_MKDIR); + return SSH_NO_ERROR; + } + else if(!strncmp(cmd, "rename ", 7)) { + /* rename file */ + /* first param is the source path */ + /* second param is the dest. path */ + result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + failf(data, "Out of memory"); + else + failf(data, "Syntax error in rename: Bad second parameter"); + Curl_safefree(sshc->quote_path1); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + return SSH_NO_ERROR; + } + myssh_to(data, sshc, SSH_SFTP_QUOTE_RENAME); + return SSH_NO_ERROR; + } + else if(!strncmp(cmd, "rmdir ", 6)) { + /* delete dir */ + myssh_to(data, sshc, SSH_SFTP_QUOTE_RMDIR); + return SSH_NO_ERROR; + } + else if(!strncmp(cmd, "rm ", 3)) { + myssh_to(data, sshc, SSH_SFTP_QUOTE_UNLINK); + return SSH_NO_ERROR; + } +#ifdef HAS_STATVFS_SUPPORT + else if(!strncmp(cmd, "statvfs ", 8)) { + myssh_to(data, sshc, SSH_SFTP_QUOTE_STATVFS); + return SSH_NO_ERROR; + } +#endif + + failf(data, "Unknown SFTP command"); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_NEXT_QUOTE(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + + sshc->quote_item = sshc->quote_item->next; + + if(sshc->quote_item) { + myssh_to(data, sshc, SSH_SFTP_QUOTE); + } + else { + if(sshc->nextstate != SSH_NO_STATE) { + myssh_to(data, sshc, sshc->nextstate); + sshc->nextstate = SSH_NO_STATE; + } + else { + myssh_to(data, sshc, SSH_SFTP_GETINFO); + } + } + return SSH_NO_ERROR; +} + +static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + char *cmd = sshc->quote_item->data; + sshc->acceptfail = FALSE; + + /* if a command starts with an asterisk, which a legal SFTP command never + can, the command will be allowed to fail without it causing any + aborts or cancels etc. It will cause libcurl to act as if the command + is successful, whatever the server responds. */ + + if(cmd[0] == '*') { + cmd++; + sshc->acceptfail = TRUE; + } + + /* We read the file attributes, store them in sshc->quote_attrs + * and modify them accordingly to command. Then we switch to + * QUOTE_SETSTAT state to write new ones. + */ + + if(sshc->quote_attrs) + sftp_attributes_free(sshc->quote_attrs); + sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2); + if(!sshc->quote_attrs) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Attempt to get SFTP stats failed: %d", + sftp_get_error(sshc->sftp_session)); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; + } + + /* Now set the new attributes... */ + if(!strncmp(cmd, "chgrp", 5)) { + const char *p = sshc->quote_path1; + curl_off_t gid; + (void)curlx_str_number(&p, &gid, UINT_MAX); + sshc->quote_attrs->gid = (uint32_t)gid; + if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chgrp gid not a number"); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; + } + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; + } + else if(!strncmp(cmd, "chmod", 5)) { + curl_off_t perms; + const char *p = sshc->quote_path1; + if(curlx_str_octal(&p, &perms, 07777)) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chmod permissions not a number"); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; + } + sshc->quote_attrs->permissions = (mode_t)perms; + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS; + } + else if(!strncmp(cmd, "chown", 5)) { + const char *p = sshc->quote_path1; + curl_off_t uid; + (void)curlx_str_number(&p, &uid, UINT_MAX); + if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && + !sshc->acceptfail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + failf(data, "Syntax error: chown uid not a number"); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; + } + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; + } + else if(!strncmp(cmd, "atime", 5) || + !strncmp(cmd, "mtime", 5)) { + time_t date = Curl_getdate_capped(sshc->quote_path1); + bool fail = FALSE; + if(date == -1) { + failf(data, "incorrect date format for %.*s", 5, cmd); + fail = TRUE; + } +#if SIZEOF_TIME_T > 4 + else if(date > 0xffffffff) { + failf(data, "date overflow"); + fail = TRUE; /* avoid setting a capped time */ + } +#endif + if(fail) { + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + return SSH_NO_ERROR; + } + if(!strncmp(cmd, "atime", 5)) + sshc->quote_attrs->atime = (uint32_t)date; + else /* mtime */ + sshc->quote_attrs->mtime = (uint32_t)date; - Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME; + } - conn->sockfd = sock; - conn->writesockfd = CURL_SOCKET_BAD; + /* Now send the completed structure... */ + myssh_to(data, sshc, SSH_SFTP_QUOTE_SETSTAT); + return SSH_NO_ERROR; +} - if(conn->handler->protocol == CURLPROTO_SFTP) { - myssh_state(data, sshc, SSH_SFTP_INIT); - break; - } - infof(data, "SSH CONNECT phase done"); - myssh_state(data, sshc, SSH_STOP); - break; +/* + * ssh_statemach_act() runs the SSH state machine as far as it can without + * blocking and without reaching the end. The data the pointer 'block' points + * to will be set to TRUE if the libssh function returns SSH_AGAIN + * meaning it wants to be called again when the socket is ready + */ +static CURLcode myssh_statemach_act(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, + bool *block) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; + int rc = SSH_NO_ERROR, err; + const char *err_msg; - case SSH_SFTP_INIT: - ssh_set_blocking(sshc->ssh_session, 1); + *block = FALSE; /* we are not blocking by default */ + do { - sshc->sftp_session = sftp_new(sshc->ssh_session); - if(!sshc->sftp_session) { - failf(data, "Failure initializing sftp session: %s", - ssh_get_error(sshc->ssh_session)); - MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); + switch(sshc->state) { + case SSH_INIT: + myssh_state_init(data, sshc); + FALLTHROUGH(); + case SSH_S_STARTUP: + rc = myssh_in_S_STARTUP(data, sshc); + if(rc) break; - } - - rc = sftp_init(sshc->sftp_session); + FALLTHROUGH(); + case SSH_HOSTKEY: + rc = myssh_is_known(data, sshc); if(rc != SSH_OK) { - failf(data, "Failure initializing sftp session: %s", - ssh_get_error(sshc->ssh_session)); - MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE)); + rc = myssh_to_ERROR(data, sshc, CURLE_PEER_FAILED_VERIFICATION); break; } - myssh_state(data, sshc, SSH_SFTP_REALPATH); + myssh_to(data, sshc, SSH_AUTHLIST); FALLTHROUGH(); + case SSH_AUTHLIST: + rc = myssh_in_AUTHLIST(data, sshc); + break; + case SSH_AUTH_PKEY_INIT: + rc = myssh_in_AUTH_PKEY_INIT(data, sshc); + break; + case SSH_AUTH_PKEY: + rc = myssh_in_AUTH_PKEY(data, sshc); + break; + case SSH_AUTH_GSSAPI: + rc = myssh_in_AUTH_GSSAPI(data, sshc); + break; + case SSH_AUTH_KEY_INIT: + rc = myssh_in_AUTH_KEY_INIT(data, sshc); + break; + case SSH_AUTH_KEY: + rc = myssh_in_AUTH_KEY(data, sshc); + break; + case SSH_AUTH_PASS_INIT: + rc = myssh_in_AUTH_PASS_INIT(data, sshc); + break; + case SSH_AUTH_PASS: + rc = myssh_in_AUTH_PASS(data, sshc); + break; + case SSH_AUTH_DONE: + rc = myssh_in_AUTH_DONE(data, sshc); + break; + case SSH_SFTP_INIT: + rc = myssh_in_SFTP_INIT(data, sshc); + break; case SSH_SFTP_REALPATH: - /* - * Get the "home" directory - */ - sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, "."); - if(!sshc->homedir) { - MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); - break; - } - free(data->state.most_recent_ftp_entrypath); - data->state.most_recent_ftp_entrypath = strdup(sshc->homedir); - if(!data->state.most_recent_ftp_entrypath) - return CURLE_OUT_OF_MEMORY; - - /* This is the last step in the SFTP connect phase. Do note that while - we get the homedir here, we get the "workingpath" in the DO action - since the homedir will remain the same between request but the - working path will not. */ - DEBUGF(infof(data, "SSH CONNECT phase done")); - myssh_state(data, sshc, SSH_STOP); + rc = myssh_in_SFTP_REALPATH(data, sshc); break; - case SSH_SFTP_QUOTE_INIT: - result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); - if(result) { - sshc->actualcode = result; - myssh_state(data, sshc, SSH_STOP); - break; - } - - if(data->set.quote) { - infof(data, "Sending quote commands"); - sshc->quote_item = data->set.quote; - myssh_state(data, sshc, SSH_SFTP_QUOTE); - } - else { - myssh_state(data, sshc, SSH_SFTP_GETINFO); - } + rc = myssh_in_SFTP_QUOTE_INIT(data, sshc, sshp); break; - case SSH_SFTP_POSTQUOTE_INIT: - if(data->set.postquote) { - infof(data, "Sending quote commands"); - sshc->quote_item = data->set.postquote; - myssh_state(data, sshc, SSH_SFTP_QUOTE); - } - else { - myssh_state(data, sshc, SSH_STOP); - } + rc = myssh_in_SFTP_POSTQUOTE_INIT(data, sshc); break; - case SSH_SFTP_QUOTE: - /* Send any quote commands */ - sftp_quote(data, sshc, sshp); + rc = myssh_in_SFTP_QUOTE(data, sshc, sshp); break; - case SSH_SFTP_NEXT_QUOTE: - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - - sshc->quote_item = sshc->quote_item->next; - - if(sshc->quote_item) { - myssh_state(data, sshc, SSH_SFTP_QUOTE); - } - else { - if(sshc->nextstate != SSH_NO_STATE) { - myssh_state(data, sshc, sshc->nextstate); - sshc->nextstate = SSH_NO_STATE; - } - else { - myssh_state(data, sshc, SSH_SFTP_GETINFO); - } - } + rc = myssh_in_SFTP_NEXT_QUOTE(data, sshc); break; - case SSH_SFTP_QUOTE_STAT: - sftp_quote_stat(data, sshc); + rc = myssh_in_SFTP_QUOTE_STAT(data, sshc); break; case SSH_SFTP_QUOTE_SETSTAT: @@ -1340,7 +1983,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, Curl_safefree(sshc->quote_path2); failf(data, "Attempt to set SFTP stats failed: %s", ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; /* sshc->actualcode = sftp_error_to_CURLE(err); @@ -1348,7 +1991,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, * the error the libssh2 backend is returning */ break; } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_SYMLINK: @@ -1359,12 +2002,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, Curl_safefree(sshc->quote_path2); failf(data, "symlink command failed: %s", ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_MKDIR: @@ -1374,12 +2017,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); failf(data, "mkdir command failed: %s", ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RENAME: @@ -1390,12 +2033,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, Curl_safefree(sshc->quote_path2); failf(data, "rename command failed: %s", ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_RMDIR: @@ -1404,12 +2047,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); failf(data, "rmdir command failed: %s", ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_UNLINK: @@ -1418,84 +2061,28 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, Curl_safefree(sshc->quote_path1); failf(data, "rm command failed: %s", ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + myssh_to(data, sshc, SSH_SFTP_NEXT_QUOTE); break; case SSH_SFTP_QUOTE_STATVFS: - { - sftp_statvfs_t statvfs; - - statvfs = sftp_statvfs(sshc->sftp_session, sshc->quote_path1); - if(!statvfs && !sshc->acceptfail) { - Curl_safefree(sshc->quote_path1); - failf(data, "statvfs command failed: %s", - ssh_get_error(sshc->ssh_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; - } - else if(statvfs) { - #ifdef _MSC_VER - #define CURL_LIBSSH_VFS_SIZE_MASK "I64u" - #else - #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64 - #endif - char *tmp = aprintf("statvfs:\n" - "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n" - "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n", - statvfs->f_bsize, statvfs->f_frsize, - statvfs->f_blocks, statvfs->f_bfree, - statvfs->f_bavail, statvfs->f_files, - statvfs->f_ffree, statvfs->f_favail, - statvfs->f_fsid, statvfs->f_flag, - statvfs->f_namemax); - sftp_statvfs_free(statvfs); - - if(!tmp) { - result = CURLE_OUT_OF_MEMORY; - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - break; - } - - result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); - free(tmp); - if(result) { - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - } - } - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); + rc = myssh_in_SFTP_QUOTE_STATVFS(data, sshc); break; - } case SSH_SFTP_GETINFO: if(data->set.get_filetime) { - myssh_state(data, sshc, SSH_SFTP_FILETIME); + myssh_to(data, sshc, SSH_SFTP_FILETIME); } else { - myssh_state(data, sshc, SSH_SFTP_TRANS_INIT); + myssh_to(data, sshc, SSH_SFTP_TRANS_INIT); } break; - case SSH_SFTP_FILETIME: - { + case SSH_SFTP_FILETIME: { sftp_attributes attrs; attrs = sftp_stat(sshc->sftp_session, sshp->path); @@ -1504,32 +2091,32 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, sftp_attributes_free(attrs); } - myssh_state(data, sshc, SSH_SFTP_TRANS_INIT); + myssh_to(data, sshc, SSH_SFTP_TRANS_INIT); break; } case SSH_SFTP_TRANS_INIT: if(data->state.upload) - myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); + myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); else { if(sshp->path[strlen(sshp->path)-1] == '/') - myssh_state(data, sshc, SSH_SFTP_READDIR_INIT); + myssh_to(data, sshc, SSH_SFTP_READDIR_INIT); else - myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); + myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_INIT); } break; case SSH_SFTP_UPLOAD_INIT: - rc = myssh_state_upload_init(data, sshc, sshp); + rc = myssh_in_UPLOAD_INIT(data, sshc, sshp); break; case SSH_SFTP_CREATE_DIRS_INIT: if(strlen(sshp->path) > 1) { sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */ - myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS); + myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS); } else { - myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); + myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); } break; @@ -1539,10 +2126,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, *sshc->slash_pos = 0; infof(data, "Creating directory '%s'", sshp->path); - myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR); + myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR); break; } - myssh_state(data, sshc, SSH_SFTP_UPLOAD_INIT); + myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); break; case SSH_SFTP_CREATE_DIRS_MKDIR: @@ -1561,254 +2148,47 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, if((err != SSH_FX_FILE_ALREADY_EXISTS) && (err != SSH_FX_FAILURE) && (err != SSH_FX_PERMISSION_DENIED)) { - MOVE_TO_SFTP_CLOSE_STATE(); + rc = myssh_to_SFTP_CLOSE(data, sshc); break; } rc = 0; /* clear rc and continue */ } - myssh_state(data, sshc, SSH_SFTP_CREATE_DIRS); + myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS); break; case SSH_SFTP_READDIR_INIT: - Curl_pgrsSetDownloadSize(data, -1); - if(data->req.no_body) { - myssh_state(data, sshc, SSH_STOP); - break; - } - - /* - * This is a directory that we are trying to get, so produce a directory - * listing - */ - sshc->sftp_dir = sftp_opendir(sshc->sftp_session, - sshp->path); - if(!sshc->sftp_dir) { - failf(data, "Could not open directory for reading: %s", - ssh_get_error(sshc->ssh_session)); - MOVE_TO_SFTP_CLOSE_STATE(); - break; - } - myssh_state(data, sshc, SSH_SFTP_READDIR); + rc = myssh_in_SFTP_READDIR_INIT(data, sshc, sshp); break; - case SSH_SFTP_READDIR: - curlx_dyn_reset(&sshc->readdir_buf); - if(sshc->readdir_attrs) - sftp_attributes_free(sshc->readdir_attrs); - - sshc->readdir_attrs = sftp_readdir(sshc->sftp_session, sshc->sftp_dir); - if(sshc->readdir_attrs) { - sshc->readdir_filename = sshc->readdir_attrs->name; - sshc->readdir_longentry = sshc->readdir_attrs->longname; - sshc->readdir_len = strlen(sshc->readdir_filename); - - if(data->set.list_only) { - char *tmpLine; - - tmpLine = aprintf("%s\n", sshc->readdir_filename); - if(!tmpLine) { - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - result = Curl_client_write(data, CLIENTWRITE_BODY, - tmpLine, sshc->readdir_len + 1); - free(tmpLine); - - if(result) { - myssh_state(data, sshc, SSH_STOP); - break; - } - - } - else { - if(curlx_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) { - sshc->actualcode = CURLE_OUT_OF_MEMORY; - myssh_state(data, sshc, SSH_STOP); - break; - } - - if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && - ((sshc->readdir_attrs->permissions & SSH_S_IFMT) == - SSH_S_IFLNK)) { - sshc->readdir_linkPath = aprintf("%s%s", sshp->path, - sshc->readdir_filename); - - if(!sshc->readdir_linkPath) { - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - - myssh_state(data, sshc, SSH_SFTP_READDIR_LINK); - break; - } - myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM); - break; - } - } - else if(sftp_dir_eof(sshc->sftp_dir)) { - myssh_state(data, sshc, SSH_SFTP_READDIR_DONE); - break; - } - else { - failf(data, "Could not open remote file for reading: %s", - ssh_get_error(sshc->ssh_session)); - MOVE_TO_SFTP_CLOSE_STATE(); - break; - } + rc = myssh_in_SFTP_READDIR(data, sshc, sshp); break; - case SSH_SFTP_READDIR_LINK: - if(sshc->readdir_link_attrs) - sftp_attributes_free(sshc->readdir_link_attrs); - - sshc->readdir_link_attrs = sftp_lstat(sshc->sftp_session, - sshc->readdir_linkPath); - if(sshc->readdir_link_attrs == 0) { - failf(data, "Could not read symlink for reading: %s", - ssh_get_error(sshc->ssh_session)); - MOVE_TO_SFTP_CLOSE_STATE(); - break; - } - - if(!sshc->readdir_link_attrs->name) { - sshc->readdir_tmp = sftp_readlink(sshc->sftp_session, - sshc->readdir_linkPath); - if(!sshc->readdir_filename) - sshc->readdir_len = 0; - else - sshc->readdir_len = strlen(sshc->readdir_tmp); - sshc->readdir_longentry = NULL; - sshc->readdir_filename = sshc->readdir_tmp; - } - else { - sshc->readdir_len = strlen(sshc->readdir_link_attrs->name); - sshc->readdir_filename = sshc->readdir_link_attrs->name; - sshc->readdir_longentry = sshc->readdir_link_attrs->longname; - } - - Curl_safefree(sshc->readdir_linkPath); - - if(curlx_dyn_addf(&sshc->readdir_buf, " -> %s", - sshc->readdir_filename)) { - sshc->actualcode = CURLE_OUT_OF_MEMORY; - break; - } - - sftp_attributes_free(sshc->readdir_link_attrs); - sshc->readdir_link_attrs = NULL; - sshc->readdir_filename = NULL; - sshc->readdir_longentry = NULL; - - myssh_state(data, sshc, SSH_SFTP_READDIR_BOTTOM); - FALLTHROUGH(); + rc = myssh_in_SFTP_READDIR_LINK(data, sshc); + break; case SSH_SFTP_READDIR_BOTTOM: - if(curlx_dyn_addn(&sshc->readdir_buf, "\n", 1)) - result = CURLE_OUT_OF_MEMORY; - else - result = Curl_client_write(data, CLIENTWRITE_BODY, - curlx_dyn_ptr(&sshc->readdir_buf), - curlx_dyn_len(&sshc->readdir_buf)); - - ssh_string_free_char(sshc->readdir_tmp); - sshc->readdir_tmp = NULL; - - if(result) { - myssh_state(data, sshc, SSH_STOP); - } - else - myssh_state(data, sshc, SSH_SFTP_READDIR); + rc = myssh_in_SFTP_READDIR_BOTTOM(data, sshc); break; - case SSH_SFTP_READDIR_DONE: - sftp_closedir(sshc->sftp_dir); - sshc->sftp_dir = NULL; - - /* no data to transfer */ - Curl_xfer_setup_nop(data); - myssh_state(data, sshc, SSH_STOP); + rc = myssh_in_SFTP_READDIR_DONE(data, sshc); break; - case SSH_SFTP_DOWNLOAD_INIT: - /* - * Work on getting the specified file - */ - if(sshc->sftp_file) - sftp_close(sshc->sftp_file); - - sshc->sftp_file = sftp_open(sshc->sftp_session, sshp->path, - O_RDONLY, (mode_t)data->set.new_file_perms); - if(!sshc->sftp_file) { - failf(data, "Could not open remote file for reading: %s", - ssh_get_error(sshc->ssh_session)); - - MOVE_TO_SFTP_CLOSE_STATE(); - break; - } - sftp_file_set_nonblocking(sshc->sftp_file); - myssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); + rc = myssh_in_SFTP_DOWNLOAD_INIT(data, sshc, sshp); break; - case SSH_SFTP_DOWNLOAD_STAT: - rc = myssh_state_sftp_dowload_stat(data, sshc); + rc = myssh_in_SFTP_DOWNLOAD_STAT(data, sshc); break; - case SSH_SFTP_CLOSE: - if(sshc->sftp_file) { - sftp_close(sshc->sftp_file); - sshc->sftp_file = NULL; - } - Curl_safefree(sshp->path); - - DEBUGF(infof(data, "SFTP DONE done")); - - /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT - After nextstate is executed, the control should come back to - SSH_SFTP_CLOSE to pass the correct result back */ - if(sshc->nextstate != SSH_NO_STATE && - sshc->nextstate != SSH_SFTP_CLOSE) { - myssh_state(data, sshc, sshc->nextstate); - sshc->nextstate = SSH_SFTP_CLOSE; - } - else { - myssh_state(data, sshc, SSH_STOP); - result = sshc->actualcode; - } + rc = myssh_in_SFTP_CLOSE(data, sshc, sshp); break; - case SSH_SFTP_SHUTDOWN: - /* during times we get here due to a broken transfer and then the - sftp_handle might not have been taken down so make sure that is done - before we proceed */ - ssh_set_blocking(sshc->ssh_session, 0); -#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) - if(sshc->sftp_aio) { - sftp_aio_free(sshc->sftp_aio); - sshc->sftp_aio = NULL; - } -#endif - - if(sshc->sftp_file) { - sftp_close(sshc->sftp_file); - sshc->sftp_file = NULL; - } - - if(sshc->sftp_session) { - sftp_free(sshc->sftp_session); - sshc->sftp_session = NULL; - } - - SSH_STRING_FREE_CHAR(sshc->homedir); - - myssh_state(data, sshc, SSH_SESSION_DISCONNECT); + rc = myssh_in_SFTP_SHUTDOWN(data, sshc); break; case SSH_SCP_TRANS_INIT: result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); if(result) { sshc->actualcode = result; - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); break; } @@ -1819,26 +2199,25 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, if(data->state.infilesize < 0) { failf(data, "SCP requires a known file size for upload"); sshc->actualcode = CURLE_UPLOAD_FAILED; - MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED); break; } sshc->scp_session = ssh_scp_new(sshc->ssh_session, SSH_SCP_WRITE, sshp->path); - myssh_state(data, sshc, SSH_SCP_UPLOAD_INIT); + myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT); } else { sshc->scp_session = ssh_scp_new(sshc->ssh_session, SSH_SCP_READ, sshp->path); - myssh_state(data, sshc, SSH_SCP_DOWNLOAD_INIT); + myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT); } if(!sshc->scp_session) { err_msg = ssh_get_error(sshc->ssh_session); failf(data, "%s", err_msg); - MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED); } - break; case SSH_SCP_UPLOAD_INIT: @@ -1847,7 +2226,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, if(rc != SSH_OK) { err_msg = ssh_get_error(sshc->ssh_session); failf(data, "%s", err_msg); - MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED); break; } @@ -1858,7 +2237,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, if(rc != SSH_OK) { err_msg = ssh_get_error(sshc->ssh_session); failf(data, "%s", err_msg); - MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED); + rc = myssh_to_ERROR(data, sshc, CURLE_UPLOAD_FAILED); break; } @@ -1872,12 +2251,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh scp send function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_OUT; - - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); break; @@ -1887,20 +2261,20 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, if(rc != SSH_OK) { err_msg = ssh_get_error(sshc->ssh_session); failf(data, "%s", err_msg); - MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT); + rc = myssh_to_ERROR(data, sshc, CURLE_COULDNT_CONNECT); break; } - myssh_state(data, sshc, SSH_SCP_DOWNLOAD); + myssh_to(data, sshc, SSH_SCP_DOWNLOAD); FALLTHROUGH(); - case SSH_SCP_DOWNLOAD:{ + case SSH_SCP_DOWNLOAD: { curl_off_t bytecount; rc = ssh_scp_pull_request(sshc->scp_session); if(rc != SSH_SCP_REQUEST_NEWFILE) { err_msg = ssh_get_error(sshc->ssh_session); failf(data, "%s", err_msg); - MOVE_TO_ERROR_STATE(CURLE_REMOTE_FILE_NOT_FOUND); + rc = myssh_to_ERROR(data, sshc, CURLE_REMOTE_FILE_NOT_FOUND); break; } @@ -1912,19 +2286,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, /* not set by Curl_xfer_setup 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 libssh recv function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_IN; - - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); break; - } + } case SSH_SCP_DONE: if(data->state.upload) - myssh_state(data, sshc, SSH_SCP_SEND_EOF); + myssh_to(data, sshc, SSH_SCP_SEND_EOF); else - myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); + myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_SEND_EOF: @@ -1942,7 +2311,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, } } - myssh_state(data, sshc, SSH_SCP_CHANNEL_FREE); + myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); break; case SSH_SCP_CHANNEL_FREE: @@ -1954,7 +2323,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, ssh_set_blocking(sshc->ssh_session, 0); - myssh_state(data, sshc, SSH_SESSION_DISCONNECT); + myssh_to(data, sshc, SSH_SESSION_DISCONNECT); FALLTHROUGH(); case SSH_SESSION_DISCONNECT: @@ -1985,7 +2354,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, SSH_STRING_FREE_CHAR(sshc->homedir); - myssh_state(data, sshc, SSH_SESSION_FREE); + myssh_to(data, sshc, SSH_SESSION_FREE); FALLTHROUGH(); case SSH_SESSION_FREE: sshc_cleanup(sshc); @@ -1995,14 +2364,14 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, connclose(conn, "SSH session free"); sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); break; case SSH_QUIT: default: /* internal error */ sshc->nextstate = SSH_NO_STATE; - myssh_state(data, sshc, SSH_STOP); + myssh_to(data, sshc, SSH_STOP); break; } @@ -2014,7 +2383,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, right direction too)! */ *block = TRUE; } - + if(!result && (sshc->state == SSH_STOP)) + result = sshc->actualcode; + DEBUGF(infof(data, "SSH: myssh_statemach_act -> %d", result)); return result; } @@ -2284,7 +2655,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) /* we do not verify here, we do it at the state machine, * after connection */ - myssh_state(data, sshc, SSH_INIT); + myssh_to(data, sshc, SSH_INIT); result = myssh_multi_statemach(data, done); @@ -2327,7 +2698,7 @@ CURLcode scp_perform(struct Curl_easy *data, return CURLE_FAILED_INIT; /* start the first command in the DO phase */ - myssh_state(data, sshc, SSH_SCP_TRANS_INIT); + myssh_to(data, sshc, SSH_SCP_TRANS_INIT); result = myssh_multi_statemach(data, dophase_done); @@ -2441,7 +2812,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data, if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ - myssh_state(data, sshc, SSH_SESSION_DISCONNECT); + myssh_to(data, sshc, SSH_SESSION_DISCONNECT); result = myssh_block_statemach(data, sshc, sshp, TRUE); } @@ -2482,24 +2853,25 @@ static CURLcode scp_done(struct Curl_easy *data, CURLcode status, if(!sshc) return CURLE_FAILED_INIT; if(!status) - myssh_state(data, sshc, SSH_SCP_DONE); + myssh_to(data, sshc, SSH_SCP_DONE); return myssh_done(data, sshc, status); } -static ssize_t scp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, CURLcode *err) +static CURLcode scp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { int rc; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + (void) sockindex; /* we only support SCP on the fixed known primary socket */ (void)eos; + *pnwritten = 0; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } + if(!sshc) + return CURLE_FAILED_INIT; rc = ssh_scp_write(sshc->scp_session, mem, len); @@ -2509,32 +2881,30 @@ static ssize_t scp_send(struct Curl_easy *data, int sockindex, * Currently rc can only be number of bytes read or SSH_ERROR. */ myssh_block2waitfor(conn, sshc, (rc == SSH_AGAIN)); - if(rc == SSH_AGAIN) { - *err = CURLE_AGAIN; - return 0; - } + if(rc == SSH_AGAIN) + return CURLE_AGAIN; else #endif - if(rc != SSH_OK) { - *err = CURLE_SSH; - return -1; - } + if(rc != SSH_OK) + return CURLE_SSH; - return len; + *pnwritten = len; + return CURLE_OK; } -static ssize_t scp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, CURLcode *err) +static CURLcode scp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, size_t *pnread) { - ssize_t nread; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + ssize_t nread; + (void) sockindex; /* we only support SCP on the fixed known primary socket */ + *pnread = 0; + + if(!sshc) + return CURLE_FAILED_INIT; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } /* libssh returns int */ nread = ssh_scp_read(sshc->scp_session, mem, len); @@ -2544,13 +2914,11 @@ static ssize_t scp_recv(struct Curl_easy *data, int sockindex, * Currently rc can only be SSH_OK or SSH_ERROR. */ myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN)); - if(nread == SSH_AGAIN) { - *err = CURLE_AGAIN; - nread = -1; - } + if(nread == SSH_AGAIN) + return CURLE_AGAIN; #endif - - return nread; + *pnread = (size_t)nread; + return CURLE_OK; } /* @@ -2581,7 +2949,7 @@ CURLcode sftp_perform(struct Curl_easy *data, return CURLE_FAILED_INIT; /* start the first command in the DO phase */ - myssh_state(data, sshc, SSH_SFTP_QUOTE_INIT); + myssh_to(data, sshc, SSH_SFTP_QUOTE_INIT); /* run the state-machine */ result = myssh_multi_statemach(data, dophase_done); @@ -2622,7 +2990,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ - myssh_state(data, sshc, SSH_SFTP_SHUTDOWN); + myssh_to(data, sshc, SSH_SFTP_SHUTDOWN); result = myssh_block_statemach(data, sshc, sshp, TRUE); } @@ -2644,26 +3012,27 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, operation */ if(!premature && data->set.postquote && !conn->bits.retry) sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT; - myssh_state(data, sshc, SSH_SFTP_CLOSE); + myssh_to(data, sshc, SSH_SFTP_CLOSE); } return myssh_done(data, sshc, status); } /* return number of sent bytes */ -static ssize_t sftp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, - CURLcode *err) +static CURLcode sftp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { - ssize_t nwrite; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + ssize_t nwrite; + (void)sockindex; (void)eos; + *pnwritten = 0; + + if(!sshc) + return CURLE_FAILED_INIT; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } /* limit the writes to the maximum specified in Section 3 of * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02 */ @@ -2675,31 +3044,27 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, sftp_file_set_nonblocking(sshc->sftp_file); if(sftp_aio_begin_write(sshc->sftp_file, mem, len, &sshc->sftp_aio) == SSH_ERROR) { - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } sshc->sftp_send_state = 1; FALLTHROUGH(); case 1: nwrite = sftp_aio_wait_write(&sshc->sftp_aio); myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE); - if(nwrite == SSH_AGAIN) { - *err = CURLE_AGAIN; - return 0; - } - else if(nwrite < 0) { - *err = CURLE_SEND_ERROR; - return -1; - } + if(nwrite == SSH_AGAIN) + return CURLE_AGAIN; + else if(nwrite < 0) + return CURLE_SEND_ERROR; if(sshc->sftp_aio) { sftp_aio_free(sshc->sftp_aio); sshc->sftp_aio = NULL; } sshc->sftp_send_state = 0; - return nwrite; + *pnwritten = (size_t)nwrite; + return CURLE_OK; default: /* we never reach here */ - return -1; + return CURLE_SEND_ERROR; } #else nwrite = sftp_write(sshc->sftp_file, mem, len); @@ -2713,12 +3078,11 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, } else #endif - if(nwrite < 0) { - *err = CURLE_SSH; - nwrite = -1; - } + if(nwrite < 0) + return CURLE_SSH; - return nwrite; + *pnwritten = (size_t)nwrite; + return CURLE_OK; #endif } @@ -2726,28 +3090,26 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex, * Return number of received (decrypted) bytes * or <0 on error */ -static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, CURLcode *err) +static CURLcode sftp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, size_t *pnread) { - ssize_t nread; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + ssize_t nread; + (void)sockindex; + *pnread = 0; DEBUGASSERT(len < CURL_MAX_READ_SIZE); - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } + if(!sshc) + return CURLE_FAILED_INIT; switch(sshc->sftp_recv_state) { case 0: sshc->sftp_file_index = sftp_async_read_begin(sshc->sftp_file, (uint32_t)len); - if(sshc->sftp_file_index < 0) { - *err = CURLE_RECV_ERROR; - return -1; - } + if(sshc->sftp_file_index < 0) + return CURLE_RECV_ERROR; FALLTHROUGH(); case 1: @@ -2757,321 +3119,21 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN)); - if(nread == SSH_AGAIN) { - *err = CURLE_AGAIN; - return -1; - } - else if(nread < 0) { - *err = CURLE_RECV_ERROR; - return -1; - } + if(nread == SSH_AGAIN) + return CURLE_AGAIN; + else if(nread < 0) + return CURLE_RECV_ERROR; sshc->sftp_recv_state = 0; - return nread; + *pnread = (size_t)nread; + return CURLE_OK; default: /* we never reach here */ - return -1; - } -} - -static void sftp_quote(struct Curl_easy *data, - struct ssh_conn *sshc, - struct SSHPROTO *sshp) -{ - const char *cp; - CURLcode result; - - /* - * Support some of the "FTP" commands - */ - char *cmd = sshc->quote_item->data; - sshc->acceptfail = FALSE; - - /* if a command starts with an asterisk, which a legal SFTP command never - can, the command will be allowed to fail without it causing any - aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server responds. */ - - if(cmd[0] == '*') { - cmd++; - sshc->acceptfail = TRUE; - } - - if(strcasecompare("pwd", cmd)) { - /* output debug output if that is requested */ - char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path); - if(!tmp) { - sshc->actualcode = CURLE_OUT_OF_MEMORY; - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - return; - } - Curl_debug(data, CURLINFO_HEADER_OUT, "PWD\n", 4); - Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp)); - - /* this sends an FTP-like "header" to the header callback so that the - current directory can be read very similar to how it is read when - using ordinary FTP. */ - result = Curl_client_write(data, CLIENTWRITE_HEADER, tmp, strlen(tmp)); - free(tmp); - if(result) { - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - } - else - myssh_state(data, sshc, SSH_SFTP_NEXT_QUOTE); - return; - } - - /* - * the arguments following the command must be separated from the - * command with a space so we can check for it unconditionally - */ - cp = strchr(cmd, ' '); - if(!cp) { - failf(data, "Syntax error in SFTP command. Supply parameter(s)"); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; - } - - /* - * also, every command takes at least one argument so we get that - * first argument right now - */ - result = Curl_get_pathname(&cp, &sshc->quote_path1, sshc->homedir); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error: Bad first parameter"); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - return; - } - - /* - * SFTP is a binary protocol, so we do not send text commands - * to the server. Instead, we scan for commands used by - * OpenSSH's sftp program and call the appropriate libssh - * functions. - */ - if(!strncmp(cmd, "chgrp ", 6) || - !strncmp(cmd, "chmod ", 6) || - !strncmp(cmd, "chown ", 6) || - !strncmp(cmd, "atime ", 6) || - !strncmp(cmd, "mtime ", 6)) { - /* attribute change */ - - /* sshc->quote_path1 contains the mode to set */ - /* get the destination */ - result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error in chgrp/chmod/chown/atime/mtime: " - "Bad second parameter"); - Curl_safefree(sshc->quote_path1); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - return; - } - sshc->quote_attrs = NULL; - myssh_state(data, sshc, SSH_SFTP_QUOTE_STAT); - return; - } - if(!strncmp(cmd, "ln ", 3) || - !strncmp(cmd, "symlink ", 8)) { - /* symbolic linking */ - /* sshc->quote_path1 is the source */ - /* get the destination */ - result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error in ln/symlink: Bad second parameter"); - Curl_safefree(sshc->quote_path1); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - return; - } - myssh_state(data, sshc, SSH_SFTP_QUOTE_SYMLINK); - return; - } - else if(!strncmp(cmd, "mkdir ", 6)) { - /* create dir */ - myssh_state(data, sshc, SSH_SFTP_QUOTE_MKDIR); - return; - } - else if(!strncmp(cmd, "rename ", 7)) { - /* rename file */ - /* first param is the source path */ - /* second param is the dest. path */ - result = Curl_get_pathname(&cp, &sshc->quote_path2, sshc->homedir); - if(result) { - if(result == CURLE_OUT_OF_MEMORY) - failf(data, "Out of memory"); - else - failf(data, "Syntax error in rename: Bad second parameter"); - Curl_safefree(sshc->quote_path1); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = result; - return; - } - myssh_state(data, sshc, SSH_SFTP_QUOTE_RENAME); - return; - } - else if(!strncmp(cmd, "rmdir ", 6)) { - /* delete dir */ - myssh_state(data, sshc, SSH_SFTP_QUOTE_RMDIR); - return; - } - else if(!strncmp(cmd, "rm ", 3)) { - myssh_state(data, sshc, SSH_SFTP_QUOTE_UNLINK); - return; - } -#ifdef HAS_STATVFS_SUPPORT - else if(!strncmp(cmd, "statvfs ", 8)) { - myssh_state(data, sshc, SSH_SFTP_QUOTE_STATVFS); - return; + return CURLE_RECV_ERROR; } -#endif - - failf(data, "Unknown SFTP command"); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; } -static void sftp_quote_stat(struct Curl_easy *data, - struct ssh_conn *sshc) -{ - char *cmd = sshc->quote_item->data; - sshc->acceptfail = FALSE; - - /* if a command starts with an asterisk, which a legal SFTP command never - can, the command will be allowed to fail without it causing any - aborts or cancels etc. It will cause libcurl to act as if the command - is successful, whatever the server responds. */ - - if(cmd[0] == '*') { - cmd++; - sshc->acceptfail = TRUE; - } - - /* We read the file attributes, store them in sshc->quote_attrs - * and modify them accordingly to command. Then we switch to - * QUOTE_SETSTAT state to write new ones. - */ - - if(sshc->quote_attrs) - sftp_attributes_free(sshc->quote_attrs); - sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2); - if(!sshc->quote_attrs) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Attempt to get SFTP stats failed: %d", - sftp_get_error(sshc->sftp_session)); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; - } - - /* Now set the new attributes... */ - if(!strncmp(cmd, "chgrp", 5)) { - const char *p = sshc->quote_path1; - curl_off_t gid; - (void)curlx_str_number(&p, &gid, UINT_MAX); - sshc->quote_attrs->gid = (uint32_t)gid; - if(sshc->quote_attrs->gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: chgrp gid not a number"); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; - } - sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; - } - else if(!strncmp(cmd, "chmod", 5)) { - curl_off_t perms; - const char *p = sshc->quote_path1; - if(curlx_str_octal(&p, &perms, 07777)) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: chmod permissions not a number"); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; - } - sshc->quote_attrs->permissions = (mode_t)perms; - sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_PERMISSIONS; - } - else if(!strncmp(cmd, "chown", 5)) { - const char *p = sshc->quote_path1; - curl_off_t uid; - (void)curlx_str_number(&p, &uid, UINT_MAX); - if(sshc->quote_attrs->uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && - !sshc->acceptfail) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: chown uid not a number"); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; - } - sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; - } - else if(!strncmp(cmd, "atime", 5) || - !strncmp(cmd, "mtime", 5)) { - time_t date = Curl_getdate_capped(sshc->quote_path1); - bool fail = FALSE; - if(date == -1) { - failf(data, "incorrect date format for %.*s", 5, cmd); - fail = TRUE; - } -#if SIZEOF_TIME_T > 4 - else if(date > 0xffffffff) { - failf(data, "date overflow"); - fail = TRUE; /* avoid setting a capped time */ - } -#endif - if(fail) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - myssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; - } - if(!strncmp(cmd, "atime", 5)) - sshc->quote_attrs->atime = (uint32_t)date; - else /* mtime */ - sshc->quote_attrs->mtime = (uint32_t)date; - - sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME; - } - - /* Now send the completed structure... */ - myssh_state(data, sshc, SSH_SFTP_QUOTE_SETSTAT); - return; -} CURLcode Curl_ssh_init(void) { diff --git a/vendor/curl/lib/vssh/libssh2.c b/vendor/curl/lib/vssh/libssh2.c index 3e8aade5..d599d3cc 100644 --- a/vendor/curl/lib/vssh/libssh2.c +++ b/vendor/curl/lib/vssh/libssh2.c @@ -61,11 +61,9 @@ #include "../speedcheck.h" #include "../getinfo.h" #include "../strdup.h" -#include "../strcase.h" #include "../vtls/vtls.h" #include "../cfilters.h" #include "../connect.h" -#include "../inet_ntop.h" #include "../parsedate.h" /* for the week day and month names */ #include "../sockaddr.h" /* required for Curl_sockaddr_storage */ #include "../multiif.h" @@ -696,7 +694,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data, /* This does NOT verify the length of 'pubkey_md5' separately, which will make the comparison below fail unless it is exactly 32 characters */ - if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { + if(!fingerprint || !curl_strequal(md5buffer, pubkey_md5)) { if(fingerprint) { failf(data, "Denied establishing ssh session: mismatch md5 fingerprint. " @@ -920,7 +918,7 @@ static CURLcode sftp_quote(struct Curl_easy *data, sshc->acceptfail = TRUE; } - if(strcasecompare("pwd", cmd)) { + if(curl_strequal("pwd", cmd)) { /* output debug output if that is requested */ char *tmp = aprintf("257 \"%s\" is current directory.\n", sshp->path); if(!tmp) @@ -1210,15 +1208,9 @@ sftp_upload_init(struct Curl_easy *data, figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh2 sftp send function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_OUT; - /* since we do not really wait for anything at this point, we want the - state machine to move on as soon as possible so we set a very short - timeout here */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); + state machine to move on as soon as possible so mark this as dirty */ + Curl_multi_mark_dirty(data); myssh_state(data, sshc, SSH_STOP); return CURLE_OK; @@ -1553,10 +1545,6 @@ sftp_download_stat(struct Curl_easy *data, /* not set by Curl_xfer_setup to preserve keepon bits */ data->conn->writesockfd = data->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 */ - data->state.select_bits = CURL_CSELECT_IN; myssh_state(data, sshc, SSH_STOP); return CURLE_OK; @@ -1809,7 +1797,7 @@ static CURLcode ssh_state_auth_host_init(struct Curl_easy *data, } static CURLcode ssh_state_auth_agent_init(struct Curl_easy *data, - struct ssh_conn *sshc) + struct ssh_conn *sshc) { int rc = 0; if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT) @@ -1918,7 +1906,7 @@ static CURLcode ssh_state_auth_key_init(struct Curl_easy *data, } static CURLcode ssh_state_auth_key(struct Curl_easy *data, - struct ssh_conn *sshc) + struct ssh_conn *sshc) { /* Authentication failed. Continue with keyboard-interactive now. */ struct connectdata *conn = data->conn; @@ -2007,7 +1995,7 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, return CURLE_AGAIN; if(rc > 0) { - /* It seems that this string is not always NULL terminated */ + /* It seems that this string is not always null-terminated */ sshp->readdir_filename[rc] = '\0'; free(sshc->homedir); sshc->homedir = strdup(sshp->readdir_filename); @@ -2274,7 +2262,7 @@ static CURLcode ssh_state_sftp_quote_unlink(struct Curl_easy *data, } static CURLcode ssh_state_sftp_quote_statvfs(struct Curl_easy *data, - struct ssh_conn *sshc) + struct ssh_conn *sshc) { LIBSSH2_SFTP_STATVFS statvfs; int rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1, @@ -2477,11 +2465,6 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, /* not set by Curl_xfer_setup to preserve keepon bits */ data->conn->writesockfd = data->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 */ - data->state.select_bits = CURL_CSELECT_IN; - myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } @@ -2524,7 +2507,7 @@ static CURLcode ssh_state_sftp_close(struct Curl_easy *data, } static CURLcode ssh_state_sftp_shutdown(struct Curl_easy *data, - struct ssh_conn *sshc) + struct ssh_conn *sshc) { /* during times we get here due to a broken transfer and then the sftp_handle might not have been taken down so make sure that is done @@ -2635,11 +2618,6 @@ static CURLcode ssh_state_scp_upload_init(struct Curl_easy *data, figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh2 scp send function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_OUT; - myssh_state(data, sshc, SSH_STOP); return CURLE_OK; @@ -3267,7 +3245,6 @@ static CURLcode ssh_setup_connection(struct Curl_easy *data, if(!sshc) return CURLE_OUT_OF_MEMORY; - sshc->initialised = TRUE; if(Curl_conn_meta_set(conn, CURL_META_SSH_CONN, sshc, myssh_conn_dtor)) return CURLE_OUT_OF_MEMORY; @@ -3291,7 +3268,7 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags, void **abstract) { struct Curl_easy *data = (struct Curl_easy *)*abstract; - ssize_t nread; + size_t nread; CURLcode result; struct connectdata *conn = data->conn; Curl_recv *backup = conn->recv[0]; @@ -3312,7 +3289,7 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer, else if(result) return -1; /* generic error */ Curl_debug(data, CURLINFO_DATA_IN, (const char *)buffer, (size_t)nread); - return nread; + return (ssize_t)nread; } static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer, @@ -3611,101 +3588,99 @@ static CURLcode sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data, { int rc; - if(sshc->initialised) { - if(sshc->kh) { - libssh2_knownhost_free(sshc->kh); - sshc->kh = NULL; - } - - if(sshc->ssh_agent) { - rc = libssh2_agent_disconnect(sshc->ssh_agent); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) - return CURLE_AGAIN; + if(sshc->kh) { + libssh2_knownhost_free(sshc->kh); + sshc->kh = NULL; + } - if((rc < 0) && data) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to disconnect from libssh2 agent: %d %s", - rc, err_msg); - } - libssh2_agent_free(sshc->ssh_agent); - sshc->ssh_agent = NULL; + if(sshc->ssh_agent) { + rc = libssh2_agent_disconnect(sshc->ssh_agent); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) + return CURLE_AGAIN; - /* NB: there is no need to free identities, they are part of internal - agent stuff */ - sshc->sshagent_identity = NULL; - sshc->sshagent_prev_identity = NULL; + if((rc < 0) && data) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to disconnect from libssh2 agent: %d %s", + rc, err_msg); } + libssh2_agent_free(sshc->ssh_agent); + sshc->ssh_agent = NULL; - if(sshc->sftp_handle) { - rc = libssh2_sftp_close(sshc->sftp_handle); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) - return CURLE_AGAIN; + /* NB: there is no need to free identities, they are part of internal + agent stuff */ + sshc->sshagent_identity = NULL; + sshc->sshagent_prev_identity = NULL; + } - if((rc < 0) && data) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, - NULL, 0); - infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg); - } - sshc->sftp_handle = NULL; + if(sshc->sftp_handle) { + rc = libssh2_sftp_close(sshc->sftp_handle); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) + return CURLE_AGAIN; + + if((rc < 0) && data) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, + NULL, 0); + infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg); } + sshc->sftp_handle = NULL; + } - if(sshc->ssh_channel) { - rc = libssh2_channel_free(sshc->ssh_channel); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) - return CURLE_AGAIN; + if(sshc->ssh_channel) { + rc = libssh2_channel_free(sshc->ssh_channel); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) + return CURLE_AGAIN; - if((rc < 0) && data) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to free libssh2 scp subsystem: %d %s", - rc, err_msg); - } - sshc->ssh_channel = NULL; + if((rc < 0) && data) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 scp subsystem: %d %s", + rc, err_msg); } + sshc->ssh_channel = NULL; + } - if(sshc->sftp_session) { - rc = libssh2_sftp_shutdown(sshc->sftp_session); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) - return CURLE_AGAIN; + if(sshc->sftp_session) { + rc = libssh2_sftp_shutdown(sshc->sftp_session); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) + return CURLE_AGAIN; - if((rc < 0) && data) - infof(data, "Failed to stop libssh2 sftp subsystem"); - sshc->sftp_session = NULL; - } + if((rc < 0) && data) + infof(data, "Failed to stop libssh2 sftp subsystem"); + sshc->sftp_session = NULL; + } - if(sshc->ssh_session) { - rc = libssh2_session_free(sshc->ssh_session); - if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) - return CURLE_AGAIN; + if(sshc->ssh_session) { + rc = libssh2_session_free(sshc->ssh_session); + if(!block && (rc == LIBSSH2_ERROR_EAGAIN)) + return CURLE_AGAIN; - if((rc < 0) && data) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg); - } - sshc->ssh_session = NULL; + if((rc < 0) && data) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg); } + sshc->ssh_session = NULL; + } - /* worst-case scenario cleanup */ - DEBUGASSERT(sshc->ssh_session == NULL); - DEBUGASSERT(sshc->ssh_channel == NULL); - DEBUGASSERT(sshc->sftp_session == NULL); - DEBUGASSERT(sshc->sftp_handle == NULL); - DEBUGASSERT(sshc->kh == NULL); - DEBUGASSERT(sshc->ssh_agent == NULL); + /* worst-case scenario cleanup */ + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->ssh_channel == NULL); + DEBUGASSERT(sshc->sftp_session == NULL); + DEBUGASSERT(sshc->sftp_handle == NULL); + DEBUGASSERT(sshc->kh == NULL); + DEBUGASSERT(sshc->ssh_agent == NULL); + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + Curl_safefree(sshc->homedir); - Curl_safefree(sshc->rsa_pub); - Curl_safefree(sshc->rsa); - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - Curl_safefree(sshc->homedir); - sshc->initialised = FALSE; - } return CURLE_OK; } @@ -3770,58 +3745,63 @@ static CURLcode scp_done(struct Curl_easy *data, CURLcode status, return ssh_done(data, status); } -static ssize_t scp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, CURLcode *err) +static CURLcode scp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { - ssize_t nwrite; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + CURLcode result = CURLE_OK; + ssize_t nwritten; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)eos; + *pnwritten = 0; + + if(!sshc) + return CURLE_FAILED_INIT; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } /* libssh2_channel_write() returns int! */ - nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len); + nwritten = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len); - ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN)); + ssh_block2waitfor(data, sshc, (nwritten == LIBSSH2_ERROR_EAGAIN)); - if(nwrite == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nwrite = 0; - } - else if(nwrite < LIBSSH2_ERROR_NONE) { - *err = libssh2_session_error_to_CURLE((int)nwrite); - nwrite = -1; - } + if(nwritten == LIBSSH2_ERROR_EAGAIN) + result = CURLE_AGAIN; + else if(nwritten < LIBSSH2_ERROR_NONE) + result = libssh2_session_error_to_CURLE((int)nwritten); + else + *pnwritten = (size_t)nwritten; - return nwrite; + return result; } -static ssize_t scp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, CURLcode *err) +static CURLcode scp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, size_t *pnread) { - ssize_t nread; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + CURLcode result = CURLE_OK; + ssize_t nread; + (void)sockindex; /* we only support SCP on the fixed known primary socket */ + *pnread = 0; + + if(!sshc) + return CURLE_FAILED_INIT; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } /* libssh2_channel_read() returns int */ nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len); ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN)); - if(nread == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nread = -1; - } + if(nread == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + else if(nread < LIBSSH2_ERROR_NONE) + result = libssh2_session_error_to_CURLE((int)nread); + else + *pnread = (size_t)nread; - return nread; + return result; } /* @@ -3906,7 +3886,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, } static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, - bool premature) + bool premature) { struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); @@ -3926,64 +3906,61 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status, } /* return number of sent bytes */ -static ssize_t sftp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, CURLcode *err) +static CURLcode sftp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { - ssize_t nwrite; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + ssize_t nwrite; + (void)sockindex; (void)eos; + *pnwritten = 0; + + if(!sshc) + return CURLE_FAILED_INIT; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len); ssh_block2waitfor(data, sshc, (nwrite == LIBSSH2_ERROR_EAGAIN)); - if(nwrite == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nwrite = 0; - } - else if(nwrite < LIBSSH2_ERROR_NONE) { - *err = libssh2_session_error_to_CURLE((int)nwrite); - nwrite = -1; - } - - return nwrite; + if(nwrite == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + else if(nwrite < LIBSSH2_ERROR_NONE) + return libssh2_session_error_to_CURLE((int)nwrite); + *pnwritten = (size_t)nwrite; + return CURLE_OK; } /* * Return number of received (decrypted) bytes * or <0 on error */ -static ssize_t sftp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, CURLcode *err) +static CURLcode sftp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, size_t *pnread) { - ssize_t nread; struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); + ssize_t nread; + (void)sockindex; + *pnread = 0; + + if(!sshc) + return CURLE_FAILED_INIT; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } nread = libssh2_sftp_read(sshc->sftp_handle, mem, len); ssh_block2waitfor(data, sshc, (nread == LIBSSH2_ERROR_EAGAIN)); - if(nread == LIBSSH2_ERROR_EAGAIN) { - *err = CURLE_AGAIN; - nread = -1; + if(nread == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + else if(nread < 0) + return libssh2_session_error_to_CURLE((int)nread); - } - else if(nread < 0) { - *err = libssh2_session_error_to_CURLE((int)nread); - } - return nread; + *pnread = (size_t)nread; + return CURLE_OK; } static const char *sftp_libssh2_strerror(unsigned long err) diff --git a/vendor/curl/lib/vssh/ssh.h b/vendor/curl/lib/vssh/ssh.h index feee8865..4056c39b 100644 --- a/vendor/curl/lib/vssh/ssh.h +++ b/vendor/curl/lib/vssh/ssh.h @@ -191,6 +191,7 @@ struct ssh_conn { const char *readdir_filename; /* points within readdir_attrs */ const char *readdir_longentry; char *readdir_tmp; + BIT(initialised); #elif defined(USE_LIBSSH2) LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ @@ -214,8 +215,8 @@ struct ssh_conn { word32 handleSz; byte handle[WOLFSSH_MAX_HANDLE]; curl_off_t offset; -#endif /* USE_LIBSSH */ BIT(initialised); +#endif /* USE_LIBSSH */ BIT(authed); /* the connection has been authenticated fine */ BIT(acceptfail); /* used by the SFTP_QUOTE (continue if quote command fails) */ diff --git a/vendor/curl/lib/vssh/wolfssh.c b/vendor/curl/lib/vssh/wolfssh.c index 5097ca02..eed73fd9 100644 --- a/vendor/curl/lib/vssh/wolfssh.c +++ b/vendor/curl/lib/vssh/wolfssh.c @@ -220,37 +220,35 @@ static void wssh_state(struct Curl_easy *data, sshc->state = nowstate; } -static ssize_t wscp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, - CURLcode *err) +static CURLcode wscp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { - ssize_t nwrite = 0; (void)data; (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)mem; (void)len; (void)eos; - (void)err; - - return nwrite; + *pnwritten = 0; + return CURLE_OK; } -static ssize_t wscp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, CURLcode *err) +static CURLcode wscp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, size_t *pnread) { - ssize_t nread = 0; (void)data; (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)mem; (void)len; - (void)err; + *pnread = 0; - return nread; + return CURLE_OK; } /* return number of sent bytes */ -static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, - const void *mem, size_t len, bool eos, CURLcode *err) +static CURLcode wsftp_send(struct Curl_easy *data, int sockindex, + const void *mem, size_t len, bool eos, + size_t *pnwritten) { struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); @@ -259,10 +257,10 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, (void)sockindex; (void)eos; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } + *pnwritten = 0; + if(!sshc) + return CURLE_FAILED_INIT; + offset[0] = (word32)sshc->offset & 0xFFFFFFFF; offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; @@ -275,31 +273,30 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex, rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { conn->waitfor = KEEP_RECV; - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } else if(rc == WS_WANT_WRITE) { conn->waitfor = KEEP_SEND; - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } if(rc < 0) { failf(data, "wolfSSH_SFTP_SendWritePacket returned %d", rc); - return -1; + return CURLE_SEND_ERROR; } DEBUGASSERT(rc == (int)len); + *pnwritten = (size_t)rc; + sshc->offset += *pnwritten; infof(data, "sent %zu bytes SFTP from offset %" FMT_OFF_T, - len, sshc->offset); - sshc->offset += len; - return (ssize_t)rc; + *pnwritten, sshc->offset); + return CURLE_OK; } /* * Return number of received (decrypted) bytes * or <0 on error */ -static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, - char *mem, size_t len, CURLcode *err) +static CURLcode wsftp_recv(struct Curl_easy *data, int sockindex, + char *mem, size_t len, size_t *pnread) { int rc; struct connectdata *conn = data->conn; @@ -307,10 +304,10 @@ static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, word32 offset[2]; (void)sockindex; - if(!sshc) { - *err = CURLE_FAILED_INIT; - return -1; - } + *pnread = 0; + if(!sshc) + return CURLE_FAILED_INIT; + offset[0] = (word32)sshc->offset & 0xFFFFFFFF; offset[1] = (word32)(sshc->offset >> 32) & 0xFFFFFFFF; @@ -322,24 +319,22 @@ static ssize_t wsftp_recv(struct Curl_easy *data, int sockindex, rc = wolfSSH_get_error(sshc->ssh_session); if(rc == WS_WANT_READ) { conn->waitfor = KEEP_RECV; - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } else if(rc == WS_WANT_WRITE) { conn->waitfor = KEEP_SEND; - *err = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } DEBUGASSERT(rc <= (int)len); if(rc < 0) { failf(data, "wolfSSH_SFTP_SendReadPacket returned %d", rc); - return -1; + return CURLE_RECV_ERROR; } - sshc->offset += len; - - return (ssize_t)rc; + *pnread = (size_t)rc; + sshc->offset += *pnread; + return CURLE_OK; } static void wssh_easy_dtor(void *key, size_t klen, void *entry) @@ -737,15 +732,9 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, figure out a "real" bitmask */ sshc->orig_waitfor = data->req.keepon; - /* we want to use the _sending_ function even when the socket turns - out readable as the underlying libssh2 sftp send function will deal - with both accordingly */ - data->state.select_bits = CURL_CSELECT_OUT; - /* since we do not really wait for anything at this point, we want the - state machine to move on as soon as possible so we set a very short - timeout here */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); + state machine to move on as soon as possible */ + Curl_multi_mark_dirty(data); wssh_state(data, sshc, SSH_STOP); } @@ -833,11 +822,6 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, /* not set by Curl_xfer_setup 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 */ - data->state.select_bits = CURL_CSELECT_IN; - if(result) { /* this should never occur; the close state should be entered at the time the error occurs */ @@ -1123,7 +1107,7 @@ static void wssh_sshc_cleanup(struct ssh_conn *sshc) #if 0 static CURLcode wscp_done(struct Curl_easy *data, - CURLcode code, bool premature) + CURLcode code, bool premature) { CURLcode result = CURLE_OK; (void)conn; @@ -1134,7 +1118,7 @@ static CURLcode wscp_done(struct Curl_easy *data, } static CURLcode wscp_doing(struct Curl_easy *data, - bool *dophase_done) + bool *dophase_done) { CURLcode result = CURLE_OK; (void)conn; @@ -1156,7 +1140,7 @@ static CURLcode wscp_disconnect(struct Curl_easy *data, #endif static CURLcode wsftp_done(struct Curl_easy *data, - CURLcode code, bool premature) + CURLcode code, bool premature) { struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); (void)premature; @@ -1169,7 +1153,7 @@ static CURLcode wsftp_done(struct Curl_easy *data, } static CURLcode wsftp_doing(struct Curl_easy *data, - bool *dophase_done) + bool *dophase_done) { CURLcode result = wssh_multi_statemach(data, dophase_done); diff --git a/vendor/curl/lib/vtls/bearssl.c b/vendor/curl/lib/vtls/bearssl.c deleted file mode 100644 index 4b652444..00000000 --- a/vendor/curl/lib/vtls/bearssl.c +++ /dev/null @@ -1,1104 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Michael Forney, - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ -#include "../curl_setup.h" - -#ifdef USE_BEARSSL - -#include - -#include "bearssl.h" -#include "cipher_suite.h" -#include "../urldata.h" -#include "../sendf.h" -#include "../curlx/inet_pton.h" -#include "vtls.h" -#include "vtls_int.h" -#include "vtls_scache.h" -#include "../connect.h" -#include "../select.h" -#include "../multiif.h" -#include "../curl_printf.h" - -/* The last #include files should be: */ -#include "../curl_memory.h" -#include "../memdebug.h" - -struct x509_context { - const br_x509_class *vtable; - br_x509_minimal_context minimal; - br_x509_decoder_context decoder; - bool verifyhost; - bool verifypeer; - int cert_num; -}; - -struct bearssl_ssl_backend_data { - br_ssl_client_context ctx; - struct x509_context x509; - unsigned char buf[BR_SSL_BUFSIZE_BIDI]; - br_x509_trust_anchor *anchors; - size_t anchors_len; - const char *protocols[ALPN_ENTRIES_MAX]; - /* SSL client context is active */ - bool active; - /* size of pending write, yet to be flushed */ - size_t pending_write; - BIT(sent_shutdown); -}; - -struct cafile_parser { - CURLcode err; - bool in_cert; - br_x509_decoder_context xc; - /* array of trust anchors loaded from CAfile */ - br_x509_trust_anchor *anchors; - size_t anchors_len; - /* buffer for DN data */ - unsigned char dn[1024]; - size_t dn_len; -}; - -#define CAFILE_SOURCE_PATH 1 -#define CAFILE_SOURCE_BLOB 2 -struct cafile_source { - int type; - const char *data; - size_t len; -}; - -static void append_dn(void *ctx, const void *buf, size_t len) -{ - struct cafile_parser *ca = ctx; - - if(ca->err != CURLE_OK || !ca->in_cert) - return; - if(sizeof(ca->dn) - ca->dn_len < len) { - ca->err = CURLE_FAILED_INIT; - return; - } - memcpy(ca->dn + ca->dn_len, buf, len); - ca->dn_len += len; -} - -static void x509_push(void *ctx, const void *buf, size_t len) -{ - struct cafile_parser *ca = ctx; - - if(ca->in_cert) - br_x509_decoder_push(&ca->xc, buf, len); -} - -static CURLcode load_cafile(struct cafile_source *source, - br_x509_trust_anchor **anchors, - size_t *anchors_len) -{ - struct cafile_parser ca; - br_pem_decoder_context pc; - br_x509_trust_anchor *ta; - size_t ta_size; - br_x509_trust_anchor *new_anchors; - size_t new_anchors_len; - br_x509_pkey *pkey; - FILE *fp = 0; - unsigned char buf[BUFSIZ]; - const unsigned char *p = NULL; - const char *name; - size_t n = 0, i, pushed; - - DEBUGASSERT(source->type == CAFILE_SOURCE_PATH - || source->type == CAFILE_SOURCE_BLOB); - - if(source->type == CAFILE_SOURCE_PATH) { - fp = fopen(source->data, "rb"); - if(!fp) - return CURLE_SSL_CACERT_BADFILE; - } - - if(source->type == CAFILE_SOURCE_BLOB && source->len > (size_t)INT_MAX) - return CURLE_SSL_CACERT_BADFILE; - - ca.err = CURLE_OK; - ca.in_cert = FALSE; - ca.anchors = NULL; - ca.anchors_len = 0; - br_pem_decoder_init(&pc); - br_pem_decoder_setdest(&pc, x509_push, &ca); - do { - if(source->type == CAFILE_SOURCE_PATH) { - n = fread(buf, 1, sizeof(buf), fp); - if(n == 0) - break; - p = buf; - } - else if(source->type == CAFILE_SOURCE_BLOB) { - n = source->len; - p = (const unsigned char *) source->data; - } - while(n) { - pushed = br_pem_decoder_push(&pc, p, n); - if(ca.err) - goto fail; - p += pushed; - n -= pushed; - - switch(br_pem_decoder_event(&pc)) { - case 0: - break; - case BR_PEM_BEGIN_OBJ: - name = br_pem_decoder_name(&pc); - if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE")) - break; - br_x509_decoder_init(&ca.xc, append_dn, &ca); - ca.in_cert = TRUE; - ca.dn_len = 0; - break; - case BR_PEM_END_OBJ: - if(!ca.in_cert) - break; - ca.in_cert = FALSE; - if(br_x509_decoder_last_error(&ca.xc)) { - ca.err = CURLE_SSL_CACERT_BADFILE; - goto fail; - } - /* add trust anchor */ - if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) { - ca.err = CURLE_OUT_OF_MEMORY; - goto fail; - } - new_anchors_len = ca.anchors_len + 1; - new_anchors = realloc(ca.anchors, - new_anchors_len * sizeof(ca.anchors[0])); - if(!new_anchors) { - ca.err = CURLE_OUT_OF_MEMORY; - goto fail; - } - ca.anchors = new_anchors; - ca.anchors_len = new_anchors_len; - ta = &ca.anchors[ca.anchors_len - 1]; - ta->dn.data = NULL; - ta->flags = 0; - if(br_x509_decoder_isCA(&ca.xc)) - ta->flags |= BR_X509_TA_CA; - pkey = br_x509_decoder_get_pkey(&ca.xc); - if(!pkey) { - ca.err = CURLE_SSL_CACERT_BADFILE; - goto fail; - } - ta->pkey = *pkey; - - /* calculate space needed for trust anchor data */ - ta_size = ca.dn_len; - switch(pkey->key_type) { - case BR_KEYTYPE_RSA: - ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen; - break; - case BR_KEYTYPE_EC: - ta_size += pkey->key.ec.qlen; - break; - default: - ca.err = CURLE_FAILED_INIT; - goto fail; - } - - /* fill in trust anchor DN and public key data */ - ta->dn.data = malloc(ta_size); - if(!ta->dn.data) { - ca.err = CURLE_OUT_OF_MEMORY; - goto fail; - } - memcpy(ta->dn.data, ca.dn, ca.dn_len); - ta->dn.len = ca.dn_len; - switch(pkey->key_type) { - case BR_KEYTYPE_RSA: - ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len; - memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen); - ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen; - memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen); - break; - case BR_KEYTYPE_EC: - ta->pkey.key.ec.q = ta->dn.data + ta->dn.len; - memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen); - break; - } - break; - default: - ca.err = CURLE_SSL_CACERT_BADFILE; - goto fail; - } - } - } while(source->type != CAFILE_SOURCE_BLOB); - if(fp && ferror(fp)) - ca.err = CURLE_READ_ERROR; - else if(ca.in_cert) - ca.err = CURLE_SSL_CACERT_BADFILE; - -fail: - if(fp) - fclose(fp); - if(ca.err == CURLE_OK) { - *anchors = ca.anchors; - *anchors_len = ca.anchors_len; - } - else { - for(i = 0; i < ca.anchors_len; ++i) - free(ca.anchors[i].dn.data); - free(ca.anchors); - } - - return ca.err; -} - -static void x509_start_chain(const br_x509_class **ctx, - const char *server_name) -{ - struct x509_context *x509 = (struct x509_context *)ctx; - - if(!x509->verifypeer) { - x509->cert_num = 0; - return; - } - - if(!x509->verifyhost) - server_name = NULL; - x509->minimal.vtable->start_chain(&x509->minimal.vtable, server_name); -} - -static void x509_start_cert(const br_x509_class **ctx, uint32_t length) -{ - struct x509_context *x509 = (struct x509_context *)ctx; - - if(!x509->verifypeer) { - /* Only decode the first cert in the chain to obtain the public key */ - if(x509->cert_num == 0) - br_x509_decoder_init(&x509->decoder, NULL, NULL); - return; - } - - x509->minimal.vtable->start_cert(&x509->minimal.vtable, length); -} - -static void x509_append(const br_x509_class **ctx, const unsigned char *buf, - size_t len) -{ - struct x509_context *x509 = (struct x509_context *)ctx; - - if(!x509->verifypeer) { - if(x509->cert_num == 0) - br_x509_decoder_push(&x509->decoder, buf, len); - return; - } - - x509->minimal.vtable->append(&x509->minimal.vtable, buf, len); -} - -static void x509_end_cert(const br_x509_class **ctx) -{ - struct x509_context *x509 = (struct x509_context *)ctx; - - if(!x509->verifypeer) { - x509->cert_num++; - return; - } - - x509->minimal.vtable->end_cert(&x509->minimal.vtable); -} - -static unsigned x509_end_chain(const br_x509_class **ctx) -{ - struct x509_context *x509 = (struct x509_context *)ctx; - - if(!x509->verifypeer) { - return (unsigned)br_x509_decoder_last_error(&x509->decoder); - } - - return x509->minimal.vtable->end_chain(&x509->minimal.vtable); -} - -static const br_x509_pkey *x509_get_pkey(const br_x509_class *const *ctx, - unsigned *usages) -{ - struct x509_context *x509 = (struct x509_context *)CURL_UNCONST(ctx); - - if(!x509->verifypeer) { - /* Nothing in the chain is verified, just return the public key of the - first certificate and allow its usage for both TLS_RSA_* and - TLS_ECDHE_* */ - if(usages) - *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; - return br_x509_decoder_get_pkey(&x509->decoder); - } - - return x509->minimal.vtable->get_pkey(&x509->minimal.vtable, usages); -} - -static const br_x509_class x509_vtable = { - sizeof(struct x509_context), - x509_start_chain, - x509_start_cert, - x509_append, - x509_end_cert, - x509_end_chain, - x509_get_pkey -}; - -static CURLcode -bearssl_set_ssl_version_min_max(struct Curl_easy *data, - br_ssl_engine_context *ssl_eng, - struct ssl_primary_config *conn_config) -{ - unsigned version_min, version_max; - - switch(conn_config->version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - version_min = BR_TLS10; - break; - case CURL_SSLVERSION_TLSv1_1: - version_min = BR_TLS11; - break; - case CURL_SSLVERSION_TLSv1_2: - version_min = BR_TLS12; - break; - case CURL_SSLVERSION_TLSv1_3: - failf(data, "BearSSL: does not support TLS 1.3"); - return CURLE_SSL_CONNECT_ERROR; - default: - failf(data, "BearSSL: unsupported minimum TLS version value"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(conn_config->version_max) { - case CURL_SSLVERSION_MAX_DEFAULT: - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_TLSv1_3: - case CURL_SSLVERSION_MAX_TLSv1_2: - version_max = BR_TLS12; - break; - case CURL_SSLVERSION_MAX_TLSv1_1: - version_max = BR_TLS11; - break; - case CURL_SSLVERSION_MAX_TLSv1_0: - version_max = BR_TLS10; - break; - default: - failf(data, "BearSSL: unsupported maximum TLS version value"); - return CURLE_SSL_CONNECT_ERROR; - } - - br_ssl_engine_set_versions(ssl_eng, version_min, version_max); - - return CURLE_OK; -} - -static const uint16_t ciphertable[] = { - /* RFC 2246 TLS 1.0 */ - BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */ - - /* RFC 3268 TLS 1.0 AES */ - BR_TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */ - BR_TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */ - - /* RFC 5246 TLS 1.2 */ - BR_TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */ - BR_TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */ - - /* RFC 5288 TLS 1.2 AES GCM */ - BR_TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */ - BR_TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */ - - /* RFC 4492 TLS 1.0 ECC */ - BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */ - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */ - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */ - BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */ - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */ - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */ - BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */ - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */ - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */ - BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */ - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */ - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */ - - /* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */ - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */ - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */ - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */ - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */ - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */ - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */ - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */ - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */ - - /* RFC 5289 TLS 1.2 GCM */ - BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */ - BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */ - BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */ - BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */ - BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */ - BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */ - BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */ - BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */ - -#ifdef BR_TLS_RSA_WITH_AES_128_CCM - /* RFC 6655 TLS 1.2 CCM - Supported since BearSSL 0.6 */ - BR_TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */ - BR_TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */ - BR_TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */ - BR_TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */ - - /* RFC 7251 TLS 1.2 ECC CCM - Supported since BearSSL 0.6 */ - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */ - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */ - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */ - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */ -#endif - - /* RFC 7905 TLS 1.2 ChaCha20-Poly1305 - Supported since BearSSL 0.2 */ - BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */ - BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */ -}; - -#define NUM_OF_CIPHERS CURL_ARRAYSIZE(ciphertable) - -static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data, - br_ssl_engine_context *ssl_eng, - const char *ciphers) -{ - uint16_t selected[NUM_OF_CIPHERS]; - size_t count = 0, i; - const char *ptr, *end; - - for(ptr = ciphers; ptr[0] != '\0' && count < NUM_OF_CIPHERS; ptr = end) { - uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end); - - /* Check if cipher is supported */ - if(id) { - for(i = 0; i < NUM_OF_CIPHERS && ciphertable[i] != id; i++); - if(i == NUM_OF_CIPHERS) - id = 0; - } - if(!id) { - if(ptr[0] != '\0') - infof(data, "BearSSL: unknown cipher in list: \"%.*s\"", - (int) (end - ptr), ptr); - continue; - } - - /* No duplicates allowed */ - for(i = 0; i < count && selected[i] != id; i++); - if(i < count) { - infof(data, "BearSSL: duplicate cipher in list: \"%.*s\"", - (int) (end - ptr), ptr); - continue; - } - - selected[count++] = id; - } - - if(count == 0) { - failf(data, "BearSSL: no supported cipher in list"); - return CURLE_SSL_CIPHER; - } - - br_ssl_engine_set_suites(ssl_eng, selected, count); - return CURLE_OK; -} - -static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - const struct curl_blob *ca_info_blob = conn_config->ca_info_blob; - const char * const ssl_cafile = - /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ - (ca_info_blob ? NULL : conn_config->CAfile); - const char *hostname = connssl->peer.hostname; - const bool verifypeer = conn_config->verifypeer; - const bool verifyhost = conn_config->verifyhost; - CURLcode ret; - int session_set = 0; - - DEBUGASSERT(backend); - CURL_TRC_CF(data, cf, "connect_step1"); - - if(verifypeer) { - if(ca_info_blob) { - struct cafile_source source; - source.type = CAFILE_SOURCE_BLOB; - source.data = ca_info_blob->data; - source.len = ca_info_blob->len; - - CURL_TRC_CF(data, cf, "connect_step1, load ca_info_blob"); - ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); - if(ret != CURLE_OK) { - failf(data, "error importing CA certificate blob"); - return ret; - } - } - - if(ssl_cafile) { - struct cafile_source source; - source.type = CAFILE_SOURCE_PATH; - source.data = ssl_cafile; - source.len = 0; - - CURL_TRC_CF(data, cf, "connect_step1, load cafile"); - ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); - if(ret != CURLE_OK) { - failf(data, "error setting certificate verify locations." - " CAfile: %s", ssl_cafile); - return ret; - } - } - } - - /* initialize SSL context */ - br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal, - backend->anchors, backend->anchors_len); - - ret = bearssl_set_ssl_version_min_max(data, &backend->ctx.eng, conn_config); - if(ret != CURLE_OK) - return ret; - - br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf, - sizeof(backend->buf), 1); - - if(conn_config->cipher_list) { - /* Override the ciphers as specified. For the default cipher list see the - BearSSL source code of br_ssl_client_init_full() */ - CURL_TRC_CF(data, cf, "connect_step1, set ciphers"); - ret = bearssl_set_selected_ciphers(data, &backend->ctx.eng, - conn_config->cipher_list); - if(ret) - return ret; - } - - /* initialize X.509 context */ - backend->x509.vtable = &x509_vtable; - backend->x509.verifypeer = verifypeer; - backend->x509.verifyhost = verifyhost; - br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable); - - if(ssl_config->primary.cache_session) { - struct Curl_ssl_session *sc_session = NULL; - - ret = Curl_ssl_scache_take(cf, data, connssl->peer.scache_key, - &sc_session); - if(!ret && sc_session && sc_session->sdata && sc_session->sdata_len) { - const br_ssl_session_parameters *session; - session = (const br_ssl_session_parameters *)sc_session->sdata; - br_ssl_engine_set_session_parameters(&backend->ctx.eng, session); - session_set = 1; - infof(data, "BearSSL: reusing session ID"); - /* single use of sessions */ - Curl_ssl_scache_return(cf, data, connssl->peer.scache_key, sc_session); - } - } - - if(connssl->alpn) { - struct alpn_proto_buf proto; - size_t i; - - for(i = 0; i < connssl->alpn->count; ++i) { - backend->protocols[i] = connssl->alpn->entries[i]; - } - br_ssl_engine_set_protocol_names(&backend->ctx.eng, backend->protocols, - connssl->alpn->count); - Curl_alpn_to_proto_str(&proto, connssl->alpn); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); - } - - if(connssl->peer.type != CURL_SSL_PEER_DNS) { - if(verifyhost) { - failf(data, "BearSSL: " - "host verification of IP address is not supported"); - return CURLE_PEER_FAILED_VERIFICATION; - } - hostname = NULL; - } - else { - if(!connssl->peer.sni) { - failf(data, "Failed to set SNI"); - return CURLE_SSL_CONNECT_ERROR; - } - hostname = connssl->peer.sni; - CURL_TRC_CF(data, cf, "connect_step1, SNI set"); - } - - /* give application a chance to interfere with SSL set up. */ - if(data->set.ssl.fsslctx) { - Curl_set_in_callback(data, TRUE); - ret = (*data->set.ssl.fsslctx)(data, &backend->ctx, - data->set.ssl.fsslctxp); - Curl_set_in_callback(data, FALSE); - if(ret) { - failf(data, "BearSSL: error signaled by ssl ctx callback"); - return ret; - } - } - - if(!br_ssl_client_reset(&backend->ctx, hostname, session_set)) - return CURLE_FAILED_INIT; - backend->active = TRUE; - - connssl->connecting_state = ssl_connect_2; - - return CURLE_OK; -} - -static CURLcode bearssl_run_until(struct Curl_cfilter *cf, - struct Curl_easy *data, - unsigned target) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - unsigned state; - unsigned char *buf; - size_t len; - ssize_t ret; - CURLcode result; - int err; - - DEBUGASSERT(backend); - - connssl->io_need = CURL_SSL_IO_NEED_NONE; - for(;;) { - state = br_ssl_engine_current_state(&backend->ctx.eng); - if(state & BR_SSL_CLOSED) { - err = br_ssl_engine_last_error(&backend->ctx.eng); - switch(err) { - case BR_ERR_OK: - /* TLS close notify */ - if(connssl->state != ssl_connection_complete) { - failf(data, "SSL: connection closed during handshake"); - return CURLE_SSL_CONNECT_ERROR; - } - return CURLE_OK; - case BR_ERR_X509_EXPIRED: - failf(data, "SSL: X.509 verification: " - "certificate is expired or not yet valid"); - return CURLE_PEER_FAILED_VERIFICATION; - case BR_ERR_X509_BAD_SERVER_NAME: - failf(data, "SSL: X.509 verification: " - "expected server name was not found in the chain"); - return CURLE_PEER_FAILED_VERIFICATION; - case BR_ERR_X509_NOT_TRUSTED: - failf(data, "SSL: X.509 verification: " - "chain could not be linked to a trust anchor"); - return CURLE_PEER_FAILED_VERIFICATION; - default:; - } - failf(data, "BearSSL: connection error 0x%04x", err); - /* X.509 errors are documented to have the range 32..63 */ - if(err >= 32 && err < 64) - return CURLE_PEER_FAILED_VERIFICATION; - return CURLE_SSL_CONNECT_ERROR; - } - if(state & target) - return CURLE_OK; - if(state & BR_SSL_SENDREC) { - buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len); - ret = Curl_conn_cf_send(cf->next, data, (const char *)buf, len, FALSE, - &result); - CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result); - if(ret <= 0) { - if(result == CURLE_AGAIN) - connssl->io_need |= CURL_SSL_IO_NEED_SEND; - return result; - } - br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret); - } - else if(state & BR_SSL_RECVREC) { - buf = br_ssl_engine_recvrec_buf(&backend->ctx.eng, &len); - ret = Curl_conn_cf_recv(cf->next, data, (char *)buf, len, &result); - CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result); - if(ret == 0) { - failf(data, "SSL: EOF without close notify"); - return CURLE_RECV_ERROR; - } - if(ret <= 0) { - if(result == CURLE_AGAIN) - connssl->io_need |= CURL_SSL_IO_NEED_RECV; - return result; - } - br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret); - } - } -} - -static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - br_ssl_session_parameters session; - char cipher_str[64]; - CURLcode ret; - - DEBUGASSERT(backend); - CURL_TRC_CF(data, cf, "connect_step2"); - - ret = bearssl_run_until(cf, data, BR_SSL_SENDAPP | BR_SSL_RECVAPP); - if(ret == CURLE_AGAIN) - return CURLE_OK; - if(ret == CURLE_OK) { - unsigned int tver; - int subver = 0; - - if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) { - failf(data, "SSL: connection closed during handshake"); - return CURLE_SSL_CONNECT_ERROR; - } - connssl->connecting_state = ssl_connect_3; - /* Informational message */ - tver = br_ssl_engine_get_version(&backend->ctx.eng); - switch(tver) { - case BR_TLS12: - subver = 2; /* 1.2 */ - break; - case BR_TLS11: - subver = 1; /* 1.1 */ - break; - case BR_TLS10: /* 1.0 */ - default: /* unknown, leave it at zero */ - break; - } - br_ssl_engine_get_session_parameters(&backend->ctx.eng, &session); - Curl_cipher_suite_get_str(session.cipher_suite, cipher_str, - sizeof(cipher_str), TRUE); - infof(data, "BearSSL: TLS v1.%d connection using %s", subver, - cipher_str); - } - return ret; -} - -static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - CURLcode ret; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - DEBUGASSERT(backend); - CURL_TRC_CF(data, cf, "connect_step3"); - - if(connssl->alpn) { - const char *proto; - - proto = br_ssl_engine_get_selected_protocol(&backend->ctx.eng); - Curl_alpn_set_negotiated(cf, data, connssl, (const unsigned char *)proto, - proto ? strlen(proto) : 0); - } - - if(ssl_config->primary.cache_session) { - struct Curl_ssl_session *sc_session; - br_ssl_session_parameters *session; - - session = malloc(sizeof(*session)); - if(!session) - return CURLE_OUT_OF_MEMORY; - br_ssl_engine_get_session_parameters(&backend->ctx.eng, session); - ret = Curl_ssl_session_create((unsigned char *)session, sizeof(*session), - (int)session->version, - connssl->negotiated.alpn, - 0, 0, &sc_session); - if(!ret) { - ret = Curl_ssl_scache_put(cf, data, connssl->peer.scache_key, - sc_session); - /* took ownership of `sc_session` */ - } - if(ret) - return ret; - } - - connssl->connecting_state = ssl_connect_done; - - return CURLE_OK; -} - -static ssize_t bearssl_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, CURLcode *err) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - unsigned char *app; - size_t applen; - - DEBUGASSERT(backend); - - for(;;) { - *err = bearssl_run_until(cf, data, BR_SSL_SENDAPP); - if(*err) - return -1; - app = br_ssl_engine_sendapp_buf(&backend->ctx.eng, &applen); - if(!app) { - failf(data, "SSL: connection closed during write"); - *err = CURLE_SEND_ERROR; - return -1; - } - if(backend->pending_write) { - applen = backend->pending_write; - backend->pending_write = 0; - return applen; - } - if(applen > len) - applen = len; - memcpy(app, buf, applen); - br_ssl_engine_sendapp_ack(&backend->ctx.eng, applen); - br_ssl_engine_flush(&backend->ctx.eng, 0); - backend->pending_write = applen; - } -} - -static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - unsigned char *app; - size_t applen; - - DEBUGASSERT(backend); - - *err = bearssl_run_until(cf, data, BR_SSL_RECVAPP); - if(*err != CURLE_OK) - return -1; - app = br_ssl_engine_recvapp_buf(&backend->ctx.eng, &applen); - if(!app) - return 0; - if(applen > len) - applen = len; - memcpy(buf, app, applen); - br_ssl_engine_recvapp_ack(&backend->ctx.eng, applen); - - return applen; -} - -static CURLcode bearssl_connect(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - CURLcode ret; - struct ssl_connect_data *connssl = cf->ctx; - - CURL_TRC_CF(data, cf, "connect()"); - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - CURL_TRC_CF(data, cf, "connect_common, connected"); - *done = TRUE; - return CURLE_OK; - } - - *done = FALSE; - connssl->io_need = CURL_SSL_IO_NEED_NONE; - - if(ssl_connect_1 == connssl->connecting_state) { - ret = bearssl_connect_step1(cf, data); - if(ret) - return ret; - } - - if(ssl_connect_2 == connssl->connecting_state) { - ret = bearssl_connect_step2(cf, data); - if(ret) - return ret; - } - - if(ssl_connect_3 == connssl->connecting_state) { - ret = bearssl_connect_step3(cf, data); - if(ret) - return ret; - } - - if(ssl_connect_done == connssl->connecting_state) { - connssl->state = ssl_connection_complete; - *done = TRUE; - } - - return CURLE_OK; -} - -static size_t bearssl_version(char *buffer, size_t size) -{ - return msnprintf(buffer, size, "BearSSL"); -} - -static bool bearssl_data_pending(struct Curl_cfilter *cf, - const struct Curl_easy *data) -{ - struct ssl_connect_data *ctx = cf->ctx; - struct bearssl_ssl_backend_data *backend; - - (void)data; - DEBUGASSERT(ctx && ctx->backend); - backend = (struct bearssl_ssl_backend_data *)ctx->backend; - return br_ssl_engine_current_state(&backend->ctx.eng) & BR_SSL_RECVAPP; -} - -static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM, - unsigned char *entropy, size_t length) -{ - static br_hmac_drbg_context ctx; - static bool seeded = FALSE; - - if(!seeded) { - br_prng_seeder seeder; - - br_hmac_drbg_init(&ctx, &br_sha256_vtable, NULL, 0); - seeder = br_prng_seeder_system(NULL); - if(!seeder || !seeder(&ctx.vtable)) - return CURLE_FAILED_INIT; - seeded = TRUE; - } - br_hmac_drbg_generate(&ctx, entropy, length); - - return CURLE_OK; -} - -static void *bearssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - DEBUGASSERT(backend); - return &backend->ctx; -} - -static CURLcode bearssl_shutdown(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool send_shutdown, bool *done) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - CURLcode result; - - DEBUGASSERT(backend); - if(!backend->active || cf->shutdown) { - *done = TRUE; - return CURLE_OK; - } - - *done = FALSE; - if(!backend->sent_shutdown) { - (void)send_shutdown; /* unknown how to suppress our close notify */ - br_ssl_engine_close(&backend->ctx.eng); - backend->sent_shutdown = TRUE; - } - - result = bearssl_run_until(cf, data, BR_SSL_CLOSED); - if(result == CURLE_OK) { - *done = TRUE; - } - else if(result == CURLE_AGAIN) { - CURL_TRC_CF(data, cf, "shutdown EAGAIN, io_need=%x", connssl->io_need); - result = CURLE_OK; - } - else - CURL_TRC_CF(data, cf, "shutdown error: %d", result); - - cf->shutdown = (result || *done); - return result; -} - -static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct bearssl_ssl_backend_data *backend = - (struct bearssl_ssl_backend_data *)connssl->backend; - size_t i; - - (void)data; - DEBUGASSERT(backend); - - backend->active = FALSE; - if(backend->anchors) { - for(i = 0; i < backend->anchors_len; ++i) - free(backend->anchors[i].dn.data); - Curl_safefree(backend->anchors); - } -} - -static CURLcode bearssl_sha256sum(const unsigned char *input, - size_t inputlen, - unsigned char *sha256sum, - size_t sha256len UNUSED_PARAM) -{ - br_sha256_context ctx; - - br_sha256_init(&ctx); - br_sha256_update(&ctx, input, inputlen); - br_sha256_out(&ctx, sha256sum); - return CURLE_OK; -} - -const struct Curl_ssl Curl_ssl_bearssl = { - { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */ - - SSLSUPP_CAINFO_BLOB | - SSLSUPP_SSL_CTX | - SSLSUPP_HTTPS_PROXY | - SSLSUPP_CIPHER_LIST, - - sizeof(struct bearssl_ssl_backend_data), - - NULL, /* init */ - NULL, /* cleanup */ - bearssl_version, /* version */ - bearssl_shutdown, /* shutdown */ - bearssl_data_pending, /* data_pending */ - bearssl_random, /* random */ - NULL, /* cert_status_request */ - bearssl_connect, /* connect */ - Curl_ssl_adjust_pollset, /* adjust_pollset */ - bearssl_get_internals, /* get_internals */ - bearssl_close, /* close_one */ - NULL, /* close_all */ - NULL, /* set_engine */ - NULL, /* set_engine_default */ - NULL, /* engines_list */ - NULL, /* false_start */ - bearssl_sha256sum, /* sha256sum */ - bearssl_recv, /* recv decrypted data */ - bearssl_send, /* send data to encrypt */ - NULL, /* get_channel_binding */ -}; - -#endif /* USE_BEARSSL */ diff --git a/vendor/curl/lib/vtls/cipher_suite.c b/vendor/curl/lib/vtls/cipher_suite.c index d058bd3f..cefc92c5 100644 --- a/vendor/curl/lib/vtls/cipher_suite.c +++ b/vendor/curl/lib/vtls/cipher_suite.c @@ -23,11 +23,9 @@ ***************************************************************************/ #include "../curl_setup.h" -#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \ - defined(USE_BEARSSL) || defined(USE_RUSTLS) +#if defined(USE_MBEDTLS) || defined(USE_RUSTLS) #include "cipher_suite.h" #include "../curl_printf.h" -#include "../strcase.h" #include /* @@ -90,21 +88,6 @@ static const char *cs_txt = "CAMELLIA128" "\0" "CAMELLIA256" "\0" #endif -#if defined(USE_SECTRANSP) - "40" "\0" - "ADH" "\0" - "AECDH" "\0" - "anon" "\0" - "DES40" "\0" - "DH" "\0" - "DSS" "\0" - "EDH" "\0" - "EXP" "\0" - "EXPORT" "\0" - "IDEA" "\0" - "RC2" "\0" - "RC4" "\0" -#endif ; /* Indexes of above cs_txt */ enum { @@ -145,21 +128,6 @@ enum { CS_TXT_IDX_CAMELLIA, CS_TXT_IDX_CAMELLIA128, CS_TXT_IDX_CAMELLIA256, -#endif -#if defined(USE_SECTRANSP) - CS_TXT_IDX_40, - CS_TXT_IDX_ADH, - CS_TXT_IDX_AECDH, - CS_TXT_IDX_anon, - CS_TXT_IDX_DES40, - CS_TXT_IDX_DH, - CS_TXT_IDX_DSS, - CS_TXT_IDX_EDH, - CS_TXT_IDX_EXP, - CS_TXT_IDX_EXPORT, - CS_TXT_IDX_IDEA, - CS_TXT_IDX_RC2, - CS_TXT_IDX_RC4, #endif CS_TXT_LEN, }; @@ -192,7 +160,7 @@ struct cs_entry { /* !checksrc! disable COMMANOSPACE all */ static const struct cs_entry cs_list [] = { /* TLS 1.3 ciphers */ -#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_RUSTLS) +#if defined(USE_MBEDTLS) || defined(USE_RUSTLS) CS_ENTRY(0x1301, TLS,AES,128,GCM,SHA256,,,), CS_ENTRY(0x1302, TLS,AES,256,GCM,SHA384,,,), CS_ENTRY(0x1303, TLS,CHACHA20,POLY1305,SHA256,,,,), @@ -212,7 +180,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,), CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,), CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,), -#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL) +#if defined(USE_MBEDTLS) CS_ENTRY(0x002F, TLS,RSA,WITH,AES,128,CBC,SHA,), CS_ENTRY(0x002F, AES128,SHA,,,,,,), CS_ENTRY(0x0035, TLS,RSA,WITH,AES,256,CBC,SHA,), @@ -266,7 +234,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384), CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,), #endif -#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) +#if defined(USE_MBEDTLS) CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,), CS_ENTRY(0x0001, NULL,MD5,,,,,,), CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,), @@ -354,19 +322,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,), CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,), #endif -#if defined(USE_SECTRANSP) || defined(USE_BEARSSL) - CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,), - CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,), - CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,), - CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,), - CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,), - CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,), -#endif -#if defined(USE_MBEDTLS) || defined(USE_BEARSSL) +#if defined(USE_MBEDTLS) CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,), CS_ENTRY(0xC09C, AES128,CCM,,,,,,), CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,), @@ -384,141 +340,6 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8), CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,), #endif -#if defined(USE_SECTRANSP) - /* entries marked bc are backward compatible aliases for old OpenSSL names */ - CS_ENTRY(0x0003, TLS,RSA,EXPORT,WITH,RC4,40,MD5,), - CS_ENTRY(0x0003, EXP,RC4,MD5,,,,,), - CS_ENTRY(0x0004, TLS,RSA,WITH,RC4,128,MD5,,), - CS_ENTRY(0x0004, RC4,MD5,,,,,,), - CS_ENTRY(0x0005, TLS,RSA,WITH,RC4,128,SHA,,), - CS_ENTRY(0x0005, RC4,SHA,,,,,,), - CS_ENTRY(0x0006, TLS,RSA,EXPORT,WITH,RC2,CBC,40,MD5), - CS_ENTRY(0x0006, EXP,RC2,CBC,MD5,,,,), - CS_ENTRY(0x0007, TLS,RSA,WITH,IDEA,CBC,SHA,,), - CS_ENTRY(0x0007, IDEA,CBC,SHA,,,,,), - CS_ENTRY(0x0008, TLS,RSA,EXPORT,WITH,DES40,CBC,SHA,), - CS_ENTRY(0x0008, EXP,DES,CBC,SHA,,,,), - CS_ENTRY(0x0009, TLS,RSA,WITH,DES,CBC,SHA,,), - CS_ENTRY(0x0009, DES,CBC,SHA,,,,,), - CS_ENTRY(0x000B, TLS,DH,DSS,EXPORT,WITH,DES40,CBC,SHA), - CS_ENTRY(0x000B, EXP,DH,DSS,DES,CBC,SHA,,), - CS_ENTRY(0x000C, TLS,DH,DSS,WITH,DES,CBC,SHA,), - CS_ENTRY(0x000C, DH,DSS,DES,CBC,SHA,,,), - CS_ENTRY(0x000D, TLS,DH,DSS,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x000D, DH,DSS,DES,CBC3,SHA,,,), - CS_ENTRY(0x000E, TLS,DH,RSA,EXPORT,WITH,DES40,CBC,SHA), - CS_ENTRY(0x000E, EXP,DH,RSA,DES,CBC,SHA,,), - CS_ENTRY(0x000F, TLS,DH,RSA,WITH,DES,CBC,SHA,), - CS_ENTRY(0x000F, DH,RSA,DES,CBC,SHA,,,), - CS_ENTRY(0x0010, TLS,DH,RSA,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x0010, DH,RSA,DES,CBC3,SHA,,,), - CS_ENTRY(0x0011, TLS,DHE,DSS,EXPORT,WITH,DES40,CBC,SHA), - CS_ENTRY(0x0011, EXP,DHE,DSS,DES,CBC,SHA,,), - CS_ENTRY(0x0011, EXP,EDH,DSS,DES,CBC,SHA,,), /* bc */ - CS_ENTRY(0x0012, TLS,DHE,DSS,WITH,DES,CBC,SHA,), - CS_ENTRY(0x0012, DHE,DSS,DES,CBC,SHA,,,), - CS_ENTRY(0x0012, EDH,DSS,DES,CBC,SHA,,,), /* bc */ - CS_ENTRY(0x0013, TLS,DHE,DSS,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x0013, DHE,DSS,DES,CBC3,SHA,,,), - CS_ENTRY(0x0013, EDH,DSS,DES,CBC3,SHA,,,), /* bc */ - CS_ENTRY(0x0014, TLS,DHE,RSA,EXPORT,WITH,DES40,CBC,SHA), - CS_ENTRY(0x0014, EXP,DHE,RSA,DES,CBC,SHA,,), - CS_ENTRY(0x0014, EXP,EDH,RSA,DES,CBC,SHA,,), /* bc */ - CS_ENTRY(0x0015, TLS,DHE,RSA,WITH,DES,CBC,SHA,), - CS_ENTRY(0x0015, DHE,RSA,DES,CBC,SHA,,,), - CS_ENTRY(0x0015, EDH,RSA,DES,CBC,SHA,,,), /* bc */ - CS_ENTRY(0x0016, TLS,DHE,RSA,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x0016, DHE,RSA,DES,CBC3,SHA,,,), - CS_ENTRY(0x0016, EDH,RSA,DES,CBC3,SHA,,,), /* bc */ - CS_ENTRY(0x0017, TLS,DH,anon,EXPORT,WITH,RC4,40,MD5), - CS_ENTRY(0x0017, EXP,ADH,RC4,MD5,,,,), - CS_ENTRY(0x0018, TLS,DH,anon,WITH,RC4,128,MD5,), - CS_ENTRY(0x0018, ADH,RC4,MD5,,,,,), - CS_ENTRY(0x0019, TLS,DH,anon,EXPORT,WITH,DES40,CBC,SHA), - CS_ENTRY(0x0019, EXP,ADH,DES,CBC,SHA,,,), - CS_ENTRY(0x001A, TLS,DH,anon,WITH,DES,CBC,SHA,), - CS_ENTRY(0x001A, ADH,DES,CBC,SHA,,,,), - CS_ENTRY(0x001B, TLS,DH,anon,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x001B, ADH,DES,CBC3,SHA,,,,), - CS_ENTRY(0x0030, TLS,DH,DSS,WITH,AES,128,CBC,SHA), - CS_ENTRY(0x0030, DH,DSS,AES128,SHA,,,,), - CS_ENTRY(0x0031, TLS,DH,RSA,WITH,AES,128,CBC,SHA), - CS_ENTRY(0x0031, DH,RSA,AES128,SHA,,,,), - CS_ENTRY(0x0032, TLS,DHE,DSS,WITH,AES,128,CBC,SHA), - CS_ENTRY(0x0032, DHE,DSS,AES128,SHA,,,,), - CS_ENTRY(0x0034, TLS,DH,anon,WITH,AES,128,CBC,SHA), - CS_ENTRY(0x0034, ADH,AES128,SHA,,,,,), - CS_ENTRY(0x0036, TLS,DH,DSS,WITH,AES,256,CBC,SHA), - CS_ENTRY(0x0036, DH,DSS,AES256,SHA,,,,), - CS_ENTRY(0x0037, TLS,DH,RSA,WITH,AES,256,CBC,SHA), - CS_ENTRY(0x0037, DH,RSA,AES256,SHA,,,,), - CS_ENTRY(0x0038, TLS,DHE,DSS,WITH,AES,256,CBC,SHA), - CS_ENTRY(0x0038, DHE,DSS,AES256,SHA,,,,), - CS_ENTRY(0x003A, TLS,DH,anon,WITH,AES,256,CBC,SHA), - CS_ENTRY(0x003A, ADH,AES256,SHA,,,,,), - CS_ENTRY(0x003E, TLS,DH,DSS,WITH,AES,128,CBC,SHA256), - CS_ENTRY(0x003E, DH,DSS,AES128,SHA256,,,,), - CS_ENTRY(0x003F, TLS,DH,RSA,WITH,AES,128,CBC,SHA256), - CS_ENTRY(0x003F, DH,RSA,AES128,SHA256,,,,), - CS_ENTRY(0x0040, TLS,DHE,DSS,WITH,AES,128,CBC,SHA256), - CS_ENTRY(0x0040, DHE,DSS,AES128,SHA256,,,,), - CS_ENTRY(0x0068, TLS,DH,DSS,WITH,AES,256,CBC,SHA256), - CS_ENTRY(0x0068, DH,DSS,AES256,SHA256,,,,), - CS_ENTRY(0x0069, TLS,DH,RSA,WITH,AES,256,CBC,SHA256), - CS_ENTRY(0x0069, DH,RSA,AES256,SHA256,,,,), - CS_ENTRY(0x006A, TLS,DHE,DSS,WITH,AES,256,CBC,SHA256), - CS_ENTRY(0x006A, DHE,DSS,AES256,SHA256,,,,), - CS_ENTRY(0x006C, TLS,DH,anon,WITH,AES,128,CBC,SHA256), - CS_ENTRY(0x006C, ADH,AES128,SHA256,,,,,), - CS_ENTRY(0x006D, TLS,DH,anon,WITH,AES,256,CBC,SHA256), - CS_ENTRY(0x006D, ADH,AES256,SHA256,,,,,), - CS_ENTRY(0x008A, TLS,PSK,WITH,RC4,128,SHA,,), - CS_ENTRY(0x008A, PSK,RC4,SHA,,,,,), - CS_ENTRY(0x008B, TLS,PSK,WITH,3DES,EDE,CBC,SHA,), - CS_ENTRY(0x008B, PSK,3DES,EDE,CBC,SHA,,,), - CS_ENTRY(0x008E, TLS,DHE,PSK,WITH,RC4,128,SHA,), - CS_ENTRY(0x008E, DHE,PSK,RC4,SHA,,,,), - CS_ENTRY(0x008F, TLS,DHE,PSK,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x008F, DHE,PSK,3DES,EDE,CBC,SHA,,), - CS_ENTRY(0x0092, TLS,RSA,PSK,WITH,RC4,128,SHA,), - CS_ENTRY(0x0092, RSA,PSK,RC4,SHA,,,,), - CS_ENTRY(0x0093, TLS,RSA,PSK,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0x0093, RSA,PSK,3DES,EDE,CBC,SHA,,), - CS_ENTRY(0x00A0, TLS,DH,RSA,WITH,AES,128,GCM,SHA256), - CS_ENTRY(0x00A0, DH,RSA,AES128,GCM,SHA256,,,), - CS_ENTRY(0x00A1, TLS,DH,RSA,WITH,AES,256,GCM,SHA384), - CS_ENTRY(0x00A1, DH,RSA,AES256,GCM,SHA384,,,), - CS_ENTRY(0x00A2, TLS,DHE,DSS,WITH,AES,128,GCM,SHA256), - CS_ENTRY(0x00A2, DHE,DSS,AES128,GCM,SHA256,,,), - CS_ENTRY(0x00A3, TLS,DHE,DSS,WITH,AES,256,GCM,SHA384), - CS_ENTRY(0x00A3, DHE,DSS,AES256,GCM,SHA384,,,), - CS_ENTRY(0x00A4, TLS,DH,DSS,WITH,AES,128,GCM,SHA256), - CS_ENTRY(0x00A4, DH,DSS,AES128,GCM,SHA256,,,), - CS_ENTRY(0x00A5, TLS,DH,DSS,WITH,AES,256,GCM,SHA384), - CS_ENTRY(0x00A5, DH,DSS,AES256,GCM,SHA384,,,), - CS_ENTRY(0x00A6, TLS,DH,anon,WITH,AES,128,GCM,SHA256), - CS_ENTRY(0x00A6, ADH,AES128,GCM,SHA256,,,,), - CS_ENTRY(0x00A7, TLS,DH,anon,WITH,AES,256,GCM,SHA384), - CS_ENTRY(0x00A7, ADH,AES256,GCM,SHA384,,,,), - CS_ENTRY(0xC002, TLS,ECDH,ECDSA,WITH,RC4,128,SHA,), - CS_ENTRY(0xC002, ECDH,ECDSA,RC4,SHA,,,,), - CS_ENTRY(0xC007, TLS,ECDHE,ECDSA,WITH,RC4,128,SHA,), - CS_ENTRY(0xC007, ECDHE,ECDSA,RC4,SHA,,,,), - CS_ENTRY(0xC00C, TLS,ECDH,RSA,WITH,RC4,128,SHA,), - CS_ENTRY(0xC00C, ECDH,RSA,RC4,SHA,,,,), - CS_ENTRY(0xC011, TLS,ECDHE,RSA,WITH,RC4,128,SHA,), - CS_ENTRY(0xC011, ECDHE,RSA,RC4,SHA,,,,), - CS_ENTRY(0xC015, TLS,ECDH,anon,WITH,NULL,SHA,,), - CS_ENTRY(0xC015, AECDH,NULL,SHA,,,,,), - CS_ENTRY(0xC016, TLS,ECDH,anon,WITH,RC4,128,SHA,), - CS_ENTRY(0xC016, AECDH,RC4,SHA,,,,,), - CS_ENTRY(0xC017, TLS,ECDH,anon,WITH,3DES,EDE,CBC,SHA), - CS_ENTRY(0xC017, AECDH,DES,CBC3,SHA,,,,), - CS_ENTRY(0xC018, TLS,ECDH,anon,WITH,AES,128,CBC,SHA), - CS_ENTRY(0xC018, AECDH,AES128,SHA,,,,,), - CS_ENTRY(0xC019, TLS,ECDH,anon,WITH,AES,256,CBC,SHA), - CS_ENTRY(0xC019, AECDH,AES256,SHA,,,,,), -#endif #if defined(USE_MBEDTLS) /* entries marked ns are "non-standard", they are not in OpenSSL */ CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,), @@ -739,7 +560,7 @@ static int cs_str_to_zip(const char *cs_str, size_t cs_len, size_t len; /* split the cipher string by '-' or '_' */ - if(strncasecompare(cs_str, "TLS", 3)) + if(curl_strnequal(cs_str, "TLS", 3)) separator = '_'; do { @@ -754,7 +575,7 @@ static int cs_str_to_zip(const char *cs_str, size_t cs_len, /* lookup index for the part (skip empty string at 0) */ for(idx = 1, entry = cs_txt + 1; idx < CS_TXT_LEN; idx++) { size_t elen = strlen(entry); - if(elen == len && strncasecompare(entry, cur, len)) + if(elen == len && curl_strnequal(entry, cur, len)) break; entry += elen + 1; } @@ -887,5 +708,4 @@ int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, return r; } -#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \ - defined(USE_BEARSSL) || defined(USE_RUSTLS) */ +#endif /* defined(USE_MBEDTLS) || defined(USE_RUSTLS) */ diff --git a/vendor/curl/lib/vtls/cipher_suite.h b/vendor/curl/lib/vtls/cipher_suite.h index cd556db1..a1dcbc52 100644 --- a/vendor/curl/lib/vtls/cipher_suite.h +++ b/vendor/curl/lib/vtls/cipher_suite.h @@ -26,8 +26,7 @@ #include "../curl_setup.h" -#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \ - defined(USE_BEARSSL) || defined(USE_RUSTLS) +#if defined(USE_MBEDTLS) || defined(USE_RUSTLS) #include /* Lookup IANA id for cipher suite string, returns 0 if not recognized */ @@ -43,6 +42,5 @@ uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end); int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, bool prefer_rfc); -#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \ - defined(USE_BEARSSL) || defined(USE_RUSTLS) */ +#endif /* defined(USE_MBEDTLS) || defined(USE_RUSTLS) */ #endif /* HEADER_CURL_CIPHER_SUITE_H */ diff --git a/vendor/curl/lib/vtls/gtls.c b/vendor/curl/lib/vtls/gtls.c index bb2a0265..f5e02975 100644 --- a/vendor/curl/lib/vtls/gtls.c +++ b/vendor/curl/lib/vtls/gtls.c @@ -53,7 +53,6 @@ #include "../connect.h" /* for the connect timeout */ #include "../progress.h" #include "../select.h" -#include "../strcase.h" #include "../strdup.h" #include "../curlx/warnless.h" #include "x509asn1.h" @@ -91,21 +90,21 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen) struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten; + size_t nwritten; CURLcode result; DEBUGASSERT(data); - nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result); - CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d", - blen, nwritten, result); + result = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &nwritten); + CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %d, %zu", + blen, result, nwritten); backend->gtls.io_result = result; - if(nwritten < 0) { + if(result) { /* !checksrc! disable ERRNOVAR 1 */ gnutls_transport_set_errno(backend->gtls.session, (CURLE_AGAIN == result) ? EAGAIN : EINVAL); - nwritten = -1; + return -1; } - return nwritten; + return (ssize_t)nwritten; } static ssize_t gtls_pull(void *s, void *buf, size_t blen) @@ -115,7 +114,7 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen) struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nread; + size_t nread; CURLcode result; DEBUGASSERT(data); @@ -129,19 +128,19 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen) } } - nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); - CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d", - blen, nread, result); + result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); + CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %d, %zd", + blen, result, nread); backend->gtls.io_result = result; - if(nread < 0) { + if(result) { /* !checksrc! disable ERRNOVAR 1 */ gnutls_transport_set_errno(backend->gtls.session, (CURLE_AGAIN == result) ? EAGAIN : EINVAL); - nread = -1; + return -1; } else if(nread == 0) connssl->peer_closed = TRUE; - return nread; + return (ssize_t)nread; } /* gtls_init() @@ -233,7 +232,7 @@ static void unload_file(gnutls_datum_t data) } -/* this function does a SSL/TLS (re-)handshake */ +/* this function does an SSL/TLS (re-)handshake */ static CURLcode handshake(struct Curl_cfilter *cf, struct Curl_easy *data) { @@ -303,9 +302,9 @@ static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; - if(strcasecompare(type, "PEM")) + if(curl_strequal(type, "PEM")) return GNUTLS_X509_FMT_PEM; - if(strcasecompare(type, "DER")) + if(curl_strequal(type, "DER")) return GNUTLS_X509_FMT_DER; return GNUTLS_X509_FMT_PEM; /* default to PEM */ } @@ -784,9 +783,9 @@ static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype, } static CURLcode gtls_set_priority(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct gtls_ctx *gtls, - const char *priority) + struct Curl_easy *data, + struct gtls_ctx *gtls, + const char *priority) { struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct dynbuf buf; @@ -982,7 +981,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, if(result) return result; } - if(ssl_config->cert_type && strcasecompare(ssl_config->cert_type, "P12")) { + if(ssl_config->cert_type && curl_strequal(ssl_config->cert_type, "P12")) { rc = gnutls_certificate_set_x509_simple_pkcs12_file( gtls->shared_creds->creds, config->clientcert, GNUTLS_X509_FMT_DER, ssl_config->key_passwd ? ssl_config->key_passwd : ""); @@ -1080,7 +1079,7 @@ static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf, connssl->earlydata_max = gnutls_record_get_max_early_data_size(backend->gtls.session); if((!connssl->earlydata_max || connssl->earlydata_max == 0xFFFFFFFFUL)) { - /* Seems to be GnuTLS way to signal no EarlyData in session */ + /* Seems to be no GnuTLS way to signal no EarlyData in session */ CURL_TRC_CF(data, cf, "SSL session does not allow earlydata"); } else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) { @@ -1308,6 +1307,28 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, return result; } +void Curl_gtls_report_handshake(struct Curl_easy *data, + struct gtls_ctx *gctx) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_is_verbose(data)) { + const char *ptr; + gnutls_protocol_t version = gnutls_protocol_get_version(gctx->session); + + /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ + ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(gctx->session), + gnutls_cipher_get(gctx->session), + gnutls_mac_get(gctx->session)); + + infof(data, "SSL connection using %s / %s", + gnutls_protocol_get_name(version), ptr); + } +#else + (void)data; + (void)gctx; +#endif +} + CURLcode Curl_gtls_verifyserver(struct Curl_easy *data, gnutls_session_t session, @@ -1328,23 +1349,11 @@ Curl_gtls_verifyserver(struct Curl_easy *data, int rc; CURLcode result = CURLE_OK; #ifndef CURL_DISABLE_VERBOSE_STRINGS - const char *ptr; int algo; unsigned int bits; - gnutls_protocol_t version = gnutls_protocol_get_version(session); #endif long * const certverifyresult = &ssl_config->certverifyresult; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ - ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), - gnutls_cipher_get(session), - gnutls_mac_get(session)); - - infof(data, "SSL connection using %s / %s", - gnutls_protocol_get_name(version), ptr); -#endif - /* This function will return the peer's raw certificate (chain) as sent by the peer. These certificates are in raw format (DER encoded for X.509). In case of a X.509 then a certificate list may be present. The @@ -1877,6 +1886,9 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf, if(connssl->connecting_state == ssl_connect_3) { gnutls_datum_t proto; int rc; + + Curl_gtls_report_handshake(data, &backend->gtls); + result = gtls_verifyserver(cf, data, backend->gtls.session); if(result) goto out; @@ -1948,48 +1960,49 @@ static bool gtls_data_pending(struct Curl_cfilter *cf, return FALSE; } -static ssize_t gtls_send(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *buf, - size_t blen, - CURLcode *curlcode) +static CURLcode gtls_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, + size_t blen, + size_t *pnwritten) { struct ssl_connect_data *connssl = cf->ctx; struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; - ssize_t rc; - size_t nwritten, total_written = 0; + CURLcode result = CURLE_OK; + ssize_t nwritten; + size_t remain = blen; (void)data; DEBUGASSERT(backend); + *pnwritten = 0; - while(blen) { + while(remain) { backend->gtls.io_result = CURLE_OK; - rc = gnutls_record_send(backend->gtls.session, buf, blen); + nwritten = gnutls_record_send(backend->gtls.session, buf, remain); - if(rc < 0) { - if(total_written && (rc == GNUTLS_E_AGAIN)) { - *curlcode = CURLE_OK; - rc = (ssize_t)total_written; + if(nwritten >= 0) { + *pnwritten += (size_t)nwritten; + DEBUGASSERT((size_t)nwritten <= remain); + buf = (char *)CURL_UNCONST(buf) + (size_t)nwritten; + remain -= (size_t)nwritten; + } + else { + if(*pnwritten && (nwritten == GNUTLS_E_AGAIN)) { + result = CURLE_OK; goto out; } - *curlcode = (rc == GNUTLS_E_AGAIN) ? + result = (nwritten == GNUTLS_E_AGAIN) ? CURLE_AGAIN : (backend->gtls.io_result ? backend->gtls.io_result : CURLE_SEND_ERROR); - - rc = -1; goto out; } - nwritten = (size_t)rc; - total_written += nwritten; - DEBUGASSERT(nwritten <= blen); - buf = (char *)CURL_UNCONST(buf) + nwritten; - blen -= nwritten; } - rc = total_written; out: - return rc; + CURL_TRC_CF(data, cf, "gtls_send(len=%zu) -> %d, %zu", + blen, result, *pnwritten); + return result; } /* @@ -2095,50 +2108,49 @@ static void gtls_close(struct Curl_cfilter *cf, #endif } -static ssize_t gtls_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, - size_t buffersize, - CURLcode *curlcode) +static CURLcode gtls_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t blen, + size_t *pnread) { struct ssl_connect_data *connssl = cf->ctx; struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; - ssize_t ret; + CURLcode result = CURLE_OK; + ssize_t nread; (void)data; DEBUGASSERT(backend); - ret = gnutls_record_recv(backend->gtls.session, buf, buffersize); - if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) { - *curlcode = CURLE_AGAIN; - ret = -1; - goto out; - } + nread = gnutls_record_recv(backend->gtls.session, buf, blen); - if(ret == GNUTLS_E_REHANDSHAKE) { - /* BLOCKING call, this is bad but a work-around for now. Fixing this "the - proper way" takes a whole lot of work. */ - CURLcode result = handshake(cf, data); - if(result) - *curlcode = result; - else - *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ - ret = -1; - goto out; - } - - if(ret < 0) { - failf(data, "GnuTLS recv error (%d): %s", - (int)ret, gnutls_strerror((int)ret)); - *curlcode = backend->gtls.io_result ? - backend->gtls.io_result : CURLE_RECV_ERROR; - ret = -1; - goto out; + if(nread >= 0) + *pnread = (size_t)nread; + else { + if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) { + result = CURLE_AGAIN; + goto out; + } + else if(nread == GNUTLS_E_REHANDSHAKE) { + /* BLOCKING call, this is bad but a work-around for now. Fixing this "the + proper way" takes a whole lot of work. */ + result = handshake(cf, data); + if(!result) + result = CURLE_AGAIN; /* then return as if this was a wouldblock */ + goto out; + } + else { + failf(data, "GnuTLS recv error (%d): %s", + (int)nread, gnutls_strerror((int)nread)); + result = backend->gtls.io_result ? + backend->gtls.io_result : CURLE_RECV_ERROR; + goto out; + } } out: - return ret; + CURL_TRC_CF(data, cf, "gtls_recv(len=%zu) -> 0, %zu", blen, *pnread); + return result; } size_t Curl_gtls_version(char *buffer, size_t size) @@ -2210,7 +2222,6 @@ const struct Curl_ssl Curl_ssl_gnutls = { NULL, /* set_engine */ NULL, /* set_engine_default */ NULL, /* engines_list */ - NULL, /* false_start */ gtls_sha256sum, /* sha256sum */ gtls_recv, /* recv decrypted data */ gtls_send, /* send data to encrypt */ diff --git a/vendor/curl/lib/vtls/gtls.h b/vendor/curl/lib/vtls/gtls.h index 35af9db1..01f8b43a 100644 --- a/vendor/curl/lib/vtls/gtls.h +++ b/vendor/curl/lib/vtls/gtls.h @@ -117,6 +117,10 @@ CURLcode Curl_gtls_cache_session(struct Curl_cfilter *cf, unsigned char *quic_tp, size_t quic_tp_len); +/* Report properties of a successful handshake */ +void Curl_gtls_report_handshake(struct Curl_easy *data, + struct gtls_ctx *gctx); + extern const struct Curl_ssl Curl_ssl_gnutls; #endif /* USE_GNUTLS */ diff --git a/vendor/curl/lib/vtls/hostcheck.c b/vendor/curl/lib/vtls/hostcheck.c index 8ca69941..68af9be5 100644 --- a/vendor/curl/lib/vtls/hostcheck.c +++ b/vendor/curl/lib/vtls/hostcheck.c @@ -36,7 +36,6 @@ #endif #include "../curl_memrchr.h" #include "hostcheck.h" -#include "../strcase.h" #include "../hostip.h" #include "../curl_memory.h" @@ -50,7 +49,7 @@ static bool pmatch(const char *hostname, size_t hostlen, { if(hostlen != patternlen) return FALSE; - return strncasecompare(hostname, pattern, hostlen); + return curl_strnequal(hostname, pattern, hostlen); } /* diff --git a/vendor/curl/lib/vtls/keylog.c b/vendor/curl/lib/vtls/keylog.c index 8f4880cf..2fd25089 100644 --- a/vendor/curl/lib/vtls/keylog.c +++ b/vendor/curl/lib/vtls/keylog.c @@ -94,7 +94,7 @@ Curl_tls_keylog_write_line(const char *line) linelen = strlen(line); if(linelen == 0 || linelen > sizeof(buf) - 2) { - /* Empty line or too big to fit in a LF and NUL. */ + /* Empty line or too big to fit in an LF and NUL. */ return FALSE; } @@ -134,14 +134,14 @@ Curl_tls_keylog_write(const char *label, /* Client Random */ for(i = 0; i < CLIENT_RANDOM_SIZE; i++) { - Curl_hexbyte(&line[pos], client_random[i], FALSE); + Curl_hexbyte(&line[pos], client_random[i]); pos += 2; } line[pos++] = ' '; /* Secret */ for(i = 0; i < secretlen; i++) { - Curl_hexbyte(&line[pos], secret[i], FALSE); + Curl_hexbyte(&line[pos], secret[i]); pos += 2; } line[pos++] = '\n'; diff --git a/vendor/curl/lib/vtls/keylog.h b/vendor/curl/lib/vtls/keylog.h index a00a2256..ec82abf5 100644 --- a/vendor/curl/lib/vtls/keylog.h +++ b/vendor/curl/lib/vtls/keylog.h @@ -61,7 +61,7 @@ bool Curl_tls_keylog_write(const char *label, const unsigned char *secret, size_t secretlen); /* - * Appends a line to the key log file, ensure it is terminated by a LF. + * Appends a line to the key log file, ensure it is terminated by an LF. * Returns true iff the key log file is open and a valid line was provided. */ bool Curl_tls_keylog_write_line(const char *line); diff --git a/vendor/curl/lib/vtls/mbedtls.c b/vendor/curl/lib/vtls/mbedtls.c index 7af207ca..75190d30 100644 --- a/vendor/curl/lib/vtls/mbedtls.c +++ b/vendor/curl/lib/vtls/mbedtls.c @@ -57,7 +57,6 @@ #endif /* MBEDTLS_VERSION_MAJOR >= 2 */ #include "cipher_suite.h" -#include "../strcase.h" #include "../urldata.h" #include "../sendf.h" #include "../curlx/inet_pton.h" @@ -191,28 +190,27 @@ static int mbedtls_bio_cf_write(void *bio, { struct Curl_cfilter *cf = bio; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten; + size_t nwritten; CURLcode result; DEBUGASSERT(data); if(!data) return 0; - nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, blen, FALSE, - &result); - CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d", - blen, nwritten, result); - if(nwritten < 0 && CURLE_AGAIN == result) { - nwritten = MBEDTLS_ERR_SSL_WANT_WRITE; - } - return (int)nwritten; + result = Curl_conn_cf_send(cf->next, data, (const char *)buf, blen, FALSE, + &nwritten); + CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %d, %zu", + blen, result, nwritten); + if(CURLE_AGAIN == result) + return MBEDTLS_ERR_SSL_WANT_WRITE; + return result ? -1 : (int)nwritten; } static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) { struct Curl_cfilter *cf = bio; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nread; + size_t nread; CURLcode result; DEBUGASSERT(data); @@ -222,13 +220,12 @@ static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen) if(!buf) return 0; - nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &result); - CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %zd, err=%d", - blen, nread, result); - if(nread < 0 && CURLE_AGAIN == result) { - nread = MBEDTLS_ERR_SSL_WANT_READ; - } - return (int)nread; + result = Curl_conn_cf_recv(cf->next, data, (char *)buf, blen, &nread); + CURL_TRC_CF(data, cf, "mbedtls_bio_cf_in_read(len=%zu) -> %d, %zu", + blen, result, nread); + if(CURLE_AGAIN == result) + return MBEDTLS_ERR_SSL_WANT_READ; + return result ? -1 : (int)nread; } /* @@ -384,7 +381,7 @@ mbed_cipher_suite_walk_str(const char **str, const char **end) size_t len = *end - *str; if(!id) { - if(strncasecompare("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len)) + if(curl_strnequal("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len)) id = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8; } return id; @@ -1205,16 +1202,18 @@ mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data) return result; } -static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *mem, size_t len, - CURLcode *curlcode) +static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *mem, size_t len, + size_t *pnwritten) { struct ssl_connect_data *connssl = cf->ctx; struct mbed_ssl_backend_data *backend = (struct mbed_ssl_backend_data *)connssl->backend; - int ret = -1; + CURLcode result = CURLE_OK; + int nwritten; (void)data; + *pnwritten = 0; DEBUGASSERT(backend); /* mbedtls is picky when a mbedtls_ssl_write) was previously blocked. * It requires to be called with the same amount of bytes again, or it @@ -1227,28 +1226,29 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, len = backend->send_blocked_len; } - ret = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len); + nwritten = mbedtls_ssl_write(&backend->ssl, (const unsigned char *)mem, len); - if(ret < 0) { + if(nwritten >= 0) { + *pnwritten = (size_t)nwritten; + backend->send_blocked = FALSE; + } + else { CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X", - len, -ret); - *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE) + len, -nwritten); + result = ((nwritten == MBEDTLS_ERR_SSL_WANT_WRITE) #ifdef HAS_TLS13_SUPPORT - || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) + || (nwritten == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) #endif ) ? CURLE_AGAIN : CURLE_SEND_ERROR; - ret = -1; - if((*curlcode == CURLE_AGAIN) && !backend->send_blocked) { + if((result == CURLE_AGAIN) && !backend->send_blocked) { backend->send_blocked = TRUE; backend->send_blocked_len = len; } } - else { - CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d", len, ret); - backend->send_blocked = FALSE; - } - return ret; + CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d, %zu", + len, result, *pnwritten); + return result; } static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf, @@ -1367,48 +1367,48 @@ static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data) } } -static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t buffersize, - CURLcode *curlcode) +static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t buffersize, + size_t *pnread) { struct ssl_connect_data *connssl = cf->ctx; struct mbed_ssl_backend_data *backend = (struct mbed_ssl_backend_data *)connssl->backend; - int ret = -1; + CURLcode result = CURLE_OK; + int nread; (void)data; DEBUGASSERT(backend); + *pnread = 0; - ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, - buffersize); - if(ret <= 0) { + nread = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, buffersize); + if(nread > 0) + *pnread = (size_t)nread; + else { CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X", - buffersize, -ret); - switch(ret) { + buffersize, -nread); + switch(nread) { #ifdef HAS_SESSION_TICKETS case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: mbed_new_session(cf, data); FALLTHROUGH(); #endif case MBEDTLS_ERR_SSL_WANT_READ: - *curlcode = CURLE_AGAIN; - ret = -1; + result = CURLE_AGAIN; break; case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: - *curlcode = CURLE_OK; - ret = 0; + result = CURLE_OK; break; default: { char errorbuf[128]; - mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); - failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf); - *curlcode = CURLE_RECV_ERROR; - ret = -1; + mbedtls_strerror(nread, errorbuf, sizeof(errorbuf)); + failf(data, "ssl_read returned: (-0x%04X) %s", -nread, errorbuf); + result = CURLE_RECV_ERROR; break; } } } - return (ssize_t)ret; + return result; } static size_t mbedtls_version(char *buffer, size_t size) @@ -1620,7 +1620,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = { NULL, /* set_engine */ NULL, /* set_engine_default */ NULL, /* engines_list */ - NULL, /* false_start */ mbedtls_sha256sum, /* sha256sum */ mbed_recv, /* recv decrypted data */ mbed_send, /* send data to encrypt */ diff --git a/vendor/curl/lib/vtls/openssl.c b/vendor/curl/lib/vtls/openssl.c index ffdae239..b0f91cf4 100644 --- a/vendor/curl/lib/vtls/openssl.c +++ b/vendor/curl/lib/vtls/openssl.c @@ -54,12 +54,12 @@ #include "../connect.h" #include "../slist.h" #include "../select.h" +#include "../curlx/wait.h" #include "vtls.h" #include "vtls_int.h" #include "vtls_scache.h" #include "../vauth/vauth.h" #include "keylog.h" -#include "../strcase.h" #include "hostcheck.h" #include "../multiif.h" #include "../curlx/strparse.h" @@ -122,6 +122,12 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #endif +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER) && \ + !defined(OPENSSL_IS_BORINGSSL)) + #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 +#endif + #include "../curlx/warnless.h" /* The last #include files should be: */ @@ -698,9 +704,11 @@ static long ossl_bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) ret = 1; break; #ifdef BIO_CTRL_EOF - case BIO_CTRL_EOF: + case BIO_CTRL_EOF: { /* EOF has been reached on input? */ - return !cf->next || !cf->next->connected; + struct ssl_connect_data *connssl = cf->ctx; + return connssl->peer_closed; + } #endif default: ret = 0; @@ -715,22 +723,23 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen) struct ssl_connect_data *connssl = cf->ctx; struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten; - CURLcode result = CURLE_SEND_ERROR; + size_t nwritten; + CURLcode result; DEBUGASSERT(data); if(blen < 0) return 0; - nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, FALSE, - &result); - CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d", - blen, (int)nwritten, result); + result = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, FALSE, + &nwritten); + CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, %zu", + blen, result, nwritten); BIO_clear_retry_flags(bio); octx->io_result = result; - if(nwritten < 0) { + if(result) { if(CURLE_AGAIN == result) BIO_set_retry_write(bio); + return -1; } return (int)nwritten; } @@ -741,8 +750,8 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) struct ssl_connect_data *connssl = cf->ctx; struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nread; - CURLcode result = CURLE_RECV_ERROR; + size_t nread; + CURLcode result, r2; DEBUGASSERT(data); /* OpenSSL catches this case, so should we. */ @@ -751,31 +760,33 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen) if(blen < 0) return 0; - nread = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &result); - CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d", - blen, (int)nread, result); + result = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &nread); + CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, %zu", + blen, result, nread); BIO_clear_retry_flags(bio); octx->io_result = result; - if(nread < 0) { + if(result) { if(CURLE_AGAIN == result) BIO_set_retry_read(bio); } - else if(nread == 0) { - connssl->peer_closed = TRUE; + else { + /* feeding data to OpenSSL means SSL_read() might succeed */ + connssl->input_pending = TRUE; + if(nread == 0) + connssl->peer_closed = TRUE; } /* Before returning server replies to the SSL instance, we need * to have setup the x509 store or verification will fail. */ if(!octx->x509_store_setup) { - result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); - if(result) { - octx->io_result = result; + r2 = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx); + if(r2) { + octx->io_result = r2; return -1; } octx->x509_store_setup = TRUE; } - - return (int)nread; + return result ? -1 : (int)nread; } #if OPENSSL_VERSION_NUMBER < 0x10100000L @@ -993,7 +1004,7 @@ static CURLcode ossl_seed(struct Curl_easy *data) size_t i, i_max; for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) { struct curltime tv = curlx_now(); - Curl_wait_ms(1); + curlx_wait_ms(1); tv.tv_sec *= (time_t)i + 1; tv.tv_usec *= (int)i + 2; tv.tv_sec ^= ((curlx_now().tv_sec + (time_t)curlx_now().tv_usec) * @@ -1046,15 +1057,15 @@ static int ossl_do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(strcasecompare(type, "PEM")) + if(curl_strequal(type, "PEM")) return SSL_FILETYPE_PEM; - if(strcasecompare(type, "DER")) + if(curl_strequal(type, "DER")) return SSL_FILETYPE_ASN1; - if(strcasecompare(type, "PROV")) + if(curl_strequal(type, "PROV")) return SSL_FILETYPE_PROVIDER; - if(strcasecompare(type, "ENG")) + if(curl_strequal(type, "ENG")) return SSL_FILETYPE_ENGINE; - if(strcasecompare(type, "P12")) + if(curl_strequal(type, "P12")) return SSL_FILETYPE_PKCS12; return -1; } @@ -1107,7 +1118,7 @@ static int ssl_ui_writer(UI *ui, UI_STRING *uis) */ static bool is_pkcs11_uri(const char *string) { - return string && strncasecompare(string, "pkcs11:", 7); + return string && curl_strnequal(string, "pkcs11:", 7); } #endif @@ -1373,7 +1384,7 @@ int cert_stuff(struct Curl_easy *data, { /* Implicitly use pkcs11 provider if none was provided and the * cert_file is a PKCS#11 URI */ - if(!data->state.provider) { + if(!data->state.provider_loaded) { if(is_pkcs11_uri(cert_file)) { if(ossl_set_provider(data, "pkcs11") != CURLE_OK) { return 0; @@ -1381,7 +1392,7 @@ int cert_stuff(struct Curl_easy *data, } } - if(data->state.provider) { + if(data->state.provider_loaded) { /* Load the certificate from the provider */ OSSL_STORE_INFO *info = NULL; X509 *cert = NULL; @@ -1626,7 +1637,7 @@ int cert_stuff(struct Curl_easy *data, { /* Implicitly use pkcs11 provider if none was provided and the * key_file is a PKCS#11 URI */ - if(!data->state.provider) { + if(!data->state.provider_loaded) { if(is_pkcs11_uri(key_file)) { if(ossl_set_provider(data, "pkcs11") != CURLE_OK) { return 0; @@ -1634,7 +1645,7 @@ int cert_stuff(struct Curl_easy *data, } } - if(data->state.provider) { + if(data->state.provider_loaded) { /* Load the private key from the provider */ EVP_PKEY *priv_key = NULL; OSSL_STORE_CTX *store = NULL; @@ -1896,6 +1907,9 @@ static CURLcode ossl_set_engine(struct Curl_easy *data, const char *name) result = CURLE_SSL_ENGINE_INITFAILED; e = NULL; } + else { + result = CURLE_OK; + } data->state.engine = e; return result; } @@ -2017,6 +2031,14 @@ static CURLcode ossl_set_provider(struct Curl_easy *data, const char *iname) data->state.libctx = libctx; } +#ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG + /* load the configuration file into the library context before checking the + * provider availability */ + if(!OSSL_LIB_CTX_load_config(data->state.libctx, NULL)) { + infof(data, "Failed to load default openssl config. Proceeding."); + } +#endif + if(OSSL_PROVIDER_available(data->state.libctx, name)) { /* already loaded through the configuration - no action needed */ data->state.provider_loaded = TRUE; @@ -2162,6 +2184,8 @@ static CURLcode ossl_shutdown(struct Curl_cfilter *cf, out: cf->shutdown = (result || *done); + if(cf->shutdown || (connssl->io_need != CURL_SSL_IO_NEED_NONE)) + connssl->input_pending = FALSE; return result; } @@ -2173,6 +2197,7 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data) (void)data; DEBUGASSERT(octx); + connssl->input_pending = FALSE; if(octx->ssl) { SSL_free(octx->ssl); octx->ssl = NULL; @@ -2843,8 +2868,8 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) long curl_ssl_version_max; /* convert curl min SSL version option to OpenSSL constant */ -#if (defined(OPENSSL_IS_BORINGSSL) || \ - defined(OPENSSL_IS_AWSLC) || \ +#if (defined(OPENSSL_IS_BORINGSSL) || \ + defined(OPENSSL_IS_AWSLC) || \ defined(LIBRESSL_VERSION_NUMBER)) uint16_t ossl_ssl_version_min = 0; uint16_t ossl_ssl_version_max = 0; @@ -4048,7 +4073,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, CVE-2010-4180 when using previous OpenSSL versions we no longer enable this option regardless of OpenSSL version and SSL_OP_ALL definition. - OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability: + OpenSSL added a work-around for an SSL 3.0/TLS 1.0 CBC vulnerability: https://web.archive.org/web/20240114184648/openssl.org/~bodo/tls-cbc.txt. In 0.9.6e they added a bit to SSL_OP_ALL that _disables_ that work-around despite the fact that SSL_OP_ALL is documented to do "rather harmless" @@ -4110,6 +4135,21 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, } SSL_CTX_set_options(octx->ssl_ctx, ctx_options); + SSL_CTX_set_read_ahead(octx->ssl_ctx, 1); + + /* Max TLS1.2 record size 0x4000 + 0x800. + OpenSSL supports processing "jumbo TLS record" (8 TLS records) in one go + for some algorithms, so match that here. + Experimentation shows that a slightly larger buffer is needed + to avoid short reads. + + However using a large buffer (8 packets) actually decreases performance. + 4 packets is better. + */ + +#ifdef HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN + SSL_CTX_set_default_read_buffer_len(octx->ssl_ctx, 0x401e * 4); +#endif #ifdef SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER /* We do retry writes sometimes from another buffer address */ @@ -4294,6 +4334,38 @@ static CURLcode ossl_on_session_reuse(struct Curl_cfilter *cf, return result; } +void Curl_ossl_report_handshake(struct Curl_easy *data, + struct ossl_ctx *octx) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_is_verbose(data)) { + int psigtype_nid = NID_undef; + const char *negotiated_group_name = NULL; + +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid); +#if (OPENSSL_VERSION_NUMBER >= 0x30200000L) + negotiated_group_name = SSL_get0_group_name(octx->ssl); +#else + negotiated_group_name = + OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF); +#endif +#endif + + /* Informational message */ + infof(data, "SSL connection using %s / %s / %s / %s", + SSL_get_version(octx->ssl), + SSL_get_cipher(octx->ssl), + negotiated_group_name ? negotiated_group_name : "[blank]", + OBJ_nid2sn(psigtype_nid)); + } +#else + (void)data; + (void)octx; +#endif /* CURL_DISABLE_VERBOSE_STRINGS */ + +} + static CURLcode ossl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { @@ -4559,28 +4631,9 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, } } else { - int psigtype_nid = NID_undef; - const char *negotiated_group_name = NULL; - /* we connected fine, we are not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; - -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid); -#if (OPENSSL_VERSION_NUMBER >= 0x30200000L) - negotiated_group_name = SSL_get0_group_name(octx->ssl); -#else - negotiated_group_name = - OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF); -#endif -#endif - - /* Informational message */ - infof(data, "SSL connection using %s / %s / %s / %s", - SSL_get_version(octx->ssl), - SSL_get_cipher(octx->ssl), - negotiated_group_name ? negotiated_group_name : "[blank]", - OBJ_nid2sn(psigtype_nid)); + Curl_ossl_report_handshake(data, octx); #ifdef USE_ECH_OPENSSL # if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) @@ -4637,10 +4690,10 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, infof(data, "ECH: ech-hard failed"); return CURLE_SSL_CONNECT_ERROR; } - } - else { + } + else { infof(data, "ECH: result: status is not attempted"); - } + } # endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */ #endif /* USE_ECH_OPENSSL */ @@ -5193,20 +5246,15 @@ static bool ossl_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; - struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; - (void)data; - DEBUGASSERT(connssl && octx); - if(octx->ssl && SSL_pending(octx->ssl)) - return TRUE; - return FALSE; + return connssl->input_pending; } -static ssize_t ossl_send(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *mem, - size_t len, - CURLcode *curlcode) +static CURLcode ossl_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, + size_t len, + size_t *pnwritten) { /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ @@ -5214,39 +5262,39 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, char error_buffer[256]; sslerr_t sslerror; int memlen; - int rc; struct ssl_connect_data *connssl = cf->ctx; struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; + CURLcode result = CURLE_OK; + int nwritten; (void)data; DEBUGASSERT(octx); - + *pnwritten = 0; ERR_clear_error(); connssl->io_need = CURL_SSL_IO_NEED_NONE; memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - rc = SSL_write(octx->ssl, mem, memlen); + nwritten = SSL_write(octx->ssl, mem, memlen); - if(rc <= 0) { - err = SSL_get_error(octx->ssl, rc); + if(nwritten > 0) + *pnwritten = (size_t)nwritten; + else { + err = SSL_get_error(octx->ssl, nwritten); switch(err) { case SSL_ERROR_WANT_READ: connssl->io_need = CURL_SSL_IO_NEED_RECV; - *curlcode = CURLE_AGAIN; - rc = -1; + result = CURLE_AGAIN; goto out; case SSL_ERROR_WANT_WRITE: - *curlcode = CURLE_AGAIN; - rc = -1; + result = CURLE_AGAIN; goto out; case SSL_ERROR_SYSCALL: { int sockerr = SOCKERRNO; if(octx->io_result == CURLE_AGAIN) { - *curlcode = CURLE_AGAIN; - rc = -1; + result = CURLE_AGAIN; goto out; } sslerror = ERR_get_error(); @@ -5260,8 +5308,7 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d", error_buffer, sockerr); - *curlcode = CURLE_SEND_ERROR; - rc = -1; + result = CURLE_SEND_ERROR; goto out; } case SSL_ERROR_SSL: { @@ -5270,49 +5317,50 @@ static ssize_t ossl_send(struct Curl_cfilter *cf, sslerror = ERR_get_error(); failf(data, "SSL_write() error: %s", ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); - *curlcode = CURLE_SEND_ERROR; - rc = -1; + result = CURLE_SEND_ERROR; goto out; } default: /* a true error */ failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d", SSL_ERROR_to_str(err), SOCKERRNO); - *curlcode = CURLE_SEND_ERROR; - rc = -1; + result = CURLE_SEND_ERROR; goto out; } } - *curlcode = CURLE_OK; out: - return (ssize_t)rc; /* number of bytes */ + return result; } -static ssize_t ossl_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, /* transfer */ - char *buf, /* store read data here */ - size_t buffersize, /* max amount to read */ - CURLcode *curlcode) +static CURLcode ossl_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, /* transfer */ + char *buf, /* store read data here */ + size_t buffersize, /* max amount to read */ + size_t *pnread) { char error_buffer[256]; unsigned long sslerror; - ssize_t nread; int buffsize; struct connectdata *conn = cf->conn; struct ssl_connect_data *connssl = cf->ctx; struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend; + CURLcode result = CURLE_OK; + int nread; (void)data; DEBUGASSERT(octx); + *pnread = 0; ERR_clear_error(); connssl->io_need = CURL_SSL_IO_NEED_NONE; buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - nread = (ssize_t)SSL_read(octx->ssl, buf, buffsize); + nread = SSL_read(octx->ssl, buf, buffsize); - if(nread <= 0) { + if(nread > 0) + *pnread = (size_t)nread; + else { /* failed SSL_read */ int err = SSL_get_error(octx->ssl, (int)nread); @@ -5327,21 +5375,18 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf, connclose(conn, "TLS close_notify"); break; case SSL_ERROR_WANT_READ: - *curlcode = CURLE_AGAIN; - nread = -1; + result = CURLE_AGAIN; goto out; case SSL_ERROR_WANT_WRITE: connssl->io_need = CURL_SSL_IO_NEED_SEND; - *curlcode = CURLE_AGAIN; - nread = -1; + result = CURLE_AGAIN; goto out; default: /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return value/errno" */ /* https://docs.openssl.org/master/man3/ERR_get_error/ */ if(octx->io_result == CURLE_AGAIN) { - *curlcode = CURLE_AGAIN; - nread = -1; + result = CURLE_AGAIN; goto out; } sslerror = ERR_get_error(); @@ -5358,40 +5403,50 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf, SSL_ERROR_to_str(err)); failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", error_buffer, sockerr); - *curlcode = CURLE_RECV_ERROR; - nread = -1; + result = CURLE_RECV_ERROR; goto out; } - /* For debug builds be a little stricter and error on any - SSL_ERROR_SYSCALL. For example a server may have closed the connection - abruptly without a close_notify alert. For compatibility with older - peers we do not do this by default. #4624 - - We can use this to gauge how many users may be affected, and - if it goes ok eventually transition to allow in dev and release with - the newest OpenSSL: #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) */ -#ifdef DEBUGBUILD - if(err == SSL_ERROR_SYSCALL) { - int sockerr = SOCKERRNO; - if(sockerr) - Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + else if(err == SSL_ERROR_SYSCALL) { + if(octx->io_result) { + /* logging handling in underlying filter already */ + result = octx->io_result; + } + else if(connssl->peer_closed) { + failf(data, "Connection closed abruptly"); + result = CURLE_RECV_ERROR; + } else { - msnprintf(error_buffer, sizeof(error_buffer), - "Connection closed abruptly"); + /* We should no longer get here nowadays. But handle + * the error in case of some weirdness in the OSSL stack */ + int sockerr = SOCKERRNO; + if(sockerr) + Curl_strerror(sockerr, error_buffer, sizeof(error_buffer)); + else { + msnprintf(error_buffer, sizeof(error_buffer), + "Connection closed abruptly"); + } + failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d", + error_buffer, sockerr); + result = CURLE_RECV_ERROR; } - failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d" - " (Fatal because this is a curl debug build)", - error_buffer, sockerr); - *curlcode = CURLE_RECV_ERROR; - nread = -1; goto out; } -#endif } } out: - return nread; + if((!result && !*pnread) || (result == CURLE_AGAIN)) { + /* This happens when: + * - we read an EOF + * - OpenSSLs buffers are empty, there is no more data + * - OpenSSL read is blocked on writing something first + * - an incomplete TLS packet is buffered that cannot be read + * until more data arrives */ + connssl->input_pending = FALSE; + } + CURL_TRC_CF(data, cf, "ossl_recv(len=%zu) -> %d, %zu (in_pending=%d)", + buffersize, result, *pnread, connssl->input_pending); + return result; } static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, @@ -5485,7 +5540,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) size_t count; const char *ver = OpenSSL_version(OPENSSL_VERSION); const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */ - if(strncasecompare(ver, expected, sizeof(expected) - 1)) { + if(curl_strnequal(ver, expected, sizeof(expected) - 1)) { ver += sizeof(expected) - 1; } count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); @@ -5643,7 +5698,6 @@ const struct Curl_ssl Curl_ssl_openssl = { ossl_set_engine, /* set_engine or provider */ ossl_set_engine_default, /* set_engine_default */ ossl_engines_list, /* engines_list */ - NULL, /* false_start */ #ifndef OPENSSL_NO_SHA256 ossl_sha256sum, /* sha256sum */ #else diff --git a/vendor/curl/lib/vtls/openssl.h b/vendor/curl/lib/vtls/openssl.h index 8d063e25..1338eafb 100644 --- a/vendor/curl/lib/vtls/openssl.h +++ b/vendor/curl/lib/vtls/openssl.h @@ -142,5 +142,9 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, struct ossl_ctx *octx, struct ssl_peer *peer); +/* Report properties of a successful handshake */ +void Curl_ossl_report_handshake(struct Curl_easy *data, + struct ossl_ctx *octx); + #endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ diff --git a/vendor/curl/lib/vtls/rustls.c b/vendor/curl/lib/vtls/rustls.c index cb9fd623..4e1b78a7 100644 --- a/vendor/curl/lib/vtls/rustls.c +++ b/vendor/curl/lib/vtls/rustls.c @@ -43,6 +43,10 @@ #include "cipher_suite.h" #include "x509asn1.h" +/* The last #include files should be: */ +#include "../curl_memory.h" +#include "../memdebug.h" + struct rustls_ssl_backend_data { const struct rustls_client_config *config; @@ -101,9 +105,11 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n) struct ssl_connect_data *const connssl = io_ctx->cf->ctx; CURLcode result; int ret = 0; - ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data, - (char *)buf, len, &result); - if(nread < 0) { + size_t nread; + + result = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data, + (char *)buf, len, &nread); + if(result) { nread = 0; /* !checksrc! disable ERRNOVAR 4 */ if(CURLE_AGAIN == result) @@ -114,8 +120,8 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n) else if(nread == 0) connssl->peer_closed = TRUE; *out_n = (uintptr_t)nread; - CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d", - len, nread, result); + CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %d, %zu", + len, result, nread); return ret; } @@ -125,10 +131,11 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n) const struct io_ctx *io_ctx = userdata; CURLcode result; int ret = 0; - ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data, - (const char *)buf, len, FALSE, - &result); - if(nwritten < 0) { + size_t nwritten; + + result = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data, + (const char *)buf, len, FALSE, &nwritten); + if(result) { nwritten = 0; if(CURLE_AGAIN == result) ret = EAGAIN; @@ -136,8 +143,8 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n) ret = EINVAL; } *out_n = (uintptr_t)nwritten; - CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d", - len, nwritten, result); + CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %d, %zu", + len, result, nwritten); return ret; } @@ -192,37 +199,37 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf, * buffer, and process packets, but will not consume bytes from Rustls' * plaintext output buffer. */ -static ssize_t +static CURLcode cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *plainbuf, size_t plainlen, CURLcode *err) + char *plainbuf, size_t plainlen, size_t *pnread) { const struct ssl_connect_data *const connssl = cf->ctx; struct rustls_ssl_backend_data *const backend = (struct rustls_ssl_backend_data *)connssl->backend; struct rustls_connection *rconn = NULL; + CURLcode result = CURLE_OK; size_t n = 0; - size_t plain_bytes_copied = 0; rustls_result rresult = 0; - ssize_t nread; bool eof = FALSE; DEBUGASSERT(backend); + *pnread = 0; rconn = backend->conn; - while(plain_bytes_copied < plainlen) { + while(*pnread < plainlen) { if(!backend->data_in_pending) { - if(tls_recv_more(cf, data, err) < 0) { - if(*err != CURLE_AGAIN) { - nread = -1; + if(tls_recv_more(cf, data, &result) < 0) { + if(result != CURLE_AGAIN) { goto out; } + result = CURLE_OK; break; } } rresult = rustls_connection_read(rconn, - (uint8_t *)plainbuf + plain_bytes_copied, - plainlen - plain_bytes_copied, + (uint8_t *)plainbuf + *pnread, + plainlen - *pnread, &n); if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) { backend->data_in_pending = FALSE; @@ -230,15 +237,13 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) { failf(data, "rustls: peer closed TCP connection " "without first closing TLS connection"); - *err = CURLE_RECV_ERROR; - nread = -1; + result = CURLE_RECV_ERROR; goto out; } else if(rresult != RUSTLS_RESULT_OK) { /* n always equals 0 in this case, do not need to check it */ rustls_failf(data, rresult, "rustls_connection_read"); - *err = CURLE_RECV_ERROR; - nread = -1; + result = CURLE_RECV_ERROR; goto out; } else if(n == 0) { @@ -249,27 +254,18 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data, break; } else { - plain_bytes_copied += n; + *pnread += n; } } - if(plain_bytes_copied) { - *err = CURLE_OK; - nread = (ssize_t)plain_bytes_copied; - } - else if(eof) { - *err = CURLE_OK; - nread = 0; - } - else { - *err = CURLE_AGAIN; - nread = -1; + if(!eof && !*pnread) { + result = CURLE_AGAIN; } out: - CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", - plainlen, nread, *err); - return nread; + CURL_TRC_CF(data, cf, "rustls_recv(len=%zu) -> %d, %zu", + plainlen, result, *pnread); + return result; } static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -317,9 +313,9 @@ static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data, * In that case, it will not read anything into Rustls' plaintext input buffer. * It will only drain Rustls' plaintext output buffer into the socket. */ -static ssize_t +static CURLcode cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *plainbuf, size_t plainlen, CURLcode *err) + const void *plainbuf, size_t plainlen, size_t *pnwritten) { const struct ssl_connect_data *const connssl = cf->ctx; struct rustls_ssl_backend_data *const backend = @@ -327,10 +323,11 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, struct rustls_connection *rconn = NULL; size_t plainwritten = 0; const unsigned char *buf = plainbuf; + CURLcode result = CURLE_OK; size_t blen = plainlen; - ssize_t nwritten = 0; DEBUGASSERT(backend); + *pnwritten = 0; rconn = backend->conn; DEBUGASSERT(rconn); @@ -341,18 +338,18 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, * if successful, deduct the previous plain bytes from the current * send. */ if(backend->plain_out_buffered) { - *err = cr_flush_out(cf, data, rconn); + result = cr_flush_out(cf, data, rconn); CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d", - backend->plain_out_buffered, *err); - if(*err) - return -1; + backend->plain_out_buffered, result); + if(result) + return result; if(blen > backend->plain_out_buffered) { blen -= backend->plain_out_buffered; buf += backend->plain_out_buffered; } else blen = 0; - nwritten += (ssize_t)backend->plain_out_buffered; + *pnwritten += (ssize_t)backend->plain_out_buffered; backend->plain_out_buffered = 0; } @@ -362,37 +359,35 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, rresult = rustls_connection_write(rconn, buf, blen, &plainwritten); if(rresult != RUSTLS_RESULT_OK) { rustls_failf(data, rresult, "rustls_connection_write"); - *err = CURLE_WRITE_ERROR; - return -1; + result = CURLE_WRITE_ERROR; + goto out; } else if(plainwritten == 0) { failf(data, "rustls_connection_write: EOF"); - *err = CURLE_WRITE_ERROR; - return -1; + result = CURLE_WRITE_ERROR; + goto out; } } - *err = cr_flush_out(cf, data, rconn); - if(*err) { - if(CURLE_AGAIN == *err) { + result = cr_flush_out(cf, data, rconn); + if(result) { + if(CURLE_AGAIN == result) { /* The TLS bytes may have been partially written, but we fail the * complete send() and remember how much we already added to Rustls. */ - CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain" - " bytes already to Rustls", blen); backend->plain_out_buffered = plainwritten; - if(nwritten) { - *err = CURLE_OK; - return (ssize_t)nwritten; + if(*pnwritten) { + result = CURLE_OK; } } - return -1; + goto out; } else - nwritten += (ssize_t)plainwritten; + *pnwritten += (ssize_t)plainwritten; - CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd", - plainlen, *err, nwritten); - return nwritten; +out: + CURL_TRC_CF(data, cf, "rustls_send(len=%zu) -> %d, %zd", + plainlen, result, *pnwritten); + return result; } /* A server certificate verify callback for Rustls that always returns @@ -864,7 +859,7 @@ init_config_builder_client_auth(struct Curl_easy *data, } else if(!conn_config->clientcert && ssl_config->key) { failf(data, "rustls: must provide certificate with key '%s'", - conn_config->clientcert); + ssl_config->key); return CURLE_SSL_CERTPROBLEM; } @@ -1181,8 +1176,9 @@ cr_connect(struct Curl_cfilter *cf, * send its FINISHED message off. We attempt to let it write * one more time. Oh my. */ + size_t nwritten; cr_set_negotiated_alpn(cf, data, rconn); - cr_send(cf, data, NULL, 0, &tmperr); + tmperr = cr_send(cf, data, NULL, 0, &nwritten); if(tmperr == CURLE_AGAIN) { connssl->io_need = CURL_SSL_IO_NEED_SEND; return CURLE_OK; @@ -1194,17 +1190,23 @@ cr_connect(struct Curl_cfilter *cf, { const uint16_t proto = rustls_connection_get_protocol_version(rconn); - const uint16_t cipher = - rustls_connection_get_negotiated_ciphersuite(rconn); - char buf[64] = ""; + const rustls_str ciphersuite_name = + rustls_connection_get_negotiated_ciphersuite_name(rconn); + const rustls_str kex_group_name = + rustls_connection_get_negotiated_key_exchange_group_name(rconn); const char *ver = "TLS version unknown"; if(proto == RUSTLS_TLS_VERSION_TLSV1_3) ver = "TLSv1.3"; if(proto == RUSTLS_TLS_VERSION_TLSV1_2) ver = "TLSv1.2"; - Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), TRUE); - infof(data, "rustls: handshake complete, %s, cipher: %s", - ver, buf); + infof(data, + "rustls: handshake complete, %s, ciphersuite: %.*s, " + "key exchange group: %.*s", + ver, + (int) ciphersuite_name.len, + ciphersuite_name.data, + (int) kex_group_name.len, + kex_group_name.data); } if(data->set.ssl.certinfo) { size_t num_certs = 0; @@ -1255,8 +1257,9 @@ cr_connect(struct Curl_cfilter *cf, DEBUGASSERT(wants_read || wants_write); if(wants_write) { + size_t nwritten; CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls."); - cr_send(cf, data, NULL, 0, &tmperr); + tmperr = cr_send(cf, data, NULL, 0, &nwritten); if(tmperr == CURLE_AGAIN) { CURL_TRC_CF(data, cf, "writing would block"); connssl->io_need = CURL_SSL_IO_NEED_SEND; @@ -1309,8 +1312,7 @@ cr_shutdown(struct Curl_cfilter *cf, struct rustls_ssl_backend_data *backend = (struct rustls_ssl_backend_data *)connssl->backend; CURLcode result = CURLE_OK; - ssize_t nwritten, nread; - size_t i; + size_t i, nread, nwritten; DEBUGASSERT(backend); if(!backend->conn || cf->shutdown) { @@ -1329,8 +1331,8 @@ cr_shutdown(struct Curl_cfilter *cf, } } - nwritten = cr_send(cf, data, NULL, 0, &result); - if(nwritten < 0) { + result = cr_send(cf, data, NULL, 0, &nwritten); + if(result) { if(result == CURLE_AGAIN) { connssl->io_need = CURL_SSL_IO_NEED_SEND; result = CURLE_OK; @@ -1343,26 +1345,23 @@ cr_shutdown(struct Curl_cfilter *cf, for(i = 0; i < 10; ++i) { char buf[1024]; - nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result); - if(nread <= 0) + result = cr_recv(cf, data, buf, (int)sizeof(buf), &nread); + if(result) break; } - if(nread > 0) { - /* still data coming in? */ - } - else if(nread == 0) { - /* We got the close notify alert and are done. */ - *done = TRUE; - } - else if(result == CURLE_AGAIN) { + if(result == CURLE_AGAIN) { connssl->io_need = CURL_SSL_IO_NEED_RECV; result = CURLE_OK; } - else { + else if(result) { DEBUGASSERT(result); CURL_TRC_CF(data, cf, "shutdown, error: %d", result); } + else if(nread == 0) { + /* We got the close notify alert and are done. */ + *done = TRUE; + } out: cf->shutdown = (result || *done); @@ -1434,7 +1433,6 @@ const struct Curl_ssl Curl_ssl_rustls = { NULL, /* set_engine */ NULL, /* set_engine_default */ NULL, /* engines_list */ - NULL, /* false_start */ NULL, /* sha256sum */ cr_recv, /* recv decrypted data */ cr_send, /* send data to encrypt */ diff --git a/vendor/curl/lib/vtls/schannel.c b/vendor/curl/lib/vtls/schannel.c index bea8eef8..2ac61ba7 100644 --- a/vendor/curl/lib/vtls/schannel.c +++ b/vendor/curl/lib/vtls/schannel.c @@ -42,9 +42,9 @@ #include "vtls.h" #include "vtls_int.h" #include "vtls_scache.h" -#include "../strcase.h" #include "../sendf.h" #include "../connect.h" /* for the connect timeout */ +#include "../strdup.h" #include "../strerror.h" #include "../select.h" /* for the socket readiness */ #include "../curlx/inet_pton.h" /* for IP addr SNI check */ @@ -598,7 +598,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, } if((fInCert || blob) && (data->set.ssl.cert_type) && - (!strcasecompare(data->set.ssl.cert_type, "P12"))) { + (!curl_strequal(data->set.ssl.cert_type, "P12"))) { failf(data, "schannel: certificate format compatibility error " " for %s", blob ? "(memory blob)" : data->set.ssl.primary.clientcert); @@ -897,7 +897,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, static CURLcode schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) { - ssize_t written = -1; + size_t written = 0; struct ssl_connect_data *connssl = cf->ctx; struct schannel_ssl_backend_data *backend = (struct schannel_ssl_backend_data *)connssl->backend; @@ -1128,18 +1128,18 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) "sending %lu bytes.", outbuf.cbBuffer)); /* send initial handshake data which is now stored in output buffer */ - written = Curl_conn_cf_send(cf->next, data, - outbuf.pvBuffer, outbuf.cbBuffer, FALSE, - &result); + result = Curl_conn_cf_send(cf->next, data, + outbuf.pvBuffer, outbuf.cbBuffer, FALSE, + &written); Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer); - if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) { + if((result != CURLE_OK) || (outbuf.cbBuffer != written)) { failf(data, "schannel: failed to send initial handshake data: " - "sent %zd of %lu bytes", written, outbuf.cbBuffer); + "sent %zu of %lu bytes", written, outbuf.cbBuffer); return CURLE_SSL_CONNECT_ERROR; } DEBUGF(infof(data, "schannel: sent initial handshake data: " - "sent %zd bytes", written)); + "sent %zu bytes", written)); backend->recv_unrecoverable_err = CURLE_OK; backend->recv_sspi_close_notify = FALSE; @@ -1161,7 +1161,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) (struct schannel_ssl_backend_data *)connssl->backend; struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); int i; - ssize_t nread = -1, written = -1; + size_t nread = 0, written = 0; unsigned char *reallocated_buffer; SecBuffer outbuf[3]; SecBufferDesc outbuf_desc; @@ -1229,12 +1229,12 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) for(;;) { if(doread) { /* read encrypted handshake data from socket */ - nread = Curl_conn_cf_recv(cf->next, data, - (char *) (backend->encdata_buffer + - backend->encdata_offset), - backend->encdata_length - - backend->encdata_offset, - &result); + result = Curl_conn_cf_recv(cf->next, data, + (char *) (backend->encdata_buffer + + backend->encdata_offset), + backend->encdata_length - + backend->encdata_offset, + &nread); if(result == CURLE_AGAIN) { connssl->io_need = CURL_SSL_IO_NEED_RECV; DEBUGF(infof(data, "schannel: failed to receive handshake, " @@ -1250,7 +1250,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* increase encrypted data buffer offset */ backend->encdata_offset += nread; backend->encdata_is_incomplete = FALSE; - SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread)); + SCH_DEV(infof(data, "schannel: encrypted data got %zu", nread)); } SCH_DEV(infof(data, @@ -1317,13 +1317,13 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) "sending %lu bytes.", outbuf[i].cbBuffer)); /* send handshake token to server */ - written = Curl_conn_cf_send(cf->next, data, - outbuf[i].pvBuffer, outbuf[i].cbBuffer, - FALSE, &result); + result = Curl_conn_cf_send(cf->next, data, + outbuf[i].pvBuffer, outbuf[i].cbBuffer, + FALSE, &written); if((result != CURLE_OK) || - (outbuf[i].cbBuffer != (size_t) written)) { + (outbuf[i].cbBuffer != written)) { failf(data, "schannel: failed to send next handshake data: " - "sent %zd of %lu bytes", written, outbuf[i].cbBuffer); + "sent %zu of %lu bytes", written, outbuf[i].cbBuffer); return CURLE_SSL_CONNECT_ERROR; } } @@ -1714,22 +1714,22 @@ static CURLcode schannel_connect(struct Curl_cfilter *cf, return CURLE_OK; } -static ssize_t +static CURLcode schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, CURLcode *err) + const void *buf, size_t len, size_t *pnwritten) { - ssize_t written = -1; size_t data_len = 0; unsigned char *ptr = NULL; struct ssl_connect_data *connssl = cf->ctx; SecBuffer outbuf[4]; SecBufferDesc outbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; - CURLcode result; + CURLcode result = CURLE_OK; struct schannel_ssl_backend_data *backend = (struct schannel_ssl_backend_data *)connssl->backend; DEBUGASSERT(backend); + *pnwritten = 0; /* check if the maximum stream sizes were queried */ if(backend->stream_sizes.cbMaximumMessage == 0) { @@ -1738,8 +1738,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, SECPKG_ATTR_STREAM_SIZES, &backend->stream_sizes); if(sspi_status != SEC_E_OK) { - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } } @@ -1753,8 +1752,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, backend->stream_sizes.cbTrailer; ptr = (unsigned char *) malloc(data_len); if(!ptr) { - *err = CURLE_OUT_OF_MEMORY; - return -1; + return CURLE_OUT_OF_MEMORY; } /* setup output buffers (header, data, trailer, empty) */ @@ -1777,7 +1775,6 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* check if the message was encrypted */ if(sspi_status == SEC_E_OK) { - written = 0; /* send the encrypted message including header, data and trailer */ len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer; @@ -1799,16 +1796,15 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, */ /* send entire message or fail */ - while(len > (size_t)written) { - ssize_t this_write = 0; + while(len > *pnwritten) { + size_t this_write = 0; int what; timediff_t timeout_ms = Curl_timeleft(data, NULL, FALSE); if(timeout_ms < 0) { /* we already got the timeout */ failf(data, "schannel: timed out sending data " - "(bytes sent: %zd)", written); - *err = CURLE_OPERATION_TIMEDOUT; - written = -1; + "(bytes sent: %zu)", *pnwritten); + result = CURLE_OPERATION_TIMEDOUT; break; } else if(!timeout_ms) @@ -1817,56 +1813,52 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - *err = CURLE_SEND_ERROR; - written = -1; + result = CURLE_SEND_ERROR; break; } else if(0 == what) { failf(data, "schannel: timed out sending data " - "(bytes sent: %zd)", written); - *err = CURLE_OPERATION_TIMEDOUT; - written = -1; + "(bytes sent: %zu)", *pnwritten); + result = CURLE_OPERATION_TIMEDOUT; break; } /* socket is writable */ - this_write = Curl_conn_cf_send(cf->next, data, - ptr + written, len - written, - FALSE, &result); + result = Curl_conn_cf_send(cf->next, data, + ptr + *pnwritten, len - *pnwritten, + FALSE, &this_write); if(result == CURLE_AGAIN) continue; else if(result != CURLE_OK) { - *err = result; - written = -1; break; } - written += this_write; + *pnwritten += this_write; } } else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) { - *err = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; } else{ - *err = CURLE_SEND_ERROR; + result = CURLE_SEND_ERROR; } Curl_safefree(ptr); - if(len == (size_t)written) + if(len == *pnwritten) /* Encrypted message including header, data and trailer entirely sent. The return value is the number of unencrypted bytes that were sent. */ - written = outbuf[1].cbBuffer; + *pnwritten = outbuf[1].cbBuffer; - return written; + return result; } -static ssize_t +static CURLcode schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *err) + char *buf, size_t len, size_t *pnread) { size_t size = 0; - ssize_t nread = -1; + size_t nread = 0; struct ssl_connect_data *connssl = cf->ctx; unsigned char *reallocated_buffer; size_t reallocated_length; @@ -1879,8 +1871,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; struct schannel_ssl_backend_data *backend = (struct schannel_ssl_backend_data *)connssl->backend; + CURLcode result = CURLE_OK; DEBUGASSERT(backend); + *pnread = 0; /**************************************************************************** * Do not return or set backend->recv_unrecoverable_err unless in the @@ -1899,7 +1893,6 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, */ SCH_DEV(infof(data, "schannel: client wants to read %zu bytes", len)); - *err = CURLE_OK; if(len && len <= backend->decdata_offset) { SCH_DEV(infof(data, @@ -1907,7 +1900,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto cleanup; } else if(backend->recv_unrecoverable_err) { - *err = backend->recv_unrecoverable_err; + result = backend->recv_unrecoverable_err; infof(data, "schannel: an unrecoverable error occurred in a prior call"); goto cleanup; } @@ -1933,7 +1926,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, reallocated_buffer = realloc(backend->encdata_buffer, reallocated_length); if(!reallocated_buffer) { - *err = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } @@ -1950,26 +1943,26 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, backend->encdata_offset, backend->encdata_length)); /* read encrypted data from socket */ - nread = Curl_conn_cf_recv(cf->next, data, - (char *)(backend->encdata_buffer + - backend->encdata_offset), - size, err); - if(*err) { - if(*err == CURLE_AGAIN) + result = Curl_conn_cf_recv(cf->next, data, + (char *)(backend->encdata_buffer + + backend->encdata_offset), + size, &nread); + if(result) { + if(result == CURLE_AGAIN) SCH_DEV(infof(data, "schannel: recv returned CURLE_AGAIN")); - else if(*err == CURLE_RECV_ERROR) + else if(result == CURLE_RECV_ERROR) infof(data, "schannel: recv returned CURLE_RECV_ERROR"); else - infof(data, "schannel: recv returned error %d", *err); + infof(data, "schannel: recv returned error %d", result); } else if(nread == 0) { backend->recv_connection_closed = TRUE; DEBUGF(infof(data, "schannel: server closed the connection")); } - else if(nread > 0) { - backend->encdata_offset += (size_t)nread; + else { + backend->encdata_offset += nread; backend->encdata_is_incomplete = FALSE; - SCH_DEV(infof(data, "schannel: encrypted data got %zd", nread)); + SCH_DEV(infof(data, "schannel: encrypted data got %zu", nread)); } } @@ -2019,7 +2012,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, reallocated_buffer = realloc(backend->decdata_buffer, reallocated_length); if(!reallocated_buffer) { - *err = CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; failf(data, "schannel: unable to re-allocate memory"); goto cleanup; } @@ -2070,7 +2063,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* check if server wants to renegotiate the connection context */ if(sspi_status == SEC_I_RENEGOTIATE) { infof(data, "schannel: remote party requests renegotiation"); - if(*err && *err != CURLE_AGAIN) { + if(result && result != CURLE_AGAIN) { infof(data, "schannel: cannot renegotiate, an error is pending"); goto cleanup; } @@ -2081,9 +2074,9 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->connecting_state = ssl_connect_2; connssl->io_need = CURL_SSL_IO_NEED_SEND; backend->recv_renegotiating = TRUE; - *err = schannel_connect(cf, data, &done); + result = schannel_connect(cf, data, &done); backend->recv_renegotiating = FALSE; - if(*err) { + if(result) { infof(data, "schannel: renegotiation failed"); goto cleanup; } @@ -2102,8 +2095,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* We received the close notify just fine, any error we got * from the lower filters afterwards (e.g. the socket), is not * an error on the TLS data stream. That one ended here. */ - if(*err == CURLE_RECV_ERROR) - *err = CURLE_OK; + if(result == CURLE_RECV_ERROR) + result = CURLE_OK; infof(data, "schannel: server close notification received (close_notify)"); goto cleanup; @@ -2111,8 +2104,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, } else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { backend->encdata_is_incomplete = TRUE; - if(!*err) - *err = CURLE_AGAIN; + if(!result) + result = CURLE_AGAIN; SCH_DEV(infof(data, "schannel: failed to decrypt data, need more data")); goto cleanup; } @@ -2122,7 +2115,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, failf(data, "schannel: failed to read data from server: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); #endif - *err = CURLE_RECV_ERROR; + result = CURLE_RECV_ERROR; goto cleanup; } } @@ -2142,28 +2135,16 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, The behavior here is a matter of debate. We do not want to be vulnerable to a truncation attack however there is some browser precedent for ignoring the close_notify for compatibility reasons. - - Additionally, Windows 2000 (v5.0) is a special case since it seems it - does not return close_notify. In that case if the connection was closed we - assume it was graceful (close_notify) since there does not seem to be a - way to tell. */ if(len && !backend->decdata_offset && backend->recv_connection_closed && !backend->recv_sspi_close_notify) { - bool isWin2k = curlx_verify_windows_version(5, 0, 0, PLATFORM_WINNT, - VERSION_EQUAL); - - if(isWin2k && sspi_status == SEC_E_OK) - backend->recv_sspi_close_notify = TRUE; - else { - *err = CURLE_RECV_ERROR; - failf(data, "schannel: server closed abruptly (missing close_notify)"); - } + result = CURLE_RECV_ERROR; + failf(data, "schannel: server closed abruptly (missing close_notify)"); } /* Any error other than CURLE_AGAIN is an unrecoverable error. */ - if(*err && *err != CURLE_AGAIN) - backend->recv_unrecoverable_err = *err; + if(result && result != CURLE_AGAIN) + backend->recv_unrecoverable_err = result; size = len < backend->decdata_offset ? len : backend->decdata_offset; if(size) { @@ -2175,21 +2156,21 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, SCH_DEV(infof(data, "schannel: decrypted data buffer: offset %zu length %zu", backend->decdata_offset, backend->decdata_length)); - *err = CURLE_OK; - return (ssize_t)size; + *pnread = size; + return CURLE_OK; } - if(!*err && !backend->recv_connection_closed) - *err = CURLE_AGAIN; + if(!result && !backend->recv_connection_closed) + result = CURLE_AGAIN; /* it is debatable what to return when !len. We could return whatever error we got from decryption but instead we override here so the return is consistent. */ if(!len) - *err = CURLE_OK; + return CURLE_OK; - return *err ? -1 : 0; + return result; } static bool schannel_data_pending(struct Curl_cfilter *cf, @@ -2291,14 +2272,16 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) { /* send close message which is in output buffer */ - ssize_t written = Curl_conn_cf_send(cf->next, data, - outbuf.pvBuffer, outbuf.cbBuffer, - FALSE, &result); + size_t written; + + result = Curl_conn_cf_send(cf->next, data, + outbuf.pvBuffer, outbuf.cbBuffer, + FALSE, &written); Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer); if(!result) { - if(written < (ssize_t)outbuf.cbBuffer) { + if(written < outbuf.cbBuffer) { failf(data, "schannel: failed to send close msg: %s" - " (bytes written: %zd)", curl_easy_strerror(result), written); + " (bytes written: %zu)", curl_easy_strerror(result), written); result = CURLE_SEND_ERROR; goto out; } @@ -2329,23 +2312,23 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf, if(backend->cred && backend->ctxt && !backend->recv_sspi_close_notify && !backend->recv_connection_closed) { char buffer[1024]; - ssize_t nread; + size_t nread; - nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result); - if(nread > 0) { - /* still data coming in? */ + result = schannel_recv(cf, data, buffer, sizeof(buffer), &nread); + if(result == CURLE_AGAIN) { + connssl->io_need = CURL_SSL_IO_NEED_RECV; + } + else if(result) { + CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result); + result = CURLE_RECV_ERROR; } else if(nread == 0) { /* We got the close notify alert and are done. */ backend->recv_connection_closed = TRUE; *done = TRUE; } - else if(nread < 0 && result == CURLE_AGAIN) { - connssl->io_need = CURL_SSL_IO_NEED_RECV; - } else { - CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result); - result = CURLE_RECV_ERROR; + /* still data coming in? */ } } @@ -2770,7 +2753,6 @@ const struct Curl_ssl Curl_ssl_schannel = { NULL, /* set_engine */ NULL, /* set_engine_default */ NULL, /* engines_list */ - NULL, /* false_start */ schannel_sha256sum, /* sha256sum */ schannel_recv, /* recv decrypted data */ schannel_send, /* send data to encrypt */ diff --git a/vendor/curl/lib/vtls/schannel_int.h b/vendor/curl/lib/vtls/schannel_int.h index fe101254..511a852c 100644 --- a/vendor/curl/lib/vtls/schannel_int.h +++ b/vendor/curl/lib/vtls/schannel_int.h @@ -68,53 +68,51 @@ #endif #ifndef SCH_CREDENTIALS_VERSION - #define SCH_CREDENTIALS_VERSION 0x00000005 -typedef enum _eTlsAlgorithmUsage -{ - TlsParametersCngAlgUsageKeyExchange, - TlsParametersCngAlgUsageSignature, - TlsParametersCngAlgUsageCipher, - TlsParametersCngAlgUsageDigest, - TlsParametersCngAlgUsageCertSig +typedef enum _eTlsAlgorithmUsage { + TlsParametersCngAlgUsageKeyExchange, + TlsParametersCngAlgUsageSignature, + TlsParametersCngAlgUsageCipher, + TlsParametersCngAlgUsageDigest, + TlsParametersCngAlgUsageCertSig } eTlsAlgorithmUsage; -typedef struct _CRYPTO_SETTINGS -{ - eTlsAlgorithmUsage eAlgorithmUsage; - UNICODE_STRING strCngAlgId; - DWORD cChainingModes; - PUNICODE_STRING rgstrChainingModes; - DWORD dwMinBitLength; - DWORD dwMaxBitLength; +/* !checksrc! disable TYPEDEFSTRUCT 1 */ +typedef struct _CRYPTO_SETTINGS { + eTlsAlgorithmUsage eAlgorithmUsage; + UNICODE_STRING strCngAlgId; + DWORD cChainingModes; + PUNICODE_STRING rgstrChainingModes; + DWORD dwMinBitLength; + DWORD dwMaxBitLength; } CRYPTO_SETTINGS, * PCRYPTO_SETTINGS; -typedef struct _TLS_PARAMETERS -{ - DWORD cAlpnIds; - PUNICODE_STRING rgstrAlpnIds; - DWORD grbitDisabledProtocols; - DWORD cDisabledCrypto; - PCRYPTO_SETTINGS pDisabledCrypto; - DWORD dwFlags; +/* !checksrc! disable TYPEDEFSTRUCT 1 */ +typedef struct _TLS_PARAMETERS { + DWORD cAlpnIds; + PUNICODE_STRING rgstrAlpnIds; + DWORD grbitDisabledProtocols; + DWORD cDisabledCrypto; + PCRYPTO_SETTINGS pDisabledCrypto; + DWORD dwFlags; } TLS_PARAMETERS, * PTLS_PARAMETERS; -typedef struct _SCH_CREDENTIALS -{ - DWORD dwVersion; - DWORD dwCredFormat; - DWORD cCreds; - PCCERT_CONTEXT* paCred; - HCERTSTORE hRootStore; - - DWORD cMappers; - struct _HMAPPER **aphMappers; - - DWORD dwSessionLifespan; - DWORD dwFlags; - DWORD cTlsParameters; - PTLS_PARAMETERS pTlsParameters; +/* !checksrc! disable TYPEDEFSTRUCT 1 */ +typedef struct _SCH_CREDENTIALS { + DWORD dwVersion; + DWORD dwCredFormat; + DWORD cCreds; + PCCERT_CONTEXT* paCred; + HCERTSTORE hRootStore; + + DWORD cMappers; + struct _HMAPPER **aphMappers; + + DWORD dwSessionLifespan; + DWORD dwFlags; + DWORD cTlsParameters; + PTLS_PARAMETERS pTlsParameters; } SCH_CREDENTIALS, * PSCH_CREDENTIALS; #define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16 diff --git a/vendor/curl/lib/vtls/schannel_verify.c b/vendor/curl/lib/vtls/schannel_verify.c index efa24053..7db13f2a 100644 --- a/vendor/curl/lib/vtls/schannel_verify.c +++ b/vendor/curl/lib/vtls/schannel_verify.c @@ -78,6 +78,28 @@ #define BEGIN_CERT "-----BEGIN CERTIFICATE-----" #define END_CERT "\n-----END CERTIFICATE-----" +struct cert_chain_engine_config_win8 { + DWORD cbSize; + HCERTSTORE hRestrictedRoot; + HCERTSTORE hRestrictedTrust; + HCERTSTORE hRestrictedOther; + DWORD cAdditionalStore; + HCERTSTORE *rghAdditionalStore; + DWORD dwFlags; + DWORD dwUrlRetrievalTimeout; + DWORD MaximumCachedCertificates; + DWORD CycleDetectionModulus; + HCERTSTORE hExclusiveRoot; + HCERTSTORE hExclusiveTrustedPeople; + DWORD dwExclusiveFlags; +}; + +/* Not defined before mingw-w64 4.0.0 */ +#ifndef CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG +#define CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG 0x00000001 +#endif + +/* Legacy structure to supply size to Win7 clients */ struct cert_chain_engine_config_win7 { DWORD cbSize; HCERTSTORE hRestrictedRoot; @@ -331,7 +353,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store, } } - /* Null terminate the buffer */ + /* null-terminate the buffer */ ca_file_buffer[ca_file_bufsize] = '\0'; result = add_certs_data_to_store(trust_store, @@ -838,13 +860,22 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, } if(result == CURLE_OK) { - struct cert_chain_engine_config_win7 engine_config; + struct cert_chain_engine_config_win8 engine_config; BOOL create_engine_result; memset(&engine_config, 0, sizeof(engine_config)); - engine_config.cbSize = sizeof(engine_config); engine_config.hExclusiveRoot = trust_store; + /* Win8/Server2012 allows us to match partial chains */ + if(curlx_verify_windows_version(6, 2, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL) && + !ssl_config->no_partialchain) { + engine_config.cbSize = sizeof(engine_config); + engine_config.dwExclusiveFlags = CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG; + } + else + engine_config.cbSize = sizeof(struct cert_chain_engine_config_win7); + /* CertCreateCertificateChainEngine will check the expected size of the * CERT_CHAIN_ENGINE_CONFIG structure and fail if the specified size * does not match the expected size. When this occurs, it indicates that diff --git a/vendor/curl/lib/vtls/sectransp.c b/vendor/curl/lib/vtls/sectransp.c deleted file mode 100644 index 2ae2ef35..00000000 --- a/vendor/curl/lib/vtls/sectransp.c +++ /dev/null @@ -1,2708 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , et al. - * Copyright (C) Nick Zitzmann, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -/* - * Source file for all iOS and macOS Secure Transport-specific code for the - * TLS/SSL layer. No code but vtls.c should ever call or use these functions. - */ - -#include "../curl_setup.h" - -#ifdef USE_SECTRANSP - -#include "../urldata.h" /* for the Curl_easy definition */ -#include "../curlx/base64.h" -#include "../curlx/strparse.h" -#include "../multiif.h" -#include "../strcase.h" -#include "x509asn1.h" -#include "vtls_scache.h" -#include "../strerror.h" -#include "cipher_suite.h" - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif /* __clang__ */ - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Waddress" -#endif - -#if defined(__GNUC__) && defined(__APPLE__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif - -#include - -#include -/* For some reason, when building for iOS, the omnibus header above does - * not include SecureTransport.h as of iOS SDK 5.1. */ -#include -#include -#include - -/* The Security framework has changed greatly between iOS and different macOS - versions, and we will try to support as many of them as we can (back to - Leopard and iOS 5) by using macros and weak-linking. - - In general, you want to build this using the most recent OS SDK, since some - features require curl to be built against the latest SDK. TLS 1.1 and 1.2 - support, for instance, require the macOS 10.8 SDK or later. TLS 1.3 - requires the macOS 10.13 or iOS 11 SDK or later. */ -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 -#error "The Secure Transport backend requires Leopard or later." -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */ - -#define CURL_BUILD_IOS 0 -#define CURL_BUILD_IOS_7 0 -#define CURL_BUILD_IOS_9 0 -#define CURL_BUILD_IOS_11 0 -#define CURL_BUILD_IOS_13 0 -#define CURL_BUILD_MAC 1 -/* This is the maximum API level we are allowed to use when building: */ -#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 -#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 -#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 -#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 -#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 -#define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 -#define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 -#define CURL_BUILD_MAC_10_15 MAC_OS_X_VERSION_MAX_ALLOWED >= 101500 -/* These macros mean "the following code is present to allow runtime backward - compatibility with at least this cat or earlier": - (You set this at build-time using the compiler command line option - "-mmacosx-version-min.") */ -#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 -#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060 -#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 -#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080 -#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 - -#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE -#define CURL_BUILD_IOS 1 -#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 -#define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 -#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 -#define CURL_BUILD_IOS_13 __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 -#define CURL_BUILD_MAC 0 -#define CURL_BUILD_MAC_10_5 0 -#define CURL_BUILD_MAC_10_6 0 -#define CURL_BUILD_MAC_10_7 0 -#define CURL_BUILD_MAC_10_8 0 -#define CURL_BUILD_MAC_10_9 0 -#define CURL_BUILD_MAC_10_11 0 -#define CURL_BUILD_MAC_10_13 0 -#define CURL_BUILD_MAC_10_15 0 -#define CURL_SUPPORT_MAC_10_5 0 -#define CURL_SUPPORT_MAC_10_6 0 -#define CURL_SUPPORT_MAC_10_7 0 -#define CURL_SUPPORT_MAC_10_8 0 -#define CURL_SUPPORT_MAC_10_9 0 - -#else -#error "The Secure Transport backend requires iOS or macOS." -#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ - -#if CURL_BUILD_MAC -#include -#endif /* CURL_BUILD_MAC */ - -#include "../sendf.h" -#include "../curlx/inet_pton.h" -#include "../connect.h" -#include "../select.h" -#include "vtls.h" -#include "vtls_int.h" -#include "sectransp.h" -#include "../curl_printf.h" -#include "../strdup.h" - -#include "../curl_memory.h" -/* The last #include file should be: */ -#include "../memdebug.h" - - -/* From MacTypes.h (which we cannot include because it is not present in - iOS: */ -#define ioErr -36 -#define paramErr -50 - -struct st_ssl_backend_data { - SSLContextRef ssl_ctx; - bool ssl_direction; /* true if writing, false if reading */ - size_t ssl_write_buffered_length; - BIT(sent_shutdown); -}; - -/* Create the list of default ciphers to use by making an intersection of the - * ciphers supported by Secure Transport and the list below, using the order - * of the former. - * This list is based on TLS recommendations by Mozilla, balancing between - * security and wide compatibility: "Most ciphers that are not clearly broken - * and dangerous to use are supported" - */ -static const uint16_t default_ciphers[] = { - TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */ - TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */ - TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */ - -#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */ - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */ - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */ - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */ -#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ - -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */ - TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */ - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */ - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */ - TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */ - TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */ - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */ - TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */ - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */ - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */ - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */ - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */ - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */ - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */ - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */ - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */ -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - -#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */ - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */ - - /* TLSv1.3 is not supported by Secure Transport, but there is also other - * code referencing TLSv1.3, like: kTLSProtocol13 ? */ - TLS_AES_128_GCM_SHA256, /* 0x1301 */ - TLS_AES_256_GCM_SHA384, /* 0x1302 */ - TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */ -#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ -}; - -/* pinned public key support tests */ - -/* version 1 supports macOS 10.12+ and iOS 10+ */ -#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \ - (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)) -#define SECTRANSP_PINNEDPUBKEY_V1 1 -#endif - -/* version 2 supports macOS 10.7+ */ -#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) -#define SECTRANSP_PINNEDPUBKEY_V2 1 -#endif - -#if defined(SECTRANSP_PINNEDPUBKEY_V1) || defined(SECTRANSP_PINNEDPUBKEY_V2) -/* this backend supports CURLOPT_PINNEDPUBLICKEY */ -#define SECTRANSP_PINNEDPUBKEY 1 -#endif /* SECTRANSP_PINNEDPUBKEY */ - -#ifdef SECTRANSP_PINNEDPUBKEY -/* both new and old APIs return rsa keys missing the spki header (not DER) */ -static const unsigned char rsa4096SpkiHeader[] = { - 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, - 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00}; - -static const unsigned char rsa2048SpkiHeader[] = { - 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, - 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00}; -#ifdef SECTRANSP_PINNEDPUBKEY_V1 -/* the *new* version does not return DER encoded ecdsa certs like the old... */ -static const unsigned char ecDsaSecp256r1SpkiHeader[] = { - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, - 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, - 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, - 0x42, 0x00}; - -static const unsigned char ecDsaSecp384r1SpkiHeader[] = { - 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, - 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, - 0x00, 0x22, 0x03, 0x62, 0x00}; -#endif /* SECTRANSP_PINNEDPUBKEY_V1 */ -#endif /* SECTRANSP_PINNEDPUBKEY */ - -static OSStatus sectransp_bio_cf_in_read(SSLConnectionRef connection, - void *buf, - size_t *dataLength) /* IN/OUT */ -{ - const struct Curl_cfilter *cf = (const struct Curl_cfilter *)connection; - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nread; - CURLcode result; - OSStatus rtn = noErr; - - DEBUGASSERT(data); - nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result); - CURL_TRC_CF(data, cf, "bio_read(len=%zu) -> %zd, result=%d", - *dataLength, nread, result); - if(nread < 0) { - switch(result) { - case CURLE_OK: - case CURLE_AGAIN: - rtn = errSSLWouldBlock; - backend->ssl_direction = FALSE; - break; - default: - rtn = ioErr; - break; - } - nread = 0; - } - else if(nread == 0) { - rtn = errSSLClosedGraceful; - } - else if((size_t)nread < *dataLength) { - rtn = errSSLWouldBlock; - } - *dataLength = nread; - return rtn; -} - -static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection, - const void *buf, - size_t *dataLength) /* IN/OUT */ -{ - const struct Curl_cfilter *cf = (const struct Curl_cfilter *)connection; - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten; - CURLcode result; - OSStatus rtn = noErr; - - DEBUGASSERT(data); - nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, FALSE, - &result); - CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d", - *dataLength, nwritten, result); - if(nwritten <= 0) { - if(result == CURLE_AGAIN) { - rtn = errSSLWouldBlock; - backend->ssl_direction = TRUE; - } - else { - rtn = ioErr; - } - nwritten = 0; - } - else if((size_t)nwritten < *dataLength) { - rtn = errSSLWouldBlock; - } - *dataLength = nwritten; - return rtn; -} - -#if CURL_BUILD_MAC -CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) -{ - int mib[2]; - size_t os_version_len; - char buf[256]; - - /* Get the Darwin kernel version from the kernel using sysctl(): */ - mib[0] = CTL_KERN; - mib[1] = KERN_OSRELEASE; - if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1) - return; - if(os_version_len < sizeof(buf)) { - if(sysctl(mib, 2, buf, &os_version_len, NULL, 0) != -1) { - const char *os = buf; - curl_off_t fnum; - curl_off_t snum; - /* Parse the version: */ - if(!curlx_str_number(&os, &fnum, INT_MAX) && - !curlx_str_single(&os, '.') && - !curlx_str_number(&os, &snum, INT_MAX)) { - *major = (int)fnum; - *minor = (int)snum; - } - } - } -} -#endif /* CURL_BUILD_MAC */ - -/* Apple provides a myriad of ways of getting information about a certificate - into a string. Some are not available under iOS or newer cats. Here's a - unified function for getting a string describing the certificate that ought - to work in all cats starting with Leopard. */ -CF_INLINE CFStringRef getsubject(SecCertificateRef cert) -{ - CFStringRef server_cert_summary = CFSTR("(null)"); - -#if CURL_BUILD_IOS - /* iOS: There is only one way to do this. */ - server_cert_summary = SecCertificateCopySubjectSummary(cert); -#else -#if CURL_BUILD_MAC_10_7 - /* Lion & later: Get the long description if we can. */ - if(&SecCertificateCopyLongDescription) - server_cert_summary = - SecCertificateCopyLongDescription(NULL, cert, NULL); - else -#endif /* CURL_BUILD_MAC_10_7 */ -#if CURL_BUILD_MAC_10_6 - /* Snow Leopard: Get the certificate summary. */ - if(&SecCertificateCopySubjectSummary) - server_cert_summary = SecCertificateCopySubjectSummary(cert); - else -#endif /* CURL_BUILD_MAC_10_6 */ - /* Leopard is as far back as we go... */ - (void)SecCertificateCopyCommonName(cert, &server_cert_summary); -#endif /* CURL_BUILD_IOS */ - return server_cert_summary; -} - -static CURLcode CopyCertSubject(struct Curl_easy *data, - SecCertificateRef cert, char **certp) -{ - CFStringRef c = getsubject(cert); - CURLcode result = CURLE_OK; - const char *direct; - char *cbuf = NULL; - *certp = NULL; - - if(!c) { - failf(data, "SSL: invalid CA certificate subject"); - return CURLE_PEER_FAILED_VERIFICATION; - } - - /* If the subject is already available as UTF-8 encoded (ie 'direct') then - use that, else convert it. */ - direct = CFStringGetCStringPtr(c, kCFStringEncodingUTF8); - if(direct) { - *certp = strdup(direct); - if(!*certp) { - failf(data, "SSL: out of memory"); - result = CURLE_OUT_OF_MEMORY; - } - } - else { - size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1; - cbuf = calloc(1, cbuf_size); - if(cbuf) { - if(!CFStringGetCString(c, cbuf, (CFIndex)cbuf_size, - kCFStringEncodingUTF8)) { - failf(data, "SSL: invalid CA certificate subject"); - result = CURLE_PEER_FAILED_VERIFICATION; - } - else - /* pass back the buffer */ - *certp = cbuf; - } - else { - failf(data, "SSL: could not allocate %zu bytes of memory", cbuf_size); - result = CURLE_OUT_OF_MEMORY; - } - } - if(result) - free(cbuf); - CFRelease(c); - return result; -} - -#if CURL_SUPPORT_MAC_10_6 -/* The SecKeychainSearch API was deprecated in Lion, and using it will raise - deprecation warnings, so let's not compile this unless it is necessary: */ -static OSStatus CopyIdentityWithLabelOldSchool(char *label, - SecIdentityRef *out_c_a_k) -{ - OSStatus status = errSecItemNotFound; - SecKeychainAttributeList attr_list; - SecKeychainAttribute attr; - SecKeychainSearchRef search = NULL; - SecCertificateRef cert = NULL; - - /* Set up the attribute list: */ - attr_list.count = 1L; - attr_list.attr = &attr; - - /* Set up our lone search criterion: */ - attr.tag = kSecLabelItemAttr; - attr.data = label; - attr.length = (UInt32)strlen(label); - - /* Start searching: */ - status = SecKeychainSearchCreateFromAttributes(NULL, - kSecCertificateItemClass, - &attr_list, - &search); - if(status == noErr) { - status = SecKeychainSearchCopyNext(search, - (SecKeychainItemRef *)&cert); - if(status == noErr && cert) { - /* If we found a certificate, does it have a private key? */ - status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k); - CFRelease(cert); - } - } - - if(search) - CFRelease(search); - return status; -} -#endif /* CURL_SUPPORT_MAC_10_6 */ - -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; - - /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. - kSecClassIdentity was introduced in Lion. If both exist, let's use them - to find the certificate. */ - if(&SecItemCopyMatching && kSecClassIdentity) { - CFTypeRef keys[5]; - CFTypeRef values[5]; - CFDictionaryRef query_dict; - CFStringRef label_cf = CFStringCreateWithCString(NULL, label, - kCFStringEncodingUTF8); - - /* Set up our search criteria and expected results: */ - values[0] = kSecClassIdentity; /* we want a certificate and a key */ - keys[0] = kSecClass; - values[1] = kCFBooleanTrue; /* we want a reference */ - keys[1] = kSecReturnRef; - values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the - * label matching below worked correctly */ - keys[2] = kSecMatchLimit; - /* identity searches need a SecPolicyRef in order to work */ - values[3] = SecPolicyCreateSSL(FALSE, NULL); - keys[3] = kSecMatchPolicy; - /* match the name of the certificate (does not work in macOS 10.12.1) */ - values[4] = label_cf; - keys[4] = kSecAttrLabel; - query_dict = CFDictionaryCreate(NULL, (const void **)keys, - (const void **)values, 5L, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFRelease(values[3]); - - /* Do we have a match? */ - status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list); - - /* Because kSecAttrLabel matching does not work with kSecClassIdentity, - * we need to find the correct identity ourselves */ - 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; - const void *item = CFArrayGetValueAtIndex(keys_list, i); - SecIdentityRef identity = (SecIdentityRef)CURL_UNCONST(item); - err = SecIdentityCopyCertificate(identity, &cert); - if(err == noErr) { - CFStringRef common_name = NULL; - OSStatus copy_status = noErr; -#if CURL_BUILD_IOS - common_name = SecCertificateCopySubjectSummary(cert); -#elif CURL_BUILD_MAC_10_7 - copy_status = SecCertificateCopyCommonName(cert, &common_name); -#endif - if(copy_status == noErr && - CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) { - CFRelease(cert); - CFRelease(common_name); - CFRetain(identity); - *out_cert_and_key = identity; - status = noErr; - break; - } - if(common_name) - CFRelease(common_name); - } - CFRelease(cert); - } - } - - if(keys_list) - CFRelease(keys_list); - CFRelease(query_dict); - CFRelease(label_cf); - } - else { -#if CURL_SUPPORT_MAC_10_6 - /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */ - status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); -#endif /* CURL_SUPPORT_MAC_10_6 */ - } -#elif CURL_SUPPORT_MAC_10_6 - /* For developers building on older cats, we have no choice but to fall back - to SecKeychainSearch. */ - status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); -#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ - return status; -} - -static OSStatus CopyIdentityFromPKCS12File(const char *cPath, - const struct curl_blob *blob, - const char *cPassword, - SecIdentityRef *out_cert_and_key) -{ - OSStatus status = errSecItemNotFound; - CFURLRef pkcs_url = NULL; - CFStringRef password = cPassword ? CFStringCreateWithCString(NULL, - cPassword, kCFStringEncodingUTF8) : NULL; - CFDataRef pkcs_data = NULL; - - /* We can import P12 files on iOS or macOS 10.7 or later: */ - /* These constants are documented as having first appeared in 10.6 but they - raise linker errors when used on that cat for some reason. */ -#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS - bool resource_imported; - - if(blob) { - pkcs_data = CFDataCreate(kCFAllocatorDefault, - (const unsigned char *)blob->data, - (CFIndex)blob->len); - status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate; - resource_imported = (pkcs_data != NULL); - } - else { - pkcs_url = - CFURLCreateFromFileSystemRepresentation(NULL, - (const UInt8 *)cPath, - (CFIndex)strlen(cPath), FALSE); - resource_imported = - CFURLCreateDataAndPropertiesFromResource(NULL, - pkcs_url, &pkcs_data, - NULL, NULL, &status); - } - - if(resource_imported) { - CFArrayRef items = NULL; - - /* On iOS SecPKCS12Import will never add the client certificate to the - * Keychain. - * - * It gives us back a SecIdentityRef that we can use directly. */ -#if CURL_BUILD_IOS - const void *cKeys[] = {kSecImportExportPassphrase}; - const void *cValues[] = {password}; - CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues, - password ? 1L : 0L, NULL, NULL); - - if(options) { - status = SecPKCS12Import(pkcs_data, options, &items); - CFRelease(options); - } - - - /* On macOS SecPKCS12Import will always add the client certificate to - * the Keychain. - * - * As this does not match iOS, and apps may not want to see their client - * certificate saved in the user's keychain, we use SecItemImport - * with a NULL keychain to avoid importing it. - * - * This returns a SecCertificateRef from which we can construct a - * SecIdentityRef. - */ -#elif CURL_BUILD_MAC_10_7 - SecItemImportExportKeyParameters keyParams; - SecExternalFormat inputFormat = kSecFormatPKCS12; - SecExternalItemType inputType = kSecItemTypeCertificate; - - memset(&keyParams, 0x00, sizeof(keyParams)); - keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; - keyParams.passphrase = password; - - status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType, - 0, &keyParams, NULL, &items); -#endif - - - /* Extract the SecIdentityRef */ - if(status == errSecSuccess && items && CFArrayGetCount(items)) { - CFIndex i, count; - count = CFArrayGetCount(items); - - for(i = 0; i < count; i++) { - const CFTypeRef item = CFArrayGetValueAtIndex(items, i); - CFTypeID itemID = CFGetTypeID(item); - - if(itemID == CFDictionaryGetTypeID()) { - const CFTypeRef identity = CFDictionaryGetValue( - (CFDictionaryRef)item, - kSecImportItemIdentity); - CFRetain(identity); - *out_cert_and_key = (SecIdentityRef)CURL_UNCONST(identity); - break; - } -#if CURL_BUILD_MAC_10_7 - else if(itemID == SecCertificateGetTypeID()) { - status = SecIdentityCreateWithCertificate(NULL, - (SecCertificateRef)CURL_UNCONST(item), - out_cert_and_key); - break; - } -#endif - } - } - - if(items) - CFRelease(items); - CFRelease(pkcs_data); - } -#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ - if(password) - CFRelease(password); - if(pkcs_url) - CFRelease(pkcs_url); - return status; -} - -/* This code was borrowed from nss.c, with some modifications: - * Determine whether the nickname passed in is a filename that needs to - * be loaded as a PEM or a nickname. - * - * returns 1 for a file - * returns 0 for not a file - */ -CF_INLINE bool is_file(const char *filename) -{ - struct_stat st; - - if(!filename) - return FALSE; - - if(stat(filename, &st) == 0) - return S_ISREG(st.st_mode); - return FALSE; -} - -static CURLcode -sectransp_set_ssl_version_min_max(struct Curl_easy *data, - struct st_ssl_backend_data *backend, - struct ssl_primary_config *conn_config) -{ -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - OSStatus err; - SSLProtocol ver_min; - SSLProtocol ver_max; - -#if CURL_SUPPORT_MAC_10_7 - if(!&SSLSetProtocolVersionMax) - goto legacy; -#endif - - switch(conn_config->version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - ver_min = kTLSProtocol1; - break; - case CURL_SSLVERSION_TLSv1_1: - ver_min = kTLSProtocol11; - break; - case CURL_SSLVERSION_TLSv1_2: - ver_min = kTLSProtocol12; - break; - case CURL_SSLVERSION_TLSv1_3: - default: - failf(data, "SSL: unsupported minimum TLS version value"); - return CURLE_SSL_CONNECT_ERROR; - } - - switch(conn_config->version_max) { - case CURL_SSLVERSION_MAX_DEFAULT: - case CURL_SSLVERSION_MAX_NONE: - case CURL_SSLVERSION_MAX_TLSv1_3: - case CURL_SSLVERSION_MAX_TLSv1_2: - ver_max = kTLSProtocol12; - break; - case CURL_SSLVERSION_MAX_TLSv1_1: - ver_max = kTLSProtocol11; - break; - case CURL_SSLVERSION_MAX_TLSv1_0: - ver_max = kTLSProtocol1; - break; - default: - failf(data, "SSL: unsupported maximum TLS version value"); - return CURLE_SSL_CONNECT_ERROR; - } - - err = SSLSetProtocolVersionMin(backend->ssl_ctx, ver_min); - if(err != noErr) { - failf(data, "SSL: failed to set minimum TLS version"); - return CURLE_SSL_CONNECT_ERROR; - } - err = SSLSetProtocolVersionMax(backend->ssl_ctx, ver_max); - if(err != noErr) { - failf(data, "SSL: failed to set maximum TLS version"); - return CURLE_SSL_CONNECT_ERROR; - } - - return CURLE_OK; -#endif -#if CURL_SUPPORT_MAC_10_7 - goto legacy; -legacy: - switch(conn_config->version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - break; - default: - failf(data, "SSL: unsupported minimum TLS version value"); - return CURLE_SSL_CONNECT_ERROR; - } - - /* only TLS 1.0 is supported, disable SSL 3.0 and SSL 2.0 */ - SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, FALSE); - SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, TRUE); - - return CURLE_OK; -#endif -} - -static int sectransp_cipher_suite_get_str(uint16_t id, char *buf, - size_t buf_size, bool prefer_rfc) -{ - /* are these fortezza suites even supported ? */ - if(id == SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) - msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"); - else if(id == SSL_FORTEZZA_DMS_WITH_NULL_SHA) - msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_NULL_SHA"); - /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */ - else if(id == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) - msnprintf(buf, buf_size, "%s", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); - /* do we still need to support these SSL2-only ciphers ? */ - else if(id == SSL_RSA_WITH_RC2_CBC_MD5) - msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_RC2_CBC_MD5"); - else if(id == SSL_RSA_WITH_IDEA_CBC_MD5) - msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_IDEA_CBC_MD5"); - else if(id == SSL_RSA_WITH_DES_CBC_MD5) - msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_DES_CBC_MD5"); - else if(id == SSL_RSA_WITH_3DES_EDE_CBC_MD5) - msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_3DES_EDE_CBC_MD5"); - else - return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc); - return 0; -} - -static uint16_t sectransp_cipher_suite_walk_str(const char **str, - const char **end) -{ - uint16_t id = Curl_cipher_suite_walk_str(str, end); - size_t len = *end - *str; - - if(!id) { - /* are these fortezza suites even supported ? */ - if(strncasecompare("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", *str, len)) - id = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA; - else if(strncasecompare("SSL_FORTEZZA_DMS_WITH_NULL_SHA", *str, len)) - id = SSL_FORTEZZA_DMS_WITH_NULL_SHA; - /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */ - else if(strncasecompare("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", *str, len)) - id = TLS_EMPTY_RENEGOTIATION_INFO_SCSV; - /* do we still need to support these SSL2-only ciphers ? */ - else if(strncasecompare("SSL_RSA_WITH_RC2_CBC_MD5", *str, len)) - id = SSL_RSA_WITH_RC2_CBC_MD5; - else if(strncasecompare("SSL_RSA_WITH_IDEA_CBC_MD5", *str, len)) - id = SSL_RSA_WITH_IDEA_CBC_MD5; - else if(strncasecompare("SSL_RSA_WITH_DES_CBC_MD5", *str, len)) - id = SSL_RSA_WITH_DES_CBC_MD5; - else if(strncasecompare("SSL_RSA_WITH_3DES_EDE_CBC_MD5", *str, len)) - id = SSL_RSA_WITH_3DES_EDE_CBC_MD5; - } - return id; -} - -/* allocated memory must be freed */ -static SSLCipherSuite * sectransp_get_supported_ciphers(SSLContextRef ssl_ctx, - size_t *len) -{ - SSLCipherSuite *ciphers = NULL; - OSStatus err = noErr; - *len = 0; - - err = SSLGetNumberSupportedCiphers(ssl_ctx, len); - if(err != noErr) - goto failed; - - ciphers = malloc(*len * sizeof(SSLCipherSuite)); - if(!ciphers) - goto failed; - - err = SSLGetSupportedCiphers(ssl_ctx, ciphers, len); - if(err != noErr) - goto failed; - -#if CURL_BUILD_MAC - { - int maj = 0, min = 0; - GetDarwinVersionNumber(&maj, &min); - /* There is a known bug in early versions of Mountain Lion where ST's ECC - ciphers (cipher suite 0xC001 through 0xC032) simply do not work. - Work around the problem here by disabling those ciphers if we are - running in an affected version of macOS. */ - if(maj == 12 && min <= 3) { - size_t i = 0, j = 0; - for(; i < *len; i++) { - if(ciphers[i] >= 0xC001 && ciphers[i] <= 0xC032) - continue; - ciphers[j++] = ciphers[i]; - } - *len = j; - } - } -#endif - - return ciphers; -failed: - *len = 0; - Curl_safefree(ciphers); - return NULL; -} - -static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data, - SSLContextRef ssl_ctx) -{ - CURLcode ret = CURLE_SSL_CIPHER; - size_t count = 0, i, j; - OSStatus err; - size_t supported_len; - SSLCipherSuite *ciphers = NULL; - - ciphers = sectransp_get_supported_ciphers(ssl_ctx, &supported_len); - if(!ciphers) { - failf(data, "SSL: Failed to get supported ciphers"); - goto failed; - } - - /* Intersect the ciphers supported by Secure Transport with the default - * ciphers, using the order of the former. */ - for(i = 0; i < supported_len; i++) { - for(j = 0; j < CURL_ARRAYSIZE(default_ciphers); j++) { - if(default_ciphers[j] == ciphers[i]) { - ciphers[count++] = ciphers[i]; - break; - } - } - } - - if(count == 0) { - failf(data, "SSL: no supported default ciphers"); - goto failed; - } - - err = SSLSetEnabledCiphers(ssl_ctx, ciphers, count); - if(err != noErr) { - failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); - goto failed; - } - - ret = CURLE_OK; -failed: - Curl_safefree(ciphers); - return ret; -} - -static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data, - SSLContextRef ssl_ctx, - const char *ciphers) -{ - CURLcode ret = CURLE_SSL_CIPHER; - size_t count = 0, i; - const char *ptr, *end; - OSStatus err; - size_t supported_len; - SSLCipherSuite *supported = NULL; - SSLCipherSuite *selected = NULL; - - supported = sectransp_get_supported_ciphers(ssl_ctx, &supported_len); - if(!supported) { - failf(data, "SSL: Failed to get supported ciphers"); - goto failed; - } - - selected = malloc(supported_len * sizeof(SSLCipherSuite)); - if(!selected) { - failf(data, "SSL: Failed to allocate memory"); - goto failed; - } - - for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) { - uint16_t id = sectransp_cipher_suite_walk_str(&ptr, &end); - - /* Check if cipher is supported */ - if(id) { - for(i = 0; i < supported_len && supported[i] != id; i++); - if(i == supported_len) - id = 0; - } - if(!id) { - if(ptr[0] != '\0') - infof(data, "SSL: unknown cipher in list: \"%.*s\"", (int) (end - ptr), - ptr); - continue; - } - - /* No duplicates allowed (so selected cannot overflow) */ - for(i = 0; i < count && selected[i] != id; i++); - if(i < count) { - infof(data, "SSL: duplicate cipher in list: \"%.*s\"", (int) (end - ptr), - ptr); - continue; - } - - selected[count++] = id; - } - - if(count == 0) { - failf(data, "SSL: no supported cipher in list"); - goto failed; - } - - err = SSLSetEnabledCiphers(ssl_ctx, selected, count); - if(err != noErr) { - failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err); - goto failed; - } - - ret = CURLE_OK; -failed: - Curl_safefree(supported); - Curl_safefree(selected); - return ret; -} - -static void sectransp_session_free(void *sessionid) -{ - /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a - cached session ID inside the Security framework. There is a private - function that does this, but I do not want to have to explain to you why I - got your application rejected from the App Store due to the use of a - private API, so the best we can do is free up our own char array that we - created way back in sectransp_connect_step1... */ - Curl_safefree(sessionid); -} - -static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - const struct curl_blob *ssl_cablob = conn_config->ca_info_blob; - const char * const ssl_cafile = - /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ - (ssl_cablob ? NULL : conn_config->CAfile); - const bool verifypeer = conn_config->verifypeer; - char * const ssl_cert = ssl_config->primary.clientcert; - const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob; - char *ciphers; - OSStatus err = noErr; - CURLcode result; -#if CURL_BUILD_MAC - int darwinver_maj = 0, darwinver_min = 0; - - DEBUGASSERT(backend); - - CURL_TRC_CF(data, cf, "connect_step1"); - GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); -#endif /* CURL_BUILD_MAC */ - -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(&SSLCreateContext) { /* use the newer API if available */ - if(backend->ssl_ctx) - CFRelease(backend->ssl_ctx); - backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType); - if(!backend->ssl_ctx) { - failf(data, "SSL: could not create a context"); - return CURLE_OUT_OF_MEMORY; - } - } - else { - /* The old ST API does not exist under iOS, so do not compile it: */ -#if CURL_SUPPORT_MAC_10_8 - if(backend->ssl_ctx) - (void)SSLDisposeContext(backend->ssl_ctx); - err = SSLNewContext(FALSE, &(backend->ssl_ctx)); - if(err != noErr) { - failf(data, "SSL: could not create a context: OSStatus %d", err); - return CURLE_OUT_OF_MEMORY; - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#else - if(backend->ssl_ctx) - (void)SSLDisposeContext(backend->ssl_ctx); - err = SSLNewContext(FALSE, &(backend->ssl_ctx)); - if(err != noErr) { - failf(data, "SSL: could not create a context: OSStatus %d", err); - return CURLE_OUT_OF_MEMORY; - } -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */ - - result = sectransp_set_ssl_version_min_max(data, backend, conn_config); - if(result != CURLE_OK) - return result; - - if(connssl->alpn) { -#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 -#ifdef HAVE_BUILTIN_AVAILABLE - if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { -#else - if(&SSLSetALPNProtocols && &SSLCopyALPNProtocols) { -#endif - struct alpn_proto_buf proto; - size_t i; - CFStringRef cstr; - CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0, - &kCFTypeArrayCallBacks); - for(i = 0; i < connssl->alpn->count; ++i) { - cstr = CFStringCreateWithCString(NULL, connssl->alpn->entries[i], - kCFStringEncodingUTF8); - if(!cstr) - return CURLE_OUT_OF_MEMORY; - CFArrayAppendValue(alpnArr, cstr); - CFRelease(cstr); - } - err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr); - if(err != noErr) - infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d", - err); - CFRelease(alpnArr); - Curl_alpn_to_proto_str(&proto, connssl->alpn); - infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); - } -#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ - } - - if(ssl_config->key) { - infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " - "Transport. The private key must be in the Keychain."); - } - - if(ssl_cert || ssl_cert_blob) { - bool is_cert_data = ssl_cert_blob != NULL; - bool is_cert_file = (!is_cert_data) && is_file(ssl_cert); - SecIdentityRef cert_and_key = NULL; - - /* User wants to authenticate with a client cert. Look for it. Assume that - the user wants to use an identity loaded from the Keychain. If not, try - it as a file on disk */ - - if(!is_cert_data) - err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); - else - err = !noErr; - if((err != noErr) && (is_cert_file || is_cert_data)) { - if(!ssl_config->cert_type) - infof(data, "SSL: Certificate type not set, assuming " - "PKCS#12 format."); - else if(!strcasecompare(ssl_config->cert_type, "P12")) { - failf(data, "SSL: The Security framework only supports " - "loading identities that are in PKCS#12 format."); - return CURLE_SSL_CERTPROBLEM; - } - - err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob, - ssl_config->key_passwd, - &cert_and_key); - } - - if(err == noErr && cert_and_key) { - SecCertificateRef cert = NULL; - CFTypeRef certs_c[1]; - CFArrayRef certs; - - /* If we found one, print it out: */ - err = SecIdentityCopyCertificate(cert_and_key, &cert); - if(err == noErr) { - char *certp; - result = CopyCertSubject(data, cert, &certp); - if(!result) { - infof(data, "Client certificate: %s", certp); - free(certp); - } - - CFRelease(cert); - if(result == CURLE_PEER_FAILED_VERIFICATION) - return CURLE_SSL_CERTPROBLEM; - if(result) - return result; - } - certs_c[0] = cert_and_key; - certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, - &kCFTypeArrayCallBacks); - err = SSLSetCertificate(backend->ssl_ctx, certs); - if(certs) - CFRelease(certs); - if(err != noErr) { - failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err); - return CURLE_SSL_CERTPROBLEM; - } - CFRelease(cert_and_key); - } - else { - const char *cert_showfilename_error = - is_cert_data ? "(memory blob)" : ssl_cert; - - switch(err) { - case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ - failf(data, "SSL: Incorrect password for the certificate \"%s\" " - "and its private key.", cert_showfilename_error); - break; - case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ - failf(data, "SSL: Couldn't make sense of the data in the " - "certificate \"%s\" and its private key.", - cert_showfilename_error); - break; - case -25260: /* errSecPassphraseRequired */ - failf(data, "SSL The certificate \"%s\" requires a password.", - cert_showfilename_error); - break; - case errSecItemNotFound: - failf(data, "SSL: cannot find the certificate \"%s\" and its private " - "key in the Keychain.", cert_showfilename_error); - break; - default: - failf(data, "SSL: cannot load the certificate \"%s\" and its private " - "key: OSStatus %d", cert_showfilename_error, err); - break; - } - return CURLE_SSL_CERTPROBLEM; - } - } - - /* SSL always tries to verify the peer, this only says whether it should - * fail to connect if the verification fails, or if it should continue - * anyway. In the latter case the result of the verification is checked with - * SSL_get_verify_result() below. */ -#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS - /* Snow Leopard introduced the SSLSetSessionOption() function, but due to - a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag - works, it does not work as expected under Snow Leopard, Lion or - Mountain Lion. - So we need to call SSLSetEnableCertVerify() on those older cats in order - to disable certificate validation if the user turned that off. - (Secure Transport always validates the certificate chain by default.) - Note: - Darwin 11.x.x is Lion (10.7) - Darwin 12.x.x is Mountain Lion (10.8) - Darwin 13.x.x is Mavericks (10.9) - Darwin 14.x.x is Yosemite (10.10) - Darwin 15.x.x is El Capitan (10.11) - */ -#if CURL_BUILD_MAC - if(&SSLSetSessionOption && darwinver_maj >= 13) { -#else - if(&SSLSetSessionOption) { -#endif /* CURL_BUILD_MAC */ - bool break_on_auth = !conn_config->verifypeer || - ssl_cafile || ssl_cablob; - err = SSLSetSessionOption(backend->ssl_ctx, - kSSLSessionOptionBreakOnServerAuth, - break_on_auth); - if(err != noErr) { - failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - } - else { -#if CURL_SUPPORT_MAC_10_8 - err = SSLSetEnableCertVerify(backend->ssl_ctx, - conn_config->verifypeer ? true : FALSE); - if(err != noErr) { - failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#else - err = SSLSetEnableCertVerify(backend->ssl_ctx, - conn_config->verifypeer ? true : FALSE); - if(err != noErr) { - failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } -#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ - - if((ssl_cafile || ssl_cablob) && verifypeer) { - bool is_cert_data = ssl_cablob != NULL; - bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile); - - if(!(is_cert_file || is_cert_data)) { - failf(data, "SSL: cannot load CA certificate file %s", - ssl_cafile ? ssl_cafile : "(blob memory)"); - return CURLE_SSL_CACERT_BADFILE; - } - } - - /* Configure hostname check. SNI is used if available. - * Both hostname check and SNI require SSLSetPeerDomainName(). - * Also: the verifyhost setting influences SNI usage */ - if(conn_config->verifyhost) { - char *server = connssl->peer.sni ? - connssl->peer.sni : connssl->peer.hostname; - err = SSLSetPeerDomainName(backend->ssl_ctx, server, strlen(server)); - - if(err != noErr) { - failf(data, "SSL: SSLSetPeerDomainName() failed: OSStatus %d", - err); - return CURLE_SSL_CONNECT_ERROR; - } - - if(connssl->peer.type != CURL_SSL_PEER_DNS) { - infof(data, "WARNING: using IP address, SNI is being disabled by " - "the OS."); - } - } - else { - infof(data, "WARNING: disabling hostname validation also disables SNI."); - } - - ciphers = conn_config->cipher_list; - if(ciphers) { - result = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers); - } - else { - result = sectransp_set_default_ciphers(data, backend->ssl_ctx); - } - if(result != CURLE_OK) { - failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. " - "Error code: %d", (int)result); - return CURLE_SSL_CIPHER; - } - -#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - /* We want to enable 1/n-1 when using a CBC cipher unless the user - specifically does not want us doing that: */ - if(&SSLSetSessionOption) { - SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord, - !ssl_config->enable_beast); - SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart, - ssl_config->falsestart); /* false start support */ - } -#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ - - /* Check if there is a cached ID we can/should use here! */ - if(ssl_config->primary.cache_session) { - char *ssl_sessionid; - size_t ssl_sessionid_len; - - Curl_ssl_scache_lock(data); - ssl_sessionid = Curl_ssl_scache_get_obj(cf, data, - connssl->peer.scache_key); - if(ssl_sessionid) { - /* we got a session id, use it! */ - err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, - strlen(ssl_sessionid)); - Curl_ssl_scache_unlock(data); - if(err != noErr) { - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - else - infof(data, "SSL reusing session ID"); - } - /* If there is not one, then let's make one up! This has to be done prior - to starting the handshake. */ - else { - ssl_sessionid = - aprintf("%s:%d:%d:%s:%d", - ssl_cafile ? ssl_cafile : "(blob memory)", - verifypeer, conn_config->verifyhost, connssl->peer.hostname, - connssl->peer.port); - ssl_sessionid_len = strlen(ssl_sessionid); - - err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - if(err != noErr) { - Curl_ssl_scache_unlock(data); - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - - /* This is all a bit weird, as we have not handshaked yet. - * I hope this backend will go away soon. */ - result = Curl_ssl_scache_add_obj(cf, data, connssl->peer.scache_key, - (void *)ssl_sessionid, - sectransp_session_free); - Curl_ssl_scache_unlock(data); - if(result) - return result; - } - } - - err = SSLSetIOFuncs(backend->ssl_ctx, - sectransp_bio_cf_in_read, - sectransp_bio_cf_out_write); - if(err != noErr) { - failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - - err = SSLSetConnection(backend->ssl_ctx, cf); - if(err != noErr) { - failf(data, "SSL: SSLSetConnection() failed: %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - - connssl->connecting_state = ssl_connect_2; - return CURLE_OK; -} - -static long pem_to_der(const char *in, unsigned char **out, size_t *outlen) -{ - char *sep_start, *sep_end, *cert_start, *cert_end; - size_t i, j, err; - size_t len; - char *b64; - - /* Jump through the separators at the beginning of the certificate. */ - sep_start = strstr(in, "-----"); - if(!sep_start) - return 0; - cert_start = strstr(sep_start + 1, "-----"); - if(!cert_start) - return -1; - - cert_start += 5; - - /* Find separator after the end of the certificate. */ - cert_end = strstr(cert_start, "-----"); - if(!cert_end) - return -1; - - sep_end = strstr(cert_end + 1, "-----"); - if(!sep_end) - return -1; - sep_end += 5; - - len = cert_end - cert_start; - b64 = malloc(len + 1); - if(!b64) - return -1; - - /* Create base64 string without linefeeds. */ - for(i = 0, j = 0; i < len; i++) { - if(cert_start[i] != '\r' && cert_start[i] != '\n') - b64[j++] = cert_start[i]; - } - b64[j] = '\0'; - - err = curlx_base64_decode((const char *)b64, out, outlen); - free(b64); - if(err) { - free(*out); - return -1; - } - - return sep_end - in; -} - -#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */ - -static int read_cert(const char *file, unsigned char **out, size_t *outlen) -{ - int fd; - ssize_t n; - unsigned char buf[512]; - struct dynbuf certs; - - curlx_dyn_init(&certs, MAX_CERTS_SIZE); - - fd = open(file, 0); - if(fd < 0) - return -1; - - for(;;) { - n = read(fd, buf, sizeof(buf)); - if(!n) - break; - if(n < 0) { - close(fd); - curlx_dyn_free(&certs); - return -1; - } - if(curlx_dyn_addn(&certs, buf, n)) { - close(fd); - return -1; - } - } - close(fd); - - *out = curlx_dyn_uptr(&certs); - *outlen = curlx_dyn_len(&certs); - - return 0; -} - -static CURLcode append_cert_to_array(struct Curl_easy *data, - const unsigned char *buf, size_t buflen, - CFMutableArrayRef array) -{ - char *certp; - CURLcode result; - SecCertificateRef cacert; - CFDataRef certdata; - - certdata = CFDataCreate(kCFAllocatorDefault, buf, (CFIndex)buflen); - if(!certdata) { - failf(data, "SSL: failed to allocate array for CA certificate"); - return CURLE_OUT_OF_MEMORY; - } - - cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata); - CFRelease(certdata); - if(!cacert) { - failf(data, "SSL: failed to create SecCertificate from CA certificate"); - return CURLE_SSL_CACERT_BADFILE; - } - - /* Check if cacert is valid. */ - result = CopyCertSubject(data, cacert, &certp); - switch(result) { - case CURLE_OK: - break; - case CURLE_PEER_FAILED_VERIFICATION: - CFRelease(cacert); - return CURLE_SSL_CACERT_BADFILE; - case CURLE_OUT_OF_MEMORY: - default: - CFRelease(cacert); - return result; - } - free(certp); - - CFArrayAppendValue(array, cacert); - CFRelease(cacert); - - return CURLE_OK; -} - -static CURLcode verify_cert_buf(struct Curl_cfilter *cf, - struct Curl_easy *data, - const unsigned char *certbuf, size_t buflen, - SSLContextRef ctx) -{ - int n = 0; - CURLcode rc; - long res; - unsigned char *der; - size_t derlen, offset = 0; - OSStatus ret; - SecTrustResultType trust_eval; - CFMutableArrayRef array = NULL; - SecTrustRef trust = NULL; - CURLcode result = CURLE_PEER_FAILED_VERIFICATION; - (void)cf; - /* - * Certbuf now contains the contents of the certificate file, which can be - * - a single DER certificate, - * - a single PEM certificate or - * - a bunch of PEM certificates (certificate bundle). - * - * Go through certbuf, and convert any PEM certificate in it into DER - * format. - */ - array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if(!array) { - failf(data, "SSL: out of memory creating CA certificate array"); - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - while(offset < buflen) { - n++; - - /* - * Check if the certificate is in PEM format, and convert it to DER. If - * this fails, we assume the certificate is in DER format. - */ - res = pem_to_der((const char *)certbuf + offset, &der, &derlen); - if(res < 0) { - failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle", - n, offset); - result = CURLE_SSL_CACERT_BADFILE; - goto out; - } - offset += res; - - if(res == 0 && offset == 0) { - /* This is not a PEM file, probably a certificate in DER format. */ - rc = append_cert_to_array(data, certbuf, buflen, array); - if(rc != CURLE_OK) { - CURL_TRC_CF(data, cf, "append_cert for CA failed"); - result = rc; - goto out; - } - break; - } - else if(res == 0) { - /* No more certificates in the bundle. */ - break; - } - - rc = append_cert_to_array(data, der, derlen, array); - free(der); - if(rc != CURLE_OK) { - CURL_TRC_CF(data, cf, "append_cert for CA failed"); - result = rc; - goto out; - } - } - - ret = SSLCopyPeerTrust(ctx, &trust); - if(!trust) { - failf(data, "SSL: error getting certificate chain"); - goto out; - } - else if(ret != noErr) { - failf(data, "SSLCopyPeerTrust() returned error %d", ret); - goto out; - } - - CURL_TRC_CF(data, cf, "setting %d trust anchors", n); - ret = SecTrustSetAnchorCertificates(trust, array); - if(ret != noErr) { - failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret); - goto out; - } - ret = SecTrustSetAnchorCertificatesOnly(trust, TRUE); - if(ret != noErr) { - failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret); - goto out; - } - - trust_eval = 0; - ret = SecTrustEvaluate(trust, &trust_eval); - if(ret != noErr) { - failf(data, "SecTrustEvaluate() returned error %d", ret); - goto out; - } - - switch(trust_eval) { - case kSecTrustResultUnspecified: - /* what does this really mean? */ - CURL_TRC_CF(data, cf, "trust result: Unspecified"); - result = CURLE_OK; - goto out; - case kSecTrustResultProceed: - CURL_TRC_CF(data, cf, "trust result: Proceed"); - result = CURLE_OK; - goto out; - - case kSecTrustResultRecoverableTrustFailure: - failf(data, "SSL: peer not verified: RecoverableTrustFailure"); - goto out; - case kSecTrustResultDeny: - failf(data, "SSL: peer not verified: Deny"); - goto out; - default: - failf(data, "SSL: perr not verified: result=%d", trust_eval); - goto out; - } - -out: - if(trust) - CFRelease(trust); - if(array) - CFRelease(array); - return result; -} - -static CURLcode verify_cert(struct Curl_cfilter *cf, - struct Curl_easy *data, const char *cafile, - const struct curl_blob *ca_info_blob, - SSLContextRef ctx) -{ - CURLcode result; - unsigned char *certbuf; - size_t buflen; - bool free_certbuf = FALSE; - - if(ca_info_blob) { - CURL_TRC_CF(data, cf, "verify_peer, CA from config blob"); - certbuf = ca_info_blob->data; - buflen = ca_info_blob->len; - } - else if(cafile) { - CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile); - if(read_cert(cafile, &certbuf, &buflen) < 0) { - failf(data, "SSL: failed to read or invalid CA certificate"); - return CURLE_SSL_CACERT_BADFILE; - } - free_certbuf = TRUE; - } - else - return CURLE_SSL_CACERT_BADFILE; - - result = verify_cert_buf(cf, data, certbuf, buflen, ctx); - if(free_certbuf) - free(certbuf); - return result; -} - - -#ifdef SECTRANSP_PINNEDPUBKEY -static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, - SSLContextRef ctx, - const char *pinnedpubkey) -{ /* Scratch */ - size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24; - const unsigned char *pubkey = NULL; - unsigned char *realpubkey = NULL; - const unsigned char *spkiHeader = NULL; - CFDataRef publicKeyBits = NULL; - - /* Result is returned to caller */ - CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - - /* if a path was not specified, do not pin */ - if(!pinnedpubkey) - return CURLE_OK; - - - if(!ctx) - return result; - - do { - SecTrustRef trust; - OSStatus ret; - SecKeyRef keyRef; - - ret = SSLCopyPeerTrust(ctx, &trust); - if(ret != noErr || !trust) - break; - - keyRef = SecTrustCopyPublicKey(trust); - CFRelease(trust); - if(!keyRef) - break; - -#ifdef SECTRANSP_PINNEDPUBKEY_V1 - - publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL); - CFRelease(keyRef); - if(!publicKeyBits) - break; - -#elif SECTRANSP_PINNEDPUBKEY_V2 - - { - OSStatus success; - success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, - &publicKeyBits); - CFRelease(keyRef); - if(success != errSecSuccess || !publicKeyBits) - break; - } - -#endif /* SECTRANSP_PINNEDPUBKEY_V2 */ - - pubkeylen = (size_t)CFDataGetLength(publicKeyBits); - pubkey = (const unsigned char *)CFDataGetBytePtr(publicKeyBits); - - switch(pubkeylen) { - case 526: - /* 4096 bit RSA pubkeylen == 526 */ - spkiHeader = rsa4096SpkiHeader; - break; - case 270: - /* 2048 bit RSA pubkeylen == 270 */ - spkiHeader = rsa2048SpkiHeader; - break; -#ifdef SECTRANSP_PINNEDPUBKEY_V1 - case 65: - /* ecDSA secp256r1 pubkeylen == 65 */ - spkiHeader = ecDsaSecp256r1SpkiHeader; - spkiHeaderLength = 26; - break; - case 97: - /* ecDSA secp384r1 pubkeylen == 97 */ - spkiHeader = ecDsaSecp384r1SpkiHeader; - spkiHeaderLength = 23; - break; - default: - infof(data, "SSL: unhandled public key length: %zu", pubkeylen); -#elif SECTRANSP_PINNEDPUBKEY_V2 - default: - /* ecDSA secp256r1 pubkeylen == 91 header already included? - * ecDSA secp384r1 header already included too - * we assume rest of algorithms do same, so do nothing - */ - result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey, - pubkeylen); -#endif /* SECTRANSP_PINNEDPUBKEY_V2 */ - continue; /* break from loop */ - } - - realpubkeylen = pubkeylen + spkiHeaderLength; - realpubkey = malloc(realpubkeylen); - if(!realpubkey) - break; - - memcpy(realpubkey, spkiHeader, spkiHeaderLength); - memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen); - - result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey, - realpubkeylen); - - } while(0); - - Curl_safefree(realpubkey); - if(publicKeyBits) - CFRelease(publicKeyBits); - - return result; -} -#endif /* SECTRANSP_PINNEDPUBKEY */ - -static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); - OSStatus err; - SSLCipherSuite cipher; - SSLProtocol protocol = 0; - - DEBUGASSERT(ssl_connect_2 == connssl->connecting_state); - DEBUGASSERT(backend); - CURL_TRC_CF(data, cf, "connect_step2"); - - /* Here goes nothing: */ -check_handshake: - connssl->io_need = CURL_SSL_IO_NEED_NONE; - err = SSLHandshake(backend->ssl_ctx); - - if(err != noErr) { - switch(err) { - case errSSLWouldBlock: /* they are not done with us yet */ - connssl->io_need = backend->ssl_direction ? - CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV; - return CURLE_OK; - - /* The below is errSSLServerAuthCompleted; it is not defined in - Leopard's headers */ - case -9841: - if((conn_config->CAfile || conn_config->ca_info_blob) && - conn_config->verifypeer) { - CURLcode result = verify_cert(cf, data, conn_config->CAfile, - conn_config->ca_info_blob, - backend->ssl_ctx); - if(result) - return result; - } - /* the documentation says we need to call SSLHandshake() again */ - goto check_handshake; - - /* Problem with encrypt / decrypt */ - case errSSLPeerDecodeError: - failf(data, "Decode failed"); - break; - case errSSLDecryptionFail: - case errSSLPeerDecryptionFail: - failf(data, "Decryption failed"); - break; - case errSSLPeerDecryptError: - failf(data, "A decryption error occurred"); - break; - case errSSLBadCipherSuite: - failf(data, "A bad SSL cipher suite was encountered"); - break; - case errSSLCrypto: - failf(data, "An underlying cryptographic error was encountered"); - break; -#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9 - case errSSLWeakPeerEphemeralDHKey: - failf(data, "Indicates a weak ephemeral Diffie-Hellman key"); - break; -#endif - - /* Problem with the message record validation */ - case errSSLBadRecordMac: - case errSSLPeerBadRecordMac: - failf(data, "A record with a bad message authentication code (MAC) " - "was encountered"); - break; - case errSSLRecordOverflow: - case errSSLPeerRecordOverflow: - failf(data, "A record overflow occurred"); - break; - - /* Problem with zlib decompression */ - case errSSLPeerDecompressFail: - failf(data, "Decompression failed"); - break; - - /* Problem with access */ - case errSSLPeerAccessDenied: - failf(data, "Access was denied"); - break; - case errSSLPeerInsufficientSecurity: - failf(data, "There is insufficient security for this operation"); - break; - - /* These are all certificate problems with the server: */ - case errSSLXCertChainInvalid: - failf(data, "SSL certificate problem: Invalid certificate chain"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLUnknownRootCert: - failf(data, "SSL certificate problem: Untrusted root certificate"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLNoRootCert: - failf(data, "SSL certificate problem: No root certificate"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLCertNotYetValid: - failf(data, "SSL certificate problem: The certificate chain had a " - "certificate that is not yet valid"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLCertExpired: - case errSSLPeerCertExpired: - failf(data, "SSL certificate problem: Certificate chain had an " - "expired certificate"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLBadCert: - case errSSLPeerBadCert: - failf(data, "SSL certificate problem: Couldn't understand the server " - "certificate format"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLPeerUnsupportedCert: - failf(data, "SSL certificate problem: An unsupported certificate " - "format was encountered"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLPeerCertRevoked: - failf(data, "SSL certificate problem: The certificate was revoked"); - return CURLE_PEER_FAILED_VERIFICATION; - case errSSLPeerCertUnknown: - failf(data, "SSL certificate problem: The certificate is unknown"); - return CURLE_PEER_FAILED_VERIFICATION; - - /* These are all certificate problems with the client: */ - case errSecAuthFailed: - failf(data, "SSL authentication failed"); - break; - case errSSLPeerHandshakeFail: - failf(data, "SSL peer handshake failed, the server most likely " - "requires a client certificate to connect"); - break; - case errSSLPeerUnknownCA: - failf(data, "SSL server rejected the client certificate due to " - "the certificate being signed by an unknown certificate " - "authority"); - break; - - /* This error is raised if the server's cert did not match the server's - hostname: */ - case errSSLHostNameMismatch: - failf(data, "SSL certificate peer verification failed, the " - "certificate did not match \"%s\"\n", connssl->peer.dispname); - return CURLE_PEER_FAILED_VERIFICATION; - - /* Problem with SSL / TLS negotiation */ - case errSSLNegotiation: - failf(data, "Could not negotiate an SSL cipher suite with the server"); - break; - case errSSLBadConfiguration: - failf(data, "A configuration error occurred"); - break; - case errSSLProtocol: - failf(data, "SSL protocol error"); - break; - case errSSLPeerProtocolVersion: - failf(data, "A bad protocol version was encountered"); - break; - case errSSLPeerNoRenegotiation: - failf(data, "No renegotiation is allowed"); - break; - - /* Generic handshake errors: */ - case errSSLConnectionRefused: - failf(data, "Server dropped the connection during the SSL handshake"); - break; - case errSSLClosedAbort: - failf(data, "Server aborted the SSL handshake"); - break; - case errSSLClosedGraceful: - failf(data, "The connection closed gracefully"); - break; - case errSSLClosedNoNotify: - failf(data, "The server closed the session with no notification"); - break; - /* Sometimes paramErr happens with buggy ciphers: */ - case paramErr: - case errSSLInternal: - case errSSLPeerInternalError: - failf(data, "Internal SSL engine error encountered during the " - "SSL handshake"); - break; - case errSSLFatalAlert: - failf(data, "Fatal SSL engine error encountered during the SSL " - "handshake"); - break; - /* Unclassified error */ - case errSSLBufferOverflow: - failf(data, "An insufficient buffer was provided"); - break; - case errSSLIllegalParam: - failf(data, "An illegal parameter was encountered"); - break; - case errSSLModuleAttach: - failf(data, "Module attach failure"); - break; - case errSSLSessionNotFound: - failf(data, "An attempt to restore an unknown session failed"); - break; - case errSSLPeerExportRestriction: - failf(data, "An export restriction occurred"); - break; - case errSSLPeerUserCancelled: - failf(data, "The user canceled the operation"); - break; - case errSSLPeerUnexpectedMsg: - failf(data, "Peer rejected unexpected message"); - break; -#if CURL_BUILD_MAC_10_11 || CURL_BUILD_IOS_9 - /* Treating non-fatal error as fatal like before */ - case errSSLClientHelloReceived: - failf(data, "A non-fatal result for providing a server name " - "indication"); - break; -#endif - - /* Error codes defined in the enum but should never be returned. - We list them here just in case. */ -#if CURL_BUILD_MAC_10_6 - /* Only returned when kSSLSessionOptionBreakOnCertRequested is set */ - case errSSLClientCertRequested: - failf(data, "Server requested a client certificate during the " - "handshake"); - return CURLE_SSL_CLIENTCERT; -#endif -#if CURL_BUILD_MAC_10_9 - /* Alias for errSSLLast, end of error range */ - case errSSLUnexpectedRecord: - failf(data, "Unexpected (skipped) record in DTLS"); - break; -#endif - default: - /* May also return codes listed in Security Framework Result Codes */ - failf(data, "Unknown SSL protocol error in connection to %s:%d", - connssl->peer.hostname, err); - break; - } - return CURLE_SSL_CONNECT_ERROR; - } - else { - char cipher_str[64]; - /* we have been connected fine, we are not waiting for anything else. */ - connssl->connecting_state = ssl_connect_3; - -#ifdef SECTRANSP_PINNEDPUBKEY - if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { - CURLcode result = - pkp_pin_peer_pubkey(data, backend->ssl_ctx, - data->set.str[STRING_SSL_PINNEDPUBLICKEY]); - if(result) { - failf(data, "SSL: public key does not match pinned public key"); - return result; - } - } -#endif /* SECTRANSP_PINNEDPUBKEY */ - - /* Informational message */ - (void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher); - (void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol); - - sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str, - sizeof(cipher_str), TRUE); - switch(protocol) { - case kSSLProtocol2: - infof(data, "SSL 2.0 connection using %s", cipher_str); - break; - case kSSLProtocol3: - infof(data, "SSL 3.0 connection using %s", cipher_str); - break; - case kTLSProtocol1: - infof(data, "TLS 1.0 connection using %s", cipher_str); - break; -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - case kTLSProtocol11: - infof(data, "TLS 1.1 connection using %s", cipher_str); - break; - case kTLSProtocol12: - infof(data, "TLS 1.2 connection using %s", cipher_str); - break; -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ -#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 - case kTLSProtocol13: - infof(data, "TLS 1.3 connection using %s", cipher_str); - break; -#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ - default: - infof(data, "Unknown protocol connection"); - break; - } - - if(connssl->alpn) { -#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 -#ifdef HAVE_BUILTIN_AVAILABLE - if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) { -#else - if(&SSLSetALPNProtocols && &SSLCopyALPNProtocols) { -#endif - CFArrayRef alpnArr = NULL; - CFStringRef chosenProtocol = NULL; - err = SSLCopyALPNProtocols(backend->ssl_ctx, &alpnArr); - - if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1) - chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0); - -#ifdef USE_HTTP2 - if(chosenProtocol && - !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) { - cf->conn->alpn = CURL_HTTP_VERSION_2; - } - else -#endif - if(chosenProtocol && - !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) { - cf->conn->alpn = CURL_HTTP_VERSION_1_1; - } - else - infof(data, VTLS_INFOF_NO_ALPN); - - /* chosenProtocol is a reference to the string within alpnArr - and does not need to be freed separately */ - if(alpnArr) - CFRelease(alpnArr); - } -#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */ - } - - return CURLE_OK; - } -} - -static CURLcode -add_cert_to_certinfo(struct Curl_easy *data, - const SecCertificateRef server_cert, - int idx) -{ - CURLcode result = CURLE_OK; - const char *beg; - const char *end; - CFDataRef cert_data = SecCertificateCopyData(server_cert); - - if(!cert_data) - return CURLE_PEER_FAILED_VERIFICATION; - - beg = (const char *)CFDataGetBytePtr(cert_data); - end = beg + CFDataGetLength(cert_data); - result = Curl_extract_certinfo(data, idx, beg, end); - CFRelease(cert_data); - return result; -} - -static CURLcode -collect_server_cert_single(struct Curl_cfilter *cf, struct Curl_easy *data, - const SecCertificateRef server_cert, - CFIndex idx) -{ - CURLcode result = CURLE_OK; - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); -#ifndef CURL_DISABLE_VERBOSE_STRINGS - if(data->set.verbose) { - char *certp; - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s", certp); - free(certp); - } - } -#endif - if(ssl_config->certinfo) - result = add_cert_to_certinfo(data, server_cert, (int)idx); - return result; -} - -/* This should be called during step3 of the connection at the earliest */ -static CURLcode collect_server_cert(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - const bool show_verbose_server_cert = data->set.verbose; -#else - const bool show_verbose_server_cert = FALSE; -#endif - struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); - CURLcode result = ssl_config->certinfo ? - CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - CFArrayRef server_certs = NULL; - SecCertificateRef server_cert; - OSStatus err; - CFIndex i, count; - SecTrustRef trust = NULL; - - DEBUGASSERT(backend); - - if(!show_verbose_server_cert && !ssl_config->certinfo) - return CURLE_OK; - - if(!backend->ssl_ctx) - return result; - -#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS -#if CURL_BUILD_IOS -#pragma unused(server_certs) - err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); - /* For some reason, SSLCopyPeerTrust() can return noErr and yet return - a null trust, so be on guard for that: */ - if(err == noErr && trust) { - count = SecTrustGetCertificateCount(trust); - if(ssl_config->certinfo) - result = Curl_ssl_init_certinfo(data, (int)count); - for(i = 0L ; !result && (i < count) ; i++) { - server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = collect_server_cert_single(cf, data, server_cert, i); - } - CFRelease(trust); - } -#else - /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion. - The function SecTrustGetCertificateAtIndex() is officially present - in Lion, but it is unfortunately also present in Snow Leopard as - private API and does not work as expected. So we have to look for - a different symbol to make sure this code is only executed under - Lion or later. */ - if(&SecTrustCopyPublicKey) { -#pragma unused(server_certs) - err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); - /* For some reason, SSLCopyPeerTrust() can return noErr and yet return - a null trust, so be on guard for that: */ - if(err == noErr && trust) { - count = SecTrustGetCertificateCount(trust); - if(ssl_config->certinfo) - result = Curl_ssl_init_certinfo(data, (int)count); - for(i = 0L ; !result && (i < count) ; i++) { - server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = collect_server_cert_single(cf, data, server_cert, i); - } - CFRelease(trust); - } - } - else { -#if CURL_SUPPORT_MAC_10_8 - err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); - /* Just in case SSLCopyPeerCertificates() returns null too... */ - if(err == noErr && server_certs) { - count = CFArrayGetCount(server_certs); - if(ssl_config->certinfo) - result = Curl_ssl_init_certinfo(data, (int)count); - for(i = 0L ; !result && (i < count) ; i++) { - const void *item = CFArrayGetValueAtIndex(server_certs, i); - server_cert = (SecCertificateRef)CURL_UNCONST(item); - result = collect_server_cert_single(cf, data, server_cert, i); - } - CFRelease(server_certs); - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#endif /* CURL_BUILD_IOS */ -#else -#pragma unused(trust) - err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); - if(err == noErr) { - count = CFArrayGetCount(server_certs); - if(ssl_config->certinfo) - result = Curl_ssl_init_certinfo(data, (int)count); - for(i = 0L ; !result && (i < count) ; i++) { - const void *item = CFArrayGetValueAtIndex(server_certs, i); - server_cert = (SecCertificateRef)CURL_UNCONST(item); - result = collect_server_cert_single(cf, data, server_cert, i); - } - CFRelease(server_certs); - } -#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ - return result; -} - -static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - CURLcode result; - - CURL_TRC_CF(data, cf, "connect_step3"); - /* There is no step 3! - * Well, okay, let's collect server certificates, and if verbose mode is on, - * let's print the details of the server certificates. */ - result = collect_server_cert(cf, data); - if(result) - return result; - - connssl->connecting_state = ssl_connect_done; - return CURLE_OK; -} - -static CURLcode sectransp_connect(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - CURLcode result; - struct ssl_connect_data *connssl = cf->ctx; - - /* check if the connection has already been established */ - if(ssl_connection_complete == connssl->state) { - *done = TRUE; - return CURLE_OK; - } - - *done = FALSE; - connssl->io_need = CURL_SSL_IO_NEED_NONE; - - if(ssl_connect_1 == connssl->connecting_state) { - result = sectransp_connect_step1(cf, data); - if(result) - return result; - } - - if(ssl_connect_2 == connssl->connecting_state) { - result = sectransp_connect_step2(cf, data); - if(result) - return result; - } - - if(ssl_connect_3 == connssl->connecting_state) { - result = sectransp_connect_step3(cf, data); - if(result) - return result; - } - - if(ssl_connect_done == connssl->connecting_state) { - CURL_TRC_CF(data, cf, "connected"); - connssl->state = ssl_connection_complete; - *done = TRUE; - } - - return CURLE_OK; -} - -static ssize_t sectransp_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, - size_t buffersize, - CURLcode *curlcode); - -static CURLcode sectransp_shutdown(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool send_shutdown, bool *done) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - CURLcode result = CURLE_OK; - ssize_t nread = 0; - char buf[1024]; - size_t i; - - DEBUGASSERT(backend); - if(!backend->ssl_ctx || cf->shutdown) { - *done = TRUE; - goto out; - } - - connssl->io_need = CURL_SSL_IO_NEED_NONE; - *done = FALSE; - - if(send_shutdown && !backend->sent_shutdown) { - OSStatus err; - - CURL_TRC_CF(data, cf, "shutdown, send close notify"); - err = SSLClose(backend->ssl_ctx); - switch(err) { - case noErr: - backend->sent_shutdown = TRUE; - break; - case errSSLWouldBlock: - connssl->io_need = CURL_SSL_IO_NEED_SEND; - result = CURLE_OK; - goto out; - default: - CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)err); - result = CURLE_SEND_ERROR; - goto out; - } - } - - for(i = 0; i < 10; ++i) { - if(!backend->sent_shutdown) { - nread = sectransp_recv(cf, data, buf, (int)sizeof(buf), &result); - } - else { - /* We would like to read the close notify from the server using - * Secure Transport, however SSLRead() no longer works after we - * sent the notify from our side. So, we just read from the - * underlying filter and hope it will end. */ - nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result); - } - CURL_TRC_CF(data, cf, "shutdown read -> %zd, %d", nread, result); - if(nread <= 0) - break; - } - - if(nread > 0) { - /* still data coming in? */ - connssl->io_need = CURL_SSL_IO_NEED_RECV; - } - else if(nread == 0) { - /* We got the close notify alert and are done. */ - CURL_TRC_CF(data, cf, "shutdown done"); - *done = TRUE; - } - else if(result == CURLE_AGAIN) { - connssl->io_need = CURL_SSL_IO_NEED_RECV; - result = CURLE_OK; - } - else { - DEBUGASSERT(result); - CURL_TRC_CF(data, cf, "shutdown, error: %d", result); - } - -out: - cf->shutdown = (result || *done); - return result; -} - -static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - - (void) data; - - DEBUGASSERT(backend); - - if(backend->ssl_ctx) { - CURL_TRC_CF(data, cf, "close"); -#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS - if(&SSLCreateContext) - CFRelease(backend->ssl_ctx); -#if CURL_SUPPORT_MAC_10_8 - else - (void)SSLDisposeContext(backend->ssl_ctx); -#endif /* CURL_SUPPORT_MAC_10_8 */ -#else - (void)SSLDisposeContext(backend->ssl_ctx); -#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - backend->ssl_ctx = NULL; - } -} - -static size_t sectransp_version(char *buffer, size_t size) -{ - return msnprintf(buffer, size, "SecureTransport"); -} - -static bool sectransp_data_pending(struct Curl_cfilter *cf, - const struct Curl_easy *data) -{ - const struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - OSStatus err; - size_t buffer; - - (void)data; - DEBUGASSERT(backend); - - if(backend->ssl_ctx) { /* SSL is in use */ - CURL_TRC_CF((struct Curl_easy *)CURL_UNCONST(data), cf, "data_pending"); - err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer); - if(err == noErr) - return buffer > 0UL; - return FALSE; - } - else - return FALSE; -} - -static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM, - unsigned char *entropy, size_t length) -{ - /* arc4random_buf() is not available on cats older than Lion, so let's - do this manually for the benefit of the older cats. */ - size_t i; - u_int32_t random_number = 0; - - (void)data; - - for(i = 0 ; i < length ; i++) { - if(i % sizeof(u_int32_t) == 0) - random_number = arc4random(); - entropy[i] = random_number & 0xFF; - random_number >>= 8; - } - i = random_number = 0; - return CURLE_OK; -} - -static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */ - size_t tmplen, - unsigned char *sha256sum, /* output */ - size_t sha256len) -{ - (void)sha256len; - assert(sha256len >= CURL_SHA256_DIGEST_LENGTH); - (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum); - return CURLE_OK; -} - -static bool sectransp_false_start(void) -{ -#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 - if(&SSLSetSessionOption) - return TRUE; -#endif - return FALSE; -} - -static ssize_t sectransp_send(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *mem, - size_t len, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - size_t processed = 0UL; - OSStatus err; - - DEBUGASSERT(backend); - - /* The SSLWrite() function works a little differently than expected. The - fourth argument (processed) is currently documented in Apple's - documentation as: "On return, the length, in bytes, of the data actually - written." - - Now, one could interpret that as "written to the socket," but actually, - it returns the amount of data that was written to a buffer internal to - the SSLContextRef instead. So it is possible for SSLWrite() to return - errSSLWouldBlock and a number of bytes "written" because those bytes were - encrypted and written to a buffer, not to the socket. - - So if this happens, then we need to keep calling SSLWrite() over and - over again with no new data until it quits returning errSSLWouldBlock. */ - - /* Do we have buffered data to write from the last time we were called? */ - if(backend->ssl_write_buffered_length) { - /* Write the buffered data: */ - err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed); - switch(err) { - case noErr: - /* processed is always going to be 0 because we did not write to - the buffer, so return how much was written to the socket */ - processed = backend->ssl_write_buffered_length; - backend->ssl_write_buffered_length = 0UL; - break; - case errSSLWouldBlock: /* argh, try again */ - *curlcode = CURLE_AGAIN; - return -1L; - default: - failf(data, "SSLWrite() returned error %d", err); - *curlcode = CURLE_SEND_ERROR; - return -1L; - } - } - else { - /* We have got new data to write: */ - err = SSLWrite(backend->ssl_ctx, mem, len, &processed); - if(err != noErr) { - switch(err) { - case errSSLWouldBlock: - /* Data was buffered but not sent, we have to tell the caller - to try sending again, and remember how much was buffered */ - backend->ssl_write_buffered_length = len; - *curlcode = CURLE_AGAIN; - return -1L; - default: - failf(data, "SSLWrite() returned error %d", err); - *curlcode = CURLE_SEND_ERROR; - return -1L; - } - } - } - return (ssize_t)processed; -} - -static ssize_t sectransp_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, - size_t buffersize, - CURLcode *curlcode) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); - size_t processed = 0UL; - OSStatus err; - - DEBUGASSERT(backend); - -again: - *curlcode = CURLE_OK; - err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed); - - if(err != noErr) { - switch(err) { - case errSSLWouldBlock: /* return how much we read (if anything) */ - if(processed) { - return (ssize_t)processed; - } - *curlcode = CURLE_AGAIN; - return -1L; - - /* errSSLClosedGraceful - server gracefully shut down the SSL session - errSSLClosedNoNotify - server hung up on us instead of sending a - closure alert notice, read() is returning 0 - Either way, inform the caller that the server disconnected. */ - case errSSLClosedGraceful: - case errSSLClosedNoNotify: - *curlcode = CURLE_OK; - return 0; - - /* The below is errSSLPeerAuthCompleted; it is not defined in - Leopard's headers */ - case -9841: - if((conn_config->CAfile || conn_config->ca_info_blob) && - conn_config->verifypeer) { - CURLcode result = verify_cert(cf, data, conn_config->CAfile, - conn_config->ca_info_blob, - backend->ssl_ctx); - if(result) { - *curlcode = result; - return -1; - } - } - goto again; - default: - failf(data, "SSLRead() return error %d", err); - *curlcode = CURLE_RECV_ERROR; - return -1L; - } - } - return (ssize_t)processed; -} - -static void *sectransp_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) -{ - struct st_ssl_backend_data *backend = - (struct st_ssl_backend_data *)connssl->backend; - (void)info; - DEBUGASSERT(backend); - return backend->ssl_ctx; -} - -const struct Curl_ssl Curl_ssl_sectransp = { - { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */ - - SSLSUPP_CAINFO_BLOB | - SSLSUPP_CERTINFO | -#ifdef SECTRANSP_PINNEDPUBKEY - SSLSUPP_PINNEDPUBKEY | -#endif /* SECTRANSP_PINNEDPUBKEY */ - SSLSUPP_HTTPS_PROXY | - SSLSUPP_CIPHER_LIST, - - sizeof(struct st_ssl_backend_data), - - NULL, /* init */ - NULL, /* cleanup */ - sectransp_version, /* version */ - sectransp_shutdown, /* shutdown */ - sectransp_data_pending, /* data_pending */ - sectransp_random, /* random */ - NULL, /* cert_status_request */ - sectransp_connect, /* connect */ - Curl_ssl_adjust_pollset, /* adjust_pollset */ - sectransp_get_internals, /* get_internals */ - sectransp_close, /* close_one */ - NULL, /* close_all */ - NULL, /* set_engine */ - NULL, /* set_engine_default */ - NULL, /* engines_list */ - sectransp_false_start, /* false_start */ - sectransp_sha256sum, /* sha256sum */ - sectransp_recv, /* recv decrypted data */ - sectransp_send, /* send data to encrypt */ - NULL, /* get_channel_binding */ -}; - -#if defined(__GNUC__) && defined(__APPLE__) -#pragma GCC diagnostic pop -#endif - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif /* USE_SECTRANSP */ diff --git a/vendor/curl/lib/vtls/vtls.c b/vendor/curl/lib/vtls/vtls.c index 2f2c544a..db4e5734 100644 --- a/vendor/curl/lib/vtls/vtls.c +++ b/vendor/curl/lib/vtls/vtls.c @@ -43,9 +43,6 @@ #ifdef HAVE_SYS_TYPES_H #include #endif -#ifdef HAVE_SYS_STAT_H -#include -#endif #ifdef HAVE_FCNTL_H #include #endif @@ -61,9 +58,7 @@ #include "gtls.h" /* GnuTLS versions */ #include "wolfssl.h" /* wolfSSL versions */ #include "schannel.h" /* Schannel SSPI version */ -#include "sectransp.h" /* Secure Transport (Darwin) version */ #include "mbedtls.h" /* mbedTLS versions */ -#include "bearssl.h" /* BearSSL versions */ #include "rustls.h" /* Rustls versions */ #include "../slist.h" @@ -212,12 +207,12 @@ match_ssl_primary_config(struct Curl_easy *data, !Curl_timestrcmp(c1->username, c2->username) && !Curl_timestrcmp(c1->password, c2->password) && #endif - strcasecompare(c1->cipher_list, c2->cipher_list) && - strcasecompare(c1->cipher_list13, c2->cipher_list13) && - strcasecompare(c1->curves, c2->curves) && - strcasecompare(c1->signature_algorithms, c2->signature_algorithms) && - strcasecompare(c1->CRLfile, c2->CRLfile) && - strcasecompare(c1->pinned_key, c2->pinned_key)) + curl_strequal(c1->cipher_list, c2->cipher_list) && + curl_strequal(c1->cipher_list13, c2->cipher_list13) && + curl_strequal(c1->curves, c2->curves) && + curl_strequal(c1->signature_algorithms, c2->signature_algorithms) && + curl_strequal(c1->CRLfile, c2->CRLfile) && + curl_strequal(c1->pinned_key, c2->pinned_key)) return TRUE; return FALSE; @@ -491,7 +486,7 @@ static void cf_ctx_free(struct ssl_connect_data *ctx) } CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex, - struct dynbuf *binding) + struct dynbuf *binding) { if(Curl_ssl->get_channel_binding) return Curl_ssl->get_channel_binding(data, sockindex, binding); @@ -505,7 +500,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) } void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, - struct easy_pollset *ps) + struct easy_pollset *ps) { struct ssl_connect_data *connssl = cf->ctx; @@ -768,8 +763,8 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, do { end_pos = strstr(begin_pos, ";sha256//"); /* - * if there is an end_pos, null terminate, - * otherwise it will go to the end of the original string + * if there is an end_pos, null-terminate, otherwise it will go to the + * end of the original string */ if(end_pos) end_pos[0] = '\0'; @@ -845,8 +840,8 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, } /* - * Otherwise we will assume it is PEM and try to decode it - * after placing null terminator + * Otherwise we will assume it is PEM and try to decode it after placing + * null-terminator */ pem_read = pubkey_pem_to_der(curlx_dyn_ptr(&buf), &pem_ptr, &pem_len); /* if it was not read successfully, exit */ @@ -878,16 +873,6 @@ bool Curl_ssl_cert_status_request(void) return FALSE; } -/* - * Check whether the SSL backend supports false start. - */ -bool Curl_ssl_false_start(void) -{ - if(Curl_ssl->false_start) - return Curl_ssl->false_start(); - return FALSE; -} - static int multissl_init(void) { if(multissl_setup(NULL)) @@ -906,8 +891,8 @@ static CURLcode multissl_connect(struct Curl_cfilter *cf, } static void multissl_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) + struct Curl_easy *data, + struct easy_pollset *ps) { if(multissl_setup(NULL)) return; @@ -929,23 +914,23 @@ static void multissl_close(struct Curl_cfilter *cf, struct Curl_easy *data) Curl_ssl->close(cf, data); } -static ssize_t multissl_recv_plain(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, size_t len, CURLcode *code) +static CURLcode multissl_recv_plain(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t len, size_t *pnread) { if(multissl_setup(NULL)) return CURLE_FAILED_INIT; - return Curl_ssl->recv_plain(cf, data, buf, len, code); + return Curl_ssl->recv_plain(cf, data, buf, len, pnread); } -static ssize_t multissl_send_plain(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *mem, size_t len, - CURLcode *code) +static CURLcode multissl_send_plain(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *mem, size_t len, + size_t *pnwritten) { if(multissl_setup(NULL)) return CURLE_FAILED_INIT; - return Curl_ssl->send_plain(cf, data, mem, len, code); + return Curl_ssl->send_plain(cf, data, mem, len, pnwritten); } static const struct Curl_ssl Curl_ssl_multi = { @@ -968,7 +953,6 @@ static const struct Curl_ssl Curl_ssl_multi = { NULL, /* set_engine */ NULL, /* set_engine_default */ NULL, /* engines_list */ - NULL, /* false_start */ NULL, /* sha256sum */ multissl_recv_plain, /* recv decrypted data */ multissl_send_plain, /* send data to encrypt */ @@ -988,12 +972,8 @@ const struct Curl_ssl *Curl_ssl = &Curl_ssl_rustls; #elif defined(USE_OPENSSL) &Curl_ssl_openssl; -#elif defined(USE_SECTRANSP) - &Curl_ssl_sectransp; #elif defined(USE_SCHANNEL) &Curl_ssl_schannel; -#elif defined(USE_BEARSSL) - &Curl_ssl_bearssl; #else #error "Missing struct Curl_ssl for selected SSL backend" #endif @@ -1011,15 +991,9 @@ static const struct Curl_ssl *available_backends[] = { #if defined(USE_OPENSSL) &Curl_ssl_openssl, #endif -#if defined(USE_SECTRANSP) - &Curl_ssl_sectransp, -#endif #if defined(USE_SCHANNEL) &Curl_ssl_schannel, #endif -#if defined(USE_BEARSSL) - &Curl_ssl_bearssl, -#endif #if defined(USE_RUSTLS) &Curl_ssl_rustls, #endif @@ -1099,7 +1073,7 @@ static int multissl_setup(const struct Curl_ssl *backend) env = curl_getenv("CURL_SSL_BACKEND"); if(env) { for(i = 0; available_backends[i]; i++) { - if(strcasecompare(env, available_backends[i]->info.name)) { + if(curl_strequal(env, available_backends[i]->info.name)) { Curl_ssl = available_backends[i]; free(env); return 0; @@ -1109,8 +1083,8 @@ static int multissl_setup(const struct Curl_ssl *backend) #ifdef CURL_DEFAULT_SSL_BACKEND for(i = 0; available_backends[i]; i++) { - if(strcasecompare(CURL_DEFAULT_SSL_BACKEND, - available_backends[i]->info.name)) { + if(curl_strequal(CURL_DEFAULT_SSL_BACKEND, + available_backends[i]->info.name)) { Curl_ssl = available_backends[i]; free(env); return 0; @@ -1136,7 +1110,7 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, if(Curl_ssl != &Curl_ssl_multi) return id == Curl_ssl->info.id || - (name && strcasecompare(name, Curl_ssl->info.name)) ? + (name && curl_strequal(name, Curl_ssl->info.name)) ? CURLSSLSET_OK : #if defined(CURL_WITH_MULTI_SSL) CURLSSLSET_TOO_LATE; @@ -1146,7 +1120,7 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, for(i = 0; available_backends[i]; i++) { if(available_backends[i]->info.id == id || - (name && strcasecompare(available_backends[i]->info.name, name))) { + (name && curl_strequal(available_backends[i]->info.name, name))) { multissl_setup(available_backends[i]); return CURLSSLSET_OK; } @@ -1372,7 +1346,7 @@ static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf, const void *buf, size_t blen) { struct ssl_connect_data *connssl = cf->ctx; - ssize_t nwritten = 0; + size_t nwritten = 0; CURLcode result = CURLE_OK; DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_await); @@ -1380,10 +1354,10 @@ static CURLcode ssl_cf_set_earlydata(struct Curl_cfilter *cf, if(blen) { if(blen > connssl->earlydata_max) blen = connssl->earlydata_max; - nwritten = Curl_bufq_write(&connssl->earlydata, buf, blen, &result); + result = Curl_bufq_write(&connssl->earlydata, buf, blen, &nwritten); CURL_TRC_CF(data, cf, "ssl_cf_set_earlydata(len=%zu) -> %zd", blen, nwritten); - if(nwritten < 0) + if(result) return result; } return CURLE_OK; @@ -1455,29 +1429,26 @@ static bool ssl_cf_data_pending(struct Curl_cfilter *cf, return result; } -static ssize_t ssl_cf_send(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *buf, size_t blen, - bool eos, CURLcode *err) +static CURLcode ssl_cf_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t blen, + bool eos, size_t *pnwritten) { struct ssl_connect_data *connssl = cf->ctx; struct cf_call_data save; - ssize_t nwritten = 0, early_written = 0; + CURLcode result = CURLE_OK; (void)eos; - *err = CURLE_OK; + *pnwritten = 0; CF_DATA_SAVE(save, cf, data); if(connssl->state == ssl_connection_deferred) { bool done = FALSE; - *err = ssl_cf_connect_deferred(cf, data, buf, blen, &done); - if(*err) { - nwritten = -1; + result = ssl_cf_connect_deferred(cf, data, buf, blen, &done); + if(result) goto out; - } else if(!done) { - *err = CURLE_AGAIN; - nwritten = -1; + result = CURLE_AGAIN; goto out; } DEBUGASSERT(connssl->state == ssl_connection_complete); @@ -1486,12 +1457,12 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf, if(connssl->earlydata_skip) { if(connssl->earlydata_skip >= blen) { connssl->earlydata_skip -= blen; - *err = CURLE_OK; - nwritten = (ssize_t)blen; + result = CURLE_OK; + *pnwritten = blen; goto out; } else { - early_written = connssl->earlydata_skip; + *pnwritten = connssl->earlydata_skip; buf = ((const char *)buf) + connssl->earlydata_skip; blen -= connssl->earlydata_skip; connssl->earlydata_skip = 0; @@ -1499,56 +1470,45 @@ static ssize_t ssl_cf_send(struct Curl_cfilter *cf, } /* OpenSSL and maybe other TLS libs do not like 0-length writes. Skip. */ - if(blen > 0) - nwritten = connssl->ssl_impl->send_plain(cf, data, buf, blen, err); - - if(nwritten >= 0) - nwritten += early_written; + if(blen > 0) { + size_t nwritten; + result = connssl->ssl_impl->send_plain(cf, data, buf, blen, &nwritten); + if(!result) + *pnwritten += nwritten; + } out: CF_DATA_RESTORE(cf, save); - return nwritten; + return result; } -static ssize_t ssl_cf_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, char *buf, size_t len, - CURLcode *err) +static CURLcode ssl_cf_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, char *buf, size_t len, + size_t *pnread) { struct ssl_connect_data *connssl = cf->ctx; struct cf_call_data save; - ssize_t nread; + CURLcode result = CURLE_OK; CF_DATA_SAVE(save, cf, data); - *err = CURLE_OK; + *pnread = 0; if(connssl->state == ssl_connection_deferred) { bool done = FALSE; - *err = ssl_cf_connect_deferred(cf, data, NULL, 0, &done); - if(*err) { - nread = -1; + result = ssl_cf_connect_deferred(cf, data, NULL, 0, &done); + if(result) goto out; - } else if(!done) { - *err = CURLE_AGAIN; - nread = -1; + result = CURLE_AGAIN; goto out; } DEBUGASSERT(connssl->state == ssl_connection_complete); } - nread = connssl->ssl_impl->recv_plain(cf, data, buf, len, err); - if(nread > 0) { - DEBUGASSERT((size_t)nread <= len); - } - else if(nread == 0) { - /* eof */ - *err = CURLE_OK; - } + result = connssl->ssl_impl->recv_plain(cf, data, buf, len, pnread); out: - CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, - nread, *err); CF_DATA_RESTORE(cf, save); - return nread; + return result; } static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf, @@ -1598,6 +1558,18 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, *when = connssl->handshake_done; return CURLE_OK; } + case CF_QUERY_SSL_INFO: + case CF_QUERY_SSL_CTX_INFO: { + struct curl_tlssessioninfo *info = pres2; + struct cf_call_data save; + CF_DATA_SAVE(save, cf, data); + info->backend = Curl_ssl_backend(); + info->internals = connssl->ssl_impl->get_internals( + cf->ctx, (query == CF_QUERY_SSL_INFO) ? + CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } default: break; } @@ -1625,7 +1597,6 @@ struct Curl_cftype Curl_cft_ssl = { ssl_cf_connect, ssl_cf_close, ssl_cf_shutdown, - Curl_cf_def_get_host, ssl_cf_adjust_pollset, ssl_cf_data_pending, ssl_cf_send, @@ -1646,7 +1617,6 @@ struct Curl_cftype Curl_cft_ssl_proxy = { ssl_cf_connect, ssl_cf_close, ssl_cf_shutdown, - Curl_cf_def_get_host, ssl_cf_adjust_pollset, ssl_cf_data_pending, ssl_cf_send, @@ -1769,40 +1739,6 @@ bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option) return (Curl_ssl->supports & ssl_option); } -static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf) -{ - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_ssl) - return cf; -#ifndef CURL_DISABLE_PROXY - if(cf->cft == &Curl_cft_ssl_proxy) - return cf; -#endif - } - return NULL; -} - - -void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, - CURLINFO info, int n) -{ - void *result = NULL; - (void)n; - if(data->conn) { - struct Curl_cfilter *cf; - /* get first SSL filter in chain, if any is present */ - cf = get_ssl_filter(data->conn->cfilter[sockindex]); - if(cf) { - struct ssl_connect_data *connssl = cf->ctx; - struct cf_call_data save; - CF_DATA_SAVE(save, cf, data); - result = connssl->ssl_impl->get_internals(cf->ctx, info); - CF_DATA_RESTORE(cf, save); - } - } - return result; -} - static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf, struct Curl_easy *data, bool send_shutdown, bool *done) diff --git a/vendor/curl/lib/vtls/vtls.h b/vendor/curl/lib/vtls/vtls.h index 0bb333b9..c62b8ae2 100644 --- a/vendor/curl/lib/vtls/vtls.h +++ b/vendor/curl/lib/vtls/vtls.h @@ -190,8 +190,6 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, bool Curl_ssl_cert_status_request(void); -bool Curl_ssl_false_start(void); - /* The maximum size of the SSL channel binding is 85 bytes, as defined in * RFC 5929, Section 4.1. The 'tls-server-end-point:' prefix is 21 bytes long, * and SHA-512 is the longest supported hash algorithm, with a digest length of @@ -209,7 +207,7 @@ bool Curl_ssl_false_start(void); * returned. */ CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex, - struct dynbuf *binding); + struct dynbuf *binding); #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ @@ -235,16 +233,6 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at, */ bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option); -/** - * Get the internal ssl instance (like OpenSSL's SSL*) from the filter - * chain at `sockindex` of type specified by `info`. - * For `n` == 0, the first active (top down) instance is returned. - * 1 gives the second active, etc. - * NULL is returned when no active SSL filter is present. - */ -void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex, - CURLINFO info, int n); - /** * Get the ssl_config_data in `data` that is relevant for cfilter `cf`. */ @@ -274,8 +262,6 @@ extern struct Curl_cftype Curl_cft_ssl_proxy; #define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN) #define Curl_ssl_cert_status_request() FALSE -#define Curl_ssl_false_start() FALSE -#define Curl_ssl_get_internals(a,b,c,d) NULL #define Curl_ssl_supports(a,b) FALSE #define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN #define Curl_ssl_cfilter_remove(a,b,c) CURLE_OK diff --git a/vendor/curl/lib/vtls/vtls_int.h b/vendor/curl/lib/vtls/vtls_int.h index 0632a076..11987c38 100644 --- a/vendor/curl/lib/vtls/vtls_int.h +++ b/vendor/curl/lib/vtls/vtls_int.h @@ -127,6 +127,7 @@ struct ssl_connect_data { BIT(use_alpn); /* if ALPN shall be used in handshake */ BIT(peer_closed); /* peer has closed connection */ BIT(prefs_checked); /* SSL preferences have been checked */ + BIT(input_pending); /* data for SSL_read() may be available */ }; @@ -175,13 +176,12 @@ struct Curl_ssl { CURLcode (*set_engine_default)(struct Curl_easy *data); struct curl_slist *(*engines_list)(struct Curl_easy *data); - bool (*false_start)(void); CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen, unsigned char *sha256sum, size_t sha256sumlen); - ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, CURLcode *code); - ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *mem, size_t len, CURLcode *code); + CURLcode (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data, + char *buf, size_t len, size_t *pnread); + CURLcode (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data, + const void *mem, size_t len, size_t *pnwritten); CURLcode (*get_channel_binding)(struct Curl_easy *data, int sockindex, struct dynbuf *binding); diff --git a/vendor/curl/lib/vtls/vtls_scache.c b/vendor/curl/lib/vtls/vtls_scache.c index 8d3517ca..662539cd 100644 --- a/vendor/curl/lib/vtls/vtls_scache.c +++ b/vendor/curl/lib/vtls/vtls_scache.c @@ -29,9 +29,6 @@ #ifdef HAVE_SYS_TYPES_H #include #endif -#ifdef HAVE_SYS_STAT_H -#include -#endif #ifdef HAVE_FCNTL_H #include #endif @@ -108,7 +105,7 @@ static struct Curl_ssl_scache *cf_ssl_scache_get(struct Curl_easy *data) return scache; } -static void cf_ssl_scache_sesssion_ldestroy(void *udata, void *obj) +static void cf_ssl_scache_session_ldestroy(void *udata, void *obj) { struct Curl_ssl_session *s = obj; (void)udata; @@ -161,7 +158,7 @@ Curl_ssl_session_create2(void *sdata, size_t sdata_len, if(alpn) { s->alpn = strdup(alpn); if(!s->alpn) { - cf_ssl_scache_sesssion_ldestroy(NULL, s); + cf_ssl_scache_session_ldestroy(NULL, s); return CURLE_OUT_OF_MEMORY; } } @@ -176,7 +173,7 @@ void Curl_ssl_session_destroy(struct Curl_ssl_session *s) if(Curl_node_llist(&s->list)) Curl_node_remove(&s->list); else { - cf_ssl_scache_sesssion_ldestroy(NULL, s); + cf_ssl_scache_session_ldestroy(NULL, s); } } } @@ -341,7 +338,7 @@ CURLcode Curl_ssl_scache_create(size_t max_peers, for(i = 0; i < scache->peer_count; ++i) { scache->peers[i].max_sessions = max_sessions_per_peer; Curl_llist_init(&scache->peers[i].sessions, - cf_ssl_scache_sesssion_ldestroy); + cf_ssl_scache_session_ldestroy); } *pscache = scache; @@ -376,9 +373,9 @@ void Curl_ssl_scache_unlock(struct Curl_easy *data) } static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf, - const char *name, - char *path, - bool *is_local) + const char *name, + char *path, + bool *is_local) { if(path && path[0]) { /* We try to add absolute paths, so that the session key can stay @@ -410,8 +407,8 @@ static CURLcode cf_ssl_peer_key_add_path(struct dynbuf *buf, } static CURLcode cf_ssl_peer_key_add_hash(struct dynbuf *buf, - const char *name, - struct curl_blob *blob) + const char *name, + struct curl_blob *blob) { CURLcode r = CURLE_OK; if(blob && blob->len) { @@ -598,9 +595,8 @@ CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf, goto out; *ppeer_key = curlx_dyn_take(&buf, &key_len); - /* we just added printable char, and dynbuf always 0 terminates, - * no need to track length */ - + /* we just added printable char, and dynbuf always null-terminates, no need + * to track length */ out: curlx_dyn_free(&buf); @@ -650,7 +646,7 @@ cf_ssl_find_peer_by_key(struct Curl_easy *data, /* check for entries with known peer_key */ for(i = 0; scache && i < scache->peer_count; i++) { if(scache->peers[i].ssl_peer_key && - strcasecompare(ssl_peer_key, scache->peers[i].ssl_peer_key) && + curl_strequal(ssl_peer_key, scache->peers[i].ssl_peer_key) && cf_ssl_scache_match_auth(&scache->peers[i], conn_config)) { /* yes, we have a cached session for this! */ *ppeer = &scache->peers[i]; @@ -869,9 +865,9 @@ CURLcode Curl_ssl_scache_put(struct Curl_cfilter *cf, } void Curl_ssl_scache_return(struct Curl_cfilter *cf, - struct Curl_easy *data, - const char *ssl_peer_key, - struct Curl_ssl_session *s) + struct Curl_easy *data, + const char *ssl_peer_key, + struct Curl_ssl_session *s) { /* See RFC 8446 C.4: * "Clients SHOULD NOT reuse a ticket for multiple connections." */ diff --git a/vendor/curl/lib/vtls/vtls_scache.h b/vendor/curl/lib/vtls/vtls_scache.h index c95fa42a..deedccfe 100644 --- a/vendor/curl/lib/vtls/vtls_scache.h +++ b/vendor/curl/lib/vtls/vtls_scache.h @@ -113,7 +113,7 @@ CURLcode Curl_ssl_scache_add_obj(struct Curl_cfilter *cf, void *sobj, Curl_ssl_scache_obj_dtor *sobj_dtor_cb); -/* All about a SSL session ticket */ +/* All about an SSL session ticket */ struct Curl_ssl_session { const void *sdata; /* session ticket data, plain bytes */ size_t sdata_len; /* number of bytes in sdata */ @@ -206,12 +206,6 @@ CURLcode Curl_ssl_session_export(struct Curl_easy *data, void *userptr); #endif /* USE_SSLS_EXPORT */ - -#else /* USE_SSL */ - -#define Curl_ssl_scache_create(x,y,z) ((void)x, CURLE_OK) -#define Curl_ssl_scache_destroy(x) do {} while(0) - -#endif /* USE_SSL (else) */ +#endif /* USE_SSL */ #endif /* HEADER_CURL_VTLS_SCACHE_H */ diff --git a/vendor/curl/lib/vtls/wolfssl.c b/vendor/curl/lib/vtls/wolfssl.c index fb27b543..c3560e8b 100644 --- a/vendor/curl/lib/vtls/wolfssl.c +++ b/vendor/curl/lib/vtls/wolfssl.c @@ -67,7 +67,6 @@ #include "../connect.h" /* for the connect timeout */ #include "../progress.h" #include "../select.h" -#include "../strcase.h" #include "../strdup.h" #include "x509asn1.h" #include "../curl_printf.h" @@ -227,9 +226,9 @@ static int wssl_do_file_type(const char *type) { if(!type || !type[0]) return WOLFSSL_FILETYPE_PEM; - if(strcasecompare(type, "PEM")) + if(curl_strequal(type, "PEM")) return WOLFSSL_FILETYPE_PEM; - if(strcasecompare(type, "DER")) + if(curl_strequal(type, "DER")) return WOLFSSL_FILETYPE_ASN1; return -1; } @@ -247,6 +246,9 @@ static const struct group_name_map gnm[] = { { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" }, { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" }, { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" }, + { WOLFSSL_P256_ML_KEM_768, "P256_ML_KEM_768" }, + { WOLFSSL_P384_ML_KEM_1024, "P384_ML_KEM_1024" }, + { WOLFSSL_X25519_ML_KEM_768, "X25519_ML_KEM_768" }, { 0, NULL } }; #endif @@ -299,9 +301,11 @@ static long wssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) ret = 1; break; #ifdef WOLFSSL_BIO_CTRL_EOF - case WOLFSSL_BIO_CTRL_EOF: + case WOLFSSL_BIO_CTRL_EOF: { /* EOF has been reached on input? */ - return !cf->next || !cf->next->connected; + struct ssl_connect_data *connssl = cf->ctx; + return connssl->peer_closed; + } #endif default: ret = 0; @@ -317,7 +321,7 @@ static int wssl_bio_cf_out_write(WOLFSSL_BIO *bio, struct ssl_connect_data *connssl = cf->ctx; struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nwritten, skiplen = 0; + size_t nwritten, skiplen = 0; CURLcode result = CURLE_OK; DEBUGASSERT(data); @@ -331,21 +335,21 @@ static int wssl_bio_cf_out_write(WOLFSSL_BIO *bio, skiplen = (ssize_t)(blen - wssl->io_send_blocked_len); blen = wssl->io_send_blocked_len; } - nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result); + result = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &nwritten); wssl->io_result = result; - CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d", - blen, nwritten, result); + CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %d, %zu", + blen, result, nwritten); #ifdef USE_FULL_BIO wolfSSL_BIO_clear_retry_flags(bio); #endif - if(nwritten < 0 && CURLE_AGAIN == result) { + if(CURLE_AGAIN == result) { wolfSSL_BIO_set_retry_write(bio); if(wssl->shutting_down && !wssl->io_send_blocked_len) wssl->io_send_blocked_len = blen; } else if(!result && skiplen) nwritten += skiplen; - return (int)nwritten; + return result ? -1 : (int)nwritten; } static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) @@ -354,7 +358,7 @@ static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) struct ssl_connect_data *connssl = cf->ctx; struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend; struct Curl_easy *data = CF_DATA_CURRENT(cf); - ssize_t nread; + size_t nread; CURLcode result = CURLE_OK; DEBUGASSERT(data); @@ -374,17 +378,17 @@ static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) } } - nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); + result = Curl_conn_cf_recv(cf->next, data, buf, blen, &nread); wssl->io_result = result; - CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result); + CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %d, %zu", blen, result, nread); #ifdef USE_FULL_BIO wolfSSL_BIO_clear_retry_flags(bio); #endif - if(nread < 0 && CURLE_AGAIN == result) + if(CURLE_AGAIN == result) wolfSSL_BIO_set_retry_read(bio); else if(nread == 0) connssl->peer_closed = TRUE; - return (int)nread; + return result ? -1 : (int)nread; } static WOLFSSL_BIO_METHOD *wssl_bio_cf_method = NULL; @@ -509,14 +513,14 @@ static CURLcode wssl_on_session_reuse(struct Curl_cfilter *cf, *do_early_data = FALSE; #ifdef WOLFSSL_EARLY_DATA connssl->earlydata_max = wolfSSL_SESSION_get_max_early_data( - wolfSSL_get_session(wssl->ssl)); + wolfSSL_get_session(wssl->ssl)); #else (void)wssl; connssl->earlydata_max = 0; #endif if(!connssl->earlydata_max) { - /* Seems to be GnuTLS way to signal no EarlyData in session */ + /* Seems to be no WolfSSL way to signal no EarlyData in session */ CURL_TRC_CF(data, cf, "SSL session does not allow earlydata"); } else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) { @@ -574,11 +578,19 @@ wssl_setup_session(struct Curl_cfilter *cf, if(result) goto out; } +#ifdef WOLFSSL_EARLY_DATA if(do_early_data) { + unsigned int edmax = (scs->earlydata_max < UINT_MAX) ? + (unsigned int)scs->earlydata_max : UINT_MAX; /* We only try the ALPN protocol the session used before, * otherwise we might send early data for the wrong protocol */ Curl_alpn_restrict_to(alpns, scs->alpn); + wolfSSL_set_max_early_data(wss->ssl, edmax); } +#else + /* Should never enable when not supported */ + DEBUGASSERT(!do_early_data); +#endif } } wolfSSL_SESSION_free(session); @@ -931,14 +943,6 @@ wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" #define QUIC_GROUPS "P-256:P-384:P-521" -#if defined(HAVE_SECRET_CALLBACK) -static void keylog_callback(const WOLFSSL *ssl, const char *line) -{ - (void)ssl; - Curl_tls_keylog_write_line(line); -} -#endif - CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, struct Curl_cfilter *cf, struct Curl_easy *data, @@ -960,6 +964,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, size_t idx = 0; #endif CURLcode result = CURLE_FAILED_INIT; + unsigned char transport; DEBUGASSERT(!wctx->ssl_ctx); DEBUGASSERT(!wctx->ssl); @@ -969,6 +974,8 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, goto out; } Curl_alpn_copy(&alpns, alpns_requested); + DEBUGASSERT(cf->next); + transport = Curl_conn_cf_get_transport(cf->next, data); #if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */ req_method = wolfSSLv23_client_method(); @@ -1099,7 +1106,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, #endif curves = conn_config->curves; - if(!curves && cf->conn->transport == TRNSPRT_QUIC) + if(!curves && (transport == TRNSPRT_QUIC)) curves = (char *)CURL_UNCONST(QUIC_GROUPS); if(curves) { @@ -1240,8 +1247,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, } #endif - if(ssl_config->primary.cache_session && - cf->conn->transport != TRNSPRT_QUIC) { + if(ssl_config->primary.cache_session && (transport != TRNSPRT_QUIC)) { /* Register to get notified when a new session is received */ wolfSSL_CTX_sess_set_new_cb(wctx->ssl_ctx, wssl_vtls_new_session_cb); } @@ -1287,7 +1293,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, wolfSSL_set_app_data(wctx->ssl, ssl_user_data); #ifdef WOLFSSL_QUIC - if(cf->conn->transport == TRNSPRT_QUIC) + if(transport == TRNSPRT_QUIC) wolfSSL_set_quic_use_legacy_codepoint(wctx->ssl, 0); #endif @@ -1787,49 +1793,48 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf, } } -static ssize_t wssl_send(struct Curl_cfilter *cf, - struct Curl_easy *data, - const void *buf, size_t blen, - CURLcode *curlcode) +static CURLcode wssl_send(struct Curl_cfilter *cf, + struct Curl_easy *data, + const void *buf, size_t blen, + size_t *pnwritten) { struct ssl_connect_data *connssl = cf->ctx; struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend; - size_t total_written = 0; - ssize_t nwritten = -1; - DEBUGASSERT(wssl); + CURLcode result = CURLE_OK; + int nwritten; + DEBUGASSERT(wssl); + *pnwritten = 0; wolfSSL_ERR_clear_error(); if(blen) { int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen; - int rc; - rc = wolfSSL_write(wssl->ssl, buf, memlen); - if(rc <= 0) { - int err = wolfSSL_get_error(wssl->ssl, rc); + nwritten = wolfSSL_write(wssl->ssl, buf, memlen); + + if(nwritten > 0) + *pnwritten += (size_t)nwritten; + else { + int err = wolfSSL_get_error(wssl->ssl, nwritten); switch(err) { case WOLFSSL_ERROR_WANT_READ: case WOLFSSL_ERROR_WANT_WRITE: /* there is data pending, re-invoke wolfSSL_write() */ - if(total_written) { - *curlcode = CURLE_OK; - nwritten = total_written; + if(*pnwritten) { + result = CURLE_OK; goto out; } - *curlcode = CURLE_AGAIN; - nwritten = -1; + result = CURLE_AGAIN; goto out; default: if(wssl->io_result == CURLE_AGAIN) { - if(total_written) { - *curlcode = CURLE_OK; - nwritten = total_written; + if(*pnwritten) { + result = CURLE_OK; goto out; } - *curlcode = CURLE_AGAIN; - nwritten = -1; + result = CURLE_AGAIN; goto out; } { @@ -1839,21 +1844,16 @@ static ssize_t wssl_send(struct Curl_cfilter *cf, sizeof(error_buffer)), SOCKERRNO); } - *curlcode = CURLE_SEND_ERROR; - nwritten = -1; + result = CURLE_SEND_ERROR; goto out; } } - else - total_written += rc; } - *curlcode = CURLE_OK; - nwritten = total_written; out: - CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %" FMT_OFF_T ", %d", - blen, nwritten, *curlcode); - return nwritten; + CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %d, %zu", + blen, result, *pnwritten); + return result; } static CURLcode wssl_shutdown(struct Curl_cfilter *cf, @@ -1980,10 +1980,10 @@ static void wssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) } } -static ssize_t wssl_recv(struct Curl_cfilter *cf, - struct Curl_easy *data, - char *buf, size_t blen, - CURLcode *curlcode) +static CURLcode wssl_recv(struct Curl_cfilter *cf, + struct Curl_easy *data, + char *buf, size_t blen, + size_t *pnread) { struct ssl_connect_data *connssl = cf->ctx; struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend; @@ -1992,41 +1992,38 @@ static ssize_t wssl_recv(struct Curl_cfilter *cf, DEBUGASSERT(wssl); + *pnread = 0; wolfSSL_ERR_clear_error(); - *curlcode = CURLE_OK; nread = wolfSSL_read(wssl->ssl, buf, buffsize); - if(nread <= 0) { + if(nread > 0) + *pnread = (size_t)nread; + else { int err = wolfSSL_get_error(wssl->ssl, nread); switch(err) { case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen); - *curlcode = CURLE_OK; - return 0; + return CURLE_OK; case WOLFSSL_ERROR_NONE: case WOLFSSL_ERROR_WANT_READ: case WOLFSSL_ERROR_WANT_WRITE: if(!wssl->io_result && connssl->peer_closed) { CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen); - *curlcode = CURLE_OK; - return 0; + return CURLE_OK; } /* there is data pending, re-invoke wolfSSL_read() */ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen); - *curlcode = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; default: if(wssl->io_result == CURLE_AGAIN) { CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen); - *curlcode = CURLE_AGAIN; - return -1; + return CURLE_AGAIN; } else if(!wssl->io_result && connssl->peer_closed) { CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen); - *curlcode = CURLE_OK; - return 0; + failf(data, "Connection closed abruptly"); } else { char error_buffer[256]; @@ -2035,13 +2032,12 @@ static ssize_t wssl_recv(struct Curl_cfilter *cf, sizeof(error_buffer)), SOCKERRNO); } - *curlcode = CURLE_RECV_ERROR; - return -1; + return CURLE_RECV_ERROR; } } - CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> %d", blen, nread); - return nread; + CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> 0, %zu", blen, *pnread); + return CURLE_OK; } size_t Curl_wssl_version(char *buffer, size_t size) @@ -2093,6 +2089,18 @@ static bool wssl_data_pending(struct Curl_cfilter *cf, return FALSE; } +void Curl_wssl_report_handshake(struct Curl_easy *data, + struct wssl_ctx *wssl) +{ +#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) + infof(data, "SSL connection using %s / %s", + wolfSSL_get_version(wssl->ssl), + wolfSSL_get_cipher_name(wssl->ssl)); +#else + infof(data, "SSL connected"); +#endif +} + static CURLcode wssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done) @@ -2166,16 +2174,9 @@ static CURLcode wssl_connect(struct Curl_cfilter *cf, } #endif /* HAVE_ALPN */ -#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010) - infof(data, "SSL connection using %s / %s", - wolfSSL_get_version(wssl->ssl), - wolfSSL_get_cipher_name(wssl->ssl)); -#else - infof(data, "SSL connected"); -#endif - connssl->connecting_state = ssl_connect_done; connssl->state = ssl_connection_complete; + Curl_wssl_report_handshake(data, wssl); #ifdef WOLFSSL_EARLY_DATA if(connssl->earlydata_state > ssl_earlydata_none) { @@ -2284,7 +2285,6 @@ const struct Curl_ssl Curl_ssl_wolfssl = { NULL, /* set_engine */ NULL, /* set_engine_default */ NULL, /* engines_list */ - NULL, /* false_start */ wssl_sha256sum, /* sha256sum */ wssl_recv, /* recv decrypted data */ wssl_send, /* send data to encrypt */ diff --git a/vendor/curl/lib/vtls/wolfssl.h b/vendor/curl/lib/vtls/wolfssl.h index 0ddbee9e..19ca609c 100644 --- a/vendor/curl/lib/vtls/wolfssl.h +++ b/vendor/curl/lib/vtls/wolfssl.h @@ -88,6 +88,8 @@ CURLcode Curl_wssl_verify_pinned(struct Curl_cfilter *cf, struct Curl_easy *data, struct wssl_ctx *wssl); +void Curl_wssl_report_handshake(struct Curl_easy *data, + struct wssl_ctx *wssl); #endif /* USE_WOLFSSL */ #endif /* HEADER_CURL_WOLFSSL_H */ diff --git a/vendor/curl/lib/vtls/x509asn1.c b/vendor/curl/lib/vtls/x509asn1.c index dd2aa145..fe47e81a 100644 --- a/vendor/curl/lib/vtls/x509asn1.c +++ b/vendor/curl/lib/vtls/x509asn1.c @@ -24,23 +24,21 @@ #include "../curl_setup.h" -#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \ - defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ +#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ defined(USE_MBEDTLS) || defined(USE_RUSTLS) -#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ - defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_RUSTLS) +#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \ + defined(USE_WOLFSSL) || defined(USE_RUSTLS) #define WANT_PARSEX509 /* uses Curl_parseX509() */ #endif -#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ - defined(USE_MBEDTLS) || defined(USE_RUSTLS) +#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \ + defined(USE_RUSTLS) #define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */ #endif #include #include "../urldata.h" -#include "../strcase.h" #include "../curl_ctype.h" #include "hostcheck.h" #include "vtls.h" @@ -256,14 +254,14 @@ static const char *getASN1Element(struct Curl_asn1Element *elem, #ifdef WANT_EXTRACT_CERTINFO /* - * Search the null terminated OID or OID identifier in local table. + * Search the null-terminated OID or OID identifier in local table. * Return the table entry pointer or NULL if not found. */ static const struct Curl_OID *searchOID(const char *oid) { const struct Curl_OID *op; for(op = OIDtable; op->numoid; op++) - if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) + if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid)) return op; return NULL; @@ -591,7 +589,7 @@ CURLcode Curl_x509_GTime2str(struct dynbuf *store, * Return error code. */ static CURLcode UTime2str(struct dynbuf *store, - const char *beg, const char *end) + const char *beg, const char *end) { const char *tzp; size_t tzl; @@ -861,7 +859,7 @@ int Curl_parseX509(struct Curl_X509certificate *cert, if(!getASN1Element(&cert->subjectPublicKey, ccp, cert->subjectPublicKeyInfo.end)) return -1; - /* Get optional issuerUiqueID, subjectUniqueID and extensions. */ + /* Get optional issuerUniqueID, subjectUniqueID and extensions. */ cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; cert->extensions.tag = elem.tag = 0; cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; @@ -990,7 +988,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, /* Generate all information records for the public key. */ - if(strcasecompare(algo, "ecPublicKey")) { + if(curl_strequal(algo, "ecPublicKey")) { /* * ECC public key is all the data, a value of type BIT STRING mapped to * OCTET STRING and should not be parsed as an ASN.1 value. @@ -1012,7 +1010,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, if(!getASN1Element(&pk, pubkey->beg + 1, pubkey->end)) return 1; - if(strcasecompare(algo, "rsaEncryption")) { + if(curl_strequal(algo, "rsaEncryption")) { const char *q; size_t len; @@ -1047,7 +1045,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, if(do_pubkey_field(data, certnum, "rsa(e)", &elem)) return 1; } - else if(strcasecompare(algo, "dsa")) { + else if(curl_strequal(algo, "dsa")) { p = getASN1Element(&elem, param->beg, param->end); if(p) { if(do_pubkey_field(data, certnum, "dsa(p)", &elem)) @@ -1065,7 +1063,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, } } } - else if(strcasecompare(algo, "dhpublicnumber")) { + else if(curl_strequal(algo, "dhpublicnumber")) { p = getASN1Element(&elem, param->beg, param->end); if(p) { if(do_pubkey_field(data, certnum, "dh(p)", &elem)) @@ -1277,5 +1275,5 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, #endif /* WANT_EXTRACT_CERTINFO */ -#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP - or USE_MBEDTLS or USE_RUSTLS */ +#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_MBEDTLS or + USE_RUSTLS */ diff --git a/vendor/curl/lib/vtls/x509asn1.h b/vendor/curl/lib/vtls/x509asn1.h index 1c9c35c3..f9bd455b 100644 --- a/vendor/curl/lib/vtls/x509asn1.h +++ b/vendor/curl/lib/vtls/x509asn1.h @@ -27,8 +27,7 @@ #include "../curl_setup.h" -#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \ - defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ +#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ defined(USE_MBEDTLS) || defined(USE_RUSTLS) #include "../cfilters.h" @@ -79,8 +78,8 @@ CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data, const char *beg, const char *end); #ifdef UNITTESTS -#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \ - defined(USE_MBEDTLS) || defined(USE_RUSTLS) +#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \ + defined(USE_RUSTLS) /* used by unit1656.c */ CURLcode Curl_x509_GTime2str(struct dynbuf *store, @@ -91,6 +90,6 @@ CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem, #endif #endif -#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP - or USE_MBEDTLS or USE_RUSTLS */ +#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_MBEDTLS or + USE_RUSTLS */ #endif /* HEADER_CURL_X509ASN1_H */ diff --git a/vendor/curl/lib/ws.c b/vendor/curl/lib/ws.c index 93ec3a78..7f8a688c 100644 --- a/vendor/curl/lib/ws.c +++ b/vendor/curl/lib/ws.c @@ -145,35 +145,77 @@ static int ws_frame_firstbyte2flags(struct Curl_easy *data, unsigned char firstbyte, int cont_flags) { switch(firstbyte) { + /* 0x00 - intermediate TEXT/BINARY fragment */ case WSBIT_OPCODE_CONT: - /* continuation of a previous fragment: restore stored flags */ + if(!(cont_flags & CURLWS_CONT)) { + failf(data, "[WS] no ongoing fragmented message to resume"); + return 0; + } return cont_flags | CURLWS_CONT; + /* 0x80 - final TEXT/BIN fragment */ case (WSBIT_OPCODE_CONT | WSBIT_FIN): - /* continuation of a previous fragment: restore stored flags */ + if(!(cont_flags & CURLWS_CONT)) { + failf(data, "[WS] no ongoing fragmented message to resume"); + return 0; + } return cont_flags & ~CURLWS_CONT; + /* 0x01 - first TEXT fragment */ case WSBIT_OPCODE_TEXT: + if(cont_flags & CURLWS_CONT) { + failf(data, "[WS] fragmented message interrupted by new TEXT msg"); + return 0; + } return CURLWS_TEXT | CURLWS_CONT; + /* 0x81 - unfragmented TEXT msg */ case (WSBIT_OPCODE_TEXT | WSBIT_FIN): + if(cont_flags & CURLWS_CONT) { + failf(data, "[WS] fragmented message interrupted by new TEXT msg"); + return 0; + } return CURLWS_TEXT; + /* 0x02 - first BINARY fragment */ case WSBIT_OPCODE_BIN: + if(cont_flags & CURLWS_CONT) { + failf(data, "[WS] fragmented message interrupted by new BINARY msg"); + return 0; + } return CURLWS_BINARY | CURLWS_CONT; + /* 0x82 - unfragmented BINARY msg */ case (WSBIT_OPCODE_BIN | WSBIT_FIN): + if(cont_flags & CURLWS_CONT) { + failf(data, "[WS] fragmented message interrupted by new BINARY msg"); + return 0; + } return CURLWS_BINARY; + /* 0x08 - first CLOSE fragment */ + case WSBIT_OPCODE_CLOSE: + failf(data, "[WS] invalid fragmented CLOSE frame"); + return 0; + /* 0x88 - unfragmented CLOSE */ case (WSBIT_OPCODE_CLOSE | WSBIT_FIN): return CURLWS_CLOSE; + /* 0x09 - first PING fragment */ + case WSBIT_OPCODE_PING: + failf(data, "[WS] invalid fragmented PING frame"); + return 0; + /* 0x89 - unfragmented PING */ case (WSBIT_OPCODE_PING | WSBIT_FIN): return CURLWS_PING; + /* 0x0a - first PONG fragment */ + case WSBIT_OPCODE_PONG: + failf(data, "[WS] invalid fragmented PONG frame"); + return 0; + /* 0x8a - unfragmented PONG */ case (WSBIT_OPCODE_PONG | WSBIT_FIN): return CURLWS_PONG; + /* invalid first byte */ default: - if(firstbyte & WSBIT_RSV_MASK) { - failf(data, "WS: unknown reserved bit: %x", - firstbyte & WSBIT_RSV_MASK); - } - else { - failf(data, "WS: unknown opcode: %x", - firstbyte & WSBIT_OPCODE_MASK); - } + if(firstbyte & WSBIT_RSV_MASK) + /* any of the reserved bits 0x40/0x20/0x10 are set */ + failf(data, "[WS] invalid reserved bits: %02x", firstbyte); + else + /* any of the reserved opcodes 0x3-0x7 or 0xb-0xf is used */ + failf(data, "[WS] invalid opcode: %02x", firstbyte); return 0; } } @@ -186,20 +228,20 @@ static unsigned char ws_frame_flags2firstbyte(struct Curl_easy *data, switch(flags & ~CURLWS_OFFSET) { case 0: if(contfragment) { - infof(data, "WS: no flags given; interpreting as continuation " + infof(data, "[WS] no flags given; interpreting as continuation " "fragment for compatibility"); return (WSBIT_OPCODE_CONT | WSBIT_FIN); } - failf(data, "WS: no flags given"); + failf(data, "[WS] no flags given"); *err = CURLE_BAD_FUNCTION_ARGUMENT; return 0xff; case CURLWS_CONT: if(contfragment) { - infof(data, "WS: setting CURLWS_CONT flag without message type is " + infof(data, "[WS] setting CURLWS_CONT flag without message type is " "supported for compatibility but highly discouraged"); return WSBIT_OPCODE_CONT; } - failf(data, "WS: No ongoing fragmented message to continue"); + failf(data, "[WS] No ongoing fragmented message to continue"); *err = CURLE_BAD_FUNCTION_ARGUMENT; return 0xff; case CURLWS_TEXT: @@ -215,24 +257,24 @@ static unsigned char ws_frame_flags2firstbyte(struct Curl_easy *data, case CURLWS_CLOSE: return WSBIT_OPCODE_CLOSE | WSBIT_FIN; case (CURLWS_CLOSE | CURLWS_CONT): - failf(data, "WS: CLOSE frame must not be fragmented"); + failf(data, "[WS] CLOSE frame must not be fragmented"); *err = CURLE_BAD_FUNCTION_ARGUMENT; return 0xff; case CURLWS_PING: return WSBIT_OPCODE_PING | WSBIT_FIN; case (CURLWS_PING | CURLWS_CONT): - failf(data, "WS: PING frame must not be fragmented"); + failf(data, "[WS] PING frame must not be fragmented"); *err = CURLE_BAD_FUNCTION_ARGUMENT; return 0xff; case CURLWS_PONG: return WSBIT_OPCODE_PONG | WSBIT_FIN; case (CURLWS_PONG | CURLWS_CONT): - failf(data, "WS: PONG frame must not be fragmented"); + failf(data, "[WS] PONG frame must not be fragmented"); *err = CURLE_BAD_FUNCTION_ARGUMENT; return 0xff; default: - failf(data, "WS: unknown flags: %x", flags); - *err = CURLE_SEND_ERROR; + failf(data, "[WS] unknown flags: %x", flags); + *err = CURLE_BAD_FUNCTION_ARGUMENT; return 0xff; } } @@ -244,23 +286,23 @@ static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data, case 0: break; case 1: - CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s]", msg, - ws_frame_name_of_op(dec->head[0]), - (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL"); + CURL_TRC_WS(data, "decoded %s [%s%s]", msg, + ws_frame_name_of_op(dec->head[0]), + (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL"); break; default: if(dec->head_len < dec->head_total) { - CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s](%d/%d)", msg, - ws_frame_name_of_op(dec->head[0]), - (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL", - dec->head_len, dec->head_total); + CURL_TRC_WS(data, "decoded %s [%s%s](%d/%d)", msg, + ws_frame_name_of_op(dec->head[0]), + (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL", + dec->head_len, dec->head_total); } else { - CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s payload=%" - FMT_OFF_T "/%" FMT_OFF_T "]", - msg, ws_frame_name_of_op(dec->head[0]), - (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL", - dec->payload_offset, dec->payload_len); + CURL_TRC_WS(data, "decoded %s [%s%s payload=%" + FMT_OFF_T "/%" FMT_OFF_T "]", + msg, ws_frame_name_of_op(dec->head[0]), + (dec->head[0] & WSBIT_FIN) ? "" : " NON-FINAL", + dec->payload_offset, dec->payload_len); } break; } @@ -318,17 +360,15 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, dec->frame_flags = ws_frame_firstbyte2flags(data, dec->head[0], dec->cont_flags); if(!dec->frame_flags) { - failf(data, "WS: invalid first byte: %x", dec->head[0]); ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_CONT) { + /* fragmentation only applies to data frames (text/binary); + * control frames (close/ping/pong) do not affect the CONT status */ + if(dec->frame_flags & (CURLWS_TEXT | CURLWS_BINARY)) { dec->cont_flags = dec->frame_flags; } - else { - dec->cont_flags = 0; - } dec->head_len = 1; /* ws_dec_info(dec, data, "seeing opcode"); */ @@ -341,10 +381,30 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, if(dec->head[1] & WSBIT_MASK) { /* A client MUST close a connection if it detects a masked frame. */ - failf(data, "WS: masked input frame"); + failf(data, "[WS] masked input frame"); + ws_dec_reset(dec); + return CURLE_RECV_ERROR; + } + if(dec->frame_flags & CURLWS_PING && dec->head[1] > 125) { + /* The maximum valid size of PING frames is 125 bytes. + Accepting overlong pings would mean sending equivalent pongs! */ + failf(data, "[WS] received PING frame is too big"); + ws_dec_reset(dec); + return CURLE_RECV_ERROR; + } + if(dec->frame_flags & CURLWS_PONG && dec->head[1] > 125) { + /* The maximum valid size of PONG frames is 125 bytes. */ + failf(data, "[WS] received PONG frame is too big"); + ws_dec_reset(dec); + return CURLE_RECV_ERROR; + } + if(dec->frame_flags & CURLWS_CLOSE && dec->head[1] > 125) { + /* The maximum valid size of CLOSE frames is 125 bytes. */ + failf(data, "[WS] received CLOSE frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; } + /* How long is the frame head? */ if(dec->head[1] == 126) { dec->head_total = 4; @@ -379,7 +439,7 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, break; case 10: if(dec->head[2] > 127) { - failf(data, "WS: frame length longer than 64 signed not supported"); + failf(data, "[WS] frame length longer than 64 signed not supported"); return CURLE_RECV_ERROR; } dec->payload_len = ((curl_off_t)dec->head[2] << 56) | @@ -394,7 +454,7 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, default: /* this should never happen */ DEBUGASSERT(0); - failf(data, "WS: unexpected frame header length"); + failf(data, "[WS] unexpected frame header length"); return CURLE_RECV_ERROR; } @@ -430,8 +490,8 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, Curl_bufq_skip(inraw, (size_t)nwritten); dec->payload_offset += (curl_off_t)nwritten; remain = dec->payload_len - dec->payload_offset; - CURL_TRC_WRITE(data, "websocket, passed %zd bytes payload, %" - FMT_OFF_T " remain", nwritten, remain); + CURL_TRC_WS(data, "passed %zd bytes payload, %" + FMT_OFF_T " remain", nwritten, remain); } return remain ? CURLE_AGAIN : CURLE_OK; @@ -457,7 +517,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, result = ws_dec_read_head(dec, data, inraw); if(result) { if(result != CURLE_AGAIN) { - infof(data, "WS: decode error %d", (int)result); + infof(data, "[WS] decode error %d", (int)result); break; /* real error */ } /* incomplete ws frame head */ @@ -483,7 +543,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, ws_dec_info(dec, data, "passing"); if(result) return result; - /* paylod parsing done */ + /* payload parsing done */ dec->state = WS_DEC_INIT; break; default: @@ -555,7 +615,7 @@ static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen, if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ size_t bytes; - infof(data, "WS: auto-respond to PING with a PONG"); + infof(data, "[WS] auto-respond to PING with a PONG"); /* send back the exact same content as a PONG */ *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG); if(*err) @@ -588,15 +648,15 @@ static CURLcode ws_cw_write(struct Curl_easy *data, ws = Curl_conn_meta_get(data->conn, CURL_META_PROTO_WS_CONN); if(!ws) { - failf(data, "WS: not a websocket transfer"); + failf(data, "[WS] not a websocket transfer"); return CURLE_FAILED_INIT; } if(nbytes) { - ssize_t nwritten; - nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf, - nbytes, &result); - if(nwritten < 0) { + size_t nwritten; + result = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf, + nbytes, &nwritten); + if(result) { infof(data, "WS: error adding data to buffer %d", result); return result; } @@ -613,17 +673,17 @@ static CURLcode ws_cw_write(struct Curl_easy *data, if(result == CURLE_AGAIN) { /* insufficient amount of data, keep it for later. * we pretend to have written all since we have a copy */ - CURL_TRC_WRITE(data, "websocket, buffered incomplete frame head"); + CURL_TRC_WS(data, "buffered incomplete frame head"); return CURLE_OK; } else if(result) { - infof(data, "WS: decode error %d", (int)result); + infof(data, "[WS] decode error %d", (int)result); return result; } } if((type & CLIENTWRITE_EOS) && !Curl_bufq_is_empty(&ctx->buf)) { - infof(data, "WS: decode ending with %zd frame bytes remaining", + failf(data, "[WS] decode ending with %zd frame bytes remaining", Curl_bufq_len(&ctx->buf)); return CURLE_RECV_ERROR; } @@ -645,10 +705,11 @@ static const struct Curl_cwtype ws_cw_decode = { static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data, const char *msg) { - infof(data, "WS-ENC: %s [%s%s payload=%" FMT_OFF_T "/%" FMT_OFF_T "]", - msg, ws_frame_name_of_op(enc->firstbyte), - (enc->firstbyte & WSBIT_FIN) ? "" : " NON-FIN", - enc->payload_len - enc->payload_remain, enc->payload_len); + CURL_TRC_WS(data, "WS-ENC: %s [%s%s payload=%" + FMT_OFF_T "/%" FMT_OFF_T "]", + msg, ws_frame_name_of_op(enc->firstbyte), + (enc->firstbyte & WSBIT_FIN) ? "" : " NON-FIN", + enc->payload_len - enc->payload_remain, enc->payload_len); } static void ws_enc_reset(struct ws_encoder *enc) @@ -695,11 +756,10 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, { unsigned char firstbyte = 0; unsigned char head[14]; - size_t hlen; - ssize_t n; + size_t hlen, n; if(payload_len < 0) { - failf(data, "WS: starting new frame with negative payload length %" + failf(data, "[WS] starting new frame with negative payload length %" FMT_OFF_T, payload_len); *err = CURLE_SEND_ERROR; return -1; @@ -707,7 +767,7 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, if(enc->payload_remain > 0) { /* trying to write a new frame before the previous one is finished */ - failf(data, "WS: starting new frame with %zd bytes from last one " + failf(data, "[WS] starting new frame with %zd bytes from last one " "remaining to be sent", (ssize_t)enc->payload_remain); *err = CURLE_SEND_ERROR; return -1; @@ -715,7 +775,6 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, firstbyte = ws_frame_flags2firstbyte(data, flags, enc->contfragment, err); if(*err) { - failf(data, "WS: provided flags not valid: %x", flags); return -1; } @@ -725,6 +784,25 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, enc->contfragment = (flags & CURLWS_CONT) ? (bit)TRUE : (bit)FALSE; } + if(flags & CURLWS_PING && payload_len > 125) { + /* The maximum valid size of PING frames is 125 bytes. */ + failf(data, "[WS] given PING frame is too big"); + *err = CURLE_TOO_LARGE; + return -1; + } + if(flags & CURLWS_PONG && payload_len > 125) { + /* The maximum valid size of PONG frames is 125 bytes. */ + failf(data, "[WS] given PONG frame is too big"); + *err = CURLE_TOO_LARGE; + return -1; + } + if(flags & CURLWS_CLOSE && payload_len > 125) { + /* The maximum valid size of CLOSE frames is 125 bytes. */ + failf(data, "[WS] given CLOSE frame is too big"); + *err = CURLE_TOO_LARGE; + return -1; + } + head[0] = enc->firstbyte = firstbyte; if(payload_len > 65535) { head[1] = 127 | WSBIT_MASK; @@ -758,16 +836,16 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, /* reset for payload to come */ enc->xori = 0; - n = Curl_bufq_write(out, head, hlen, err); - if(n < 0) + *err = Curl_bufq_write(out, head, hlen, &n); + if(*err) return -1; - if((size_t)n != hlen) { + if(n != hlen) { /* We use a bufq with SOFT_LIMIT, writing should always succeed */ DEBUGASSERT(0); *err = CURLE_SEND_ERROR; return -1; } - return n; + return (ssize_t)n; } static ssize_t ws_enc_write_payload(struct ws_encoder *enc, @@ -775,8 +853,7 @@ static ssize_t ws_enc_write_payload(struct ws_encoder *enc, const unsigned char *buf, size_t buflen, struct bufq *out, CURLcode *err) { - ssize_t n; - size_t i, len; + size_t i, len, n; if(Curl_bufq_is_full(out)) { *err = CURLE_AGAIN; @@ -790,8 +867,8 @@ static ssize_t ws_enc_write_payload(struct ws_encoder *enc, for(i = 0; i < len; ++i) { unsigned char c = buf[i] ^ enc->mask[enc->xori]; - n = Curl_bufq_write(out, &c, 1, err); - if(n < 0) { + *err = Curl_bufq_write(out, &c, 1, &n); + if(*err) { if((*err != CURLE_AGAIN) || !i) return -1; break; @@ -952,7 +1029,14 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, sizeof(ws->enc.mask)); if(result) return result; - infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x", + +#ifdef DEBUGBUILD + if(getenv("CURL_WS_FORCE_ZERO_MASK")) + /* force the bit mask to 0x00000000, effectively disabling masking */ + memset(ws->enc.mask, 0, sizeof(ws->enc.mask)); +#endif + + infof(data, "[WS] Received 101, switch to WebSocket; mask %02x%02x%02x%02x", ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]); /* Install our client writer that decodes WS frames payload */ @@ -968,14 +1052,15 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, } if(data->set.connect_only) { - ssize_t nwritten; + size_t nwritten; /* In CONNECT_ONLY setup, the payloads from `mem` need to be received * when using `curl_ws_recv` later on after this transfer is already * marked as DONE. */ - nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem, - nread, &result); - if(nwritten < 0) + result = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem, + nread, &nwritten); + if(result) return result; + DEBUGASSERT(nread == nwritten); infof(data, "%zu bytes websocket payload", nread); } else { /* !connect_only */ @@ -1025,7 +1110,7 @@ static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ size_t bytes; - infof(ctx->data, "WS: auto-respond to PING with a PONG"); + infof(ctx->data, "[WS] auto-respond to PING with a PONG"); /* send back the exact same content as a PONG */ *err = curl_ws_send(ctx->data, buf, buflen, &bytes, 0, CURLWS_PONG); if(*err) @@ -1051,22 +1136,17 @@ static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, return nwritten; } -static ssize_t nw_in_recv(void *reader_ctx, - unsigned char *buf, size_t buflen, - CURLcode *err) +static CURLcode nw_in_recv(void *reader_ctx, + unsigned char *buf, size_t buflen, + size_t *pnread) { struct Curl_easy *data = reader_ctx; - size_t nread; - - *err = curl_easy_recv(data, buf, buflen, &nread); - if(*err) - return -1; - return (ssize_t)nread; + return curl_easy_recv(data, buf, buflen, pnread); } -CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer, - size_t buflen, size_t *nread, - const struct curl_ws_frame **metap) +CURLcode curl_ws_recv(CURL *d, void *buffer, + size_t buflen, size_t *nread, + const struct curl_ws_frame **metap) { struct Curl_easy *data = d; struct connectdata *conn = data->conn; @@ -1079,19 +1159,19 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer, if(!conn) { /* Unhappy hack with lifetimes of transfers and connection */ if(!data->set.connect_only) { - failf(data, "CONNECT_ONLY is required"); + failf(data, "[WS] CONNECT_ONLY is required"); return CURLE_UNSUPPORTED_PROTOCOL; } Curl_getconnectinfo(data, &conn); if(!conn) { - failf(data, "connection not found"); + failf(data, "[WS] connection not found"); return CURLE_BAD_FUNCTION_ARGUMENT; } } ws = Curl_conn_meta_get(conn, CURL_META_PROTO_WS_CONN); if(!ws) { - failf(data, "connection is not setup for websocket"); + failf(data, "[WS] connection is not setup for websocket"); return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -1106,13 +1186,13 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *d, void *buffer, /* receive more when our buffer is empty */ if(Curl_bufq_is_empty(&ws->recvbuf)) { - ssize_t n = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &result); - if(n < 0) { + size_t n; + result = Curl_bufq_slurp(&ws->recvbuf, nw_in_recv, data, &n); + if(result) return result; - } else if(n == 0) { /* connection closed */ - infof(data, "connection expectedly closed?"); + infof(data, "[WS] connection expectedly closed?"); return CURLE_GOT_NOTHING; } CURL_TRC_WS(data, "curl_ws_recv, added %zu bytes from network", @@ -1196,11 +1276,11 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, return result; } else if(result) { - failf(data, "WS: flush, write error %d", result); + failf(data, "[WS] flush, write error %d", result); return result; } else { - infof(data, "WS: flushed %zu bytes", n); + CURL_TRC_WS(data, "flushed %zu bytes", n); Curl_bufq_skip(&ws->sendbuf, n); } } @@ -1232,7 +1312,7 @@ static CURLcode ws_send_raw_blocking(CURL *d, struct websocket *ws, buflen); left_ms = Curl_timeleft(data, NULL, FALSE); if(left_ms < 0) { - failf(data, "Timeout waiting for socket becoming writable"); + failf(data, "[WS] Timeout waiting for socket becoming writable"); return CURLE_SEND_ERROR; } @@ -1242,7 +1322,7 @@ static CURLcode ws_send_raw_blocking(CURL *d, struct websocket *ws, ev = Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, sock, left_ms ? left_ms : 500); if(ev < 0) { - failf(data, "Error while waiting for socket becoming writable"); + failf(data, "[WS] Error while waiting for socket becoming writable"); return CURLE_SEND_ERROR; } } @@ -1258,7 +1338,7 @@ static CURLcode ws_send_raw(struct Curl_easy *data, const void *buffer, ws = Curl_conn_meta_get(data->conn, CURL_META_PROTO_WS_CONN); if(!ws) { - failf(data, "Not a websocket transfer"); + failf(data, "[WS] Not a websocket transfer"); return CURLE_SEND_ERROR; } if(!buflen) @@ -1287,10 +1367,10 @@ static CURLcode ws_send_raw(struct Curl_easy *data, const void *buffer, return result; } -CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg, - size_t buflen, size_t *sent, - curl_off_t fragsize, - unsigned int flags) +CURLcode curl_ws_send(CURL *d, const void *buffer_arg, + size_t buflen, size_t *sent, + curl_off_t fragsize, + unsigned int flags) { struct websocket *ws; const unsigned char *buffer = buffer_arg; @@ -1308,13 +1388,13 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg, goto out; } if(!data->conn) { - failf(data, "No associated connection"); + failf(data, "[WS] No associated connection"); result = CURLE_SEND_ERROR; goto out; } ws = Curl_conn_meta_get(data->conn, CURL_META_PROTO_WS_CONN); if(!ws) { - failf(data, "Not a websocket transfer"); + failf(data, "[WS] Not a websocket transfer"); result = CURLE_SEND_ERROR; goto out; } @@ -1327,7 +1407,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg, goto out; if(fragsize || flags) { - failf(data, "ws_send, raw mode: fragsize and flags cannot be non-zero"); + failf(data, "[WS] fragsize and flags must be zero in raw mode"); return CURLE_BAD_FUNCTION_ARGUMENT; } result = ws_send_raw(data, buffer, buflen, sent); @@ -1342,7 +1422,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg, if(buflen < ws->sendbuf_payload) { /* We have been called with LESS buffer data than before. This * is not how it's supposed too work. */ - failf(data, "curl_ws_send() called with smaller 'buflen' than " + failf(data, "[WS] curl_ws_send() called with smaller 'buflen' than " "bytes already buffered in previous call, %zu vs %zu", buflen, ws->sendbuf_payload); result = CURLE_BAD_FUNCTION_ARGUMENT; @@ -1351,7 +1431,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg, if((curl_off_t)buflen > (ws->enc.payload_remain + (curl_off_t)ws->sendbuf_payload)) { /* too large buflen beyond payload length of frame */ - infof(data, "WS: unaligned frame size (sending %zu instead of %" + failf(data, "[WS] unaligned frame size (sending %zu instead of %" FMT_OFF_T ")", buflen, ws->enc.payload_remain + ws->sendbuf_payload); result = CURLE_BAD_FUNCTION_ARGUMENT; @@ -1384,11 +1464,15 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *d, const void *buffer_arg, if(n < 0 && (result != CURLE_AGAIN)) goto out; ws->sendbuf_payload += Curl_bufq_len(&ws->sendbuf) - prev_len; + if(!ws->sendbuf_payload) { + result = CURLE_AGAIN; + goto out; + } } /* flush, blocking when in callback */ result = ws_flush(data, ws, Curl_is_in_callback(data)); - if(!result) { + if(!result && ws->sendbuf_payload > 0) { *sent += ws->sendbuf_payload; buffer += ws->sendbuf_payload; buflen -= ws->sendbuf_payload; @@ -1437,7 +1521,7 @@ static CURLcode ws_setup_conn(struct Curl_easy *data, } -CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *d) +const struct curl_ws_frame *curl_ws_meta(CURL *d) { /* we only return something for websocket, called from within the callback when not using raw mode */ @@ -1510,9 +1594,9 @@ const struct Curl_handler Curl_handler_wss = { #else -CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, - size_t *nread, - const struct curl_ws_frame **metap) +CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *nread, + const struct curl_ws_frame **metap) { (void)curl; (void)buffer; @@ -1522,10 +1606,10 @@ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, return CURLE_NOT_BUILT_IN; } -CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, - size_t buflen, size_t *sent, - curl_off_t fragsize, - unsigned int flags) +CURLcode curl_ws_send(CURL *curl, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t fragsize, + unsigned int flags) { (void)curl; (void)buffer; @@ -1536,7 +1620,7 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, return CURLE_NOT_BUILT_IN; } -CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *data) +const struct curl_ws_frame *curl_ws_meta(CURL *data) { (void)data; return NULL;