diff options
author | dartraiden <wowemuh@gmail.com> | 2021-11-16 22:24:39 +0300 |
---|---|---|
committer | dartraiden <wowemuh@gmail.com> | 2021-11-16 22:26:13 +0300 |
commit | 53a0928794b1b7f3e9bbb7c09d939d32378379d6 (patch) | |
tree | 00b4b965972b4133dd56fcaa1e80b5c330687837 /libs/libcurl/src | |
parent | aa3402bb65378066b00862547ebe7b6ce5c821c6 (diff) |
libcurl: update to 7.80.0
Diffstat (limited to 'libs/libcurl/src')
110 files changed, 2735 insertions, 1554 deletions
diff --git a/libs/libcurl/src/.checksrc b/libs/libcurl/src/.checksrc new file mode 100644 index 0000000000..16133a44c5 --- /dev/null +++ b/libs/libcurl/src/.checksrc @@ -0,0 +1 @@ +enable STRERROR diff --git a/libs/libcurl/src/Makefile.am b/libs/libcurl/src/Makefile.am index b51796f91e..7693639415 100644 --- a/libs/libcurl/src/Makefile.am +++ b/libs/libcurl/src/Makefile.am @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -30,7 +30,7 @@ EXTRA_DIST = Makefile.m32 config-win32.h config-win32ce.h \ config-os400.h setup-os400.h \ config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \ - setup-win32.h + setup-win32.h .checksrc lib_LTLIBRARIES = libcurl.la diff --git a/libs/libcurl/src/Makefile.in b/libs/libcurl/src/Makefile.in index 2c01947112..188b2c4c25 100644 --- a/libs/libcurl/src/Makefile.in +++ b/libs/libcurl/src/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.16.3 from Makefile.am. +# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2020 Free Software Foundation, Inc. +# Copyright (C) 1994-2021 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -728,8 +728,6 @@ am__define_uniq_tagged_files = \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.inc \ $(srcdir)/curl_config.h.in $(srcdir)/libcurl.vers.in \ $(top_srcdir)/depcomp @@ -755,6 +753,8 @@ CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ CURLVERSION = @CURLVERSION@ CURL_CA_BUNDLE = @CURL_CA_BUNDLE@ CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@ @@ -791,6 +791,7 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ ENABLE_SHARED = @ENABLE_SHARED@ ENABLE_STATIC = @ENABLE_STATIC@ +ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FISH_FUNCTIONS_DIR = @FISH_FUNCTIONS_DIR@ @@ -956,7 +957,7 @@ top_srcdir = @top_srcdir@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -979,7 +980,7 @@ EXTRA_DIST = Makefile.m32 config-win32.h config-win32ce.h \ config-os400.h setup-os400.h \ config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \ - setup-win32.h + setup-win32.h .checksrc lib_LTLIBRARIES = libcurl.la @BUILD_UNITTESTS_FALSE@noinst_LTLIBRARIES = @@ -4190,7 +4191,6 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am diff --git a/libs/libcurl/src/Makefile.m32 b/libs/libcurl/src/Makefile.m32 index 9f1f5963d5..d78614da33 100644 --- a/libs/libcurl/src/Makefile.m32 +++ b/libs/libcurl/src/Makefile.m32 @@ -179,12 +179,10 @@ SYNC = 1 endif ifeq ($(findstring -rtmp,$(CFG)),-rtmp) RTMP = 1 -SSL = 1 ZLIB = 1 endif ifeq ($(findstring -ssh2,$(CFG)),-ssh2) SSH2 = 1 -SSL = 1 ZLIB = 1 endif ifeq ($(findstring -ssl,$(CFG)),-ssl) @@ -237,6 +235,13 @@ ifeq ($(findstring -unicode,$(CFG)),-unicode) UNICODE = 1 endif +# SSH2 and RTMP require an SSL library; assume OpenSSL if none specified +ifneq ($(SSH2)$(RTMP),) + ifeq ($(SSL)$(WINSSL),) + SSL = 1 + endif +endif + INCLUDES = -I. -I../include CFLAGS += -DBUILDING_LIBCURL ifdef SSL @@ -299,7 +304,7 @@ ifdef SSL endif endif ifneq "$(wildcard $(OPENSSL_INCLUDE)/openssl/opensslv.h)" "$(OPENSSL_INCLUDE)/openssl/opensslv.h" - $(error Invalid path to OpenSSL package: $(OPENSSL_PATH)) + $(error Invalid path to OpenSSL package: $(OPENSSL_PATH)) endif ifndef OPENSSL_LIBPATH ifeq "$(wildcard $(OPENSSL_PATH)/out)" "$(OPENSSL_PATH)/out" diff --git a/libs/libcurl/src/Makefile.netware b/libs/libcurl/src/Makefile.netware index cf7904aa72..92752128da 100644 --- a/libs/libcurl/src/Makefile.netware +++ b/libs/libcurl/src/Makefile.netware @@ -580,7 +580,6 @@ endif @echo $(DL)#define HAVE_SETLOCALE 1$(DL) >> $@ @echo $(DL)#define HAVE_SIGNAL 1$(DL) >> $@ @echo $(DL)#define HAVE_SIGNAL_H 1$(DL) >> $@ - @echo $(DL)#define HAVE_SIG_ATOMIC_T 1$(DL) >> $@ @echo $(DL)#define HAVE_SOCKET 1$(DL) >> $@ @echo $(DL)#define HAVE_STDLIB_H 1$(DL) >> $@ @echo $(DL)#define HAVE_STRDUP 1$(DL) >> $@ diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c index 839fabb86a..fc168baa6e 100644 --- a/libs/libcurl/src/asyn-ares.c +++ b/libs/libcurl/src/asyn-ares.c @@ -59,7 +59,6 @@ #include "hostip.h" #include "hash.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "multiif.h" #include "inet_pton.h" @@ -80,13 +79,33 @@ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif +#if ARES_VERSION >= 0x010601 +/* IPv6 supported since 1.6.1 */ +#define HAVE_CARES_IPV6 1 +#endif + +#if ARES_VERSION >= 0x010704 +#define HAVE_CARES_SERVERS_CSV 1 +#define HAVE_CARES_LOCAL_DEV 1 +#define HAVE_CARES_SET_LOCAL 1 +#endif + +#if ARES_VERSION >= 0x010b00 +#define HAVE_CARES_PORTS_CSV 1 +#endif + +#if ARES_VERSION >= 0x011000 +/* 1.16.0 or later has ares_getaddrinfo */ +#define HAVE_CARES_GETADDRINFO 1 +#endif + /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" struct thread_data { - int num_pending; /* number of ares_gethostbyname() requests */ + int num_pending; /* number of outstanding c-ares requests */ struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ int last_status; @@ -322,7 +341,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) nfds = 0; if(!nfds) - /* Call ares_process() unconditonally here, even if we simply timed out + /* Call ares_process() unconditionally here, even if we simply timed out above, as otherwise the ares name resolve won't timeout! */ ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD, ARES_SOCKET_BAD); @@ -490,6 +509,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, return result; } +#ifndef HAVE_CARES_GETADDRINFO + /* Connects results to the list */ static void compound_results(struct thread_data *res, struct Curl_addrinfo *ai) @@ -620,8 +641,99 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */ } } } +#else +/* c-ares 1.16.0 or later */ /* + * ares2addr() converts an address list provided by c-ares to an internal + * libcurl compatible list + */ +static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node) +{ + /* traverse the ares_addrinfo_node list */ + struct ares_addrinfo_node *ai; + struct Curl_addrinfo *cafirst = NULL; + struct Curl_addrinfo *calast = NULL; + int error = 0; + + for(ai = node; ai != NULL; ai = ai->ai_next) { + size_t ss_size; + struct Curl_addrinfo *ca; + /* ignore elements with unsupported address family, */ + /* settle family-specific sockaddr structure size. */ + if(ai->ai_family == AF_INET) + ss_size = sizeof(struct sockaddr_in); +#ifdef ENABLE_IPV6 + else if(ai->ai_family == AF_INET6) + ss_size = sizeof(struct sockaddr_in6); +#endif + else + continue; + + /* ignore elements without required address info */ + if(!ai->ai_addr || !(ai->ai_addrlen > 0)) + continue; + + /* ignore elements with bogus address size */ + if((size_t)ai->ai_addrlen < ss_size) + continue; + + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size); + if(!ca) { + error = EAI_MEMORY; + break; + } + + /* copy each structure member individually, member ordering, */ + /* size, or padding might be different for each platform. */ + + ca->ai_flags = ai->ai_flags; + ca->ai_family = ai->ai_family; + ca->ai_socktype = ai->ai_socktype; + ca->ai_protocol = ai->ai_protocol; + ca->ai_addrlen = (curl_socklen_t)ss_size; + ca->ai_addr = NULL; + ca->ai_canonname = NULL; + ca->ai_next = NULL; + + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); + memcpy(ca->ai_addr, ai->ai_addr, ss_size); + + /* if the return list is empty, this becomes the first element */ + if(!cafirst) + cafirst = ca; + + /* add this element last in the return list */ + if(calast) + calast->ai_next = ca; + calast = ca; + } + + /* if we failed, destroy the Curl_addrinfo list */ + if(error) { + Curl_freeaddrinfo(cafirst); + cafirst = NULL; + } + + return cafirst; +} + +static void addrinfo_cb(void *arg, int status, int timeouts, + struct ares_addrinfo *result) +{ + struct Curl_easy *data = (struct Curl_easy *)arg; + struct thread_data *res = data->state.async.tdata; + (void)timeouts; + if(ARES_SUCCESS == status) { + res->temp_ai = ares2addr(result->nodes); + res->last_status = CURL_ASYNC_SUCCESS; + ares_freeaddrinfo(result); + } + res->num_pending--; +} + +#endif +/* * Curl_resolver_getaddrinfo() - when using ares * * Returns name information about the given hostname and port number. If @@ -658,8 +770,28 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, /* initial status - failed */ res->last_status = ARES_ENOTFOUND; -#if ARES_VERSION >= 0x010601 - /* IPv6 supported by c-ares since 1.6.1 */ +#ifdef HAVE_CARES_GETADDRINFO + { + struct ares_addrinfo_hints hints; + char service[12]; + int pf = PF_INET; + memset(&hints, 0, sizeof(hints)); +#ifdef CURLRES_IPV6 + if(Curl_ipv6works(data)) + /* The stack seems to be IPv6-enabled */ + pf = PF_UNSPEC; +#endif /* CURLRES_IPV6 */ + hints.ai_family = pf; + hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)? + SOCK_STREAM : SOCK_DGRAM; + msnprintf(service, sizeof(service), "%d", port); + res->num_pending = 1; + ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, + service, &hints, addrinfo_cb, data); + } +#else + +#ifdef HAVE_CARES_IPV6 if(Curl_ipv6works(data)) { /* The stack seems to be IPv6-enabled */ res->num_pending = 2; @@ -671,7 +803,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, PF_INET6, query_completed_cb, data); } else -#endif /* ARES_VERSION >= 0x010601 */ +#endif { res->num_pending = 1; @@ -680,7 +812,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, hostname, PF_INET, query_completed_cb, data); } - +#endif *waitp = 1; /* expect asynchronous response */ } return NULL; /* no struct yet */ @@ -701,8 +833,8 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data, if(!(servers && servers[0])) return CURLE_OK; -#if (ARES_VERSION >= 0x010704) -#if (ARES_VERSION >= 0x010b00) +#ifdef HAVE_CARES_SERVERS_CSV +#ifdef HAVE_CARES_PORTS_CSV ares_result = ares_set_servers_ports_csv(data->state.async.resolver, servers); #else @@ -732,7 +864,7 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data, CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { -#if (ARES_VERSION >= 0x010704) +#ifdef HAVE_CARES_LOCAL_DEV if(!interf) interf = ""; @@ -749,7 +881,7 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data, CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { -#if (ARES_VERSION >= 0x010704) +#ifdef HAVE_CARES_SET_LOCAL struct in_addr a4; if((!local_ip4) || (local_ip4[0] == 0)) { @@ -775,7 +907,7 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { -#if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6) +#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6) unsigned char a6[INET6_ADDRSTRLEN]; if((!local_ip6) || (local_ip6[0] == 0)) { diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c index 36f68cb493..149172ad3d 100644 --- a/libs/libcurl/src/asyn-thread.c +++ b/libs/libcurl/src/asyn-thread.c @@ -68,7 +68,6 @@ #include "hostip.h" #include "hash.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "multiif.h" #include "inet_ntop.h" diff --git a/libs/libcurl/src/c-hyper.c b/libs/libcurl/src/c-hyper.c index 2cc5d496e1..c253cd36ed 100644 --- a/libs/libcurl/src/c-hyper.c +++ b/libs/libcurl/src/c-hyper.c @@ -156,13 +156,15 @@ static int hyper_each_header(void *userdata, Curl_debug(data, CURLINFO_HEADER_IN, headp, len); - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - result = Curl_client_write(data, writetype, headp, len); - if(result) { - data->state.hresult = CURLE_ABORTED_BY_CALLBACK; - return HYPER_ITER_BREAK; + if(!data->state.hconnect || !data->set.suppress_connect_headers) { + writetype = CLIENTWRITE_HEADER; + if(data->set.include_header) + writetype |= CLIENTWRITE_BODY; + result = Curl_client_write(data, writetype, headp, len); + if(result) { + data->state.hresult = CURLE_ABORTED_BY_CALLBACK; + return HYPER_ITER_BREAK; + } } data->info.header_size += (long)len; @@ -176,7 +178,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk) size_t len = hyper_buf_len(chunk); struct Curl_easy *data = (struct Curl_easy *)userdata; struct SingleRequest *k = &data->req; - CURLcode result; + CURLcode result = CURLE_OK; if(0 == k->bodywrites++) { bool done = FALSE; @@ -192,8 +194,21 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk) Curl_safefree(data->req.newurl); } #endif - if(data->state.hconnect && - (data->req.httpcode/100 != 2)) { + if(data->state.expect100header) { + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + if(data->req.httpcode < 400) { + k->exp100 = EXP100_SEND_DATA; + if(data->hyp.exp100_waker) { + hyper_waker_wake(data->hyp.exp100_waker); + data->hyp.exp100_waker = NULL; + } + } + else { /* >= 4xx */ + k->exp100 = EXP100_FAILED; + } + } + if(data->state.hconnect && (data->req.httpcode/100 != 2) && + data->state.authproxy.done) { done = TRUE; result = CURLE_OK; } @@ -245,6 +260,15 @@ static CURLcode status_line(struct Curl_easy *data, conn->httpversion = http_version == HYPER_HTTP_VERSION_1_1 ? 11 : (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10); + if(http_version == HYPER_HTTP_VERSION_1_0) + data->state.httpwant = CURL_HTTP_VERSION_1_0; + + if(data->state.hconnect) + /* CONNECT */ + data->info.httpproxycode = http_status; + + /* We need to set 'httpcodeq' for functions that check the response code in + a single place. */ data->req.httpcode = http_status; result = Curl_http_statusline(data, conn); @@ -262,16 +286,18 @@ static CURLcode status_line(struct Curl_easy *data, len = Curl_dyn_len(&data->state.headerb); Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb), len); - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - result = Curl_client_write(data, writetype, - Curl_dyn_ptr(&data->state.headerb), len); - if(result) { - data->state.hresult = CURLE_ABORTED_BY_CALLBACK; - return HYPER_ITER_BREAK; - } + if(!data->state.hconnect || !data->set.suppress_connect_headers) { + writetype = CLIENTWRITE_HEADER; + if(data->set.include_header) + writetype |= CLIENTWRITE_BODY; + result = Curl_client_write(data, writetype, + Curl_dyn_ptr(&data->state.headerb), len); + if(result) { + data->state.hresult = CURLE_ABORTED_BY_CALLBACK; + return HYPER_ITER_BREAK; + } + } data->info.header_size += (long)len; data->req.headerbytecount += (long)len; data->req.httpcode = http_status; @@ -284,8 +310,14 @@ static CURLcode status_line(struct Curl_easy *data, */ static CURLcode empty_header(struct Curl_easy *data) { - return hyper_each_header(data, NULL, 0, NULL, 0) ? - CURLE_WRITE_ERROR : CURLE_OK; + CURLcode result = Curl_http_size(data); + if(!result) { + result = hyper_each_header(data, NULL, 0, NULL, 0) ? + CURLE_WRITE_ERROR : CURLE_OK; + if(result) + failf(data, "hyperstream: couldn't pass blank header"); + } + return result; } CURLcode Curl_hyper_stream(struct Curl_easy *data, @@ -306,8 +338,25 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, const uint8_t *reasonp; size_t reason_len; CURLcode result = CURLE_OK; + struct SingleRequest *k = &data->req; (void)conn; + if(k->exp100 > EXP100_SEND_DATA) { + struct curltime now = Curl_now(); + timediff_t ms = Curl_timediff(now, k->start100); + if(ms >= data->set.expect_100_timeout) { + /* we've waited long enough, continue anyway */ + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + Curl_expire_done(data, EXPIRE_100_TIMEOUT); + infof(data, "Done waiting for 100-continue"); + if(data->hyp.exp100_waker) { + hyper_waker_wake(data->hyp.exp100_waker); + data->hyp.exp100_waker = NULL; + } + } + } + if(select_res & CURL_CSELECT_IN) { if(h->read_waker) hyper_waker_wake(h->read_waker); @@ -341,8 +390,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, hyper_task_free(task); if(t == HYPER_TASK_ERROR) { - hyper_code errnum = hyper_error_code(hypererr); - if(errnum == HYPERE_ABORTED_BY_CALLBACK) { + if(data->state.hresult) { /* override Hyper's view, might not even be an error */ result = data->state.hresult; infof(data, "hyperstream is done (by early callback)"); @@ -352,7 +400,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf)); hyper_code code = hyper_error_code(hypererr); failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf); - if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount) + if(code == HYPERE_ABORTED_BY_CALLBACK) + result = CURLE_OK; + else if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount) result = CURLE_GOT_NOTHING; else if(code == HYPERE_INVALID_PEER_MESSAGE) result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */ @@ -367,6 +417,11 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, /* end of transfer */ *done = TRUE; infof(data, "hyperstream is done!"); + if(!k->bodywrites) { + /* hyper doesn't always call the body write callback */ + bool stilldone; + result = Curl_http_firstwrite(data, data->conn, &stilldone); + } break; } else if(t != HYPER_TASK_RESPONSE) { @@ -405,11 +460,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, break; } - if(empty_header(data)) { - failf(data, "hyperstream: couldn't pass blank header"); - result = CURLE_OUT_OF_MEMORY; + result = empty_header(data); + if(result) break; - } /* Curl_http_auth_act() checks what authentication methods that are * available and decides which one (if any) to use. It will set 'newurl' @@ -523,7 +576,7 @@ CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers, free(ptr); } else - Curl_debug(data, CURLINFO_HEADER_OUT, (char *)line, linelen); + Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen); } numh++; n += linelen; @@ -546,9 +599,22 @@ static CURLcode request_target(struct Curl_easy *data, if(result) return result; - if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r), - Curl_dyn_len(&r))) { - failf(data, "error setting path"); + if(h2 && hyper_request_set_uri_parts(req, + /* scheme */ + (uint8_t *)data->state.up.scheme, + strlen(data->state.up.scheme), + /* authority */ + (uint8_t *)conn->host.name, + strlen(conn->host.name), + /* path_and_query */ + (uint8_t *)Curl_dyn_uptr(&r), + Curl_dyn_len(&r))) { + failf(data, "error setting uri parts to hyper"); + result = CURLE_OUT_OF_MEMORY; + } + else if(!h2 && hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r), + Curl_dyn_len(&r))) { + failf(data, "error setting uri to hyper"); result = CURLE_OUT_OF_MEMORY; } else @@ -564,6 +630,16 @@ static int uploadpostfields(void *userdata, hyper_context *ctx, { struct Curl_easy *data = (struct Curl_easy *)userdata; (void)ctx; + if(data->req.exp100 > EXP100_SEND_DATA) { + if(data->req.exp100 == EXP100_FAILED) + return HYPER_POLL_ERROR; + + /* still waiting confirmation */ + if(data->hyp.exp100_waker) + hyper_waker_free(data->hyp.exp100_waker); + data->hyp.exp100_waker = hyper_context_waker(ctx); + return HYPER_POLL_PENDING; + } if(data->req.upload_done) *chunk = NULL; /* nothing more to deliver */ else { @@ -590,9 +666,21 @@ static int uploadstreamed(void *userdata, hyper_context *ctx, { size_t fillcount; struct Curl_easy *data = (struct Curl_easy *)userdata; - CURLcode result = - Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount); + CURLcode result; (void)ctx; + + if(data->req.exp100 > EXP100_SEND_DATA) { + if(data->req.exp100 == EXP100_FAILED) + return HYPER_POLL_ERROR; + + /* still waiting confirmation */ + if(data->hyp.exp100_waker) + hyper_waker_free(data->hyp.exp100_waker); + data->hyp.exp100_waker = hyper_context_waker(ctx); + return HYPER_POLL_PENDING; + } + + result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount); if(result) { data->state.hresult = result; return HYPER_POLL_ERROR; @@ -627,6 +715,7 @@ static CURLcode bodysend(struct Curl_easy *data, hyper_request *hyperreq, Curl_HttpReq httpreq) { + struct HTTP *http = data->req.p.http; CURLcode result = CURLE_OK; struct dynbuf req; if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) @@ -659,6 +748,7 @@ static CURLcode bodysend(struct Curl_easy *data, result = CURLE_OUT_OF_MEMORY; } } + http->sending = HTTPSEND_BODY; return result; } @@ -677,6 +767,48 @@ static CURLcode cookies(struct Curl_easy *data, return result; } +/* called on 1xx responses */ +static void http1xx_cb(void *arg, struct hyper_response *resp) +{ + struct Curl_easy *data = (struct Curl_easy *)arg; + hyper_headers *headers = NULL; + CURLcode result = CURLE_OK; + uint16_t http_status; + int http_version; + const uint8_t *reasonp; + size_t reason_len; + + infof(data, "Got HTTP 1xx informational"); + + http_status = hyper_response_status(resp); + http_version = hyper_response_version(resp); + reasonp = hyper_response_reason_phrase(resp); + reason_len = hyper_response_reason_phrase_len(resp); + + result = status_line(data, data->conn, + http_status, http_version, reasonp, reason_len); + if(!result) { + headers = hyper_response_headers(resp); + if(!headers) { + failf(data, "hyperstream: couldn't get 1xx response headers"); + result = CURLE_RECV_ERROR; + } + } + data->state.hresult = result; + + if(!result) { + /* the headers are already received */ + hyper_headers_foreach(headers, hyper_each_header, data); + /* this callback also sets data->state.hresult on error */ + + if(empty_header(data)) + result = CURLE_OUT_OF_MEMORY; + } + + if(data->state.hresult) + infof(data, "ERROR in 1xx, bail out!"); +} + /* * Curl_http() gets called from the generic multi_do() function when a HTTP * request is to be performed. This creates and sends a properly constructed @@ -694,13 +826,13 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) hyper_request *req = NULL; hyper_headers *headers = NULL; hyper_task *handshake = NULL; - hyper_error *hypererr = NULL; CURLcode result; const char *p_accept; /* Accept: string */ const char *method; Curl_HttpReq httpreq; bool h2 = FALSE; const char *te = NULL; /* transfer-encoding */ + hyper_code rc; /* Always consider the DO phase done after this function call, even if there may be parts of the request that is not yet sent, since we can deal with @@ -746,6 +878,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) io = hyper_io_new(); if(!io) { failf(data, "Couldn't create hyper IO"); + result = CURLE_OUT_OF_MEMORY; goto error; } /* tell Hyper how to read/write network data */ @@ -758,6 +891,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) h->exec = hyper_executor_new(); if(!h->exec) { failf(data, "Couldn't create hyper executor"); + result = CURLE_OUT_OF_MEMORY; goto error; } } @@ -765,6 +899,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) options = hyper_clientconn_options_new(); if(!options) { failf(data, "Couldn't create hyper client options"); + result = CURLE_OUT_OF_MEMORY; goto error; } if(conn->negnpn == CURL_HTTP_VERSION_2) { @@ -778,6 +913,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) handshake = hyper_clientconn_handshake(io, options); if(!handshake) { failf(data, "Couldn't create hyper client handshake"); + result = CURLE_OUT_OF_MEMORY; goto error; } io = NULL; @@ -785,6 +921,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) { failf(data, "Couldn't hyper_executor_push the handshake"); + result = CURLE_OUT_OF_MEMORY; goto error; } handshake = NULL; /* ownership passed on */ @@ -792,6 +929,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) task = hyper_executor_poll(h->exec); if(!task) { failf(data, "Couldn't hyper_executor_poll the handshake"); + result = CURLE_OUT_OF_MEMORY; goto error; } @@ -801,19 +939,22 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) req = hyper_request_new(); if(!req) { failf(data, "Couldn't hyper_request_new"); + result = CURLE_OUT_OF_MEMORY; goto error; } - if(data->state.httpwant == CURL_HTTP_VERSION_1_0) { + if(!Curl_use_http_1_1plus(data, conn)) { if(HYPERE_OK != hyper_request_set_version(req, HYPER_HTTP_VERSION_1_0)) { failf(data, "error setting HTTP version"); + result = CURLE_OUT_OF_MEMORY; goto error; } } if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) { failf(data, "error setting method"); + result = CURLE_OUT_OF_MEMORY; goto error; } @@ -824,47 +965,81 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) headers = hyper_request_headers(req); if(!headers) { failf(data, "hyper_request_headers"); + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + rc = hyper_request_on_informational(req, http1xx_cb, data); + if(rc) { + result = CURLE_OUT_OF_MEMORY; goto error; } result = Curl_http_body(data, conn, httpreq, &te); if(result) - return result; - - if(data->state.aptr.host && - Curl_hyper_header(data, headers, data->state.aptr.host)) goto error; - if(data->state.aptr.proxyuserpwd && - Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd)) - goto error; + if(!h2) { + if(data->state.aptr.host) { + result = Curl_hyper_header(data, headers, data->state.aptr.host); + if(result) + goto error; + } + } + else { + /* For HTTP/2, we show the Host: header as if we sent it, to make it look + like for HTTP/1 but it isn't actually sent since :authority is then + used. */ + result = Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host, + strlen(data->state.aptr.host)); + if(result) + goto error; + } - if(data->state.aptr.userpwd && - Curl_hyper_header(data, headers, data->state.aptr.userpwd)) - goto error; + if(data->state.aptr.proxyuserpwd) { + result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd); + if(result) + goto error; + } - if((data->state.use_range && data->state.aptr.rangeline) && - Curl_hyper_header(data, headers, data->state.aptr.rangeline)) - goto error; + if(data->state.aptr.userpwd) { + result = Curl_hyper_header(data, headers, data->state.aptr.userpwd); + if(result) + goto error; + } + + if((data->state.use_range && data->state.aptr.rangeline)) { + result = Curl_hyper_header(data, headers, data->state.aptr.rangeline); + if(result) + goto error; + } if(data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT] && - data->state.aptr.uagent && - Curl_hyper_header(data, headers, data->state.aptr.uagent)) - goto error; + data->state.aptr.uagent) { + result = Curl_hyper_header(data, headers, data->state.aptr.uagent); + if(result) + goto error; + } p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n"; - if(p_accept && Curl_hyper_header(data, headers, p_accept)) - goto error; - - if(te && Curl_hyper_header(data, headers, te)) - goto error; + if(p_accept) { + result = Curl_hyper_header(data, headers, p_accept); + if(result) + goto error; + } + if(te) { + result = Curl_hyper_header(data, headers, te); + if(result) + goto error; + } #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy && !Curl_checkheaders(data, "Proxy-Connection") && !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) { - if(Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive")) + result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"); + if(result) goto error; } #endif @@ -873,8 +1048,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(data->state.referer && !Curl_checkheaders(data, "Referer")) { data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); if(!data->state.aptr.ref) - return CURLE_OUT_OF_MEMORY; - if(Curl_hyper_header(data, headers, data->state.aptr.ref)) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_hyper_header(data, headers, data->state.aptr.ref); + if(result) goto error; } @@ -884,8 +1061,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) data->state.aptr.accept_encoding = aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); if(!data->state.aptr.accept_encoding) - return CURLE_OUT_OF_MEMORY; - if(Curl_hyper_header(data, headers, data->state.aptr.accept_encoding)) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_hyper_header(data, headers, + data->state.aptr.accept_encoding); + if(result) goto error; } else @@ -895,61 +1075,58 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) /* we only consider transfer-encoding magic if libz support is built-in */ result = Curl_transferencode(data); if(result) - return result; - if(Curl_hyper_header(data, headers, data->state.aptr.te)) + goto error; + result = Curl_hyper_header(data, headers, data->state.aptr.te); + if(result) goto error; #endif result = cookies(data, conn, headers); if(result) - return result; + goto error; result = Curl_add_timecondition(data, headers); if(result) - return result; + goto error; result = Curl_add_custom_headers(data, FALSE, headers); if(result) - return result; + goto error; result = bodysend(data, conn, headers, req, httpreq); if(result) - return result; + goto error; - Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2); + result = Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2); + if(result) + goto error; data->req.upload_chunky = FALSE; sendtask = hyper_clientconn_send(client, req); if(!sendtask) { failf(data, "hyper_clientconn_send"); + result = CURLE_OUT_OF_MEMORY; goto error; } if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) { failf(data, "Couldn't hyper_executor_push the send"); + result = CURLE_OUT_OF_MEMORY; goto error; } hyper_clientconn_free(client); - do { - task = hyper_executor_poll(h->exec); - if(task) { - bool error = hyper_task_type(task) == HYPER_TASK_ERROR; - if(error) - hypererr = hyper_task_value(task); - hyper_task_free(task); - if(error) - goto error; - } - } while(task); - if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) { /* HTTP GET/HEAD download */ Curl_pgrsSetUploadSize(data, 0); /* nothing */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); } conn->datastream = Curl_hyper_stream; + if(data->state.expect100header) + /* Timeout count starts now since with Hyper we don't know exactly when + the full request has been sent. */ + data->req.start100 = Curl_now(); /* clear userpwd and proxyuserpwd to avoid re-using old credentials * from re-used connections */ @@ -957,7 +1134,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) Curl_safefree(data->state.aptr.proxyuserpwd); return CURLE_OK; error: - + DEBUGASSERT(result); if(io) hyper_io_free(io); @@ -967,16 +1144,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(handshake) hyper_task_free(handshake); - if(hypererr) { - uint8_t errbuf[256]; - size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf)); - hyper_code code = hyper_error_code(hypererr); - failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf); - hyper_error_free(hypererr); - if(data->state.hresult) - return data->state.hresult; - } - return CURLE_OUT_OF_MEMORY; + return result; } void Curl_hyper_done(struct Curl_easy *data) @@ -994,6 +1162,10 @@ void Curl_hyper_done(struct Curl_easy *data) hyper_waker_free(h->write_waker); h->write_waker = NULL; } + if(h->exp100_waker) { + hyper_waker_free(h->exp100_waker); + h->exp100_waker = NULL; + } } #endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */ diff --git a/libs/libcurl/src/c-hyper.h b/libs/libcurl/src/c-hyper.h index d60ed78d1d..d63defeffe 100644 --- a/libs/libcurl/src/c-hyper.h +++ b/libs/libcurl/src/c-hyper.h @@ -33,6 +33,7 @@ struct hyptransfer { hyper_waker *read_waker; const hyper_executor *exec; hyper_task *endtask; + hyper_waker *exp100_waker; }; size_t Curl_hyper_recv(void *userp, hyper_context *ctx, diff --git a/libs/libcurl/src/checksrc.pl b/libs/libcurl/src/checksrc.pl index a35535c191..8f98a99ab5 100644 --- a/libs/libcurl/src/checksrc.pl +++ b/libs/libcurl/src/checksrc.pl @@ -47,6 +47,7 @@ my @ignore_line; my %warnings_extended = ( 'COPYRIGHTYEAR' => 'copyright year incorrect', + 'STRERROR', => 'strerror() detected', ); my %warnings = ( @@ -87,7 +88,7 @@ my %warnings = ( 'EXCLAMATIONSPACE' => 'Whitespace after exclamation mark in expression', 'EMPTYLINEBRACE' => 'Empty line before the open brace', 'EQUALSNULL' => 'if/while comparison with == NULL', - 'NOTEQUALSZERO' => 'if/while comparison with != 0' + 'NOTEQUALSZERO', => 'if/while comparison with != 0', ); sub readskiplist { @@ -238,9 +239,17 @@ if(!$file) { print " -i<n> Indent spaces. Default: 2\n"; print " -m<n> Maximum line length. Default: 79\n"; print "\nDetects and warns for these problems:\n"; - for(sort keys %warnings) { - printf (" %-18s: %s\n", $_, $warnings{$_}); + my @allw = keys %warnings; + push @allw, keys %warnings_extended; + for my $w (sort @allw) { + if($warnings{$w}) { + printf (" %-18s: %s\n", $w, $warnings{$w}); + } + else { + printf (" %-18s: %s[*]\n", $w, $warnings_extended{$w}); + } } + print " [*] = disabled by default\n"; exit; } @@ -361,7 +370,10 @@ sub scanfile { my $line = 1; my $prevl=""; - my $l; + my $prevpl=""; + my $l = ""; + my $prep = 0; + my $prevp = 0; open(R, "<$file") || die "failed to open $file"; my $incomment=0; @@ -443,6 +455,14 @@ sub scanfile { # comments # ------------------------------------------------------------ + # prev line was a preprocessor **and** ended with a backslash + if($prep && ($prevpl =~ /\\ *\z/)) { + # this is still a preprocessor line + $prep = 1; + goto preproc; + } + $prep = 0; + # crude attempt to detect // comments without too many false # positives if($l =~ /^(([^"\*]*)[^:"]|)\/\//) { @@ -450,6 +470,13 @@ sub scanfile { $line, length($1), $file, $l, "\/\/ comment"); } + # detect and strip preprocessor directives + if($l =~ /^[ \t]*\#/) { + # preprocessor line + $prep = 1; + goto preproc; + } + my $nostr = nostrings($l); # check spaces after for/if/while/function call if($nostr =~ /^(.*)(for|if|while| ([a-zA-Z0-9_]+)) \((.)/) { @@ -520,7 +547,6 @@ sub scanfile { } elsif($even && $postparen && ($postparen !~ /^ *$/) && ($postparen !~ /^ *[,{&|\\]+/)) { - print STDERR "5: '$postparen'\n"; checkwarn("ONELINECONDITION", $line, length($l)-length($postparen), $file, $l, "conditional block on the same line"); @@ -621,7 +647,7 @@ sub scanfile { # check for space before the semicolon last in a line if($l =~ /^(.*[^ ].*) ;$/) { checkwarn("SPACESEMICOLON", - $line, length($1), $file, $ol, "space before last semicolon"); + $line, length($1), $file, $ol, "no space before semicolon"); } # scan for use of banned functions @@ -638,7 +664,18 @@ sub scanfile { $line, length($1), $file, $ol, "use of $2 is banned"); } - + if($warnings{"STRERROR"}) { + # scan for use of banned strerror. This is not a BANNEDFUNC to + # allow for individual enable/disable of this warning. + if($l =~ /^(.*\W)(strerror)\s*\(/x) { + if($1 !~ /^ *\#/) { + # skip preprocessor lines + checkwarn("STRERROR", + $line, length($1), $file, $ol, + "use of $2 is banned"); + } + } + } # scan for use of snprintf for curl-internals reasons if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) { checkwarn("SNPRINTF", @@ -656,10 +693,9 @@ sub scanfile { } } - # check for open brace first on line but not first column - # only alert if previous line ended with a close paren and wasn't a cpp - # line - if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) { + # check for open brace first on line but not first column only alert + # if previous line ended with a close paren and it wasn't a cpp line + if(($prevl =~ /\)\z/) && ($l =~ /^( +)\{/) && !$prevp) { checkwarn("BRACEPOS", $line, length($1), $file, $ol, "badly placed open brace"); } @@ -667,11 +703,10 @@ sub scanfile { # if the previous line starts with if/while/for AND ends with an open # brace, or an else statement, check that this line is indented $indent # more steps, if not a cpp line - if($prevl =~ /^( *)((if|while|for)\(.*\{|else)\z/) { + if(!$prevp && ($prevl =~ /^( *)((if|while|for)\(.*\{|else)\z/)) { my $first = length($1); - # this line has some character besides spaces - if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) { + if($l =~ /^( *)[^ ]/) { my $second = length($1); my $expect = $first+$indent; if($expect != $second) { @@ -762,13 +797,13 @@ sub scanfile { $nostr =~ /^(.*(\S)) + [{?]/i) { checkwarn("MULTISPACE", $line, length($1)+1, $file, $ol, - "multiple space"); - print STDERR "L: $l\n"; - print STDERR "nostr: $nostr\n"; + "multiple spaces"); } - + preproc: $line++; - $prevl = $ol; + $prevp = $prep; + $prevl = $ol if(!$prep); + $prevpl = $ol if($prep); } if(!scalar(@copyright)) { diff --git a/libs/libcurl/src/config-amigaos.h b/libs/libcurl/src/config-amigaos.h index 0bbf4c41df..842cbc247b 100644 --- a/libs/libcurl/src/config-amigaos.h +++ b/libs/libcurl/src/config-amigaos.h @@ -55,7 +55,6 @@ #define HAVE_SETJMP_H 1 #define HAVE_SIGNAL 1 #define HAVE_SIGNAL_H 1 -#define HAVE_SIG_ATOMIC_T 1 #define HAVE_SOCKET 1 #define HAVE_STRCASECMP 1 #define HAVE_STRDUP 1 diff --git a/libs/libcurl/src/config-mac.h b/libs/libcurl/src/config-mac.h index c8833e3006..22d32d480d 100644 --- a/libs/libcurl/src/config-mac.h +++ b/libs/libcurl/src/config-mac.h @@ -67,7 +67,6 @@ #define HAVE_SIGACTION 1 #define HAVE_SIGNAL_H 1 -#define HAVE_SIG_ATOMIC_T 1 #ifdef MACOS_SSL_SUPPORT # define USE_OPENSSL 1 diff --git a/libs/libcurl/src/config-os400.h b/libs/libcurl/src/config-os400.h index cff9c3e624..d68cb4b18e 100644 --- a/libs/libcurl/src/config-os400.h +++ b/libs/libcurl/src/config-os400.h @@ -235,12 +235,6 @@ /* Define if you have the <signal.h> header file. */ #define HAVE_SIGNAL_H -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T - -/* Define if sig_atomic_t is already defined as volatile. */ -#undef HAVE_SIG_ATOMIC_T_VOLATILE - /* Define if you have the `socket' function. */ #define HAVE_SOCKET @@ -334,9 +328,6 @@ /* Define if you have the <unistd.h> header file. */ #define HAVE_UNISTD_H -/* Define if you have the <winsock.h> header file. */ -#undef HAVE_WINSOCK_H - /* Define if you have the <x509.h> header file. */ #undef HAVE_X509_H diff --git a/libs/libcurl/src/config-plan9.h b/libs/libcurl/src/config-plan9.h index 9b98a6e249..dbe9b82af6 100644 --- a/libs/libcurl/src/config-plan9.h +++ b/libs/libcurl/src/config-plan9.h @@ -149,7 +149,6 @@ #define HAVE_SIGNAL 1 #define HAVE_SIGNAL_H 1 #define HAVE_SIGSETJMP 1 -#define HAVE_SIG_ATOMIC_T 1 #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 #define HAVE_SOCKET 1 #define HAVE_SSL_GET_SHUTDOWN 1 diff --git a/libs/libcurl/src/config-riscos.h b/libs/libcurl/src/config-riscos.h index 0535137bef..9986b20fba 100644 --- a/libs/libcurl/src/config-riscos.h +++ b/libs/libcurl/src/config-riscos.h @@ -227,12 +227,6 @@ /* Define if you have the <signal.h> header file. */ #define HAVE_SIGNAL_H -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T - -/* Define if sig_atomic_t is already defined as volatile. */ -#undef HAVE_SIG_ATOMIC_T_VOLATILE - /* Define if you have the `socket' function. */ #define HAVE_SOCKET @@ -311,9 +305,6 @@ /* Define if you have the <unistd.h> header file. */ #define HAVE_UNISTD_H -/* Define if you have the <winsock.h> header file. */ -#undef HAVE_WINSOCK_H - /* Define if you have the <x509.h> header file. */ #undef HAVE_X509_H diff --git a/libs/libcurl/src/config-tpf.h b/libs/libcurl/src/config-tpf.h index ab29bfccc2..cce06cedd8 100644 --- a/libs/libcurl/src/config-tpf.h +++ b/libs/libcurl/src/config-tpf.h @@ -366,12 +366,6 @@ /* Define to 1 if you have the <signal.h> header file. */ #define HAVE_SIGNAL_H 1 -/* Define to 1 if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ - /* If you have sigsetjmp */ /* #undef HAVE_SIGSETJMP */ @@ -489,9 +483,6 @@ /* Define to 1 if you have the <winsock2.h> header file. */ /* #undef HAVE_WINSOCK2_H */ -/* Define to 1 if you have the <winsock.h> header file. */ -/* #undef HAVE_WINSOCK_H */ - /* Define this symbol if your OS supports changing the contents of argv */ /* #undef HAVE_WRITABLE_ARGV */ diff --git a/libs/libcurl/src/config-vxworks.h b/libs/libcurl/src/config-vxworks.h index 22d2b964a4..af1d87345c 100644 --- a/libs/libcurl/src/config-vxworks.h +++ b/libs/libcurl/src/config-vxworks.h @@ -445,12 +445,6 @@ /* Define to 1 if you have the sigsetjmp function or macro. */ /* #undef HAVE_SIGSETJMP */ -/* Define to 1 if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */ - /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 @@ -607,9 +601,6 @@ /* Define to 1 if you have the winsock2.h header file. */ /* #undef HAVE_WINSOCK2_H */ -/* Define to 1 if you have the winsock.h header file. */ -/* #undef HAVE_WINSOCK_H */ - /* Define this symbol if your OS supports changing the contents of argv */ #define HAVE_WRITABLE_ARGV 1 diff --git a/libs/libcurl/src/config-win32.h b/libs/libcurl/src/config-win32.h index 2021fab815..89593a815d 100644 --- a/libs/libcurl/src/config-win32.h +++ b/libs/libcurl/src/config-win32.h @@ -132,9 +132,6 @@ /* Define if you have the <windows.h> header file. */ #define HAVE_WINDOWS_H 1 -/* Define if you have the <winsock.h> header file. */ -#define HAVE_WINSOCK_H 1 - /* Define if you have the <winsock2.h> header file. */ #ifndef __SALFORDC__ #define HAVE_WINSOCK2_H 1 @@ -149,9 +146,6 @@ /* OTHER HEADER INFO */ /* ---------------------------------------------------------------- */ -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 @@ -231,10 +225,6 @@ /* Define if you have the socket function. */ #define HAVE_SOCKET 1 -/* Define if libSSH2 is in use */ -#define USE_LIBSSH2 1 -#define HAVE_LIBSSH2_H 1 - /* Define if you have the strcasecmp function. */ #ifdef __MINGW32__ #define HAVE_STRCASECMP 1 @@ -388,7 +378,6 @@ #ifdef USE_LWIPSOCK # undef USE_WINSOCK -# undef HAVE_WINSOCK_H # undef HAVE_WINSOCK2_H # undef HAVE_WS2TCPIP_H # undef HAVE_ERRNO_H @@ -419,7 +408,6 @@ #undef byte #undef word #undef USE_WINSOCK - #undef HAVE_WINSOCK_H #undef HAVE_WINSOCK2_H #undef HAVE_WS2TCPIP_H #define HAVE_GETADDRINFO @@ -677,9 +665,6 @@ Vista # define CURL_DISABLE_LDAP 1 #endif -/* if SSL is enabled */ -#define USE_OPENSSL 1 - /* Define to use the Windows crypto library. */ #if !defined(CURL_WINDOWS_APP) #define USE_WIN32_CRYPTO diff --git a/libs/libcurl/src/config-win32ce.h b/libs/libcurl/src/config-win32ce.h index f3f02e720a..889028b269 100644 --- a/libs/libcurl/src/config-win32ce.h +++ b/libs/libcurl/src/config-win32ce.h @@ -110,22 +110,16 @@ /* Define if you have the <windows.h> header file. */ #define HAVE_WINDOWS_H 1 -/* Define if you have the <winsock.h> header file. */ -#define HAVE_WINSOCK_H 1 - /* Define if you have the <winsock2.h> header file. */ -/* #define HAVE_WINSOCK2_H 1 */ +#define HAVE_WINSOCK2_H 1 /* Define if you have the <ws2tcpip.h> header file. */ -/* #define HAVE_WS2TCPIP_H 1 */ +#define HAVE_WS2TCPIP_H 1 /* ---------------------------------------------------------------- */ /* OTHER HEADER INFO */ /* ---------------------------------------------------------------- */ -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c index 11e6b888b7..af60947314 100644 --- a/libs/libcurl/src/connect.c +++ b/libs/libcurl/src/connect.c @@ -85,7 +85,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error); -#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H) +#if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H) /* DragonFlyBSD and Windows use millisecond units */ #define KEEPALIVE_FACTOR(x) (x *= 1000) #else @@ -589,12 +589,10 @@ static CURLcode trynextip(struct Curl_easy *data, struct Curl_addrinfo *ai = conn->tempaddr[tempindex]; while(ai) { - if(ai) { - result = singleipconnect(data, conn, ai, tempindex); - if(result == CURLE_COULDNT_CONNECT) { - ai = ainext(conn, tempindex, TRUE); - continue; - } + result = singleipconnect(data, conn, ai, tempindex); + if(result == CURLE_COULDNT_CONNECT) { + ai = ainext(conn, tempindex, TRUE); + continue; } break; } @@ -631,7 +629,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, #ifdef ENABLE_IPV6 struct sockaddr_in6 *si6 = NULL; #endif -#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) +#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX) struct sockaddr_un *su = NULL; #else (void)salen; @@ -658,7 +656,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, } break; #endif -#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) +#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX) case AF_UNIX: if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) { su = (struct sockaddr_un*)sa; @@ -746,18 +744,15 @@ void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd, void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn, curl_socket_t sockfd) { - /* 'local_ip' and 'local_port' get filled with local's numerical - ip address and port number whenever an outgoing connection is - **established** from the primary socket to a remote address. */ + /* 'local_ip' and 'local_port' get filled with local's numerical ip address + and port number whenever an outgoing connection is **established** from + the primary socket to a remote address. */ char local_ip[MAX_IPADR_LEN] = ""; int local_port = -1; - if(conn->transport == TRNSPRT_TCP) { - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { - Curl_conninfo_remote(data, conn, sockfd); - Curl_conninfo_local(data, sockfd, local_ip, &local_port); - } - } /* end of TCP-only section */ + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) + Curl_conninfo_remote(data, conn, sockfd); + Curl_conninfo_local(data, sockfd, local_ip, &local_port); /* persist connection info in session handle */ Curl_persistconninfo(data, conn, local_ip, local_port); diff --git a/libs/libcurl/src/content_encoding.c b/libs/libcurl/src/content_encoding.c index a84ff543b9..c03637a391 100644 --- a/libs/libcurl/src/content_encoding.c +++ b/libs/libcurl/src/content_encoding.c @@ -240,7 +240,8 @@ static CURLcode inflate_stream(struct Curl_easy *data, } zp->zlib_init = ZLIB_UNINIT; /* inflateEnd() already called. */ } - /* FALLTHROUGH */ + result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); + break; default: result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z)); break; diff --git a/libs/libcurl/src/curl_config.h.cmake b/libs/libcurl/src/curl_config.h.cmake index fa4f19c74f..d2a0f438cc 100644 --- a/libs/libcurl/src/curl_config.h.cmake +++ b/libs/libcurl/src/curl_config.h.cmake @@ -33,61 +33,91 @@ /* Location of default ca path */ #cmakedefine CURL_CA_PATH "${CURL_CA_PATH}" -/* to disable cookies support */ +/* disables alt-svc */ +#cmakedefine CURL_DISABLE_ALTSVC 1 + +/* disables cookies support */ #cmakedefine CURL_DISABLE_COOKIES 1 -/* to disable cryptographic authentication */ +/* disables cryptographic authentication */ #cmakedefine CURL_DISABLE_CRYPTO_AUTH 1 -/* to disable DICT */ +/* disables DICT */ #cmakedefine CURL_DISABLE_DICT 1 -/* to disable FILE */ +/* disables DNS-over-HTTPS */ +#cmakedefine CURL_DISABLE_DOH 1 + +/* disables FILE */ #cmakedefine CURL_DISABLE_FILE 1 -/* to disable FTP */ +/* disables FTP */ #cmakedefine CURL_DISABLE_FTP 1 -/* to disable GOPHER */ +/* disables GOPHER */ #cmakedefine CURL_DISABLE_GOPHER 1 -/* to disable IMAP */ -#cmakedefine CURL_DISABLE_IMAP 1 +/* disables HSTS support */ +#cmakedefine CURL_DISABLE_HSTS 1 -/* to disable HTTP */ +/* disables HTTP */ #cmakedefine CURL_DISABLE_HTTP 1 -/* to disable LDAP */ +/* disables IMAP */ +#cmakedefine CURL_DISABLE_IMAP 1 + +/* disables LDAP */ #cmakedefine CURL_DISABLE_LDAP 1 -/* to disable LDAPS */ +/* disables LDAPS */ #cmakedefine CURL_DISABLE_LDAPS 1 -/* to disable MQTT */ +/* disables --libcurl option from the curl tool */ +#cmakedefine CURL_DISABLE_LIBCURL_OPTION 1 + +/* disables MIME support */ +#cmakedefine CURL_DISABLE_MIME 1 + +/* disables MQTT */ #cmakedefine CURL_DISABLE_MQTT 1 -/* to disable POP3 */ +/* disables netrc parser */ +#cmakedefine CURL_DISABLE_NETRC 1 + +/* disables NTLM support */ +#cmakedefine CURL_DISABLE_NTLM 1 + +/* disables date parsing */ +#cmakedefine CURL_DISABLE_PARSEDATE 1 + +/* disables POP3 */ #cmakedefine CURL_DISABLE_POP3 1 -/* to disable proxies */ +/* disables built-in progress meter */ +#cmakedefine CURL_DISABLE_PROGRESS_METER 1 + +/* disables proxies */ #cmakedefine CURL_DISABLE_PROXY 1 -/* to disable RTSP */ +/* disables RTSP */ #cmakedefine CURL_DISABLE_RTSP 1 -/* to disable SMB */ +/* disables SMB */ #cmakedefine CURL_DISABLE_SMB 1 -/* to disable SMTP */ +/* disables SMTP */ #cmakedefine CURL_DISABLE_SMTP 1 -/* to disable TELNET */ +/* disables use of socketpair for curl_multi_poll */ +#cmakedefine CURL_DISABLE_SOCKETPAIR 1 + +/* disables TELNET */ #cmakedefine CURL_DISABLE_TELNET 1 -/* to disable TFTP */ +/* disables TFTP */ #cmakedefine CURL_DISABLE_TFTP 1 -/* to disable verbose strings */ +/* disables verbose strings */ #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 /* to make a symbol visible */ @@ -521,12 +551,6 @@ /* Define to 1 if you have the sigsetjmp function or macro. */ #cmakedefine HAVE_SIGSETJMP 1 -/* Define to 1 if sig_atomic_t is an available typedef. */ -#cmakedefine HAVE_SIG_ATOMIC_T 1 - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE 1 - /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 @@ -686,9 +710,6 @@ /* Define to 1 if you have the winsock2.h header file. */ #cmakedefine HAVE_WINSOCK2_H 1 -/* Define to 1 if you have the winsock.h header file. */ -#cmakedefine HAVE_WINSOCK_H 1 - /* Define this symbol if your OS supports changing the contents of argv */ #cmakedefine HAVE_WRITABLE_ARGV 1 @@ -931,9 +952,6 @@ ${SIZEOF_TIME_T_CODE} /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS -/* to disable alt-svc */ -#cmakedefine CURL_DISABLE_ALTSVC 1 - /* Define to 1 if you are building a Windows target with large file support. */ #cmakedefine USE_WIN32_LARGE_FILES 1 diff --git a/libs/libcurl/src/curl_config.h.in b/libs/libcurl/src/curl_config.h.in index 5a8190f8c0..751f6a4f65 100644 --- a/libs/libcurl/src/curl_config.h.in +++ b/libs/libcurl/src/curl_config.h.in @@ -588,12 +588,6 @@ /* Define to 1 if you have the sigsetjmp function or macro. */ #undef HAVE_SIGSETJMP -/* Define to 1 if sig_atomic_t is an available typedef. */ -#undef HAVE_SIG_ATOMIC_T - -/* Define to 1 if sig_atomic_t is already defined as volatile. */ -#undef HAVE_SIG_ATOMIC_T_VOLATILE - /* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */ #undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID @@ -621,6 +615,9 @@ /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H @@ -765,9 +762,6 @@ /* Define to 1 if you have the winsock2.h header file. */ #undef HAVE_WINSOCK2_H -/* Define to 1 if you have the winsock.h header file. */ -#undef HAVE_WINSOCK_H - /* Define to 1 if you have the <wolfssh/ssh.h> header file. */ #undef HAVE_WOLFSSH_SSH_H @@ -924,7 +918,9 @@ /* The number of bytes in type time_t */ #undef SIZEOF_TIME_T -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Define to the type of arg 3 for strerror_r. */ @@ -1058,11 +1054,6 @@ # undef _ALL_SOURCE #endif -/* Enable large inode numbers on Mac OS X 10.5. */ -#ifndef _DARWIN_USE_64_BIT_INODE -# define _DARWIN_USE_64_BIT_INODE 1 -#endif - /* Number of bits in a file offset, on hosts where this is settable. */ #undef _FILE_OFFSET_BITS diff --git a/libs/libcurl/src/curl_des.c b/libs/libcurl/src/curl_des.c index 8c5af19cd2..76185cbf21 100644 --- a/libs/libcurl/src/curl_des.c +++ b/libs/libcurl/src/curl_des.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2015 - 2020, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2015 - 2021, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,7 @@ #include "curl_setup.h" -#if defined(USE_NTLM) && !defined(USE_OPENSSL) +#if defined(USE_NTLM) && !defined(USE_OPENSSL) && !defined(USE_WOLFSSL) #include "curl_des.h" diff --git a/libs/libcurl/src/curl_gssapi.c b/libs/libcurl/src/curl_gssapi.c index 5810dad14b..8f340562bc 100644 --- a/libs/libcurl/src/curl_gssapi.c +++ b/libs/libcurl/src/curl_gssapi.c @@ -32,10 +32,12 @@ #include "curl_memory.h" #include "memdebug.h" -static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02"; -gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes }; -static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; -gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; +gss_OID_desc Curl_spnego_mech_oid = { + 6, (char *)"\x2b\x06\x01\x05\x05\x02" +}; +gss_OID_desc Curl_krb5_mech_oid = { + 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" +}; OM_uint32 Curl_gss_init_sec_context( struct Curl_easy *data, diff --git a/libs/libcurl/src/curl_ntlm_core.c b/libs/libcurl/src/curl_ntlm_core.c index 749b44e4a9..ed123d0c1c 100644 --- a/libs/libcurl/src/curl_ntlm_core.c +++ b/libs/libcurl/src/curl_ntlm_core.c @@ -49,7 +49,14 @@ in NTLM type-3 messages. */ -#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) +#if defined(USE_OPENSSL) + #include <openssl/opensslconf.h> + #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0) + #define USE_OPENSSL_DES + #endif +#endif + +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) #ifdef USE_WOLFSSL #include <wolfssl/options.h> @@ -97,7 +104,7 @@ #elif defined(USE_WIN32_CRYPTO) # include <wincrypt.h> #else -# error "Can't compile NTLM support without a crypto library." +# error "Can't compile NTLM support without a crypto library with DES." #endif #include "urldata.h" @@ -133,7 +140,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key) key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); } -#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) /* * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The * key schedule ks is also set. @@ -150,7 +157,7 @@ static void setup_des_key(const unsigned char *key_56, DES_set_odd_parity(&key); /* Set the key */ - DES_set_key(&key, ks); + DES_set_key_unchecked(&key, ks); } #elif defined(USE_GNUTLS) @@ -362,7 +369,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results) { -#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) DES_key_schedule ks; setup_des_key(keys, DESKEY(ks)); @@ -420,7 +427,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, { /* Create LanManager hashed password. */ -#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) +#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) DES_key_schedule ks; setup_des_key(pw, DESKEY(ks)); diff --git a/libs/libcurl/src/curl_ntlm_wb.c b/libs/libcurl/src/curl_ntlm_wb.c index ca9e2874a7..5a3bc3c893 100644 --- a/libs/libcurl/src/curl_ntlm_wb.c +++ b/libs/libcurl/src/curl_ntlm_wb.c @@ -426,7 +426,8 @@ CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn, /* Use Samba's 'winbind' daemon to support NTLM authentication, * by delegating the NTLM challenge/response protocol to a helper * in ntlm_auth. - * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html + * https://web.archive.org/web/20190925164737 + * /devel.squid-cache.org/ntlm/squid_helper_protocol.html * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this diff --git a/libs/libcurl/src/curl_sasl.c b/libs/libcurl/src/curl_sasl.c index f5ac99a68d..8d39e4f81b 100644 --- a/libs/libcurl/src/curl_sasl.c +++ b/libs/libcurl/src/curl_sasl.c @@ -56,8 +56,8 @@ /* Supported mechanisms */ static const struct { - const char *name; /* Name */ - size_t len; /* Name length */ + const char *name; /* Name */ + size_t len; /* Name length */ unsigned short bit; /* Flag bit */ } mechtable[] = { { "LOGIN", 5, SASL_MECH_LOGIN }, @@ -85,8 +85,11 @@ static const struct { * conn [in] - The connection data. * authused [in] - The authentication mechanism used. */ -void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) +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) { @@ -107,12 +110,6 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) Curl_auth_cleanup_ntlm(&conn->ntlm); } #endif - -#if !defined(USE_KERBEROS5) && !defined(USE_NTLM) - /* Reserved for future use */ - (void)conn; - (void)authused; -#endif } /* @@ -189,16 +186,35 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, * * Initializes the SASL structure. */ -void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params) +void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data, + const struct SASLproto *params) { + unsigned long auth = data->set.httpauth; + sasl->params = params; /* Set protocol dependent parameters */ sasl->state = SASL_STOP; /* Not yet running */ + sasl->curmech = NULL; /* No mechanism yet. */ sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */ - sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */ - sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */ + sasl->prefmech = params->defmechs; /* Default preferred mechanisms */ + sasl->authused = SASL_AUTH_NONE; /* The authentication mechanism used */ sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */ sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */ sasl->force_ir = FALSE; /* Respect external option */ + + if(auth != CURLAUTH_BASIC) { + sasl->resetprefs = FALSE; + sasl->prefmech = SASL_AUTH_NONE; + if(auth & CURLAUTH_BASIC) + sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN; + if(auth & CURLAUTH_DIGEST) + sasl->prefmech |= SASL_MECH_DIGEST_MD5; + if(auth & CURLAUTH_NTLM) + sasl->prefmech |= SASL_MECH_NTLM; + if(auth & CURLAUTH_BEARER) + sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2; + if(auth & CURLAUTH_GSSAPI) + sasl->prefmech |= SASL_MECH_GSSAPI; + } } /* @@ -247,40 +263,45 @@ static void state(struct SASL *sasl, struct Curl_easy *data, static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data, struct bufref *out) { - unsigned char *msg; - size_t msglen; - char *serverdata = NULL; CURLcode result = CURLE_OK; - sasl->params->getmessage(data->state.buffer, &serverdata); - if(!serverdata) - result = CURLE_BAD_CONTENT_ENCODING; - else if(!*serverdata || *serverdata == '=') - Curl_bufref_set(out, NULL, 0, NULL); - else { - result = Curl_base64_decode(serverdata, &msg, &msglen); - if(!result) - Curl_bufref_set(out, msg, msglen, curl_free); + result = sasl->params->getmessage(data, out); + if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) { + unsigned char *msg; + size_t msglen; + const char *serverdata = (const char *) Curl_bufref_ptr(out); + + if(!*serverdata || *serverdata == '=') + Curl_bufref_set(out, NULL, 0, NULL); + else { + result = Curl_base64_decode(serverdata, &msg, &msglen); + if(!result) + Curl_bufref_set(out, msg, msglen, curl_free); + } } return result; } /* Encode the outgoing SASL message. */ -static CURLcode build_message(struct Curl_easy *data, struct bufref *msg) +static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data, + struct bufref *msg) { CURLcode result = CURLE_OK; - char *base64; - size_t base64len; - if(!Curl_bufref_ptr(msg)) /* Empty mesage. */ - Curl_bufref_set(msg, "", 0, NULL); - else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ - Curl_bufref_set(msg, "=", 1, NULL); - else { - result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg), - Curl_bufref_len(msg), &base64, &base64len); - if(!result) - Curl_bufref_set(msg, base64, base64len, curl_free); + if(sasl->params->flags & SASL_FLAG_BASE64) { + if(!Curl_bufref_ptr(msg)) /* Empty message. */ + Curl_bufref_set(msg, "", 0, NULL); + else if(!Curl_bufref_len(msg)) /* Explicit empty response. */ + Curl_bufref_set(msg, "=", 1, NULL); + else { + char *base64; + size_t base64len; + + result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg), + Curl_bufref_len(msg), &base64, &base64len); + if(!result) + Curl_bufref_set(msg, base64, base64len, curl_free); + } } return result; @@ -310,11 +331,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn) * Calculate the required login details for SASL authentication. */ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, bool force_ir, saslprogress *progress) { CURLcode result = CURLE_OK; - unsigned int enabledmechs; + struct connectdata *conn = data->conn; + unsigned short enabledmechs; const char *mech = NULL; struct bufref resp; saslstate state1 = SASL_STOP; @@ -471,16 +492,16 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, } if(!result && mech) { + sasl->curmech = mech; if(Curl_bufref_ptr(&resp)) - result = build_message(data, &resp); + result = build_message(sasl, data, &resp); if(sasl->params->maxirlen && strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen) Curl_bufref_free(&resp); if(!result) - result = sasl->params->sendauth(data, conn, mech, - (const char *) Curl_bufref_ptr(&resp)); + result = sasl->params->sendauth(data, mech, &resp); if(!result) { *progress = SASL_INPROGRESS; @@ -498,10 +519,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, * Continue the authentication. */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, int code, saslprogress *progress) { CURLcode result = CURLE_OK; + struct connectdata *conn = data->conn; saslstate newstate = SASL_FINAL; struct bufref resp; const char * const hostname = SSL_HOST_NAME(); @@ -574,7 +595,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, result = Curl_auth_create_digest_md5_message(data, &serverdata, conn->user, conn->passwd, service, &resp); - newstate = SASL_DIGESTMD5_RESP; + if(!result && (sasl->params->flags & SASL_FLAG_BASE64)) + newstate = SASL_DIGESTMD5_RESP; break; case SASL_DIGESTMD5_RESP: /* Keep response NULL to output an empty line. */ @@ -630,7 +652,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, } else /* Decode the security challenge and create the response message */ - result = Curl_auth_create_gssapi_security_message(data, &serverdata, + result = Curl_auth_create_gssapi_security_message(data, + conn->sasl_authzid, + &serverdata, &conn->krb5, &resp); } @@ -639,7 +663,9 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *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, &serverdata, + result = Curl_auth_create_gssapi_security_message(data, + conn->sasl_authzid, + &serverdata, &conn->krb5, &resp); break; @@ -687,7 +713,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, sasl->authmechs ^= sasl->authused; /* Start an alternative SASL authentication */ - return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress); + return Curl_sasl_start(sasl, data, sasl->force_ir, progress); default: failf(data, "Unsupported SASL authentication mechanism"); result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */ @@ -699,14 +725,13 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, switch(result) { case CURLE_BAD_CONTENT_ENCODING: /* Cancel dialog */ - result = sasl->params->sendcont(data, conn, "*"); + result = sasl->params->cancelauth(data, sasl->curmech); newstate = SASL_CANCEL; break; case CURLE_OK: - result = build_message(data, &resp); + result = build_message(sasl, data, &resp); if(!result) - result = sasl->params->sendcont(data, conn, - (const char *) Curl_bufref_ptr(&resp)); + result = sasl->params->contauth(data, sasl->curmech, &resp); break; default: newstate = SASL_STOP; /* Stop on error */ diff --git a/libs/libcurl/src/curl_sasl.h b/libs/libcurl/src/curl_sasl.h index e17d323eba..91458c74a0 100644 --- a/libs/libcurl/src/curl_sasl.h +++ b/libs/libcurl/src/curl_sasl.h @@ -24,6 +24,8 @@ #include <curl/curl.h> +#include "bufref.h" + struct Curl_easy; struct connectdata; @@ -46,17 +48,20 @@ struct connectdata; #define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL) /* Authentication mechanism strings */ -#define SASL_MECH_STRING_LOGIN "LOGIN" -#define SASL_MECH_STRING_PLAIN "PLAIN" -#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" -#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" -#define SASL_MECH_STRING_GSSAPI "GSSAPI" -#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" -#define SASL_MECH_STRING_NTLM "NTLM" -#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" -#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" -#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1" -#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256" +#define SASL_MECH_STRING_LOGIN "LOGIN" +#define SASL_MECH_STRING_PLAIN "PLAIN" +#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5" +#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5" +#define SASL_MECH_STRING_GSSAPI "GSSAPI" +#define SASL_MECH_STRING_EXTERNAL "EXTERNAL" +#define SASL_MECH_STRING_NTLM "NTLM" +#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" +#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" +#define SASL_MECH_STRING_SCRAM_SHA_1 "SCRAM-SHA-1" +#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256" + +/* SASL flags */ +#define SASL_FLAG_BASE64 0x0001 /* Messages are base64-encoded */ /* SASL machine states */ typedef enum { @@ -90,30 +95,37 @@ typedef enum { /* Protocol dependent SASL parameters */ struct SASLproto { const char *service; /* The service name */ - int contcode; /* Code to receive when continuation is expected */ - int finalcode; /* Code to receive upon authentication success */ - size_t maxirlen; /* Maximum initial response length */ - CURLcode (*sendauth)(struct Curl_easy *data, - struct connectdata *conn, - const char *mech, const char *ir); + CURLcode (*sendauth)(struct Curl_easy *data, const char *mech, + const struct bufref *ir); /* Send authentication command */ - CURLcode (*sendcont)(struct Curl_easy *data, - struct connectdata *conn, const char *contauth); + CURLcode (*contauth)(struct Curl_easy *data, const char *mech, + const struct bufref *contauth); /* Send authentication continuation */ - void (*getmessage)(char *buffer, char **outptr); + CURLcode (*cancelauth)(struct Curl_easy *data, const char *mech); + /* Cancel authentication. */ + CURLcode (*getmessage)(struct Curl_easy *data, struct bufref *out); /* Get SASL response message */ + size_t maxirlen; /* Maximum initial response + mechanism length, + or zero if no max. This is normally the max + command length - other characters count. + This has to be zero for non-base64 protocols. */ + int contcode; /* Code to receive when continuation is expected */ + int finalcode; /* Code to receive upon authentication success */ + unsigned short defmechs; /* Mechanisms enabled by default */ + unsigned short flags; /* Configuration flags. */ }; /* Per-connection parameters */ struct SASL { const struct SASLproto *params; /* Protocol dependent parameters */ - saslstate state; /* Current machine state */ + saslstate state; /* Current machine state */ + const char *curmech; /* Current mechanism id. */ unsigned short authmechs; /* Accepted authentication mechanisms */ unsigned short prefmech; /* Preferred authentication mechanism */ unsigned short authused; /* Auth mechanism used for the connection */ - bool resetprefs; /* For URL auth option parsing. */ - bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ - bool force_ir; /* Protocol always supports initial response */ + bool resetprefs; /* For URL auth option parsing. */ + bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */ + bool force_ir; /* Protocol always supports initial response */ }; /* This is used to test whether the line starts with the given mechanism */ @@ -123,7 +135,7 @@ struct SASL { /* This is used to cleanup any libraries or curl modules used by the sasl functions */ -void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); +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, @@ -134,19 +146,18 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, const char *value, size_t len); /* Initializes an SASL structure */ -void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params); +void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data, + const struct SASLproto *params); /* Check if we have enough auth data and capabilities to authenticate */ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn); /* Calculate the required login details for SASL authentication */ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, bool force_ir, saslprogress *progress); /* Continue an SASL authentication */ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, - struct connectdata *conn, int code, saslprogress *progress); #endif /* HEADER_CURL_SASL_H */ diff --git a/libs/libcurl/src/curl_setup.h b/libs/libcurl/src/curl_setup.h index c0861d79b7..61384cdff6 100644 --- a/libs/libcurl/src/curl_setup.h +++ b/libs/libcurl/src/curl_setup.h @@ -166,41 +166,47 @@ */ #ifdef HTTP_ONLY -# ifndef CURL_DISABLE_TFTP -# define CURL_DISABLE_TFTP +# ifndef CURL_DISABLE_DICT +# define CURL_DISABLE_DICT +# endif +# ifndef CURL_DISABLE_FILE +# define CURL_DISABLE_FILE # endif # ifndef CURL_DISABLE_FTP # define CURL_DISABLE_FTP # endif +# ifndef CURL_DISABLE_GOPHER +# define CURL_DISABLE_GOPHER +# endif +# ifndef CURL_DISABLE_IMAP +# define CURL_DISABLE_IMAP +# endif # ifndef CURL_DISABLE_LDAP # define CURL_DISABLE_LDAP # endif -# ifndef CURL_DISABLE_TELNET -# define CURL_DISABLE_TELNET +# ifndef CURL_DISABLE_LDAPS +# define CURL_DISABLE_LDAPS # endif -# ifndef CURL_DISABLE_DICT -# define CURL_DISABLE_DICT +# ifndef CURL_DISABLE_MQTT +# define CURL_DISABLE_MQTT # endif -# ifndef CURL_DISABLE_FILE -# define CURL_DISABLE_FILE +# ifndef CURL_DISABLE_POP3 +# define CURL_DISABLE_POP3 # endif # ifndef CURL_DISABLE_RTSP # define CURL_DISABLE_RTSP # endif -# ifndef CURL_DISABLE_POP3 -# define CURL_DISABLE_POP3 -# endif -# ifndef CURL_DISABLE_IMAP -# define CURL_DISABLE_IMAP +# ifndef CURL_DISABLE_SMB +# define CURL_DISABLE_SMB # endif # ifndef CURL_DISABLE_SMTP # define CURL_DISABLE_SMTP # endif -# ifndef CURL_DISABLE_GOPHER -# define CURL_DISABLE_GOPHER +# ifndef CURL_DISABLE_TELNET +# define CURL_DISABLE_TELNET # endif -# ifndef CURL_DISABLE_SMB -# define CURL_DISABLE_SMB +# ifndef CURL_DISABLE_TFTP +# define CURL_DISABLE_TFTP # endif #endif @@ -711,7 +717,6 @@ int netware_init(void); #if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H) # if defined(SOCKET) || \ defined(USE_WINSOCK) || \ - defined(HAVE_WINSOCK_H) || \ defined(HAVE_WINSOCK2_H) || \ defined(HAVE_WS2TCPIP_H) # error "WinSock and lwIP TCP/IP stack definitions shall not coexist!" @@ -833,6 +838,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, ADDRESS_FAMILY sun_family; char sun_path[UNIX_PATH_MAX]; } SOCKADDR_UN, *PSOCKADDR_UN; +# define WIN32_SOCKADDR_UN # endif #endif diff --git a/libs/libcurl/src/curl_setup_once.h b/libs/libcurl/src/curl_setup_once.h index 22d0a063ef..38018d23c7 100644 --- a/libs/libcurl/src/curl_setup_once.h +++ b/libs/libcurl/src/curl_setup_once.h @@ -323,26 +323,6 @@ struct timeval { #include "curl_ctype.h" -/* - * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. - */ - -#ifndef HAVE_SIG_ATOMIC_T -typedef int sig_atomic_t; -#define HAVE_SIG_ATOMIC_T -#endif - - -/* - * Convenience SIG_ATOMIC_T definition - */ - -#ifdef HAVE_SIG_ATOMIC_T_VOLATILE -#define SIG_ATOMIC_T static sig_atomic_t -#else -#define SIG_ATOMIC_T static volatile sig_atomic_t -#endif - /* * Macro used to include code only in debug builds. diff --git a/libs/libcurl/src/curl_sha256.h b/libs/libcurl/src/curl_sha256.h index b4579d7692..b14c475ef8 100644 --- a/libs/libcurl/src/curl_sha256.h +++ b/libs/libcurl/src/curl_sha256.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2017, Florin Petriuc, <petriuc.florin@gmail.com> - * Copyright (C) 2018 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,7 +28,14 @@ extern const struct HMAC_params Curl_HMAC_SHA256[1]; +#ifdef USE_WOLFSSL +/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from + * sha.h*/ +#include <wolfssl/options.h> +#include <openssl/sha.h> +#else #define SHA256_DIGEST_LENGTH 32 +#endif void Curl_sha256it(unsigned char *outbuffer, const unsigned char *input, const size_t len); diff --git a/libs/libcurl/src/doh.c b/libs/libcurl/src/doh.c index de0c902b86..d6a2167701 100644 --- a/libs/libcurl/src/doh.c +++ b/libs/libcurl/src/doh.c @@ -235,25 +235,6 @@ static CURLcode dohprobe(struct Curl_easy *data, p->dnstype = dnstype; Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE); - /* Note: this is code for sending the DoH request with GET but there's still - no logic that actually enables this. We should either add that ability or - yank out the GET code. Discuss! */ - if(data->set.doh_get) { - char *b64; - size_t b64len; - result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen, - &b64, &b64len); - if(result) - goto error; - nurl = aprintf("%s?dns=%s", url, b64); - free(b64); - if(!nurl) { - result = CURLE_OUT_OF_MEMORY; - goto error; - } - url = nurl; - } - timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms <= 0) { result = CURLE_OPERATION_TIMEDOUT; @@ -268,10 +249,8 @@ static CURLcode dohprobe(struct Curl_easy *data, ERROR_CHECK_SETOPT(CURLOPT_URL, url); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp); - if(!data->set.doh_get) { - ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer); - ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen); - } + ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer); + ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen); ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers); #ifdef USE_NGHTTP2 ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c index 588b1fb47e..2aca93845b 100644 --- a/libs/libcurl/src/easy.c +++ b/libs/libcurl/src/easy.c @@ -117,7 +117,7 @@ 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_callback)_wcsdup; +curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup; #endif #if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__) diff --git a/libs/libcurl/src/easyoptions.c b/libs/libcurl/src/easyoptions.c index 4e65e3525b..b6131d4321 100644 --- a/libs/libcurl/src/easyoptions.c +++ b/libs/libcurl/src/easyoptions.c @@ -165,6 +165,7 @@ struct curl_easyoption Curl_easyopts[] = { {"MAXCONNECTS", CURLOPT_MAXCONNECTS, CURLOT_LONG, 0}, {"MAXFILESIZE", CURLOPT_MAXFILESIZE, CURLOT_LONG, 0}, {"MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE, CURLOT_OFF_T, 0}, + {"MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN, CURLOT_LONG, 0}, {"MAXREDIRS", CURLOPT_MAXREDIRS, CURLOT_LONG, 0}, {"MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE, CURLOT_OFF_T, 0}, {"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0}, @@ -192,6 +193,8 @@ struct curl_easyoption Curl_easyopts[] = { {"POSTQUOTE", CURLOPT_POSTQUOTE, CURLOT_SLIST, 0}, {"POSTREDIR", CURLOPT_POSTREDIR, CURLOT_VALUES, 0}, {"PREQUOTE", CURLOPT_PREQUOTE, CURLOT_SLIST, 0}, + {"PREREQDATA", CURLOPT_PREREQDATA, CURLOT_CBPTR, 0}, + {"PREREQFUNCTION", CURLOPT_PREREQFUNCTION, CURLOT_FUNCTION, 0}, {"PRE_PROXY", CURLOPT_PRE_PROXY, CURLOT_STRING, 0}, {"PRIVATE", CURLOPT_PRIVATE, CURLOT_OBJECT, 0}, {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, @@ -271,6 +274,8 @@ struct curl_easyoption Curl_easyopts[] = { {"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0}, {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOT_STRING, 0}, + {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, + CURLOT_STRING, 0}, {"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0}, {"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0}, {"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0}, @@ -354,6 +359,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (310 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (314 + 1)); } #endif diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c index 1a699de594..a8d209e3fb 100644 --- a/libs/libcurl/src/ftp.c +++ b/libs/libcurl/src/ftp.c @@ -876,11 +876,6 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data, ftpc->count2 = 0; /* count2 counts failed CWDs */ - /* count3 is set to allow a MKD to fail once. In the case when first CWD - fails and then MKD fails (due to another session raced it to create the - dir) this then allows for a second try to CWD to it */ - ftpc->count3 = (data->set.ftp_create_missing_dirs == 2)?1:0; - if(conn->bits.reuse && ftpc->entrypath && /* no need to go to entrypath when we have an absolute path */ !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { @@ -2681,9 +2676,12 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, /* we have now received a full FTP server response */ switch(ftpc->state) { case FTP_WAIT220: - if(ftpcode == 230) - /* 230 User logged in - already! */ - return ftp_state_user_resp(data, ftpcode, ftpc->state); + if(ftpcode == 230) { + /* 230 User logged in - already! Take as 220 if TLS required. */ + if(data->set.use_ssl <= CURLUSESSL_TRY || + conn->bits.ftp_use_control_ssl) + return ftp_state_user_resp(data, ftpcode, ftpc->state); + } else if(ftpcode != 220) { failf(data, "Got a %03d ftp-server response when 220 was expected", ftpcode); @@ -2740,6 +2738,9 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, case FTP_AUTH: /* we have gotten the response to a previous AUTH command */ + if(pp->cache_size) + return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ + /* RFC2228 (page 5) says: * * If the server is willing to accept the named security mechanism, @@ -2996,6 +2997,12 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, ftpc->cwdcount && !ftpc->count2) { /* try making it */ ftpc->count2++; /* counter to prevent CWD-MKD loops */ + + /* count3 is set to allow MKD to fail once per dir. In the case when + CWD fails and then MKD fails (due to another session raced it to + create the dir) this then allows for a second try to CWD to it. */ + ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0; + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", ftpc->dirs[ftpc->cwdcount - 1]); if(!result) diff --git a/libs/libcurl/src/hostasyn.c b/libs/libcurl/src/hostasyn.c index b25de1d417..f7d99ce9a6 100644 --- a/libs/libcurl/src/hostasyn.c +++ b/libs/libcurl/src/hostasyn.c @@ -50,7 +50,6 @@ #include "hostip.h" #include "hash.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "curl_memory.h" /* The last #include file should be: */ diff --git a/libs/libcurl/src/hostip.c b/libs/libcurl/src/hostip.c index 30ce509267..c33c9af9d0 100644 --- a/libs/libcurl/src/hostip.c +++ b/libs/libcurl/src/hostip.c @@ -56,7 +56,6 @@ #include "hash.h" #include "rand.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "inet_ntop.h" #include "inet_pton.h" @@ -508,9 +507,6 @@ static struct Curl_addrinfo *get_localhost(int port) struct sockaddr_in sa; unsigned int ipv4; unsigned short port16 = (unsigned short)(port & 0xffff); - ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1); - if(!ca) - return NULL; /* memset to clear the sa.sin_zero field */ memset(&sa, 0, sizeof(sa)); @@ -520,6 +516,9 @@ static struct Curl_addrinfo *get_localhost(int port) return NULL; memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4)); + ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1); + if(!ca) + return NULL; ca->ai_flags = 0; ca->ai_family = AF_INET; ca->ai_socktype = SOCK_STREAM; @@ -533,6 +532,36 @@ static struct Curl_addrinfo *get_localhost(int port) return ca; } +#ifdef ENABLE_IPV6 +/* + * Curl_ipv6works() returns TRUE if IPv6 seems to work. + */ +bool Curl_ipv6works(struct Curl_easy *data) +{ + if(data) { + /* the nature of most system is that IPv6 status doesn't come and go + during a program's lifetime so we only probe the first time and then we + have the info kept for fast re-use */ + DEBUGASSERT(data); + DEBUGASSERT(data->multi); + return data->multi->ipv6_works; + } + else { + int ipv6_works = -1; + /* probe to see if we have a working IPv6 stack */ + curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); + if(s == CURL_SOCKET_BAD) + /* an IPv6 address was requested but we can't get/use one */ + ipv6_works = 0; + else { + ipv6_works = 1; + sclose(s); + } + return (ipv6_works>0)?TRUE:FALSE; + } +} +#endif /* ENABLE_IPV6 */ + /* * Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4 * (or IPv6 if supported) address. @@ -674,9 +703,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, #endif /* !USE_RESOLVE_ON_IPS */ if(!addr) { - /* Check what IP specifics the app has requested and if we can provide - * it. If not, bail out. */ - if(!Curl_ipvalid(data, conn)) + if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data)) return CURLRESOLV_ERROR; if(strcasecompare(hostname, "localhost")) @@ -684,6 +711,10 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, else if(allowDOH && data->set.doh && !ipnum) addr = Curl_doh(data, hostname, port, &respwait); else { + /* Check what IP specifics the app has requested and if we can provide + * it. If not, bail out. */ + if(!Curl_ipvalid(data, conn)) + return CURLRESOLV_ERROR; /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a non-zero value indicating that we need to wait for the response to the resolve call */ diff --git a/libs/libcurl/src/hostip.h b/libs/libcurl/src/hostip.h index 28f3b84018..67a688aebd 100644 --- a/libs/libcurl/src/hostip.h +++ b/libs/libcurl/src/hostip.h @@ -97,7 +97,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data, struct Curl_dns_entry **dnsentry, timediff_t timeoutms); -#ifdef CURLRES_IPV6 +#ifdef ENABLE_IPV6 /* * Curl_ipv6works() returns TRUE if IPv6 seems to work. */ diff --git a/libs/libcurl/src/hostip4.c b/libs/libcurl/src/hostip4.c index ac92126d8c..1fd791015c 100644 --- a/libs/libcurl/src/hostip4.c +++ b/libs/libcurl/src/hostip4.c @@ -50,7 +50,6 @@ #include "hostip.h" #include "hash.h" #include "share.h" -#include "strerror.h" #include "url.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" diff --git a/libs/libcurl/src/hostip6.c b/libs/libcurl/src/hostip6.c index 943cdd261c..c2d5f08e32 100644 --- a/libs/libcurl/src/hostip6.c +++ b/libs/libcurl/src/hostip6.c @@ -50,7 +50,6 @@ #include "hostip.h" #include "hash.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "inet_pton.h" #include "connect.h" @@ -60,34 +59,6 @@ #include "memdebug.h" /* - * Curl_ipv6works() returns TRUE if IPv6 seems to work. - */ -bool Curl_ipv6works(struct Curl_easy *data) -{ - if(data) { - /* the nature of most system is that IPv6 status doesn't come and go - during a program's lifetime so we only probe the first time and then we - have the info kept for fast re-use */ - DEBUGASSERT(data); - DEBUGASSERT(data->multi); - return data->multi->ipv6_works; - } - else { - int ipv6_works = -1; - /* probe to see if we have a working IPv6 stack */ - curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0); - if(s == CURL_SOCKET_BAD) - /* an IPv6 address was requested but we can't get/use one */ - ipv6_works = 0; - else { - ipv6_works = 1; - sclose(s); - } - return (ipv6_works>0)?TRUE:FALSE; - } -} - -/* * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've * been set and returns TRUE if they are OK. */ diff --git a/libs/libcurl/src/hostsyn.c b/libs/libcurl/src/hostsyn.c index 550b43a085..c00c2744c4 100644 --- a/libs/libcurl/src/hostsyn.c +++ b/libs/libcurl/src/hostsyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -50,7 +50,6 @@ #include "hostip.h" #include "hash.h" #include "share.h" -#include "strerror.h" #include "url.h" #include "curl_memory.h" /* The last #include file should be: */ diff --git a/libs/libcurl/src/hsts.c b/libs/libcurl/src/hsts.c index 0d5a584012..052dc11571 100644 --- a/libs/libcurl/src/hsts.c +++ b/libs/libcurl/src/hsts.c @@ -49,6 +49,7 @@ #define MAX_HSTS_HOSTLENSTR "256" #define MAX_HSTS_DATELEN 64 #define MAX_HSTS_DATELENSTR "64" +#define UNLIMITED "unlimited" #ifdef DEBUGBUILD /* to play well with debug builds, we can *set* a fixed time this will @@ -283,13 +284,17 @@ static CURLcode hsts_push(struct Curl_easy *data, e.namelen = strlen(sts->host); e.includeSubDomains = sts->includeSubDomains; - result = Curl_gmtime((time_t)sts->expires, &stamp); - if(result) - return result; + if(sts->expires != TIME_T_MAX) { + result = Curl_gmtime((time_t)sts->expires, &stamp); + if(result) + return result; - msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d", - stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, - stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d", + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + } + else + strcpy(e.expire, UNLIMITED); sc = data->set.hsts_write(data, &e, i, data->set.hsts_write_userp); @@ -303,14 +308,18 @@ static CURLcode hsts_push(struct Curl_easy *data, static CURLcode hsts_out(struct stsentry *sts, FILE *fp) { struct tm stamp; - CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp); - if(result) - return result; - - fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", - sts->includeSubDomains ? ".": "", sts->host, - stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, - stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + if(sts->expires != TIME_T_MAX) { + CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp); + if(result) + return result; + fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", + sts->includeSubDomains ? ".": "", sts->host, + stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, + stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + } + else + fprintf(fp, "%s%s \"%s\"\n", + sts->includeSubDomains ? ".": "", sts->host, UNLIMITED); return CURLE_OK; } @@ -403,7 +412,8 @@ static CURLcode hsts_add(struct hsts *h, char *line) "%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"", host, date); if(2 == rc) { - time_t expires = Curl_getdate_capped(date); + time_t expires = strcmp(date, UNLIMITED) ? Curl_getdate_capped(date) : + TIME_T_MAX; CURLcode result; char *p = host; bool subdomain = FALSE; @@ -456,7 +466,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h) return result; } else if(sc == CURLSTS_FAIL) - return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_ABORTED_BY_CALLBACK; } while(sc == CURLSTS_OK); } return CURLE_OK; @@ -526,7 +536,9 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data, */ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h) { - return hsts_pull(data, h); + if(h) + return hsts_pull(data, h); + return CURLE_OK; } #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ diff --git a/libs/libcurl/src/hsts.h b/libs/libcurl/src/hsts.h index baa582864a..653c05348d 100644 --- a/libs/libcurl/src/hsts.h +++ b/libs/libcurl/src/hsts.h @@ -59,7 +59,7 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h); #else #define Curl_hsts_cleanup(x) -#define Curl_hsts_loadcb(x,y) +#define Curl_hsts_loadcb(x,y) CURLE_OK #define Curl_hsts_save(x,y,z) #endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */ #endif /* HEADER_CURL_HSTS_H */ diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c index 05b971b204..78ad10edea 100644 --- a/libs/libcurl/src/http.c +++ b/libs/libcurl/src/http.c @@ -323,7 +323,7 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy) pwd = data->state.aptr.passwd; } - out = aprintf("%s:%s", user, pwd ? pwd : ""); + out = aprintf("%s:%s", user ? user : "", pwd ? pwd : ""); if(!out) return CURLE_OUT_OF_MEMORY; @@ -1669,8 +1669,8 @@ CURLcode Curl_http_done(struct Curl_easy *data, * - if any server previously contacted to handle this request only supports * 1.0. */ -static bool use_http_1_1plus(const struct Curl_easy *data, - const struct connectdata *conn) +bool Curl_use_http_1_1plus(const struct Curl_easy *data, + const struct connectdata *conn) { if((data->state.httpversion == 10) || (conn->httpversion == 10)) return FALSE; @@ -1696,7 +1696,7 @@ static const char *get_http_string(const struct Curl_easy *data, return "2"; #endif - if(use_http_1_1plus(data, conn)) + if(Curl_use_http_1_1plus(data, conn)) return "1.1"; return "1.0"; @@ -1711,7 +1711,7 @@ static CURLcode expect100(struct Curl_easy *data, CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ - if(!data->state.disableexpect && use_http_1_1plus(data, conn) && + if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) && (conn->httpversion < 20)) { /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an Expect: 100-continue to the headers which actually speeds up post @@ -2348,7 +2348,7 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn, if(conn->bits.authneg) /* don't enable chunked during auth neg */ ; - else if(use_http_1_1plus(data, conn)) { + else if(Curl_use_http_1_1plus(data, conn)) { if(conn->httpversion < 20) /* HTTP, upload, unknown file size and not HTTP 1.0 */ data->req.upload_chunky = TRUE; @@ -2711,14 +2711,16 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, int count = 0; if(data->cookies && data->state.cookie_engine) { + const char *host = data->state.aptr.cookiehost ? + data->state.aptr.cookiehost : conn->host.name; + const bool secure_context = + conn->handler->protocol&CURLPROTO_HTTPS || + strcasecompare("localhost", host) || + !strcmp(host, "127.0.0.1") || + !strcmp(host, "[::1]") ? TRUE : FALSE; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - co = Curl_cookie_getlist(data->cookies, - data->state.aptr.cookiehost? - data->state.aptr.cookiehost: - conn->host.name, - data->state.up.path, - (conn->handler->protocol&CURLPROTO_HTTPS)? - TRUE:FALSE); + co = Curl_cookie_getlist(data->cookies, host, data->state.up.path, + secure_context); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { @@ -2900,7 +2902,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data, bool *done) { struct SingleRequest *k = &data->req; - DEBUGASSERT(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)); + if(data->req.newurl) { if(conn->bits.close) { /* Abort after the headers if "follow Location" is set @@ -3401,17 +3403,8 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, NULL, 10, &contentlength); if(offt == CURL_OFFT_OK) { - if(data->set.max_filesize && - contentlength > data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } k->size = contentlength; k->maxdownload = k->size; - /* we set the progress download size already at this point - just to make it easier for apps/callbacks to extract this - info as soon as possible */ - Curl_pgrsSetDownloadSize(data, k->size); } else if(offt == CURL_OFFT_FLOW) { /* out of range */ @@ -3502,6 +3495,12 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, TRUE); if(result) return result; + if(!k->chunk) { + /* if this isn't 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; + } } else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) && data->set.str[STRING_ENCODING]) { @@ -3564,18 +3563,21 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, #if !defined(CURL_DISABLE_COOKIES) else if(data->cookies && data->state.cookie_engine && checkprefix("Set-Cookie:", headp)) { + /* If there is a custom-set Host: name, use it here, or else use real peer + host name. */ + const char *host = data->state.aptr.cookiehost? + data->state.aptr.cookiehost:conn->host.name; + const bool secure_context = + conn->handler->protocol&CURLPROTO_HTTPS || + strcasecompare("localhost", host) || + !strcmp(host, "127.0.0.1") || + !strcmp(host, "[::1]") ? TRUE : FALSE; + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_add(data, - data->cookies, TRUE, FALSE, - headp + strlen("Set-Cookie:"), - /* If there is a custom-set Host: name, use it - here, or else use real peer host name. */ - data->state.aptr.cookiehost? - data->state.aptr.cookiehost:conn->host.name, - data->state.up.path, - (conn->handler->protocol&CURLPROTO_HTTPS)? - TRUE:FALSE); + Curl_cookie_add(data, data->cookies, TRUE, FALSE, + headp + strlen("Set-Cookie:"), host, + data->state.up.path, secure_context); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } #endif @@ -3771,6 +3773,29 @@ CURLcode Curl_http_statusline(struct Curl_easy *data, return CURLE_OK; } +/* Content-Length must be ignored if any Transfer-Encoding is present in the + response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is + figured out here after all headers have been received but before the final + call to the user's header callback, so that a valid content length can be + retrieved by the user in the final call. */ +CURLcode Curl_http_size(struct Curl_easy *data) +{ + struct SingleRequest *k = &data->req; + if(data->req.ignore_cl || k->chunk) { + k->size = k->maxdownload = -1; + } + else if(k->size != -1) { + if(data->set.max_filesize && + k->size > data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + Curl_pgrsSetDownloadSize(data, k->size); + k->maxdownload = k->size; + } + return CURLE_OK; +} + /* * Read any HTTP header lines from the server and pass them to the client app. */ @@ -3965,6 +3990,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } + if(!k->header) { + result = Curl_http_size(data); + if(result) + return result; + } + /* At this point we have some idea about the fate of the connection. If we are closing the connection it may result auth failure. */ #if defined(USE_NTLM) @@ -4121,31 +4152,6 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, reason */ *stop_reading = TRUE; #endif - else { - /* If we know the expected size of this document, we set the - maximum download size to the size of the expected - document or else, we won't know when to stop reading! - - Note that we set the download maximum even if we read a - "Connection: close" header, to make sure that - "Content-Length: 0" still prevents us from attempting to - read the (missing) response-body. - */ - /* According to RFC2616 section 4.4, we MUST ignore - Content-Length: headers if we are now receiving data - using chunked Transfer-Encoding. - */ - if(k->chunk) - k->maxdownload = k->size = -1; - } - if(-1 != k->size) { - /* We do this operation even if no_body is true, since this - data might be retrieved later with curl_easy_getinfo() - and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */ - - Curl_pgrsSetDownloadSize(data, k->size); - k->maxdownload = k->size; - } /* If max download size is *zero* (nothing) we already have nothing and can safely return ok now! But for HTTP/2, we'd @@ -4210,18 +4216,20 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * https://tools.ietf.org/html/rfc7230#section-3.1.2 * * The response code is always a three-digit number in HTTP as the spec - * says. We try to allow any number here, but we cannot make + * says. We allow any three-digit number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ char separator; char twoorthree[2]; int httpversion = 0; + char digit4 = 0; nc = sscanf(HEADER1, - " HTTP/%1d.%1d%c%3d", + " HTTP/%1d.%1d%c%3d%c", &httpversion_major, &httpversion, &separator, - &k->httpcode); + &k->httpcode, + &digit4); if(nc == 1 && httpversion_major >= 2 && 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) { @@ -4230,7 +4238,19 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, separator = ' '; } - if((nc == 4) && (' ' == separator)) { + /* There can only be a 4th response code digit stored in 'digit4' if + all the other fields were parsed and stored first, so nc is 5 when + digit4 a digit. + + The sscanf() line above will also allow zero-prefixed and negative + numbers, so we check for that too here. + */ + else if(ISDIGIT(digit4) || (k->httpcode < 100)) { + failf(data, "Unsupported response code in HTTP response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + + if((nc >= 4) && (' ' == separator)) { httpversion += 10 * httpversion_major; switch(httpversion) { case 10: diff --git a/libs/libcurl/src/http.h b/libs/libcurl/src/http.h index bce171550d..cb5b56faf3 100644 --- a/libs/libcurl/src/http.h +++ b/libs/libcurl/src/http.h @@ -99,6 +99,8 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn, const char **teep); CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, struct dynbuf *r, Curl_HttpReq httpreq); +bool Curl_use_http_1_1plus(const struct Curl_easy *data, + const struct connectdata *conn); #ifndef CURL_DISABLE_COOKIES CURLcode Curl_http_cookies(struct Curl_easy *data, struct connectdata *conn, @@ -287,6 +289,8 @@ struct http_conn { #endif }; +CURLcode Curl_http_size(struct Curl_easy *data); + CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c index 60e0143c15..992fbbb26d 100644 --- a/libs/libcurl/src/http2.c +++ b/libs/libcurl/src/http2.c @@ -100,6 +100,7 @@ static int http2_getsock(struct Curl_easy *data, const struct http_conn *c = &conn->proto.httpc; struct SingleRequest *k = &data->req; int bitmap = GETSOCK_BLANK; + struct HTTP *stream = data->req.p.http; sock[0] = conn->sock[FIRSTSOCKET]; @@ -108,9 +109,13 @@ static int http2_getsock(struct Curl_easy *data, frame so we should always be ready for one */ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - /* we're still uploading or the HTTP/2 layer wants to send data */ - if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) || - nghttp2_session_want_write(c->h2)) + /* we're (still uploading OR the HTTP/2 layer wants to send data) AND + there's a window to send data in */ + if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) || + nghttp2_session_want_write(c->h2)) && + (nghttp2_session_get_remote_window_size(c->h2) && + nghttp2_session_get_stream_remote_window_size(c->h2, + stream->stream_id))) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); return bitmap; @@ -763,6 +768,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, ncopy); stream->nread_header_recvbuf += ncopy; + DEBUGASSERT(stream->mem); H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p", ncopy, stream_id, stream->mem)); @@ -1624,10 +1630,6 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex, return -1; } - if(stream->closed) - /* closed overrides paused */ - return http2_handle_stream_close(conn, data, stream, err); - /* Nullify here because we call nghttp2_session_send() and they might refer to the old buffer. */ stream->upload_mem = NULL; @@ -1956,8 +1958,19 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, nghttp2_session_resume_data(h2, stream->stream_id); } - H2BUGF(infof(data, "http2_send returns %zu for stream %u", len, - stream->stream_id)); +#ifdef DEBUG_HTTP2 + if(!len) { + infof(data, "http2_send: easy %p (stream %u) win %u/%u", + data, stream->stream_id, + nghttp2_session_get_remote_window_size(httpc->h2), + nghttp2_session_get_stream_remote_window_size(httpc->h2, + stream->stream_id) + ); + + } + infof(data, "http2_send returns %zu for stream %u", len, + stream->stream_id); +#endif return len; } @@ -2218,6 +2231,16 @@ CURLcode Curl_http2_setup(struct Curl_easy *data, Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS); Curl_dyn_init(&stream->trailer_recvbuf, DYN_H2_TRAILERS); + stream->upload_left = 0; + stream->upload_mem = NULL; + stream->upload_len = 0; + stream->mem = data->state.buffer; + stream->len = data->set.buffer_size; + + multi_connchanged(data->multi); + /* below this point only connection related inits are done, which only needs + to be done once per connection */ + if((conn->handler == &Curl_handler_http2_ssl) || (conn->handler == &Curl_handler_http2)) return CURLE_OK; /* already done */ @@ -2234,11 +2257,10 @@ CURLcode Curl_http2_setup(struct Curl_easy *data, } infof(data, "Using HTTP2, server supports multiplexing"); - stream->upload_left = 0; - stream->upload_mem = NULL; - stream->upload_len = 0; - stream->mem = data->state.buffer; - stream->len = data->set.buffer_size; + + conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ + conn->httpversion = 20; + conn->bundle->multiuse = BUNDLE_MULTIPLEX; httpc->inbuflen = 0; httpc->nread_inbuf = 0; @@ -2246,12 +2268,7 @@ CURLcode Curl_http2_setup(struct Curl_easy *data, httpc->pause_stream_id = 0; httpc->drain_total = 0; - conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - conn->httpversion = 20; - conn->bundle->multiuse = BUNDLE_MULTIPLEX; - infof(data, "Connection state changed (HTTP/2 confirmed)"); - multi_connchanged(data->multi); return CURLE_OK; } @@ -2340,15 +2357,8 @@ CURLcode Curl_http2_switched(struct Curl_easy *data, DEBUGASSERT(httpc->nread_inbuf == 0); - /* Good enough to call it an end once the remaining payload is copied to the - * connection buffer. - * Some servers (e.g. nghttpx v1.43.0) may fulfill stream 1 immediately - * following the protocol switch other than waiting for the client-side - * connection preface. If h2_process_pending_input is invoked here to parse - * the remaining payload, stream 1 would be marked as closed too early and - * thus ignored in http2_recv (following 252790c53). - * The logic in lib/http.c and lib/transfer.c guarantees a following - * http2_recv would be invoked very soon. */ + if(-1 == h2_process_pending_input(data, httpc, &result)) + return CURLE_HTTP2; return CURLE_OK; } diff --git a/libs/libcurl/src/http_aws_sigv4.c b/libs/libcurl/src/http_aws_sigv4.c index 02663abd63..cbbecb7129 100644 --- a/libs/libcurl/src/http_aws_sigv4.c +++ b/libs/libcurl/src/http_aws_sigv4.c @@ -92,6 +92,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) char *signed_headers = NULL; Curl_HttpReq httpreq; const char *method; + size_t post_data_len; const char *post_data = data->set.postfields ? data->set.postfields : ""; unsigned char sha_hash[32]; char sha_hex[65]; @@ -281,8 +282,12 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) goto fail; } + if(data->set.postfieldsize < 0) + post_data_len = strlen(post_data); + else + post_data_len = (size_t)data->set.postfieldsize; Curl_sha256it(sha_hash, - (const unsigned char *) post_data, strlen(post_data)); + (const unsigned char *) post_data, post_data_len); sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); Curl_http_method(data, conn, &method, &httpreq); @@ -321,7 +326,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) /* * Google allow to use rsa key instead of HMAC, so this code might change - * In the furure, but for now we support only HMAC version + * In the future, but for now we support only HMAC version */ str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */ "%s\n" /* RequestDateTime */ diff --git a/libs/libcurl/src/http_ntlm.c b/libs/libcurl/src/http_ntlm.c index 627a11c5af..a6526db9f7 100644 --- a/libs/libcurl/src/http_ntlm.c +++ b/libs/libcurl/src/http_ntlm.c @@ -198,6 +198,12 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) #endif Curl_bufref_init(&ntlmmsg); + + /* connection is already authenticated, don't send a header in future + * requests so go directly to NTLMSTATE_LAST */ + if(*state == NTLMSTATE_TYPE3) + *state = NTLMSTATE_LAST; + switch(*state) { case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ @@ -246,11 +252,6 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy) } break; - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - *state = NTLMSTATE_LAST; - /* FALLTHROUGH */ case NTLMSTATE_LAST: Curl_safefree(*allocuserpwd); authp->done = TRUE; diff --git a/libs/libcurl/src/http_proxy.c b/libs/libcurl/src/http_proxy.c index a7f7aa353f..fc050a07d5 100644 --- a/libs/libcurl/src/http_proxy.c +++ b/libs/libcurl/src/http_proxy.c @@ -148,7 +148,7 @@ int Curl_connect_getsock(struct connectdata *conn) DEBUGASSERT(conn->connect_state); http = &conn->connect_state->http_proxy; - if(http->sending) + if(http->sending == HTTPSEND_REQUEST) return GETSOCK_WRITESOCK(0); return GETSOCK_READSOCK(0); @@ -207,9 +207,15 @@ static void connect_done(struct Curl_easy *data) Curl_dyn_free(&s->rcvbuf); Curl_dyn_free(&s->req); - /* retore the protocol pointer */ + /* restore the protocol pointer */ data->req.p.http = s->prot_save; s->prot_save = NULL; + data->info.httpcode = 0; /* clear it as it might've been used for the + proxy */ + data->req.ignorebody = FALSE; +#ifdef USE_HYPER + data->state.hconnect = FALSE; +#endif infof(data, "CONNECT phase completed!"); } } @@ -284,8 +290,7 @@ static CURLcode CONNECT(struct Curl_easy *data, /* This only happens if we've looped here due to authentication reasons, and we don't really use the newly cloned URL here then. Just free() it. */ - free(data->req.newurl); - data->req.newurl = NULL; + Curl_safefree(data->req.newurl); /* initialize send-buffer */ Curl_dyn_init(req, DYN_HTTP_REQUEST); @@ -300,32 +305,27 @@ static CURLcode CONNECT(struct Curl_easy *data, hostheader, TRUE); if(!result) { - const char *proxyconn = ""; - const char *useragent = ""; const char *httpv = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; - if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) - proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - - if(!Curl_checkProxyheaders(data, conn, "User-Agent") && - data->set.str[STRING_USERAGENT]) - useragent = data->state.aptr.uagent; - result = Curl_dyn_addf(req, "CONNECT %s HTTP/%s\r\n" "%s" /* Host: */ - "%s" /* Proxy-Authorization */ - "%s" /* User-Agent */ - "%s", /* Proxy-Connection */ + "%s", /* Proxy-Authorization */ hostheader, httpv, host?host:"", data->state.aptr.proxyuserpwd? - data->state.aptr.proxyuserpwd:"", - useragent, - proxyconn); + data->state.aptr.proxyuserpwd:""); + + if(!result && !Curl_checkProxyheaders(data, conn, "User-Agent") && + data->set.str[STRING_USERAGENT]) + result = Curl_dyn_addf(req, "User-Agent: %s\r\n", + data->set.str[STRING_USERAGENT]); + + if(!result && !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) + result = Curl_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n"); if(!result) result = Curl_add_custom_headers(data, TRUE, req); @@ -390,6 +390,7 @@ static CURLcode CONNECT(struct Curl_easy *data, k->upload_fromhere += bytes_written; return result; } + http->sending = HTTPSEND_NADA; /* if nothing left to send, continue */ } { /* READING RESPONSE PHASE */ @@ -739,6 +740,7 @@ static CURLcode CONNECT(struct Curl_easy *data, io = hyper_io_new(); if(!io) { failf(data, "Couldn't create hyper IO"); + result = CURLE_OUT_OF_MEMORY; goto error; } /* tell Hyper how to read/write network data */ @@ -754,6 +756,7 @@ static CURLcode CONNECT(struct Curl_easy *data, h->exec = hyper_executor_new(); if(!h->exec) { failf(data, "Couldn't create hyper executor"); + result = CURLE_OUT_OF_MEMORY; goto error; } } @@ -761,6 +764,7 @@ static CURLcode CONNECT(struct Curl_easy *data, options = hyper_clientconn_options_new(); if(!options) { failf(data, "Couldn't create hyper client options"); + result = CURLE_OUT_OF_MEMORY; goto error; } @@ -771,6 +775,7 @@ static CURLcode CONNECT(struct Curl_easy *data, handshake = hyper_clientconn_handshake(io, options); if(!handshake) { failf(data, "Couldn't create hyper client handshake"); + result = CURLE_OUT_OF_MEMORY; goto error; } io = NULL; @@ -778,6 +783,7 @@ static CURLcode CONNECT(struct Curl_easy *data, if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) { failf(data, "Couldn't hyper_executor_push the handshake"); + result = CURLE_OUT_OF_MEMORY; goto error; } handshake = NULL; /* ownership passed on */ @@ -785,6 +791,7 @@ static CURLcode CONNECT(struct Curl_easy *data, task = hyper_executor_poll(h->exec); if(!task) { failf(data, "Couldn't hyper_executor_poll the handshake"); + result = CURLE_OUT_OF_MEMORY; goto error; } @@ -793,14 +800,24 @@ static CURLcode CONNECT(struct Curl_easy *data, req = hyper_request_new(); if(!req) { failf(data, "Couldn't hyper_request_new"); + result = CURLE_OUT_OF_MEMORY; goto error; } if(hyper_request_set_method(req, (uint8_t *)"CONNECT", strlen("CONNECT"))) { failf(data, "error setting method"); + result = CURLE_OUT_OF_MEMORY; goto error; } + infof(data, "Establish HTTP proxy tunnel to %s:%d", + hostname, remote_port); + + /* This only happens if we've looped here due to authentication + reasons, and we don't really use the newly cloned URL here + then. Just free() it. */ + Curl_safefree(data->req.newurl); + result = CONNECT_host(data, conn, hostname, remote_port, &hostheader, &host); if(result) @@ -810,6 +827,16 @@ static CURLcode CONNECT(struct Curl_easy *data, strlen(hostheader))) { failf(data, "error setting path"); result = CURLE_OUT_OF_MEMORY; + goto error; + } + if(data->set.verbose) { + char *se = aprintf("CONNECT %s HTTP/1.1\r\n", hostheader); + if(!se) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se)); + free(se); } /* Setup the proxy-authorization header, if any */ result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET, @@ -823,40 +850,65 @@ static CURLcode CONNECT(struct Curl_easy *data, (HYPERE_OK != hyper_request_set_version(req, HYPER_HTTP_VERSION_1_0))) { failf(data, "error setting HTTP version"); + result = CURLE_OUT_OF_MEMORY; goto error; } headers = hyper_request_headers(req); if(!headers) { failf(data, "hyper_request_headers"); + result = CURLE_OUT_OF_MEMORY; goto error; } - if(host && Curl_hyper_header(data, headers, host)) - goto error; - Curl_safefree(host); + if(host) { + result = Curl_hyper_header(data, headers, host); + if(result) + goto error; + Curl_safefree(host); + } - if(data->state.aptr.proxyuserpwd && - Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd)) - goto error; + if(data->state.aptr.proxyuserpwd) { + result = Curl_hyper_header(data, headers, + data->state.aptr.proxyuserpwd); + if(result) + goto error; + } - if(data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && - data->state.aptr.uagent && - Curl_hyper_header(data, headers, data->state.aptr.uagent)) - goto error; + if(!Curl_checkProxyheaders(data, conn, "User-Agent") && + data->set.str[STRING_USERAGENT]) { + struct dynbuf ua; + Curl_dyn_init(&ua, DYN_HTTP_REQUEST); + result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n", + data->set.str[STRING_USERAGENT]); + if(result) + goto error; + result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)); + if(result) + goto error; + Curl_dyn_free(&ua); + } - if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") && - Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive")) + if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) { + result = Curl_hyper_header(data, headers, + "Proxy-Connection: Keep-Alive"); + if(result) + goto error; + } + + result = Curl_add_custom_headers(data, TRUE, headers); + if(result) goto error; sendtask = hyper_clientconn_send(client, req); if(!sendtask) { failf(data, "hyper_clientconn_send"); + result = CURLE_OUT_OF_MEMORY; goto error; } if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) { failf(data, "Couldn't hyper_executor_push the send"); + result = CURLE_OUT_OF_MEMORY; goto error; } @@ -869,8 +921,11 @@ static CURLcode CONNECT(struct Curl_easy *data, if(error) hypererr = hyper_task_value(task); hyper_task_free(task); - if(error) + if(error) { + /* this could probably use a better error code? */ + result = CURLE_OUT_OF_MEMORY; goto error; + } } } while(task); s->tunnel_state = TUNNEL_CONNECT; @@ -898,15 +953,23 @@ static CURLcode CONNECT(struct Curl_easy *data, h->write_waker = NULL; } } - /* FALLTHROUGH */ + break; + default: break; } + + /* If we are supposed to continue and request a new URL, which basically + * means the HTTP authentication is still going on so if the tunnel + * is complete we start over in INIT state */ + if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) { + infof(data, "CONNECT request done, loop to make another"); + connect_init(data, TRUE); /* reinit */ + } } while(data->req.newurl); result = CURLE_OK; if(s->tunnel_state == TUNNEL_COMPLETE) { - data->info.httpproxycode = data->req.httpcode; if(data->info.httpproxycode/100 != 2) { if(conn->bits.close && data->req.newurl) { conn->bits.proxy_connect_closed = TRUE; diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c index ab4d412ee3..bea964f79a 100644 --- a/libs/libcurl/src/imap.c +++ b/libs/libcurl/src/imap.c @@ -74,11 +74,11 @@ #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" -#include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "strcase.h" +#include "bufref.h" #include "curl_sasl.h" #include "warnless.h" @@ -102,19 +102,19 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done); static CURLcode imap_setup_connection(struct Curl_easy *data, struct connectdata *conn); static char *imap_atom(const char *str, bool escape_only); -static CURLcode imap_sendf(struct Curl_easy *data, - struct connectdata *conn, const char *fmt, ...); +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...); static CURLcode imap_parse_url_options(struct connectdata *conn); static CURLcode imap_parse_url_path(struct Curl_easy *data); static CURLcode imap_parse_custom_request(struct Curl_easy *data); static CURLcode imap_perform_authenticate(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp); + const struct bufref *initresp); static CURLcode imap_continue_authenticate(struct Curl_easy *data, - struct connectdata *conn, - const char *resp); -static void imap_get_message(char *buffer, char **outptr); + const char *mech, + const struct bufref *resp); +static CURLcode imap_cancel_authenticate(struct Curl_easy *data, + const char *mech); +static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out); /* * IMAP protocol handler. @@ -181,12 +181,15 @@ const struct Curl_handler Curl_handler_imaps = { /* SASL parameters for the imap protocol */ static const struct SASLproto saslimap = { "imap", /* The service name */ - '+', /* Code received when continuation is expected */ - IMAP_RESP_OK, /* Code to receive upon authentication success */ - 0, /* Maximum initial response length (no max) */ imap_perform_authenticate, /* Send authentication command */ imap_continue_authenticate, /* Send authentication continuation */ - imap_get_message /* Get SASL response message */ + imap_cancel_authenticate, /* Send authentication cancellation */ + imap_get_message, /* Get SASL response message */ + 0, /* No maximum initial response length */ + '+', /* Code received when continuation is expected */ + IMAP_RESP_OK, /* Code to receive upon authentication success */ + SASL_AUTH_DEFAULT, /* Default mechanisms */ + SASL_FLAG_BASE64 /* Configuration flags */ }; @@ -294,6 +297,7 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn, !strcasecompare(imap->custom, "EXPUNGE") && !strcasecompare(imap->custom, "LSUB") && !strcasecompare(imap->custom, "UID") && + !strcasecompare(imap->custom, "GETQUOTAROOT") && !strcasecompare(imap->custom, "NOOP"))) return FALSE; break; @@ -353,34 +357,32 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn, * * Gets the authentication message from the response buffer. */ -static void imap_get_message(char *buffer, char **outptr) +static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out) { - size_t len = strlen(buffer); - char *message = NULL; + char *message = data->state.buffer; + size_t len = strlen(message); if(len > 2) { /* Find the start of the message */ len -= 2; - for(message = buffer + 2; *message == ' ' || *message == '\t'; - message++, len--) + for(message += 2; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ - for(; len--;) + while(len--) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); } else /* junk input => zero length output */ - message = &buffer[len]; + Curl_bufref_set(out, "", 0, NULL); - *outptr = message; + return CURLE_OK; } /*********************************************************************** @@ -438,7 +440,7 @@ static CURLcode imap_perform_capability(struct Curl_easy *data, imapc->tls_supported = FALSE; /* Clear the TLS capability */ /* Send the CAPABILITY command */ - result = imap_sendf(data, conn, "CAPABILITY"); + result = imap_sendf(data, "CAPABILITY"); if(!result) state(data, IMAP_CAPABILITY); @@ -452,11 +454,10 @@ static CURLcode imap_perform_capability(struct Curl_easy *data, * * Sends the STARTTLS command to start the upgrade to TLS. */ -static CURLcode imap_perform_starttls(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_starttls(struct Curl_easy *data) { /* Send the STARTTLS command */ - CURLcode result = imap_sendf(data, conn, "STARTTLS"); + CURLcode result = imap_sendf(data, "STARTTLS"); if(!result) state(data, IMAP_STARTTLS); @@ -517,7 +518,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data, passwd = imap_atom(conn->passwd, false); /* Send the LOGIN command */ - result = imap_sendf(data, conn, "LOGIN %s %s", user ? user : "", + result = imap_sendf(data, "LOGIN %s %s", user ? user : "", passwd ? passwd : ""); free(user); @@ -537,20 +538,19 @@ static CURLcode imap_perform_login(struct Curl_easy *data, * SASL authentication mechanism. */ static CURLcode imap_perform_authenticate(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp) + const struct bufref *initresp) { CURLcode result = CURLE_OK; - (void)data; + const char *ir = (const char *) Curl_bufref_ptr(initresp); - if(initresp) { + if(ir) { /* Send the AUTHENTICATE command with the initial response */ - result = imap_sendf(data, conn, "AUTHENTICATE %s %s", mech, initresp); + result = imap_sendf(data, "AUTHENTICATE %s %s", mech, ir); } else { /* Send the AUTHENTICATE command */ - result = imap_sendf(data, conn, "AUTHENTICATE %s", mech); + result = imap_sendf(data, "AUTHENTICATE %s", mech); } return result; @@ -560,15 +560,34 @@ static CURLcode imap_perform_authenticate(struct Curl_easy *data, * * imap_continue_authenticate() * - * Sends SASL continuation data or cancellation. + * Sends SASL continuation data. */ static CURLcode imap_continue_authenticate(struct Curl_easy *data, - struct connectdata *conn, - const char *resp) + const char *mech, + const struct bufref *resp) { - struct imap_conn *imapc = &conn->proto.imapc; + struct imap_conn *imapc = &data->conn->proto.imapc; + + (void)mech; + + return Curl_pp_sendf(data, &imapc->pp, + "%s", (const char *) Curl_bufref_ptr(resp)); +} + +/*********************************************************************** + * + * imap_cancel_authenticate() + * + * Sends SASL cancellation. + */ +static CURLcode imap_cancel_authenticate(struct Curl_easy *data, + const char *mech) +{ + struct imap_conn *imapc = &data->conn->proto.imapc; + + (void)mech; - return Curl_pp_sendf(data, &imapc->pp, "%s", resp); + return Curl_pp_sendf(data, &imapc->pp, "*"); } /*********************************************************************** @@ -595,8 +614,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data, } /* Calculate the SASL login details */ - result = Curl_sasl_start(&imapc->sasl, data, conn, - imapc->ir_supported, &progress); + result = Curl_sasl_start(&imapc->sasl, data, imapc->ir_supported, &progress); if(!result) { if(progress == SASL_INPROGRESS) @@ -623,12 +641,11 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data, static CURLcode imap_perform_list(struct Curl_easy *data) { CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; struct IMAP *imap = data->req.p.imap; if(imap->custom) /* Send the custom request */ - result = imap_sendf(data, conn, "%s%s", imap->custom, + result = imap_sendf(data, "%s%s", imap->custom, imap->custom_params ? imap->custom_params : ""); else { /* Make sure the mailbox is in the correct atom format if necessary */ @@ -638,7 +655,7 @@ static CURLcode imap_perform_list(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; /* Send the LIST command */ - result = imap_sendf(data, conn, "LIST \"%s\" *", mailbox); + result = imap_sendf(data, "LIST \"%s\" *", mailbox); free(mailbox); } @@ -679,7 +696,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; /* Send the SELECT command */ - result = imap_sendf(data, conn, "SELECT %s", mailbox); + result = imap_sendf(data, "SELECT %s", mailbox); free(mailbox); @@ -695,8 +712,7 @@ static CURLcode imap_perform_select(struct Curl_easy *data) * * Sends a FETCH command to initiate the download of a message. */ -static CURLcode imap_perform_fetch(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_fetch(struct Curl_easy *data) { CURLcode result = CURLE_OK; struct IMAP *imap = data->req.p.imap; @@ -705,21 +721,21 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data, /* Send the FETCH command */ if(imap->partial) - result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]<%s>", + result = imap_sendf(data, "UID FETCH %s BODY[%s]<%s>", imap->uid, imap->section ? imap->section : "", imap->partial); else - result = imap_sendf(data, conn, "UID FETCH %s BODY[%s]", + result = imap_sendf(data, "UID FETCH %s BODY[%s]", imap->uid, imap->section ? imap->section : ""); } else if(imap->mindex) { /* Send the FETCH command */ if(imap->partial) - result = imap_sendf(data, conn, "FETCH %s BODY[%s]<%s>", + result = imap_sendf(data, "FETCH %s BODY[%s]<%s>", imap->mindex, imap->section ? imap->section : "", imap->partial); else - result = imap_sendf(data, conn, "FETCH %s BODY[%s]", + result = imap_sendf(data, "FETCH %s BODY[%s]", imap->mindex, imap->section ? imap->section : ""); } else { @@ -741,7 +757,6 @@ static CURLcode imap_perform_fetch(struct Curl_easy *data, static CURLcode imap_perform_append(struct Curl_easy *data) { CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; struct IMAP *imap = data->req.p.imap; char *mailbox; @@ -792,7 +807,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; /* Send the APPEND command */ - result = imap_sendf(data, conn, + result = imap_sendf(data, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}", mailbox, data->state.infilesize); @@ -810,8 +825,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data) * * Sends a SEARCH command. */ -static CURLcode imap_perform_search(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_search(struct Curl_easy *data) { CURLcode result = CURLE_OK; struct IMAP *imap = data->req.p.imap; @@ -823,7 +837,7 @@ static CURLcode imap_perform_search(struct Curl_easy *data, } /* Send the SEARCH command */ - result = imap_sendf(data, conn, "SEARCH %s", imap->query); + result = imap_sendf(data, "SEARCH %s", imap->query); if(!result) state(data, IMAP_SEARCH); @@ -837,11 +851,10 @@ static CURLcode imap_perform_search(struct Curl_easy *data, * * Performs the logout action prior to sclose() being called. */ -static CURLcode imap_perform_logout(struct Curl_easy *data, - struct connectdata *conn) +static CURLcode imap_perform_logout(struct Curl_easy *data) { /* Send the LOGOUT command */ - CURLcode result = imap_sendf(data, conn, "LOGOUT"); + CURLcode result = imap_sendf(data, "LOGOUT"); if(!result) state(data, IMAP_LOGOUT); @@ -935,22 +948,18 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data, line += wordlen; } } - else if(imapcode == IMAP_RESP_OK) { - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested */ - if(imapc->tls_supported) - /* Switch to TLS connection now */ - result = imap_perform_starttls(data, conn); - else if(data->set.use_ssl == CURLUSESSL_TRY) - /* Fallback and carry on with authentication */ - result = imap_perform_authentication(data, conn); - else { - failf(data, "STARTTLS not supported."); - result = CURLE_USE_SSL_FAILED; - } + else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* PREAUTH is not compatible with STARTTLS. */ + if(imapcode == IMAP_RESP_OK && imapc->tls_supported && !imapc->preauth) { + /* Switch to TLS connection now */ + result = imap_perform_starttls(data); } - else + else if(data->set.use_ssl <= CURLUSESSL_TRY) result = imap_perform_authentication(data, conn); + else { + failf(data, "STARTTLS not available."); + result = CURLE_USE_SSL_FAILED; + } } else result = imap_perform_authentication(data, conn); @@ -968,6 +977,10 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ + /* Pipelining in response is forbidden. */ + if(data->conn->proto.imapc.pp.cache_size) + return CURLE_WEIRD_SERVER_REPLY; + if(imapcode != IMAP_RESP_OK) { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied"); @@ -994,7 +1007,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ - result = Curl_sasl_continue(&imapc->sasl, data, conn, imapcode, &progress); + result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress); if(!result) switch(progress) { case SASL_DONE: @@ -1095,9 +1108,9 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode, if(imap->custom) result = imap_perform_list(data); else if(imap->query) - result = imap_perform_search(data, conn); + result = imap_perform_search(data); else - result = imap_perform_fetch(data, conn); + result = imap_perform_fetch(data); } } else { @@ -1442,7 +1455,7 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done) /* Set the default preferred authentication type and mechanism */ imapc->preftype = IMAP_TYPE_ANY; - Curl_sasl_init(&imapc->sasl, &saslimap); + Curl_sasl_init(&imapc->sasl, data, &saslimap); Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD); /* Initialise the pingpong layer */ @@ -1569,10 +1582,10 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected, result = imap_perform_list(data); else if(!imap->custom && selected && (imap->uid || imap->mindex)) /* FETCH from the same mailbox */ - result = imap_perform_fetch(data, conn); + result = imap_perform_fetch(data); else if(!imap->custom && selected && imap->query) /* SEARCH the current mailbox */ - result = imap_perform_search(data, conn); + result = imap_perform_search(data); else if(imap->mailbox && !selected && (imap->custom || imap->uid || imap->mindex || imap->query)) /* SELECT the mailbox */ @@ -1644,7 +1657,7 @@ static CURLcode imap_disconnect(struct Curl_easy *data, /* The IMAP session may or may not have been allocated/setup at this point! */ if(!dead_connection && conn->bits.protoconnstart) { - if(!imap_perform_logout(data, conn)) + if(!imap_perform_logout(data)) (void)imap_block_statemach(data, conn, TRUE); /* ignore errors */ } @@ -1748,17 +1761,16 @@ static CURLcode imap_setup_connection(struct Curl_easy *data, * * Designed to never block. */ -static CURLcode imap_sendf(struct Curl_easy *data, - struct connectdata *conn, const char *fmt, ...) +static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...) { CURLcode result = CURLE_OK; - struct imap_conn *imapc = &conn->proto.imapc; + struct imap_conn *imapc = &data->conn->proto.imapc; DEBUGASSERT(fmt); /* Calculate the tag based on the connection ID and command ID */ msnprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", - 'A' + curlx_sltosi(conn->connection_id % 26), + 'A' + curlx_sltosi(data->conn->connection_id % 26), (++imapc->cmdid)%1000); /* start with a blank buffer */ @@ -1912,8 +1924,6 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) struct imap_conn *imapc = &conn->proto.imapc; const char *ptr = conn->options; - imapc->sasl.resetprefs = TRUE; - while(!result && ptr && *ptr) { const char *key = ptr; const char *value; diff --git a/libs/libcurl/src/krb5.c b/libs/libcurl/src/krb5.c index e25f526564..afe425b046 100644 --- a/libs/libcurl/src/krb5.c +++ b/libs/libcurl/src/krb5.c @@ -374,7 +374,7 @@ static void krb5_end(void *app_data) } } -static struct Curl_sec_client_mech Curl_krb5_client_mech = { +static const struct Curl_sec_client_mech Curl_krb5_client_mech = { "GSSAPI", sizeof(gss_ctx_id_t), krb5_init, @@ -684,7 +684,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, (void) data; if(!conn->mech) - /* not inititalized, return error */ + /* not initialized, return error */ return -1; DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); @@ -768,7 +768,7 @@ static int sec_set_protection_level(struct Curl_easy *data) } } - /* Now try to negiociate the protection level. */ + /* Now try to negotiate the protection level. */ code = ftp_send_command(data, "PROT %c", level_to_char(level)); if(code < 0) diff --git a/libs/libcurl/src/libcurl.plist b/libs/libcurl/src/libcurl.plist index 575e28da76..daf485621b 100644 --- a/libs/libcurl/src/libcurl.plist +++ b/libs/libcurl/src/libcurl.plist @@ -15,7 +15,7 @@ <string>se.curl.libcurl</string> <key>CFBundleVersion</key> - <string>7.78.0</string> + <string>7.80.0</string> <key>CFBundleName</key> <string>libcurl</string> @@ -27,9 +27,9 @@ <string>????</string> <key>CFBundleShortVersionString</key> - <string>libcurl 7.78.0</string> + <string>libcurl 7.80.0</string> <key>CFBundleGetInfoString</key> - <string>libcurl.plist 7.78.0</string> + <string>libcurl.plist 7.80.0</string> </dict> </plist> diff --git a/libs/libcurl/src/libcurl.rc b/libs/libcurl/src/libcurl.rc index 3f7ae16034..fde6c8cae1 100644 --- a/libs/libcurl/src/libcurl.rc +++ b/libs/libcurl/src/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,7 +51,7 @@ BEGIN VALUE "OriginalFilename", "libcurl.dll\0" VALUE "ProductName", "The curl library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" - VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */ + VALUE "LegalCopyright", "Copyright (C) " LIBCURL_COPYRIGHT "\0" VALUE "License", "https://curl.se/docs/copyright.html\0" END END diff --git a/libs/libcurl/src/llist.c b/libs/libcurl/src/llist.c index e0ec7393d2..e78da7da82 100644 --- a/libs/libcurl/src/llist.c +++ b/libs/libcurl/src/llist.c @@ -106,9 +106,7 @@ Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e, e->next->prev = NULL; } else { - if(!e->prev) - list->head = e->next; - else + if(e->prev) e->prev->next = e->next; if(!e->next) diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c index c651ddf669..d90e45475c 100644 --- a/libs/libcurl/src/md4.c +++ b/libs/libcurl/src/md4.c @@ -27,6 +27,7 @@ #include "curl_md4.h" #include "warnless.h" + #ifdef USE_OPENSSL #include <openssl/opensslconf.h> #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) @@ -35,9 +36,20 @@ #endif #endif /* USE_OPENSSL */ +#ifdef USE_WOLFSSL +#include <wolfssl/options.h> +#ifdef NO_MD4 +#define OPENSSL_NO_MD4 +#endif +#endif + #ifdef USE_MBEDTLS -#include <mbedtls/config.h> #include <mbedtls/version.h> +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 +#include <mbedtls/mbedtls_config.h> +#else +#include <mbedtls/config.h> +#endif #if(MBEDTLS_VERSION_NUMBER >= 0x02070000) #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS @@ -70,8 +82,9 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) md4_digest(ctx, MD4_DIGEST_SIZE, result); } -#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) -/* When OpenSSL is available we use the MD4-functions from OpenSSL */ +#elif (defined(USE_OPENSSL) || defined(USE_WOLFSSL)) && \ + !defined(OPENSSL_NO_MD4) +/* When OpenSSL or wolfSSL is available, we use their MD4 functions. */ #include <openssl/md4.h> #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ diff --git a/libs/libcurl/src/md5.c b/libs/libcurl/src/md5.c index 7a24fd8cf4..810c5fba8e 100644 --- a/libs/libcurl/src/md5.c +++ b/libs/libcurl/src/md5.c @@ -33,11 +33,26 @@ #ifdef USE_MBEDTLS #include <mbedtls/version.h> -#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ + (MBEDTLS_VERSION_NUMBER < 0x03000000) #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS #endif #endif /* USE_MBEDTLS */ +#if defined(USE_OPENSSL) && !defined(USE_AMISSL) + #include <openssl/opensslconf.h> + #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0) + #define USE_OPENSSL_MD5 + #endif +#endif + +#ifdef USE_WOLFSSL + #include <wolfssl/options.h> + #ifndef NO_MD5 + #define USE_WOLFSSL_MD5 + #endif +#endif + #if defined(USE_GNUTLS) #include <nettle/md5.h> @@ -64,8 +79,9 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) md5_digest(ctx, 16, digest); } -#elif defined(USE_OPENSSL) && !defined(USE_AMISSL) -/* When OpenSSL is available we use the MD5-function from OpenSSL */ +#elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5) + +/* When OpenSSL or wolfSSL is available, we use their MD5 functions. */ #include <openssl/md5.h> #include "curl_memory.h" /* The last #include file should be: */ @@ -85,7 +101,7 @@ typedef mbedtls_md5_context MD5_CTX; static void MD5_Init(MD5_CTX *ctx) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - mbedtls_md5_starts(ctx); + (void) mbedtls_md5_starts(ctx); #else (void) mbedtls_md5_starts_ret(ctx); #endif @@ -96,7 +112,7 @@ static void MD5_Update(MD5_CTX *ctx, unsigned int length) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - mbedtls_md5_update(ctx, data, length); + (void) mbedtls_md5_update(ctx, data, length); #else (void) mbedtls_md5_update_ret(ctx, data, length); #endif @@ -105,7 +121,7 @@ static void MD5_Update(MD5_CTX *ctx, static void MD5_Final(unsigned char *digest, MD5_CTX *ctx) { #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - mbedtls_md5_finish(ctx, digest); + (void) mbedtls_md5_finish(ctx, digest); #else (void) mbedtls_md5_finish_ret(ctx, digest); #endif diff --git a/libs/libcurl/src/mime.c b/libs/libcurl/src/mime.c index 0bf1b46a4c..f40cc1a618 100644 --- a/libs/libcurl/src/mime.c +++ b/libs/libcurl/src/mime.c @@ -462,11 +462,13 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, /* Buffered data size can only be 0, 1 or 2. */ ptr[2] = ptr[3] = '='; i = 0; - switch(st->bufend - st->bufbeg) { - case 2: - i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; - /* FALLTHROUGH */ - case 1: + + /* If there is buffered data */ + if(st->bufend != st->bufbeg) { + + if(st->bufend - st->bufbeg == 2) + i = (st->buf[st->bufbeg + 1] & 0xFF) << 8; + i |= (st->buf[st->bufbeg] & 0xFF) << 16; ptr[0] = base64[(i >> 18) & 0x3F]; ptr[1] = base64[(i >> 12) & 0x3F]; @@ -476,7 +478,6 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, } cursize += 4; st->pos += 4; - break; } } } @@ -1954,7 +1955,8 @@ void Curl_mime_unpause(curl_mimepart *part) } -#else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ +#else /* !CURL_DISABLE_HTTP && !CURL_DISABLE_MIME || + !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ /* Mime not compiled in: define stubs for externally-referenced functions. */ curl_mime *curl_mime_init(CURL *easy) diff --git a/libs/libcurl/src/mk-ca-bundle.pl b/libs/libcurl/src/mk-ca-bundle.pl index 910fedb0ca..e5a7420c0e 100644 --- a/libs/libcurl/src/mk-ca-bundle.pl +++ b/libs/libcurl/src/mk-ca-bundle.pl @@ -436,9 +436,25 @@ while (<TXT>) { last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); } } - elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Not Valid After |Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { +# Not Valid After : Thu Sep 30 14:01:15 2021 + elsif(/^# Not Valid After : (.*)/) { + my $stamp = $1; + use Time::Piece; + my $t = Time::Piece->strptime + ($stamp, "%a %b %d %H:%M:%S %Y"); + my $delta = ($t->epoch - time()); # negative means no longer valid + if($delta < 0) { + $skipnum++; + report "Skipping: $caname is not valid anymore" if ($opt_v); + $valid = 0; + } + else { + $valid = 1; + } + next; + } + elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { push @precert, $_; - $valid = 1; next; } elsif(/^#|^\s*$/) { diff --git a/libs/libcurl/src/mqtt.c b/libs/libcurl/src/mqtt.c index f077e6c3dc..fcd40b41e6 100644 --- a/libs/libcurl/src/mqtt.c +++ b/libs/libcurl/src/mqtt.c @@ -128,6 +128,10 @@ static CURLcode mqtt_send(struct Curl_easy *data, mq->sendleftovers = sendleftovers; mq->nsend = nsend; } + else { + mq->sendleftovers = NULL; + mq->nsend = 0; + } return result; } diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c index 82d538d009..f307d63b93 100644 --- a/libs/libcurl/src/multi.c +++ b/libs/libcurl/src/multi.c @@ -1052,11 +1052,17 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi, for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; - if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { + if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK(sockbunch[i])) { + if(!FDSET_SOCK(sockbunch[i])) + /* pretend it doesn't exist */ + continue; FD_SET(sockbunch[i], read_fd_set); s = sockbunch[i]; } - if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { + if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK(sockbunch[i])) { + if(!FDSET_SOCK(sockbunch[i])) + /* pretend it doesn't exist */ + continue; FD_SET(sockbunch[i], write_fd_set); s = sockbunch[i]; } @@ -1100,6 +1106,9 @@ static CURLMcode multi_wait(struct Curl_multi *multi, WSANETWORKEVENTS wsa_events; DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT); #endif +#ifndef ENABLE_WAKEUP + (void)use_wakeup; +#endif if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -2019,6 +2028,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; case MSTATE_DO: + if(data->set.fprereq) { + int prereq_rc; + + /* call the prerequest callback function */ + Curl_set_in_callback(data, true); + prereq_rc = data->set.fprereq(data->set.prereq_userp, + data->info.conn_primary_ip, + data->info.conn_local_ip, + data->info.conn_primary_port, + data->info.conn_local_port); + Curl_set_in_callback(data, false); + if(prereq_rc != CURL_PREREQFUNC_OK) { + failf(data, "operation aborted by pre-request callback"); + /* failure in pre-request callback - don't do any other processing */ + result = CURLE_ABORTED_BY_CALLBACK; + Curl_posttransfer(data); + multi_done(data, result, FALSE); + stream_error = TRUE; + break; + } + } + if(data->set.connect_only) { /* keep connection open for application to use the socket */ connkeep(data->conn, "CONNECT_ONLY"); @@ -2602,7 +2633,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) multi->magic = 0; /* not good anymore */ - /* Firsrt remove all remaining easy handles */ + /* First remove all remaining easy handles */ data = multi->easyp; while(data) { nextdata = data->next; @@ -3171,7 +3202,7 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms) { - static struct curltime tv_zero = {0, 0}; + static const struct curltime tv_zero = {0, 0}; if(multi->timetree) { /* we have a tree of expire times */ diff --git a/libs/libcurl/src/non-ascii.c b/libs/libcurl/src/non-ascii.c index 932cf89eef..3b77ae98d5 100644 --- a/libs/libcurl/src/non-ascii.c +++ b/libs/libcurl/src/non-ascii.c @@ -31,6 +31,7 @@ #include "sendf.h" #include "urldata.h" #include "multiif.h" +#include "strerror.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -104,6 +105,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data, iconv_t *cd = &tmpcd; char *input_ptr, *output_ptr; size_t in_bytes, out_bytes, rc; + char ebuffer[STRERROR_LEN]; /* open an iconv conversion descriptor if necessary */ if(data) @@ -116,7 +118,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_NETWORK, CURL_ICONV_CODESET_OF_HOST, - errno, strerror(errno)); + errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer))); return CURLE_CONV_FAILED; } } @@ -130,7 +132,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data, if((rc == ICONV_ERROR) || (in_bytes)) { failf(data, "The Curl_convert_to_network iconv call failed with errno %i: %s", - errno, strerror(errno)); + errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer))); return CURLE_CONV_FAILED; } #else @@ -170,6 +172,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data, iconv_t *cd = &tmpcd; char *input_ptr, *output_ptr; size_t in_bytes, out_bytes, rc; + char ebuffer[STRERROR_LEN]; /* open an iconv conversion descriptor if necessary */ if(data) @@ -182,7 +185,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK, - errno, strerror(errno)); + errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer))); return CURLE_CONV_FAILED; } } @@ -196,7 +199,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data, if((rc == ICONV_ERROR) || (in_bytes)) { failf(data, "Curl_convert_from_network iconv call failed with errno %i: %s", - errno, strerror(errno)); + errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer))); return CURLE_CONV_FAILED; } #else @@ -237,6 +240,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *input_ptr; char *output_ptr; size_t in_bytes, out_bytes, rc; + char ebuffer[STRERROR_LEN]; /* open an iconv conversion descriptor if necessary */ if(data) @@ -249,7 +253,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data, "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s", CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_FOR_UTF8, - errno, strerror(errno)); + errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer))); return CURLE_CONV_FAILED; } } @@ -263,7 +267,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data, if((rc == ICONV_ERROR) || (in_bytes)) { failf(data, "The Curl_convert_from_utf8 iconv call failed with errno %i: %s", - errno, strerror(errno)); + errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer))); return CURLE_CONV_FAILED; } if(output_ptr < input_ptr) { diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c index 5fdd6f3e05..d4ca67877d 100644 --- a/libs/libcurl/src/pop3.c +++ b/libs/libcurl/src/pop3.c @@ -75,10 +75,10 @@ #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" -#include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" +#include "bufref.h" #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" @@ -104,12 +104,12 @@ static CURLcode pop3_setup_connection(struct Curl_easy *data, static CURLcode pop3_parse_url_options(struct connectdata *conn); static CURLcode pop3_parse_url_path(struct Curl_easy *data); static CURLcode pop3_parse_custom_request(struct Curl_easy *data); -static CURLcode pop3_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp); -static CURLcode pop3_continue_auth(struct Curl_easy *data, - struct connectdata *conn, const char *resp); -static void pop3_get_message(char *buffer, char **outptr); +static CURLcode pop3_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out); /* * POP3 protocol handler. @@ -171,13 +171,16 @@ const struct Curl_handler Curl_handler_pop3s = { /* SASL parameters for the pop3 protocol */ static const struct SASLproto saslpop3 = { - "pop", /* The service name */ - '*', /* Code received when continuation is expected */ - '+', /* Code to receive upon authentication success */ - 255 - 8, /* Maximum initial response length (no max) */ - pop3_perform_auth, /* Send authentication command */ - pop3_continue_auth, /* Send authentication continuation */ - pop3_get_message /* Get SASL response message */ + "pop", /* The service name */ + pop3_perform_auth, /* Send authentication command */ + pop3_continue_auth, /* Send authentication continuation */ + pop3_cancel_auth, /* Send authentication cancellation */ + pop3_get_message, /* Get SASL response message */ + 255 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ + '*', /* Code received when continuation is expected */ + '+', /* Code to receive upon authentication success */ + SASL_AUTH_DEFAULT, /* Default mechanisms */ + SASL_FLAG_BASE64 /* Configuration flags */ }; #ifdef USE_SSL @@ -251,34 +254,32 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn, * * Gets the authentication message from the response buffer. */ -static void pop3_get_message(char *buffer, char **outptr) +static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out) { - size_t len = strlen(buffer); - char *message = NULL; + char *message = data->state.buffer; + size_t len = strlen(message); if(len > 2) { /* Find the start of the message */ len -= 2; - for(message = buffer + 2; *message == ' ' || *message == '\t'; - message++, len--) + for(message += 2; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ - for(; len--;) + while(len--) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); } else /* junk input => zero length output */ - message = &buffer[len]; + Curl_bufref_set(out, "", 0, NULL); - *outptr = message; + return CURLE_OK; } /*********************************************************************** @@ -475,16 +476,16 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data, * authentication mechanism. */ static CURLcode pop3_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp) + const struct bufref *initresp) { CURLcode result = CURLE_OK; - struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pop3_conn *pop3c = &data->conn->proto.pop3c; + const char *ir = (const char *) Curl_bufref_ptr(initresp); - if(initresp) { /* AUTH <mech> ...<crlf> */ + if(ir) { /* AUTH <mech> ...<crlf> */ /* Send the AUTH command with the initial response */ - result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, initresp); + result = Curl_pp_sendf(data, &pop3c->pp, "AUTH %s %s", mech, ir); } else { /* Send the AUTH command */ @@ -498,15 +499,33 @@ static CURLcode pop3_perform_auth(struct Curl_easy *data, * * pop3_continue_auth() * - * Sends SASL continuation data or cancellation. + * Sends SASL continuation data. */ static CURLcode pop3_continue_auth(struct Curl_easy *data, - struct connectdata *conn, - const char *resp) + const char *mech, + const struct bufref *resp) { - struct pop3_conn *pop3c = &conn->proto.pop3c; + struct pop3_conn *pop3c = &data->conn->proto.pop3c; + + (void)mech; + + return Curl_pp_sendf(data, &pop3c->pp, + "%s", (const char *) Curl_bufref_ptr(resp)); +} + +/*********************************************************************** + * + * pop3_cancel_auth() + * + * Sends SASL cancellation. + */ +static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech) +{ + struct pop3_conn *pop3c = &data->conn->proto.pop3c; - return Curl_pp_sendf(data, &pop3c->pp, "%s", resp); + (void)mech; + + return Curl_pp_sendf(data, &pop3c->pp, "*"); } /*********************************************************************** @@ -533,7 +552,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data, if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) { /* Calculate the SASL login details */ - result = Curl_sasl_start(&pop3c->sasl, data, conn, FALSE, &progress); + result = Curl_sasl_start(&pop3c->sasl, data, FALSE, &progress); if(!result) if(progress == SASL_INPROGRESS) @@ -741,28 +760,23 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, } } } - else if(pop3code == '+') { - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { - /* We don't have a SSL/TLS connection yet, but SSL is requested */ - if(pop3c->tls_supported) - /* Switch to TLS connection now */ - result = pop3_perform_starttls(data, conn); - else if(data->set.use_ssl == CURLUSESSL_TRY) - /* Fallback and carry on with authentication */ - result = pop3_perform_authentication(data, conn); - else { - failf(data, "STLS not supported."); - result = CURLE_USE_SSL_FAILED; - } - } - else - result = pop3_perform_authentication(data, conn); - } else { /* Clear text is supported when CAPA isn't recognised */ - pop3c->authtypes |= POP3_TYPE_CLEARTEXT; + if(pop3code != '+') + pop3c->authtypes |= POP3_TYPE_CLEARTEXT; - result = pop3_perform_authentication(data, conn); + if(!data->set.use_ssl || conn->ssl[FIRSTSOCKET].use) + result = pop3_perform_authentication(data, conn); + else if(pop3code == '+' && pop3c->tls_supported) + /* Switch to TLS connection now */ + result = pop3_perform_starttls(data, conn); + else if(data->set.use_ssl <= CURLUSESSL_TRY) + /* Fallback and carry on with authentication */ + result = pop3_perform_authentication(data, conn); + else { + failf(data, "STLS not supported."); + result = CURLE_USE_SSL_FAILED; + } } return result; @@ -777,6 +791,10 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; (void)instate; /* no use for this yet */ + /* Pipelining in response is forbidden. */ + if(data->conn->proto.pop3c.pp.cache_size) + return CURLE_WEIRD_SERVER_REPLY; + if(pop3code != '+') { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied"); @@ -803,7 +821,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ - result = Curl_sasl_continue(&pop3c->sasl, data, conn, pop3code, &progress); + result = Curl_sasl_continue(&pop3c->sasl, data, pop3code, &progress); if(!result) switch(progress) { case SASL_DONE: @@ -1013,7 +1031,9 @@ static CURLcode pop3_statemachine(struct Curl_easy *data, break; case POP3_QUIT: - /* fallthrough, just stop! */ + state(data, POP3_STOP); + break; + default: /* internal error */ state(data, POP3_STOP); @@ -1104,7 +1124,7 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done) /* Set the default preferred authentication type and mechanism */ pop3c->preftype = POP3_TYPE_ANY; - Curl_sasl_init(&pop3c->sasl, &saslpop3); + Curl_sasl_init(&pop3c->sasl, data, &saslpop3); /* Initialise the pingpong layer */ Curl_pp_setup(pp); @@ -1345,8 +1365,6 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) struct pop3_conn *pop3c = &conn->proto.pop3c; const char *ptr = conn->options; - pop3c->sasl.resetprefs = TRUE; - while(!result && ptr && *ptr) { const char *key = ptr; const char *value; diff --git a/libs/libcurl/src/progress.c b/libs/libcurl/src/progress.c index 4bcd615eba..f5ef6bd526 100644 --- a/libs/libcurl/src/progress.c +++ b/libs/libcurl/src/progress.c @@ -377,7 +377,12 @@ static curl_off_t trspeed(curl_off_t size, /* number of bytes */ { if(us < 1) return size * 1000000; - return (curl_off_t)((long double)size/us * 1000000); + else if(size < CURL_OFF_T_MAX/1000000) + return (size * 1000000) / us; + else if(us >= 1000000) + return size / (us / 1000000); + else + return CURL_OFF_T_MAX; } /* returns TRUE if it's time to show the progress meter */ diff --git a/libs/libcurl/src/select.c b/libs/libcurl/src/select.c index 52dca5a2c0..70d7ee5c26 100644 --- a/libs/libcurl/src/select.c +++ b/libs/libcurl/src/select.c @@ -64,7 +64,7 @@ * 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 citical issue + * value is system dependent, neither factor is a critical issue * for the intended use of this function in the library. * * Return values: diff --git a/libs/libcurl/src/select.h b/libs/libcurl/src/select.h index 19da1e774b..59a571dbbd 100644 --- a/libs/libcurl/src/select.h +++ b/libs/libcurl/src/select.h @@ -97,8 +97,10 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, #if defined(TPF) #define VALID_SOCK(x) 1 #define VERIFY_SOCK(x) Curl_nop_stmt +#define FDSET_SOCK(x) 1 #elif defined(USE_WINSOCK) #define VALID_SOCK(s) ((s) < INVALID_SOCKET) +#define FDSET_SOCK(x) 1 #define VERIFY_SOCK(x) do { \ if(!VALID_SOCK(x)) { \ SET_SOCKERRNO(WSAEINVAL); \ @@ -106,17 +108,17 @@ int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, } \ } while(0) #else -#ifdef HAVE_POLL_FINE -#define VALID_SOCK(s) ((s) >= 0) /* FD_SETSIZE is irrelevant for poll */ -#else -#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) -#endif -#define VERIFY_SOCK(x) do { \ - if(!VALID_SOCK(x)) { \ - SET_SOCKERRNO(EINVAL); \ - return -1; \ - } \ -} while(0) +#define VALID_SOCK(s) ((s) >= 0) + +/* If the socket is small enough to get set or read from an fdset */ +#define FDSET_SOCK(s) ((s) < FD_SETSIZE) + +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x) || !FDSET_SOCK(x)) { \ + SET_SOCKERRNO(EINVAL); \ + return -1; \ + } \ + } while(0) #endif #endif /* HEADER_CURL_SELECT_H */ diff --git a/libs/libcurl/src/sendf.c b/libs/libcurl/src/sendf.c index 14ca84bfe5..bcfa27a501 100644 --- a/libs/libcurl/src/sendf.c +++ b/libs/libcurl/src/sendf.c @@ -608,7 +608,7 @@ static CURLcode chop_write(struct Curl_easy *data, /* Curl_client_write() sends data to the write callback(s) The bit pattern defines to what "streams" to write to. Body and/or header. - The defines are in sendf.h of course. "len" is not allowed to be 0. + The defines are in sendf.h of course. If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the local character encoding. This is a problem and should be changed in @@ -621,8 +621,10 @@ CURLcode Curl_client_write(struct Curl_easy *data, { struct connectdata *conn = data->conn; - DEBUGASSERT(len); - DEBUGASSERT(type <= 3); + DEBUGASSERT(!(type & ~CLIENTWRITE_BOTH)); + + if(!len) + return CURLE_OK; /* FTP data may need conversion. */ if((type & CLIENTWRITE_BODY) && diff --git a/libs/libcurl/src/setopt.c b/libs/libcurl/src/setopt.c index 076fe5f59c..56d9c49926 100644 --- a/libs/libcurl/src/setopt.c +++ b/libs/libcurl/src/setopt.c @@ -2370,12 +2370,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_IGNORE_CONTENT_LENGTH: -#ifndef USE_HYPER data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE; break; -#else - return CURLE_NOT_BUILT_IN; -#endif case CURLOPT_CONNECT_ONLY: /* @@ -2481,6 +2477,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) va_arg(param, char *)); break; + case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256: + /* + * Option to allow for the SHA256 of the host public key to be checked + * for validation purposes. + */ + result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], + va_arg(param, char *)); + break; + case CURLOPT_SSH_KNOWNHOSTS: /* * Store the file name to read known hosts from. @@ -2511,8 +2516,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) /* * disable libcurl transfer encoding is used */ +#ifndef USE_HYPER data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; +#else + return CURLE_NOT_BUILT_IN; /* hyper doesn't support */ +#endif case CURLOPT_HTTP_CONTENT_DECODING: /* @@ -2933,6 +2942,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) return CURLE_BAD_FUNCTION_ARGUMENT; data->set.maxage_conn = arg; break; + case CURLOPT_MAXLIFETIME_CONN: + arg = va_arg(param, long); + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.maxlifetime_conn = arg; + break; case CURLOPT_TRAILERFUNCTION: #ifndef CURL_DISABLE_HTTP data->set.trailer_callback = va_arg(param, curl_trailer_callback); @@ -3008,6 +3023,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) return result; break; #endif + case CURLOPT_PREREQFUNCTION: + data->set.fprereq = va_arg(param, curl_prereq_callback); + break; + case CURLOPT_PREREQDATA: + data->set.prereq_userp = va_arg(param, void *); + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/libs/libcurl/src/setup-win32.h b/libs/libcurl/src/setup-win32.h index c35dec88cb..fa8742f3b1 100644 --- a/libs/libcurl/src/setup-win32.h +++ b/libs/libcurl/src/setup-win32.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,11 +25,11 @@ /* * Include header files for windows builds before redefining anything. * Use this preprocessor block only to include or exclude windows.h, - * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs + * winsock2.h or ws2tcpip.h. Any other windows thing belongs * to any other further and independent block. Under Cygwin things work * just as under linux (e.g. <sys/socket.h>) and the winsock headers should * never be included when __CYGWIN__ is defined. configure script takes - * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H, + * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK2_H, * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined. */ @@ -47,10 +47,6 @@ # ifdef HAVE_WS2TCPIP_H # include <ws2tcpip.h> # endif -# else -# ifdef HAVE_WINSOCK_H -# include <winsock.h> -# endif # endif # include <tchar.h> # ifdef UNICODE @@ -67,10 +63,6 @@ #ifdef HAVE_WINSOCK2_H # define USE_WINSOCK 2 -#else -# ifdef HAVE_WINSOCK_H -# error "WinSock version 1 is no longer supported, version 2 is required!" -# endif #endif /* diff --git a/libs/libcurl/src/sha256.c b/libs/libcurl/src/sha256.c index c34f97e8f6..1391412ce5 100644 --- a/libs/libcurl/src/sha256.c +++ b/libs/libcurl/src/sha256.c @@ -29,11 +29,18 @@ #include "curl_sha256.h" #include "curl_hmac.h" +#ifdef USE_WOLFSSL +#include <wolfssl/options.h> +#ifndef NO_SHA256 +#define USE_OPENSSL_SHA256 +#endif +#endif + #if defined(USE_OPENSSL) #include <openssl/opensslv.h> -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) +#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL) #define USE_OPENSSL_SHA256 #endif @@ -42,8 +49,9 @@ #ifdef USE_MBEDTLS #include <mbedtls/version.h> -#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) - #define HAS_RESULT_CODE_BASED_FUNCTIONS +#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ + (MBEDTLS_VERSION_NUMBER < 0x03000000) + #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS #endif #endif /* USE_MBEDTLS */ @@ -62,7 +70,36 @@ #if defined(USE_OPENSSL_SHA256) /* When OpenSSL is available we use the SHA256-function from OpenSSL */ -#include <openssl/sha.h> +#include <openssl/evp.h> + +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +struct sha256_ctx { + EVP_MD_CTX *openssl_ctx; +}; +typedef struct sha256_ctx my_sha256_ctx; + +static void my_sha256_init(my_sha256_ctx *ctx) +{ + ctx->openssl_ctx = EVP_MD_CTX_create(); + EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL); +} + +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) +{ + EVP_DigestUpdate(ctx->openssl_ctx, data, length); +} + +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) +{ + EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL); + EVP_MD_CTX_destroy(ctx->openssl_ctx); +} #elif defined(USE_GNUTLS) @@ -73,21 +110,21 @@ /* The last #include file should be: */ #include "memdebug.h" -typedef struct sha256_ctx SHA256_CTX; +typedef struct sha256_ctx my_sha256_ctx; -static void SHA256_Init(SHA256_CTX *ctx) +static void my_sha256_init(my_sha256_ctx *ctx) { sha256_init(ctx); } -static void SHA256_Update(SHA256_CTX *ctx, - const unsigned char *data, - unsigned int length) +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) { sha256_update(ctx, length, data); } -static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) { sha256_digest(ctx, SHA256_DIGEST_SIZE, digest); } @@ -101,32 +138,32 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" -typedef mbedtls_sha256_context SHA256_CTX; +typedef mbedtls_sha256_context my_sha256_ctx; -static void SHA256_Init(SHA256_CTX *ctx) +static void my_sha256_init(my_sha256_ctx *ctx) { -#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) - mbedtls_sha256_starts(ctx, 0); +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_sha256_starts(ctx, 0); #else (void) mbedtls_sha256_starts_ret(ctx, 0); #endif } -static void SHA256_Update(SHA256_CTX *ctx, - const unsigned char *data, - unsigned int length) +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) { -#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) - mbedtls_sha256_update(ctx, data, length); +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_sha256_update(ctx, data, length); #else (void) mbedtls_sha256_update_ret(ctx, data, length); #endif } -static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) { -#if !defined(HAS_RESULT_CODE_BASED_FUNCTIONS) - mbedtls_sha256_finish(ctx, digest); +#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) + (void) mbedtls_sha256_finish(ctx, digest); #else (void) mbedtls_sha256_finish_ret(ctx, digest); #endif @@ -144,21 +181,21 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) /* The last #include file should be: */ #include "memdebug.h" -typedef CC_SHA256_CTX SHA256_CTX; +typedef CC_SHA256_CTX my_sha256_ctx; -static void SHA256_Init(SHA256_CTX *ctx) +static void my_sha256_init(my_sha256_ctx *ctx) { (void) CC_SHA256_Init(ctx); } -static void SHA256_Update(SHA256_CTX *ctx, - const unsigned char *data, - unsigned int length) +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) { (void) CC_SHA256_Update(ctx, data, length); } -static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) { (void) CC_SHA256_Final(digest, ctx); } @@ -171,13 +208,13 @@ struct sha256_ctx { HCRYPTPROV hCryptProv; HCRYPTHASH hHash; }; -typedef struct sha256_ctx SHA256_CTX; +typedef struct sha256_ctx my_sha256_ctx; #if !defined(CALG_SHA_256) #define CALG_SHA_256 0x0000800c #endif -static void SHA256_Init(SHA256_CTX *ctx) +static void my_sha256_init(my_sha256_ctx *ctx) { if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { @@ -185,14 +222,14 @@ static void SHA256_Init(SHA256_CTX *ctx) } } -static void SHA256_Update(SHA256_CTX *ctx, - const unsigned char *data, - unsigned int length) +static void my_sha256_update(my_sha256_ctx *ctx, + const unsigned char *data, + unsigned int length) { CryptHashData(ctx->hHash, (unsigned char *) data, length, 0); } -static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx) +static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx) { unsigned long length = 0; @@ -261,7 +298,7 @@ struct sha256_state { unsigned long state[8], curlen; unsigned char buf[64]; }; -typedef struct sha256_state SHA256_CTX; +typedef struct sha256_state my_sha256_ctx; /* The K array */ static const unsigned long K[64] = { @@ -338,7 +375,7 @@ static int sha256_compress(struct sha256_state *md, } /* Initialize the hash state */ -static void SHA256_Init(struct sha256_state *md) +static void my_sha256_init(struct sha256_state *md) { md->curlen = 0; md->length = 0; @@ -359,9 +396,9 @@ static void SHA256_Init(struct sha256_state *md) @param inlen The length of the data (octets) @return CRYPT_OK if successful */ -static int SHA256_Update(struct sha256_state *md, - const unsigned char *in, - unsigned long inlen) +static int my_sha256_update(struct sha256_state *md, + const unsigned char *in, + unsigned long inlen) { unsigned long n; @@ -400,8 +437,8 @@ static int SHA256_Update(struct sha256_state *md, @param out [out] The destination of the hash (32 bytes) @return CRYPT_OK if successful */ -static int SHA256_Final(unsigned char *out, - struct sha256_state *md) +static int my_sha256_final(unsigned char *out, + struct sha256_state *md) { int i; @@ -458,24 +495,24 @@ static int SHA256_Final(unsigned char *out, void Curl_sha256it(unsigned char *output, const unsigned char *input, const size_t length) { - SHA256_CTX ctx; + my_sha256_ctx ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, input, curlx_uztoui(length)); - SHA256_Final(output, &ctx); + my_sha256_init(&ctx); + my_sha256_update(&ctx, input, curlx_uztoui(length)); + my_sha256_final(output, &ctx); } const struct HMAC_params Curl_HMAC_SHA256[] = { { /* Hash initialization function. */ - CURLX_FUNCTION_CAST(HMAC_hinit_func, SHA256_Init), + CURLX_FUNCTION_CAST(HMAC_hinit_func, my_sha256_init), /* Hash update function. */ - CURLX_FUNCTION_CAST(HMAC_hupdate_func, SHA256_Update), + CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_sha256_update), /* Hash computation end function. */ - CURLX_FUNCTION_CAST(HMAC_hfinal_func, SHA256_Final), + CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_sha256_final), /* Size of hash context structure. */ - sizeof(SHA256_CTX), + sizeof(my_sha256_ctx), /* Maximum key length. */ 64, /* Result size. */ diff --git a/libs/libcurl/src/smtp.c b/libs/libcurl/src/smtp.c index 1a3da15599..8e0b046096 100644 --- a/libs/libcurl/src/smtp.c +++ b/libs/libcurl/src/smtp.c @@ -78,11 +78,11 @@ #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" -#include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" #include "curl_gethostname.h" +#include "bufref.h" #include "curl_sasl.h" #include "warnless.h" /* The last 3 #include files should be in this order */ @@ -109,12 +109,12 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data); static CURLcode smtp_parse_custom_request(struct Curl_easy *data); static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma, char **address, struct hostname *host); -static CURLcode smtp_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp); -static CURLcode smtp_continue_auth(struct Curl_easy *data, - struct connectdata *conn, const char *resp); -static void smtp_get_message(char *buffer, char **outptr); +static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech, + const struct bufref *initresp); +static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech, + const struct bufref *resp); +static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech); +static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out); /* * SMTP protocol handler. @@ -176,13 +176,16 @@ const struct Curl_handler Curl_handler_smtps = { /* SASL parameters for the smtp protocol */ static const struct SASLproto saslsmtp = { - "smtp", /* The service name */ - 334, /* Code received when continuation is expected */ - 235, /* Code to receive upon authentication success */ - 512 - 8, /* Maximum initial response length (no max) */ - smtp_perform_auth, /* Send authentication command */ - smtp_continue_auth, /* Send authentication continuation */ - smtp_get_message /* Get SASL response message */ + "smtp", /* The service name */ + smtp_perform_auth, /* Send authentication command */ + smtp_continue_auth, /* Send authentication continuation */ + smtp_cancel_auth, /* Cancel authentication */ + smtp_get_message, /* Get SASL response message */ + 512 - 8, /* Max line len - strlen("AUTH ") - 1 space - crlf */ + 334, /* Code received when continuation is expected */ + 235, /* Code to receive upon authentication success */ + SASL_AUTH_DEFAULT, /* Default mechanisms */ + SASL_FLAG_BASE64 /* Configuration flags */ }; #ifdef USE_SSL @@ -249,34 +252,32 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn, * * Gets the authentication message from the response buffer. */ -static void smtp_get_message(char *buffer, char **outptr) +static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out) { - size_t len = strlen(buffer); - char *message = NULL; + char *message = data->state.buffer; + size_t len = strlen(message); if(len > 4) { /* Find the start of the message */ len -= 4; - for(message = buffer + 4; *message == ' ' || *message == '\t'; - message++, len--) + for(message += 4; *message == ' ' || *message == '\t'; message++, len--) ; /* Find the end of the message */ - for(; len--;) + while(len--) if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' && message[len] != '\t') break; /* Terminate the message */ - if(++len) { - message[len] = '\0'; - } + message[++len] = '\0'; + Curl_bufref_set(out, message, len, NULL); } else /* junk input => zero length output */ - message = &buffer[len]; + Curl_bufref_set(out, "", 0, NULL); - *outptr = message; + return CURLE_OK; } /*********************************************************************** @@ -422,16 +423,16 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data) * authentication mechanism. */ static CURLcode smtp_perform_auth(struct Curl_easy *data, - struct connectdata *conn, const char *mech, - const char *initresp) + const struct bufref *initresp) { CURLcode result = CURLE_OK; - struct smtp_conn *smtpc = &conn->proto.smtpc; + struct smtp_conn *smtpc = &data->conn->proto.smtpc; + const char *ir = (const char *) Curl_bufref_ptr(initresp); - if(initresp) { /* AUTH <mech> ...<crlf> */ + if(ir) { /* AUTH <mech> ...<crlf> */ /* Send the AUTH command with the initial response */ - result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, initresp); + result = Curl_pp_sendf(data, &smtpc->pp, "AUTH %s %s", mech, ir); } else { /* Send the AUTH command */ @@ -445,14 +446,33 @@ static CURLcode smtp_perform_auth(struct Curl_easy *data, * * smtp_continue_auth() * - * Sends SASL continuation data or cancellation. + * Sends SASL continuation data. */ static CURLcode smtp_continue_auth(struct Curl_easy *data, - struct connectdata *conn, const char *resp) + const char *mech, + const struct bufref *resp) { - struct smtp_conn *smtpc = &conn->proto.smtpc; + struct smtp_conn *smtpc = &data->conn->proto.smtpc; + + (void)mech; - return Curl_pp_sendf(data, &smtpc->pp, "%s", resp); + return Curl_pp_sendf(data, &smtpc->pp, + "%s", (const char *) Curl_bufref_ptr(resp)); +} + +/*********************************************************************** + * + * smtp_cancel_auth() + * + * Sends SASL cancellation. + */ +static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech) +{ + struct smtp_conn *smtpc = &data->conn->proto.smtpc; + + (void)mech; + + return Curl_pp_sendf(data, &smtpc->pp, "*"); } /*********************************************************************** @@ -470,7 +490,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data) saslprogress progress; /* Check we have enough data to authenticate with, and the - server supports authentiation, and end the connect phase if not */ + server supports authentication, and end the connect phase if not */ if(!smtpc->auth_supported || !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) { state(data, SMTP_STOP); @@ -478,7 +498,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data) } /* Calculate the SASL login details */ - result = Curl_sasl_start(&smtpc->sasl, data, conn, FALSE, &progress); + result = Curl_sasl_start(&smtpc->sasl, data, FALSE, &progress); if(!result) { if(progress == SASL_INPROGRESS) @@ -507,7 +527,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data) if(smtp->rcpt) { /* We notify the server we are sending UTF-8 data if a) it supports the - SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in + SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in either the local address or host name parts. This is regardless of whether the host name is encoded using IDN ACE */ bool utf8 = FALSE; @@ -580,7 +600,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data) struct connectdata *conn = data->conn; /* We notify the server we are sending UTF-8 data if a) it supports the - SMTPUTF8 extension and b) The mailbox contains UTF-8 charaacters, in + SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in either the local address or host name parts. This is regardless of whether the host name is encoded using IDN ACE */ bool utf8 = FALSE; @@ -835,6 +855,10 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; (void)instate; /* no use for this yet */ + /* Pipelining in response is forbidden. */ + if(data->conn->proto.smtpc.pp.cache_size) + return CURLE_WEIRD_SERVER_REPLY; + if(smtpcode != 220) { if(data->set.use_ssl != CURLUSESSL_TRY) { failf(data, "STARTTLS denied, code %d", smtpcode); @@ -982,7 +1006,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data, (void)instate; /* no use for this yet */ - result = Curl_sasl_continue(&smtpc->sasl, data, conn, smtpcode, &progress); + result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress); if(!result) switch(progress) { case SASL_DONE: @@ -1330,7 +1354,7 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done) PINGPONG_SETUP(pp, smtp_statemachine, smtp_endofresp); /* Initialize the SASL storage */ - Curl_sasl_init(&smtpc->sasl, &saslsmtp); + Curl_sasl_init(&smtpc->sasl, data, &saslsmtp); /* Initialise the pingpong layer */ Curl_pp_setup(pp); @@ -1652,8 +1676,6 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) struct smtp_conn *smtpc = &conn->proto.smtpc; const char *ptr = conn->options; - smtpc->sasl.resetprefs = TRUE; - while(!result && ptr && *ptr) { const char *key = ptr; const char *value; diff --git a/libs/libcurl/src/socks.c b/libs/libcurl/src/socks.c index 91c4223a5f..db4c80834e 100644 --- a/libs/libcurl/src/socks.c +++ b/libs/libcurl/src/socks.c @@ -99,24 +99,24 @@ int Curl_blockread_all(struct Curl_easy *data, /* transfer */ } #endif -#ifndef DEBUGBUILD -#define sxstate(x,y) socksstate(x,y) -#else +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#define DEBUG_AND_VERBOSE #define sxstate(x,y) socksstate(x,y, __LINE__) +#else +#define sxstate(x,y) socksstate(x,y) #endif - /* always use this function to change state, to make debugging easier */ static void socksstate(struct Curl_easy *data, enum connect_t state -#ifdef DEBUGBUILD +#ifdef DEBUG_AND_VERBOSE , int lineno #endif ) { struct connectdata *conn = data->conn; enum connect_t oldstate = conn->cnnct.state; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifdef DEBUG_AND_VERBOSE /* synced with the state list in urldata.h */ static const char * const statename[] = { "INIT", @@ -146,7 +146,7 @@ static void socksstate(struct Curl_easy *data, conn->cnnct.state = state; -#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifdef DEBUG_AND_VERBOSE infof(data, "SXSTATE: %s => %s conn %p; line %d", statename[oldstate], statename[conn->cnnct.state], conn, diff --git a/libs/libcurl/src/socks_gssapi.c b/libs/libcurl/src/socks_gssapi.c index 34bfa37d7f..8ef2f8f374 100644 --- a/libs/libcurl/src/socks_gssapi.c +++ b/libs/libcurl/src/socks_gssapi.c @@ -257,7 +257,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - if(socksreq[1] != 1) { /* status / messgae type */ + if(socksreq[1] != 1) { /* status / message type */ failf(data, "Invalid GSS-API authentication response type (%d %d).", socksreq[0], socksreq[1]); gss_release_name(&gss_status, &server); @@ -452,7 +452,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - if(socksreq[1] != 2) { /* status / messgae type */ + 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); diff --git a/libs/libcurl/src/socks_sspi.c b/libs/libcurl/src/socks_sspi.c index cb225b9b5a..ffc8703468 100644 --- a/libs/libcurl/src/socks_sspi.c +++ b/libs/libcurl/src/socks_sspi.c @@ -277,7 +277,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_COULDNT_CONNECT; } - if(socksreq[1] != 1) { /* status / messgae type */ + if(socksreq[1] != 1) { /* status / message type */ failf(data, "Invalid SSPI authentication response type (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); free(service_name); diff --git a/libs/libcurl/src/splay.c b/libs/libcurl/src/splay.c index a94e2c85e9..1c1dafb920 100644 --- a/libs/libcurl/src/splay.c +++ b/libs/libcurl/src/splay.c @@ -154,7 +154,7 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i, struct Curl_tree *t, struct Curl_tree **removed) { - static struct curltime tv_zero = {0, 0}; + static const struct curltime tv_zero = {0, 0}; struct Curl_tree *x; if(!t) { diff --git a/libs/libcurl/src/strdup.c b/libs/libcurl/src/strdup.c index 9af47ea473..85cf33b3ed 100644 --- a/libs/libcurl/src/strdup.c +++ b/libs/libcurl/src/strdup.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,6 +24,10 @@ #include <curl/curl.h> +#ifdef WIN32 +#include <wchar.h> +#endif + #include "strdup.h" #include "curl_memory.h" @@ -50,6 +54,28 @@ char *curlx_strdup(const char *str) } #endif +#ifdef WIN32 +/*************************************************************************** + * + * Curl_wcsdup(source) + * + * Copies the 'source' wchar string to a newly allocated buffer (that is + * returned). + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +wchar_t *Curl_wcsdup(const wchar_t *src) +{ + size_t length = wcslen(src); + + if(length > (SIZE_T_MAX / sizeof(wchar_t)) - 1) + return (wchar_t *)NULL; /* integer overflow */ + + return (wchar_t *)Curl_memdup(src, (length + 1) * sizeof(wchar_t)); +} +#endif + /*************************************************************************** * * Curl_memdup(source, length) diff --git a/libs/libcurl/src/strdup.h b/libs/libcurl/src/strdup.h index 0936956f89..8c8a6f20e1 100644 --- a/libs/libcurl/src/strdup.h +++ b/libs/libcurl/src/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,9 @@ #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif +#ifdef WIN32 +wchar_t* Curl_wcsdup(const wchar_t* src); +#endif void *Curl_memdup(const void *src, size_t buffer_length); void *Curl_saferealloc(void *ptr, size_t size); diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c index a1ec539b90..31eb2bf790 100644 --- a/libs/libcurl/src/strerror.c +++ b/libs/libcurl/src/strerror.c @@ -453,6 +453,78 @@ curl_share_strerror(CURLSHcode error) #endif } +const char * +curl_url_strerror(CURLUcode error) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + switch(error) { + case CURLUE_OK: + return "No error"; + + case CURLUE_BAD_HANDLE: + return "An invalid CURLU pointer was passed as argument"; + + case CURLUE_BAD_PARTPOINTER: + return "An invalid 'part' argument was passed as argument"; + + case CURLUE_MALFORMED_INPUT: + return "A malformed input was passed to a URL API function"; + + case CURLUE_BAD_PORT_NUMBER: + return "The port number was not a decimal number between 0 and 65535"; + + case CURLUE_UNSUPPORTED_SCHEME: + return "This libcurl build doesn't support the given URL scheme"; + + case CURLUE_URLDECODE: + return "URL decode error, most likely because of rubbish in the input"; + + case CURLUE_OUT_OF_MEMORY: + return "A memory function failed"; + + case CURLUE_USER_NOT_ALLOWED: + return "Credentials was passed in the URL when prohibited"; + + case CURLUE_UNKNOWN_PART: + return "An unknown part ID was passed to a URL API function"; + + case CURLUE_NO_SCHEME: + return "There is no scheme part in the URL"; + + case CURLUE_NO_USER: + return "There is no user part in the URL"; + + case CURLUE_NO_PASSWORD: + return "There is no password part in the URL"; + + case CURLUE_NO_OPTIONS: + return "There is no options part in the URL"; + + case CURLUE_NO_HOST: + return "There is no host part in the URL"; + + case CURLUE_NO_PORT: + return "There is no port part in the URL"; + + case CURLUE_NO_QUERY: + return "There is no query part in the URL"; + + case CURLUE_NO_FRAGMENT: + return "There is no fragment part in the URL"; + + case CURLUE_LAST: + break; + } + + return "CURLUcode unknown"; +#else + if(error == CURLUE_OK) + return "No error"; + else + return "Error"; +#endif +} + #ifdef USE_WINSOCK /* This is a helper function for Curl_strerror that converts Winsock error * codes (WSAGetLastError) to error messages. @@ -735,7 +807,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) #if defined(WIN32) /* 'sys_nerr' is the maximum errno number, it is not widely portable */ if(err >= 0 && err < sys_nerr) - strncpy(buf, strerror(err), max); + strncpy(buf, sys_errlist[err], max); else #endif { @@ -786,6 +858,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) } #else { + /* !checksrc! disable STRERROR 1 */ const char *msg = strerror(err); if(msg) strncpy(buf, msg, max); diff --git a/libs/libcurl/src/system_win32.c b/libs/libcurl/src/system_win32.c index 2939fd0d74..d4e194831f 100644 --- a/libs/libcurl/src/system_win32.c +++ b/libs/libcurl/src/system_win32.c @@ -102,6 +102,8 @@ CURLcode Curl_win32_init(long flags) Curl_if_nametoindex = pIfNameToIndex; } + /* curlx_verify_windows_version must be called during init at least once + because it has its own initialization routine. */ if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { Curl_isVistaOrGreater = TRUE; diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c index 8aeb14a4f5..7e5246f010 100644 --- a/libs/libcurl/src/tftp.c +++ b/libs/libcurl/src/tftp.c @@ -720,7 +720,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event) /* There's a bug in tftpd-hpa that causes it to send us an ack for * 65535 when the block number wraps to 0. So when we're expecting * 0, also accept 65535. See - * http://syslinux.zytor.com/archives/2010-September/015253.html + * https://www.syslinux.org/archives/2010-September/015612.html * */ !(state->block == 0 && rblock == 65535)) { /* This isn't the expected block. Log it and up the retry counter */ @@ -1304,9 +1304,9 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done) /********************************************************** * - * tftp_peform + * tftp_perform * - * Entry point for transfer from tftp_do, sarts state mach + * Entry point for transfer from tftp_do, starts state mach * **********************************************************/ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done) diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c index 3e650b5b9e..05fec7998c 100644 --- a/libs/libcurl/src/transfer.c +++ b/libs/libcurl/src/transfer.c @@ -1503,7 +1503,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) } #endif Curl_http2_init_state(&data->state); - Curl_hsts_loadcb(data, data->hsts); + result = Curl_hsts_loadcb(data, data->hsts); } /* diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c index 8a2845dddd..93b4397bff 100644 --- a/libs/libcurl/src/url.c +++ b/libs/libcurl/src/url.c @@ -622,6 +622,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) 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->http09_allowed = FALSE; set->httpwant = #ifdef USE_NGHTTP2 @@ -962,21 +963,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' to - be subject for reuse. The success rate is just too low after this. */ +/* A connection has to have been idle for a shorter time than 'maxage_conn' + (the success rate is just too low after this), or created less than + 'maxlifetime_conn' ago, to be subject for reuse. */ static bool conn_maxage(struct Curl_easy *data, struct connectdata *conn, struct curltime now) { - timediff_t idletime = Curl_timediff(now, conn->lastused); + timediff_t idletime, lifetime; + + idletime = Curl_timediff(now, conn->lastused); idletime /= 1000; /* integer seconds is fine */ if(idletime > data->set.maxage_conn) { - infof(data, "Too old connection (%ld seconds), disconnect it", + infof(data, "Too old connection (%ld seconds idle), disconnect it", idletime); return TRUE; } + + lifetime = Curl_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 (%ld seconds since creation), disconnect it", + lifetime); + return TRUE; + } + + return FALSE; } @@ -1892,9 +1908,13 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data, #else scopeidx = if_nametoindex(zoneid); #endif - if(!scopeidx) + if(!scopeidx) { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + char buffer[STRERROR_LEN]; infof(data, "Invalid zoneid: %s; %s", zoneid, - strerror(errno)); + Curl_strerror(errno, buffer, sizeof(buffer))); +#endif + } else conn->scope_id = scopeidx; } @@ -1950,7 +1970,8 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, CURLU_DISALLOW_USER : 0) | (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); if(uc) { - DEBUGF(infof(data, "curl_url_set rejected %s", data->state.url)); + DEBUGF(infof(data, "curl_url_set rejected %s: %s", data->state.url, + curl_url_strerror(uc))); return Curl_uc_to_curlcode(uc); } @@ -2376,6 +2397,11 @@ static CURLcode parse_proxy(struct Curl_easy *data, CURLcode result = CURLE_OK; char *scheme = NULL; + if(!uhp) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + /* When parsing the proxy, allowing non-supported schemes since we have these made up ones for proxies. Guess scheme for URLs without it. */ uc = curl_url_set(uhp, CURLUPART_URL, proxy, @@ -2759,7 +2785,7 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, size_t plen; size_t olen; - /* the input length check is because this is called directcly from setopt + /* the input length check is because this is called directly from setopt and isn't going through the regular string length check */ size_t llen = strlen(login); if(llen > CURL_MAX_INPUT_LENGTH) @@ -4089,7 +4115,7 @@ CURLcode Curl_connect(struct Curl_easy *data, /* init the single-transfer specific data */ Curl_free_request_state(data); memset(&data->req, 0, sizeof(struct SingleRequest)); - data->req.maxdownload = -1; + data->req.size = data->req.maxdownload = -1; /* call the stuff that needs to be called */ result = create_conn(data, &conn, asyncp); diff --git a/libs/libcurl/src/urlapi.c b/libs/libcurl/src/urlapi.c index 905c499d99..6d116b61bf 100644 --- a/libs/libcurl/src/urlapi.c +++ b/libs/libcurl/src/urlapi.c @@ -157,23 +157,23 @@ static size_t strlen_url(const char *url, bool relative) continue; } - switch(*ptr) { - case '?': - left = FALSE; - /* FALLTHROUGH */ - default: - if(urlchar_needs_escaping(*ptr)) - newlen += 2; - newlen++; - break; - case ' ': + if(*ptr == ' ') { if(left) newlen += 3; else newlen++; - break; + continue; } + + if (*ptr == '?') + left = FALSE; + + if(urlchar_needs_escaping(*ptr)) + newlen += 2; + + newlen++; } + return newlen; } @@ -202,19 +202,7 @@ static void strcpy_url(char *output, const char *url, bool relative) continue; } - switch(*iptr) { - case '?': - left = FALSE; - /* FALLTHROUGH */ - default: - if(urlchar_needs_escaping(*iptr)) { - msnprintf(optr, 4, "%%%02x", *iptr); - optr += 3; - } - else - *optr++=*iptr; - break; - case ' ': + if(*iptr == ' ') { if(left) { *optr++='%'; /* add a '%' */ *optr++='2'; /* add a '2' */ @@ -222,8 +210,18 @@ static void strcpy_url(char *output, const char *url, bool relative) } else *optr++='+'; /* add a '+' here */ - break; + continue; + } + + if(*iptr == '?') + left = FALSE; + + if(urlchar_needs_escaping(*iptr)) { + msnprintf(optr, 4, "%%%02x", *iptr); + optr += 3; } + else + *optr++ = *iptr; } *optr = 0; /* null-terminate output buffer */ @@ -656,7 +654,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) } else { /* letters from the second string is not ok */ - len = strcspn(hostname, " "); + len = strcspn(hostname, " \r\n"); if(hlen != len) /* hostname with bad content */ return CURLUE_MALFORMED_INPUT; @@ -756,10 +754,35 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen) return TRUE; } +/* return strdup'ed version in 'outp', possibly percent decoded */ +static CURLUcode decode_host(char *hostname, char **outp) +{ + char *per = NULL; + if(hostname[0] != '[') + /* only decode if not an ipv6 numerical */ + per = strchr(hostname, '%'); + if(!per) { + *outp = strdup(hostname); + if(!*outp) + return CURLUE_OUT_OF_MEMORY; + } + else { + /* might be encoded */ + size_t dlen; + CURLcode result = Curl_urldecode(NULL, hostname, 0, + outp, &dlen, REJECT_CTRL); + if(result) + return CURLUE_MALFORMED_INPUT; + } + + return CURLUE_OK; +} + static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) { char *path; bool path_alloced = FALSE; + bool uncpath = FALSE; char *hostname; char *query = NULL; char *fragment = NULL; @@ -770,8 +793,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) size_t schemelen = 0; size_t urllen; - if(!url) - return CURLUE_MALFORMED_INPUT; + DEBUGASSERT(url); /************************************************************* * Parse the URL. @@ -799,7 +821,6 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) /* path has been allocated large enough to hold this */ strcpy(path, &url[5]); - hostname = NULL; /* no host for file: URLs */ u->scheme = strdup("file"); if(!u->scheme) return CURLUE_OUT_OF_MEMORY; @@ -821,10 +842,13 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) * * o the hostname matches "localhost" (case-insensitively), or * - * o the hostname is a FQDN that resolves to this machine. + * o the hostname is a FQDN that resolves to this machine, or + * + * o it is an UNC String transformed to an URI (Windows only, RFC 8089 + * Appendix E.3). * * For brevity, we only consider URLs with empty, "localhost", or - * "127.0.0.1" hostnames as local. + * "127.0.0.1" hostnames as local, otherwise as an UNC String. * * Additionally, there is an exception for URLs with a Windows drive * letter in the authority (which was accidentally omitted from RFC 8089 @@ -833,18 +857,43 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) { /* the URL includes a host name, it must match "localhost" or "127.0.0.1" to be valid */ - if(!checkprefix("localhost/", ptr) && - !checkprefix("127.0.0.1/", ptr)) { + if(checkprefix("localhost/", ptr) || + checkprefix("127.0.0.1/", ptr)) { + ptr += 9; /* now points to the slash after the host */ + } + else { +#if defined(WIN32) + size_t len; + + /* the host name, NetBIOS computer name, can not contain disallowed + chars, and the delimiting slash character must be appended to the + host name */ + path = strpbrk(ptr, "/\\:*?\"<>|"); + if(!path || *path != '/') + return CURLUE_MALFORMED_INPUT; + + len = path - ptr; + if(len) { + memcpy(hostname, ptr, len); + hostname[len] = 0; + uncpath = TRUE; + } + + ptr -= 2; /* now points to the // before the host in UNC */ +#else /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ return CURLUE_MALFORMED_INPUT; +#endif } - ptr += 9; /* now points to the slash after the host */ } path = ptr; } + if(!uncpath) + hostname = NULL; /* no host for file: URLs by default */ + #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) /* Don't allow Windows drive letters when not in Windows. * This catches both "file:/c:" and "file:c:" */ @@ -1004,20 +1053,22 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ + u->host = strdup(""); } else { - result = hostname_check(u, hostname); - if(result) - return result; + if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4))) + u->host = strdup(normalized_ipv4); + else { + result = decode_host(hostname, &u->host); + if(result) + return result; + result = hostname_check(u, u->host); + if(result) + return result; + } } - - if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4))) - u->host = strdup(normalized_ipv4); - else - u->host = strdup(hostname); if(!u->host) return CURLUE_OUT_OF_MEMORY; - if((flags & CURLU_GUESS_SCHEME) && !schemep) { /* legacy curl-style guess based on host name */ if(checkprefix("ftp.", hostname)) @@ -1112,6 +1163,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, CURLUcode ifmissing = CURLUE_UNKNOWN_PART; char portbuf[7]; bool urldecode = (flags & CURLU_URLDECODE)?1:0; + bool urlencode = (flags & CURLU_URLENCODE)?1:0; bool plusdecode = FALSE; (void)flags; if(!u) @@ -1229,16 +1281,54 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, if(h && !(h->flags & PROTOPT_URLOPTIONS)) options = NULL; - if((u->host[0] == '[') && u->zoneid) { - /* make it '[ host %25 zoneid ]' */ - size_t hostlen = strlen(u->host); - size_t alen = hostlen + 3 + strlen(u->zoneid) + 1; - allochost = malloc(alen); + if(u->host[0] == '[') { + if(u->zoneid) { + /* make it '[ host %25 zoneid ]' */ + size_t hostlen = strlen(u->host); + size_t alen = hostlen + 3 + strlen(u->zoneid) + 1; + allochost = malloc(alen); + if(!allochost) + return CURLUE_OUT_OF_MEMORY; + memcpy(allochost, u->host, hostlen - 1); + msnprintf(&allochost[hostlen - 1], alen - hostlen + 1, + "%%25%s]", u->zoneid); + } + } + else if(urlencode) { + allochost = curl_easy_escape(NULL, u->host, 0); if(!allochost) return CURLUE_OUT_OF_MEMORY; - memcpy(allochost, u->host, hostlen - 1); - msnprintf(&allochost[hostlen - 1], alen - hostlen + 1, - "%%25%s]", u->zoneid); + } + else { + /* only encode '%' in output host name */ + char *host = u->host; + size_t pcount = 0; + /* first, count number of percents present in the name */ + while(*host) { + if(*host == '%') + pcount++; + host++; + } + /* if there were percents, encode the host name */ + if(pcount) { + size_t hostlen = strlen(u->host); + size_t alen = hostlen + 2 * pcount + 1; + char *o = allochost = malloc(alen); + if(!allochost) + return CURLUE_OUT_OF_MEMORY; + + host = u->host; + while(*host) { + if(*host == '%') { + memcpy(o, "%25", 3); + o += 3; + host++; + continue; + } + *o++ = *host++; + } + *o = '\0'; + } } url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", @@ -1380,10 +1470,15 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, case CURLUPART_OPTIONS: storep = &u->options; break; - case CURLUPART_HOST: + case CURLUPART_HOST: { + size_t len = strcspn(part, " \r\n"); + if(strlen(part) != len) + /* hostname with bad content */ + return CURLUE_MALFORMED_INPUT; storep = &u->host; Curl_safefree(u->zoneid); break; + } case CURLUPART_ZONEID: storep = &u->zoneid; break; diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h index 1d99112088..22068882f0 100644 --- a/libs/libcurl/src/urldata.h +++ b/libs/libcurl/src/urldata.h @@ -330,7 +330,7 @@ struct digestdata { char *opaque; char *qop; char *algorithm; - int nc; /* nounce count */ + int nc; /* nonce count */ BIT(stale); /* set true for re-negotiation */ BIT(userhash); #endif @@ -704,14 +704,15 @@ struct SingleRequest { #ifndef CURL_DISABLE_DOH struct dohdata *doh; /* DoH specific data for this request */ #endif - BIT(header); /* incoming data has HTTP header */ + BIT(header); /* incoming data has HTTP header */ BIT(content_range); /* set TRUE if Content-Range: was found */ - BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding - upload and we're uploading the last chunk */ - BIT(ignorebody); /* we read a response-body but we ignore it! */ + BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding + upload and we're uploading the last chunk */ + BIT(ignorebody); /* we read a response-body but we ignore it! */ BIT(http_bodyless); /* HTTP response status code is between 100 and 199, 204 or 304 */ - BIT(chunk); /* if set, this is a chunked transfer-encoding */ + BIT(chunk); /* if set, this is a chunked transfer-encoding */ + BIT(ignore_cl); /* ignore content-length */ BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding on upload */ BIT(getheader); /* TRUE if header parsing is wanted */ @@ -1553,6 +1554,7 @@ enum dupstring { STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */ + STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */ STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ STRING_PROXY_SERVICE_NAME, /* Proxy service name */ STRING_SERVICE_NAME, /* Service name */ @@ -1650,6 +1652,8 @@ struct UserDefined { curl_closesocket_callback fclosesocket; /* function for closing the socket */ void *closesocket_client; + curl_prereq_callback fprereq; /* pre-initial request callback */ + void *prereq_userp; /* pre-initial request user data */ void *seek_client; /* pointer to pass to the seek callback */ /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ @@ -1674,6 +1678,8 @@ struct UserDefined { long server_response_timeout; /* in milliseconds, 0 means no timeout */ long maxage_conn; /* in seconds, max idle time to allow a connection that is to be reused */ + long maxlifetime_conn; /* in seconds, max time since creation to allow a + connection that is to be reused */ long tftp_blksize; /* in bytes, 0 means use default */ curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ @@ -1851,7 +1857,6 @@ struct UserDefined { BIT(abstract_unix_socket); BIT(disallow_username_in_url); /* disallow username in url */ BIT(doh); /* DNS-over-HTTPS enabled */ - BIT(doh_get); /* use GET for DoH requests, instead of POST */ BIT(doh_verifypeer); /* DoH certificate peer verification */ BIT(doh_verifyhost); /* DoH certificate hostname verification */ BIT(doh_verifystatus); /* DoH certificate status verification */ diff --git a/libs/libcurl/src/vauth/krb5_gssapi.c b/libs/libcurl/src/vauth/krb5_gssapi.c index fee24ee470..67d43bd567 100644 --- a/libs/libcurl/src/vauth/krb5_gssapi.c +++ b/libs/libcurl/src/vauth/krb5_gssapi.c @@ -170,6 +170,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, * Parameters: * * data [in] - The session handle. + * authzid [in] - The authorization identity if some. * chlg [in] - Optional challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * out [out] - The result storage. @@ -177,6 +178,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *authzid, const struct bufref *chlg, struct kerberos5data *krb5, struct bufref *out) @@ -189,13 +191,10 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, OM_uint32 unused_status; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - unsigned int indata = 0; - unsigned int outdata = 0; + unsigned char *indata; gss_qop_t qop = GSS_C_QOP_DEFAULT; unsigned int sec_layer = 0; unsigned int max_size = 0; - gss_name_t username = GSS_C_NO_NAME; - gss_buffer_desc username_token; /* Ensure we have a valid challenge message */ if(!Curl_bufref_len(chlg)) { @@ -203,25 +202,6 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, return CURLE_BAD_CONTENT_ENCODING; } - /* Get the fully qualified username back from the context */ - major_status = gss_inquire_context(&minor_status, krb5->context, - &username, NULL, NULL, NULL, NULL, - NULL, NULL); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_inquire_context() failed: ", - major_status, minor_status); - return CURLE_AUTH_ERROR; - } - - /* Convert the username from internal format to a displayable token */ - major_status = gss_display_name(&minor_status, username, - &username_token, NULL); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, "gss_display_name() failed: ", - major_status, minor_status); - return CURLE_AUTH_ERROR; - } - /* Setup the challenge "input" security buffer */ input_token.value = (void *) Curl_bufref_ptr(chlg); input_token.length = Curl_bufref_len(chlg); @@ -232,32 +212,32 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, if(GSS_ERROR(major_status)) { Curl_gss_log_error(data, "gss_unwrap() failed: ", major_status, minor_status); - gss_release_buffer(&unused_status, &username_token); return CURLE_BAD_CONTENT_ENCODING; } /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ if(output_token.length != 4) { infof(data, "GSSAPI handshake failure (invalid security data)"); - gss_release_buffer(&unused_status, &username_token); return CURLE_BAD_CONTENT_ENCODING; } - /* Copy the data out and free the challenge as it is not required anymore */ - memcpy(&indata, output_token.value, 4); + /* Extract the security layer and the maximum message size */ + indata = output_token.value; + sec_layer = indata[0]; + max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3]; + + /* Free the challenge as it is not required anymore */ gss_release_buffer(&unused_status, &output_token); - /* Extract the security layer */ - sec_layer = indata & 0x000000FF; + /* Process the security layer */ if(!(sec_layer & GSSAUTH_P_NONE)) { infof(data, "GSSAPI handshake failure (invalid security layer)"); - gss_release_buffer(&unused_status, &username_token); return CURLE_BAD_CONTENT_ENCODING; } + sec_layer &= GSSAUTH_P_NONE; /* We do not support a security layer */ - /* Extract the maximum message size the server can receive */ - max_size = ntohl(indata & 0xFFFFFF00); + /* Process the maximum message size the server can receive */ if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as we don't require one unless we are encrypting data, we tell the server @@ -266,26 +246,24 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, } /* Allocate our message */ - messagelen = sizeof(outdata) + username_token.length + 1; + messagelen = 4; + if(authzid) + messagelen += strlen(authzid); message = malloc(messagelen); - if(!message) { - gss_release_buffer(&unused_status, &username_token); + if(!message) return CURLE_OUT_OF_MEMORY; - } - /* Populate the message with the security layer, client supported receive - message size and authorization identity including the 0x00 based - terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization - identity is not terminated with the zero-valued (%x00) octet." it seems - necessary to include it. */ - outdata = htonl(max_size) | sec_layer; - memcpy(message, &outdata, sizeof(outdata)); - memcpy(message + sizeof(outdata), username_token.value, - username_token.length); - message[messagelen - 1] = '\0'; - - /* Free the username token as it is not required anymore */ - gss_release_buffer(&unused_status, &username_token); + /* Populate the message with the security layer and client supported receive + message size. */ + message[0] = sec_layer & 0xFF; + message[1] = (max_size >> 16) & 0xFF; + message[2] = (max_size >> 8) & 0xFF; + message[3] = max_size & 0xFF; + + /* If given, append the authorization identity. */ + + if(authzid && *authzid) + memcpy(message + 4, authzid, messagelen - 4); /* Setup the "authentication data" security buffer */ input_token.value = message; diff --git a/libs/libcurl/src/vauth/krb5_sspi.c b/libs/libcurl/src/vauth/krb5_sspi.c index 8f7a2b02de..c652fd7365 100644 --- a/libs/libcurl/src/vauth/krb5_sspi.c +++ b/libs/libcurl/src/vauth/krb5_sspi.c @@ -238,13 +238,15 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, * Parameters: * * data [in] - The session handle. - * chlg [in] - The optional challenge message. + * authzid [in] - The authorization identity if some. + * chlg [in] - The optional challenge message. * krb5 [in/out] - The Kerberos 5 data struct being used and modified. * out [out] - The result storage. * * Returns CURLE_OK on success. */ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *authzid, const struct bufref *chlg, struct kerberos5data *krb5, struct bufref *out) @@ -260,15 +262,12 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, SecBuffer wrap_buf[3]; SecBufferDesc input_desc; SecBufferDesc wrap_desc; - unsigned long indata = 0; - unsigned long outdata = 0; + unsigned char *indata; unsigned long qop = 0; unsigned long sec_layer = 0; unsigned long max_size = 0; SecPkgContext_Sizes sizes; - SecPkgCredentials_Names names; SECURITY_STATUS status; - char *user_name; #if defined(CURL_DISABLE_VERBOSE_STRINGS) (void) data; @@ -291,17 +290,6 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, if(status != SEC_E_OK) return CURLE_AUTH_ERROR; - /* Get the fully qualified username back from the context */ - status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, - SECPKG_CRED_ATTR_NAMES, - &names); - - if(status == SEC_E_INSUFFICIENT_MEMORY) - return CURLE_OUT_OF_MEMORY; - - if(status != SEC_E_OK) - return CURLE_AUTH_ERROR; - /* Setup the "input" security buffer */ input_desc.ulVersion = SECBUFFER_VERSION; input_desc.cBuffers = 2; @@ -326,19 +314,22 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, return CURLE_BAD_CONTENT_ENCODING; } - /* Copy the data out and free the challenge as it is not required anymore */ - memcpy(&indata, input_buf[1].pvBuffer, 4); + /* Extract the security layer and the maximum message size */ + indata = input_buf[1].pvBuffer; + sec_layer = indata[0]; + max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3]; + + /* Free the challenge as it is not required anymore */ s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); - /* Extract the security layer */ - sec_layer = indata & 0x000000FF; + /* Process the security layer */ if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { infof(data, "GSSAPI handshake failure (invalid security layer)"); return CURLE_BAD_CONTENT_ENCODING; } + sec_layer &= KERB_WRAP_NO_ENCRYPT; /* We do not support a security layer */ - /* Extract the maximum message size the server can receive */ - max_size = ntohl(indata & 0xFFFFFF00); + /* Process the maximum message size the server can receive */ if(max_size > 0) { /* The server has told us it supports a maximum receive buffer, however, as we don't require one unless we are encrypting data, we tell the server @@ -351,33 +342,28 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, if(!trailer) return CURLE_OUT_OF_MEMORY; - /* Convert the user name to UTF8 when operating with Unicode */ - user_name = curlx_convert_tchar_to_UTF8(names.sUserName); - if(!user_name) { - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - /* Allocate our message */ - messagelen = sizeof(outdata) + strlen(user_name) + 1; + messagelen = 4; + if(authzid) + messagelen += strlen(authzid); message = malloc(messagelen); if(!message) { free(trailer); - curlx_unicodefree(user_name); return CURLE_OUT_OF_MEMORY; } - /* Populate the message with the security layer, client supported receive - message size and authorization identity including the 0x00 based - terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization - identity is not terminated with the zero-valued (%x00) octet." it seems - necessary to include it. */ - outdata = htonl(max_size) | sec_layer; - memcpy(message, &outdata, sizeof(outdata)); - strcpy((char *) message + sizeof(outdata), user_name); - curlx_unicodefree(user_name); + /* Populate the message with the security layer and client supported receive + message size. */ + message[0] = sec_layer & 0xFF; + message[1] = (max_size >> 16) & 0xFF; + message[2] = (max_size >> 8) & 0xFF; + message[3] = max_size & 0xFF; + + /* If given, append the authorization identity. */ + + if(authzid && *authzid) + memcpy(message + 4, authzid, messagelen - 4); /* Allocate the padding */ padding = malloc(sizes.cbBlockSize); diff --git a/libs/libcurl/src/vauth/vauth.h b/libs/libcurl/src/vauth/vauth.h index ec5b0007f5..47a7c0bc81 100644 --- a/libs/libcurl/src/vauth/vauth.h +++ b/libs/libcurl/src/vauth/vauth.h @@ -194,6 +194,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security token message */ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, + const char *authzid, const struct bufref *chlg, struct kerberos5data *krb5, struct bufref *out); diff --git a/libs/libcurl/src/version_win32.c b/libs/libcurl/src/version_win32.c index b8157e9893..2f845413cc 100644 --- a/libs/libcurl/src/version_win32.c +++ b/libs/libcurl/src/version_win32.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016 - 2020, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2016 - 2021, Steve Holme, <steve_holme@hotmail.com>. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,11 +26,28 @@ #include <curl/curl.h> #include "version_win32.h" +#include "warnless.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" +/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW) + and RtlVerifyVersionInfo (RTLOSVERSIONINFOEXW) */ +struct OUR_OSVERSIONINFOEXW { + ULONG dwOSVersionInfoSize; + ULONG dwMajorVersion; + ULONG dwMinorVersion; + ULONG dwBuildNumber; + ULONG dwPlatformId; + WCHAR szCSDVersion[128]; + USHORT wServicePackMajor; + USHORT wServicePackMinor; + USHORT wSuiteMask; + UCHAR wProductType; + UCHAR wReserved; +}; + /* * curlx_verify_windows_version() * @@ -152,12 +169,23 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, } #else ULONGLONG cm = 0; - OSVERSIONINFOEX osver; + struct OUR_OSVERSIONINFOEXW osver; BYTE majorCondition; BYTE minorCondition; BYTE spMajorCondition; BYTE spMinorCondition; + typedef LONG (APIENTRY *RTLVERIFYVERSIONINFO_FN) + (struct OUR_OSVERSIONINFOEXW *, ULONG, ULONGLONG); + static RTLVERIFYVERSIONINFO_FN pRtlVerifyVersionInfo; + static bool onetime = true; /* safe because first call is during init */ + + if(onetime) { + pRtlVerifyVersionInfo = CURLX_FUNCTION_CAST(RTLVERIFYVERSIONINFO_FN, + (GetProcAddress(GetModuleHandleA("ntdll"), "RtlVerifyVersionInfo"))); + onetime = false; + } + switch(condition) { case VERSION_LESS_THAN: majorCondition = VER_LESS; @@ -214,10 +242,23 @@ bool curlx_verify_windows_version(const unsigned int majorVersion, if(platform != PLATFORM_DONT_CARE) cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm)) - matched = TRUE; + /* Later versions of Windows have version functions that may not return the + real version of Windows unless the application is so manifested. We prefer + the real version always, so we use the Rtl variant of the function when + possible. Note though the function signatures have underlying fundamental + types that are the same, the return values are different. */ + if(pRtlVerifyVersionInfo) { + matched = !pRtlVerifyVersionInfo(&osver, + (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm); + } + else { + matched = !!VerifyVersionInfoW((OSVERSIONINFOEXW *)&osver, + (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm); + } #endif return matched; diff --git a/libs/libcurl/src/vquic/ngtcp2.c b/libs/libcurl/src/vquic/ngtcp2.c index fc449c4152..dfe8f96fb1 100644 --- a/libs/libcurl/src/vquic/ngtcp2.c +++ b/libs/libcurl/src/vquic/ngtcp2.c @@ -28,6 +28,9 @@ #include <nghttp3/nghttp3.h> #ifdef USE_OPENSSL #include <openssl/err.h> +#include <ngtcp2/ngtcp2_crypto_openssl.h> +#elif defined(USE_GNUTLS) +#include <ngtcp2/ngtcp2_crypto_gnutls.h> #endif #include "urldata.h" #include "sendf.h" @@ -58,6 +61,7 @@ #endif #define H3_ALPN_H3_29 "\x5h3-29" +#define H3_ALPN_H3 "\x2h3" /* * This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked. @@ -117,42 +121,6 @@ static void quic_printf(void *user_data, const char *fmt, ...) } #endif -#ifdef USE_OPENSSL -static ngtcp2_crypto_level -quic_from_ossl_level(OSSL_ENCRYPTION_LEVEL ossl_level) -{ - switch(ossl_level) { - case ssl_encryption_initial: - return NGTCP2_CRYPTO_LEVEL_INITIAL; - case ssl_encryption_early_data: - return NGTCP2_CRYPTO_LEVEL_EARLY; - case ssl_encryption_handshake: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; - case ssl_encryption_application: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; - default: - assert(0); - } -} -#elif defined(USE_GNUTLS) -static ngtcp2_crypto_level -quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level) -{ - switch(gtls_level) { - case GNUTLS_ENCRYPTION_LEVEL_INITIAL: - return NGTCP2_CRYPTO_LEVEL_INITIAL; - case GNUTLS_ENCRYPTION_LEVEL_EARLY: - return NGTCP2_CRYPTO_LEVEL_EARLY; - case GNUTLS_ENCRYPTION_LEVEL_HANDSHAKE: - return NGTCP2_CRYPTO_LEVEL_HANDSHAKE; - case GNUTLS_ENCRYPTION_LEVEL_APPLICATION: - return NGTCP2_CRYPTO_LEVEL_APPLICATION; - default: - assert(0); - } -} -#endif - static void qlog_callback(void *user_data, uint32_t flags, const void *data, size_t datalen) { @@ -223,27 +191,9 @@ static int write_client_handshake(struct quicsocket *qs, ngtcp2_crypto_level level, const uint8_t *data, size_t len) { - struct quic_handshake *crypto_data; int rv; - crypto_data = &qs->crypto_data[level]; - if(!crypto_data->buf) { - crypto_data->buf = malloc(4096); - if(!crypto_data->buf) - return 0; - crypto_data->alloclen = 4096; - } - - /* TODO Just pretend that handshake does not grow more than 4KiB for - now */ - assert(crypto_data->len + len <= crypto_data->alloclen); - - memcpy(&crypto_data->buf[crypto_data->len], data, len); - crypto_data->len += len; - - rv = ngtcp2_conn_submit_crypto_data( - qs->qconn, level, (uint8_t *)(&crypto_data->buf[crypto_data->len] - len), - len); + rv = ngtcp2_conn_submit_crypto_data(qs->qconn, level, data, len); if(rv) { H3BUGF(fprintf(stderr, "write_client_handshake failed\n")); } @@ -260,7 +210,7 @@ static int quic_set_encryption_secrets(SSL *ssl, size_t secretlen) { struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - int level = quic_from_ossl_level(ossl_level); + int level = ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); if(ngtcp2_crypto_derive_and_install_rx_key( qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) @@ -282,7 +232,8 @@ static int quic_add_handshake_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL ossl_level, const uint8_t *data, size_t len) { struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - ngtcp2_crypto_level level = quic_from_ossl_level(ossl_level); + ngtcp2_crypto_level level = + ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); return write_client_handshake(qs, level, data, len); } @@ -353,9 +304,10 @@ static int quic_init_ssl(struct quicsocket *qs) SSL_set_app_data(qs->ssl, qs); SSL_set_connect_state(qs->ssl); + SSL_set_quic_use_legacy_codepoint(qs->ssl, 0); - alpn = (const uint8_t *)H3_ALPN_H3_29; - alpnlen = sizeof(H3_ALPN_H3_29) - 1; + alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3; + alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1; if(alpn) SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen); @@ -370,7 +322,8 @@ static int secret_func(gnutls_session_t ssl, const void *tx_secret, size_t secretlen) { struct quicsocket *qs = gnutls_session_get_ptr(ssl); - int level = quic_from_gtls_level(gtls_level); + int level = + ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(gtls_level); if(level != NGTCP2_CRYPTO_LEVEL_EARLY && ngtcp2_crypto_derive_and_install_rx_key( @@ -395,7 +348,8 @@ static int read_func(gnutls_session_t ssl, size_t len) { struct quicsocket *qs = gnutls_session_get_ptr(ssl); - ngtcp2_crypto_level level = quic_from_gtls_level(gtls_level); + ngtcp2_crypto_level level = + ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(gtls_level); int rv; if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC) @@ -465,7 +419,7 @@ static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata) static int quic_init_ssl(struct quicsocket *qs) { - gnutls_datum_t alpn = {NULL, 0}; + gnutls_datum_t alpn[2]; /* this will need some attention when HTTPS proxy over QUIC get fixed */ const char * const hostname = qs->conn->host.name; int rc; @@ -487,12 +441,10 @@ static int quic_init_ssl(struct quicsocket *qs) gnutls_alert_set_read_function(qs->ssl, alert_read_func); rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters", - 0xffa5, GNUTLS_EXT_TLS, - tp_recv_func, tp_send_func, - NULL, NULL, NULL, - GNUTLS_EXT_FLAG_TLS | - GNUTLS_EXT_FLAG_CLIENT_HELLO | - GNUTLS_EXT_FLAG_EE); + NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1, GNUTLS_EXT_TLS, + tp_recv_func, tp_send_func, NULL, NULL, NULL, + GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | + GNUTLS_EXT_FLAG_EE); if(rc < 0) { H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n", gnutls_strerror(rc))); @@ -532,10 +484,12 @@ static int quic_init_ssl(struct quicsocket *qs) } /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */ - alpn.data = (unsigned char *)H3_ALPN_H3_29 + 1; - alpn.size = sizeof(H3_ALPN_H3_29) - 2; - if(alpn.data) - gnutls_alpn_set_protocols(qs->ssl, &alpn, 1, 0); + alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1; + alpn[0].size = sizeof(H3_ALPN_H3_29) - 2; + alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1; + alpn[1].size = sizeof(H3_ALPN_H3) - 2; + + gnutls_alpn_set_protocols(qs->ssl, alpn, 2, GNUTLS_ALPN_MANDATORY); /* set SNI */ gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname)); @@ -543,22 +497,6 @@ static int quic_init_ssl(struct quicsocket *qs) } #endif -static int -cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level, - uint64_t offset, - const uint8_t *data, size_t datalen, - void *user_data) -{ - (void)offset; - (void)user_data; - - if(ngtcp2_crypto_read_write_crypto_data(tconn, crypto_level, data, - datalen) != 0) - return NGTCP2_ERR_CRYPTO; - - return 0; -} - static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) { (void)user_data; @@ -623,8 +561,8 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id, return 0; } -static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id, - uint64_t app_error_code, +static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags, + int64_t stream_id, uint64_t app_error_code, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; @@ -633,6 +571,10 @@ static int cb_stream_close(ngtcp2_conn *tconn, int64_t stream_id, (void)stream_user_data; /* stream is closed... */ + if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) { + app_error_code = NGHTTP3_H3_NO_ERROR; + } + rv = nghttp3_conn_close_stream(qs->h3conn, stream_id, app_error_code); if(rv) { @@ -653,7 +595,25 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id, (void)app_error_code; (void)stream_user_data; - rv = nghttp3_conn_reset_stream(qs->h3conn, stream_id); + rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id); + if(rv) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_stream_stop_sending(ngtcp2_conn *tconn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) +{ + struct quicsocket *qs = (struct quicsocket *)user_data; + int rv; + (void)tconn; + (void)app_error_code; + (void)stream_user_data; + + rv = nghttp3_conn_shutdown_stream_read(qs->h3conn, stream_id); if(rv) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -690,6 +650,20 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id, return 0; } +static void cb_rand(uint8_t *dest, size_t destlen, + const ngtcp2_rand_ctx *rand_ctx) +{ + CURLcode result; + (void)rand_ctx; + + result = Curl_rand(NULL, dest, destlen); + if(result) { + /* cb_rand is only used for non-cryptographic context. If Curl_rand + failed, just fill 0 and call it *random*. */ + memset(dest, 0, destlen); + } +} + static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, uint8_t *token, size_t cidlen, void *user_data) @@ -713,14 +687,13 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_client_initial_cb, NULL, /* recv_client_initial */ - cb_recv_crypto_data, + ngtcp2_crypto_recv_crypto_data_cb, cb_handshake_completed, NULL, /* recv_version_negotiation */ ngtcp2_crypto_encrypt_cb, ngtcp2_crypto_decrypt_cb, ngtcp2_crypto_hp_mask_cb, cb_recv_stream_data, - NULL, /* acked_crypto_offset */ cb_acked_stream_data_offset, NULL, /* stream_open */ cb_stream_close, @@ -728,7 +701,7 @@ static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_recv_retry_cb, cb_extend_max_local_streams_bidi, NULL, /* extend_max_local_streams_uni */ - NULL, /* rand */ + cb_rand, cb_get_new_connection_id, NULL, /* remove_connection_id */ ngtcp2_crypto_update_key_cb, /* update_key */ @@ -745,7 +718,9 @@ static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_delete_crypto_cipher_ctx_cb, NULL, /* recv_datagram */ NULL, /* ack_datagram */ - NULL /* lost_datagram */ + NULL, /* lost_datagram */ + ngtcp2_crypto_get_path_challenge_data_cb, + cb_stream_stop_sending }; /* @@ -817,7 +792,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, ngtcp2_addr_init(&path.remote, addr, addrlen); rc = ngtcp2_conn_client_new(&qs->qconn, &qs->dcid, &qs->scid, &path, - NGTCP2_PROTO_VER_MIN, &ng_callbacks, + NGTCP2_PROTO_VER_V1, &ng_callbacks, &qs->settings, &qs->transport_params, NULL, qs); if(rc) return CURLE_QUIC_CONNECT_ERROR; @@ -833,7 +808,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, void Curl_quic_ver(char *p, size_t len) { const ngtcp2_info *ng2 = ngtcp2_version(0); - nghttp3_info *ht3 = nghttp3_version(0); + const nghttp3_info *ht3 = nghttp3_version(0); (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s", ng2->version_str, ht3->version_str); } @@ -859,7 +834,6 @@ static int ng_getsock(struct Curl_easy *data, struct connectdata *conn, static void qs_disconnect(struct quicsocket *qs) { - int i; if(!qs->conn) /* already closed */ return; qs->conn = NULL; @@ -880,8 +854,6 @@ static void qs_disconnect(struct quicsocket *qs) qs->cred = NULL; } #endif - for(i = 0; i < 3; i++) - Curl_safefree(qs->crypto_data[i].buf); nghttp3_conn_del(qs->h3conn); ngtcp2_conn_del(qs->qconn); #ifdef USE_OPENSSL @@ -1143,14 +1115,10 @@ static nghttp3_callbacks ngh3_callbacks = { NULL, /* begin_trailers */ cb_h3_recv_header, NULL, /* end_trailers */ - NULL, /* http_begin_push_promise */ - NULL, /* http_recv_push_promise */ - NULL, /* http_end_push_promise */ - NULL, /* http_cancel_push */ cb_h3_send_stop_sending, - NULL, /* push_stream */ NULL, /* end_stream */ NULL, /* reset_stream */ + NULL /* shutdown */ }; static int init_ngh3_conn(struct quicsocket *qs) @@ -1660,6 +1628,12 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data, return -1; } + /* Reset post upload buffer after resumed. */ + if(stream->upload_mem) { + stream->upload_mem = NULL; + stream->upload_len = 0; + } + *curlcode = CURLE_OK; return sent; } @@ -1758,8 +1732,7 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, int rv; ssize_t sent; ssize_t outlen; - uint8_t out[NGTCP2_MAX_PKTLEN_IPV4]; - size_t pktlen; + uint8_t out[NGTCP2_MAX_UDP_PAYLOAD_SIZE]; ngtcp2_path_storage ps; ngtcp2_tstamp ts = timestamp(); struct sockaddr_storage remote_addr; @@ -1772,19 +1745,6 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, ssize_t ndatalen; uint32_t flags; - switch(qs->local_addr.ss_family) { - case AF_INET: - pktlen = NGTCP2_MAX_PKTLEN_IPV4; - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - pktlen = NGTCP2_MAX_PKTLEN_IPV6; - break; -#endif - default: - assert(0); - } - rv = ngtcp2_conn_handle_expiry(qs->qconn, ts); if(rv) { failf(data, "ngtcp2_conn_handle_expiry returned error: %s", @@ -1811,15 +1771,16 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, flags = NGTCP2_WRITE_STREAM_FLAG_MORE | (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); - outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, pktlen, + outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, + sizeof(out), &ndatalen, flags, stream_id, (const ngtcp2_vec *)vec, veccnt, ts); if(outlen == 0) { break; } if(outlen < 0) { - if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED || - outlen == NGTCP2_ERR_STREAM_SHUT_WR) { + switch(outlen) { + case NGTCP2_ERR_STREAM_DATA_BLOCKED: assert(ndatalen == -1); rv = nghttp3_conn_block_stream(qs->h3conn, stream_id); if(rv) { @@ -1828,8 +1789,17 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, return CURLE_SEND_ERROR; } continue; - } - else if(outlen == NGTCP2_ERR_WRITE_MORE) { + case NGTCP2_ERR_STREAM_SHUT_WR: + assert(ndatalen == -1); + rv = nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id); + if(rv) { + failf(data, + "nghttp3_conn_shutdown_stream_write returned error: %s\n", + nghttp3_strerror(rv)); + return CURLE_SEND_ERROR; + } + continue; + case NGTCP2_ERR_WRITE_MORE: assert(ndatalen >= 0); rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen); if(rv) { @@ -1838,8 +1808,7 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, return CURLE_SEND_ERROR; } continue; - } - else { + default: assert(ndatalen == -1); failf(data, "ngtcp2_conn_writev_stream returned error: %s", ngtcp2_strerror((int)outlen)); diff --git a/libs/libcurl/src/vquic/ngtcp2.h b/libs/libcurl/src/vquic/ngtcp2.h index cbede45146..501453042b 100644 --- a/libs/libcurl/src/vquic/ngtcp2.h +++ b/libs/libcurl/src/vquic/ngtcp2.h @@ -34,13 +34,6 @@ #include <gnutls/gnutls.h> #endif -struct quic_handshake { - char *buf; /* pointer to the buffer */ - size_t alloclen; /* size of allocation */ - size_t len; /* size of content in buffer */ - size_t nread; /* how many bytes have been read */ -}; - struct quicsocket { struct connectdata *conn; /* point back to the connection */ ngtcp2_conn *qconn; @@ -56,7 +49,6 @@ struct quicsocket { gnutls_certificate_credentials_t cred; gnutls_session_t ssl; #endif - struct quic_handshake crypto_data[3]; /* the last TLS alert description generated by the local endpoint */ uint8_t tls_alert; struct sockaddr_storage local_addr; diff --git a/libs/libcurl/src/vssh/libssh.c b/libs/libcurl/src/vssh/libssh.c index c2ca8ef63e..3e317e87c9 100644 --- a/libs/libcurl/src/vssh/libssh.c +++ b/libs/libcurl/src/vssh/libssh.c @@ -74,7 +74,6 @@ #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" -#include "strerror.h" #include "inet_ntop.h" #include "parsedate.h" /* for the week day and month names */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ diff --git a/libs/libcurl/src/vssh/libssh2.c b/libs/libcurl/src/vssh/libssh2.c index 5cbff0769a..7466840ffa 100644 --- a/libs/libcurl/src/vssh/libssh2.c +++ b/libs/libcurl/src/vssh/libssh2.c @@ -73,7 +73,6 @@ #include "strcase.h" #include "vtls/vtls.h" #include "connect.h" -#include "strerror.h" #include "inet_ntop.h" #include "parsedate.h" /* for the week day and month names */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ @@ -82,6 +81,11 @@ #include "select.h" #include "warnless.h" #include "curl_path.h" +#include "strcase.h" + +#include <curl_base64.h> /* for base64 encoding/decoding */ +#include <curl_sha256.h> + /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -616,40 +620,142 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) struct connectdata *conn = data->conn; struct ssh_conn *sshc = &conn->proto.sshc; const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; - char md5buffer[33]; + const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256]; + + infof(data, "SSH MD5 public key: %s", + pubkey_md5 != NULL ? pubkey_md5 : "NULL"); + infof(data, "SSH SHA256 public key: %s", + pubkey_sha256 != NULL ? pubkey_sha256 : "NULL"); - const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session, - LIBSSH2_HOSTKEY_HASH_MD5); + if(pubkey_sha256) { + const char *fingerprint = NULL; + char *fingerprint_b64 = NULL; + size_t fingerprint_b64_len; + size_t pub_pos = 0; + size_t b64_pos = 0; - if(fingerprint) { +#ifdef LIBSSH2_HOSTKEY_HASH_SHA256 /* The fingerprint points to static storage (!), don't free() it. */ - int i; - for(i = 0; i < 16; i++) - msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); - infof(data, "SSH MD5 fingerprint: %s", md5buffer); - } + fingerprint = libssh2_hostkey_hash(sshc->ssh_session, + LIBSSH2_HOSTKEY_HASH_SHA256); +#else + const char *hostkey; + size_t len = 0; + unsigned char hash[32]; + + hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL); + if(hostkey) { + Curl_sha256it(hash, (const unsigned char *) hostkey, len); + fingerprint = (char *) hash; + } +#endif - /* Before we authenticate we check the hostkey's MD5 fingerprint - * against a known fingerprint, if available. - */ - if(pubkey_md5 && strlen(pubkey_md5) == 32) { - if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { - if(fingerprint) - failf(data, - "Denied establishing ssh session: mismatch md5 fingerprint. " - "Remote %s is not equal to %s", md5buffer, pubkey_md5); - else - failf(data, - "Denied establishing ssh session: md5 fingerprint not available"); + if(!fingerprint) { + failf(data, + "Denied establishing ssh session: sha256 fingerprint " + "not available"); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + /* The length of fingerprint is 32 bytes for SHA256. + * See libssh2_hostkey_hash documentation. */ + if(Curl_base64_encode (data, fingerprint, 32, &fingerprint_b64, + &fingerprint_b64_len) != CURLE_OK) { + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + if(!fingerprint_b64) { + failf(data, + "sha256 fingerprint could not be encoded"); + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + + infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64); + + /* Find the position of any = padding characters in the public key */ + while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) { + pub_pos++; + } + + /* Find the position of any = padding characters in the base64 coded + * hostkey fingerprint */ + while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) { + b64_pos++; + } + + /* Before we authenticate we check the hostkey's sha256 fingerprint + * against a known fingerprint, if available. + */ + if((pub_pos != b64_pos) || + Curl_strncasecompare(fingerprint_b64, pubkey_sha256, pub_pos) != 1) { + free(fingerprint_b64); + + failf(data, + "Denied establishing ssh session: mismatch sha256 fingerprint. " + "Remote %s is not equal to %s", fingerprint, pubkey_sha256); state(data, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; } - infof(data, "MD5 checksum match!"); + + free(fingerprint_b64); + + infof(data, "SHA256 checksum match!"); + } + + if(pubkey_md5) { + char md5buffer[33]; + const char *fingerprint = NULL; + + fingerprint = libssh2_hostkey_hash(sshc->ssh_session, + LIBSSH2_HOSTKEY_HASH_MD5); + + if(fingerprint) { + /* The fingerprint points to static storage (!), don't free() it. */ + int i; + for(i = 0; i < 16; i++) { + msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]); + } + + infof(data, "SSH MD5 fingerprint: %s", md5buffer); + } + + /* Before we authenticate we check the hostkey's MD5 fingerprint + * against a known fingerprint, if available. + */ + if(pubkey_md5 && strlen(pubkey_md5) == 32) { + if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { + if(fingerprint) { + failf(data, + "Denied establishing ssh session: mismatch md5 fingerprint. " + "Remote %s is not equal to %s", md5buffer, pubkey_md5); + } + else { + failf(data, + "Denied establishing ssh session: md5 fingerprint " + "not available"); + } + state(data, SSH_SESSION_FREE); + sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; + return sshc->actualcode; + } + infof(data, "MD5 checksum match!"); + } + } + + if(!pubkey_md5 && !pubkey_sha256) { + return ssh_knownhost(data); + } + else { /* as we already matched, we skip the check for known hosts */ return CURLE_OK; } - return ssh_knownhost(data); } /* @@ -3611,7 +3717,7 @@ void Curl_ssh_cleanup(void) void Curl_ssh_version(char *buffer, size_t buflen) { - (void)msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION); + (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION); } /* The SSH session is associated with the *CONNECTION* but the callback user diff --git a/libs/libcurl/src/vssh/wolfssh.c b/libs/libcurl/src/vssh/wolfssh.c index 4b1e2ec5e3..5b4cde91b0 100644 --- a/libs/libcurl/src/vssh/wolfssh.c +++ b/libs/libcurl/src/vssh/wolfssh.c @@ -449,7 +449,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) switch(sshc->state) { case SSH_INIT: state(data, SSH_S_STARTUP); - /* FALLTHROUGH */ + break; + case SSH_S_STARTUP: rc = wolfSSH_connect(sshc->ssh_session); if(rc != WS_SUCCESS) @@ -838,7 +839,8 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block) break; } state(data, SSH_SFTP_READDIR); - /* FALLTHROUGH */ + break; + case SSH_SFTP_READDIR: name = wolfSSH_SFTP_LS(sshc->ssh_session, sftp_scp->path); if(!name) diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c index cbbb3b5deb..9b772d064d 100644 --- a/libs/libcurl/src/vtls/bearssl.c +++ b/libs/libcurl/src/vtls/bearssl.c @@ -68,6 +68,14 @@ struct cafile_parser { size_t dn_len; }; +#define CAFILE_SOURCE_PATH 1 +#define CAFILE_SOURCE_BLOB 2 +struct cafile_source { + const int type; + const char * const data; + const size_t len; +}; + static void append_dn(void *ctx, const void *buf, size_t len) { struct cafile_parser *ca = ctx; @@ -90,7 +98,8 @@ static void x509_push(void *ctx, const void *buf, size_t len) br_x509_decoder_push(&ca->xc, buf, len); } -static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, +static CURLcode load_cafile(struct cafile_source *source, + br_x509_trust_anchor **anchors, size_t *anchors_len) { struct cafile_parser ca; @@ -100,13 +109,22 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, br_x509_trust_anchor *new_anchors; size_t new_anchors_len; br_x509_pkey *pkey; - FILE *fp; - unsigned char buf[BUFSIZ], *p; + FILE *fp = 0; + unsigned char buf[BUFSIZ]; + const unsigned char *p; const char *name; size_t n, i, pushed; - fp = fopen(path, "rb"); - if(!fp) + 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; @@ -115,11 +133,17 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, ca.anchors_len = 0; br_pem_decoder_init(&pc); br_pem_decoder_setdest(&pc, x509_push, &ca); - for(;;) { - n = fread(buf, 1, sizeof(buf), fp); - if(n == 0) - break; - p = buf; + 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 = (unsigned char *) source->data; + } while(n) { pushed = br_pem_decoder_push(&pc, p, n); if(ca.err) @@ -211,12 +235,13 @@ static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors, goto fail; } } - } - if(ferror(fp)) + } while(source->type != CAFILE_SOURCE_BLOB); + if(fp && ferror(fp)) ca.err = CURLE_READ_ERROR; fail: - fclose(fp); + if(fp) + fclose(fp); if(ca.err == CURLE_OK) { *anchors = ca.anchors; *anchors_len = ca.anchors_len; @@ -299,7 +324,10 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; - const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob); + const char * const ssl_cafile = + /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */ + (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile)); const char *hostname = SSL_HOST_NAME(); const bool verifypeer = SSL_CONN_CONFIG(verifypeer); const bool verifyhost = SSL_CONN_CONFIG(verifyhost); @@ -340,8 +368,30 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } + if(ca_info_blob) { + struct cafile_source source = { + CAFILE_SOURCE_BLOB, + ca_info_blob->data, + ca_info_blob->len, + }; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); + if(ret != CURLE_OK) { + if(verifypeer) { + failf(data, "error importing CA certificate blob"); + return ret; + } + /* Only warn if no certificate verification is required. */ + infof(data, "error importing CA certificate blob, continuing anyway"); + } + } + if(ssl_cafile) { - ret = load_cafile(ssl_cafile, &backend->anchors, &backend->anchors_len); + struct cafile_source source = { + CAFILE_SOURCE_PATH, + ssl_cafile, + 0, + }; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { failf(data, "error setting certificate verify locations." @@ -558,6 +608,7 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; void *oldsession; br_ssl_session_parameters *session; @@ -573,10 +624,11 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, Curl_ssl_delsessionid(data, oldsession); ret = Curl_ssl_addsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, - session, 0, sockindex); + session, 0, sockindex, &added); Curl_ssl_sessionid_unlock(data); - if(ret) { + if(!added) free(session); + if(ret) { return CURLE_OUT_OF_MEMORY; } } @@ -841,7 +893,7 @@ static CURLcode bearssl_sha256sum(const unsigned char *input, const struct Curl_ssl Curl_ssl_bearssl = { { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */ - 0, + SSLSUPP_CAINFO_BLOB, sizeof(struct ssl_backend_data), Curl_none_init, /* init */ diff --git a/libs/libcurl/src/vtls/gskit.c b/libs/libcurl/src/vtls/gskit.c index af8fc92b27..e451f6aebe 100644 --- a/libs/libcurl/src/vtls/gskit.c +++ b/libs/libcurl/src/vtls/gskit.c @@ -180,6 +180,7 @@ static bool is_separator(char c) static CURLcode gskit_status(struct Curl_easy *data, int rc, const char *procname, CURLcode defcode) { + char buffer[STRERROR_LEN]; /* Process GSKit status and map it to a CURLcode. */ switch(rc) { case GSK_OK: @@ -208,7 +209,8 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc, case ENOMEM: return CURLE_OUT_OF_MEMORY; default: - failf(data, "%s I/O error: %s", procname, strerror(errno)); + failf(data, "%s I/O error: %s", procname, + Curl_strerror(errno, buffer, sizeof(buffer))); break; } break; @@ -223,13 +225,15 @@ static CURLcode gskit_status(struct Curl_easy *data, int rc, static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_enum(h, id, value); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); + failf(data, "gsk_attribute_set_enum() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); break; case GSK_ATTRIBUTE_INVALID_ID: if(unsupported_ok) @@ -245,13 +249,15 @@ static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, GSK_BUF_ID id, const char *buffer, bool unsupported_ok) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_buffer(h, id, buffer, 0); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); + failf(data, "gsk_attribute_set_buffer() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); break; case GSK_ATTRIBUTE_INVALID_ID: if(unsupported_ok) @@ -267,6 +273,7 @@ static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, static CURLcode set_numeric(struct Curl_easy *data, gsk_handle h, GSK_NUM_ID id, int value) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_numeric_value(h, id, value); switch(rc) { @@ -274,7 +281,7 @@ static CURLcode set_numeric(struct Curl_easy *data, return CURLE_OK; case GSK_ERROR_IO: failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", - strerror(errno)); + Curl_strerror(errno, buffer, sizeof(buffer))); break; default: failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); @@ -287,13 +294,15 @@ static CURLcode set_numeric(struct Curl_easy *data, static CURLcode set_callback(struct Curl_easy *data, gsk_handle h, GSK_CALLBACK_ID id, void *info) { + char buffer[STRERROR_LEN]; int rc = gsk_attribute_set_callback(h, id, info); switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: - failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); + failf(data, "gsk_attribute_set_callback() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); break; default: failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); @@ -966,7 +975,9 @@ static CURLcode gskit_connect_step2(struct Curl_easy *data, continue; /* Retry. */ } if(errno != ETIME) { - failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); + char buffer[STRERROR_LEN]; + failf(data, "QsoWaitForIOCompletion() I/O error: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); cancel_async_handshake(conn, sockindex); close_async_handshake(connssl); return CURLE_SSL_CONNECT_ERROR; @@ -1229,7 +1240,8 @@ static int gskit_shutdown(struct Curl_easy *data, nread = read(conn->sock[sockindex], buf, sizeof(buf)); if(nread < 0) { - failf(data, "read: %s", strerror(errno)); + char buffer[STRERROR_LEN]; + failf(data, "read: %s", Curl_strerror(errno, buffer, sizeof(buffer))); rc = -1; } diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c index 1b145d8ebb..2053fd439d 100644 --- a/libs/libcurl/src/vtls/gtls.c +++ b/libs/libcurl/src/vtls/gtls.c @@ -404,6 +404,7 @@ gtls_connect_step1(struct Curl_easy *data, const char * const hostname = SSL_HOST_NAME(); long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult); const char *tls13support; + CURLcode result; if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -557,31 +558,25 @@ gtls_connect_step1(struct Curl_easy *data, /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ - switch(SSL_CONN_CONFIG(version)) { - case CURL_SSLVERSION_TLSv1_3: - if(!tls13support) { - failf(data, "This GnuTLS installation does not support TLS 1.3"); - return CURLE_SSL_CONNECT_ERROR; - } - /* FALLTHROUGH */ - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - case CURL_SSLVERSION_TLSv1_1: - case CURL_SSLVERSION_TLSv1_2: { - CURLcode result = set_ssl_version_min_max(data, &prioritylist, - tls13support); - if(result) - return result; - break; - } - case CURL_SSLVERSION_SSLv2: - case CURL_SSLVERSION_SSLv3: - default: - failf(data, "GnuTLS does not support SSLv2 or SSLv3"); + + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2 || + SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) { + failf(data, "GnuTLS does not support SSLv2 or SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_TLSv1_3) { + if(!tls13support) { + failf(data, "This GnuTLS installation does not support TLS 1.3"); return CURLE_SSL_CONNECT_ERROR; + } } + /* At this point we know we have a supported TLS version, so set it */ + result = set_ssl_version_min_max(data, &prioritylist, tls13support); + if(result) + return result; + #ifdef HAVE_GNUTLS_SRP /* Only add SRP to the cipher list if SRP is requested. Otherwise * GnuTLS will disable TLS 1.3 support. */ @@ -1287,6 +1282,7 @@ gtls_connect_step3(struct Curl_easy *data, if(connect_sessionid) { bool incache; + bool added = FALSE; void *ssl_sessionid; /* extract session ID to the allocated buffer */ @@ -1306,10 +1302,11 @@ gtls_connect_step3(struct Curl_easy *data, result = Curl_ssl_addsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, connect_sessionid, connect_idsize, - sockindex); + sockindex, &added); Curl_ssl_sessionid_unlock(data); - if(result) { + if(!added) free(connect_sessionid); + if(result) { result = CURLE_OUT_OF_MEMORY; } } diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c index e986bea82d..08c79e1624 100644 --- a/libs/libcurl/src/vtls/mbedtls.c +++ b/libs/libcurl/src/vtls/mbedtls.c @@ -41,7 +41,9 @@ #include <mbedtls/net.h> #endif #include <mbedtls/ssl.h> +#if MBEDTLS_VERSION_NUMBER < 0x03000000 #include <mbedtls/certs.h> +#endif #include <mbedtls/x509.h> #include <mbedtls/error.h> @@ -183,6 +185,17 @@ static Curl_send mbed_send; static CURLcode mbedtls_version_from_curl(int *mbedver, long version) { +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + switch(version) { + case CURL_SSLVERSION_TLSv1_0: + case CURL_SSLVERSION_TLSv1_1: + case CURL_SSLVERSION_TLSv1_2: + *mbedver = MBEDTLS_SSL_MINOR_VERSION_3; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1_3: + break; + } +#else switch(version) { case CURL_SSLVERSION_TLSv1_0: *mbedver = MBEDTLS_SSL_MINOR_VERSION_1; @@ -196,6 +209,8 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version) case CURL_SSLVERSION_TLSv1_3: break; } +#endif + return CURLE_SSL_CONNECT_ERROR; } @@ -205,8 +220,13 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn, { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3; + int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3; +#else int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1; int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1; +#endif long ssl_version = SSL_CONN_CONFIG(version); long ssl_version_max = SSL_CONN_CONFIG(version_max); CURLcode result = CURLE_OK; @@ -257,7 +277,9 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob); const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); const char * const hostname = SSL_HOST_NAME(); +#ifndef CURL_DISABLE_VERBOSE_STRINGS const long int port = SSL_HOST_PORT(); +#endif int ret = -1; char errorbuf[128]; @@ -354,8 +376,15 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) { if(SSL_SET_OPTION(key)) { +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), + SSL_SET_OPTION(key_passwd), + mbedtls_ctr_drbg_random, + &backend->ctr_drbg); +#else ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key), SSL_SET_OPTION(key_passwd)); +#endif if(ret) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -369,9 +398,17 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, const unsigned char *key_data = (const unsigned char *)ssl_key_blob->data; const char *passwd = SSL_SET_OPTION(key_passwd); +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, + (const unsigned char *)passwd, + passwd ? strlen(passwd) : 0, + mbedtls_ctr_drbg_random, + &backend->ctr_drbg); +#else ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, (const unsigned char *)passwd, passwd ? strlen(passwd) : 0); +#endif if(ret) { mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -426,10 +463,12 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn, switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: +#if MBEDTLS_VERSION_NUMBER < 0x03000000 mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1); infof(data, "mbedTLS: Set min SSL version to TLS 1.0"); break; +#endif case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: @@ -629,10 +668,15 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(pinnedpubkey) { int size; CURLcode result; - mbedtls_x509_crt *p; - unsigned char pubkey[PUB_DER_MAX_BYTES]; + mbedtls_x509_crt *p = NULL; + unsigned char *pubkey = NULL; +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || + !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { +#else if(!peercert || !peercert->raw.p || !peercert->raw.len) { +#endif failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } @@ -642,39 +686,54 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(!p) return CURLE_OUT_OF_MEMORY; + pubkey = malloc(PUB_DER_MAX_BYTES); + + if(!pubkey) { + result = CURLE_OUT_OF_MEMORY; + goto pinnedpubkey_error; + } + mbedtls_x509_crt_init(p); /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/ARMmbed/mbedtls/issues/396 */ +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(mbedtls_x509_crt_parse_der(p, + peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), + peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { +#else if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { +#endif failf(data, "Failed copying peer certificate"); - mbedtls_x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + goto pinnedpubkey_error; } +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, + PUB_DER_MAX_BYTES); +#else size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); +#endif if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); - mbedtls_x509_crt_free(p); - free(p); - return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; + goto pinnedpubkey_error; } /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, pinnedpubkey, &pubkey[PUB_DER_MAX_BYTES - size], size); + pinnedpubkey_error: + mbedtls_x509_crt_free(p); + free(p); + free(pubkey); if(result) { - mbedtls_x509_crt_free(p); - free(p); return result; } - - mbedtls_x509_crt_free(p); - free(p); } #ifdef HAS_ALPN @@ -725,6 +784,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn, mbedtls_ssl_session *our_ssl_sessionid; void *old_ssl_sessionid = NULL; bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; + bool added = FALSE; our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); if(!our_ssl_sessionid) @@ -748,11 +808,13 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn, Curl_ssl_delsessionid(data, old_ssl_sessionid); retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, - 0, sockindex); + 0, sockindex, &added); Curl_ssl_sessionid_unlock(data); - if(retcode) { + if(!added) { mbedtls_ssl_session_free(our_ssl_sessionid); free(our_ssl_sessionid); + } + if(retcode) { failf(data, "failed to store ssl session"); return retcode; } @@ -1064,12 +1126,17 @@ static CURLcode mbedtls_sha256sum(const unsigned char *input, unsigned char *sha256sum, size_t sha256len UNUSED_PARAM) { + /* TODO: explain this for different mbedtls 2.x vs 3 version */ (void)sha256len; #if MBEDTLS_VERSION_NUMBER < 0x02070000 mbedtls_sha256(input, inputlen, sha256sum, 0); #else /* returns 0 on success, otherwise failure */ +#if MBEDTLS_VERSION_NUMBER >= 0x03000000 + if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0) +#else if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) +#endif return CURLE_BAD_FUNCTION_ARGUMENT; #endif return CURLE_OK; diff --git a/libs/libcurl/src/vtls/mbedtls_threadlock.c b/libs/libcurl/src/vtls/mbedtls_threadlock.c index 473f5171e2..751755c239 100644 --- a/libs/libcurl/src/vtls/mbedtls_threadlock.c +++ b/libs/libcurl/src/vtls/mbedtls_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -55,10 +55,8 @@ int Curl_mbedtlsthreadlock_thread_setup(void) return 0; /* error, no number of threads defined */ for(i = 0; i < NUMT; i++) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_init(&mutex_buf[i], NULL); - if(ret) + if(pthread_mutex_init(&mutex_buf[i], NULL)) return 0; /* pthread_mutex_init failed */ #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) mutex_buf[i] = CreateMutex(0, FALSE, 0); @@ -78,14 +76,11 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void) return 0; /* error, no threads locks defined */ for(i = 0; i < NUMT; i++) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_destroy(&mutex_buf[i]); - if(ret) + if(pthread_mutex_destroy(&mutex_buf[i])) return 0; /* pthread_mutex_destroy failed */ #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) - ret = CloseHandle(mutex_buf[i]); - if(!ret) + if(!CloseHandle(mutex_buf[i])) return 0; /* CloseHandle failed */ #endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */ } @@ -98,17 +93,14 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void) int Curl_mbedtlsthreadlock_lock_function(int n) { if(n < NUMT) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_lock(&mutex_buf[n]); - if(ret) { + if(pthread_mutex_lock(&mutex_buf[n])) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) - ret = (WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED?1:0); - if(ret) { + if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_lock_function failed\n")); return 0; /* pthread_mutex_lock failed */ @@ -121,17 +113,14 @@ int Curl_mbedtlsthreadlock_lock_function(int n) int Curl_mbedtlsthreadlock_unlock_function(int n) { if(n < NUMT) { - int ret; #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H) - ret = pthread_mutex_unlock(&mutex_buf[n]); - if(ret) { + if(pthread_mutex_unlock(&mutex_buf[n])) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_unlock failed */ } #elif defined(USE_THREADS_WIN32) && defined(HAVE_PROCESS_H) - ret = ReleaseMutex(mutex_buf[n]); - if(!ret) { + if(!ReleaseMutex(mutex_buf[n])) { DEBUGF(fprintf(stderr, "Error: mbedtlsthreadlock_unlock_function failed\n")); return 0; /* pthread_mutex_lock failed */ diff --git a/libs/libcurl/src/vtls/mesalink.c b/libs/libcurl/src/vtls/mesalink.c index 3db9184f79..0a1dea3ac0 100644 --- a/libs/libcurl/src/vtls/mesalink.c +++ b/libs/libcurl/src/vtls/mesalink.c @@ -365,7 +365,7 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex) if(!incache) { result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0, - sockindex); + sockindex, NULL); if(result) { Curl_ssl_sessionid_unlock(data); failf(data, "failed to store ssl session"); diff --git a/libs/libcurl/src/vtls/nss.c b/libs/libcurl/src/vtls/nss.c index cf657895f6..1897b9ab1d 100644 --- a/libs/libcurl/src/vtls/nss.c +++ b/libs/libcurl/src/vtls/nss.c @@ -955,7 +955,7 @@ static void display_cert_info(struct Curl_easy *data, subject = CERT_NameToAscii(&cert->subject); issuer = CERT_NameToAscii(&cert->issuer); common_name = CERT_GetCommonName(&cert->subject); - infof(data, "subject: %s\n", subject); + infof(data, "subject: %s", subject); CERT_GetCertTimes(cert, ¬Before, ¬After); PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime); @@ -2250,10 +2250,11 @@ static CURLcode nss_connect_common(struct Curl_easy *data, case CURLE_OK: break; case CURLE_AGAIN: + /* CURLE_AGAIN in non-blocking mode is not an error */ if(!blocking) - /* CURLE_AGAIN in non-blocking mode is not an error */ return CURLE_OK; - /* FALLTHROUGH */ + else + return result; default: return result; } diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c index 8af23b783a..a1baef9c3f 100644 --- a/libs/libcurl/src/vtls/openssl.c +++ b/libs/libcurl/src/vtls/openssl.c @@ -194,7 +194,7 @@ !defined(OPENSSL_IS_BORINGSSL)) #define HAVE_SSL_CTX_SET_CIPHERSUITES #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH -/* SET_EC_CURVES available under the same preconditions: see +/* SET_EC_CURVES is available under the same preconditions: see * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html */ #define HAVE_SSL_CTX_SET_EC_CURVES @@ -209,8 +209,8 @@ #endif #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) -/* up2date versions of OpenSSL maintain the default reasonably secure without - * breaking compatibility, so it is better not to override the default by curl +/* up2date versions of OpenSSL maintain reasonably secure defaults without + * breaking compatibility, so it is better not to override the defaults in curl */ #define DEFAULT_CIPHER_SELECTION NULL #else @@ -227,6 +227,10 @@ #endif #endif +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#define HAVE_RANDOM_INIT_BY_DEFAULT 1 +#endif + struct ssl_backend_data { struct Curl_easy *logger; /* transfer handle to pass trace logs to, only using sockindex 0 */ @@ -435,18 +439,21 @@ static bool rand_enough(void) static CURLcode ossl_seed(struct Curl_easy *data) { - char fname[256]; - /* This might get called before it has been added to a multi handle */ if(data->multi && data->multi->ssl_seeded) return CURLE_OK; if(rand_enough()) { - /* OpenSSL 1.1.0+ will return here */ + /* OpenSSL 1.1.0+ should return here */ if(data->multi) data->multi->ssl_seeded = TRUE; return CURLE_OK; } +#ifdef HAVE_RANDOM_INIT_BY_DEFAULT + /* with OpenSSL 1.1.0+, a failed RAND_status is a showstopper */ + failf(data, "Insufficient randomness"); + return CURLE_SSL_CONNECT_ERROR; +#else #ifndef RANDOM_FILE /* if RANDOM_FILE isn't defined, we only perform this if an option tells @@ -507,19 +514,23 @@ static CURLcode ossl_seed(struct Curl_easy *data) RAND_add(randb, (int)len, (double)len/2); } while(!rand_enough()); - /* generates a default path for the random seed file */ - fname[0] = 0; /* blank it first */ - RAND_file_name(fname, sizeof(fname)); - if(fname[0]) { - /* we got a file name to try */ - RAND_load_file(fname, RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; + { + /* generates a default path for the random seed file */ + char fname[256]; + fname[0] = 0; /* blank it first */ + RAND_file_name(fname, sizeof(fname)); + if(fname[0]) { + /* we got a file name to try */ + RAND_load_file(fname, RAND_LOAD_LENGTH); + if(rand_enough()) + return CURLE_OK; + } } infof(data, "libcurl is now using a weak random seed!"); return (rand_enough() ? CURLE_OK : - CURLE_SSL_CONNECT_ERROR /* confusing error code */); + CURLE_SSL_CONNECT_ERROR /* confusing error code */); +#endif } #ifndef SSL_FILETYPE_ENGINE @@ -1192,7 +1203,7 @@ static int ossl_init(void) CONF_MFLAGS_IGNORE_MISSING_FILE); #endif - /* Lets get nice error messages */ + /* Let's get nice error messages */ SSL_load_error_strings(); /* Init the global ciphers and digests */ @@ -1769,7 +1780,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn, /* we have the name entry and we will now convert this to a string that we can use for comparison. Doing this we support BMPstring, - UTF8 etc. */ + UTF8, etc. */ if(i >= 0) { ASN1_STRING *tmp = @@ -2060,6 +2071,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg) case SSL3_MT_ENCRYPTED_EXTENSIONS: return "Encrypted Extensions"; #endif +#ifdef SSL3_MT_SUPPLEMENTAL_DATA + case SSL3_MT_SUPPLEMENTAL_DATA: + return "Supplemental data"; +#endif #ifdef SSL3_MT_END_OF_EARLY_DATA case SSL3_MT_END_OF_EARLY_DATA: return "End of early data"; @@ -2158,7 +2173,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, /* Log progress for interesting records only (like Handshake or Alert), skip * all raw record headers (content_type == SSL3_RT_HEADER or ssl_ver == 0). - * For TLS 1.3, skip notification of the decrypted inner Content Type. + * For TLS 1.3, skip notification of the decrypted inner Content-Type. */ if(ssl_ver #ifdef SSL3_RT_INNER_CONTENT_TYPE @@ -2299,7 +2314,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) long curl_ssl_version_min = SSL_CONN_CONFIG(version); long curl_ssl_version_max; - /* convert cURL min SSL version option to OpenSSL constant */ + /* convert curl min SSL version option to OpenSSL constant */ #if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER) uint16_t ossl_ssl_version_min = 0; uint16_t ossl_ssl_version_max = 0; @@ -2329,7 +2344,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) We don't want to pass 0 to SSL_CTX_set_min_proto_version as it would enable all versions down to the lowest supported by the library. - So we skip this, and stay with the OS default + So we skip this, and stay with the library default */ if(curl_ssl_version_min != CURL_SSLVERSION_DEFAULT) { if(!SSL_CTX_set_min_proto_version(ctx, ossl_ssl_version_min)) { @@ -2340,7 +2355,7 @@ set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) /* ... then, TLS max version */ curl_ssl_version_max = SSL_CONN_CONFIG(version_max); - /* convert cURL max SSL version option to OpenSSL constant */ + /* convert curl max SSL version option to OpenSSL constant */ switch(curl_ssl_version_max) { case CURL_SSLVERSION_MAX_TLSv1_0: ossl_ssl_version_max = TLS1_VERSION; @@ -2489,6 +2504,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; void *old_ssl_sessionid = NULL; Curl_ssl_sessionid_lock(data); @@ -2507,9 +2523,11 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) if(!incache) { if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid, - 0 /* unknown size */, sockindex)) { - /* the session has been put into the session cache */ - res = 1; + 0 /* unknown size */, sockindex, &added)) { + if(added) { + /* the session has been put into the session cache */ + res = 1; + } } else failf(data, "failed to store ssl session"); @@ -2523,7 +2541,7 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid) static CURLcode load_cacert_from_memory(SSL_CTX *ctx, const struct curl_blob *ca_info_blob) { - /* these need freed at the end */ + /* these need to be freed at the end */ BIO *cbio = NULL; STACK_OF(X509_INFO) *inf = NULL; @@ -2658,8 +2676,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } - if(backend->ctx) - SSL_CTX_free(backend->ctx); + DEBUGASSERT(!backend->ctx); backend->ctx = SSL_CTX_new(req_method); if(!backend->ctx) { @@ -2681,23 +2698,23 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } #endif - /* OpenSSL contains code to work-around lots of bugs and flaws in various + /* OpenSSL contains code to work around lots of bugs and flaws in various SSL-implementations. SSL_CTX_set_options() is used to enabled those work-arounds. The man page for this option states that SSL_OP_ALL enables all the work-arounds and that "It is usually safe to use SSL_OP_ALL to enable the bug workaround options if compatibility with somewhat broken implementations is desired." - The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to + The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to disable "rfc4507bis session ticket support". rfc4507bis was later turned into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077 The enabled extension concerns the session management. I wonder how often - libcurl stops a connection and then resumes a TLS session. also, sending - the session data is some overhead. .I suggest that you just use your + libcurl stops a connection and then resumes a TLS session. Also, sending + the session data is some overhead. I suggest that you just use your proposed patch (which explicitly disables TICKET). - If someone writes an application with libcurl and openssl who wants to + If someone writes an application with libcurl and OpenSSL who wants to enable the feature, one can do this in the SSL callback. SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper @@ -2733,7 +2750,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - /* unless the user explicitly ask to allow the protocol vulnerability we + /* unless the user explicitly asks to allow the protocol vulnerability we use the work-around */ if(!SSL_SET_OPTION(enable_beast)) ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; @@ -2933,7 +2950,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, NULL, cert_name, sizeof(cert_name))) { strcpy(cert_name, "Unknown"); } - infof(data, "SSL: Checking cert %s\"\n", cert_name); + infof(data, "SSL: Checking cert \"%s\"", cert_name); #endif encoded_cert = (const unsigned char *)pContext->pbCertEncoded; @@ -3030,9 +3047,9 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return result; } if(imported_native_ca) - infof(data, "successfully imported windows ca store"); + infof(data, "successfully imported Windows CA store"); else - infof(data, "error importing windows ca store, continuing anyway"); + infof(data, "error importing Windows CA store, continuing anyway"); } #endif @@ -3044,77 +3061,53 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, failf(data, "error importing CA certificate blob"); return result; } - /* Only warning if no certificate verification is required. */ + /* Only warn if no certificate verification is required. */ infof(data, "error importing CA certificate blob, continuing anyway"); } } + if(verifypeer && !imported_native_ca && (ssl_cafile || ssl_capath)) { #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ - { - if(ssl_cafile) { - if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { - if(verifypeer && !imported_native_ca) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate file: %s", ssl_cafile); - return CURLE_SSL_CACERT_BADFILE; - } - /* Continue with a warning if no certificate verif is required. */ - infof(data, "error setting certificate file, continuing anyway"); - } - infof(data, " CAfile: %s", ssl_cafile); + if(ssl_cafile && + !SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate file: %s", ssl_cafile); + return CURLE_SSL_CACERT_BADFILE; } - if(ssl_capath) { - if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { - if(verifypeer && !imported_native_ca) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate path: %s", ssl_capath); - return CURLE_SSL_CACERT_BADFILE; - } - /* Continue with a warning if no certificate verif is required. */ - infof(data, "error setting certificate path, continuing anyway"); - } - infof(data, " CApath: %s", ssl_capath); + if(ssl_capath && + !SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate path: %s", ssl_capath); + return CURLE_SSL_CACERT_BADFILE; } - } #else - if(ssl_cafile || ssl_capath) { - /* tell SSL where to find CA certificates that are used to verify - the servers certificate. */ + /* tell OpenSSL where to find CA certificates that are used to verify the + server's certificate. */ if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) { - if(verifypeer && !imported_native_ca) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return CURLE_SSL_CACERT_BADFILE; - } - /* Just continue with a warning if no strict certificate verification - is required. */ - infof(data, "error setting certificate verify locations," - " continuing anyway:"); - } - else { - /* Everything is fine. */ - infof(data, "successfully set certificate verify locations:"); + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return CURLE_SSL_CACERT_BADFILE; } +#endif infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); } -#endif #ifdef CURL_CA_FALLBACK if(verifypeer && !ca_info_blob && !ssl_cafile && !ssl_capath && !imported_native_ca) { /* verifying the peer without any CA certificates won't - work so use openssl's built in default as fallback */ + work so use openssl's built-in default as fallback */ SSL_CTX_set_default_verify_paths(backend->ctx); } #endif if(ssl_crlfile) { - /* tell SSL where to find CRL file that is used to check certificate + /* tell OpenSSL where to find CRL file that is used to check certificate * revocation */ lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(backend->ctx), X509_LOOKUP_file()); @@ -3124,7 +3117,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, return CURLE_SSL_CRL_BADFILE; } /* Everything is fine. */ - infof(data, "successfully load CRL file:"); + infof(data, "successfully loaded CRL file:"); X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); @@ -3150,7 +3143,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, only, instead of needing the whole chain. Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we - cannot do partial chains with CRL check. + cannot do partial chains with a CRL check. */ X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx), X509_V_FLAG_PARTIAL_CHAIN); @@ -3158,7 +3151,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif } - /* SSL always tries to verify the peer, this only says whether it should + /* OpenSSL 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. */ @@ -3173,7 +3166,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #endif /* Enable the session cache because it's a prerequisite for the "new session" - * callback. Use the "external storage" mode to avoid that OpenSSL creates + * callback. Use the "external storage" mode to prevent OpenSSL from creating * an internal session cache. */ SSL_CTX_set_session_cache_mode(backend->ctx, @@ -3192,7 +3185,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, } } - /* Lets make an SSL structure */ + /* Let's make an SSL structure */ if(backend->handle) SSL_free(backend->handle); backend->handle = SSL_new(backend->ctx); @@ -3332,7 +3325,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, /* the connection failed, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_2; - /* Get the earliest error code from the thread's error queue and removes + /* Get the earliest error code from the thread's error queue and remove the entry. */ errdetail = ERR_get_error(); @@ -3361,7 +3354,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, !defined(LIBRESSL_VERSION_NUMBER) && \ !defined(OPENSSL_IS_BORINGSSL)) /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on - OpenSSL version above v1.1.1, not Libre SSL nor BoringSSL */ + OpenSSL version above v1.1.1, not LibreSSL nor BoringSSL */ else if((lib == ERR_LIB_SSL) && (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) { /* If client certificate is required, communicate the @@ -3378,7 +3371,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, /* detail is already set to the SSL error above */ /* If we e.g. use SSLv2 request-method and the server doesn't like us - * (RST connection etc.), OpenSSL gives no explanation whatsoever and + * (RST connection, etc.), OpenSSL gives no explanation whatsoever and * the SO_ERROR is also lost. */ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { @@ -3401,7 +3394,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, } } else { - /* we have been connected fine, we're not waiting for anything else. */ + /* we connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ @@ -3820,7 +3813,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, } /* - * Get the server cert, verify it and show it etc, only call failf() if the + * Get the server cert, verify it and show it, etc., only call failf() if the * 'strict' argument is TRUE as otherwise all this is for informational * purposes only! * @@ -4021,7 +4014,7 @@ static CURLcode ossl_connect_step3(struct Curl_easy *data, /* * We check certificates to authenticate the server; otherwise we risk * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to - * verify the peer ignore faults and failures from the server cert + * verify the peer, ignore faults and failures from the server cert * operations. */ @@ -4059,7 +4052,7 @@ static CURLcode ossl_connect_common(struct Curl_easy *data, const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); if(timeout_ms < 0) { - /* no need to continue if time already is up */ + /* no need to continue if time is already up */ failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c index 94a1ca8861..2ac97ce28e 100644 --- a/libs/libcurl/src/vtls/rustls.c +++ b/libs/libcurl/src/vtls/rustls.c @@ -34,7 +34,7 @@ #include "sendf.h" #include "vtls.h" #include "select.h" - +#include "strerror.h" #include "multiif.h" struct ssl_backend_data @@ -132,7 +132,9 @@ cr_recv(struct Curl_easy *data, int sockindex, infof(data, "sread: EAGAIN or EWOULDBLOCK"); } else if(io_error) { - failf(data, "reading from socket: %s", strerror(io_error)); + char buffer[STRERROR_LEN]; + failf(data, "reading from socket: %s", + Curl_strerror(io_error, buffer, sizeof(buffer))); *err = CURLE_READ_ERROR; return -1; } @@ -244,7 +246,9 @@ cr_send(struct Curl_easy *data, int sockindex, return -1; } else if(io_error) { - failf(data, "writing to socket: %s", strerror(io_error)); + char buffer[STRERROR_LEN]; + failf(data, "writing to socket: %s", + Curl_strerror(io_error, buffer, sizeof(buffer))); *err = CURLE_WRITE_ERROR; return -1; } diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c index 7ffba6cc19..44c59e7796 100644 --- a/libs/libcurl/src/vtls/schannel.c +++ b/libs/libcurl/src/vtls/schannel.c @@ -141,6 +141,12 @@ # define CALG_SHA_256 0x0000800c #endif +/* Work around typo in classic MinGW's w32api up to version 5.0, + see https://osdn.net/projects/mingw/ticket/38391 */ +#if !defined(ALG_CLASS_DHASH) && defined(ALG_CLASS_HASH) +#define ALG_CLASS_DHASH ALG_CLASS_HASH +#endif + #define BACKEND connssl->backend static Curl_recv schannel_recv; @@ -279,13 +285,7 @@ get_alg_id_by_name(char *name) #ifdef CALG_HMAC CIPHEROPTION(CALG_HMAC); #endif -#if !defined(__W32API_MAJOR_VERSION) || \ - !defined(__W32API_MINOR_VERSION) || \ - defined(__MINGW64_VERSION_MAJOR) || \ - (__W32API_MAJOR_VERSION > 5) || \ - ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0)) - /* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0, - see https://osdn.net/projects/mingw/ticket/38391 */ +#ifdef CALG_TLS1PRF CIPHEROPTION(CALG_TLS1PRF); #endif #ifdef CALG_HASH_REPLACE_OWF @@ -716,8 +716,6 @@ schannel_acquire_credential_handle(struct Curl_easy *data, } BACKEND->cred->refcount = 1; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx - */ sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, @@ -1141,8 +1139,6 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn, if(!host_name) return CURLE_OUT_OF_MEMORY; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx - */ sspi_status = s_pSecFn->InitializeSecurityContext( &BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle, host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL, @@ -1364,7 +1360,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, SECURITY_STATUS sspi_status = SEC_E_OK; CERT_CONTEXT *ccert_context = NULL; bool isproxy = SSL_IS_PROXY(); -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) const char * const hostname = SSL_HOST_NAME(); #endif #ifdef HAS_ALPN @@ -1436,6 +1432,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, /* save the current session data for possible re-use */ if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; struct Curl_schannel_cred *old_cred = NULL; Curl_ssl_sessionid_lock(data); @@ -1453,13 +1450,13 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(!incache) { result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred, sizeof(struct Curl_schannel_cred), - sockindex); + sockindex, &added); if(result) { Curl_ssl_sessionid_unlock(data); failf(data, "schannel: failed to store credential handle"); return result; } - else { + else if(added) { /* this cred session is now also referenced by sessionid cache */ BACKEND->cred->refcount++; DEBUGF(infof(data, @@ -1970,12 +1967,12 @@ schannel_recv(struct Curl_easy *data, int sockindex, if(sspi_status == SEC_I_RENEGOTIATE) { infof(data, "schannel: remote party requests renegotiation"); if(*err && *err != CURLE_AGAIN) { - infof(data, "schannel: can't renogotiate, an error is pending"); + infof(data, "schannel: can't renegotiate, an error is pending"); goto cleanup; } if(BACKEND->encdata_offset) { *err = CURLE_RECV_ERROR; - infof(data, "schannel: can't renogotiate, " + infof(data, "schannel: can't renegotiate, " "encrypted data available"); goto cleanup; } @@ -2124,26 +2121,23 @@ static bool schannel_data_pending(const struct connectdata *conn, return FALSE; } -static void schannel_close(struct Curl_easy *data, struct connectdata *conn, - int sockindex) -{ - if(conn->ssl[sockindex].use) - /* if the SSL/TLS channel hasn't been shut down yet, do that now. */ - Curl_ssl_shutdown(data, conn, sockindex); -} - static void schannel_session_free(void *ptr) { /* this is expected to be called under sessionid lock */ struct Curl_schannel_cred *cred = ptr; - cred->refcount--; - if(cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); + if(cred) { + cred->refcount--; + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); + } } } +/* shut down the SSL connection and clean up related memory. + this function can be called multiple times on the same connection including + if the SSL connection failed (eg connection made but failed handshake). */ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, int sockindex) { @@ -2155,10 +2149,12 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, DEBUGASSERT(data); - infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu", - hostname, conn->remote_port); + if(connssl->use) { + infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu", + hostname, conn->remote_port); + } - if(BACKEND->cred && BACKEND->ctxt) { + if(connssl->use && BACKEND->cred && BACKEND->ctxt) { SecBufferDesc BuffDesc; SecBuffer Buffer; SECURITY_STATUS sspi_status; @@ -2251,6 +2247,16 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn, return CURLE_OK; } +static void schannel_close(struct Curl_easy *data, struct connectdata *conn, + int sockindex) +{ + if(conn->ssl[sockindex].use) + /* Curl_ssl_shutdown resets the socket state and calls schannel_shutdown */ + Curl_ssl_shutdown(data, conn, sockindex); + else + schannel_shutdown(data, conn, sockindex); +} + static int schannel_init(void) { return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0); diff --git a/libs/libcurl/src/vtls/schannel_verify.c b/libs/libcurl/src/vtls/schannel_verify.c index 12fccaa8ee..1b283d0453 100644 --- a/libs/libcurl/src/vtls/schannel_verify.c +++ b/libs/libcurl/src/vtls/schannel_verify.c @@ -80,7 +80,7 @@ static int is_cr_or_lf(char c) /* Search the substring needle,needlelen into string haystack,haystacklen * Strings don't need to be terminated by a '\0'. * Similar of OSX/Linux memmem (not available on Visual Studio). - * Return position of beginning of first occurence or NULL if not found + * Return position of beginning of first occurrence or NULL if not found */ static const char *c_memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c index 26b833dd2a..0bf515460d 100644 --- a/libs/libcurl/src/vtls/sectransp.c +++ b/libs/libcurl/src/vtls/sectransp.c @@ -33,6 +33,8 @@ #include "strtok.h" #include "multiif.h" #include "strcase.h" +#include "x509asn1.h" +#include "strerror.h" #ifdef USE_SECTRANSP @@ -2107,7 +2109,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data, } result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid, - ssl_sessionid_len, sockindex); + ssl_sessionid_len, sockindex, NULL); Curl_ssl_sessionid_unlock(data); if(result) { failf(data, "failed to store ssl session"); @@ -2854,13 +2856,60 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn, } } +static CURLcode +add_cert_to_certinfo(struct Curl_easy *data, + 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_easy *data, + SecCertificateRef server_cert, + CFIndex idx) +{ + CURLcode result = CURLE_OK; #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(data->set.ssl.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 void -show_verbose_server_cert(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) +static CURLcode +collect_server_cert(struct Curl_easy *data, + struct connectdata *conn, + int sockindex) { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const bool show_verbose_server_cert = data->set.verbose; +#else + const bool show_verbose_server_cert = false; +#endif + CURLcode result = data->set.ssl.certinfo ? + CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; CFArrayRef server_certs = NULL; @@ -2869,8 +2918,11 @@ show_verbose_server_cert(struct Curl_easy *data, CFIndex i, count; SecTrustRef trust = NULL; + if(!show_verbose_server_cert && !data->set.ssl.certinfo) + return CURLE_OK; + if(!backend->ssl_ctx) - return; + return result; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS @@ -2880,15 +2932,11 @@ show_verbose_server_cert(struct Curl_easy *data, a null trust, so be on guard for that: */ if(err == noErr && trust) { count = SecTrustGetCertificateCount(trust); - for(i = 0L ; i < count ; i++) { - CURLcode result; - char *certp; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(trust); } @@ -2906,15 +2954,11 @@ show_verbose_server_cert(struct Curl_easy *data, a null trust, so be on guard for that: */ if(err == noErr && trust) { count = SecTrustGetCertificateCount(trust); - for(i = 0L ; i < count ; i++) { - char *certp; - CURLcode result; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = SecTrustGetCertificateAtIndex(trust, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(trust); } @@ -2925,16 +2969,12 @@ show_verbose_server_cert(struct Curl_easy *data, /* Just in case SSLCopyPeerCertificates() returns null too... */ if(err == noErr && server_certs) { count = CFArrayGetCount(server_certs); - for(i = 0L ; i < count ; i++) { - char *certp; - CURLcode result; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(server_certs); } @@ -2946,21 +2986,17 @@ show_verbose_server_cert(struct Curl_easy *data, err = SSLCopyPeerCertificates(backend->ssl_ctx, &server_certs); if(err == noErr) { count = CFArrayGetCount(server_certs); - for(i = 0L ; i < count ; i++) { - CURLcode result; - char *certp; + if(data->set.ssl.certinfo) + result = Curl_ssl_init_certinfo(data, (int)count); + for(i = 0L ; !result && (i < count) ; i++) { server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i); - result = CopyCertSubject(data, server_cert, &certp); - if(!result) { - infof(data, "Server certificate: %s", certp); - free(certp); - } + result = collect_server_cert_single(data, server_cert, i); } CFRelease(server_certs); } #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ + return result; } -#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ static CURLcode sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn, @@ -2969,12 +3005,11 @@ sectransp_connect_step3(struct Curl_easy *data, struct connectdata *conn, struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* There is no step 3! - * Well, okay, if verbose mode is on, let's print the details of the - * server certificates. */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS - if(data->set.verbose) - show_verbose_server_cert(data, conn, sockindex); -#endif + * Well, okay, let's collect server certificates, and if verbose mode is on, + * let's print the details of the server certificates. */ + const CURLcode result = collect_server_cert(data, conn, sockindex); + if(result) + return result; connssl->connecting_state = ssl_connect_done; return CURLE_OK; @@ -3188,7 +3223,9 @@ static int sectransp_shutdown(struct Curl_easy *data, nread = read(conn->sock[sockindex], buf, sizeof(buf)); if(nread < 0) { - failf(data, "read: %s", strerror(errno)); + char buffer[STRERROR_LEN]; + failf(data, "read: %s", + Curl_strerror(errno, buffer, sizeof(buffer))); rc = -1; } @@ -3433,6 +3470,7 @@ const struct Curl_ssl Curl_ssl_sectransp = { { CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */ SSLSUPP_CAINFO_BLOB | + SSLSUPP_CERTINFO | #ifdef SECTRANSP_PINNEDPUBKEY SSLSUPP_PINNEDPUBKEY, #else diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c index e5bbe1f5f0..6007bbba0f 100644 --- a/libs/libcurl/src/vtls/vtls.c +++ b/libs/libcurl/src/vtls/vtls.c @@ -516,7 +516,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const bool isProxy, void *ssl_sessionid, size_t idsize, - int sockindex) + int sockindex, + bool *added) { size_t i; struct Curl_ssl_session *store; @@ -536,6 +537,10 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const char *hostname = conn->host.name; #endif (void)sockindex; + + if(added) + *added = FALSE; + if(!data->state.session) return CURLE_OK; @@ -609,6 +614,9 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } + if(added) + *added = TRUE; + DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]", store->scheme, store->name, store->remote_port, isProxy ? "PROXY" : "server")); diff --git a/libs/libcurl/src/vtls/vtls.h b/libs/libcurl/src/vtls/vtls.h index beaa83d9e3..c7bbba082d 100644 --- a/libs/libcurl/src/vtls/vtls.h +++ b/libs/libcurl/src/vtls/vtls.h @@ -261,7 +261,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, const bool isProxy, void *ssl_sessionid, size_t idsize, - int sockindex); + int sockindex, + bool *added); /* Kill a single session ID entry in the cache * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). * This will call engine-specific curlssl_session_free function, which must diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c index 7cab17fb6e..8c5b9157b8 100644 --- a/libs/libcurl/src/vtls/wolfssl.c +++ b/libs/libcurl/src/vtls/wolfssl.c @@ -202,6 +202,43 @@ static int do_file_type(const char *type) return -1; } +#ifdef HAVE_LIBOQS +struct group_name_map { + const word16 group; + const char *name; +}; + +static const struct group_name_map gnm[] = { + { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" }, + { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" }, + { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" }, + { WOLFSSL_NTRU_HPS_LEVEL1, "NTRU_HPS_LEVEL1" }, + { WOLFSSL_NTRU_HPS_LEVEL3, "NTRU_HPS_LEVEL3" }, + { WOLFSSL_NTRU_HPS_LEVEL5, "NTRU_HPS_LEVEL5" }, + { WOLFSSL_NTRU_HRSS_LEVEL3, "NTRU_HRSS_LEVEL3" }, + { WOLFSSL_SABER_LEVEL1, "SABER_LEVEL1" }, + { WOLFSSL_SABER_LEVEL3, "SABER_LEVEL3" }, + { WOLFSSL_SABER_LEVEL5, "SABER_LEVEL5" }, + { WOLFSSL_KYBER_90S_LEVEL1, "KYBER_90S_LEVEL1" }, + { WOLFSSL_KYBER_90S_LEVEL3, "KYBER_90S_LEVEL3" }, + { WOLFSSL_KYBER_90S_LEVEL5, "KYBER_90S_LEVEL5" }, + { WOLFSSL_P256_NTRU_HPS_LEVEL1, "P256_NTRU_HPS_LEVEL1" }, + { WOLFSSL_P384_NTRU_HPS_LEVEL3, "P384_NTRU_HPS_LEVEL3" }, + { WOLFSSL_P521_NTRU_HPS_LEVEL5, "P521_NTRU_HPS_LEVEL5" }, + { WOLFSSL_P384_NTRU_HRSS_LEVEL3, "P384_NTRU_HRSS_LEVEL3" }, + { WOLFSSL_P256_SABER_LEVEL1, "P256_SABER_LEVEL1" }, + { WOLFSSL_P384_SABER_LEVEL3, "P384_SABER_LEVEL3" }, + { WOLFSSL_P521_SABER_LEVEL5, "P521_SABER_LEVEL5" }, + { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" }, + { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" }, + { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" }, + { WOLFSSL_P256_KYBER_90S_LEVEL1, "P256_KYBER_90S_LEVEL1" }, + { WOLFSSL_P384_KYBER_90S_LEVEL3, "P384_KYBER_90S_LEVEL3" }, + { WOLFSSL_P521_KYBER_90S_LEVEL5, "P521_KYBER_90S_LEVEL5" }, + { 0, NULL } +}; +#endif + /* * This function loads all the client/CA certificates and CRLs. Setup the TLS * layer and do all necessary magic. @@ -210,11 +247,15 @@ static CURLcode wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, int sockindex) { - char *ciphers; + char *ciphers, *curves; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct ssl_backend_data *backend = connssl->backend; SSL_METHOD* req_method = NULL; curl_socket_t sockfd = conn->sock[sockindex]; +#ifdef HAVE_LIBOQS + word16 oqsAlg = 0; + size_t idx = 0; +#endif #ifdef HAVE_SNI bool sni = FALSE; #define use_sni(x) sni = (x) @@ -327,6 +368,26 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, infof(data, "Cipher selection: %s", ciphers); } + curves = SSL_CONN_CONFIG(curves); + if(curves) { + +#ifdef HAVE_LIBOQS + for(idx = 0; gnm[idx].name != NULL; idx++) { + if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) { + oqsAlg = gnm[idx].group; + break; + } + } + + if(oqsAlg == 0) +#endif + { + if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) { + failf(data, "failed setting curves list: '%s'", curves); + return CURLE_SSL_CIPHER; + } + } + } #ifndef NO_FILESYSTEM /* load trusted cacert */ if(SSL_CONN_CONFIG(CAfile)) { @@ -439,6 +500,14 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } +#ifdef HAVE_LIBOQS + if(oqsAlg) { + if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) { + failf(data, "unable to use oqs KEM"); + } + } +#endif + #ifdef HAVE_ALPN if(conn->bits.tls_enable_alpn) { char protocols[128]; @@ -495,7 +564,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, /* we got a session id, use it! */ if(!SSL_set_session(backend->handle, ssl_sessionid)) { Curl_ssl_delsessionid(data, ssl_sessionid); - infof(data, "Can't use session ID, going on without\n"); + infof(data, "Can't use session ID, going on without"); } else infof(data, "SSL re-using session ID"); @@ -525,6 +594,8 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, const char * const dispname = SSL_HOST_DISPNAME(); const char * const pinnedpubkey = SSL_PINNED_PUB_KEY(); + ERR_clear_error(); + conn->recv[sockindex] = wolfssl_recv; conn->send[sockindex] = wolfssl_send; @@ -747,7 +818,7 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(!incache) { result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, - 0, sockindex); + 0, sockindex, NULL); if(result) { Curl_ssl_sessionid_unlock(data); failf(data, "failed to store ssl session"); @@ -775,7 +846,11 @@ static ssize_t wolfssl_send(struct Curl_easy *data, struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; - int rc = SSL_write(backend->handle, mem, memlen); + int rc; + + ERR_clear_error(); + + rc = SSL_write(backend->handle, mem, memlen); if(rc <= 0) { int err = SSL_get_error(backend->handle, rc); @@ -831,7 +906,11 @@ static ssize_t wolfssl_recv(struct Curl_easy *data, struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; - int nread = SSL_read(backend->handle, buf, buffsize); + int nread; + + ERR_clear_error(); + + nread = SSL_read(backend->handle, buf, buffsize); if(nread < 0) { int err = SSL_get_error(backend->handle, nread); @@ -916,6 +995,7 @@ static int wolfssl_shutdown(struct Curl_easy *data, struct connectdata *conn, (void) data; if(backend->handle) { + ERR_clear_error(); SSL_free(backend->handle); backend->handle = NULL; } diff --git a/libs/libcurl/src/x509asn1.c b/libs/libcurl/src/x509asn1.c index c70378daca..1bdaeadc80 100644 --- a/libs/libcurl/src/x509asn1.c +++ b/libs/libcurl/src/x509asn1.c @@ -23,7 +23,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_WOLFSSL) || defined(USE_SCHANNEL) + defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) #include <curl/curl.h> #include "urldata.h" @@ -34,6 +34,7 @@ #include "inet_pton.h" #include "curl_base64.h" #include "x509asn1.h" +#include "dynbuf.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -205,16 +206,16 @@ static const char *bool2str(const char *beg, const char *end) */ static const char *octet2str(const char *beg, const char *end) { - size_t n = end - beg; - char *buf = NULL; + struct dynbuf buf; + CURLcode result; - if(n <= (SIZE_T_MAX - 1) / 3) { - buf = malloc(3 * n + 1); - if(buf) - for(n = 0; beg < end; n += 3) - msnprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); - } - return buf; + Curl_dyn_init(&buf, 3 * CURL_ASN1_MAX + 1); + result = Curl_dyn_addn(&buf, "", 0); + + while(!result && beg < end) + result = Curl_dyn_addf(&buf, "%02x:", (unsigned char) *beg++); + + return Curl_dyn_ptr(&buf); } static const char *bit2str(const char *beg, const char *end) @@ -1103,7 +1104,8 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, return CURLE_OK; } -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL + * or USE_SECTRANSP */ #if defined(USE_GSKIT) diff --git a/libs/libcurl/src/x509asn1.h b/libs/libcurl/src/x509asn1.h index 326e32d588..3b51eeef8d 100644 --- a/libs/libcurl/src/x509asn1.h +++ b/libs/libcurl/src/x509asn1.h @@ -26,7 +26,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_WOLFSSL) || defined(USE_SCHANNEL) + defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) #include "urldata.h" @@ -129,5 +129,6 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum, const char *beg, const char *end); CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn, const char *beg, const char *end); -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL + * or USE_SECTRANSP */ #endif /* HEADER_CURL_X509ASN1_H */ |