summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib')
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt17
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc5
-rw-r--r--Utilities/cmcurl/lib/altsvc.c12
-rw-r--r--Utilities/cmcurl/lib/amigaos.c29
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c241
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c77
-rw-r--r--Utilities/cmcurl/lib/bufref.c127
-rw-r--r--Utilities/cmcurl/lib/bufref.h46
-rw-r--r--Utilities/cmcurl/lib/c-hyper.c296
-rw-r--r--Utilities/cmcurl/lib/c-hyper.h1
-rw-r--r--Utilities/cmcurl/lib/conncache.c14
-rw-r--r--Utilities/cmcurl/lib/connect.c211
-rw-r--r--Utilities/cmcurl/lib/connect.h6
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c9
-rw-r--r--Utilities/cmcurl/lib/cookie.c504
-rw-r--r--Utilities/cmcurl/lib/cookie.h14
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.c2
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake202
-rw-r--r--Utilities/cmcurl/lib/curl_endian.c44
-rw-r--r--Utilities/cmcurl/lib/curl_endian.h4
-rw-r--r--Utilities/cmcurl/lib/curl_get_line.c4
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c6
-rw-r--r--Utilities/cmcurl/lib/curl_krb5.h1
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.c102
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.h43
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c161
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.h18
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c9
-rw-r--r--Utilities/cmcurl/lib/curl_path.c10
-rw-r--r--Utilities/cmcurl/lib/curl_range.c8
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c8
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c308
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.h17
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h160
-rw-r--r--Utilities/cmcurl/lib/curl_setup_once.h39
-rw-r--r--Utilities/cmcurl/lib/dict.c15
-rw-r--r--Utilities/cmcurl/lib/doh.c163
-rw-r--r--Utilities/cmcurl/lib/doh.h2
-rw-r--r--Utilities/cmcurl/lib/dynbuf.h4
-rw-r--r--Utilities/cmcurl/lib/easy.c79
-rw-r--r--Utilities/cmcurl/lib/easyoptions.c7
-rw-r--r--Utilities/cmcurl/lib/file.c40
-rw-r--r--Utilities/cmcurl/lib/formdata.c16
-rw-r--r--Utilities/cmcurl/lib/ftp.c242
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c3
-rw-r--r--Utilities/cmcurl/lib/getinfo.c10
-rw-r--r--Utilities/cmcurl/lib/gopher.c2
-rw-r--r--Utilities/cmcurl/lib/hash.c4
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c1
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c20
-rw-r--r--Utilities/cmcurl/lib/hostip.c249
-rw-r--r--Utilities/cmcurl/lib/hostip.h14
-rw-r--r--Utilities/cmcurl/lib/hostip4.c3
-rw-r--r--Utilities/cmcurl/lib/hostip6.c50
-rw-r--r--Utilities/cmcurl/lib/hostsyn.c3
-rw-r--r--Utilities/cmcurl/lib/hsts.c30
-rw-r--r--Utilities/cmcurl/lib/hsts.h8
-rw-r--r--Utilities/cmcurl/lib/http.c494
-rw-r--r--Utilities/cmcurl/lib/http.h19
-rw-r--r--Utilities/cmcurl/lib/http2.c378
-rw-r--r--Utilities/cmcurl/lib/http2.h11
-rw-r--r--Utilities/cmcurl/lib/http_aws_sigv4.c16
-rw-r--r--Utilities/cmcurl/lib/http_digest.c14
-rw-r--r--Utilities/cmcurl/lib/http_digest.h1
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.c8
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c108
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c236
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h25
-rw-r--r--Utilities/cmcurl/lib/imap.c65
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.c6
-rw-r--r--Utilities/cmcurl/lib/krb5.c45
-rw-r--r--Utilities/cmcurl/lib/ldap.c58
-rw-r--r--Utilities/cmcurl/lib/llist.c6
-rw-r--r--Utilities/cmcurl/lib/md4.c39
-rw-r--r--Utilities/cmcurl/lib/md5.c40
-rw-r--r--Utilities/cmcurl/lib/memdebug.c35
-rw-r--r--Utilities/cmcurl/lib/mime.c4
-rw-r--r--Utilities/cmcurl/lib/mprintf.c8
-rw-r--r--Utilities/cmcurl/lib/mqtt.c259
-rw-r--r--Utilities/cmcurl/lib/multi.c624
-rw-r--r--Utilities/cmcurl/lib/multihandle.h53
-rw-r--r--Utilities/cmcurl/lib/netrc.c25
-rw-r--r--Utilities/cmcurl/lib/non-ascii.c24
-rw-r--r--Utilities/cmcurl/lib/nonblock.c10
-rw-r--r--Utilities/cmcurl/lib/openldap.c145
-rw-r--r--Utilities/cmcurl/lib/pingpong.c4
-rw-r--r--Utilities/cmcurl/lib/pingpong.h7
-rw-r--r--Utilities/cmcurl/lib/pop3.c84
-rw-r--r--Utilities/cmcurl/lib/progress.c97
-rw-r--r--Utilities/cmcurl/lib/quic.h2
-rw-r--r--Utilities/cmcurl/lib/rand.c4
-rw-r--r--Utilities/cmcurl/lib/rtsp.c15
-rw-r--r--Utilities/cmcurl/lib/rtsp.h2
-rw-r--r--Utilities/cmcurl/lib/select.c2
-rw-r--r--Utilities/cmcurl/lib/select.h4
-rw-r--r--Utilities/cmcurl/lib/sendf.c49
-rw-r--r--Utilities/cmcurl/lib/setopt.c178
-rw-r--r--Utilities/cmcurl/lib/setup-vms.h8
-rw-r--r--Utilities/cmcurl/lib/sha256.c59
-rw-r--r--Utilities/cmcurl/lib/share.c4
-rw-r--r--Utilities/cmcurl/lib/sigpipe.h4
-rw-r--r--Utilities/cmcurl/lib/smb.c17
-rw-r--r--Utilities/cmcurl/lib/smb.h6
-rw-r--r--Utilities/cmcurl/lib/smtp.c34
-rw-r--r--Utilities/cmcurl/lib/socketpair.c36
-rw-r--r--Utilities/cmcurl/lib/socketpair.h5
-rw-r--r--Utilities/cmcurl/lib/socks.c78
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c8
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c8
-rw-r--r--Utilities/cmcurl/lib/splay.c18
-rw-r--r--Utilities/cmcurl/lib/strdup.c28
-rw-r--r--Utilities/cmcurl/lib/strdup.h5
-rw-r--r--Utilities/cmcurl/lib/strerror.c10
-rw-r--r--Utilities/cmcurl/lib/system_win32.c4
-rw-r--r--Utilities/cmcurl/lib/telnet.c34
-rw-r--r--Utilities/cmcurl/lib/tftp.c120
-rw-r--r--Utilities/cmcurl/lib/timeval.c8
-rw-r--r--Utilities/cmcurl/lib/transfer.c176
-rw-r--r--Utilities/cmcurl/lib/url.c528
-rw-r--r--Utilities/cmcurl/lib/urlapi.c123
-rw-r--r--Utilities/cmcurl/lib/urldata.h187
-rw-r--r--Utilities/cmcurl/lib/vauth/cleartext.c70
-rw-r--r--Utilities/cmcurl/lib/vauth/cram.c65
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c62
-rw-r--r--Utilities/cmcurl/lib/vauth/digest_sspi.c66
-rw-r--r--Utilities/cmcurl/lib/vauth/gsasl.c124
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_gssapi.c182
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_sspi.c187
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c198
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm_sspi.c65
-rw-r--r--Utilities/cmcurl/lib/vauth/oauth2.c53
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_gssapi.c5
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_sspi.c5
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.c25
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.h90
-rw-r--r--Utilities/cmcurl/lib/version.c73
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.c265
-rw-r--r--Utilities/cmcurl/lib/vquic/ngtcp2.h8
-rw-r--r--Utilities/cmcurl/lib/vquic/quiche.c55
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh.c222
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c220
-rw-r--r--Utilities/cmcurl/lib/vssh/ssh.h5
-rw-r--r--Utilities/cmcurl/lib/vssh/wolfssh.c52
-rw-r--r--Utilities/cmcurl/lib/vtls/bearssl.c164
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c79
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c266
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c253
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c27
-rw-r--r--Utilities/cmcurl/lib/vtls/mesalink.c40
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c157
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c771
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.c575
-rw-r--r--Utilities/cmcurl/lib/vtls/rustls.h33
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c912
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h3
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel_verify.c289
-rw-r--r--Utilities/cmcurl/lib/vtls/sectransp.c1957
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c134
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h44
-rw-r--r--Utilities/cmcurl/lib/vtls/wolfssl.c186
-rw-r--r--Utilities/cmcurl/lib/warnless.c106
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c66
-rw-r--r--Utilities/cmcurl/lib/x509asn1.h5
163 files changed, 9664 insertions, 6932 deletions
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
index 703d0ad..d8fd7bd 100644
--- a/Utilities/cmcurl/lib/CMakeLists.txt
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -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
@@ -20,6 +20,7 @@
#
###########################################################################
set(LIB_NAME cmcurl)
+set(LIBCURL_OUTPUT_NAME cmcurl)
if(BUILD_SHARED_LIBS)
set(CURL_STATICLIB NO)
@@ -125,7 +126,10 @@ if(WIN32)
endif()
endif()
-set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL)
+set_target_properties(${LIB_NAME} PROPERTIES
+ COMPILE_DEFINITIONS BUILDING_LIBCURL
+ OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
+ )
if(0) # This code not needed for building within CMake.
if(HIDES_CURL_PRIVATE_SYMBOLS)
@@ -145,13 +149,16 @@ endif()
if(WIN32)
if(BUILD_SHARED_LIBS)
- # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"
- set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
+ if(MSVC)
+ # Add "_imp" as a suffix before the extension to avoid conflicting with
+ # the statically linked "libcurl.lib"
+ set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
+ endif()
endif()
endif()
target_include_directories(${LIB_NAME} INTERFACE
- $<INSTALL_INTERFACE:include>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
install(TARGETS ${LIB_NAME}
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
index e8d2259..3e9ddec 100644
--- a/Utilities/cmcurl/lib/Makefile.inc
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -25,6 +25,7 @@ LIB_VAUTH_CFILES = \
vauth/cram.c \
vauth/digest.c \
vauth/digest_sspi.c \
+ vauth/gsasl.c \
vauth/krb5_gssapi.c \
vauth/krb5_sspi.c \
vauth/ntlm.c \
@@ -49,6 +50,7 @@ LIB_VTLS_CFILES = \
vtls/mesalink.c \
vtls/nss.c \
vtls/openssl.c \
+ vtls/rustls.c \
vtls/schannel.c \
vtls/schannel_verify.c \
vtls/sectransp.c \
@@ -65,6 +67,7 @@ LIB_VTLS_HFILES = \
vtls/mesalink.h \
vtls/nssg.h \
vtls/openssl.h \
+ vtls/rustls.h \
vtls/schannel.h \
vtls/sectransp.h \
vtls/vtls.h \
@@ -94,6 +97,7 @@ LIB_CFILES = \
asyn-ares.c \
asyn-thread.c \
base64.c \
+ bufref.c \
c-hyper.c \
conncache.c \
connect.c \
@@ -214,6 +218,7 @@ LIB_HFILES = \
amigaos.h \
arpa_telnet.h \
asyn.h \
+ bufref.h \
c-hyper.h \
conncache.h \
connect.h \
diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c
index 4ab77fd..36acc3a 100644
--- a/Utilities/cmcurl/lib/altsvc.c
+++ b/Utilities/cmcurl/lib/altsvc.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 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
@@ -460,7 +460,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
(void)data;
#endif
if(result) {
- infof(data, "Excessive alt-svc header, ignoring...\n");
+ infof(data, "Excessive alt-svc header, ignoring.");
return CURLE_OK;
}
@@ -496,7 +496,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
p++;
len = p - hostp;
if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
- infof(data, "Excessive alt-svc host name, ignoring...\n");
+ infof(data, "Excessive alt-svc host name, ignoring.");
dstalpnid = ALPN_none;
}
else {
@@ -513,7 +513,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
/* a port number */
unsigned long port = strtoul(++p, &end_ptr, 10);
if(port > USHRT_MAX || end_ptr == p || *end_ptr != '\"') {
- infof(data, "Unknown alt-svc port number, ignoring...\n");
+ infof(data, "Unknown alt-svc port number, ignoring.");
dstalpnid = ALPN_none;
}
p = end_ptr;
@@ -579,12 +579,12 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
as->expires = maxage + time(NULL);
as->persist = persist;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
- infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
+ infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
}
else {
- infof(data, "Unknown alt-svc protocol \"%s\", skipping...\n",
+ infof(data, "Unknown alt-svc protocol \"%s\", skipping.",
alpnbuf);
}
}
diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c
index d3b00d9..78bb22c 100644
--- a/Utilities/cmcurl/lib/amigaos.c
+++ b/Utilities/cmcurl/lib/amigaos.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
@@ -90,6 +90,33 @@ void Curl_amiga_X509_free(X509 *a)
{
X509_free(a);
}
+
+/* AmiSSL replaces many functions with macros. Curl requires pointer
+ * to some of these functions. Thus, we have to encapsulate these macros.
+ */
+
+#include "warnless.h"
+
+int (SHA256_Init)(SHA256_CTX *c)
+{
+ return SHA256_Init(c);
+};
+
+int (SHA256_Update)(SHA256_CTX *c, const void *data, size_t len)
+{
+ return SHA256_Update(c, data, curlx_uztoui(len));
+};
+
+int (SHA256_Final)(unsigned char *md, SHA256_CTX *c)
+{
+ return SHA256_Final(md, c);
+};
+
+void (X509_INFO_free)(X509_INFO *a)
+{
+ X509_INFO_free(a);
+};
+
#endif /* USE_AMISSL */
#endif /* __AMIGA__ */
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
index 2484a7b..763a4aa 100644
--- a/Utilities/cmcurl/lib/asyn-ares.c
+++ b/Utilities/cmcurl/lib/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;
@@ -206,7 +225,8 @@ static void destroy_async_data(struct Curl_async *async);
*/
void Curl_resolver_cancel(struct Curl_easy *data)
{
- if(data && data->state.async.resolver)
+ DEBUGASSERT(data);
+ if(data->state.async.resolver)
ares_cancel((ares_channel)data->state.async.resolver);
destroy_async_data(&data->state.async);
}
@@ -309,7 +329,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
pfd[i].fd = socks[i];
pfd[i].events |= POLLWRNORM|POLLOUT;
}
- if(pfd[i].events != 0)
+ if(pfd[i].events)
num++;
else
break;
@@ -384,13 +404,8 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
them */
res->temp_ai = NULL;
- if(!data->state.async.dns) {
- failf(data, "Could not resolve: %s (%s)",
- data->state.async.hostname,
- ares_strerror(data->state.async.status));
- result = data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
- CURLE_COULDNT_RESOLVE_HOST;
- }
+ if(!data->state.async.dns)
+ result = Curl_resolver_error(data);
else
*dns = data->state.async.dns;
@@ -494,21 +509,37 @@ 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)
{
- struct Curl_addrinfo *ai_tail;
if(!ai)
return;
- ai_tail = ai;
- while(ai_tail->ai_next)
- ai_tail = ai_tail->ai_next;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
+ /* We have results already, put the new IPv6 entries at the head of the
+ list. */
+ struct Curl_addrinfo *temp_ai_tail = res->temp_ai;
+
+ while(temp_ai_tail->ai_next)
+ temp_ai_tail = temp_ai_tail->ai_next;
- /* Add the new results to the list of old results. */
- ai_tail->ai_next = res->temp_ai;
- res->temp_ai = ai;
+ temp_ai_tail->ai_next = ai;
+ }
+ else
+#endif /* CURLRES_IPV6 */
+ {
+ /* Add the new results to the list of old results. */
+ struct Curl_addrinfo *ai_tail = ai;
+ while(ai_tail->ai_next)
+ ai_tail = ai_tail->ai_next;
+
+ ai_tail->ai_next = res->temp_ai;
+ res->temp_ai = ai;
+ }
}
/*
@@ -610,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
@@ -625,28 +747,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int *waitp)
{
char *bufp;
- int family = PF_INET;
*waitp = 0; /* default to synchronous response */
-#ifdef ENABLE_IPV6
- switch(data->set.ipver) {
- default:
-#if ARES_VERSION >= 0x010601
- family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
- c-ares versions this just falls through and defaults
- to PF_INET */
- break;
-#endif
- case CURL_IPRESOLVE_V4:
- family = PF_INET;
- break;
- case CURL_IPRESOLVE_V6:
- family = PF_INET6;
- break;
- }
-#endif /* ENABLE_IPV6 */
-
bufp = strdup(hostname);
if(bufp) {
struct thread_data *res = NULL;
@@ -666,36 +769,50 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
-#ifdef ENABLE_IPV6
- if(family == PF_UNSPEC) {
- if(Curl_ipv6works(data)) {
- res->num_pending = 2;
-
- /* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET, query_completed_cb, data);
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET6, query_completed_cb, data);
- }
- else {
- res->num_pending = 1;
- /* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET, query_completed_cb, data);
- }
+#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;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET6, query_completed_cb, data);
}
else
-#endif /* ENABLE_IPV6 */
+#endif
{
res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */
ares_gethostbyname((ares_channel)data->state.async.resolver,
- hostname, family,
+ hostname, PF_INET,
query_completed_cb, data);
}
-
+#endif
*waitp = 1; /* expect asynchronous response */
}
return NULL; /* no struct yet */
@@ -716,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
@@ -747,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 = "";
@@ -764,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)) {
@@ -790,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/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c
index 9fcbc3c..149172a 100644
--- a/Utilities/cmcurl/lib/asyn-thread.c
+++ b/Utilities/cmcurl/lib/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"
@@ -163,7 +162,7 @@ struct thread_sync_data {
int port;
char *hostname; /* hostname to resolve, Curl_async.hostname
duplicate */
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
struct Curl_easy *data;
curl_socket_t sock_pair[2]; /* socket pair */
#endif
@@ -201,7 +200,7 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
if(tsd->res)
Curl_freeaddrinfo(tsd->res);
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
/*
* close one end of the socket pair (may be done in resolver thread);
* the other end (for reading) is always closed in the parent thread.
@@ -238,12 +237,12 @@ int init_thread_sync_data(struct thread_data *td,
#endif
tsd->mtx = malloc(sizeof(curl_mutex_t));
- if(tsd->mtx == NULL)
+ if(!tsd->mtx)
goto err_exit;
Curl_mutex_init(tsd->mtx);
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
/* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
tsd->sock_pair[0] = CURL_SOCKET_BAD;
@@ -297,7 +296,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
struct thread_data *td = tsd->td;
char service[12];
int rc;
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
char buf[1];
#endif
@@ -305,7 +304,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
- if(rc != 0) {
+ if(rc) {
tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
if(tsd->sock_error == 0)
tsd->sock_error = RESOLVER_ENOMEM;
@@ -322,7 +321,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
free(td);
}
else {
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
/* DNS has been resolved, signal client task */
buf[0] = 1;
@@ -382,7 +381,7 @@ static void destroy_async_data(struct Curl_async *async)
if(async->tdata) {
struct thread_data *td = async->tdata;
int done;
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
curl_socket_t sock_rd = td->tsd.sock_pair[0];
struct Curl_easy *data = td->tsd.data;
#endif
@@ -407,7 +406,7 @@ static void destroy_async_data(struct Curl_async *async)
free(async->tdata);
}
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
/*
* ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
@@ -484,35 +483,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
}
/*
- * resolver_error() calls failf() with the appropriate message after a resolve
- * error
- */
-
-static CURLcode resolver_error(struct Curl_easy *data)
-{
- const char *host_or_proxy;
- CURLcode result;
-
-#ifndef CURL_DISABLE_PROXY
- struct connectdata *conn = data->conn;
- if(conn->bits.httpproxy) {
- host_or_proxy = "proxy";
- result = CURLE_COULDNT_RESOLVE_PROXY;
- }
- else
-#endif
- {
- host_or_proxy = "host";
- result = CURLE_COULDNT_RESOLVE_HOST;
- }
-
- failf(data, "Could not resolve %s: %s", host_or_proxy,
- data->state.async.hostname);
-
- return result;
-}
-
-/*
* 'entry' may be NULL and then no data is returned
*/
static CURLcode thread_wait_resolv(struct Curl_easy *data,
@@ -542,7 +512,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
if(!data->state.async.dns && report)
/* a name was not resolved, report error */
- result = resolver_error(data);
+ result = Curl_resolver_error(data);
destroy_async_data(&data->state.async);
@@ -616,7 +586,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
getaddrinfo_complete(data);
if(!data->state.async.dns) {
- CURLcode result = resolver_error(data);
+ CURLcode result = Curl_resolver_error(data);
destroy_async_data(&data->state.async);
return result;
}
@@ -654,13 +624,13 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
timediff_t milli;
timediff_t ms;
struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
struct thread_data *td = data->state.async.tdata;
#else
(void)socks;
#endif
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
if(td) {
/* return read fd to client for polling the DNS resolution status */
socks[0] = td->tsd.sock_pair[0];
@@ -679,7 +649,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
else
milli = 200;
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
}
#endif
@@ -730,24 +700,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
*waitp = 0; /* default to synchronous response */
#ifdef CURLRES_IPV6
- /*
- * Check if a limited name resolve has been requested.
- */
- switch(data->set.ipver) {
- case CURL_IPRESOLVE_V4:
- pf = PF_INET;
- break;
- case CURL_IPRESOLVE_V6:
- pf = PF_INET6;
- break;
- default:
+ if(Curl_ipv6works(data))
+ /* The stack seems to be IPv6-enabled */
pf = PF_UNSPEC;
- break;
- }
-
- if((pf != PF_INET) && !Curl_ipv6works(data))
- /* The stack seems to be a non-IPv6 one */
- pf = PF_INET;
#endif /* CURLRES_IPV6 */
memset(&hints, 0, sizeof(hints));
diff --git a/Utilities/cmcurl/lib/bufref.c b/Utilities/cmcurl/lib/bufref.c
new file mode 100644
index 0000000..b84511e
--- /dev/null
+++ b/Utilities/cmcurl/lib/bufref.c
@@ -0,0 +1,127 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 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
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+#include "bufref.h"
+
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SIGNATURE 0x5c48e9b2 /* Random pattern. */
+
+/*
+ * Init a bufref struct.
+ */
+void Curl_bufref_init(struct bufref *br)
+{
+ DEBUGASSERT(br);
+ br->dtor = NULL;
+ br->ptr = NULL;
+ br->len = 0;
+
+#ifdef DEBUGBUILD
+ br->signature = SIGNATURE;
+#endif
+}
+
+/*
+ * Free the buffer and re-init the necessary fields. It doesn't touch the
+ * 'signature' field and thus this buffer reference can be reused.
+ */
+
+void Curl_bufref_free(struct bufref *br)
+{
+ DEBUGASSERT(br);
+ DEBUGASSERT(br->signature == SIGNATURE);
+ DEBUGASSERT(br->ptr || !br->len);
+
+ if(br->ptr && br->dtor)
+ br->dtor((void *) br->ptr);
+
+ br->dtor = NULL;
+ br->ptr = NULL;
+ br->len = 0;
+}
+
+/*
+ * Set the buffer reference to new values. The previously referenced buffer
+ * is released before assignment.
+ */
+void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
+ void (*dtor)(void *))
+{
+ DEBUGASSERT(ptr || !len);
+ DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
+
+ Curl_bufref_free(br);
+ br->ptr = (const unsigned char *) ptr;
+ br->len = len;
+ br->dtor = dtor;
+}
+
+/*
+ * Get a pointer to the referenced buffer.
+ */
+const unsigned char *Curl_bufref_ptr(const struct bufref *br)
+{
+ DEBUGASSERT(br);
+ DEBUGASSERT(br->signature == SIGNATURE);
+ DEBUGASSERT(br->ptr || !br->len);
+
+ return br->ptr;
+}
+
+/*
+ * Get the length of the referenced buffer data.
+ */
+size_t Curl_bufref_len(const struct bufref *br)
+{
+ DEBUGASSERT(br);
+ DEBUGASSERT(br->signature == SIGNATURE);
+ DEBUGASSERT(br->ptr || !br->len);
+
+ return br->len;
+}
+
+CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
+{
+ unsigned char *cpy = NULL;
+
+ DEBUGASSERT(br);
+ DEBUGASSERT(br->signature == SIGNATURE);
+ DEBUGASSERT(br->ptr || !br->len);
+ DEBUGASSERT(ptr || !len);
+ DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
+
+ if(ptr) {
+ cpy = malloc(len + 1);
+ if(!cpy)
+ return CURLE_OUT_OF_MEMORY;
+ if(len)
+ memcpy(cpy, ptr, len);
+ cpy[len] = '\0';
+ }
+
+ Curl_bufref_set(br, cpy, len, curl_free);
+ return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/lib/bufref.h b/Utilities/cmcurl/lib/bufref.h
new file mode 100644
index 0000000..25f65d8
--- /dev/null
+++ b/Utilities/cmcurl/lib/bufref.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_BUFREF_H
+#define HEADER_CURL_BUFREF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 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
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Generic buffer reference.
+ */
+struct bufref {
+ void (*dtor)(void *); /* Associated destructor. */
+ const unsigned char *ptr; /* Referenced data buffer. */
+ size_t len; /* The data size in bytes. */
+#ifdef DEBUGBUILD
+ int signature; /* Detect API use mistakes. */
+#endif
+};
+
+
+void Curl_bufref_init(struct bufref *br);
+void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
+ void (*dtor)(void *));
+const unsigned char *Curl_bufref_ptr(const struct bufref *br);
+size_t Curl_bufref_len(const struct bufref *br);
+CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len);
+void Curl_bufref_free(struct bufref *br);
+
+#endif
diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c
index 10bd7ef..26635cd 100644
--- a/Utilities/cmcurl/lib/c-hyper.c
+++ b/Utilities/cmcurl/lib/c-hyper.c
@@ -51,6 +51,7 @@
#include "transfer.h"
#include "multiif.h"
#include "progress.h"
+#include "content_encoding.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -123,6 +124,17 @@ static int hyper_each_header(void *userdata,
size_t len;
char *headp;
CURLcode result;
+ int writetype;
+
+ if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
+ failf(data, "Too long response header");
+ data->state.hresult = CURLE_OUT_OF_MEMORY;
+ return HYPER_ITER_BREAK;
+ }
+
+ if(!data->req.bytecount)
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
Curl_dyn_reset(&data->state.headerb);
if(name_len) {
if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
@@ -144,7 +156,10 @@ static int hyper_each_header(void *userdata,
Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
- result = Curl_client_write(data, CLIENTWRITE_HEADER, 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;
@@ -161,21 +176,57 @@ 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;
- result = Curl_http_firstwrite(data, data->conn, &done);
+#if defined(USE_NTLM)
+ struct connectdata *conn = data->conn;
+ if(conn->bits.close &&
+ (((data->req.httpcode == 401) &&
+ (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
+ ((data->req.httpcode == 407) &&
+ (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
+ infof(data, "Connection closed while negotiating NTLM");
+ data->state.authproblem = TRUE;
+ Curl_safefree(data->req.newurl);
+ }
+#endif
+ 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)) {
+ done = TRUE;
+ result = CURLE_OK;
+ }
+ else
+ result = Curl_http_firstwrite(data, data->conn, &done);
if(result || done) {
- infof(data, "Return early from hyper_body_chunk\n");
+ infof(data, "Return early from hyper_body_chunk");
data->state.hresult = result;
return HYPER_ITER_BREAK;
}
}
if(k->ignorebody)
return HYPER_ITER_CONTINUE;
+ if(0 == len)
+ return HYPER_ITER_CONTINUE;
Curl_debug(data, CURLINFO_DATA_IN, buf, len);
- result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+ if(!data->set.http_ce_skip && k->writer_stack)
+ /* content-encoded data */
+ result = Curl_unencode_write(data, k->writer_stack, buf, len);
+ else
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
if(result) {
data->state.hresult = result;
@@ -198,16 +249,17 @@ static CURLcode status_line(struct Curl_easy *data,
const uint8_t *reason, size_t rlen)
{
CURLcode result;
- size_t wrote;
size_t len;
const char *vstr;
- curl_write_callback writeheader =
- data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
+ int writetype;
vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
(http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
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;
+
data->req.httpcode = http_status;
result = Curl_http_statusline(data, conn);
@@ -225,12 +277,15 @@ 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);
- Curl_set_in_callback(data, true);
- wrote = writeheader(Curl_dyn_ptr(&data->state.headerb), 1, len,
- data->set.writeheader);
- Curl_set_in_callback(data, false);
- if(wrote != len)
- return CURLE_WRITE_ERROR;
+ 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;
@@ -266,8 +321,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);
@@ -301,19 +373,22 @@ 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)\n");
+ infof(data, "hyperstream is done (by early callback)");
}
else {
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);
- 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 */
else
result = CURLE_RECV_ERROR;
}
@@ -324,7 +399,12 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
else if(h->endtask == task) {
/* end of transfer */
*done = TRUE;
- infof(data, "hyperstream is done!\n");
+ 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) {
@@ -464,13 +544,11 @@ CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
else
linelen = 2; /* CRLF ending */
linelen += (p - n);
- if(!n)
- return CURLE_BAD_FUNCTION_ARGUMENT;
vlen = p - v;
if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
(uint8_t *)v, vlen)) {
- failf(data, "hyper_headers_add host");
+ failf(data, "hyper refused to add header '%s'", line);
return CURLE_OUT_OF_MEMORY;
}
if(data->set.verbose) {
@@ -483,7 +561,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;
@@ -524,12 +602,32 @@ 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 {
/* send everything off in a single go */
- *chunk = hyper_buf_copy(data->set.postfields,
- (size_t)data->req.p.http->postsize);
+ hyper_buf *copy = hyper_buf_copy(data->set.postfields,
+ (size_t)data->req.p.http->postsize);
+ if(copy)
+ *chunk = copy;
+ else {
+ data->state.hresult = CURLE_OUT_OF_MEMORY;
+ return HYPER_POLL_ERROR;
+ }
+ /* increasing the writebytecount here is a little premature but we
+ don't know exactly when the body is sent*/
+ data->req.writebytecount += (size_t)data->req.p.http->postsize;
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
data->req.upload_done = TRUE;
}
return HYPER_POLL_READY;
@@ -540,16 +638,41 @@ 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(result)
+
+ 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;
+ }
if(!fillcount)
/* done! */
*chunk = NULL;
- else
- *chunk = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+ else {
+ hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+ if(copy)
+ *chunk = copy;
+ else {
+ data->state.hresult = CURLE_OUT_OF_MEMORY;
+ return HYPER_POLL_ERROR;
+ }
+ /* increasing the writebytecount here is a little premature but we
+ don't know exactly when the body is sent*/
+ data->req.writebytecount += fillcount;
+ Curl_pgrsSetUploadCounter(data, fillcount);
+ }
return HYPER_POLL_READY;
}
@@ -564,6 +687,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))
@@ -596,6 +720,7 @@ static CURLcode bodysend(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
}
}
+ http->sending = HTTPSEND_BODY;
return result;
}
@@ -614,6 +739,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
@@ -631,20 +798,20 @@ 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
the rest of the request in the PERFORM phase. */
*done = TRUE;
- infof(data, "Time for the Hyper dance\n");
+ infof(data, "Time for the Hyper dance");
memset(h, 0, sizeof(struct hyptransfer));
result = Curl_http_host(data, conn);
@@ -741,7 +908,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
- if(data->set.httpversion == 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");
@@ -764,6 +931,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
goto error;
}
+ rc = hyper_request_on_informational(req, http1xx_cb, data);
+ if(rc)
+ return CURLE_OUT_OF_MEMORY;
+
result = Curl_http_body(data, conn, httpreq, &te);
if(result)
return result;
@@ -807,14 +978,36 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
#endif
Curl_safefree(data->state.aptr.ref);
- if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
- data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ 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))
goto error;
}
+ if(!Curl_checkheaders(data, "Accept-Encoding") &&
+ data->set.str[STRING_ENCODING]) {
+ Curl_safefree(data->state.aptr.accept_encoding);
+ 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))
+ goto error;
+ }
+ else
+ Curl_safefree(data->state.aptr.accept_encoding);
+
+#ifdef HAVE_LIBZ
+ /* 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;
+#endif
+
result = cookies(data, conn, headers);
if(result)
return result;
@@ -847,25 +1040,21 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
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 */
+ Curl_safefree(data->state.aptr.userpwd);
+ Curl_safefree(data->state.aptr.proxyuserpwd);
return CURLE_OK;
error:
@@ -878,13 +1067,6 @@ 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);
- }
return CURLE_OUT_OF_MEMORY;
}
@@ -903,6 +1085,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/Utilities/cmcurl/lib/c-hyper.h b/Utilities/cmcurl/lib/c-hyper.h
index d60ed78..d63defe 100644
--- a/Utilities/cmcurl/lib/c-hyper.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
index 8dfdc0a..f5ba8ff 100644
--- a/Utilities/cmcurl/lib/conncache.c
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -34,6 +34,7 @@
#include "share.h"
#include "sigpipe.h"
#include "connect.h"
+#include "strcase.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -161,6 +162,7 @@ static void hashkey(struct connectdata *conn, char *buf,
/* put the number first so that the hostname gets cut off if too long */
msnprintf(buf, len, "%ld%s", port, hostname);
+ Curl_strntolower(buf, buf, len);
}
/* Returns number of connections currently held in the connection cache.
@@ -264,7 +266,7 @@ CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
connc->num_conn++;
DEBUGF(infof(data, "Added connection %ld. "
- "The cache now contains %zu members\n",
+ "The cache now contains %zu members",
conn->connection_id, connc->num_conn));
unlock:
@@ -298,7 +300,7 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
conn->bundle = NULL; /* removed from it */
if(connc) {
connc->num_conn--;
- DEBUGF(infof(data, "The cache now contains %zu members\n",
+ DEBUGF(infof(data, "The cache now contains %zu members",
connc->num_conn));
}
if(lock) {
@@ -408,7 +410,7 @@ bool Curl_conncache_return_conn(struct Curl_easy *data,
conn->lastused = Curl_now(); /* it was used up until now */
if(maxconnects > 0 &&
Curl_conncache_size(data) > maxconnects) {
- infof(data, "Connection cache is full, closing the oldest one.\n");
+ infof(data, "Connection cache is full, closing the oldest one");
conn_candidate = Curl_conncache_extract_oldest(data);
if(conn_candidate) {
@@ -464,9 +466,8 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
/* remove it to prevent another thread from nicking it */
bundle_remove_conn(bundle, conn_candidate);
data->state.conn_cache->num_conn--;
- DEBUGF(infof(data, "The cache now contains %zu members\n",
+ DEBUGF(infof(data, "The cache now contains %zu members",
data->state.conn_cache->num_conn));
- conn_candidate->data = data; /* associate! */
}
return conn_candidate;
@@ -527,9 +528,8 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
/* remove it to prevent another thread from nicking it */
bundle_remove_conn(bundle_candidate, conn_candidate);
connc->num_conn--;
- DEBUGF(infof(data, "The cache now contains %zu members\n",
+ DEBUGF(infof(data, "The cache now contains %zu members",
connc->num_conn));
- conn_candidate->data = data; /* associate! */
}
CONNCACHE_UNLOCK(data);
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
index baab184..d61b037 100644
--- a/Utilities/cmcurl/lib/connect.c
+++ b/Utilities/cmcurl/lib/connect.c
@@ -111,7 +111,7 @@ tcpkeepalive(struct Curl_easy *data,
/* only set IDLE and INTVL if setting KEEPALIVE is successful */
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
+ infof(data, "Failed to set SO_KEEPALIVE on fd %d", sockfd);
}
else {
#if defined(SIO_KEEPALIVE_VALS)
@@ -126,7 +126,7 @@ tcpkeepalive(struct Curl_easy *data,
vals.keepaliveinterval = optval;
if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
NULL, 0, &dummy, NULL, NULL) != 0) {
- infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
+ infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d",
(int)sockfd, WSAGetLastError());
}
#else
@@ -135,7 +135,7 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
+ infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd);
}
#endif
#ifdef TCP_KEEPINTVL
@@ -143,7 +143,7 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
+ infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd);
}
#endif
#ifdef TCP_KEEPALIVE
@@ -152,7 +152,7 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
+ infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
}
#endif
#endif
@@ -171,65 +171,63 @@ singleipconnect(struct Curl_easy *data,
* infinite time left). If the value is negative, the timeout time has already
* elapsed.
*
- * The start time is stored in progress.t_startsingle - as set with
- * Curl_pgrsTime(..., TIMER_STARTSINGLE);
- *
* If 'nowp' is non-NULL, it points to the current time.
* 'duringconnect' is FALSE if not during a connect, as then of course the
* connect timeout is not taken into account!
*
* @unittest: 1303
*/
+
+#define TIMEOUT_CONNECT 1
+#define TIMEOUT_MAXTIME 2
+
timediff_t Curl_timeleft(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect)
{
- int timeout_set = 0;
- timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+ unsigned int timeout_set = 0;
+ timediff_t connect_timeout_ms = 0;
+ timediff_t maxtime_timeout_ms = 0;
+ timediff_t timeout_ms = 0;
struct curltime now;
- /* if a timeout is set, use the most restrictive one */
-
- if(data->set.timeout > 0)
- timeout_set |= 1;
- if(duringconnect && (data->set.connecttimeout > 0))
- timeout_set |= 2;
-
- switch(timeout_set) {
- case 1:
- timeout_ms = data->set.timeout;
- break;
- case 2:
- timeout_ms = data->set.connecttimeout;
- break;
- case 3:
- if(data->set.timeout < data->set.connecttimeout)
- timeout_ms = data->set.timeout;
- else
- timeout_ms = data->set.connecttimeout;
- break;
- default:
- /* use the default */
- if(!duringconnect)
- /* if we're not during connect, there's no default timeout so if we're
- at zero we better just return zero and not make it a negative number
- by the math below */
- return 0;
- break;
+ /* The duration of a connect and the total transfer are calculated from two
+ different time-stamps. It can end up with the total timeout being reached
+ before the connect timeout expires and we must acknowledge whichever
+ timeout that is reached first. The total timeout is set per entire
+ operation, while the connect timeout is set per connect. */
+
+ if(data->set.timeout > 0) {
+ timeout_set = TIMEOUT_MAXTIME;
+ maxtime_timeout_ms = data->set.timeout;
+ }
+ if(duringconnect) {
+ timeout_set |= TIMEOUT_CONNECT;
+ connect_timeout_ms = (data->set.connecttimeout > 0) ?
+ data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
}
+ if(!timeout_set)
+ /* no timeout */
+ return 0;
if(!nowp) {
now = Curl_now();
nowp = &now;
}
- /* subtract elapsed time */
- if(duringconnect)
- /* since this most recent connect started */
- timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
- else
- /* since the entire operation started */
- timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ if(timeout_set & TIMEOUT_MAXTIME) {
+ maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ timeout_ms = maxtime_timeout_ms;
+ }
+
+ if(timeout_set & TIMEOUT_CONNECT) {
+ connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
+
+ if(!(timeout_set & TIMEOUT_MAXTIME) ||
+ (connect_timeout_ms < maxtime_timeout_ms))
+ timeout_ms = connect_timeout_ms;
+ }
+
if(!timeout_ms)
/* avoid returning 0 as that means no timeout! */
return -1;
@@ -333,7 +331,7 @@ static CURLcode bindlocal(struct Curl_easy *data,
/*
* We now have the numerical IP address in the 'myhost' buffer
*/
- infof(data, "Local Interface %s is ip %s using address family %i\n",
+ infof(data, "Local Interface %s is ip %s using address family %i",
dev, myhost, af);
done = 1;
break;
@@ -366,7 +364,7 @@ static CURLcode bindlocal(struct Curl_easy *data,
if(h) {
/* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
Curl_printable_address(h->addr, myhost, sizeof(myhost));
- infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
+ infof(data, "Name '%s' family %i resolved to '%s' family %i",
dev, af, myhost, h->addr->ai_family);
Curl_resolv_unlock(data, h);
if(af != h->addr->ai_family) {
@@ -460,13 +458,13 @@ static CURLcode bindlocal(struct Curl_easy *data,
error, Curl_strerror(error, buffer, sizeof(buffer)));
return CURLE_INTERFACE_FAILED;
}
- infof(data, "Local port: %hu\n", port);
+ infof(data, "Local port: %hu", port);
conn->bits.bound = TRUE;
return CURLE_OK;
}
if(--portnum > 0) {
- infof(data, "Bind to local port %hu failed, trying next\n", port);
+ infof(data, "Bind to local port %hu failed, trying next", port);
port++; /* try next port */
/* We re-use/clobber the port variable here below */
if(sock->sa_family == AF_INET)
@@ -591,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;
}
@@ -611,7 +607,7 @@ static CURLcode trynextip(struct Curl_easy *data,
/* Copies connection info into the transfer handle to make it available when
the transfer handle is no longer associated with the connection. */
void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
- char *local_ip, long local_port)
+ char *local_ip, int local_port)
{
memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
if(local_ip && local_ip[0])
@@ -627,7 +623,7 @@ void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
/* retrieves ip address and port from a sockaddr structure.
note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
- char *addr, long *port)
+ char *addr, int *port)
{
struct sockaddr_in *si = NULL;
#ifdef ENABLE_IPV6
@@ -662,7 +658,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
#endif
#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
case AF_UNIX:
- if(salen > (curl_socklen_t)sizeof(sa_family_t)) {
+ if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
su = (struct sockaddr_un*)sa;
msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
}
@@ -690,7 +686,7 @@ void Curl_conninfo_remote(struct Curl_easy *data,
char buffer[STRERROR_LEN];
struct Curl_sockaddr_storage ssrem;
curl_socklen_t plen;
- long port;
+ int port;
plen = sizeof(struct Curl_sockaddr_storage);
memset(&ssrem, 0, sizeof(ssrem));
if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
@@ -715,7 +711,7 @@ void Curl_conninfo_remote(struct Curl_easy *data,
/* retrieves the start/end point information of a socket of an established
connection */
void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
- char *local_ip, long *local_port)
+ char *local_ip, int *local_port)
{
#ifdef HAVE_GETSOCKNAME
char buffer[STRERROR_LEN];
@@ -752,13 +748,12 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
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] = "";
- long local_port = -1;
+ int local_port = -1;
if(conn->transport == TRNSPRT_TCP) {
- if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
+ if(!conn->bits.reuse && !conn->bits.tcp_fastopen)
Curl_conninfo_remote(data, conn, sockfd);
- Curl_conninfo_local(data, sockfd, local_ip, &local_port);
- }
+ Curl_conninfo_local(data, sockfd, local_ip, &local_port);
} /* end of TCP-only section */
/* persist connection info in session handle */
@@ -874,15 +869,6 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
now = Curl_now();
- /* figure out how long time we have left to connect */
- allow = Curl_timeleft(data, &now, TRUE);
-
- if(allow < 0) {
- /* time-out, bail out, go home */
- failf(data, "Connection time-out");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
if(SOCKS_STATE(conn->cnnct.state)) {
/* still doing SOCKS */
result = connect_SOCKS(data, sockindex, connected);
@@ -908,8 +894,10 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
connkeep(conn, "HTTP/3 default");
return CURLE_OK;
}
- if(result)
+ if(result) {
+ conn->tempsock[i] = CURL_SOCKET_BAD;
error = SOCKERRNO;
+ }
}
else
#endif
@@ -930,7 +918,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
if(Curl_timediff(now, conn->connecttime) >=
conn->timeoutms_per_addr[i]) {
infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
- "ms connect time, move on!\n", conn->timeoutms_per_addr[i]);
+ "ms connect time, move on!", conn->timeoutms_per_addr[i]);
error = ETIMEDOUT;
}
@@ -989,11 +977,12 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
char buffer[STRERROR_LEN];
Curl_printable_address(conn->tempaddr[i], ipaddress,
sizeof(ipaddress));
- infof(data, "connect to %s port %ld failed: %s\n",
+ infof(data, "connect to %s port %u failed: %s",
ipaddress, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
#endif
+ allow = Curl_timeleft(data, &now, TRUE);
conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
allow : allow / 2;
ainext(conn, i, TRUE);
@@ -1006,6 +995,21 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
}
}
+ /*
+ * Now that we've checked whether we are connected, check whether we've
+ * already timed out.
+ *
+ * First figure out how long time we have left to connect */
+
+ allow = Curl_timeleft(data, &now, TRUE);
+
+ if(allow < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection timeout after %ld ms",
+ Curl_timediff(now, data->progress.t_startsingle));
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
if(result &&
(conn->tempsock[0] == CURL_SOCKET_BAD) &&
(conn->tempsock[1] == CURL_SOCKET_BAD)) {
@@ -1031,9 +1035,11 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
else
hostname = conn->host.name;
- failf(data, "Failed to connect to %s port %ld: %s",
- hostname, conn->port,
- Curl_strerror(error, buffer, sizeof(buffer)));
+ failf(data, "Failed to connect to %s port %u after "
+ "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+ hostname, conn->port,
+ Curl_timediff(now, data->progress.t_startsingle),
+ Curl_strerror(error, buffer, sizeof(buffer)));
Curl_quic_disconnect(data, conn, 0);
Curl_quic_disconnect(data, conn, 1);
@@ -1065,7 +1071,7 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
sizeof(onoff)) < 0)
- infof(data, "Could not set TCP_NODELAY: %s\n",
+ infof(data, "Could not set TCP_NODELAY: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
#else
(void)data;
@@ -1084,9 +1090,11 @@ static void nosigpipe(struct Curl_easy *data,
int onoff = 1;
if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
sizeof(onoff)) < 0) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
- infof(data, "Could not set SO_NOSIGPIPE: %s\n",
+ infof(data, "Could not set SO_NOSIGPIPE: %s",
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
+#endif
}
}
#else
@@ -1158,7 +1166,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
curl_socket_t sockfd;
CURLcode result;
char ipaddress[MAX_IPADR_LEN];
- long port;
+ int port;
bool is_tcp;
#ifdef TCP_FASTOPEN_CONNECT
int optval = 1;
@@ -1180,7 +1188,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
Curl_closesocket(data, conn, sockfd);
return CURLE_OK;
}
- infof(data, " Trying %s:%ld...\n", ipaddress, port);
+ infof(data, " Trying %s:%d...", ipaddress, port);
#ifdef ENABLE_IPV6
is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
@@ -1271,7 +1279,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
(void *)&optval, sizeof(optval)) < 0)
- infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
+ infof(data, "Failed to enable TCP Fast Open on fd %d", sockfd);
rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
#elif defined(MSG_FASTOPEN) /* old Linux */
@@ -1321,7 +1329,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
default:
/* unknown error, fallthrough and try another address! */
- infof(data, "Immediate connect fail for %s: %s\n",
+ infof(data, "Immediate connect fail for %s: %s",
ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
data->state.os_errno = error;
@@ -1367,17 +1375,34 @@ CURLcode Curl_connecthost(struct Curl_easy *data,
conn->timeoutms_per_addr[1] =
conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
- conn->tempfamily[0] = conn->tempaddr[0]?
- conn->tempaddr[0]->ai_family:0;
+ if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
+ /* any IP version is allowed */
+ conn->tempfamily[0] = conn->tempaddr[0]?
+ conn->tempaddr[0]->ai_family:0;
#ifdef ENABLE_IPV6
- conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
- AF_INET : AF_INET6;
+ conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
+ AF_INET : AF_INET6;
#else
- conn->tempfamily[1] = AF_UNSPEC;
+ conn->tempfamily[1] = AF_UNSPEC;
#endif
+ }
+ else {
+ /* only one IP version is allowed */
+ conn->tempfamily[0] = (conn->ip_version == CURL_IPRESOLVE_V4) ?
+ AF_INET :
+#ifdef ENABLE_IPV6
+ AF_INET6;
+#else
+ AF_UNSPEC;
+#endif
+ conn->tempfamily[1] = AF_UNSPEC;
+
+ ainext(conn, 0, FALSE); /* find first address of the right type */
+ }
+
ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
- DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
+ DEBUGF(infof(data, "family0 == %s, family1 == %s",
conn->tempfamily[0] == AF_INET ? "v4" : "v6",
conn->tempfamily[1] == AF_INET ? "v4" : "v6"));
@@ -1448,11 +1473,9 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
}
c = find.found;
- if(connp) {
+ if(connp)
/* only store this if the caller cares for it */
*connp = c;
- c->data = data;
- }
return c->sock[FIRSTSOCKET];
}
return CURL_SOCKET_BAD;
diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h
index 566b353..1a055f5 100644
--- a/Utilities/cmcurl/lib/connect.h
+++ b/Utilities/cmcurl/lib/connect.h
@@ -54,7 +54,7 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
struct connectdata **connp);
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
- char *addr, long *port);
+ char *addr, int *port);
/*
* Check if a connection seems to be alive.
@@ -81,9 +81,9 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
void Curl_conninfo_remote(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t sockfd);
void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
- char *local_ip, long *local_port);
+ char *local_ip, int *local_port);
void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
- char *local_ip, long local_port);
+ char *local_ip, int local_port);
int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t sock);
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
index f179b81..a84ff54 100644
--- a/Utilities/cmcurl/lib/content_encoding.c
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -178,7 +178,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* Dynamically allocate a buffer for decompression because it's uncommonly
large to hold on the stack */
decomp = malloc(DSIZ);
- if(decomp == NULL)
+ if(!decomp)
return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
/* because the buffer size is fixed, iteratively decompress and transfer to
@@ -487,7 +487,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
*/
z->avail_in = (uInt) nbytes;
z->next_in = malloc(z->avail_in);
- if(z->next_in == NULL) {
+ if(!z->next_in) {
return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
}
memcpy(z->next_in, buf, z->avail_in);
@@ -509,7 +509,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
ssize_t hlen;
z->avail_in += (uInt) nbytes;
z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
- if(z->next_in == NULL) {
+ if(!z->next_in) {
return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
}
/* Append the new block of data to the previous one */
@@ -985,7 +985,8 @@ new_unencoding_writer(struct Curl_easy *data,
return writer;
}
-/* Write data using an unencoding writer stack. */
+/* Write data using an unencoding writer stack. "nbytes" is not
+ allowed to be 0. */
CURLcode Curl_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
const char *buf, size_t nbytes)
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
index 09fd092..b7531f7 100644
--- a/Utilities/cmcurl/lib/cookie.c
+++ b/Utilities/cmcurl/lib/cookie.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
@@ -95,7 +95,6 @@ Example set of cookies:
#include "strcase.h"
#include "curl_get_line.h"
#include "curl_memrchr.h"
-#include "inet_pton.h"
#include "parsedate.h"
#include "rand.h"
#include "rename.h"
@@ -105,6 +104,8 @@ Example set of cookies:
#include "curl_memory.h"
#include "memdebug.h"
+static void strstore(char **str, const char *newstr);
+
static void freecookie(struct Cookie *co)
{
free(co->expirestr);
@@ -129,12 +130,13 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
return FALSE;
- /* A lead char of cookie_domain is not '.'.
- RFC6265 4.1.2.3. The Domain Attribute says:
- For example, if the value of the Domain attribute is
- "example.com", the user agent will include the cookie in the Cookie
- header when making HTTP requests to example.com, www.example.com, and
- www.corp.example.com.
+ /*
+ * A lead char of cookie_domain is not '.'.
+ * RFC6265 4.1.2.3. The Domain Attribute says:
+ * For example, if the value of the Domain attribute is
+ * "example.com", the user agent will include the cookie in the Cookie
+ * header when making HTTP requests to example.com, www.example.com, and
+ * www.corp.example.com.
*/
if(hostname_len == cookie_domain_len)
return TRUE;
@@ -144,28 +146,6 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
}
/*
- * Return true if the given string is an IP(v4|v6) address.
- */
-static bool isip(const char *domain)
-{
- struct in_addr addr;
-#ifdef ENABLE_IPV6
- struct in6_addr addr6;
-#endif
-
- if(Curl_inet_pton(AF_INET, domain, &addr)
-#ifdef ENABLE_IPV6
- || Curl_inet_pton(AF_INET6, domain, &addr6)
-#endif
- ) {
- /* domain name given as IP address */
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
* matching cookie path and url path
* RFC6265 5.1.4 Paths and Path-Match
*/
@@ -193,19 +173,19 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
/* #-fragments are already cut off! */
if(0 == strlen(uri_path) || uri_path[0] != '/') {
- free(uri_path);
- uri_path = strdup("/");
+ strstore(&uri_path, "/");
if(!uri_path)
return FALSE;
}
- /* here, RFC6265 5.1.4 says
- 4. Output the characters of the uri-path from the first character up
- to, but not including, the right-most %x2F ("/").
- but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
- without redirect.
- Ignore this algorithm because /hoge is uri path for this case
- (uri path is not /).
+ /*
+ * here, RFC6265 5.1.4 says
+ * 4. Output the characters of the uri-path from the first character up
+ * to, but not including, the right-most %x2F ("/").
+ * but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
+ * without redirect.
+ * Ignore this algorithm because /hoge is uri path for this case
+ * (uri path is not /).
*/
uri_path_len = strlen(uri_path);
@@ -297,7 +277,7 @@ static size_t cookiehash(const char * const domain)
const char *top;
size_t len;
- if(!domain || isip(domain))
+ if(!domain || Curl_host_is_ipnum(domain))
return 0;
top = get_top_domain(domain, &len);
@@ -328,8 +308,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
/* RFC6265 5.2.4 The Path Attribute */
if(new_path[0] != '/') {
/* Let cookie-path be the default-path. */
- free(new_path);
- new_path = strdup("/");
+ strstore(&new_path, "/");
return new_path;
}
@@ -348,7 +327,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
*/
void Curl_cookie_loadfiles(struct Curl_easy *data)
{
- struct curl_slist *list = data->change.cookielist;
+ struct curl_slist *list = data->state.cookielist;
if(list) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
while(list) {
@@ -357,25 +336,29 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
data->cookies,
data->set.cookiesession);
if(!newcookies)
- /* Failure may be due to OOM or a bad cookie; both are ignored
+ /*
+ * Failure may be due to OOM or a bad cookie; both are ignored
* but only the first should be
*/
- infof(data, "ignoring failed cookie_init for %s\n", list->data);
+ infof(data, "ignoring failed cookie_init for %s", list->data);
else
data->cookies = newcookies;
list = list->next;
}
- curl_slist_free_all(data->change.cookielist); /* clean up list */
- data->change.cookielist = NULL; /* don't do this again! */
+ curl_slist_free_all(data->state.cookielist); /* clean up list */
+ data->state.cookielist = NULL; /* don't do this again! */
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
}
/*
- * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
- * that will be freed before the allocated string is stored there.
+ * strstore
*
- * It is meant to easily replace strdup()
+ * A thin wrapper around strdup which ensures that any memory allocated at
+ * *str will be freed before the string allocated by strdup is stored there.
+ * The intended usecase is repeated assignments to the same variable during
+ * parsing in a last-wins scenario. The caller is responsible for checking
+ * for OOM errors.
*/
static void strstore(char **str, const char *newstr)
{
@@ -384,7 +367,13 @@ static void strstore(char **str, const char *newstr)
}
/*
- * remove_expired() removes expired cookies.
+ * remove_expired
+ *
+ * Remove expired cookies from the hash by inspecting the expires timestamp on
+ * each cookie in the hash, freeing and deleting any where the timestamp is in
+ * the past. If the cookiejar has recorded the next timestamp at which one or
+ * more cookies expire, then processing will exit early in case this timestamp
+ * is in the future.
*/
static void remove_expired(struct CookieInfo *cookies)
{
@@ -392,6 +381,20 @@ static void remove_expired(struct CookieInfo *cookies)
curl_off_t now = (curl_off_t)time(NULL);
unsigned int i;
+ /*
+ * If the earliest expiration timestamp in the jar is in the future we can
+ * skip scanning the whole jar and instead exit early as there won't be any
+ * cookies to evict. If we need to evict however, reset the next_expiration
+ * counter in order to track the next one. In case the recorded first
+ * expiration is the max offset, then perform the safe fallback of checking
+ * all cookies.
+ */
+ if(now < cookies->next_expiration &&
+ cookies->next_expiration != CURL_OFF_T_MAX)
+ return;
+ else
+ cookies->next_expiration = CURL_OFF_T_MAX;
+
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
struct Cookie *pv = NULL;
co = cookies->cookies[i];
@@ -408,6 +411,12 @@ static void remove_expired(struct CookieInfo *cookies)
freecookie(co);
}
else {
+ /*
+ * If this cookie has an expiration timestamp earlier than what we've
+ * seen so far then record it for the next round of expirations.
+ */
+ if(co->expires && co->expires < cookies->next_expiration)
+ cookies->next_expiration = co->expires;
pv = co;
}
co = nx;
@@ -421,25 +430,23 @@ static bool bad_domain(const char *domain)
return !strchr(domain, '.') && !strcasecompare(domain, "localhost");
}
-/****************************************************************************
- *
- * Curl_cookie_add()
- *
- * Add a single cookie line to the cookie keeping object.
+/*
+ * Curl_cookie_add
*
- * Be aware that sometimes we get an IP-only host name, and that might also be
- * a numerical IPv6 address.
+ * Add a single cookie line to the cookie keeping object. Be aware that
+ * sometimes we get an IP-only host name, and that might also be a numerical
+ * IPv6 address.
*
* Returns NULL on out of memory or invalid cookie. This is suboptimal,
* as they should be treated separately.
- ***************************************************************************/
-
+ */
struct Cookie *
Curl_cookie_add(struct Curl_easy *data,
- /* The 'data' pointer here may be NULL at times, and thus
- must only be used very carefully for things that can deal
- with data being NULL. Such as infof() and similar */
-
+ /*
+ * The 'data' pointer here may be NULL at times, and thus
+ * must only be used very carefully for things that can deal
+ * with data being NULL. Such as infof() and similar
+ */
struct CookieInfo *c,
bool httpheader, /* TRUE if HTTP header-style line */
bool noexpire, /* if TRUE, skip remove_expired() */
@@ -493,9 +500,11 @@ Curl_cookie_add(struct Curl_easy *data,
if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
MAX_NAME_TXT "[^;\r\n]",
name, what)) {
- /* Use strstore() below to properly deal with received cookie
- headers that have the same string property set more than once,
- and then we use the last one. */
+ /*
+ * Use strstore() below to properly deal with received cookie
+ * headers that have the same string property set more than once,
+ * and then we use the last one.
+ */
const char *whatptr;
bool done = FALSE;
bool sep;
@@ -503,13 +512,15 @@ Curl_cookie_add(struct Curl_easy *data,
size_t nlen = strlen(name);
const char *endofn = &ptr[ nlen ];
+ /*
+ * Check for too long individual name or contents, or too long
+ * combination of name + contents. Chrome and Firefox support 4095 or
+ * 4096 bytes combo
+ */
if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
((nlen + len) > MAX_NAME)) {
- /* too long individual name or contents, or too long combination of
- name + contents. Chrome and Firefox support 4095 or 4096 bytes
- combo. */
freecookie(co);
- infof(data, "oversized cookie dropped, name/val %zu + %zu bytes\n",
+ infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
nlen, len);
return NULL;
}
@@ -569,8 +580,10 @@ Curl_cookie_add(struct Curl_easy *data,
}
}
else if(!len) {
- /* this was a "<name>=" with no content, and we must allow
- 'secure' and 'httponly' specified this weirdly */
+ /*
+ * this was a "<name>=" with no content, and we must allow
+ * 'secure' and 'httponly' specified this weirdly
+ */
done = TRUE;
/*
* secure cookies are only allowed to be set when the connection is
@@ -610,8 +623,10 @@ Curl_cookie_add(struct Curl_easy *data,
else if(strcasecompare("domain", name)) {
bool is_ip;
- /* Now, we make sure that our host is within the given domain,
- or the given domain is not valid and thus cannot be set. */
+ /*
+ * Now, we make sure that our host is within the given domain, or
+ * the given domain is not valid and thus cannot be set.
+ */
if('.' == whatptr[0])
whatptr++; /* ignore preceding dot */
@@ -626,7 +641,7 @@ Curl_cookie_add(struct Curl_easy *data,
domain = ":";
#endif
- is_ip = isip(domain ? domain : whatptr);
+ is_ip = Curl_host_is_ipnum(domain ? domain : whatptr);
if(!domain
|| (is_ip && !strcmp(whatptr, domain))
@@ -641,11 +656,12 @@ Curl_cookie_add(struct Curl_easy *data,
given */
}
else {
- /* we did not get a tailmatch and then the attempted set domain
- is not a domain to which the current host belongs. Mark as
- bad. */
+ /*
+ * We did not get a tailmatch and then the attempted set domain is
+ * not a domain to which the current host belongs. Mark as bad.
+ */
badcookie = TRUE;
- infof(data, "skipped cookie with bad tailmatch domain: %s\n",
+ infof(data, "skipped cookie with bad tailmatch domain: %s",
whatptr);
}
}
@@ -657,15 +673,15 @@ Curl_cookie_add(struct Curl_easy *data,
}
}
else if(strcasecompare("max-age", name)) {
- /* Defined in RFC2109:
-
- Optional. The Max-Age attribute defines the lifetime of the
- cookie, in seconds. The delta-seconds value is a decimal non-
- negative integer. After delta-seconds seconds elapse, the
- client should discard the cookie. A value of zero means the
- cookie should be discarded immediately.
-
- */
+ /*
+ * Defined in RFC2109:
+ *
+ * Optional. The Max-Age attribute defines the lifetime of the
+ * cookie, in seconds. The delta-seconds value is a decimal non-
+ * negative integer. After delta-seconds seconds elapse, the
+ * client should discard the cookie. A value of zero means the
+ * cookie should be discarded immediately.
+ */
strstore(&co->maxage, whatptr);
if(!co->maxage) {
badcookie = TRUE;
@@ -679,9 +695,10 @@ Curl_cookie_add(struct Curl_easy *data,
break;
}
}
+
/*
- else this is the second (or more) name we don't know
- about! */
+ * Else, this is the second (or more) name we don't know about!
+ */
}
else {
/* this is an "illegal" <what>=<this> pair */
@@ -699,8 +716,10 @@ Curl_cookie_add(struct Curl_easy *data,
semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
if(!semiptr && *ptr)
- /* There are no more semicolons, but there's a final name=value pair
- coming up */
+ /*
+ * There are no more semicolons, but there's a final name=value pair
+ * coming up
+ */
semiptr = strchr(ptr, '\0');
} while(semiptr);
@@ -724,13 +743,16 @@ Curl_cookie_add(struct Curl_easy *data,
}
}
else if(co->expirestr) {
- /* Note that if the date couldn't get parsed for whatever reason,
- the cookie will be treated as a session cookie */
+ /*
+ * Note that if the date couldn't get parsed for whatever reason, the
+ * cookie will be treated as a session cookie
+ */
co->expires = Curl_getdate_capped(co->expirestr);
- /* Session cookies have expires set to 0 so if we get that back
- from the date parser let's add a second to make it a
- non-session cookie */
+ /*
+ * Session cookies have expires set to 0 so if we get that back from the
+ * date parser let's add a second to make it a non-session cookie
+ */
if(co->expires == 0)
co->expires = 1;
else if(co->expires < 0)
@@ -747,13 +769,17 @@ Curl_cookie_add(struct Curl_easy *data,
}
if(!badcookie && !co->path && path) {
- /* No path was given in the header line, set the default.
- Note that the passed-in path to this function MAY have a '?' and
- following part that MUST not be stored as part of the path. */
+ /*
+ * No path was given in the header line, set the default. Note that the
+ * passed-in path to this function MAY have a '?' and following part that
+ * MUST NOT be stored as part of the path.
+ */
char *queryp = strchr(path, '?');
- /* queryp is where the interesting part of the path ends, so now we
- want to the find the last */
+ /*
+ * queryp is where the interesting part of the path ends, so now we
+ * want to the find the last
+ */
char *endslash;
if(!queryp)
endslash = strrchr(path, '/');
@@ -774,29 +800,34 @@ Curl_cookie_add(struct Curl_easy *data,
}
}
+ /*
+ * If we didn't get a cookie name, or a bad one, the this is an illegal
+ * line so bail out.
+ */
if(badcookie || !co->name) {
- /* we didn't get a cookie name or a bad one,
- this is an illegal line, bail out */
freecookie(co);
return NULL;
}
}
else {
- /* This line is NOT a HTTP header style line, we do offer support for
- reading the odd netscape cookies-file format here */
+ /*
+ * This line is NOT a HTTP header style line, we do offer support for
+ * reading the odd netscape cookies-file format here
+ */
char *ptr;
char *firstptr;
char *tok_buf = NULL;
int fields;
- /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
- marked with httpOnly after the domain name are not accessible
- from javascripts, but since curl does not operate at javascript
- level, we include them anyway. In Firefox's cookie files, these
- lines are preceded with #HttpOnly_ and then everything is
- as usual, so we skip 10 characters of the line..
- */
+ /*
+ * IE introduced HTTP-only cookies to prevent XSS attacks. Cookies marked
+ * with httpOnly after the domain name are not accessible from javascripts,
+ * but since curl does not operate at javascript level, we include them
+ * anyway. In Firefox's cookie files, these lines are preceded with
+ * #HttpOnly_ and then everything is as usual, so we skip 10 characters of
+ * the line..
+ */
if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
lineptr += 10;
co->httponly = TRUE;
@@ -817,8 +848,10 @@ Curl_cookie_add(struct Curl_easy *data,
firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
- /* Now loop through the fields and init the struct we already have
- allocated */
+ /*
+ * Now loop through the fields and init the struct we already have
+ * allocated
+ */
for(ptr = firstptr, fields = 0; ptr && !badcookie;
ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
switch(fields) {
@@ -830,10 +863,11 @@ Curl_cookie_add(struct Curl_easy *data,
badcookie = TRUE;
break;
case 1:
- /* flag: A TRUE/FALSE value indicating if all machines within a given
- domain can access the variable. Set TRUE when the cookie says
- .domain.com and to false when the domain is complete www.domain.com
- */
+ /*
+ * flag: A TRUE/FALSE value indicating if all machines within a given
+ * domain can access the variable. Set TRUE when the cookie says
+ * .domain.com and to false when the domain is complete www.domain.com
+ */
co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
break;
case 2:
@@ -942,17 +976,23 @@ Curl_cookie_add(struct Curl_easy *data,
co->livecookie = c->running;
co->creationtime = ++c->lastct;
- /* now, we have parsed the incoming line, we must now check if this
- supersedes an already existing cookie, which it may if the previous have
- the same domain and path as this */
+ /*
+ * Now we have parsed the incoming line, we must now check if this supersedes
+ * an already existing cookie, which it may if the previous have the same
+ * domain and path as this.
+ */
/* at first, remove expired cookies */
if(!noexpire)
remove_expired(c);
#ifdef USE_LIBPSL
- /* Check if the domain is a Public Suffix and if yes, ignore the cookie. */
- if(domain && co->domain && !isip(co->domain)) {
+ /*
+ * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
+ * must also check that the data handle isn't NULL since the psl code will
+ * dereference it.
+ */
+ if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
const psl_ctx_t *psl = Curl_psl_use(data);
int acceptable;
@@ -965,7 +1005,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(!acceptable) {
infof(data, "cookie '%s' dropped, domain '%s' must not "
- "set cookies for '%s'\n", co->name, domain, co->domain);
+ "set cookies for '%s'", co->name, domain, co->domain);
freecookie(co);
return NULL;
}
@@ -1028,12 +1068,12 @@ Curl_cookie_add(struct Curl_easy *data,
}
if(replace_old && !co->livecookie && clist->livecookie) {
- /* Both cookies matched fine, except that the already present
- cookie is "live", which means it was set from a header, while
- the new one isn't "live" and thus only read from a file. We let
- live cookies stay alive */
-
- /* Free the newcomer and get out of here! */
+ /*
+ * Both cookies matched fine, except that the already present cookie is
+ * "live", which means it was set from a header, while the new one was
+ * read from a file and thus isn't "live". "live" cookies are preferred
+ * so the new cookie is freed.
+ */
freecookie(co);
return NULL;
}
@@ -1059,8 +1099,10 @@ Curl_cookie_add(struct Curl_easy *data,
free(co); /* free the newly allocated memory */
co = clist; /* point to the previous struct instead */
- /* We have replaced a cookie, now skip the rest of the list but
- make sure the 'lastc' pointer is properly set */
+ /*
+ * We have replaced a cookie, now skip the rest of the list but make
+ * sure the 'lastc' pointer is properly set
+ */
do {
lastc = clist;
clist = clist->next;
@@ -1075,7 +1117,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(c->running)
/* Only show this when NOT reading the cookies from a file */
infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
- "expire %" CURL_FORMAT_CURL_OFF_T "\n",
+ "expire %" CURL_FORMAT_CURL_OFF_T,
replace_old?"Replaced":"Added", co->name, co->value,
co->domain, co->path, co->expires);
@@ -1088,23 +1130,30 @@ Curl_cookie_add(struct Curl_easy *data,
c->numcookies++; /* one more cookie in the jar */
}
+ /*
+ * Now that we've added a new cookie to the jar, update the expiration
+ * tracker in case it is the next one to expire.
+ */
+ if(co->expires && (co->expires < c->next_expiration))
+ c->next_expiration = co->expires;
+
return co;
}
-/*****************************************************************************
- *
+/*
* Curl_cookie_init()
*
* Inits a cookie struct to read data from a local file. This is always
- * called before any cookies are set. File may be NULL.
+ * called before any cookies are set. File may be NULL in which case only the
+ * struct is initialized. Is file is "-" then STDIN is read.
*
* If 'newsession' is TRUE, discard all "session cookies" on read from file.
*
* Note that 'data' might be called as NULL pointer.
*
* Returns NULL on out of memory. Invalid cookies are ignored.
- ****************************************************************************/
+ */
struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
const char *file,
struct CookieInfo *inc,
@@ -1123,6 +1172,11 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
c->filename = strdup(file?file:"none"); /* copy the name just in case */
if(!c->filename)
goto fail; /* failed to get memory */
+ /*
+ * Initialize the next_expiration time to signal that we don't have enough
+ * information yet.
+ */
+ c->next_expiration = CURL_OFF_T_MAX;
}
else {
/* we got an already existing one, use that */
@@ -1166,7 +1220,12 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
}
free(line); /* free the line buffer */
- remove_expired(c); /* run this once, not on every cookie */
+
+ /*
+ * Remove expired cookies from the hash. We must make sure to run this
+ * after reading the file, and not on every cookie.
+ */
+ remove_expired(c);
if(fromfile)
fclose(fp);
@@ -1180,16 +1239,25 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
fail:
free(line);
+ /*
+ * Only clean up if we allocated it here, as the original could still be in
+ * use by a share handle.
+ */
if(!inc)
- /* Only clean up if we allocated it here, as the original could still be in
- * use by a share handle */
Curl_cookie_cleanup(c);
if(fromfile && fp)
fclose(fp);
return NULL; /* out of memory */
}
-/* sort this so that the longest path gets before the shorter path */
+/*
+ * cookie_sort
+ *
+ * Helper function to sort cookies such that the longest path gets before the
+ * shorter path. Path, domain and name lengths are considered in that order,
+ * with the creationtime as the tiebreaker. The creationtime is guaranteed to
+ * be unique per cookie, so we know we will get an ordering at that point.
+ */
static int cookie_sort(const void *p1, const void *p2)
{
struct Cookie *c1 = *(struct Cookie **)p1;
@@ -1221,7 +1289,11 @@ static int cookie_sort(const void *p1, const void *p2)
return (c2->creationtime > c1->creationtime) ? 1 : -1;
}
-/* sort cookies only according to creation time */
+/*
+ * cookie_sort_ct
+ *
+ * Helper function to sort cookies according to creation time.
+ */
static int cookie_sort_ct(const void *p1, const void *p2)
{
struct Cookie *c1 = *(struct Cookie **)p1;
@@ -1265,18 +1337,15 @@ static struct Cookie *dup_cookie(struct Cookie *src)
return NULL;
}
-/*****************************************************************************
- *
- * Curl_cookie_getlist()
+/*
+ * Curl_cookie_getlist
*
- * For a given host and path, return a linked list of cookies that the
- * client should send to the server if used now. The secure boolean informs
- * the cookie if a secure connection is achieved or not.
+ * For a given host and path, return a linked list of cookies that the client
+ * should send to the server if used now. The secure boolean informs the cookie
+ * if a secure connection is achieved or not.
*
* It shall only return cookies that haven't expired.
- *
- ****************************************************************************/
-
+ */
struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
const char *host, const char *path,
bool secure)
@@ -1295,7 +1364,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
remove_expired(c);
/* check if host is an IP(v4|v6) address */
- is_ip = isip(host);
+ is_ip = Curl_host_is_ipnum(host);
co = c->cookies[myhash];
@@ -1307,15 +1376,21 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
if(!co->domain ||
(co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
- /* the right part of the host matches the domain stuff in the
- cookie data */
+ /*
+ * the right part of the host matches the domain stuff in the
+ * cookie data
+ */
- /* now check the left part of the path with the cookies path
- requirement */
+ /*
+ * now check the left part of the path with the cookies path
+ * requirement
+ */
if(!co->spath || pathmatch(co->spath, path) ) {
- /* and now, we know this is a match and we should create an
- entry for the return-linked-list */
+ /*
+ * and now, we know this is a match and we should create an
+ * entry for the return-linked-list
+ */
newco = dup_cookie(co);
if(newco) {
@@ -1336,9 +1411,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
}
if(matches) {
- /* Now we need to make sure that if there is a name appearing more than
- once, the longest specified path version comes first. To make this
- the swiftest way, we just sort them all based on path length. */
+ /*
+ * Now we need to make sure that if there is a name appearing more than
+ * once, the longest specified path version comes first. To make this
+ * the swiftest way, we just sort them all based on path length.
+ */
struct Cookie **array;
size_t i;
@@ -1373,13 +1450,11 @@ fail:
return NULL;
}
-/*****************************************************************************
- *
- * Curl_cookie_clearall()
+/*
+ * Curl_cookie_clearall
*
* Clear all existing cookies and reset the counter.
- *
- ****************************************************************************/
+ */
void Curl_cookie_clearall(struct CookieInfo *cookies)
{
if(cookies) {
@@ -1392,14 +1467,11 @@ void Curl_cookie_clearall(struct CookieInfo *cookies)
}
}
-/*****************************************************************************
- *
- * Curl_cookie_freelist()
+/*
+ * Curl_cookie_freelist
*
* Free a list of cookies previously returned by Curl_cookie_getlist();
- *
- ****************************************************************************/
-
+ */
void Curl_cookie_freelist(struct Cookie *co)
{
struct Cookie *next;
@@ -1410,14 +1482,11 @@ void Curl_cookie_freelist(struct Cookie *co)
}
}
-
-/*****************************************************************************
- *
- * Curl_cookie_clearsess()
+/*
+ * Curl_cookie_clearsess
*
* Free all session cookies in the cookies list.
- *
- ****************************************************************************/
+ */
void Curl_cookie_clearsess(struct CookieInfo *cookies)
{
struct Cookie *first, *curr, *next, *prev = NULL;
@@ -1454,14 +1523,11 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies)
}
}
-
-/*****************************************************************************
- *
+/*
* Curl_cookie_cleanup()
*
* Free a "cookie object" previous created with Curl_cookie_init().
- *
- ****************************************************************************/
+ */
void Curl_cookie_cleanup(struct CookieInfo *c)
{
if(c) {
@@ -1473,12 +1539,13 @@ void Curl_cookie_cleanup(struct CookieInfo *c)
}
}
-/* get_netscape_format()
+/*
+ * get_netscape_format()
*
* Formats a string for Netscape output file, w/o a newline at the end.
- *
- * Function returns a char * to a formatted line. Has to be free()d
-*/
+ * Function returns a char * to a formatted line. The caller is responsible
+ * for freeing the returned pointer.
+ */
static char *get_netscape_format(const struct Cookie *co)
{
return aprintf(
@@ -1491,8 +1558,10 @@ static char *get_netscape_format(const struct Cookie *co)
"%s\t" /* name */
"%s", /* value */
co->httponly?"#HttpOnly_":"",
- /* Make sure all domains are prefixed with a dot if they allow
- tailmatching. This is Mozilla-style. */
+ /*
+ * Make sure all domains are prefixed with a dot if they allow
+ * tailmatching. This is Mozilla-style.
+ */
(co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
co->domain?co->domain:"unknown",
co->tailmatch?"TRUE":"FALSE",
@@ -1511,18 +1580,18 @@ static char *get_netscape_format(const struct Cookie *co)
*
* The function returns non-zero on write failure.
*/
-static int cookie_output(struct Curl_easy *data,
- struct CookieInfo *c, const char *filename)
+static CURLcode cookie_output(struct Curl_easy *data,
+ struct CookieInfo *c, const char *filename)
{
struct Cookie *co;
FILE *out = NULL;
bool use_stdout = FALSE;
char *tempstore = NULL;
- bool error = false;
+ CURLcode error = CURLE_OK;
if(!c)
/* no cookie engine alive */
- return 0;
+ return CURLE_OK;
/* at first, remove expired cookies */
remove_expired(c);
@@ -1540,11 +1609,13 @@ static int cookie_output(struct Curl_easy *data,
tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
if(!tempstore)
- return 1;
+ return CURLE_OUT_OF_MEMORY;
out = fopen(tempstore, FOPEN_WRITETEXT);
- if(!out)
+ if(!out) {
+ error = CURLE_WRITE_ERROR;
goto error;
+ }
}
fputs("# Netscape HTTP Cookie File\n"
@@ -1559,6 +1630,7 @@ static int cookie_output(struct Curl_easy *data,
array = calloc(1, sizeof(struct Cookie *) * c->numcookies);
if(!array) {
+ error = CURLE_OUT_OF_MEMORY;
goto error;
}
@@ -1575,9 +1647,9 @@ static int cookie_output(struct Curl_easy *data,
for(i = 0; i < nvalid; i++) {
char *format_ptr = get_netscape_format(array[i]);
- if(format_ptr == NULL) {
- fprintf(out, "#\n# Fatal libcurl error\n");
+ if(!format_ptr) {
free(array);
+ error = CURLE_OUT_OF_MEMORY;
goto error;
}
fprintf(out, "%s\n", format_ptr);
@@ -1592,18 +1664,24 @@ static int cookie_output(struct Curl_easy *data,
out = NULL;
if(Curl_rename(tempstore, filename)) {
unlink(tempstore);
+ error = CURLE_WRITE_ERROR;
goto error;
}
}
- goto cleanup;
+ /*
+ * If we reach here we have successfully written a cookie file so theree is
+ * no need to inspect the error, any error case should have jumped into the
+ * error block below.
+ */
+ free(tempstore);
+ return CURLE_OK;
+
error:
- error = true;
-cleanup:
if(out && !use_stdout)
fclose(out);
free(tempstore);
- return error ? 1 : 0;
+ return error;
}
static struct curl_slist *cookie_list(struct Curl_easy *data)
@@ -1614,8 +1692,7 @@ static struct curl_slist *cookie_list(struct Curl_easy *data)
char *line;
unsigned int i;
- if((data->cookies == NULL) ||
- (data->cookies->numcookies == 0))
+ if(!data->cookies || (data->cookies->numcookies == 0))
return NULL;
for(i = 0; i < COOKIE_HASH_SIZE; i++) {
@@ -1651,8 +1728,10 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
{
+ CURLcode res;
+
if(data->set.str[STRING_COOKIEJAR]) {
- if(data->change.cookielist) {
+ if(data->state.cookielist) {
/* If there is a list of cookie files to read, do it first so that
we have all the told files read before we write the new jar.
Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
@@ -1662,16 +1741,17 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
/* if we have a destination file for all the cookies to get dumped to */
- if(cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]))
- infof(data, "WARNING: failed to save cookies in %s\n",
- data->set.str[STRING_COOKIEJAR]);
+ res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]);
+ if(res)
+ infof(data, "WARNING: failed to save cookies in %s: %s",
+ data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res));
}
else {
- if(cleanup && data->change.cookielist) {
+ if(cleanup && data->state.cookielist) {
/* since nothing is written, we can just free the list of cookie file
names */
- curl_slist_free_all(data->change.cookielist); /* clean up list */
- data->change.cookielist = NULL;
+ curl_slist_free_all(data->state.cookielist); /* clean up list */
+ data->state.cookielist = NULL;
}
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
}
diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h
index e0aa383..0ffe08e 100644
--- a/Utilities/cmcurl/lib/cookie.h
+++ b/Utilities/cmcurl/lib/cookie.h
@@ -65,6 +65,7 @@ struct CookieInfo {
bool running; /* state info, for cookie adding information */
bool newsession; /* new session, discard session cookies on load */
int lastct; /* last creation-time used in the jar */
+ curl_off_t next_expiration; /* the next time at which expiration happens */
};
/* This is the maximum line length we accept for a cookie line. RFC 2109
@@ -91,13 +92,13 @@ struct Curl_easy;
*/
struct Cookie *Curl_cookie_add(struct Curl_easy *data,
- struct CookieInfo *, bool header, bool noexpiry,
- char *lineptr,
+ struct CookieInfo *c, bool header,
+ bool noexpiry, char *lineptr,
const char *domain, const char *path,
bool secure);
-struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
- const char *, bool);
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, const char *host,
+ const char *path, bool secure);
void Curl_cookie_freelist(struct Cookie *cookies);
void Curl_cookie_clearall(struct CookieInfo *cookies);
void Curl_cookie_clearsess(struct CookieInfo *cookies);
@@ -110,9 +111,10 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies);
#define Curl_flush_cookies(x,y) Curl_nop_stmt
#else
void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
-void Curl_cookie_cleanup(struct CookieInfo *);
+void Curl_cookie_cleanup(struct CookieInfo *c);
struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
- const char *, struct CookieInfo *, bool);
+ const char *file, struct CookieInfo *inc,
+ bool newsession);
struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
void Curl_cookie_loadfiles(struct Curl_easy *data);
#endif
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c
index 06537b2..842fd7f 100644
--- a/Utilities/cmcurl/lib/curl_addrinfo.c
+++ b/Utilities/cmcurl/lib/curl_addrinfo.c
@@ -141,7 +141,7 @@ Curl_getaddrinfo_ex(const char *nodename,
continue;
/* ignore elements without required address info */
- if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0))
+ if(!ai->ai_addr || !(ai->ai_addrlen > 0))
continue;
/* ignore elements with bogus address size */
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
index 8dfe328..de03550 100644
--- a/Utilities/cmcurl/lib/curl_config.h.cmake
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -26,61 +26,91 @@
/* when building libcurl itself */
#cmakedefine BUILDING_LIBCURL 1
-/* to disable cookies support */
+/* to disable 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 */
@@ -91,7 +121,7 @@
#endif
/* Allow SMB to work on Windows */
-#cmakedefine USE_WIN32_CRYPTO
+#cmakedefine USE_WIN32_CRYPTO 1
/* Use Windows LDAP implementation */
#cmakedefine USE_WIN32_LDAP 1
@@ -105,27 +135,6 @@
/* Define if you want to enable IPv6 support */
#cmakedefine ENABLE_IPV6 1
-/* Define to the type qualifier of arg 1 for getnameinfo. */
-#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1}
-
-/* Define to the type of arg 1 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1}
-
-/* Define to the type of arg 2 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2}
-
-/* Define to the type of args 4 and 6 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46}
-
-/* Define to the type of arg 7 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7}
-
-/* Specifies the number of arguments to getservbyport_r */
-#cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS}
-
-/* Specifies the size of the buffer to pass to getservbyport_r */
-#cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE}
-
/* Define to 1 if you have the alarm function. */
#cmakedefine HAVE_ALARM 1
@@ -159,18 +168,12 @@
/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
-/* Define to 1 if you have the <crypto.h> header file. */
-#cmakedefine HAVE_CRYPTO_H 1
-
/* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H 1
/* Define to 1 if you have the <errno.h> header file. */
#cmakedefine HAVE_ERRNO_H 1
-/* Define to 1 if you have the <err.h> header file. */
-#cmakedefine HAVE_ERR_H 1
-
/* Define to 1 if you have the fcntl function. */
#cmakedefine HAVE_FCNTL 1
@@ -180,18 +183,9 @@
/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
#cmakedefine HAVE_FCNTL_O_NONBLOCK 1
-/* Define to 1 if you have the fdopen function. */
-#cmakedefine HAVE_FDOPEN 1
-
-/* Define to 1 if you have the `fork' function. */
-#cmakedefine HAVE_FORK 1
-
/* Define to 1 if you have the freeaddrinfo function. */
#cmakedefine HAVE_FREEADDRINFO 1
-/* Define to 1 if you have the freeifaddrs function. */
-#cmakedefine HAVE_FREEIFADDRS 1
-
/* Define to 1 if you have the ftruncate function. */
#cmakedefine HAVE_FTRUNCATE 1
@@ -201,20 +195,8 @@
/* Define to 1 if you have the `geteuid' function. */
#cmakedefine HAVE_GETEUID 1
-/* Define to 1 if you have the gethostbyaddr function. */
-#cmakedefine HAVE_GETHOSTBYADDR 1
-
-/* Define to 1 if you have the gethostbyaddr_r function. */
-#cmakedefine HAVE_GETHOSTBYADDR_R 1
-
-/* gethostbyaddr_r() takes 5 args */
-#cmakedefine HAVE_GETHOSTBYADDR_R_5 1
-
-/* gethostbyaddr_r() takes 7 args */
-#cmakedefine HAVE_GETHOSTBYADDR_R_7 1
-
-/* gethostbyaddr_r() takes 8 args */
-#cmakedefine HAVE_GETHOSTBYADDR_R_8 1
+/* Define to 1 if you have the `getppid' function. */
+#cmakedefine HAVE_GETPPID 1
/* Define to 1 if you have the gethostbyname function. */
#cmakedefine HAVE_GETHOSTBYNAME 1
@@ -237,9 +219,6 @@
/* Define to 1 if you have a working getifaddrs function. */
#cmakedefine HAVE_GETIFADDRS 1
-/* Define to 1 if you have the getnameinfo function. */
-#cmakedefine HAVE_GETNAMEINFO 1
-
/* Define to 1 if you have the `getpass_r' function. */
#cmakedefine HAVE_GETPASS_R 1
@@ -267,9 +246,6 @@
/* Define to 1 if you have the `getrlimit' function. */
#cmakedefine HAVE_GETRLIMIT 1
-/* Define to 1 if you have the getservbyport_r function. */
-#cmakedefine HAVE_GETSERVBYPORT_R 1
-
/* Define to 1 if you have the `gettimeofday' function. */
#cmakedefine HAVE_GETTIMEOFDAY 1
@@ -315,21 +291,18 @@
/* Define to 1 if you have the `inet_addr' function. */
#cmakedefine HAVE_INET_ADDR 1
-/* Define to 1 if you have the inet_ntoa_r function. */
-#cmakedefine HAVE_INET_NTOA_R 1
-
-/* inet_ntoa_r() takes 2 args */
-#cmakedefine HAVE_INET_NTOA_R_2 1
-
-/* inet_ntoa_r() takes 3 args */
-#cmakedefine HAVE_INET_NTOA_R_3 1
-
/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
#cmakedefine HAVE_INET_NTOP 1
/* Define to 1 if you have a IPv6 capable working inet_pton function. */
#cmakedefine HAVE_INET_PTON 1
+/* Define to 1 if symbol `sa_family_t' exists */
+#cmakedefine HAVE_SA_FAMILY_T 1
+
+/* Define to 1 if symbol `ADDRESS_FAMILY' exists */
+#cmakedefine HAVE_ADDRESS_FAMILY 1
+
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
@@ -406,21 +379,6 @@
/* Define to 1 if you have the `ssh2' library (-lssh2). */
#cmakedefine HAVE_LIBSSH2 1
-/* Define to 1 if libssh2 provides `libssh2_version'. */
-#cmakedefine HAVE_LIBSSH2_VERSION 1
-
-/* Define to 1 if libssh2 provides `libssh2_init'. */
-#cmakedefine HAVE_LIBSSH2_INIT 1
-
-/* Define to 1 if libssh2 provides `libssh2_exit'. */
-#cmakedefine HAVE_LIBSSH2_EXIT 1
-
-/* Define to 1 if libssh2 provides `libssh2_scp_send64'. */
-#cmakedefine HAVE_LIBSSH2_SCP_SEND64 1
-
-/* Define to 1 if libssh2 provides `libssh2_session_handshake'. */
-#cmakedefine HAVE_LIBSSH2_SESSION_HANDSHAKE 1
-
/* Define to 1 if you have the <libssh2.h> header file. */
#cmakedefine HAVE_LIBSSH2_H 1
@@ -501,9 +459,6 @@
/* Define to 1 if you have the <pem.h> header file. */
#cmakedefine HAVE_PEM_H 1
-/* Define to 1 if you have the `perror' function. */
-#cmakedefine HAVE_PERROR 1
-
/* Define to 1 if you have the `pipe' function. */
#cmakedefine HAVE_PIPE 1
@@ -540,9 +495,6 @@
/* Define to 1 if you have the recvfrom function. */
#cmakedefine HAVE_RECVFROM 1
-/* Define to 1 if you have the <rsa.h> header file. */
-#cmakedefine HAVE_RSA_H 1
-
/* Define to 1 if you have the select function. */
#cmakedefine HAVE_SELECT 1
@@ -576,9 +528,6 @@
/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1
-/* Define to 1 if you have the <sgtty.h> header file. */
-#cmakedefine HAVE_SGTTY_H 1
-
/* Define to 1 if you have the sigaction function. */
#cmakedefine HAVE_SIGACTION 1
@@ -594,12 +543,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
@@ -645,15 +588,6 @@
/* Define to 1 if you have the <string.h> header file. */
#cmakedefine HAVE_STRING_H 1
-/* Define to 1 if you have the strlcat function. */
-#cmakedefine HAVE_STRLCAT 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-#cmakedefine HAVE_STRLCPY 1
-
-/* Define to 1 if you have the strncasecmp function. */
-#cmakedefine HAVE_STRNCASECMP 1
-
/* Define to 1 if you have the strncmpi function. */
#cmakedefine HAVE_STRNCMPI 1
@@ -744,6 +678,9 @@
/* Define to 1 if you have the `utime' function. */
#cmakedefine HAVE_UTIME 1
+/* Define to 1 if you have the `utimes' function. */
+#cmakedefine HAVE_UTIMES 1
+
/* Define to 1 if you have the <utime.h> header file. */
#cmakedefine HAVE_UTIME_H 1
@@ -871,9 +808,6 @@
/* Define to the function return type for recv. */
#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
-/* Define as the return type of signal handlers (`int' or `void'). */
-#cmakedefine RETSIGTYPE ${RETSIGTYPE}
-
/* Define to the type qualifier of arg 5 for select. */
#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5}
@@ -966,9 +900,6 @@ ${SIZEOF_TIME_T_CODE}
/* Define if you want to enable WIN32 threaded DNS lookup */
#cmakedefine USE_THREADS_WIN32 1
-/* Define to disable non-blocking sockets. */
-#cmakedefine USE_BLOCKING_SOCKETS 1
-
/* if GnuTLS is enabled */
#cmakedefine USE_GNUTLS 1
@@ -1027,9 +958,6 @@ ${SIZEOF_TIME_T_CODE}
/* if Unix domain sockets are enabled */
#cmakedefine USE_UNIX_SOCKETS
-/* to disable alt-svc */
-#cmakedefine CURL_DISABLE_ALTSVC 1
-
/* to enable SSPI support */
#cmakedefine USE_WINDOWS_SSPI 1
@@ -1089,3 +1017,9 @@ ${SIZEOF_TIME_T_CODE}
/* Define to 1 if you have the mach_absolute_time function. */
#cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
+
+/* to enable Windows IDN */
+#cmakedefine USE_WIN32_IDN 1
+
+/* to make the compiler know the prototypes of Windows IDN APIs */
+#cmakedefine WANT_IDN_PROTOTYPES 1
diff --git a/Utilities/cmcurl/lib/curl_endian.c b/Utilities/cmcurl/lib/curl_endian.c
index 2fc25bc..ecde74b 100644
--- a/Utilities/cmcurl/lib/curl_endian.c
+++ b/Utilities/cmcurl/lib/curl_endian.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
@@ -80,45 +80,3 @@ unsigned short Curl_read16_be(const unsigned char *buf)
return (unsigned short)(((unsigned short)buf[0] << 8) |
((unsigned short)buf[1]));
}
-
-#if (CURL_SIZEOF_CURL_OFF_T > 4)
-/*
- * write32_le()
- *
- * This function converts a 32-bit integer from the native endian format,
- * to little endian format ready for sending down the wire.
- *
- * Parameters:
- *
- * value [in] - The 32-bit integer value.
- * buffer [in] - A pointer to the output buffer.
- */
-static void write32_le(const int value, unsigned char *buffer)
-{
- buffer[0] = (char)(value & 0x000000FF);
- buffer[1] = (char)((value & 0x0000FF00) >> 8);
- buffer[2] = (char)((value & 0x00FF0000) >> 16);
- buffer[3] = (char)((value & 0xFF000000) >> 24);
-}
-
-/*
- * Curl_write64_le()
- *
- * This function converts a 64-bit integer from the native endian format,
- * to little endian format ready for sending down the wire.
- *
- * Parameters:
- *
- * value [in] - The 64-bit integer value.
- * buffer [in] - A pointer to the output buffer.
- */
-#if defined(HAVE_LONGLONG)
-void Curl_write64_le(const long long value, unsigned char *buffer)
-#else
-void Curl_write64_le(const __int64 value, unsigned char *buffer)
-#endif
-{
- write32_le((int)value, buffer);
- write32_le((int)(value >> 32), buffer + 4);
-}
-#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */
diff --git a/Utilities/cmcurl/lib/curl_endian.h b/Utilities/cmcurl/lib/curl_endian.h
index 341dfaf..4e12d7d 100644
--- a/Utilities/cmcurl/lib/curl_endian.h
+++ b/Utilities/cmcurl/lib/curl_endian.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
@@ -31,7 +31,7 @@ unsigned int Curl_read32_le(const unsigned char *buf);
/* Converts a 16-bit integer from big endian */
unsigned short Curl_read16_be(const unsigned char *buf);
-#if (CURL_SIZEOF_CURL_OFF_T > 4)
+#if (SIZEOF_CURL_OFF_T > 4)
/* Converts a 64-bit integer to little endian */
#if defined(HAVE_LONGLONG)
void Curl_write64_le(const long long value, unsigned char *buffer);
diff --git a/Utilities/cmcurl/lib/curl_get_line.c b/Utilities/cmcurl/lib/curl_get_line.c
index 438ede7..8f3b0bd 100644
--- a/Utilities/cmcurl/lib/curl_get_line.c
+++ b/Utilities/cmcurl/lib/curl_get_line.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
@@ -23,7 +23,7 @@
#include "curl_setup.h"
#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \
- defined(USE_HSTS)
+ !defined(CURL_DISABLE_HSTS)
#include "curl_get_line.h"
#include "curl_memory.h"
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
index 6445fba..5810dad 100644
--- a/Utilities/cmcurl/lib/curl_gssapi.c
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -59,7 +59,7 @@ OM_uint32 Curl_gss_init_sec_context(
req_flags |= GSS_C_DELEG_POLICY_FLAG;
#else
infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
- "compiled in\n");
+ "compiled in");
#endif
}
@@ -102,7 +102,7 @@ static size_t display_gss_error(OM_uint32 status, int type,
(char *)status_string.value);
}
gss_release_buffer(&min_stat, &status_string);
- } while(!GSS_ERROR(maj_stat) && msg_ctx != 0);
+ } while(!GSS_ERROR(maj_stat) && msg_ctx);
return len;
}
@@ -130,7 +130,7 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
- infof(data, "%s%s\n", prefix, buf);
+ infof(data, "%s%s", prefix, buf);
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
(void)prefix;
diff --git a/Utilities/cmcurl/lib/curl_krb5.h b/Utilities/cmcurl/lib/curl_krb5.h
index 3f40f9a..ca06840 100644
--- a/Utilities/cmcurl/lib/curl_krb5.h
+++ b/Utilities/cmcurl/lib/curl_krb5.h
@@ -29,7 +29,6 @@ struct Curl_sec_client_mech {
int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
void (*end)(void *);
int (*check_prot)(void *, int);
- int (*overhead)(void *, int, int);
int (*encode)(void *, const void *, int, int, void **);
int (*decode)(void *, void *, int, int, struct connectdata *);
};
diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c
index d327c8b..e9d2a8c 100644
--- a/Utilities/cmcurl/lib/curl_multibyte.c
+++ b/Utilities/cmcurl/lib/curl_multibyte.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
@@ -21,7 +21,11 @@
***************************************************************************/
/*
- * This file is 'mem-include-scan' clean. See test 1132.
+ * This file is 'mem-include-scan' clean, which means memdebug.h and
+ * curl_memory.h are purposely not included in this file. See test 1132.
+ *
+ * The functions in this file are curlx functions which are not tracked by the
+ * curl memory tracker memdebug.
*/
#include "curl_setup.h"
@@ -82,6 +86,34 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
+int curlx_win32_open(const char *filename, int oflag, ...)
+{
+ int pmode = 0;
+
+#ifdef _UNICODE
+ int result = -1;
+ wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+#endif
+
+ va_list param;
+ va_start(param, oflag);
+ if(oflag & O_CREAT)
+ pmode = va_arg(param, int);
+ va_end(param);
+
+#ifdef _UNICODE
+ if(filename_w) {
+ result = _wopen(filename_w, oflag, pmode);
+ free(filename_w);
+ }
+ else
+ errno = EINVAL;
+ return result;
+#else
+ return (_open)(filename, oflag, pmode);
+#endif
+}
+
FILE *curlx_win32_fopen(const char *filename, const char *mode)
{
#ifdef _UNICODE
@@ -90,64 +122,56 @@ FILE *curlx_win32_fopen(const char *filename, const char *mode)
wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
if(filename_w && mode_w)
result = _wfopen(filename_w, mode_w);
+ else
+ errno = EINVAL;
free(filename_w);
free(mode_w);
- if(result)
- return result;
-#endif
-
+ return result;
+#else
return (fopen)(filename, mode);
+#endif
}
int curlx_win32_stat(const char *path, struct_stat *buffer)
{
- int result = -1;
#ifdef _UNICODE
+ int result = -1;
wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
-#endif /* _UNICODE */
-
+ if(path_w) {
#if defined(USE_WIN32_SMALL_FILES)
-#if defined(_UNICODE)
- if(path_w)
result = _wstat(path_w, buffer);
- else
-#endif /* _UNICODE */
- result = _stat(path, buffer);
-#else /* USE_WIN32_SMALL_FILES */
-#if defined(_UNICODE)
- if(path_w)
+#else
result = _wstati64(path_w, buffer);
- else
-#endif /* _UNICODE */
- result = _stati64(path, buffer);
-#endif /* USE_WIN32_SMALL_FILES */
-
-#ifdef _UNICODE
- free(path_w);
#endif
-
+ free(path_w);
+ }
+ else
+ errno = EINVAL;
return result;
+#else
+#if defined(USE_WIN32_SMALL_FILES)
+ return _stat(path, buffer);
+#else
+ return _stati64(path, buffer);
+#endif
+#endif
}
int curlx_win32_access(const char *path, int mode)
{
- int result = -1;
-#ifdef _UNICODE
- wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
-#endif /* _UNICODE */
-
#if defined(_UNICODE)
- if(path_w)
- result = _waccess(path_w, mode);
- else
-#endif /* _UNICODE */
- result = _access(path, mode);
-
-#ifdef _UNICODE
+ int result = -1;
+ wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+ if(path_w) {
+ result = _waccess(path_w, mode);
free(path_w);
+ }
+ else
+ errno = EINVAL;
+ return result;
+#else
+ return _access(path, mode);
#endif
-
- return result;
}
#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
diff --git a/Utilities/cmcurl/lib/curl_multibyte.h b/Utilities/cmcurl/lib/curl_multibyte.h
index 8adaf49..491155e 100644
--- a/Utilities/cmcurl/lib/curl_multibyte.h
+++ b/Utilities/cmcurl/lib/curl_multibyte.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
@@ -31,7 +31,6 @@
wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
-
#endif /* WIN32 */
/*
@@ -40,29 +39,23 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
* preprocessor conditional directives needed by code using these
* to differentiate UNICODE from non-UNICODE builds.
*
- * When building with UNICODE defined, these two macros
- * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8()
- * return a pointer to a newly allocated memory area holding result.
- * When the result is no longer needed, allocated memory is intended
- * to be free'ed with curlx_unicodefree().
+ * In the case of a non-UNICODE build the tchar strings are char strings that
+ * are duplicated via strdup and remain in whatever the passed in encoding is,
+ * which is assumed to be UTF-8 but may be other encoding. Therefore the
+ * significance of the conversion functions is primarily for UNICODE builds.
+ *
+ * Allocated memory should be free'd with curlx_unicodefree().
*
- * When building without UNICODE defined, this macros
- * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8()
- * return the pointer received as argument. curlx_unicodefree() does
- * no actual free'ing of this pointer it is simply set to NULL.
+ * Note: Because these are curlx functions their memory usage is not tracked
+ * by the curl memory tracker memdebug. You'll notice that curlx function-like
+ * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to
+ * ensure that the curl memdebug override macros do not replace them.
*/
#if defined(UNICODE) && defined(WIN32)
#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
-#define curlx_unicodefree(ptr) \
- do { \
- if(ptr) { \
- (free)(ptr); \
- (ptr) = NULL; \
- } \
- } while(0)
typedef union {
unsigned short *tchar_ptr;
@@ -73,10 +66,8 @@ typedef union {
#else
-#define curlx_convert_UTF8_to_tchar(ptr) (ptr)
-#define curlx_convert_tchar_to_UTF8(ptr) (ptr)
-#define curlx_unicodefree(ptr) \
- do {(ptr) = NULL;} while(0)
+#define curlx_convert_UTF8_to_tchar(ptr) (strdup)(ptr)
+#define curlx_convert_tchar_to_UTF8(ptr) (strdup)(ptr)
typedef union {
char *tchar_ptr;
@@ -87,4 +78,12 @@ typedef union {
#endif /* UNICODE && WIN32 */
+#define curlx_unicodefree(ptr) \
+ do { \
+ if(ptr) { \
+ (free)(ptr); \
+ (ptr) = NULL; \
+ } \
+ } while(0)
+
#endif /* HEADER_CURL_MULTIBYTE_H */
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
index 9a075ac..749b44e 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.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
@@ -34,13 +34,12 @@
/* Please keep the SSL backend-specific #if branches in this order:
1. USE_OPENSSL
- 2. USE_GNUTLS_NETTLE
- 3. USE_GNUTLS
- 4. USE_NSS
- 5. USE_MBEDTLS
- 6. USE_SECTRANSP
- 7. USE_OS400CRYPTO
- 8. USE_WIN32_CRYPTO
+ 2. USE_GNUTLS
+ 3. USE_NSS
+ 4. USE_MBEDTLS
+ 5. USE_SECTRANSP
+ 6. USE_OS400CRYPTO
+ 7. USE_WIN32_CRYPTO
This ensures that:
- the same SSL branch gets activated throughout this source
@@ -74,13 +73,9 @@
# define DESKEY(x) &x
# endif
-#elif defined(USE_GNUTLS_NETTLE)
-
-# include <nettle/des.h>
-
#elif defined(USE_GNUTLS)
-# include <gcrypt.h>
+# include <nettle/des.h>
#elif defined(USE_NSS)
@@ -91,7 +86,6 @@
#elif defined(USE_MBEDTLS)
# include <mbedtls/des.h>
-# include "curl_md4.h"
#elif defined(USE_SECTRANSP)
@@ -159,7 +153,7 @@ static void setup_des_key(const unsigned char *key_56,
DES_set_key(&key, ks);
}
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
static void setup_des_key(const unsigned char *key_56,
struct des_ctx *des)
@@ -176,26 +170,6 @@ static void setup_des_key(const unsigned char *key_56,
des_set_key(des, (const uint8_t *) key);
}
-#elif defined(USE_GNUTLS)
-
-/*
- * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
- */
-static void setup_des_key(const unsigned char *key_56,
- gcry_cipher_hd_t *des)
-{
- char key[8];
-
- /* Expand the 56-bit key to 64-bits */
- extend_key_56_to_64(key_56, key);
-
- /* Set the key parity to odd */
- Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
-
- /* Set the key */
- gcry_cipher_setkey(*des, key, sizeof(key));
-}
-
#elif defined(USE_NSS)
/*
@@ -402,7 +376,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
setup_des_key(keys + 14, DESKEY(ks));
DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
DESKEY(ks), DES_ENCRYPT);
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
struct des_ctx des;
setup_des_key(keys, &des);
des_encrypt(&des, 8, results, plaintext);
@@ -410,23 +384,6 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
des_encrypt(&des, 8, results + 8, plaintext);
setup_des_key(keys + 14, &des);
des_encrypt(&des, 8, results + 16, plaintext);
-#elif defined(USE_GNUTLS)
- gcry_cipher_hd_t des;
-
- gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
- setup_des_key(keys, &des);
- gcry_cipher_encrypt(des, results, 8, plaintext, 8);
- gcry_cipher_close(des);
-
- gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
- setup_des_key(keys + 7, &des);
- gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8);
- gcry_cipher_close(des);
-
- gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
- setup_des_key(keys + 14, &des);
- gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
- gcry_cipher_close(des);
#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
encrypt_des(plaintext, results, keys);
@@ -473,24 +430,12 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
setup_des_key(pw + 7, DESKEY(ks));
DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
DESKEY(ks), DES_ENCRYPT);
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
struct des_ctx des;
setup_des_key(pw, &des);
des_encrypt(&des, 8, lmbuffer, magic);
setup_des_key(pw + 7, &des);
des_encrypt(&des, 8, lmbuffer + 8, magic);
-#elif defined(USE_GNUTLS)
- gcry_cipher_hd_t des;
-
- gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
- setup_des_key(pw, &des);
- gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
- gcry_cipher_close(des);
-
- gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
- setup_des_key(pw + 7, &des);
- gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
- gcry_cipher_close(des);
#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
|| defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
encrypt_des(magic, lmbuffer, pw);
@@ -552,21 +497,68 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
* network encoding not the host encoding.
*/
result = Curl_convert_to_network(data, (char *)pw, len * 2);
- if(result)
- return result;
-
- /* Create NT hashed password. */
- Curl_md4it(ntbuffer, pw, 2 * len);
-
- memset(ntbuffer + 16, 0, 21 - 16);
-
+ if(!result) {
+ /* Create NT hashed password. */
+ Curl_md4it(ntbuffer, pw, 2 * len);
+ memset(ntbuffer + 16, 0, 21 - 16);
+ }
free(pw);
- return CURLE_OK;
+ return result;
}
#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+/* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */
+struct ms_filetime {
+ unsigned int dwLowDateTime;
+ unsigned int dwHighDateTime;
+};
+
+/* Convert a time_t to an MS FILETIME (MS-DTYP section 2.3.3). */
+static void time2filetime(struct ms_filetime *ft, time_t t)
+{
+#if SIZEOF_TIME_T > 4
+ t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
+ ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
+ ft->dwHighDateTime = (unsigned int) (t >> 32);
+#else
+ unsigned int r, s;
+ unsigned int i;
+
+ ft->dwLowDateTime = t & 0xFFFFFFFF;
+ ft->dwHighDateTime = 0;
+
+# ifndef HAVE_TIME_T_UNSIGNED
+ /* Extend sign if needed. */
+ if(ft->dwLowDateTime & 0x80000000)
+ ft->dwHighDateTime = ~0;
+# endif
+
+ /* Bias seconds to Jan 1, 1601.
+ 134774 days = 11644473600 seconds = 0x2B6109100 */
+ r = ft->dwLowDateTime;
+ ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
+ ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02;
+
+ /* Convert to tenths of microseconds. */
+ ft->dwHighDateTime *= 10000000;
+ i = 32;
+ do {
+ i -= 8;
+ s = ((ft->dwLowDateTime >> i) & 0xFF) * (10000000 - 1);
+ r = (s << i) & 0xFFFFFFFF;
+ s >>= 1; /* Split shift to avoid width overflow. */
+ s >>= 31 - i;
+ ft->dwLowDateTime = (ft->dwLowDateTime + r) & 0xFFFFFFFF;
+ if(ft->dwLowDateTime < r)
+ s++;
+ ft->dwHighDateTime += s;
+ } while(i);
+ ft->dwHighDateTime &= 0xFFFFFFFF;
+#endif
+}
+
/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
* (uppercase UserName + Domain) as the data
*/
@@ -640,22 +632,18 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
unsigned int len = 0;
unsigned char *ptr = NULL;
unsigned char hmac_output[HMAC_MD5_LENGTH];
- curl_off_t tw;
+ struct ms_filetime tw;
CURLcode result = CURLE_OK;
-#if CURL_SIZEOF_CURL_OFF_T < 8
-#error "this section needs 64bit support to work"
-#endif
-
/* Calculate the timestamp */
#ifdef DEBUGBUILD
char *force_timestamp = getenv("CURL_FORCETIME");
if(force_timestamp)
- tw = CURL_OFF_T_C(11644473600) * 10000000;
+ time2filetime(&tw, (time_t) 0);
else
#endif
- tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000;
+ time2filetime(&tw, time(NULL));
/* Calculate the response len */
len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN;
@@ -667,13 +655,14 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
/* Create the BLOB structure */
msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN,
- "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
- "%c%c%c%c", /* Reserved = 0 */
+ "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
+ "%c%c%c%c" /* Reserved = 0 */
+ "%c%c%c%c%c%c%c%c", /* Timestamp */
NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
- 0, 0, 0, 0);
+ 0, 0, 0, 0,
+ LONGQUARTET(tw.dwLowDateTime), LONGQUARTET(tw.dwHighDateTime));
- Curl_write64_le(tw, ptr + 24);
memcpy(ptr + 32, challenge_client, 8);
memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h
index fab628c..02b39d4 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_core.h
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.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
@@ -30,7 +30,6 @@
then it must be initialized to be used by NTLM. */
#if !defined(USE_OPENSSL) && \
!defined(USE_WOLFSSL) && \
- !defined(USE_GNUTLS_NETTLE) && \
!defined(USE_GNUTLS) && \
defined(USE_NSS)
#define NTLM_NEEDS_NSS_INIT
@@ -48,19 +47,22 @@
#define USE_NTRESPONSES
/* Define USE_NTLM2SESSION in order to make the type-3 message include the
- NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and
- MD5 support */
-#if defined(USE_NTRESPONSES) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+ NTLM2Session response message, requires USE_NTRESPONSES defined to 1 */
+#if defined(USE_NTRESPONSES)
#define USE_NTLM2SESSION
#endif
/* Define USE_NTLM_V2 in order to allow the type-3 message to include the
- LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1
- and support for 64-bit integers. */
-#if defined(USE_NTRESPONSES) && (CURL_SIZEOF_CURL_OFF_T > 4)
+ LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 */
+#if defined(USE_NTRESPONSES)
#define USE_NTLM_V2
#endif
+/* Helpers to generate function byte arguments in little endian order */
+#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
+#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
+ ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
+
void Curl_ntlm_core_lm_resp(const unsigned char *keys,
const unsigned char *plaintext,
unsigned char *results);
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c
index 9af79fd..5a3bc3c 100644
--- a/Utilities/cmcurl/lib/curl_ntlm_wb.c
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c
@@ -355,17 +355,17 @@ CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
}
else {
if(*state == NTLMSTATE_LAST) {
- infof(data, "NTLM auth restarted\n");
+ infof(data, "NTLM auth restarted");
Curl_http_auth_cleanup_ntlm_wb(conn);
}
else if(*state == NTLMSTATE_TYPE3) {
- infof(data, "NTLM handshake rejected\n");
+ infof(data, "NTLM handshake rejected");
Curl_http_auth_cleanup_ntlm_wb(conn);
*state = NTLMSTATE_NONE;
return CURLE_REMOTE_ACCESS_DENIED;
}
else if(*state >= NTLMSTATE_TYPE1) {
- infof(data, "NTLM handshake failure (internal error)\n");
+ infof(data, "NTLM handshake failure (internal error)");
return CURLE_REMOTE_ACCESS_DENIED;
}
@@ -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/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/curl_path.c
index 6100d77..6510618 100644
--- a/Utilities/cmcurl/lib/curl_path.c
+++ b/Utilities/cmcurl/lib/curl_path.c
@@ -48,7 +48,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
/* Check for /~/, indicating relative to the user's home directory */
if(data->conn->handler->protocol & CURLPROTO_SCP) {
real_path = malloc(working_path_len + 1);
- if(real_path == NULL) {
+ if(!real_path) {
free(working_path);
return CURLE_OUT_OF_MEMORY;
}
@@ -62,7 +62,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
if((working_path_len > 1) && (working_path[1] == '~')) {
size_t homelen = strlen(homedir);
real_path = malloc(homelen + working_path_len + 1);
- if(real_path == NULL) {
+ if(!real_path) {
free(working_path);
return CURLE_OUT_OF_MEMORY;
}
@@ -78,7 +78,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
}
else {
real_path = malloc(working_path_len + 1);
- if(real_path == NULL) {
+ if(!real_path) {
free(working_path);
return CURLE_OUT_OF_MEMORY;
}
@@ -130,7 +130,7 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
/* Allocate enough space for home directory and filename + separator */
fullPathLength = strlen(cp) + strlen(homedir) + 2;
*path = malloc(fullPathLength);
- if(*path == NULL)
+ if(!*path)
return CURLE_OUT_OF_MEMORY;
/* Check for quoted filenames */
@@ -169,7 +169,7 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
else {
/* Read to end of filename - either to whitespace or terminator */
end = strpbrk(cp, WHITESPACE);
- if(end == NULL)
+ if(!end)
end = strchr(cp, '\0');
/* return pointer to second parameter if it exists */
*cpp = end + strspn(end, WHITESPACE);
diff --git a/Utilities/cmcurl/lib/curl_range.c b/Utilities/cmcurl/lib/curl_range.c
index f7fb7c0..24bdb30 100644
--- a/Utilities/cmcurl/lib/curl_range.c
+++ b/Utilities/cmcurl/lib/curl_range.c
@@ -53,14 +53,14 @@ CURLcode Curl_range(struct Curl_easy *data)
if((to_t == CURL_OFFT_INVAL) && !from_t) {
/* X - */
data->state.resume_from = from;
- DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
+ DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file",
from));
}
else if((from_t == CURL_OFFT_INVAL) && !to_t) {
/* -Y */
data->req.maxdownload = to;
data->state.resume_from = -to;
- DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes",
to));
}
else {
@@ -78,12 +78,12 @@ CURLcode Curl_range(struct Curl_easy *data)
data->req.maxdownload = totalsize + 1; /* include last byte */
data->state.resume_from = from;
DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
- " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ " getting %" CURL_FORMAT_CURL_OFF_T " bytes",
from, data->req.maxdownload));
}
DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
" to %" CURL_FORMAT_CURL_OFF_T ", totally %"
- CURL_FORMAT_CURL_OFF_T " bytes\n",
+ CURL_FORMAT_CURL_OFF_T " bytes",
from, to, data->req.maxdownload));
}
else
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
index fabdc88..2fa0267 100644
--- a/Utilities/cmcurl/lib/curl_rtmp.c
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -79,6 +79,7 @@ const struct Curl_handler Curl_handler_rtmp = {
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
CURLPROTO_RTMP, /* protocol */
CURLPROTO_RTMP, /* family */
@@ -101,6 +102,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
CURLPROTO_RTMPT, /* protocol */
CURLPROTO_RTMPT, /* family */
@@ -123,6 +125,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
CURLPROTO_RTMPE, /* protocol */
CURLPROTO_RTMPE, /* family */
@@ -145,6 +148,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
CURLPROTO_RTMPTE, /* protocol */
CURLPROTO_RTMPTE, /* family */
@@ -167,6 +171,7 @@ const struct Curl_handler Curl_handler_rtmps = {
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
CURLPROTO_RTMPS, /* protocol */
CURLPROTO_RTMP, /* family */
@@ -189,6 +194,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
CURLPROTO_RTMPTS, /* protocol */
CURLPROTO_RTMPT, /* family */
@@ -204,7 +210,7 @@ static CURLcode rtmp_setup_connection(struct Curl_easy *data,
RTMP_Init(r);
RTMP_SetBufferMS(r, DEF_BUFTIME);
- if(!RTMP_SetupURL(r, data->change.url)) {
+ if(!RTMP_SetupURL(r, data->state.url)) {
RTMP_Free(r);
return CURLE_URL_MALFORMAT;
}
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
index ffeb751..4a24887 100644
--- a/Utilities/cmcurl/lib/curl_sasl.c
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -23,6 +23,8 @@
* RFC2831 DIGEST-MD5 authentication
* RFC4422 Simple Authentication and Security Layer (SASL)
* RFC4616 PLAIN authentication
+ * RFC5802 SCRAM-SHA-1 authentication
+ * RFC7677 SCRAM-SHA-256 authentication
* RFC6749 OAuth 2.0 Authorization Framework
* RFC7628 A Set of SASL Mechanisms for OAuth
* Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
@@ -56,7 +58,7 @@
static const struct {
const char *name; /* Name */
size_t len; /* Name length */
- unsigned int bit; /* Flag bit */
+ unsigned short bit; /* Flag bit */
} mechtable[] = {
{ "LOGIN", 5, SASL_MECH_LOGIN },
{ "PLAIN", 5, SASL_MECH_PLAIN },
@@ -67,6 +69,8 @@ static const struct {
{ "NTLM", 4, SASL_MECH_NTLM },
{ "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
{ "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER },
+ { "SCRAM-SHA-1", 11, SASL_MECH_SCRAM_SHA_1 },
+ { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
{ ZERO_NULL, 0, 0 }
};
@@ -90,6 +94,13 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
}
#endif
+#if defined(USE_GSASL)
+ /* Cleanup the GSASL structure */
+ if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
+ Curl_auth_gsasl_cleanup(&conn->gsasl);
+ }
+#endif
+
#if defined(USE_NTLM)
/* Cleanup the NTLM structure */
if(authused == SASL_MECH_NTLM) {
@@ -117,7 +128,8 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
*
* Returns the SASL mechanism token or 0 if no match.
*/
-unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len)
+unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
+ size_t *len)
{
unsigned int i;
char c;
@@ -162,7 +174,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
if(!strncmp(value, "*", len))
sasl->prefmech = SASL_AUTH_DEFAULT;
else {
- unsigned int mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
+ unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
if(mechbit && mechlen == len)
sasl->prefmech |= mechbit;
else
@@ -215,13 +227,14 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
"GSSAPI_NO_DATA",
"OAUTH2",
"OAUTH2_RESP",
+ "GSASL",
"CANCEL",
"FINAL",
/* LAST */
};
if(sasl->state != newstate)
- infof(data, "SASL %p state change from %s to %s\n",
+ infof(data, "SASL %p state change from %s to %s",
(void *)sasl, names[sasl->state], names[newstate]);
#else
(void) data;
@@ -230,6 +243,49 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
sasl->state = newstate;
}
+/* Get the SASL server message and convert it to binary. */
+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);
+ }
+ return result;
+}
+
+/* Encode the outgoing SASL message. */
+static CURLcode build_message(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);
+ }
+
+ return result;
+}
+
/*
* Curl_sasl_can_authenticate()
*
@@ -260,25 +316,21 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
CURLcode result = CURLE_OK;
unsigned int enabledmechs;
const char *mech = NULL;
- char *resp = NULL;
- size_t len = 0;
+ struct bufref resp;
saslstate state1 = SASL_STOP;
saslstate state2 = SASL_FINAL;
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
- const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
- const char * const hostname = conn->host.name;
- const long int port = conn->remote_port;
-#endif
+ const char * const hostname = SSL_HOST_NAME();
+ const long int port = SSL_HOST_PORT();
#if defined(USE_KERBEROS5) || defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
#endif
const char *oauth_bearer = data->set.str[STRING_BEARER];
+ struct bufref nullmsg;
+ Curl_bufref_init(&nullmsg);
+ Curl_bufref_init(&resp);
sasl->force_ir = force_ir; /* Latch for future use */
sasl->authused = 0; /* No mechanism used yet */
enabledmechs = sasl->authmechs & sasl->prefmech;
@@ -292,8 +344,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_EXTERNAL;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_external_message(data, conn->user, &resp,
- &len);
+ result = Curl_auth_create_external_message(conn->user, &resp);
}
else if(conn->bits.user_passwd) {
#if defined(USE_KERBEROS5)
@@ -309,10 +360,39 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->conn->host.name,
+ conn->host.name,
sasl->mutual_auth,
NULL, &conn->krb5,
- &resp, &len);
+ &resp);
+ }
+ else
+#endif
+#ifdef USE_GSASL
+ if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
+ Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
+ &conn->gsasl)) {
+ mech = SASL_MECH_STRING_SCRAM_SHA_256;
+ sasl->authused = SASL_MECH_SCRAM_SHA_256;
+ state1 = SASL_GSASL;
+ state2 = SASL_GSASL;
+
+ result = Curl_auth_gsasl_start(data, conn->user,
+ conn->passwd, &conn->gsasl);
+ if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
+ result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
+ }
+ else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
+ Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
+ &conn->gsasl)) {
+ mech = SASL_MECH_STRING_SCRAM_SHA_1;
+ sasl->authused = SASL_MECH_SCRAM_SHA_1;
+ state1 = SASL_GSASL;
+ state2 = SASL_GSASL;
+
+ result = Curl_auth_gsasl_start(data, conn->user,
+ conn->passwd, &conn->gsasl);
+ if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
+ result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
}
else
#endif
@@ -342,8 +422,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
conn->user, conn->passwd,
service,
hostname,
- &conn->ntlm, &resp,
- &len);
+ &conn->ntlm, &resp);
}
else
#endif
@@ -354,11 +433,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_OAUTHBEARER;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_oauth_bearer_message(conn->user,
hostname,
port,
oauth_bearer,
- &resp, &len);
+ &resp);
}
else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
mech = SASL_MECH_STRING_XOAUTH2;
@@ -366,9 +445,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_XOAUTH2;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
- &resp, &len);
+ &resp);
}
else if(enabledmechs & SASL_MECH_PLAIN) {
mech = SASL_MECH_STRING_PLAIN;
@@ -376,9 +455,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_PLAIN;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
+ result = Curl_auth_create_plain_message(conn->sasl_authzid,
conn->user, conn->passwd,
- &resp, &len);
+ &resp);
}
else if(enabledmechs & SASL_MECH_LOGIN) {
mech = SASL_MECH_STRING_LOGIN;
@@ -387,26 +466,29 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_LOGIN;
if(force_ir || data->set.sasl_ir)
- result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+ result = Curl_auth_create_login_message(conn->user, &resp);
}
}
if(!result && mech) {
- if(resp && sasl->params->maxirlen &&
- strlen(mech) + len > sasl->params->maxirlen) {
- free(resp);
- resp = NULL;
- }
+ if(Curl_bufref_ptr(&resp))
+ result = build_message(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, conn, mech, resp);
if(!result) {
*progress = SASL_INPROGRESS;
- state(sasl, data, resp ? state2 : state1);
+ state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
}
}
- free(resp);
-
+ Curl_bufref_free(&resp);
return result;
}
@@ -421,29 +503,20 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
saslstate newstate = SASL_FINAL;
- char *resp = NULL;
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
- const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
- const char * const hostname = conn->host.name;
- const long int port = conn->remote_port;
-#endif
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
- char *chlg = NULL;
- size_t chlglen = 0;
-#endif
+ struct bufref resp;
+ const char * const hostname = SSL_HOST_NAME();
+ const long int port = SSL_HOST_PORT();
#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
sasl->params->service;
- char *serverdata;
#endif
- size_t len = 0;
const char *oauth_bearer = data->set.str[STRING_BEARER];
+ struct bufref serverdata;
+ Curl_bufref_init(&serverdata);
+ Curl_bufref_init(&resp);
*progress = SASL_INPROGRESS;
if(sasl->state == SASL_FINAL) {
@@ -466,42 +539,45 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
*progress = SASL_DONE;
return result;
case SASL_PLAIN:
- result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
- conn->user, conn->passwd,
- &resp, &len);
+ result = Curl_auth_create_plain_message(conn->sasl_authzid,
+ conn->user, conn->passwd, &resp);
break;
case SASL_LOGIN:
- result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+ result = Curl_auth_create_login_message(conn->user, &resp);
newstate = SASL_LOGIN_PASSWD;
break;
case SASL_LOGIN_PASSWD:
- result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len);
+ result = Curl_auth_create_login_message(conn->passwd, &resp);
break;
case SASL_EXTERNAL:
- result = Curl_auth_create_external_message(data, conn->user, &resp, &len);
+ result = Curl_auth_create_external_message(conn->user, &resp);
break;
-
#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifdef USE_GSASL
+ case SASL_GSASL:
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
+ if(!result && Curl_bufref_len(&resp) > 0)
+ newstate = SASL_GSASL;
+ break;
+#endif
case SASL_CRAMMD5:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen);
+ result = get_server_message(sasl, data, &serverdata);
if(!result)
- result = Curl_auth_create_cram_md5_message(data, chlg, conn->user,
- conn->passwd, &resp, &len);
- free(chlg);
+ result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
+ conn->passwd, &resp);
break;
case SASL_DIGESTMD5:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_create_digest_md5_message(data, serverdata,
- conn->user, conn->passwd,
- service,
- &resp, &len);
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_create_digest_md5_message(data, &serverdata,
+ conn->user, conn->passwd,
+ service, &resp);
newstate = SASL_DIGESTMD5_RESP;
break;
case SASL_DIGESTMD5_RESP:
- resp = strdup("");
- if(!resp)
- result = CURLE_OUT_OF_MEMORY;
+ /* Keep response NULL to output an empty line. */
break;
#endif
@@ -511,18 +587,19 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_ntlm_type1_message(data,
conn->user, conn->passwd,
service, hostname,
- &conn->ntlm, &resp, &len);
+ &conn->ntlm, &resp);
newstate = SASL_NTLM_TYPE2MSG;
break;
case SASL_NTLM_TYPE2MSG:
/* Decode the type-2 message */
- sasl->params->getmessage(data->state.buffer, &serverdata);
- result = Curl_auth_decode_ntlm_type2_message(data, serverdata,
- &conn->ntlm);
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
+ &conn->ntlm);
if(!result)
result = Curl_auth_create_ntlm_type3_message(data, conn->user,
conn->passwd, &conn->ntlm,
- &resp, &len);
+ &resp);
break;
#endif
@@ -531,55 +608,63 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->conn->host.name,
+ conn->host.name,
sasl->mutual_auth, NULL,
&conn->krb5,
- &resp, &len);
+ &resp);
newstate = SASL_GSSAPI_TOKEN;
break;
case SASL_GSSAPI_TOKEN:
- sasl->params->getmessage(data->state.buffer, &serverdata);
- if(sasl->mutual_auth) {
- /* Decode the user token challenge and create the optional response
- message */
- result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
- NULL, NULL,
- sasl->mutual_auth,
- serverdata, &conn->krb5,
- &resp, &len);
- newstate = SASL_GSSAPI_NO_DATA;
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result) {
+ if(sasl->mutual_auth) {
+ /* Decode the user token challenge and create the optional response
+ message */
+ result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
+ NULL, NULL,
+ sasl->mutual_auth,
+ &serverdata,
+ &conn->krb5,
+ &resp);
+ newstate = SASL_GSSAPI_NO_DATA;
+ }
+ else
+ /* Decode the security challenge and create the response message */
+ result = Curl_auth_create_gssapi_security_message(data,
+ conn->sasl_authzid,
+ &serverdata,
+ &conn->krb5,
+ &resp);
}
- else
- /* Decode the security challenge and create the response message */
- result = Curl_auth_create_gssapi_security_message(data, serverdata,
- &conn->krb5,
- &resp, &len);
break;
case SASL_GSSAPI_NO_DATA:
- sasl->params->getmessage(data->state.buffer, &serverdata);
/* Decode the security challenge and create the response message */
- result = Curl_auth_create_gssapi_security_message(data, serverdata,
- &conn->krb5,
- &resp, &len);
+ result = get_server_message(sasl, data, &serverdata);
+ if(!result)
+ result = Curl_auth_create_gssapi_security_message(data,
+ conn->sasl_authzid,
+ &serverdata,
+ &conn->krb5,
+ &resp);
break;
#endif
case SASL_OAUTH2:
/* Create the authorisation message */
if(sasl->authused == SASL_MECH_OAUTHBEARER) {
- result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_oauth_bearer_message(conn->user,
hostname,
port,
oauth_bearer,
- &resp, &len);
+ &resp);
/* Failures maybe sent by the server as continuations for OAUTHBEARER */
newstate = SASL_OAUTH2_RESP;
}
else
- result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+ result = Curl_auth_create_xoauth_bearer_message(conn->user,
oauth_bearer,
- &resp, &len);
+ &resp);
break;
case SASL_OAUTH2_RESP:
@@ -591,11 +676,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
return result;
}
else if(code == sasl->params->contcode) {
- /* Acknowledge the continuation by sending a 0x01 response base64
- encoded */
- resp = strdup("AQ==");
- if(!resp)
- result = CURLE_OUT_OF_MEMORY;
+ /* Acknowledge the continuation by sending a 0x01 response. */
+ Curl_bufref_set(&resp, "\x01", 1, NULL);
break;
}
else {
@@ -609,15 +691,15 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
sasl->authmechs ^= sasl->authused;
/* Start an alternative SASL authentication */
- result = Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
- newstate = sasl->state; /* Use state from Curl_sasl_start() */
- break;
+ return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
default:
failf(data, "Unsupported SASL authentication mechanism");
result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
break;
}
+ Curl_bufref_free(&serverdata);
+
switch(result) {
case CURLE_BAD_CONTENT_ENCODING:
/* Cancel dialog */
@@ -625,8 +707,10 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
newstate = SASL_CANCEL;
break;
case CURLE_OK:
- if(resp)
- result = sasl->params->sendcont(data, conn, resp);
+ result = build_message(data, &resp);
+ if(!result)
+ result = sasl->params->sendcont(data, conn,
+ (const char *) Curl_bufref_ptr(&resp));
break;
default:
newstate = SASL_STOP; /* Stop on error */
@@ -634,7 +718,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
break;
}
- free(resp);
+ Curl_bufref_free(&resp);
state(sasl, data, newstate);
diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h
index 75a9575..e17d323 100644
--- a/Utilities/cmcurl/lib/curl_sasl.h
+++ b/Utilities/cmcurl/lib/curl_sasl.h
@@ -37,10 +37,12 @@ struct connectdata;
#define SASL_MECH_NTLM (1 << 6)
#define SASL_MECH_XOAUTH2 (1 << 7)
#define SASL_MECH_OAUTHBEARER (1 << 8)
+#define SASL_MECH_SCRAM_SHA_1 (1 << 9)
+#define SASL_MECH_SCRAM_SHA_256 (1 << 10)
/* Authentication mechanism values */
#define SASL_AUTH_NONE 0
-#define SASL_AUTH_ANY ~0U
+#define SASL_AUTH_ANY 0xffff
#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
/* Authentication mechanism strings */
@@ -53,6 +55,8 @@ struct connectdata;
#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 machine states */
typedef enum {
@@ -71,6 +75,7 @@ typedef enum {
SASL_GSSAPI_NO_DATA,
SASL_OAUTH2,
SASL_OAUTH2_RESP,
+ SASL_GSASL,
SASL_CANCEL,
SASL_FINAL
} saslstate;
@@ -103,9 +108,9 @@ struct SASLproto {
struct SASL {
const struct SASLproto *params; /* Protocol dependent parameters */
saslstate state; /* Current machine state */
- unsigned int authmechs; /* Accepted authentication mechanisms */
- unsigned int prefmech; /* Preferred authentication mechanism */
- unsigned int authused; /* Auth mechanism used for the connection */
+ 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 */
@@ -121,8 +126,8 @@ struct SASL {
void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
/* Convert a mechanism name to a token */
-unsigned int Curl_sasl_decode_mech(const char *ptr,
- size_t maxlen, size_t *len);
+unsigned short Curl_sasl_decode_mech(const char *ptr,
+ size_t maxlen, size_t *len);
/* Parse the URL login options */
CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
index ef43b2b..554dcc1 100644
--- a/Utilities/cmcurl/lib/curl_setup.h
+++ b/Utilities/cmcurl/lib/curl_setup.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
@@ -54,6 +54,16 @@
# ifndef NOGDI
# define NOGDI
# endif
+/* Detect Windows App environment which has a restricted access
+ * to the Win32 APIs. */
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+ defined(WINAPI_FAMILY)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define CURL_WINDOWS_APP
+# endif
+# endif
#endif
/*
@@ -155,48 +165,52 @@
#include <curl/curl.h>
-#define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T
-
/*
* Disable other protocols when http is the only one desired.
*/
#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
@@ -243,7 +257,11 @@
* performing this task will result in a synthesized IPv6 address.
*/
#if defined(__APPLE__) && !defined(USE_ARES)
+#include <TargetConditionals.h>
#define USE_RESOLVE_ON_IPS 1
+# if defined(TARGET_OS_OSX) && TARGET_OS_OSX
+# define CURL_OSX_CALL_COPYPROXIES 1
+# endif
#endif
#ifdef USE_LWIPSOCK
@@ -350,8 +368,10 @@
# define stat(fname,stp) curlx_win32_stat(fname, stp)
# define struct_stat struct _stati64
# define LSEEK_ERROR (__int64)-1
+# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
# define access(fname,mode) curlx_win32_access(fname, mode)
+ int curlx_win32_open(const char *filename, int oflag, ...);
int curlx_win32_stat(const char *path, struct_stat *buffer);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
int curlx_win32_access(const char *path, int mode);
@@ -371,9 +391,11 @@
# define fstat(fdes,stp) _fstat(fdes, stp)
# define stat(fname,stp) curlx_win32_stat(fname, stp)
# define struct_stat struct _stat
+# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_stat(const char *path, struct_stat *buffer);
+ int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
int curlx_win32_access(const char *path, int mode);
# endif
@@ -423,7 +445,7 @@
#if (SIZEOF_CURL_OFF_T == 4)
# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
#else
- /* assume CURL_SIZEOF_CURL_OFF_T == 8 */
+ /* assume SIZEOF_CURL_OFF_T == 8 */
# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
#endif
#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
@@ -455,6 +477,15 @@
#endif
#endif
+#ifndef SSIZE_T_MAX
+/* some limits.h headers have this defined, some don't */
+#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
+#define SSIZE_T_MAX 9223372036854775807
+#else
+#define SSIZE_T_MAX 2147483647
+#endif
+#endif
+
/*
* Arg 2 type for gethostname in case it hasn't been defined in config file.
*/
@@ -520,7 +551,6 @@
# undef HAVE_GETADDRINFO_THREADSAFE
# undef HAVE_FREEADDRINFO
# undef HAVE_GETADDRINFO
-# undef HAVE_GETNAMEINFO
# undef ENABLE_IPV6
# endif
#endif
@@ -627,7 +657,7 @@ int netware_init(void);
defined(USE_MBEDTLS) || \
defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \
- defined(USE_BEARSSL)
+ defined(USE_BEARSSL) || defined(USE_RUSTLS)
#define USE_SSL /* SSL support has been enabled */
#endif
@@ -644,24 +674,16 @@ int netware_init(void);
#endif
/* Single point where USE_NTLM definition might be defined */
-#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-#if defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
- defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \
- defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
- (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
-
-#define USE_CURL_NTLM_CORE
-
-# if defined(USE_MBEDTLS)
-/* Get definition of MBEDTLS_MD4_C */
-# include <mbedtls/md4.h>
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(CURL_DISABLE_NTLM)
+# if defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
+ defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \
+ defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
+ (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
+# define USE_CURL_NTLM_CORE
+# endif
+# if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)
+# define USE_NTLM
# endif
-
-#endif
-
-#if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)
-#define USE_NTLM
-#endif
#endif
#ifdef CURL_WANTS_CA_BUNDLE_ENV
@@ -718,13 +740,19 @@ int netware_init(void);
#endif
/*
- * Portable symbolic names for Winsock shutdown() mode flags.
+ * shutdown() flags for systems that don't define them
*/
-#ifdef USE_WINSOCK
-# define SHUT_RD 0x00
-# define SHUT_WR 0x01
-# define SHUT_RDWR 0x02
+#ifndef SHUT_RD
+#define SHUT_RD 0x00
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 0x01
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 0x02
#endif
/* Define S_ISREG if not defined by system headers, f.e. MSVC */
@@ -775,20 +803,16 @@ endings either CRLF or LF so 't' is appropriate.
# endif
#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */
-/* Detect Windows App environment which has a restricted access
- * to the Win32 APIs. */
-# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
- defined(WINAPI_FAMILY)
-# include <winapifamily.h>
-# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
- !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-# define CURL_WINDOWS_APP
-# endif
-# endif
-
-/* for systems that don't detect this in configure, use a sensible default */
+/* for systems that don't detect this in configure */
#ifndef CURL_SA_FAMILY_T
-#define CURL_SA_FAMILY_T unsigned short
+# if defined(HAVE_SA_FAMILY_T)
+# define CURL_SA_FAMILY_T sa_family_t
+# elif defined(HAVE_ADDRESS_FAMILY)
+# define CURL_SA_FAMILY_T ADDRESS_FAMILY
+# else
+/* use a sensible default */
+# define CURL_SA_FAMILY_T unsigned short
+# endif
#endif
/* Some convenience macros to get the larger/smaller value out of two given.
@@ -809,8 +833,28 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#define UNITTEST static
#endif
+#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+#define USE_HTTP2
+#endif
+
#if defined(USE_NGTCP2) || defined(USE_QUICHE)
#define ENABLE_QUIC
#endif
+#if defined(USE_UNIX_SOCKETS) && defined(WIN32)
+# if defined(__MINGW32__) && !defined(LUP_SECURE)
+ typedef u_short ADDRESS_FAMILY; /* Classic mingw, 11y+ old mingw-w64 */
+# endif
+# if !defined(UNIX_PATH_MAX)
+ /* Replicating logic present in afunix.h
+ (distributed with newer Windows 10 SDK versions only) */
+# define UNIX_PATH_MAX 108
+ /* !checksrc! disable TYPEDEFSTRUCT 1 */
+ typedef struct sockaddr_un {
+ ADDRESS_FAMILY sun_family;
+ char sun_path[UNIX_PATH_MAX];
+ } SOCKADDR_UN, *PSOCKADDR_UN;
+# endif
+#endif
+
#endif /* HEADER_CURL_SETUP_H */
diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h
index ef60bc7..38018d2 100644
--- a/Utilities/cmcurl/lib/curl_setup_once.h
+++ b/Utilities/cmcurl/lib/curl_setup_once.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
@@ -32,6 +32,7 @@
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
+#include <time.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -55,13 +56,6 @@
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
-#ifdef TIME_WITH_SYS_TIME
-#include <time.h>
-#endif
-#else
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
#endif
#ifdef WIN32
@@ -329,35 +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
-
-
-/*
- * Default return type for signal handlers.
- */
-
-#ifndef RETSIGTYPE
-#define RETSIGTYPE void
-#endif
-
/*
* Macro used to include code only in debug builds.
diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c
index 4319dad..5d53b8f 100644
--- a/Utilities/cmcurl/lib/dict.c
+++ b/Utilities/cmcurl/lib/dict.c
@@ -89,6 +89,7 @@ const struct Curl_handler Curl_handler_dict = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_DICT, /* defport */
CURLPROTO_DICT, /* protocol */
CURLPROTO_DICT, /* family */
@@ -214,14 +215,14 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
}
}
- if((word == NULL) || (*word == (char)0)) {
- infof(data, "lookup word is missing\n");
+ if(!word || (*word == (char)0)) {
+ infof(data, "lookup word is missing");
word = (char *)"default";
}
- if((database == NULL) || (*database == (char)0)) {
+ if(!database || (*database == (char)0)) {
database = (char *)"!";
}
- if((strategy == NULL) || (*strategy == (char)0)) {
+ if(!strategy || (*strategy == (char)0)) {
strategy = (char *)".";
}
@@ -265,11 +266,11 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
}
}
- if((word == NULL) || (*word == (char)0)) {
- infof(data, "lookup word is missing\n");
+ if(!word || (*word == (char)0)) {
+ infof(data, "lookup word is missing");
word = (char *)"default";
}
- if((database == NULL) || (*database == (char)0)) {
+ if(!database || (*database == (char)0)) {
database = (char *)"!";
}
diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c
index 004244c..de0c902 100644
--- a/Utilities/cmcurl/lib/doh.c
+++ b/Utilities/cmcurl/lib/doh.c
@@ -186,19 +186,19 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
-/* called from multi.c when this DOH transfer is complete */
+/* called from multi.c when this DoH transfer is complete */
static int doh_done(struct Curl_easy *doh, CURLcode result)
{
struct Curl_easy *data = doh->set.dohfor;
struct dohdata *dohp = data->req.doh;
- /* so one of the DOH request done for the 'data' transfer is now complete! */
+ /* so one of the DoH request done for the 'data' transfer is now complete! */
dohp->pending--;
- infof(data, "a DOH request is completed, %u to go\n", dohp->pending);
+ infof(data, "a DoH request is completed, %u to go", dohp->pending);
if(result)
- infof(data, "DOH request %s\n", curl_easy_strerror(result));
+ infof(data, "DoH request %s", curl_easy_strerror(result));
if(!dohp->pending) {
- /* DOH completed */
+ /* DoH completed */
curl_slist_free_all(dohp->headers);
dohp->headers = NULL;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
@@ -207,10 +207,12 @@ static int doh_done(struct Curl_easy *doh, CURLcode result)
}
#define ERROR_CHECK_SETOPT(x,y) \
-do { \
- result = curl_easy_setopt(doh, x, y); \
- if(result) \
- goto error; \
+do { \
+ result = curl_easy_setopt(doh, x, y); \
+ if(result && \
+ result != CURLE_NOT_BUILT_IN && \
+ result != CURLE_UNKNOWN_OPTION) \
+ goto error; \
} while(0)
static CURLcode dohprobe(struct Curl_easy *data,
@@ -226,7 +228,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
&p->dohlen);
if(d) {
- failf(data, "Failed to encode DOH packet [%d]", d);
+ failf(data, "Failed to encode DoH packet [%d]", d);
return CURLE_OUT_OF_MEMORY;
}
@@ -282,84 +284,93 @@ static CURLcode dohprobe(struct Curl_easy *data,
ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
#endif
ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
+ ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
+ if(data->set.err && data->set.err != stderr)
+ ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
if(data->set.verbose)
ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
if(data->set.no_signal)
ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
+ data->set.doh_verifyhost ? 2L : 0L);
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
+ data->set.doh_verifypeer ? 1L : 0L);
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
+ data->set.doh_verifystatus ? 1L : 0L);
+
/* Inherit *some* SSL options from the user's transfer. This is a
- best-guess as to which options are needed for compatibility. #3661 */
+ best-guess as to which options are needed for compatibility. #3661
+
+ Note DoH does not inherit the user's proxy server so proxy SSL settings
+ have no effect and are not inherited. If that changes then two new
+ options should be added to check doh proxy insecure separately,
+ CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
+ */
if(data->set.ssl.falsestart)
ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
- if(data->set.ssl.primary.verifyhost)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, 2L);
-#ifndef CURL_DISABLE_PROXY
- if(data->set.proxy_ssl.primary.verifyhost)
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYHOST, 2L);
- if(data->set.proxy_ssl.primary.verifypeer)
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
- if(data->set.str[STRING_SSL_CAFILE_PROXY]) {
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAINFO,
- data->set.str[STRING_SSL_CAFILE_PROXY]);
- }
- if(data->set.str[STRING_SSL_CRLFILE_PROXY]) {
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_CRLFILE,
- data->set.str[STRING_SSL_CRLFILE_PROXY]);
- }
- if(data->set.proxy_ssl.no_revoke)
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
- else if(data->set.proxy_ssl.revoke_best_effort)
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS,
- CURLSSLOPT_REVOKE_BEST_EFFORT);
- if(data->set.str[STRING_SSL_CAPATH_PROXY]) {
- ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH,
- data->set.str[STRING_SSL_CAPATH_PROXY]);
- }
-#endif
- if(data->set.ssl.primary.verifypeer)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, 1L);
- if(data->set.ssl.primary.verifystatus)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS, 1L);
- if(data->set.str[STRING_SSL_CAFILE_ORIG]) {
+ if(data->set.str[STRING_SSL_CAFILE]) {
ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
- data->set.str[STRING_SSL_CAFILE_ORIG]);
+ data->set.str[STRING_SSL_CAFILE]);
+ }
+ if(data->set.blobs[BLOB_CAINFO]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
+ data->set.blobs[BLOB_CAINFO]);
}
- if(data->set.str[STRING_SSL_CAPATH_ORIG]) {
+ if(data->set.str[STRING_SSL_CAPATH]) {
ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
- data->set.str[STRING_SSL_CAPATH_ORIG]);
+ data->set.str[STRING_SSL_CAPATH]);
}
- if(data->set.str[STRING_SSL_CRLFILE_ORIG]) {
+ if(data->set.str[STRING_SSL_CRLFILE]) {
ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
- data->set.str[STRING_SSL_CRLFILE_ORIG]);
+ data->set.str[STRING_SSL_CRLFILE]);
}
if(data->set.ssl.certinfo)
ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
if(data->set.str[STRING_SSL_RANDOM_FILE]) {
ERROR_CHECK_SETOPT(CURLOPT_RANDOM_FILE,
- data->set.str[STRING_SSL_RANDOM_FILE]);
+ data->set.str[STRING_SSL_RANDOM_FILE]);
}
if(data->set.str[STRING_SSL_EGDSOCKET]) {
ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET,
- data->set.str[STRING_SSL_EGDSOCKET]);
+ data->set.str[STRING_SSL_EGDSOCKET]);
}
- if(data->set.ssl.no_revoke)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
- else if(data->set.ssl.revoke_best_effort)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT);
if(data->set.ssl.fsslctx)
ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
if(data->set.ssl.fsslctxp)
ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
if(data->set.str[STRING_SSL_EC_CURVES]) {
ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
- data->set.str[STRING_SSL_EC_CURVES]);
+ data->set.str[STRING_SSL_EC_CURVES]);
+ }
+
+ {
+ long mask =
+ (data->set.ssl.enable_beast ?
+ CURLSSLOPT_ALLOW_BEAST : 0) |
+ (data->set.ssl.no_revoke ?
+ CURLSSLOPT_NO_REVOKE : 0) |
+ (data->set.ssl.no_partialchain ?
+ CURLSSLOPT_NO_PARTIALCHAIN : 0) |
+ (data->set.ssl.revoke_best_effort ?
+ CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
+ (data->set.ssl.native_ca_store ?
+ CURLSSLOPT_NATIVE_CA : 0) |
+ (data->set.ssl.auto_client_cert ?
+ CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
+ (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
}
doh->set.fmultidone = doh_done;
doh->set.dohfor = data; /* identify for which transfer this is done */
p->easy = doh;
- /* add this transfer to the multi handle */
+ /* DoH private_data must be null because the user must have a way to
+ distinguish their transfer's handle from DoH handles in user
+ callbacks (ie SSL CTX callback). */
+ DEBUGASSERT(!doh->set.private_data);
+
if(curl_multi_add_handle(multi, doh))
goto error;
}
@@ -375,7 +386,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
}
/*
- * Curl_doh() resolves a name using DOH. It resolves a name and returns a
+ * Curl_doh() resolves a name using DoH. It resolves a name and returns a
* 'Curl_addrinfo *' with the address information.
*/
@@ -409,18 +420,16 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
if(!dohp->headers)
goto error;
- if(conn->ip_version != CURL_IPRESOLVE_V6) {
- /* create IPv4 DOH request */
- result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
- DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
- data->multi, dohp->headers);
- if(result)
- goto error;
- dohp->pending++;
- }
+ /* create IPv4 DoH request */
+ result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
+ DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
+ data->multi, dohp->headers);
+ if(result)
+ goto error;
+ dohp->pending++;
- if(conn->ip_version != CURL_IPRESOLVE_V4) {
- /* create IPv6 DOH request */
+ if(Curl_ipv6works(data)) {
+ /* create IPv6 DoH request */
result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
data->multi, dohp->headers);
@@ -755,11 +764,11 @@ static void showdoh(struct Curl_easy *data,
const struct dohentry *d)
{
int i;
- infof(data, "TTL: %u seconds\n", d->ttl);
+ infof(data, "TTL: %u seconds", d->ttl);
for(i = 0; i < d->numaddr; i++) {
const struct dohaddr *a = &d->addr[i];
if(a->type == DNS_TYPE_A) {
- infof(data, "DOH A: %u.%u.%u.%u\n",
+ infof(data, "DoH A: %u.%u.%u.%u",
a->ip.v4[0], a->ip.v4[1],
a->ip.v4[2], a->ip.v4[3]);
}
@@ -768,7 +777,7 @@ static void showdoh(struct Curl_easy *data,
char buffer[128];
char *ptr;
size_t len;
- msnprintf(buffer, 128, "DOH AAAA: ");
+ msnprintf(buffer, 128, "DoH AAAA: ");
ptr = &buffer[10];
len = 118;
for(j = 0; j < 16; j += 2) {
@@ -779,11 +788,11 @@ static void showdoh(struct Curl_easy *data,
len -= l;
ptr += l;
}
- infof(data, "%s\n", buffer);
+ infof(data, "%s", buffer);
}
}
for(i = 0; i < d->numcname; i++) {
- infof(data, "CNAME: %s\n", Curl_dyn_ptr(&d->cname[i]));
+ infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
}
}
#else
@@ -794,7 +803,7 @@ static void showdoh(struct Curl_easy *data,
* doh2ai()
*
* This function returns a pointer to the first element of a newly allocated
- * Curl_addrinfo struct linked list filled with the data from a set of DOH
+ * Curl_addrinfo struct linked list filled with the data from a set of DoH
* lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
* a IPv6 stack, but usable also for IPv4, all hosts and environments.
*
@@ -922,7 +931,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
!dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
- failf(data, "Could not DOH-resolve: %s", data->state.async.hostname);
+ failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
return data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
@@ -932,7 +941,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
};
struct dohentry de;
int slot;
- /* remove DOH handles from multi handle and close them */
+ /* remove DoH handles from multi handle and close them */
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
Curl_close(&dohp->probe[slot].easy);
@@ -949,7 +958,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
&de);
Curl_dyn_free(&p->serverdoh);
if(rc[slot]) {
- infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]),
+ infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
type2name(p->dnstype), dohp->host);
}
} /* next slot */
@@ -960,7 +969,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry *dns;
struct Curl_addrinfo *ai;
- infof(data, "DOH Host name: %s\n", dohp->host);
+ infof(data, "DoH Host name: %s", dohp->host);
showdoh(data, &de);
ai = doh2ai(&de, dohp->host, dohp->port);
@@ -998,7 +1007,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
} /* !dohp->pending */
- /* else wait for pending DOH transactions to complete */
+ /* else wait for pending DoH transactions to complete */
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/doh.h b/Utilities/cmcurl/lib/doh.h
index b3584d1..70e96e0 100644
--- a/Utilities/cmcurl/lib/doh.h
+++ b/Utilities/cmcurl/lib/doh.h
@@ -101,7 +101,7 @@ void de_init(struct dohentry *d);
void de_cleanup(struct dohentry *d);
#endif
-#else /* if DOH is disabled */
+#else /* if DoH is disabled */
#define Curl_doh(a,b,c,d) NULL
#define Curl_doh_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
#endif
diff --git a/Utilities/cmcurl/lib/dynbuf.h b/Utilities/cmcurl/lib/dynbuf.h
index 484e40c..252411f 100644
--- a/Utilities/cmcurl/lib/dynbuf.h
+++ b/Utilities/cmcurl/lib/dynbuf.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2020, 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
@@ -74,7 +74,7 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
#define DYN_DOH_CNAME 256
#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
#define DYN_HAXPROXY 2048
-#define DYN_HTTP_REQUEST (128*1024)
+#define DYN_HTTP_REQUEST (1024*1024)
#define DYN_H2_HEADERS (128*1024)
#define DYN_H2_TRAILERS (128*1024)
#define DYN_APRINTF 8000000
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
index 0fb255a..2aca938 100644
--- a/Utilities/cmcurl/lib/easy.c
+++ b/Utilities/cmcurl/lib/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__)
@@ -417,13 +417,13 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
ev->list = nxt;
free(m);
m = nxt;
- infof(easy, "socket cb: socket %d REMOVED\n", s);
+ infof(easy, "socket cb: socket %d REMOVED", s);
}
else {
/* The socket 's' is already being monitored, update the activity
mask. Convert from libcurl bitmask to the poll one. */
m->socket.events = socketcb2poll(what);
- infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
+ infof(easy, "socket cb: socket %d UPDATED as %s%s", s,
(what&CURL_POLL_IN)?"IN":"",
(what&CURL_POLL_OUT)?"OUT":"");
}
@@ -447,7 +447,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
m->socket.events = socketcb2poll(what);
m->socket.revents = 0;
ev->list = m;
- infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
+ infof(easy, "socket cb: socket %d ADDED as %s%s", s,
(what&CURL_POLL_IN)?"IN":"",
(what&CURL_POLL_OUT)?"OUT":"");
}
@@ -532,7 +532,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
if(fds[i].revents) {
/* socket activity, tell libcurl */
int act = poll2cselect(fds[i].revents); /* convert */
- infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n",
+ infof(multi->easyp, "call curl_multi_socket_action(socket %d)",
fds[i].fd);
mcode = curl_multi_socket_action(multi, fds[i].fd, act,
&ev->running_handles);
@@ -789,7 +789,6 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
/* duplicate all blobs */
for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
- /* Curl_setstropt return CURLE_BAD_FUNCTION_ARGUMENT with blob */
if(result)
return result;
}
@@ -810,7 +809,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
if(src->set.resolve)
- dst->change.resolve = dst->set.resolve;
+ dst->state.resolve = dst->set.resolve;
return result;
}
@@ -858,25 +857,25 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
}
/* duplicate all values in 'change' */
- if(data->change.cookielist) {
- outcurl->change.cookielist =
- Curl_slist_duplicate(data->change.cookielist);
- if(!outcurl->change.cookielist)
+ if(data->state.cookielist) {
+ outcurl->state.cookielist =
+ Curl_slist_duplicate(data->state.cookielist);
+ if(!outcurl->state.cookielist)
goto fail;
}
- if(data->change.url) {
- outcurl->change.url = strdup(data->change.url);
- if(!outcurl->change.url)
+ if(data->state.url) {
+ outcurl->state.url = strdup(data->state.url);
+ if(!outcurl->state.url)
goto fail;
- outcurl->change.url_alloc = TRUE;
+ outcurl->state.url_alloc = TRUE;
}
- if(data->change.referer) {
- outcurl->change.referer = strdup(data->change.referer);
- if(!outcurl->change.referer)
+ if(data->state.referer) {
+ outcurl->state.referer = strdup(data->state.referer);
+ if(!outcurl->state.referer)
goto fail;
- outcurl->change.referer_alloc = TRUE;
+ outcurl->state.referer_alloc = TRUE;
}
/* Reinitialize an SSL engine for the new handle
@@ -895,7 +894,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
(void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
}
#endif
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
if(data->hsts) {
outcurl->hsts = Curl_hsts_init();
if(!outcurl->hsts)
@@ -947,12 +946,12 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
fail:
if(outcurl) {
- curl_slist_free_all(outcurl->change.cookielist);
- outcurl->change.cookielist = NULL;
+ curl_slist_free_all(outcurl->state.cookielist);
+ outcurl->state.cookielist = NULL;
Curl_safefree(outcurl->state.buffer);
Curl_dyn_free(&outcurl->state.headerb);
- Curl_safefree(outcurl->change.url);
- Curl_safefree(outcurl->change.referer);
+ Curl_safefree(outcurl->state.url);
+ Curl_safefree(outcurl->state.referer);
Curl_altsvc_cleanup(&outcurl->asi);
Curl_hsts_cleanup(&outcurl->hsts);
Curl_freeset(outcurl);
@@ -1028,14 +1027,14 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
/* Not changing any pause state, return */
- DEBUGF(infof(data, "pause: no change, early return\n"));
+ DEBUGF(infof(data, "pause: no change, early return"));
return CURLE_OK;
}
/* Unpause parts in active mime tree. */
if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
- (data->mstate == CURLM_STATE_PERFORM ||
- data->mstate == CURLM_STATE_TOOFAST) &&
+ (data->mstate == MSTATE_PERFORMING ||
+ data->mstate == MSTATE_RATELIMITING) &&
data->state.fread_func == (curl_read_callback) Curl_mime_read) {
Curl_mime_unpause(data->state.in);
}
@@ -1052,8 +1051,6 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
unsigned int i;
unsigned int count = data->state.tempcount;
struct tempbuf writebuf[3]; /* there can only be three */
- struct connectdata *conn = data->conn;
- struct Curl_easy *saved_data = NULL;
/* copy the structs to allow for immediate re-pausing */
for(i = 0; i < data->state.tempcount; i++) {
@@ -1062,12 +1059,6 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
}
data->state.tempcount = 0;
- /* set the connection's current owner */
- if(conn->data != data) {
- saved_data = conn->data;
- conn->data = data;
- }
-
for(i = 0; i < count; i++) {
/* even if one function returns error, this loops through and frees
all buffers */
@@ -1078,10 +1069,6 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
Curl_dyn_free(&writebuf[i].b);
}
- /* recover previous owner of the connection */
- if(saved_data)
- conn->data = saved_data;
-
if(result)
return result;
}
@@ -1117,7 +1104,7 @@ static CURLcode easy_connection(struct Curl_easy *data,
curl_socket_t *sfd,
struct connectdata **connp)
{
- if(data == NULL)
+ if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
/* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
@@ -1183,6 +1170,7 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
CURLcode result;
ssize_t n1;
struct connectdata *c = NULL;
+ SIGPIPE_VARIABLE(pipe_st);
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
@@ -1197,7 +1185,9 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
Curl_attach_connnection(data, c);
*n = 0;
+ sigpipe_ignore(data, &pipe_st);
result = Curl_write(data, sfd, buffer, buflen, &n1);
+ sigpipe_restore(&pipe_st);
if(n1 == -1)
return CURLE_SEND_ERROR;
@@ -1223,9 +1213,16 @@ static int conn_upkeep(struct Curl_easy *data,
/* Param is unused. */
(void)param;
- if(conn->handler->connection_check)
+ if(conn->handler->connection_check) {
+ /* briefly attach the connection to this transfer for the purpose of
+ checking it */
+ Curl_attach_connnection(data, conn);
+
/* Do a protocol-specific keepalive check on the connection. */
conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
+ /* detach the connection again */
+ Curl_detach_connnection(data);
+ }
return 0; /* continue iteration */
}
diff --git a/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c
index b54829b..4e65e35 100644
--- a/Utilities/cmcurl/lib/easyoptions.c
+++ b/Utilities/cmcurl/lib/easyoptions.c
@@ -38,6 +38,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
{"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
{"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
+ {"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0},
{"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
{"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
{"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
@@ -78,6 +79,9 @@ struct curl_easyoption Curl_easyopts[] = {
{"DNS_SERVERS", CURLOPT_DNS_SERVERS, CURLOT_STRING, 0},
{"DNS_SHUFFLE_ADDRESSES", CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOT_LONG, 0},
{"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOT_LONG, 0},
+ {"DOH_SSL_VERIFYHOST", CURLOPT_DOH_SSL_VERIFYHOST, CURLOT_LONG, 0},
+ {"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0},
+ {"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
{"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
{"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
{"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
@@ -202,6 +206,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
{"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
{"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
+ {"PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CURLOT_BLOB, 0},
{"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
{"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
{"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
@@ -349,6 +354,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return ((CURLOPT_LASTENTRY%10000) != (305 + 1));
+ return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
}
#endif
diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c
index dd8a1fd..0420db3 100644
--- a/Utilities/cmcurl/lib/file.c
+++ b/Utilities/cmcurl/lib/file.c
@@ -111,6 +111,7 @@ const struct Curl_handler Curl_handler_file = {
file_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
0, /* defport */
CURLPROTO_FILE, /* protocol */
CURLPROTO_FILE, /* family */
@@ -410,19 +411,21 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
struct tm buffer;
const struct tm *tm = &buffer;
char header[80];
+ int headerlen;
+ char accept_ranges[24]= { "Accept-ranges: bytes\r\n" };
if(expected_size >= 0) {
- msnprintf(header, sizeof(header),
+ headerlen = msnprintf(header, sizeof(header),
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
expected_size);
- result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
+ result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
if(result)
return result;
- }
- result = Curl_client_write(data, CLIENTWRITE_HEADER,
- (char *)"Accept-ranges: bytes\r\n", 0);
- if(result)
- return result;
+ result = Curl_client_write(data, CLIENTWRITE_HEADER,
+ accept_ranges, strlen(accept_ranges));
+ if(result != CURLE_OK)
+ return result;
+ }
filetime = (time_t)statbuf.st_mtime;
result = Curl_gmtime(filetime, &buffer);
@@ -430,7 +433,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
return result;
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- msnprintf(header, sizeof(header),
+ headerlen = msnprintf(header, sizeof(header),
"Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
tm->tm_mday,
@@ -440,7 +443,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
tm->tm_min,
tm->tm_sec,
data->set.opt_no_body ? "": "\r\n");
- result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
+ result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
if(result)
return result;
/* set the file size to make it available post transfer */
@@ -464,18 +467,23 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
data->state.resume_from += (curl_off_t)statbuf.st_size;
}
- if(data->state.resume_from <= expected_size)
- expected_size -= data->state.resume_from;
- else {
- failf(data, "failed to resume file:// transfer");
- return CURLE_BAD_DOWNLOAD_RESUME;
+ if(data->state.resume_from > 0) {
+ /* We check explicitly if we have a start offset, because
+ * expected_size may be -1 if we don't know how large the file is,
+ * in which case we should not adjust it. */
+ if(data->state.resume_from <= expected_size)
+ expected_size -= data->state.resume_from;
+ else {
+ failf(data, "failed to resume file:// transfer");
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
}
/* A high water mark has been specified so we obey... */
if(data->req.maxdownload > 0)
expected_size = data->req.maxdownload;
- if(!fstated || (expected_size == 0))
+ if(!fstated || (expected_size <= 0))
size_known = FALSE;
else
size_known = TRUE;
@@ -484,7 +492,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
this is both more efficient than the former call to download() and
it avoids problems with select() and recv() on file descriptors
in Winsock */
- if(fstated)
+ if(size_known)
Curl_pgrsSetDownloadSize(data, expected_size);
if(data->state.resume_from) {
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
index 769f06a..ac7a000 100644
--- a/Utilities/cmcurl/lib/formdata.c
+++ b/Utilities/cmcurl/lib/formdata.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
@@ -865,8 +865,6 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
if(post->flags & CURL_HTTPPOST_LARGE)
clen = post->contentlen;
- if(!clen)
- clen = -1;
if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
if(!strcmp(file->contents, "-")) {
@@ -888,13 +886,21 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
else if(post->flags & HTTPPOST_BUFFER)
result = curl_mime_data(part, post->buffer,
post->bufferlength? post->bufferlength: -1);
- else if(post->flags & HTTPPOST_CALLBACK)
+ else if(post->flags & HTTPPOST_CALLBACK) {
/* the contents should be read with the callback and the size is set
with the contentslength */
+ if(!clen)
+ clen = -1;
result = curl_mime_data_cb(part, clen,
fread_func, NULL, NULL, post->userp);
+ }
else {
- result = curl_mime_data(part, post->contents, (ssize_t) clen);
+ size_t uclen;
+ if(!clen)
+ uclen = CURL_ZERO_TERMINATED;
+ else
+ uclen = (size_t)clen;
+ result = curl_mime_data(part, post->contents, uclen);
#ifdef CURL_DOES_CONVERSIONS
/* Convert textual contents now. */
if(!result && data && part->datasize)
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
index f8f970c..cad584f 100644
--- a/Utilities/cmcurl/lib/ftp.c
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -175,6 +175,7 @@ const struct Curl_handler Curl_handler_ftp = {
ftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
CURLPROTO_FTP, /* protocol */
CURLPROTO_FTP, /* family */
@@ -205,6 +206,7 @@ const struct Curl_handler Curl_handler_ftps = {
ftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
CURLPROTO_FTPS, /* protocol */
CURLPROTO_FTP, /* family */
@@ -287,7 +289,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
failf(data, "Error accept()ing server connect");
return CURLE_FTP_PORT_FAILED;
}
- infof(data, "Connection accepted from server\n");
+ infof(data, "Connection accepted from server");
/* when this happens within the DO state it is important that we mark us as
not needing DO_MORE anymore */
conn->bits.do_more = FALSE;
@@ -378,7 +380,7 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
*received = FALSE;
timeout_ms = ftp_timeleft_accept(data);
- infof(data, "Checking for server connect\n");
+ infof(data, "Checking for server connect");
if(timeout_ms < 0) {
/* if a timeout was already reached, bail out */
failf(data, "Accept timeout occurred while waiting server connect");
@@ -388,7 +390,7 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
/* First check whether there is a cached response from server */
if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
/* Data connection could not be established, let's return */
- infof(data, "There is negative response in cache while serv connect\n");
+ infof(data, "There is negative response in cache while serv connect");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
@@ -406,11 +408,11 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
default:
if(result & CURL_CSELECT_IN2) {
- infof(data, "Ready to accept data connection from server\n");
+ infof(data, "Ready to accept data connection from server");
*received = TRUE;
}
else if(result & CURL_CSELECT_IN) {
- infof(data, "Ctrl conn has data while waiting for data conn\n");
+ infof(data, "Ctrl conn has data while waiting for data conn");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
if(ftpcode/100 > 3)
@@ -442,7 +444,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
if(conn->bits.ftp_use_data_ssl) {
/* since we only have a plaintext TCP connection here, we must now
* do the TLS stuff */
- infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+ infof(data, "Doing the SSL/TLS handshake on the data stream");
result = Curl_ssl_connect(data, conn, SECONDARYSOCKET);
if(result)
return result;
@@ -485,7 +487,7 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
CURLcode result = CURLE_OK;
*connected = FALSE;
- infof(data, "Preparing for accepting server on data port\n");
+ infof(data, "Preparing for accepting server on data port");
/* Save the time we start accepting server connect */
Curl_pgrsTime(data, TIMER_STARTACCEPT);
@@ -590,7 +592,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
* This response code can come at any point so having it treated
* generically is a good idea.
*/
- infof(data, "We got a 421 - timeout!\n");
+ infof(data, "We got a 421 - timeout!");
state(data, FTP_STOP);
return CURLE_OPERATION_TIMEDOUT;
}
@@ -766,7 +768,7 @@ static void _state(struct Curl_easy *data,
(void) lineno;
#else
if(ftpc->state != newstate)
- infof(data, "FTP %p (line %d) state change from %s to %s\n",
+ infof(data, "FTP %p (line %d) state change from %s to %s",
(void *)ftpc, lineno, ftp_state_names[ftpc->state],
ftp_state_names[newstate]);
#endif
@@ -1090,7 +1092,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
else
res = NULL; /* failure! */
- if(res == NULL) {
+ if(!res) {
failf(data, "failed to resolve the address provided to PORT: %s", host);
free(addr);
return CURLE_FTP_PORT_FAILED;
@@ -1137,7 +1139,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* The requested bind address is not local. Use the address used for
* the control connection instead and restart the port loop
*/
- infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
+ infof(data, "bind(port=%hu) on non-local address failed: %s", port,
Curl_strerror(error, buffer, sizeof(buffer)));
sslen = sizeof(ss);
@@ -1339,7 +1341,7 @@ static CURLcode ftp_state_use_pasv(struct Curl_easy *data,
if(!result) {
ftpc->count1 = modeoff;
state(data, FTP_PASV);
- infof(data, "Connect data stream passively\n");
+ infof(data, "Connect data stream passively");
}
return result;
}
@@ -1357,7 +1359,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
struct FTP *ftp = data->req.p.ftp;
struct connectdata *conn = data->conn;
- if(ftp->transfer != FTPTRANSFER_BODY) {
+ if(ftp->transfer != PPTRANSFER_BODY) {
/* doesn't transfer any data */
/* still possibly do PRE QUOTE jobs */
@@ -1378,7 +1380,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
data->set.str[STRING_CUSTOMREQUEST]?
data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"));
+ (data->state.list_only?"NLST":"LIST"));
else if(data->set.upload)
result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
conn->proto.ftpc.file);
@@ -1401,7 +1403,7 @@ static CURLcode ftp_state_rest(struct Curl_easy *data,
struct FTP *ftp = data->req.p.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+ if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) {
/* if a "head"-like request is being made (on a file) */
/* Determine if server can respond to REST command and therefore
@@ -1423,7 +1425,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data,
struct FTP *ftp = data->req.p.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+ if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
/* if a "head"-like request is being made (on a file) */
/* we know ftpc->file is a valid pointer to a file name */
@@ -1485,7 +1487,7 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
cmd = aprintf("%s%s%s",
data->set.str[STRING_CUSTOMREQUEST]?
data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"),
+ (data->state.list_only?"NLST":"LIST"),
lstArg? " ": "",
lstArg? lstArg: "");
free(lstArg);
@@ -1525,17 +1527,17 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
information. Which in FTP can't be much more than the file size and
date. */
if(data->set.opt_no_body && ftpc->file &&
- ftp_need_type(conn, data->set.prefer_ascii)) {
+ ftp_need_type(conn, data->state.prefer_ascii)) {
/* The SIZE command is _not_ RFC 959 specified, and therefore many servers
may not support it! It is however the only way we have to get a file's
size! */
- ftp->transfer = FTPTRANSFER_INFO;
+ ftp->transfer = PPTRANSFER_INFO;
/* this means no actual transfer will be made */
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
- result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_TYPE);
+ result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
if(result)
return result;
}
@@ -1578,6 +1580,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct FTP *ftp = data->req.p.ftp;
struct ftp_conn *ftpc = &conn->proto.ftpc;
+ bool append = data->set.remote_append;
if((data->state.resume_from && !sizechecked) ||
((data->state.resume_from > 0) && sizechecked)) {
@@ -1604,7 +1607,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
}
/* enable append */
- data->set.ftp_append = TRUE;
+ append = TRUE;
/* Let's read off the proper amount of bytes from the input. */
if(conn->seek_func) {
@@ -1645,14 +1648,14 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
data->state.infilesize -= data->state.resume_from;
if(data->state.infilesize <= 0) {
- infof(data, "File already completely uploaded\n");
+ infof(data, "File already completely uploaded");
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
/* Set ->transfer so that we won't get any error in
* ftp_done() because we didn't transfer anything! */
- ftp->transfer = FTPTRANSFER_NONE;
+ ftp->transfer = PPTRANSFER_NONE;
state(data, FTP_STOP);
return CURLE_OK;
@@ -1661,8 +1664,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
/* we've passed, proceed as normal */
} /* resume_from */
- result = Curl_pp_sendf(data, &ftpc->pp,
- data->set.ftp_append?"APPE %s":"STOR %s",
+ result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
ftpc->file);
if(!result)
state(data, FTP_STOR);
@@ -1739,7 +1741,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
result = ftp_state_cwd(data, conn);
break;
case FTP_RETR_PREQUOTE:
- if(ftp->transfer != FTPTRANSFER_BODY)
+ if(ftp->transfer != PPTRANSFER_BODY)
state(data, FTP_STOP);
else {
if(ftpc->known_filesize != -1) {
@@ -1747,13 +1749,19 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
result = ftp_state_retr(data, ftpc->known_filesize);
}
else {
- if(data->set.ignorecl) {
- /* This code is to support download of growing files. It prevents
- the state machine from requesting the file size from the
- server. With an unknown file size the download continues until
- the server terminates it, otherwise the client stops if the
- received byte count exceeds the reported file size. Set option
- CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
+ if(data->set.ignorecl || data->state.prefer_ascii) {
+ /* 'ignorecl' is used to support download of growing files. It
+ prevents the state machine from requesting the file size from
+ the server. With an unknown file size the download continues
+ until the server terminates it, otherwise the client stops if
+ the received byte count exceeds the reported file size. Set
+ option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
+ behavior.
+
+ In addition: asking for the size for 'TYPE A' transfers is not
+ constructive since servers don't report the converted size. So
+ skip it.
+ */
result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
if(!result)
state(data, FTP_RETR);
@@ -1794,7 +1802,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
return CURLE_WEIRD_SERVER_REPLY;
}
- infof(data, "Failed EPSV attempt. Disabling EPSV\n");
+ infof(data, "Failed EPSV attempt. Disabling EPSV");
/* disable it for next transfer */
conn->bits.ftp_use_epsv = FALSE;
data->state.errorbuf = FALSE; /* allow error message to get
@@ -1913,7 +1921,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
if(data->set.ftp_skip_ip) {
/* told to ignore the remotely given IP but instead use the host we used
for the control connection */
- infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead\n",
+ infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead",
ip[0], ip[1], ip[2], ip[3],
conn->host.name);
ftpc->newhost = strdup(control_address(conn));
@@ -2036,7 +2044,7 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
/* the command failed */
if(EPRT == fcmd) {
- infof(data, "disabling EPRT usage\n");
+ infof(data, "disabling EPRT usage");
conn->bits.ftp_use_eprt = FALSE;
}
fcmd++;
@@ -2050,7 +2058,7 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
result = ftp_state_use_port(data, fcmd);
}
else {
- infof(data, "Connect data stream actively\n");
+ infof(data, "Connect data stream actively");
state(data, FTP_STOP); /* end of DO phase */
result = ftp_dophase_done(data, FALSE);
}
@@ -2092,6 +2100,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
data->set.get_filetime &&
(data->info.filetime >= 0) ) {
char headerbuf[128];
+ int headerbuflen;
time_t filetime = data->info.filetime;
struct tm buffer;
const struct tm *tm = &buffer;
@@ -2101,7 +2110,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
return result;
/* format: "Tue, 15 Nov 1994 12:45:26" */
- msnprintf(headerbuf, sizeof(headerbuf),
+ headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
"Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
tm->tm_mday,
@@ -2110,7 +2119,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
- result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf, 0);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf,
+ headerbuflen);
if(result)
return result;
} /* end of a ridiculous amount of conditionals */
@@ -2118,7 +2128,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
}
break;
default:
- infof(data, "unsupported MDTM reply format\n");
+ infof(data, "unsupported MDTM reply format");
break;
case 550: /* "No such file or directory" */
failf(data, "Given file does not exist");
@@ -2132,8 +2142,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
case CURL_TIMECOND_IFMODSINCE:
default:
if(data->info.filetime <= data->set.timevalue) {
- infof(data, "The requested document is not new enough\n");
- ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ infof(data, "The requested document is not new enough");
+ ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
data->info.timecond = TRUE;
state(data, FTP_STOP);
return CURLE_OK;
@@ -2141,8 +2151,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
break;
case CURL_TIMECOND_IFUNMODSINCE:
if(data->info.filetime > data->set.timevalue) {
- infof(data, "The requested document is not old enough\n");
- ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ infof(data, "The requested document is not old enough");
+ ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
data->info.timecond = TRUE;
state(data, FTP_STOP);
return CURLE_OK;
@@ -2151,7 +2161,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
} /* switch */
}
else {
- infof(data, "Skipping time comparison\n");
+ infof(data, "Skipping time comparison");
}
}
@@ -2176,7 +2186,7 @@ static CURLcode ftp_state_type_resp(struct Curl_easy *data,
return CURLE_FTP_COULDNT_SET_TYPE;
}
if(ftpcode != 200)
- infof(data, "Got a %03d response code instead of the assumed 200\n",
+ infof(data, "Got a %03d response code instead of the assumed 200",
ftpcode);
if(instate == FTP_TYPE)
@@ -2209,7 +2219,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
/* We always (attempt to) get the size of downloads, so it is done before
this even when not doing resumes. */
if(filesize == -1) {
- infof(data, "ftp server doesn't support SIZE\n");
+ infof(data, "ftp server doesn't support SIZE");
/* We couldn't get the size and therefore we can't know if there really
is a part of the file left to get, although the server will just
close the connection when we start the connection so it won't cause
@@ -2246,18 +2256,18 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
if(ftp->downloadsize == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
- infof(data, "File already completely downloaded\n");
+ infof(data, "File already completely downloaded");
/* Set ->transfer so that we won't get any error in ftp_done()
* because we didn't transfer the any file */
- ftp->transfer = FTPTRANSFER_NONE;
+ ftp->transfer = PPTRANSFER_NONE;
state(data, FTP_STOP);
return CURLE_OK;
}
/* Set resume file transfer offset */
infof(data, "Instructs server to resume from offset %"
- CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
+ CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
data->state.resume_from);
@@ -2303,17 +2313,21 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
}
else if(ftpcode == 550) { /* "No such file or directory" */
- failf(data, "The file does not exist");
- return CURLE_REMOTE_FILE_NOT_FOUND;
+ /* allow a SIZE failure for (resumed) uploads, when probing what command
+ to use */
+ if(instate != FTP_STOR_SIZE) {
+ failf(data, "The file does not exist");
+ return CURLE_REMOTE_FILE_NOT_FOUND;
+ }
}
if(instate == FTP_SIZE) {
#ifdef CURL_FTP_HTTPSTYLE_HEAD
if(-1 != filesize) {
char clbuf[128];
- msnprintf(clbuf, sizeof(clbuf),
+ int clbuflen = msnprintf(clbuf, sizeof(clbuf),
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
- result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, 0);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen);
if(result)
return result;
}
@@ -2347,7 +2361,8 @@ static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
#ifdef CURL_FTP_HTTPSTYLE_HEAD
if(ftpcode == 350) {
char buffer[24]= { "Accept-ranges: bytes\r\n" };
- result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer, 0);
+ result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer,
+ strlen(buffer));
if(result)
return result;
}
@@ -2398,7 +2413,7 @@ static CURLcode ftp_state_stor_resp(struct Curl_easy *data,
if(!connected) {
struct ftp_conn *ftpc = &conn->proto.ftpc;
- infof(data, "Data conn was not available immediately\n");
+ infof(data, "Data conn was not available immediately");
ftpc->wait_data_conn = TRUE;
}
@@ -2448,7 +2463,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
*/
if((instate != FTP_LIST) &&
- !data->set.prefer_ascii &&
+ !data->state.prefer_ascii &&
(ftp->downloadsize < 1)) {
/*
* It seems directory listings either don't show the size or very
@@ -2476,7 +2491,8 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
bytes--;
}
/* if we have nothing but digits: */
- if(bytes++) {
+ if(bytes) {
+ ++bytes;
/* get the number! */
(void)curlx_strtoofft(bytes, NULL, 0, &size);
}
@@ -2487,14 +2503,14 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if(size > data->req.maxdownload && data->req.maxdownload > 0)
size = data->req.size = data->req.maxdownload;
- else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+ else if((instate != FTP_LIST) && (data->state.prefer_ascii))
size = -1; /* kludge for servers that understate ASCII mode file size */
- infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
+ infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
data->req.maxdownload);
if(instate != FTP_LIST)
- infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
+ infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
size);
/* FTP download: */
@@ -2510,7 +2526,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
if(!connected) {
struct ftp_conn *ftpc = &conn->proto.ftpc;
- infof(data, "Data conn was not available immediately\n");
+ infof(data, "Data conn was not available immediately");
state(data, FTP_STOP);
ftpc->wait_data_conn = TRUE;
}
@@ -2521,7 +2537,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
else {
if((instate == FTP_LIST) && (ftpcode == 450)) {
/* simply no matching files in the dir listing */
- ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
+ ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
state(data, FTP_STOP); /* this phase is over */
}
else {
@@ -2665,9 +2681,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);
@@ -2686,9 +2705,9 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
if(Curl_sec_login(data, conn))
- infof(data, "Logging in with password in cleartext!\n");
+ infof(data, "Logging in with password in cleartext!");
else
- infof(data, "Authentication successful\n");
+ infof(data, "Authentication successful");
}
#endif
@@ -2724,6 +2743,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,
@@ -2879,7 +2901,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
Curl_safefree(ftpc->entrypath);
ftpc->entrypath = dir; /* remember this */
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+ infof(data, "Entry path is '%s'", ftpc->entrypath);
/* also save it where getinfo can access it: */
data->state.most_recent_ftp_entrypath = ftpc->entrypath;
state(data, FTP_SYST);
@@ -2888,18 +2910,18 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
Curl_safefree(ftpc->entrypath);
ftpc->entrypath = dir; /* remember this */
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+ infof(data, "Entry path is '%s'", ftpc->entrypath);
/* also save it where getinfo can access it: */
data->state.most_recent_ftp_entrypath = ftpc->entrypath;
}
else {
/* couldn't get the path */
free(dir);
- infof(data, "Failed to figure out path\n");
+ infof(data, "Failed to figure out path");
}
}
state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ DEBUGF(infof(data, "protocol connect phase DONE"));
break;
case FTP_SYST:
@@ -2946,7 +2968,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ DEBUGF(infof(data, "protocol connect phase DONE"));
break;
case FTP_NAMEFMT:
@@ -2957,7 +2979,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ DEBUGF(infof(data, "protocol connect phase DONE"));
break;
case FTP_QUOTE:
@@ -3256,7 +3278,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
if(ftpc->prevpath)
- infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
+ infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath);
}
/* free the dir tree and file parts */
@@ -3291,7 +3313,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
close_secondarysocket(data, conn);
}
- if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
+ if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
pp->pending_resp && !premature) {
/*
* Let's see what the server says about the transfer we just performed,
@@ -3314,13 +3336,15 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
}
- if(result)
+ if(result) {
+ Curl_safefree(ftp->pathalloc);
return result;
+ }
if(ftpc->dont_check && data->req.maxdownload > 0) {
/* we have just sent ABOR and there is no reliable way to check if it was
* successful or not; we have to close the connection now */
- infof(data, "partial download completed, closing connection\n");
+ infof(data, "partial download completed, closing connection");
connclose(conn, "Partial download with no ability to check");
return result;
}
@@ -3351,7 +3375,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
if((-1 != data->state.infilesize) &&
(data->state.infilesize != data->req.writebytecount) &&
!data->set.crlf &&
- (ftp->transfer == FTPTRANSFER_BODY)) {
+ (ftp->transfer == PPTRANSFER_BODY)) {
failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
" out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
data->req.bytecount, data->state.infilesize);
@@ -3383,7 +3407,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
/* clear these for next connection */
- ftp->transfer = FTPTRANSFER_BODY;
+ ftp->transfer = PPTRANSFER_BODY;
ftpc->dont_check = FALSE;
/* Send any post-transfer QUOTE strings? */
@@ -3511,7 +3535,7 @@ ftp_pasv_verbose(struct Curl_easy *data,
{
char buf[256];
Curl_printable_address(ai, buf, sizeof(buf));
- infof(data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
+ infof(data, "Connecting to %s (%s) port %d", newhost, buf, port);
}
#endif
@@ -3551,7 +3575,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
/* Ready to do more? */
if(connected) {
- DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
+ DEBUGF(infof(data, "DO-MORE connected phase starts"));
}
else {
if(result && (ftpc->count1 == 0)) {
@@ -3594,7 +3618,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
*completep = 0;
}
- if(ftp->transfer <= FTPTRANSFER_INFO) {
+ if(ftp->transfer <= PPTRANSFER_INFO) {
/* a transfer is about to take place, or if not a file name was given
so we'll do a SIZE on it later and then we need the right TYPE first */
@@ -3620,13 +3644,19 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
}
}
else if(data->set.upload) {
- result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+ result = ftp_nb_type(data, conn, data->state.prefer_ascii,
+ FTP_STOR_TYPE);
if(result)
return result;
result = ftp_multi_statemach(data, &complete);
- /* ftpc->wait_data_conn is always false here */
- *completep = (int)complete;
+ if(ftpc->wait_data_conn)
+ /* if we reach the end of the FTP state machine here, *complete will be
+ TRUE but so is ftpc->wait_data_conn, which says we need to wait for
+ the data connection and therefore we're not actually complete */
+ *completep = 0;
+ else
+ *completep = (int)complete;
}
else {
/* download */
@@ -3641,13 +3671,13 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(result)
;
- else if(data->set.ftp_list_only || !ftpc->file) {
+ else if(data->state.list_only || !ftpc->file) {
/* The specified path ends with a slash, and therefore we think this
is a directory that is requested, use LIST. But before that we
need to set ASCII transfer mode. */
/* But only if a body transfer was requested. */
- if(ftp->transfer == FTPTRANSFER_BODY) {
+ if(ftp->transfer == PPTRANSFER_BODY) {
result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
if(result)
return result;
@@ -3655,7 +3685,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
/* otherwise just fall through */
}
else {
- result = ftp_nb_type(data, conn, data->set.prefer_ascii,
+ result = ftp_nb_type(data, conn, data->state.prefer_ascii,
FTP_RETR_TYPE);
if(result)
return result;
@@ -3673,7 +3703,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
*completep = 1;
- DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
+ DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
}
return result;
@@ -3698,12 +3728,12 @@ CURLcode ftp_perform(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
if(data->set.opt_no_body) {
/* requested no body means no transfer... */
struct FTP *ftp = data->req.p.ftp;
- ftp->transfer = FTPTRANSFER_INFO;
+ ftp->transfer = PPTRANSFER_INFO;
}
*dophase_done = FALSE; /* not done yet */
@@ -3718,10 +3748,10 @@ CURLcode ftp_perform(struct Curl_easy *data,
*connected = conn->bits.tcpconnect[SECONDARYSOCKET];
- infof(data, "ftp_perform ends with SECONDARY: %d\n", *connected);
+ infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete1\n"));
+ DEBUGF(infof(data, "DO phase is complete1"));
}
return result;
@@ -3816,7 +3846,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
/* let the writefunc callback know the transfer */
data->set.out = data;
- infof(data, "Wildcard - Parsing started\n");
+ infof(data, "Wildcard - Parsing started");
return CURLE_OK;
fail:
@@ -3883,7 +3913,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
free(ftp->pathalloc);
ftp->pathalloc = ftp->path = tmp_path;
- infof(data, "Wildcard - START of \"%s\"\n", finfo->filename);
+ infof(data, "Wildcard - START of \"%s\"", finfo->filename);
if(data->set.chunk_bgn) {
long userresponse;
Curl_set_in_callback(data, true);
@@ -3892,7 +3922,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
Curl_set_in_callback(data, false);
switch(userresponse) {
case CURL_CHUNK_BGN_FUNC_SKIP:
- infof(data, "Wildcard - \"%s\" skipped by user\n",
+ infof(data, "Wildcard - \"%s\" skipped by user",
finfo->filename);
wildcard->state = CURLWC_SKIP;
continue;
@@ -4194,7 +4224,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
ftpc->file = NULL; /* instead of point to a zero byte,
we make it a NULL pointer */
- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
+ if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
/* We need a file name when uploading. Return error! */
failf(data, "Uploading to a URL without a file name!");
free(rawPath);
@@ -4215,7 +4245,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
n -= ftpc->file?strlen(ftpc->file):0;
if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
- infof(data, "Request has same path as previous transfer\n");
+ infof(data, "Request has same path as previous transfer");
ftpc->cwddone = TRUE;
}
}
@@ -4242,7 +4272,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
}
}
- if(ftp->transfer != FTPTRANSFER_BODY)
+ if(ftp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
else if(!connected)
@@ -4261,11 +4291,11 @@ static CURLcode ftp_doing(struct Curl_easy *data,
CURLcode result = ftp_multi_statemach(data, dophase_done);
if(result)
- DEBUGF(infof(data, "DO phase failed\n"));
+ DEBUGF(infof(data, "DO phase failed"));
else if(*dophase_done) {
result = ftp_dophase_done(data, FALSE /* not connected */);
- DEBUGF(infof(data, "DO phase is complete2\n"));
+ DEBUGF(infof(data, "DO phase is complete2"));
}
return result;
}
@@ -4346,23 +4376,23 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
switch(command) {
case 'A': /* ASCII mode */
- data->set.prefer_ascii = TRUE;
+ data->state.prefer_ascii = TRUE;
break;
case 'D': /* directory mode */
- data->set.ftp_list_only = TRUE;
+ data->state.list_only = TRUE;
break;
case 'I': /* binary mode */
default:
/* switch off ASCII */
- data->set.prefer_ascii = FALSE;
+ data->state.prefer_ascii = FALSE;
break;
}
}
/* get some initial data into the ftp struct */
- ftp->transfer = FTPTRANSFER_BODY;
+ ftp->transfer = PPTRANSFER_BODY;
ftp->downloadsize = 0;
conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
index d3720b1..716ff38 100644
--- a/Utilities/cmcurl/lib/ftplistparser.c
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -424,7 +424,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
endptr++;
while(ISDIGIT(*endptr))
endptr++;
- if(*endptr != 0) {
+ if(*endptr) {
parser->error = CURLE_FTP_BAD_FILE_LIST;
goto fail;
}
@@ -966,7 +966,6 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
else if(c == '\n') {
parser->offsets.filename = parser->item_offset;
finfo->b_data[finfo->b_used - 1] = 0;
- parser->offsets.filename = parser->item_offset;
result = ftp_pl_insert_finfo(data, infop);
if(result) {
parser->error = result;
diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c
index 67ea07d..9091e61 100644
--- a/Utilities/cmcurl/lib/getinfo.c
+++ b/Utilities/cmcurl/lib/getinfo.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
@@ -94,7 +94,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
{
switch(info) {
case CURLINFO_EFFECTIVE_URL:
- *param_charp = data->change.url?data->change.url:(char *)"";
+ *param_charp = data->state.url?data->state.url:(char *)"";
break;
case CURLINFO_EFFECTIVE_METHOD: {
const char *m = data->set.str[STRING_CUSTOMREQUEST];
@@ -145,6 +145,10 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
option had been enabled! */
*param_charp = data->info.wouldredirect;
break;
+ case CURLINFO_REFERER:
+ /* Return the referrer header for this request, or NULL if unset */
+ *param_charp = data->state.referer;
+ break;
case CURLINFO_PRIMARY_IP:
/* Return the ip address of the most recent (primary) connection */
*param_charp = data->info.conn_primary_ip;
@@ -235,7 +239,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
break;
#endif
case CURLINFO_REDIRECT_COUNT:
- *param_longp = data->set.followlocation;
+ *param_longp = data->state.followlocation;
break;
case CURLINFO_HTTPAUTH_AVAIL:
lptr.to_long = param_longp;
diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c
index a39cc7e..f61232f 100644
--- a/Utilities/cmcurl/lib/gopher.c
+++ b/Utilities/cmcurl/lib/gopher.c
@@ -74,6 +74,7 @@ const struct Curl_handler Curl_handler_gopher = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
CURLPROTO_GOPHER, /* protocol */
CURLPROTO_GOPHER, /* family */
@@ -97,6 +98,7 @@ const struct Curl_handler Curl_handler_gophers = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
CURLPROTO_GOPHERS, /* protocol */
CURLPROTO_GOPHER, /* family */
diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c
index 5d433ad..12e7aa5 100644
--- a/Utilities/cmcurl/lib/hash.c
+++ b/Utilities/cmcurl/lib/hash.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
@@ -245,7 +245,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
struct Curl_hash_element *he = le->ptr;
lnext = le->next;
/* ask the callback function if we shall remove this entry or not */
- if(comp == NULL || comp(user, he->ptr)) {
+ if(!comp || comp(user, he->ptr)) {
Curl_llist_remove(list, le, (void *) h);
--h->size; /* one less entry in the hash now */
}
diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c
index b25de1d..f7d99ce 100644
--- a/Utilities/cmcurl/lib/hostasyn.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c
index 0fef98b..cf267a7 100644
--- a/Utilities/cmcurl/lib/hostcheck.c
+++ b/Utilities/cmcurl/lib/hostcheck.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
@@ -36,7 +36,7 @@
#include "hostcheck.h"
#include "strcase.h"
-#include "inet_pton.h"
+#include "hostip.h"
#include "curl_memory.h"
/* The last #include file should be: */
@@ -67,10 +67,6 @@ static int hostmatch(char *hostname, char *pattern)
const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
int wildcard_enabled;
size_t prefixlen, suffixlen;
- struct in_addr ignored;
-#ifdef ENABLE_IPV6
- struct sockaddr_in6 si6;
-#endif
/* normalize pattern and hostname by stripping off trailing dots */
size_t len = strlen(hostname);
@@ -81,23 +77,19 @@ static int hostmatch(char *hostname, char *pattern)
pattern[len-1] = 0;
pattern_wildcard = strchr(pattern, '*');
- if(pattern_wildcard == NULL)
+ if(!pattern_wildcard)
return strcasecompare(pattern, hostname) ?
CURL_HOST_MATCH : CURL_HOST_NOMATCH;
/* detect IP address as hostname and fail the match if so */
- if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0)
- return CURL_HOST_NOMATCH;
-#ifdef ENABLE_IPV6
- if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0)
+ if(Curl_host_is_ipnum(hostname))
return CURL_HOST_NOMATCH;
-#endif
/* We require at least 2 dots in pattern to avoid too wide wildcard
match. */
wildcard_enabled = 1;
pattern_label_end = strchr(pattern, '.');
- if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL ||
+ if(!pattern_label_end || strchr(pattern_label_end + 1, '.') == NULL ||
pattern_wildcard > pattern_label_end ||
strncasecompare(pattern, "xn--", 4)) {
wildcard_enabled = 0;
@@ -107,7 +99,7 @@ static int hostmatch(char *hostname, char *pattern)
CURL_HOST_MATCH : CURL_HOST_NOMATCH;
hostname_label_end = strchr(hostname, '.');
- if(hostname_label_end == NULL ||
+ if(!hostname_label_end ||
!strcasecompare(pattern_label_end, hostname_label_end))
return CURL_HOST_NOMATCH;
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
index 8ba3fe8..117caa2 100644
--- a/Utilities/cmcurl/lib/hostip.c
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -56,18 +56,22 @@
#include "hash.h"
#include "rand.h"
#include "share.h"
-#include "strerror.h"
#include "url.h"
#include "inet_ntop.h"
#include "inet_pton.h"
#include "multiif.h"
#include "doh.h"
#include "warnless.h"
+#include "strcase.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
+#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
+#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+#endif
+
#if defined(CURLRES_SYNCH) && \
defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
/* alarm-based timeouts can only be used with all the dependencies satisfied */
@@ -269,7 +273,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
/* No entry found in cache, check if we might have a wildcard entry */
- if(!dns && data->change.wildcard_resolve) {
+ if(!dns && data->state.wildcard_resolve) {
create_hostcache_id("*", port, entry_id, sizeof(entry_id));
entry_len = strlen(entry_id);
@@ -285,7 +289,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
user.cache_timeout = data->set.dns_cache_timeout;
if(hostcache_timestamp_remove(&user, dns)) {
- infof(data, "Hostname in DNS cache was stale, zapped\n");
+ infof(data, "Hostname in DNS cache was stale, zapped");
dns = NULL; /* the memory deallocation is being handled by the hash */
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
}
@@ -456,6 +460,127 @@ Curl_cache_addr(struct Curl_easy *data,
return dns;
}
+#ifdef ENABLE_IPV6
+/* return a static IPv6 resolve for 'localhost' */
+static struct Curl_addrinfo *get_localhost6(int port)
+{
+ struct Curl_addrinfo *ca;
+ const size_t ss_size = sizeof(struct sockaddr_in6);
+ const size_t hostlen = strlen("localhost");
+ struct sockaddr_in6 sa6;
+ unsigned char ipv6[16];
+ unsigned short port16 = (unsigned short)(port & 0xffff);
+ ca = calloc(sizeof(struct Curl_addrinfo) + ss_size + hostlen + 1, 1);
+ if(!ca)
+ return NULL;
+
+ sa6.sin6_family = AF_INET6;
+ sa6.sin6_port = htons(port16);
+ sa6.sin6_flowinfo = 0;
+ sa6.sin6_scope_id = 0;
+ if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1)
+ return NULL;
+ memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
+
+ ca->ai_flags = 0;
+ ca->ai_family = AF_INET6;
+ ca->ai_socktype = SOCK_STREAM;
+ ca->ai_protocol = IPPROTO_TCP;
+ ca->ai_addrlen = (curl_socklen_t)ss_size;
+ ca->ai_next = NULL;
+ ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+ memcpy(ca->ai_addr, &sa6, ss_size);
+ ca->ai_canonname = (char *)ca->ai_addr + ss_size;
+ strcpy(ca->ai_canonname, "localhost");
+ return ca;
+}
+#else
+#define get_localhost6(x) NULL
+#endif
+
+/* return a static IPv4 resolve for 'localhost' */
+static struct Curl_addrinfo *get_localhost(int port)
+{
+ struct Curl_addrinfo *ca;
+ const size_t ss_size = sizeof(struct sockaddr_in);
+ const size_t hostlen = strlen("localhost");
+ 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));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port16);
+ if(Curl_inet_pton(AF_INET, "127.0.0.1", (char *)&ipv4) < 1)
+ return NULL;
+ memcpy(&sa.sin_addr, &ipv4, sizeof(ipv4));
+
+ ca->ai_flags = 0;
+ ca->ai_family = AF_INET;
+ ca->ai_socktype = SOCK_STREAM;
+ ca->ai_protocol = IPPROTO_TCP;
+ ca->ai_addrlen = (curl_socklen_t)ss_size;
+ ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
+ memcpy(ca->ai_addr, &sa, ss_size);
+ ca->ai_canonname = (char *)ca->ai_addr + ss_size;
+ strcpy(ca->ai_canonname, "localhost");
+ ca->ai_next = get_localhost6(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.
+ */
+bool Curl_host_is_ipnum(const char *hostname)
+{
+ struct in_addr in;
+#ifdef ENABLE_IPV6
+ struct in6_addr in6;
+#endif
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0
+#ifdef ENABLE_IPV6
+ || Curl_inet_pton(AF_INET6, hostname, &in6) > 0
+#endif
+ )
+ return TRUE;
+ return FALSE;
+}
+
/*
* Curl_resolv() is the main name resolve function within libcurl. It resolves
* a name and returns a pointer to the entry in the 'entry' argument (if one
@@ -466,10 +591,6 @@ Curl_cache_addr(struct Curl_easy *data,
* function is used. You MUST call Curl_resolv_unlock() later (when you're
* done using this struct) to decrease the counter again.
*
- * In debug mode, we specifically test for an interface name "LocalHost"
- * and resolve "localhost" instead as a means to permit test cases
- * to connect to a local test server with any host name.
- *
* Return codes:
*
* CURLRESOLV_ERROR (-1) = error, no pointer
@@ -487,7 +608,6 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
CURLcode result;
enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
struct connectdata *conn = data->conn;
-
*entry = NULL;
conn->bits.doh = FALSE; /* default is not */
@@ -497,7 +617,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
dns = fetch_addr(data, hostname, port);
if(dns) {
- infof(data, "Hostname %s was found in DNS cache\n", hostname);
+ infof(data, "Hostname %s was found in DNS cache", hostname);
dns->inuse++; /* we use it! */
rc = CURLRESOLV_RESOLVED;
}
@@ -520,13 +640,36 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(data->set.resolver_start) {
int st;
Curl_set_in_callback(data, true);
- st = data->set.resolver_start(data->state.async.resolver, NULL,
- data->set.resolver_start_client);
+ st = data->set.resolver_start(
+#ifdef USE_CURL_ASYNC
+ data->state.async.resolver,
+#else
+ NULL,
+#endif
+ NULL,
+ data->set.resolver_start_client);
Curl_set_in_callback(data, false);
if(st)
return CURLRESOLV_ERROR;
}
+#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
+ {
+ /*
+ * The automagic conversion from IPv4 literals to IPv6 literals only
+ * works if the SCDynamicStoreCopyProxies system function gets called
+ * first. As Curl currently doesn't support system-wide HTTP proxies, we
+ * therefore don't use any value this function might return.
+ *
+ * This function is only available on a macOS and is not needed for
+ * IPv4-only builds, hence the conditions above.
+ */
+ CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
+ if(dict)
+ CFRelease(dict);
+ }
+#endif
+
#ifndef USE_RESOLVE_ON_IPS
/* First check if this is an IPv4 address string */
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
@@ -560,25 +703,22 @@ 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(allowDOH && data->set.doh && !ipnum) {
+ if(strcasecompare(hostname, "localhost"))
+ addr = get_localhost(port);
+ 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 */
- addr = Curl_getaddrinfo(data,
-#ifdef DEBUGBUILD
- (data->set.str[STRING_DEVICE]
- && !strcmp(data->set.str[STRING_DEVICE],
- "LocalHost"))?"localhost":
-#endif
- hostname, port, &respwait);
+ addr = Curl_getaddrinfo(data, hostname, port, &respwait);
}
}
if(!addr) {
@@ -625,7 +765,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
* within a signal handler which is nonportable and could lead to problems.
*/
static
-RETSIGTYPE alarmfunc(int sig)
+void alarmfunc(int sig)
{
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void)sig;
@@ -744,7 +884,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
#else
#ifndef CURLRES_ASYNCH
if(timeoutms)
- infof(data, "timeout on name lookup is not supported\n");
+ infof(data, "timeout on name lookup is not supported");
#else
(void)timeoutms; /* timeoutms not used with an async resolver */
#endif
@@ -872,9 +1012,9 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
int port = 0;
/* Default is no wildcard found */
- data->change.wildcard_resolve = false;
+ data->state.wildcard_resolve = false;
- for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
+ for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
char entry_id[MAX_HOSTCACHE_LEN];
if(!hostp->data)
continue;
@@ -882,7 +1022,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
size_t entry_len;
if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
- infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
+ infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'",
hostp->data);
continue;
}
@@ -971,7 +1111,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
#ifndef ENABLE_IPV6
if(strchr(address, ':')) {
- infof(data, "Ignoring resolve address '%s', missing IPv6 support.\n",
+ infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
address);
continue;
}
@@ -979,7 +1119,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
ai = Curl_str2addr(address, port);
if(!ai) {
- infof(data, "Resolve address '%s' found illegal!\n", address);
+ infof(data, "Resolve address '%s' found illegal!", address);
goto err;
}
@@ -998,10 +1138,10 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
error = false;
err:
if(error) {
- infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
+ failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!",
hostp->data);
Curl_freeaddrinfo(head);
- continue;
+ return CURLE_SETOPT_OPTION_SYNTAX;
}
/* Create an entry id, based upon the hostname and port */
@@ -1015,7 +1155,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
if(dns) {
- infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
+ infof(data, "RESOLVE %s:%d is - old addresses discarded!",
hostname, port);
/* delete old entry, there are two reasons for this
1. old entry may have different addresses.
@@ -1048,18 +1188,18 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_freeaddrinfo(head);
return CURLE_OUT_OF_MEMORY;
}
- infof(data, "Added %s:%d:%s to DNS cache%s\n",
+ infof(data, "Added %s:%d:%s to DNS cache%s",
hostname, port, addresses, permanent ? "" : " (non-permanent)");
/* Wildcard hostname */
if(hostname[0] == '*' && hostname[1] == '\0') {
- infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n",
+ infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks",
hostname, port);
- data->change.wildcard_resolve = true;
+ data->state.wildcard_resolve = true;
}
}
}
- data->change.resolve = NULL; /* dealt with now */
+ data->state.resolve = NULL; /* dealt with now */
return CURLE_OK;
}
@@ -1081,7 +1221,7 @@ int Curl_resolv_getsock(struct Curl_easy *data,
{
#ifdef CURLRES_ASYNCH
if(data->conn->bits.doh)
- /* nothing to wait for during DOH resolve, those handles have their own
+ /* nothing to wait for during DoH resolve, those handles have their own
sockets */
return GETSOCK_BLANK;
return Curl_resolver_getsock(data, socks);
@@ -1102,10 +1242,12 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
CURLcode result;
struct connectdata *conn = data->conn;
+#ifdef USE_CURL_ASYNC
if(data->state.async.dns) {
conn->dns_entry = data->state.async.dns;
data->state.async.dns = NULL;
}
+#endif
result = Curl_setup_conn(data, protocol_done);
@@ -1116,3 +1258,34 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
}
return result;
}
+
+/*
+ * Curl_resolver_error() calls failf() with the appropriate message after a
+ * resolve error
+ */
+
+#ifdef USE_CURL_ASYNC
+CURLcode Curl_resolver_error(struct Curl_easy *data)
+{
+ const char *host_or_proxy;
+ CURLcode result;
+
+#ifndef CURL_DISABLE_PROXY
+ struct connectdata *conn = data->conn;
+ if(conn->bits.httpproxy) {
+ host_or_proxy = "proxy";
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ }
+ else
+#endif
+ {
+ host_or_proxy = "host";
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ failf(data, "Could not resolve %s: %s", host_or_proxy,
+ data->state.async.hostname);
+
+ return result;
+}
+#endif /* USE_CURL_ASYNC */
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
index c495c21..67a688a 100644
--- a/Utilities/cmcurl/lib/hostip.h
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -71,6 +71,8 @@ struct Curl_dns_entry {
long inuse;
};
+bool Curl_host_is_ipnum(const char *hostname);
+
/*
* Curl_resolv() returns an entry with the info for the specified host
* and port.
@@ -95,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.
*/
@@ -136,15 +138,6 @@ void Curl_hostcache_prune(struct Curl_easy *data);
/* Return # of addresses in a Curl_addrinfo struct */
int Curl_num_addresses(const struct Curl_addrinfo *addr);
-#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
-int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
- GETNAMEINFO_TYPE_ARG2 salen,
- char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
- char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
- GETNAMEINFO_TYPE_ARG7 flags,
- int line, const char *source);
-#endif
-
/* IPv4 threadsafe resolve function used for synch and asynch builds */
struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
@@ -245,4 +238,5 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
int Curl_resolv_getsock(struct Curl_easy *data,
curl_socket_t *socks);
+CURLcode Curl_resolver_error(struct Curl_easy *data);
#endif /* HEADER_CURL_HOSTIP_H */
diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c
index d0754af..1fd7910 100644
--- a/Utilities/cmcurl/lib/hostip4.c
+++ b/Utilities/cmcurl/lib/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"
@@ -104,7 +103,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
ai = Curl_ipv4_resolve_r(hostname, port);
if(!ai)
- infof(data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+ infof(data, "Curl_ipv4_resolve_r failed for %s", hostname);
return ai;
}
diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c
index 53b3c67..c2d5f08 100644
--- a/Utilities/cmcurl/lib/hostip6.c
+++ b/Utilities/cmcurl/lib/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.
*/
@@ -140,26 +111,13 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
#ifndef USE_RESOLVE_ON_IPS
char addrbuf[128];
#endif
- int pf;
+ int pf = PF_INET;
*waitp = 0; /* synchronous response only */
- /* Check if a limited name resolve has been requested */
- switch(data->set.ipver) {
- case CURL_IPRESOLVE_V4:
- pf = PF_INET;
- break;
- case CURL_IPRESOLVE_V6:
- pf = PF_INET6;
- break;
- default:
+ if(Curl_ipv6works(data))
+ /* The stack seems to be IPv6-enabled */
pf = PF_UNSPEC;
- break;
- }
-
- if((pf != PF_INET) && !Curl_ipv6works(data))
- /* The stack seems to be a non-IPv6 one */
- pf = PF_INET;
memset(&hints, 0, sizeof(hints));
hints.ai_family = pf;
@@ -185,7 +143,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
if(error) {
- infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
+ infof(data, "getaddrinfo(3) failed for %s:%d", hostname, port);
return NULL;
}
diff --git a/Utilities/cmcurl/lib/hostsyn.c b/Utilities/cmcurl/lib/hostsyn.c
index 550b43a..c00c274 100644
--- a/Utilities/cmcurl/lib/hostsyn.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c
index 0e7c19c..853c7df 100644
--- a/Utilities/cmcurl/lib/hsts.c
+++ b/Utilities/cmcurl/lib/hsts.c
@@ -25,7 +25,7 @@
*/
#include "curl_setup.h"
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_HSTS)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
#include <curl/curl.h>
#include "urldata.h"
#include "llist.h"
@@ -37,6 +37,7 @@
#include "parsedate.h"
#include "rand.h"
#include "rename.h"
+#include "strtoofft.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -46,8 +47,6 @@
#define MAX_HSTS_LINE 4095
#define MAX_HSTS_HOSTLEN 256
#define MAX_HSTS_HOSTLENSTR "256"
-#define MAX_HSTS_SUBLEN 4
-#define MAX_HSTS_SUBLENSTR "4"
#define MAX_HSTS_DATELEN 64
#define MAX_HSTS_DATELENSTR "64"
@@ -60,7 +59,10 @@ static time_t debugtime(void *unused)
char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
- unsigned long val = strtol(timestr, NULL, 10) + deltatime;
+ curl_off_t val;
+ (void)curlx_strtoofft(timestr, NULL, 10, &val);
+
+ val += (curl_off_t)deltatime;
return (time_t)val;
}
return time(NULL);
@@ -136,6 +138,11 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
struct stsentry *sts;
time_t now = time(NULL);
+ if(Curl_host_is_ipnum(hostname))
+ /* "explicit IP address identification of all forms is excluded."
+ / RFC 6797 */
+ return CURLE_OK;
+
do {
while(*p && ISSPACE(*p))
p++;
@@ -276,7 +283,7 @@ static CURLcode hsts_push(struct Curl_easy *data,
e.namelen = strlen(sts->host);
e.includeSubDomains = sts->includeSubDomains;
- result = Curl_gmtime(sts->expires, &stamp);
+ result = Curl_gmtime((time_t)sts->expires, &stamp);
if(result)
return result;
@@ -296,7 +303,7 @@ static CURLcode hsts_push(struct Curl_easy *data,
static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
{
struct tm stamp;
- CURLcode result = Curl_gmtime(sts->expires, &stamp);
+ CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
if(result)
return result;
@@ -441,7 +448,10 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
expires = Curl_getdate_capped(e.expire);
else
expires = TIME_T_MAX; /* the end of time */
- result = hsts_create(h, e.name, e.includeSubDomains, expires);
+ result = hsts_create(h, e.name,
+ /* bitfield to bool conversion: */
+ e.includeSubDomains ? TRUE : FALSE,
+ expires);
if(result)
return result;
}
@@ -516,7 +526,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 || USE_HSTS */
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
diff --git a/Utilities/cmcurl/lib/hsts.h b/Utilities/cmcurl/lib/hsts.h
index ae5db74..baa5828 100644
--- a/Utilities/cmcurl/lib/hsts.h
+++ b/Utilities/cmcurl/lib/hsts.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2020 - 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
@@ -23,7 +23,7 @@
***************************************************************************/
#include "curl_setup.h"
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_HSTS)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
#include <curl/curl.h>
#include "llist.h"
@@ -35,7 +35,7 @@ struct stsentry {
struct Curl_llist_element node;
const char *host;
bool includeSubDomains;
- time_t expires; /* the timestamp of this entry's expiry */
+ curl_off_t expires; /* the timestamp of this entry's expiry */
};
/* The HSTS cache. Needs to be able to tailmatch host names. */
@@ -61,5 +61,5 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
#define Curl_hsts_cleanup(x)
#define Curl_hsts_loadcb(x,y)
#define Curl_hsts_save(x,y,z)
-#endif /* CURL_DISABLE_HTTP || USE_HSTS */
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
#endif /* HEADER_CURL_HSTS_H */
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index 6f7f55d..d5c36dd 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -133,6 +133,7 @@ const struct Curl_handler Curl_handler_http = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
CURLPROTO_HTTP, /* protocol */
CURLPROTO_HTTP, /* family */
@@ -160,6 +161,7 @@ const struct Curl_handler Curl_handler_https = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_HTTPS, /* defport */
CURLPROTO_HTTPS, /* protocol */
CURLPROTO_HTTP, /* family */
@@ -183,7 +185,7 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
Curl_mime_initpart(&http->form, data);
data->req.p.http = http;
- if(data->set.httpversion == CURL_HTTP_VERSION_3) {
+ if(data->state.httpwant == CURL_HTTP_VERSION_3) {
if(conn->handler->flags & PROTOPT_SSL)
/* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
the QUIC dance. */
@@ -298,26 +300,27 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
{
size_t size = 0;
char *authorization = NULL;
- struct connectdata *conn = data->conn;
char **userp;
const char *user;
const char *pwd;
CURLcode result;
char *out;
+ /* credentials are unique per transfer for HTTP, do not use the ones for the
+ connection */
if(proxy) {
#ifndef CURL_DISABLE_PROXY
userp = &data->state.aptr.proxyuserpwd;
- user = conn->http_proxy.user;
- pwd = conn->http_proxy.passwd;
+ user = data->state.aptr.proxyuser;
+ pwd = data->state.aptr.proxypasswd;
#else
return CURLE_NOT_BUILT_IN;
#endif
}
else {
userp = &data->state.aptr.userpwd;
- user = conn->user;
- pwd = conn->passwd;
+ user = data->state.aptr.user;
+ pwd = data->state.aptr.passwd;
}
out = aprintf("%s:%s", user, pwd ? pwd : "");
@@ -501,7 +504,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
/* rewind data when completely done sending! */
if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
conn->bits.rewindaftersend = TRUE;
- infof(data, "Rewind stream after send\n");
+ infof(data, "Rewind stream after send");
}
return CURLE_OK;
@@ -512,7 +515,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
return CURLE_OK;
infof(data, "NTLM send, close instead of sending %"
- CURL_FORMAT_CURL_OFF_T " bytes\n",
+ CURL_FORMAT_CURL_OFF_T " bytes",
(curl_off_t)(expectsend - bytessent));
}
#endif
@@ -529,7 +532,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
/* rewind data when completely done sending! */
if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
conn->bits.rewindaftersend = TRUE;
- infof(data, "Rewind stream after send\n");
+ infof(data, "Rewind stream after send");
}
return CURLE_OK;
@@ -540,7 +543,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
return CURLE_OK;
infof(data, "NEGOTIATE send, close instead of sending %"
- CURL_FORMAT_CURL_OFF_T " bytes\n",
+ CURL_FORMAT_CURL_OFF_T " bytes",
(curl_off_t)(expectsend - bytessent));
}
#endif
@@ -595,7 +598,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
conn->httpversion > 11) {
infof(data, "Forcing HTTP/1.1 for NTLM");
connclose(conn, "Force HTTP/1.1 connection");
- data->set.httpversion = CURL_HTTP_VERSION_1_1;
+ data->state.httpwant = CURL_HTTP_VERSION_1_1;
}
}
#ifndef CURL_DISABLE_PROXY
@@ -621,7 +624,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
we must make sure to free it before allocating a new one. As figured
out in bug #2284386 */
Curl_safefree(data->req.newurl);
- data->req.newurl = strdup(data->change.url); /* clone URL */
+ data->req.newurl = strdup(data->state.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
}
@@ -634,7 +637,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
we didn't try HEAD or GET */
if((data->state.httpreq != HTTPREQ_GET) &&
(data->state.httpreq != HTTPREQ_HEAD)) {
- data->req.newurl = strdup(data->change.url); /* clone URL */
+ data->req.newurl = strdup(data->state.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
data->state.authhost.done = TRUE;
@@ -709,7 +712,6 @@ output_auth_headers(struct Curl_easy *data,
if(authstatus->picked == CURLAUTH_DIGEST) {
auth = "Digest";
result = Curl_output_digest(data,
- conn,
proxy,
(const unsigned char *)request,
(const unsigned char *)path);
@@ -740,7 +742,7 @@ output_auth_headers(struct Curl_easy *data,
if(authstatus->picked == CURLAUTH_BEARER) {
/* Bearer */
if((!proxy && data->set.str[STRING_BEARER] &&
- !Curl_checkheaders(data, "Authorization:"))) {
+ !Curl_checkheaders(data, "Authorization"))) {
auth = "Bearer";
result = http_output_bearer(data);
if(result)
@@ -754,13 +756,16 @@ output_auth_headers(struct Curl_easy *data,
if(auth) {
#ifndef CURL_DISABLE_PROXY
- infof(data, "%s auth using %s with user '%s'\n",
+ infof(data, "%s auth using %s with user '%s'",
proxy ? "Proxy" : "Server", auth,
- proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") :
- (conn->user ? conn->user : ""));
+ proxy ? (data->state.aptr.proxyuser ?
+ data->state.aptr.proxyuser : "") :
+ (data->state.aptr.user ?
+ data->state.aptr.user : ""));
#else
- infof(data, "Server auth using %s with user '%s'\n",
- auth, conn->user ? conn->user : "");
+ infof(data, "Server auth using %s with user '%s'",
+ auth, data->state.aptr.user ?
+ data->state.aptr.user : "");
#endif
authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
}
@@ -845,7 +850,9 @@ Curl_http_output_auth(struct Curl_easy *data,
/* To prevent the user+password to get sent to other than the original
host due to a location-follow, we do some weirdo checks here */
if(!data->state.this_is_a_follow ||
+#ifndef CURL_DISABLE_NETRC
conn->bits.netrc ||
+#endif
!data->state.first_host ||
data->set.allow_auth_to_other_hosts ||
strcasecompare(data->state.first_host, conn->host.name)) {
@@ -871,13 +878,17 @@ Curl_http_output_auth(struct Curl_easy *data,
#else
/* when disabled */
CURLcode
-Curl_http_output_auth(struct connectdata *conn,
+Curl_http_output_auth(struct Curl_easy *data,
+ struct connectdata *conn,
const char *request,
+ Curl_HttpReq httpreq,
const char *path,
bool proxytunnel)
{
+ (void)data;
(void)conn;
(void)request;
+ (void)httpreq;
(void)path;
(void)proxytunnel;
return CURLE_OK;
@@ -890,6 +901,11 @@ Curl_http_output_auth(struct connectdata *conn,
* proxy CONNECT loop.
*/
+static int is_valid_auth_separator(char ch)
+{
+ return ch == '\0' || ch == ',' || ISSPACE(ch);
+}
+
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
const char *auth) /* the first non-space */
{
@@ -933,7 +949,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
while(*auth) {
#ifdef USE_SPNEGO
- if(checkprefix("Negotiate", auth)) {
+ if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) {
if((authp->avail & CURLAUTH_NEGOTIATE) ||
Curl_auth_is_spnego_supported()) {
*availp |= CURLAUTH_NEGOTIATE;
@@ -943,7 +959,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
if(!result) {
DEBUGASSERT(!data->req.newurl);
- data->req.newurl = strdup(data->change.url);
+ data->req.newurl = strdup(data->state.url);
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
data->state.authproblem = FALSE;
@@ -959,7 +975,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
#endif
#ifdef USE_NTLM
/* NTLM support requires the SSL crypto libs */
- if(checkprefix("NTLM", auth)) {
+ if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
if((authp->avail & CURLAUTH_NTLM) ||
(authp->avail & CURLAUTH_NTLM_WB) ||
Curl_auth_is_ntlm_supported()) {
@@ -981,14 +997,14 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
result = Curl_input_ntlm_wb(data, conn, proxy, auth);
if(result) {
- infof(data, "Authentication problem. Ignoring this.\n");
+ infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
#endif
}
else {
- infof(data, "Authentication problem. Ignoring this.\n");
+ infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
@@ -997,9 +1013,9 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
else
#endif
#ifndef CURL_DISABLE_CRYPTO_AUTH
- if(checkprefix("Digest", auth)) {
+ if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
if((authp->avail & CURLAUTH_DIGEST) != 0)
- infof(data, "Ignoring duplicate digest auth header.\n");
+ infof(data, "Ignoring duplicate digest auth header.");
else if(Curl_auth_is_digest_supported()) {
CURLcode result;
@@ -1012,14 +1028,15 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
* Digest */
result = Curl_input_digest(data, proxy, auth);
if(result) {
- infof(data, "Authentication problem. Ignoring this.\n");
+ infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
}
else
#endif
- if(checkprefix("Basic", auth)) {
+ if(checkprefix("Basic", auth) &&
+ is_valid_auth_separator(auth[5])) {
*availp |= CURLAUTH_BASIC;
authp->avail |= CURLAUTH_BASIC;
if(authp->picked == CURLAUTH_BASIC) {
@@ -1027,19 +1044,20 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
anyway, which basically means our name+password isn't
valid. */
authp->avail = CURLAUTH_NONE;
- infof(data, "Authentication problem. Ignoring this.\n");
+ infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
else
- if(checkprefix("Bearer", auth)) {
+ if(checkprefix("Bearer", auth) &&
+ is_valid_auth_separator(auth[6])) {
*availp |= CURLAUTH_BEARER;
authp->avail |= CURLAUTH_BEARER;
if(authp->picked == CURLAUTH_BEARER) {
/* We asked for Bearer authentication but got a 40X back
anyway, which basically means our token isn't valid. */
authp->avail = CURLAUTH_NONE;
- infof(data, "Authentication problem. Ignoring this.\n");
+ infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
}
}
@@ -1088,6 +1106,14 @@ static bool http_should_fail(struct Curl_easy *data)
return FALSE;
/*
+ ** A 416 response to a resume request is presumably because the file is
+ ** already completely downloaded and thus not actually a fail.
+ */
+ if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
+ httpcode == 416)
+ return FALSE;
+
+ /*
** Any code >= 400 that's not 401 or 407 is always
** a terminal error
*/
@@ -1152,7 +1178,13 @@ static size_t readmoredata(char *buffer,
/* make sure that a HTTP request is never sent away chunked! */
data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
- if(http->postsize <= (curl_off_t)fullsize) {
+ if(data->set.max_send_speed &&
+ (data->set.max_send_speed < (curl_off_t)fullsize) &&
+ (data->set.max_send_speed < http->postsize))
+ /* speed limit */
+ fullsize = (size_t)data->set.max_send_speed;
+
+ else if(http->postsize <= (curl_off_t)fullsize) {
memcpy(buffer, http->postdata, (size_t)http->postsize);
fullsize = (size_t)http->postsize;
@@ -1192,7 +1224,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
counter */
curl_off_t *bytes_written,
/* how much of the buffer contains body data */
- size_t included_body_bytes,
+ curl_off_t included_body_bytes,
int socketindex)
{
ssize_t amount;
@@ -1215,10 +1247,10 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
ptr = Curl_dyn_ptr(in);
size = Curl_dyn_len(in);
- headersize = size - included_body_bytes; /* the initial part that isn't body
- is header */
+ headersize = size - (size_t)included_body_bytes; /* the initial part that
+ isn't body is header */
- DEBUGASSERT(size > included_body_bytes);
+ DEBUGASSERT(size > (size_t)included_body_bytes);
result = Curl_convert_to_network(data, ptr, headersize);
/* Curl_convert_to_network calls failf if unsuccessful */
@@ -1234,13 +1266,17 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
#endif
)
&& conn->httpversion != 20) {
- /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
- when we speak HTTPS, as if only a fraction of it is sent now, this data
- needs to fit into the normal read-callback buffer later on and that
- buffer is using this size.
+ /* Make sure this doesn't send more body bytes than what the max send
+ speed says. The request bytes do not count to the max speed.
*/
-
- sendsize = CURLMIN(size, CURL_MAX_WRITE_SIZE);
+ if(data->set.max_send_speed &&
+ (included_body_bytes > data->set.max_send_speed)) {
+ curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
+ DEBUGASSERT((size_t)overflow < size);
+ sendsize = size - (size_t)overflow;
+ }
+ else
+ sendsize = size;
/* OpenSSL is very picky and we must send the SAME buffer pointer to the
library when we attempt to re-send this buffer. Sending the same data
@@ -1254,6 +1290,14 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
Curl_dyn_free(in);
return result;
}
+ /* We never send more than upload_buffer_size bytes in one single chunk
+ when we speak HTTPS, as if only a fraction of it is sent now, this data
+ needs to fit into the normal read-callback buffer later on and that
+ buffer is using this size.
+ */
+ if(sendsize > (size_t)data->set.upload_buffer_size)
+ sendsize = (size_t)data->set.upload_buffer_size;
+
memcpy(data->state.ulbuf, ptr, sendsize);
ptr = data->state.ulbuf;
}
@@ -1272,7 +1316,19 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
}
else
#endif
- sendsize = size;
+ {
+ /* Make sure this doesn't send more body bytes than what the max send
+ speed says. The request bytes do not count to the max speed.
+ */
+ if(data->set.max_send_speed &&
+ (included_body_bytes > data->set.max_send_speed)) {
+ curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
+ DEBUGASSERT((size_t)overflow < size);
+ sendsize = size - (size_t)overflow;
+ }
+ else
+ sendsize = size;
+ }
}
result = Curl_write(data, sockfd, ptr, sendsize, &amount);
@@ -1484,38 +1540,35 @@ static int http_getsock_do(struct Curl_easy *data,
#ifndef CURL_DISABLE_PROXY
static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
{
- char proxy_header[128];
struct dynbuf req;
CURLcode result;
- char tcp_version[5];
+ const char *tcp_version;
DEBUGASSERT(data->conn);
+ Curl_dyn_init(&req, DYN_HAXPROXY);
- /* Emit the correct prefix for IPv6 */
- if(data->conn->bits.ipv6) {
- strcpy(tcp_version, "TCP6");
- }
+#ifdef USE_UNIX_SOCKETS
+ if(data->conn->unix_domain_socket)
+ /* the buffer is large enough to hold this! */
+ result = Curl_dyn_add(&req, "PROXY UNKNOWN\r\n");
else {
- strcpy(tcp_version, "TCP4");
- }
-
- msnprintf(proxy_header,
- sizeof(proxy_header),
- "PROXY %s %s %s %li %li\r\n",
- tcp_version,
- data->info.conn_local_ip,
- data->info.conn_primary_ip,
- data->info.conn_local_port,
- data->info.conn_primary_port);
-
- Curl_dyn_init(&req, DYN_HAXPROXY);
+#endif
+ /* Emit the correct prefix for IPv6 */
+ tcp_version = data->conn->bits.ipv6 ? "TCP6" : "TCP4";
- result = Curl_dyn_add(&req, proxy_header);
- if(result)
- return result;
+ result = Curl_dyn_addf(&req, "PROXY %s %s %s %i %i\r\n",
+ tcp_version,
+ data->info.conn_local_ip,
+ data->info.conn_primary_ip,
+ data->info.conn_local_port,
+ data->info.conn_primary_port);
- result = Curl_buffer_send(&req, data, &data->info.request_size,
- 0, FIRSTSOCKET);
+#ifdef USE_UNIX_SOCKETS
+ }
+#endif
+ if(!result)
+ result = Curl_buffer_send(&req, data, &data->info.request_size,
+ 0, FIRSTSOCKET);
return result;
}
#endif
@@ -1535,7 +1588,7 @@ static CURLcode https_connecting(struct Curl_easy *data, bool *done)
#endif
/* perform SSL initialization for this socket */
- result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET, done);
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET, done);
if(result)
connclose(conn, "Failed HTTPS connection");
@@ -1548,7 +1601,7 @@ static int https_getsock(struct Curl_easy *data,
{
(void)data;
if(conn->handler->flags & PROTOPT_SSL)
- return Curl_ssl_getsock(conn, socks);
+ return Curl_ssl->getsock(conn, socks);
return GETSOCK_BLANK;
}
#endif /* USE_SSL */
@@ -1616,16 +1669,16 @@ 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;
- if((data->set.httpversion == CURL_HTTP_VERSION_1_0) &&
+ if((data->state.httpwant == CURL_HTTP_VERSION_1_0) &&
(conn->httpversion <= 10))
return FALSE;
- return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) ||
- (data->set.httpversion >= CURL_HTTP_VERSION_1_1));
+ return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) ||
+ (data->state.httpwant >= CURL_HTTP_VERSION_1_1));
}
#ifndef USE_HYPER
@@ -1633,7 +1686,7 @@ static const char *get_http_string(const struct Curl_easy *data,
const struct connectdata *conn)
{
#ifdef ENABLE_QUIC
- if((data->set.httpversion == CURL_HTTP_VERSION_3) ||
+ if((data->state.httpwant == CURL_HTTP_VERSION_3) ||
(conn->httpversion == 30))
return "3";
#endif
@@ -1643,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";
@@ -1658,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
@@ -1698,7 +1751,7 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
if(
#ifdef CURL_DO_LINEEND_CONV
- (handle->set.prefer_ascii) ||
+ (handle->state.prefer_ascii) ||
#endif
(handle->set.crlf)) {
/* \n will become \r\n later on */
@@ -1960,10 +2013,10 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
}
#else
/* disabled */
-CURLcode Curl_add_timecondition(const struct connectdata *conn,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
struct dynbuf *req)
{
- (void)conn;
+ (void)data;
(void)req;
return CURLE_OK;
}
@@ -2174,7 +2227,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
/* Extract the URL to use in the request. Store in STRING_TEMP_URL for
clean-up reasons if the function returns before the free() further
down. */
- uc = curl_url_get(h, CURLUPART_URL, &url, 0);
+ uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
@@ -2205,7 +2258,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
}
if(!type) {
result = Curl_dyn_addf(r, ";type=%c",
- data->set.prefer_ascii ? 'a' : 'i');
+ data->state.prefer_ascii ? 'a' : 'i');
if(result)
return result;
}
@@ -2295,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;
@@ -2614,8 +2667,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
}
}
/* issue the request */
- result = Curl_buffer_send(r, data, &data->info.request_size,
- (size_t)included_body, FIRSTSOCKET);
+ result = Curl_buffer_send(r, data, &data->info.request_size, included_body,
+ FIRSTSOCKET);
if(result)
failf(data, "Failed sending HTTP POST request");
@@ -2658,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) {
@@ -2848,6 +2903,20 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
{
struct SingleRequest *k = &data->req;
DEBUGASSERT(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP));
+ if(data->req.ignore_cl) {
+ k->size = k->maxdownload = -1;
+ }
+ else if(k->size != -1) {
+ /* We wait until after all headers have been received to set this so that
+ we know for sure Content-Length is valid. */
+ 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);
+ }
+
if(data->req.newurl) {
if(conn->bits.close) {
/* Abort after the headers if "follow Location" is set
@@ -2859,7 +2928,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
/* We have a new url to load, but since we want to be able to re-use this
connection properly, we read the full response in "ignore more" */
k->ignorebody = TRUE;
- infof(data, "Ignoring the response-body\n");
+ infof(data, "Ignoring the response-body");
}
if(data->state.resume_from && !k->content_range &&
(data->state.httpreq == HTTPREQ_GET) &&
@@ -2894,7 +2963,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
/* We're simulating a http 304 from server so we return
what should have been returned from the server */
data->info.httpcode = 304;
- infof(data, "Simulate a HTTP 304 response!\n");
+ infof(data, "Simulate a HTTP 304 response!");
/* we abort the transfer before it is completed == we ruin the
re-use ability. Close the connection */
connclose(conn, "Simulated 304 handling");
@@ -2905,6 +2974,39 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
return CURLE_OK;
}
+#ifdef HAVE_LIBZ
+CURLcode Curl_transferencode(struct Curl_easy *data)
+{
+ if(!Curl_checkheaders(data, "TE") &&
+ data->set.http_transfer_encoding) {
+ /* When we are to insert a TE: header in the request, we must also insert
+ TE in a Connection: header, so we need to merge the custom provided
+ Connection: header and prevent the original to get sent. Note that if
+ the user has inserted his/her own TE: header we don't do this magic
+ but then assume that the user will handle it all! */
+ char *cptr = Curl_checkheaders(data, "Connection");
+#define TE_HEADER "TE: gzip\r\n"
+
+ Curl_safefree(data->state.aptr.te);
+
+ if(cptr) {
+ cptr = Curl_copy_header_value(cptr);
+ if(!cptr)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Create the (updated) Connection: header */
+ data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
+ cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
+
+ free(cptr);
+ if(!data->state.aptr.te)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ return CURLE_OK;
+}
+#endif
+
#ifndef USE_HYPER
/*
* Curl_http() gets called from the generic multi_do() function when a HTTP
@@ -2946,16 +3048,16 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
default:
/* Check if user wants to use HTTP/2 with clear TCP*/
#ifdef USE_NGHTTP2
- if(data->set.httpversion == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+ if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* We don't support HTTP/2 proxies yet. Also it's debatable
whether or not this setting should apply to HTTP/2 proxies. */
- infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
+ infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
break;
}
#endif
- DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
+ DEBUGF(infof(data, "HTTP/2 over clean TCP"));
conn->httpversion = 20;
result = Curl_http2_switched(data, NULL, 0);
@@ -3002,8 +3104,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
}
Curl_safefree(data->state.aptr.ref);
- if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
- data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ 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;
}
@@ -3016,40 +3118,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!data->state.aptr.accept_encoding)
return CURLE_OUT_OF_MEMORY;
}
- else {
+ else
Curl_safefree(data->state.aptr.accept_encoding);
- data->state.aptr.accept_encoding = NULL;
- }
#ifdef HAVE_LIBZ
/* we only consider transfer-encoding magic if libz support is built-in */
-
- if(!Curl_checkheaders(data, "TE") &&
- data->set.http_transfer_encoding) {
- /* When we are to insert a TE: header in the request, we must also insert
- TE in a Connection: header, so we need to merge the custom provided
- Connection: header and prevent the original to get sent. Note that if
- the user has inserted his/her own TE: header we don't do this magic
- but then assume that the user will handle it all! */
- char *cptr = Curl_checkheaders(data, "Connection");
-#define TE_HEADER "TE: gzip\r\n"
-
- Curl_safefree(data->state.aptr.te);
-
- if(cptr) {
- cptr = Curl_copy_header_value(cptr);
- if(!cptr)
- return CURLE_OUT_OF_MEMORY;
- }
-
- /* Create the (updated) Connection: header */
- data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
- cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
-
- free(cptr);
- if(!data->state.aptr.te)
- return CURLE_OUT_OF_MEMORY;
- }
+ result = Curl_transferencode(data);
+ if(result)
+ return result;
#endif
result = Curl_http_body(data, conn, httpreq, &te);
@@ -3071,6 +3147,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* initialize a dynamic send-buffer */
Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+ /* make sure the header buffer is reset - if there are leftovers from a
+ previous transfer */
+ Curl_dyn_reset(&data->state.headerb);
+
/* add the main request stuff */
/* GET/HEAD/POST/PUT */
result = Curl_dyn_addf(&req, "%s ", request);
@@ -3124,7 +3204,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
*data->set.str[STRING_ENCODING] &&
data->state.aptr.accept_encoding)?
data->state.aptr.accept_encoding:"",
- (data->change.referer && data->state.aptr.ref)?
+ (data->state.referer && data->state.aptr.ref)?
data->state.aptr.ref:"" /* Referer: <data> */,
#ifndef CURL_DISABLE_PROXY
(conn->bits.httpproxy &&
@@ -3152,10 +3232,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!(conn->handler->flags&PROTOPT_SSL) &&
conn->httpversion != 20 &&
- (data->set.httpversion == CURL_HTTP_VERSION_2)) {
+ (data->state.httpwant == CURL_HTTP_VERSION_2)) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
over SSL */
- result = Curl_http2_request_upgrade(&req, conn);
+ result = Curl_http2_request_upgrade(&req, data);
if(result) {
Curl_dyn_free(&req);
return result;
@@ -3198,7 +3278,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* already sent the entire request body, mark the "upload" as
complete */
infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
- " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ " out of %" CURL_FORMAT_CURL_OFF_T " bytes",
data->req.writebytecount, http->postsize);
data->req.upload_done = TRUE;
data->req.keepon &= ~KEEP_SEND; /* we're done writing */
@@ -3333,20 +3413,12 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
if(!k->http_bodyless &&
!data->set.ignorecl && checkprefix("Content-Length:", headp)) {
curl_off_t contentlength;
- CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength);
+ CURLofft offt = curlx_strtoofft(headp + strlen("Content-Length:"),
+ 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 */
@@ -3355,7 +3427,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
return CURLE_FILESIZE_EXCEEDED;
}
streamclose(conn, "overflow content-length");
- infof(data, "Overflow Content-Length: value!\n");
+ infof(data, "Overflow Content-Length: value!");
}
else {
/* negative or just rubbish - bad HTTP */
@@ -3387,7 +3459,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
* Default action for 1.0 is to close.
*/
connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
- infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
+ infof(data, "HTTP/1.0 proxy connection set to keep alive!");
}
else if((conn->httpversion == 11) &&
conn->bits.httpproxy &&
@@ -3397,7 +3469,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
* close down after this transfer.
*/
connclose(conn, "Proxy-Connection: asked to close after done");
- infof(data, "HTTP/1.1 proxy connection set close!\n");
+ infof(data, "HTTP/1.1 proxy connection set close!");
}
#endif
else if((conn->httpversion == 10) &&
@@ -3409,7 +3481,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
*
* [RFC2068, section 19.7.1] */
connkeep(conn, "Connection keep-alive");
- infof(data, "HTTP/1.0 connection set to keep alive!\n");
+ infof(data, "HTTP/1.0 connection set to keep alive!");
}
else if(Curl_compareheader(headp, "Connection:", "close")) {
/*
@@ -3432,9 +3504,17 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
* of chunks, and a chunk-data set to zero signals the
* end-of-chunks. */
- result = Curl_build_unencoding_stack(data, headp + 18, TRUE);
+ result = Curl_build_unencoding_stack(data,
+ headp + strlen("Transfer-Encoding:"),
+ 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]) {
@@ -3445,17 +3525,20 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
* 2616). zlib cannot handle compress. However, errors are
* handled further down when the response body is processed
*/
- result = Curl_build_unencoding_stack(data, headp + 17, FALSE);
+ result = Curl_build_unencoding_stack(data,
+ headp + strlen("Content-Encoding:"),
+ FALSE);
if(result)
return result;
}
else if(checkprefix("Retry-After:", headp)) {
/* Retry-After = HTTP-date / delay-seconds */
curl_off_t retry_after = 0; /* zero for unknown or "now" */
- time_t date = Curl_getdate_capped(&headp[12]);
+ time_t date = Curl_getdate_capped(headp + strlen("Retry-After:"));
if(-1 == date) {
/* not a date, try it as a decimal number */
- (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after);
+ (void)curlx_strtoofft(headp + strlen("Retry-After:"),
+ NULL, 10, &retry_after);
}
else
/* convert date to number of seconds into the future */
@@ -3474,7 +3557,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
The forth means the requested range was unsatisfied.
*/
- char *ptr = headp + 14;
+ char *ptr = headp + strlen("Content-Range:");
/* Move forward until first digit or asterisk */
while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
@@ -3494,17 +3577,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 + 11,
- /* 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
@@ -3532,7 +3619,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
return result;
}
#ifdef USE_SPNEGO
- else if(checkprefix("Persistent-Auth", headp)) {
+ else if(checkprefix("Persistent-Auth:", headp)) {
struct negotiatedata *negdata = &conn->negotiate;
struct auth *authp = &data->state.authhost;
if(authp->picked == CURLAUTH_NEGOTIATE) {
@@ -3576,18 +3663,18 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
}
}
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
/* If enabled, the header is incoming and this is over HTTPS */
else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) &&
(conn->handler->flags & PROTOPT_SSL)) {
CURLcode check =
Curl_hsts_parse(data->hsts, data->state.up.hostname,
- &headp[ sizeof("Strict-Transport-Security:") -1 ]);
+ headp + strlen("Strict-Transport-Security:"));
if(check)
- infof(data, "Illegal STS header skipped\n");
+ infof(data, "Illegal STS header skipped");
#ifdef DEBUGBUILD
else
- infof(data, "Parsed STS header fine (%zu entries)\n",
+ infof(data, "Parsed STS header fine (%zu entries)",
data->hsts->list.size);
#endif
}
@@ -3606,7 +3693,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
/* the ALPN of the current request */
enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
result = Curl_altsvc_parse(data, data->asi,
- &headp[ strlen("Alt-Svc:") ],
+ headp + strlen("Alt-Svc:"),
id, conn->host.name,
curlx_uitous(conn->remote_port));
if(result)
@@ -3657,12 +3744,12 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
/* Default action for HTTP/1.0 must be to close, unless
we get one of those fancy headers that tell us the
server keeps it open for us! */
- infof(data, "HTTP 1.0, assume close after body\n");
+ infof(data, "HTTP 1.0, assume close after body");
connclose(conn, "HTTP/1.0 close after body");
}
else if(conn->httpversion == 20 ||
(k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
- DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
+ DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
/* HTTP/2 cannot avoid multiplexing since it is a core functionality
of the protocol */
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
@@ -3671,7 +3758,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
!conn->bits.close) {
/* If HTTP version is >= 1.1 and connection is persistent */
DEBUGF(infof(data,
- "HTTP 1.1 or later with persistent connection\n"));
+ "HTTP 1.1 or later with persistent connection"));
}
k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
@@ -3849,7 +3936,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* Switching Protocols */
if(k->upgr101 == UPGR101_REQUESTED) {
/* Switching to HTTP/2 */
- infof(data, "Received 101\n");
+ infof(data, "Received 101");
k->upgr101 = UPGR101_RECEIVED;
/* we'll get more headers (HTTP/2 response) */
@@ -3889,7 +3976,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
assume that the server will close the connection to
signal the end of the document. */
infof(data, "no chunk, no close, no size. Assume close to "
- "signal end\n");
+ "signal end");
streamclose(conn, "HTTP: No end-of-message indicator");
}
}
@@ -3902,7 +3989,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
(conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
((data->req.httpcode == 407) &&
(conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
- infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
data->state.authproblem = TRUE;
}
#endif
@@ -3912,7 +3999,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
(conn->http_negotiate_state == GSS_AUTHRECV)) ||
((data->req.httpcode == 407) &&
(conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
- infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
data->state.authproblem = TRUE;
}
if((conn->http_negotiate_state == GSS_AUTHDONE) &&
@@ -3992,21 +4079,21 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if((k->httpcode == 417) && data->state.expect100header) {
/* 417 Expectation Failed - try again without the Expect
header */
- infof(data, "Got 417 while waiting for a 100\n");
+ infof(data, "Got 417 while waiting for a 100");
data->state.disableexpect = TRUE;
DEBUGASSERT(!data->req.newurl);
- data->req.newurl = strdup(data->change.url);
+ data->req.newurl = strdup(data->state.url);
Curl_done_sending(data, k);
}
else if(data->set.http_keep_sending_on_error) {
- infof(data, "HTTP error before end of send, keep sending\n");
+ infof(data, "HTTP error before end of send, keep sending");
if(k->exp100 > EXP100_SEND_DATA) {
k->exp100 = EXP100_SEND_DATA;
k->keepon |= KEEP_SEND;
}
}
else {
- infof(data, "HTTP error before end of send, stop sending\n");
+ infof(data, "HTTP error before end of send, stop sending");
streamclose(conn, "Stop sending data before everything sent");
result = Curl_done_sending(data, k);
if(result)
@@ -4026,7 +4113,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(conn->bits.rewindaftersend) {
/* We rewind after a complete send, so thus we continue
sending now */
- infof(data, "Keep sending data to get tossed away!\n");
+ infof(data, "Keep sending data to get tossed away!");
k->keepon |= KEEP_SEND;
}
}
@@ -4139,17 +4226,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;
+ int digit4 = -1; /* should remain untouched to be good */
nc = sscanf(HEADER1,
- " HTTP/%1d.%1d%c%3d",
+ " HTTP/%1d.%1d%c%3d%1d",
&httpversion_major,
- &conn->httpversion,
+ &httpversion,
&separator,
- &k->httpcode);
+ &k->httpcode,
+ &digit4);
if(nc == 1 && httpversion_major >= 2 &&
2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) {
@@ -4158,17 +4248,41 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
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 is not -1 */
+ else if(digit4 != -1) {
+ failf(data, "Unsupported response code in HTTP response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+
if((nc == 4) && (' ' == separator)) {
- conn->httpversion += 10 * httpversion_major;
+ httpversion += 10 * httpversion_major;
+ switch(httpversion) {
+ case 10:
+ case 11:
+#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+ case 20:
+#endif
+#if defined(ENABLE_QUIC)
+ case 30:
+#endif
+ conn->httpversion = (unsigned char)httpversion;
+ break;
+ default:
+ failf(data, "Unsupported HTTP version (%u.%d) in response",
+ httpversion/10, httpversion%10);
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
if(k->upgr101 == UPGR101_RECEIVED) {
/* supposedly upgraded to http2 now */
if(conn->httpversion != 20)
- infof(data, "Lying server, not serving HTTP/2\n");
+ infof(data, "Lying server, not serving HTTP/2");
}
if(conn->httpversion < 20) {
conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
- infof(data, "Mark bundle as not supporting multiuse\n");
+ infof(data, "Mark bundle as not supporting multiuse");
}
}
else if(!nc) {
@@ -4200,14 +4314,14 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
else if(conn->handler->protocol & CURLPROTO_RTSP) {
char separator;
+ int rtspversion;
nc = sscanf(HEADER1,
" RTSP/%1d.%1d%c%3d",
&rtspversion_major,
- &conn->rtspversion,
+ &rtspversion,
&separator,
&k->httpcode);
if((nc == 4) && (' ' == separator)) {
- conn->rtspversion += 10 * rtspversion_major;
conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
}
else {
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
index 28f9341..e4ab466 100644
--- a/Utilities/cmcurl/lib/http.h
+++ b/Utilities/cmcurl/lib/http.h
@@ -58,7 +58,7 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
CURLcode Curl_buffer_send(struct dynbuf *in,
struct Curl_easy *data,
curl_off_t *bytes_written,
- size_t included_body_bytes,
+ curl_off_t included_body_bytes,
int socketindex);
#else
#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
@@ -93,11 +93,14 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
struct connectdata *conn);
CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
char *headp);
+CURLcode Curl_transferencode(struct Curl_easy *data);
CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
Curl_HttpReq httpreq,
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,
@@ -184,8 +187,7 @@ struct HTTP {
enum {
HTTPSEND_NADA, /* init */
HTTPSEND_REQUEST, /* sending a request */
- HTTPSEND_BODY, /* sending body */
- HTTPSEND_LAST /* never use this */
+ HTTPSEND_BODY /* sending body */
} sending;
#ifndef CURL_DISABLE_HTTP
@@ -211,6 +213,7 @@ struct HTTP {
char **push_headers; /* allocated array */
size_t push_headers_used; /* number of entries filled in */
size_t push_headers_alloc; /* number of entries allocated */
+ uint32_t error; /* HTTP/2 stream error code */
#endif
#if defined(USE_NGHTTP2) || defined(USE_NGHTTP3)
bool closed; /* TRUE on HTTP2 stream close */
@@ -251,9 +254,16 @@ struct h2settings {
struct http_conn {
#ifdef USE_NGHTTP2
#define H2_BINSETTINGS_LEN 80
- nghttp2_session *h2;
uint8_t binsettings[H2_BINSETTINGS_LEN];
size_t binlen; /* length of the binsettings data */
+
+ /* We associate the connnectdata struct with the connection, but we need to
+ make sure we can identify the current "driving" transfer. This is a
+ work-around for the lack of nghttp2_session_set_user_data() in older
+ nghttp2 versions that we want to support. (Added in 1.31.0) */
+ struct Curl_easy *trnsfr;
+
+ nghttp2_session *h2;
Curl_send *send_underlying; /* underlying send Curl_send callback */
Curl_recv *recv_underlying; /* underlying recv Curl_recv callback */
char *inbuf; /* buffer to receive data from underlying socket */
@@ -274,7 +284,6 @@ struct http_conn {
/* list of settings that will be sent */
nghttp2_settings_entry local_settings[3];
size_t local_settings_num;
- uint32_t error_code; /* HTTP/2 error code */
#else
int unused; /* prevent a compiler warning */
#endif
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
index be4c712..a3de607 100644
--- a/Utilities/cmcurl/lib/http2.c
+++ b/Utilities/cmcurl/lib/http2.c
@@ -146,12 +146,12 @@ static CURLcode http2_disconnect(struct Curl_easy *data,
(void)data;
#endif
- H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now\n"));
+ H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now"));
nghttp2_session_del(c->h2);
Curl_safefree(c->inbuf);
- H2BUGF(infof(data, "HTTP/2 DISCONNECT done\n"));
+ H2BUGF(infof(data, "HTTP/2 DISCONNECT done"));
return CURLE_OK;
}
@@ -196,11 +196,13 @@ static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
if(nread != -1) {
infof(data,
- "%d bytes stray data read before trying h2 connection\n",
+ "%d bytes stray data read before trying h2 connection",
(int)nread);
httpc->nread_inbuf = 0;
httpc->inbuflen = nread;
- (void)h2_process_pending_input(data, httpc, &result);
+ if(h2_process_pending_input(data, httpc, &result) < 0)
+ /* immediate error, considered dead */
+ dead = TRUE;
}
else
/* the read failed so let's say this is dead anyway */
@@ -211,6 +213,24 @@ static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
return dead;
}
+/*
+ * Set the transfer that is currently using this HTTP/2 connection.
+ */
+static void set_transfer(struct http_conn *c,
+ struct Curl_easy *data)
+{
+ c->trnsfr = data;
+}
+
+/*
+ * Get the transfer that is currently using this HTTP/2 connection.
+ */
+static struct Curl_easy *get_transfer(struct http_conn *c)
+{
+ DEBUGASSERT(c && c->trnsfr);
+ return c->trnsfr;
+}
+
static unsigned int http2_conncheck(struct Curl_easy *data,
struct connectdata *conn,
unsigned int checks_to_perform)
@@ -247,6 +267,7 @@ static unsigned int http2_conncheck(struct Curl_easy *data,
}
if(send_frames) {
+ set_transfer(c, data); /* set the transfer */
rc = nghttp2_session_send(c->h2);
if(rc)
failf(data, "nghttp2_session_send() failed: %s(%d)",
@@ -269,6 +290,7 @@ void Curl_http2_setup_req(struct Curl_easy *data)
http->mem = NULL;
http->len = 0;
http->memlen = 0;
+ http->error = NGHTTP2_NO_ERROR;
}
/* called from http_setup_conn */
@@ -276,7 +298,6 @@ void Curl_http2_setup_conn(struct connectdata *conn)
{
conn->proto.httpc.settings.max_concurrent_streams =
DEFAULT_MAX_CONCURRENT_STREAMS;
- conn->proto.httpc.error_code = NGHTTP2_NO_ERROR;
}
/*
@@ -300,6 +321,7 @@ static const struct Curl_handler Curl_handler_http2 = {
http2_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
http2_conncheck, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
CURLPROTO_HTTP, /* protocol */
CURLPROTO_HTTP, /* family */
@@ -322,6 +344,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
http2_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
http2_conncheck, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
CURLPROTO_HTTPS, /* protocol */
CURLPROTO_HTTP, /* family */
@@ -329,13 +352,12 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
};
/*
- * Store nghttp2 version info in this buffer, Prefix with a space. Return
- * total length written.
+ * Store nghttp2 version info in this buffer.
*/
-int Curl_http2_ver(char *p, size_t len)
+void Curl_http2_ver(char *p, size_t len)
{
nghttp2_info *h2 = nghttp2_version(0);
- return msnprintf(p, len, "nghttp2/%s", h2->version_str);
+ (void)msnprintf(p, len, "nghttp2/%s", h2->version_str);
}
/*
@@ -349,6 +371,7 @@ static ssize_t send_callback(nghttp2_session *h2,
{
struct connectdata *conn = (struct connectdata *)userp;
struct http_conn *c = &conn->proto.httpc;
+ struct Curl_easy *data = get_transfer(c);
ssize_t written;
CURLcode result = CURLE_OK;
@@ -359,7 +382,7 @@ static ssize_t send_callback(nghttp2_session *h2,
/* called before setup properly! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
- written = ((Curl_send*)c->send_underlying)(conn->data, FIRSTSOCKET,
+ written = ((Curl_send*)c->send_underlying)(data, FIRSTSOCKET,
mem, length, &result);
if(result == CURLE_AGAIN) {
@@ -367,7 +390,7 @@ static ssize_t send_callback(nghttp2_session *h2,
}
if(written == -1) {
- failf(conn->data, "Failed sending HTTP2 data");
+ failf(data, "Failed sending HTTP2 data");
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
@@ -479,38 +502,48 @@ static int set_transfer_url(struct Curl_easy *data,
const char *v;
CURLU *u = curl_url();
CURLUcode uc;
- char *url;
+ char *url = NULL;
+ int rc = 0;
v = curl_pushheader_byname(hp, ":scheme");
if(v) {
uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
- if(uc)
- return 1;
+ if(uc) {
+ rc = 1;
+ goto fail;
+ }
}
v = curl_pushheader_byname(hp, ":authority");
if(v) {
uc = curl_url_set(u, CURLUPART_HOST, v, 0);
- if(uc)
- return 2;
+ if(uc) {
+ rc = 2;
+ goto fail;
+ }
}
v = curl_pushheader_byname(hp, ":path");
if(v) {
uc = curl_url_set(u, CURLUPART_PATH, v, 0);
- if(uc)
- return 3;
+ if(uc) {
+ rc = 3;
+ goto fail;
+ }
}
uc = curl_url_get(u, CURLUPART_URL, &url, 0);
if(uc)
- return 4;
+ rc = 4;
+ fail:
curl_url_cleanup(u);
+ if(rc)
+ return rc;
- if(data->change.url_alloc)
- free(data->change.url);
- data->change.url_alloc = TRUE;
- data->change.url = url;
+ if(data->state.url_alloc)
+ free(data->state.url);
+ data->state.url_alloc = TRUE;
+ data->state.url = url;
return 0;
}
@@ -519,7 +552,7 @@ static int push_promise(struct Curl_easy *data,
const nghttp2_push_promise *frame)
{
int rv; /* one of the CURL_PUSH_* defines */
- H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
+ H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!",
frame->promised_stream_id));
if(data->multi->push_cb) {
struct HTTP *stream;
@@ -531,7 +564,7 @@ static int push_promise(struct Curl_easy *data,
/* clone the parent */
struct Curl_easy *newhandle = duphandle(data);
if(!newhandle) {
- infof(data, "failed to duplicate handle\n");
+ infof(data, "failed to duplicate handle");
rv = CURL_PUSH_DENY; /* FAIL HARD */
goto fail;
}
@@ -539,7 +572,7 @@ static int push_promise(struct Curl_easy *data,
heads.data = data;
heads.frame = frame;
/* ask the application */
- H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
+ H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!"));
stream = data->req.p.http;
if(!stream) {
@@ -551,6 +584,7 @@ static int push_promise(struct Curl_easy *data,
rv = set_transfer_url(newhandle, &heads);
if(rv) {
+ (void)Curl_close(&newhandle);
rv = CURL_PUSH_DENY;
goto fail;
}
@@ -586,7 +620,7 @@ static int push_promise(struct Curl_easy *data,
state with the given connection !*/
rc = Curl_multi_add_perform(data->multi, newhandle, conn);
if(rc) {
- infof(data, "failed to add handle to multi\n");
+ infof(data, "failed to add handle to multi");
http2_stream_free(newhandle->req.p.http);
newhandle->req.p.http = NULL;
Curl_close(&newhandle);
@@ -599,15 +633,17 @@ static int push_promise(struct Curl_easy *data,
frame->promised_stream_id,
newhandle);
if(rv) {
- infof(data, "failed to set user_data for stream %d\n",
+ infof(data, "failed to set user_data for stream %d",
frame->promised_stream_id);
DEBUGASSERT(0);
rv = CURL_PUSH_DENY;
goto fail;
}
+ Curl_dyn_init(&newstream->header_recvbuf, DYN_H2_HEADERS);
+ Curl_dyn_init(&newstream->trailer_recvbuf, DYN_H2_TRAILERS);
}
else {
- H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
+ H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!"));
rv = CURL_PUSH_DENY;
}
fail:
@@ -633,6 +669,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
struct http_conn *httpc = &conn->proto.httpc;
struct Curl_easy *data_s = NULL;
struct HTTP *stream = NULL;
+ struct Curl_easy *data = get_transfer(httpc);
int rv;
size_t left, ncopy;
int32_t stream_id = frame->hd.stream_id;
@@ -642,43 +679,43 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
/* stream ID zero is for connection-oriented stuff */
if(frame->hd.type == NGHTTP2_SETTINGS) {
uint32_t max_conn = httpc->settings.max_concurrent_streams;
- H2BUGF(infof(conn->data, "Got SETTINGS\n"));
+ H2BUGF(infof(data, "Got SETTINGS"));
httpc->settings.max_concurrent_streams =
nghttp2_session_get_remote_settings(
session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
httpc->settings.enable_push =
nghttp2_session_get_remote_settings(
session, NGHTTP2_SETTINGS_ENABLE_PUSH);
- H2BUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
+ H2BUGF(infof(data, "MAX_CONCURRENT_STREAMS == %d",
httpc->settings.max_concurrent_streams));
- H2BUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
+ H2BUGF(infof(data, "ENABLE_PUSH == %s",
httpc->settings.enable_push?"TRUE":"false"));
if(max_conn != httpc->settings.max_concurrent_streams) {
/* only signal change if the value actually changed */
- infof(conn->data,
- "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n",
+ infof(data,
+ "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!",
httpc->settings.max_concurrent_streams);
- multi_connchanged(conn->data->multi);
+ multi_connchanged(data->multi);
}
}
return 0;
}
data_s = nghttp2_session_get_stream_user_data(session, stream_id);
if(!data_s) {
- H2BUGF(infof(conn->data,
- "No Curl_easy associated with stream: %x\n",
+ H2BUGF(infof(data,
+ "No Curl_easy associated with stream: %x",
stream_id));
return 0;
}
stream = data_s->req.p.http;
if(!stream) {
- H2BUGF(infof(data_s, "No proto pointer for stream: %x\n",
+ H2BUGF(infof(data_s, "No proto pointer for stream: %x",
stream_id));
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
+ H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x",
frame->hd.type, stream_id));
switch(frame->hd.type) {
@@ -726,21 +763,17 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
ncopy);
stream->nread_header_recvbuf += ncopy;
- H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
+ DEBUGASSERT(stream->mem);
+ H2BUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p",
ncopy, stream_id, stream->mem));
stream->len -= ncopy;
stream->memlen += ncopy;
drain_this(data_s, httpc);
- {
- /* get the pointer from userp again since it was re-assigned above */
- struct connectdata *conn_s = (struct connectdata *)userp;
-
- /* if we receive data for another handle, wake that up */
- if(conn_s->data != data_s)
- Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
- }
+ /* if we receive data for another handle, wake that up */
+ if(get_transfer(httpc) != data_s)
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
break;
case NGHTTP2_PUSH_PROMISE:
rv = push_promise(data_s, conn, &frame->push_promise);
@@ -753,13 +786,13 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
if(nghttp2_is_fatal(h2))
return NGHTTP2_ERR_CALLBACK_FAILURE;
else if(rv == CURL_PUSH_ERROROUT) {
- DEBUGF(infof(data_s, "Fail the parent stream (too)\n"));
+ DEBUGF(infof(data_s, "Fail the parent stream (too)"));
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
}
break;
default:
- H2BUGF(infof(data_s, "Got frame type %x for stream %u!\n",
+ H2BUGF(infof(data_s, "Got frame type %x for stream %u!",
frame->hd.type, stream_id));
break;
}
@@ -768,15 +801,15 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
int32_t stream_id,
- const uint8_t *data, size_t len, void *userp)
+ const uint8_t *mem, size_t len, void *userp)
{
struct HTTP *stream;
struct Curl_easy *data_s;
size_t nread;
struct connectdata *conn = (struct connectdata *)userp;
+ struct http_conn *httpc = &conn->proto.httpc;
(void)session;
(void)flags;
- (void)data;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@@ -792,7 +825,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
return NGHTTP2_ERR_CALLBACK_FAILURE;
nread = CURLMIN(stream->len, len);
- memcpy(&stream->mem[stream->memlen], data, nread);
+ memcpy(&stream->mem[stream->memlen], mem, nread);
stream->len -= nread;
stream->memlen += nread;
@@ -800,20 +833,20 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
drain_this(data_s, &conn->proto.httpc);
/* if we receive data for another handle, wake that up */
- if(conn->data != data_s)
+ if(get_transfer(httpc) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
H2BUGF(infof(data_s, "%zu data received for stream %u "
- "(%zu left in buffer %p, total %zu)\n",
+ "(%zu left in buffer %p, total %zu)",
nread, stream_id,
stream->len, stream->mem,
stream->memlen));
if(nread < len) {
- stream->pausedata = data + nread;
+ stream->pausedata = mem + nread;
stream->pauselen = len - nread;
H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
- ", stream %u\n",
+ ", stream %u",
len - nread, stream_id));
data_s->conn->proto.httpc.pause_stream_id = stream_id;
@@ -822,7 +855,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
/* pause execution of nghttp2 if we received data for another handle
in order to process them first. */
- if(conn->data != data_s) {
+ if(get_transfer(httpc) != data_s) {
data_s->conn->proto.httpc.pause_stream_id = stream_id;
return NGHTTP2_ERR_PAUSE;
@@ -851,7 +884,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
decided to reject stream (e.g., PUSH_PROMISE). */
return 0;
}
- H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
+ H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u",
nghttp2_http2_strerror(error_code), error_code, stream_id));
stream = data_s->req.p.http;
if(!stream)
@@ -861,20 +894,20 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
httpc = &conn->proto.httpc;
drain_this(data_s, httpc);
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
- httpc->error_code = error_code;
+ stream->error = error_code;
/* remove the entry from the hash as the stream is now gone */
rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
if(rv) {
- infof(data_s, "http/2: failed to clear user_data for stream %d!\n",
+ infof(data_s, "http/2: failed to clear user_data for stream %d!",
stream_id);
DEBUGASSERT(0);
}
if(stream_id == httpc->pause_stream_id) {
- H2BUGF(infof(data_s, "Stopped the pause stream!\n"));
+ H2BUGF(infof(data_s, "Stopped the pause stream!"));
httpc->pause_stream_id = 0;
}
- H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
+ H2BUGF(infof(data_s, "Removed stream %u hash!", stream_id));
stream->stream_id = 0; /* cleared */
}
return 0;
@@ -892,7 +925,7 @@ static int on_begin_headers(nghttp2_session *session,
return 0;
}
- H2BUGF(infof(data_s, "on_begin_headers() was called\n"));
+ H2BUGF(infof(data_s, "on_begin_headers() was called"));
if(frame->hd.type != NGHTTP2_HEADERS) {
return 0;
@@ -944,6 +977,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
struct Curl_easy *data_s;
int32_t stream_id = frame->hd.stream_id;
struct connectdata *conn = (struct connectdata *)userp;
+ struct http_conn *httpc = &conn->proto.httpc;
CURLcode result;
(void)flags;
@@ -1019,7 +1053,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(stream->bodystarted) {
/* This is a trailer */
- H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
+ H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s", namelen, name, valuelen,
value));
result = Curl_dyn_addf(&stream->trailer_recvbuf,
"%.*s: %.*s\r\n", namelen, name,
@@ -1049,10 +1083,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
- if(conn->data != data_s)
+ if(get_transfer(httpc) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
- H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
+ H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)",
stream->status_code, data_s));
return 0;
}
@@ -1073,10 +1107,10 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
- if(conn->data != data_s)
+ if(get_transfer(httpc) != data_s)
Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
- H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
+ H2BUGF(infof(data_s, "h2 header: %.*s: %.*s", namelen, name, valuelen,
value));
return 0; /* 0 is successful */
@@ -1126,7 +1160,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session,
return NGHTTP2_ERR_DEFERRED;
H2BUGF(infof(data_s, "data_source_read_callback: "
- "returns %zu bytes stream %u\n",
+ "returns %zu bytes stream %u",
nread, stream_id));
return nread;
@@ -1138,27 +1172,27 @@ static int error_callback(nghttp2_session *session,
size_t len,
void *userp)
{
- struct connectdata *conn = (struct connectdata *)userp;
(void)session;
- infof(conn->data, "http2 error: %.*s\n", len, msg);
+ (void)msg;
+ (void)len;
+ (void)userp;
return 0;
}
#endif
-static void populate_settings(struct connectdata *conn,
+static void populate_settings(struct Curl_easy *data,
struct http_conn *httpc)
{
nghttp2_settings_entry *iv = httpc->local_settings;
- DEBUGASSERT(conn->data);
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
- iv[0].value = Curl_multi_max_concurrent_streams(conn->data->multi);
+ iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
- iv[2].value = conn->data->multi->push_cb != NULL;
+ iv[2].value = data->multi->push_cb != NULL;
httpc->local_settings_num = 3;
}
@@ -1187,12 +1221,13 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
if(premature) {
/* RST_STREAM */
+ set_transfer(httpc, data); /* set the transfer */
if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
http->stream_id, NGHTTP2_STREAM_CLOSED))
(void)nghttp2_session_send(httpc->h2);
if(http->stream_id == httpc->pause_stream_id) {
- infof(data, "stopped the pause stream!\n");
+ infof(data, "stopped the pause stream!");
httpc->pause_stream_id = 0;
}
}
@@ -1205,10 +1240,11 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
int rv = nghttp2_session_set_stream_user_data(httpc->h2,
http->stream_id, 0);
if(rv) {
- infof(data, "http/2: failed to clear user_data for stream %d!\n",
+ infof(data, "http/2: failed to clear user_data for stream %d!",
http->stream_id);
DEBUGASSERT(0);
}
+ set_transfer(httpc, NULL);
http->stream_id = 0;
}
}
@@ -1223,7 +1259,7 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
nghttp2_session_callbacks *callbacks;
conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
- if(conn->proto.httpc.inbuf == NULL)
+ if(!conn->proto.httpc.inbuf)
return CURLE_OUT_OF_MEMORY;
rc = nghttp2_session_callbacks_new(&callbacks);
@@ -1269,18 +1305,18 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
* Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
*/
CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
- struct connectdata *conn)
+ struct Curl_easy *data)
{
CURLcode result;
ssize_t binlen;
char *base64;
size_t blen;
- struct Curl_easy *data = conn->data;
+ struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
uint8_t *binsettings = conn->proto.httpc.binsettings;
struct http_conn *httpc = &conn->proto.httpc;
- populate_settings(conn, httpc);
+ populate_settings(data, httpc);
/* this returns number of bytes it wrote */
binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
@@ -1338,6 +1374,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
nread = httpc->inbuflen - httpc->nread_inbuf;
inbuf = httpc->inbuf + httpc->nread_inbuf;
+ set_transfer(httpc, data); /* set the transfer */
rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
if(rv < 0) {
failf(data,
@@ -1350,7 +1387,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
if(nread == rv) {
H2BUGF(infof(data,
"h2_process_pending_input: All data in connection buffer "
- "processed\n"));
+ "processed"));
httpc->inbuflen = 0;
httpc->nread_inbuf = 0;
}
@@ -1358,12 +1395,12 @@ static int h2_process_pending_input(struct Curl_easy *data,
httpc->nread_inbuf += rv;
H2BUGF(infof(data,
"h2_process_pending_input: %zu bytes left in connection "
- "buffer\n",
+ "buffer",
httpc->inbuflen - httpc->nread_inbuf));
}
rv = h2_session_send(data, httpc->h2);
- if(rv != 0) {
+ if(rv) {
*err = CURLE_SEND_ERROR;
return -1;
}
@@ -1377,9 +1414,10 @@ static int h2_process_pending_input(struct Curl_easy *data,
}
if(should_close_session(httpc)) {
+ struct HTTP *stream = data->req.p.http;
H2BUGF(infof(data,
- "h2_process_pending_input: nothing to do in this session\n"));
- if(httpc->error_code)
+ "h2_process_pending_input: nothing to do in this session"));
+ if(stream->error)
*err = CURLE_HTTP2;
else {
/* not an error per se, but should still close the connection */
@@ -1402,9 +1440,7 @@ CURLcode Curl_http2_done_sending(struct Curl_easy *data,
if((conn->handler == &Curl_handler_http2_ssl) ||
(conn->handler == &Curl_handler_http2)) {
/* make sure this is only attempted for HTTP/2 transfers */
-
struct HTTP *stream = data->req.p.http;
-
struct http_conn *httpc = &conn->proto.httpc;
nghttp2_session *h2 = httpc->h2;
@@ -1424,15 +1460,17 @@ CURLcode Curl_http2_done_sending(struct Curl_easy *data,
struct SingleRequest *k = &data->req;
int rv;
- H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)\n", data));
-
- /* re-set KEEP_SEND to make sure we are called again */
- k->keepon |= KEEP_SEND;
+ H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)", data));
/* and attempt to send the pending frames */
rv = h2_session_send(data, h2);
- if(rv != 0)
+ if(rv)
result = CURLE_SEND_ERROR;
+
+ if(nghttp2_session_want_write(h2)) {
+ /* re-set KEEP_SEND to make sure we are called again */
+ k->keepon |= KEEP_SEND;
+ }
}
}
return result;
@@ -1460,18 +1498,18 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
/* Reset to FALSE to prevent infinite loop in readwrite_data function. */
stream->closed = FALSE;
- if(httpc->error_code == NGHTTP2_REFUSED_STREAM) {
- H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n",
+ if(stream->error == NGHTTP2_REFUSED_STREAM) {
+ H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!",
stream->stream_id));
connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
data->state.refused_stream = TRUE;
*err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
return -1;
}
- else if(httpc->error_code != NGHTTP2_NO_ERROR) {
+ else if(stream->error != NGHTTP2_NO_ERROR) {
failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
- stream->stream_id, nghttp2_http2_strerror(httpc->error_code),
- httpc->error_code);
+ stream->stream_id, nghttp2_http2_strerror(stream->error),
+ stream->error);
*err = CURLE_HTTP2_STREAM;
return -1;
}
@@ -1510,7 +1548,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
stream->close_handled = TRUE;
- H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
+ H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close"));
return 0;
}
@@ -1542,6 +1580,8 @@ static int h2_session_send(struct Curl_easy *data,
nghttp2_session *h2)
{
struct HTTP *stream = data->req.p.http;
+ struct http_conn *httpc = &data->conn->proto.httpc;
+ set_transfer(httpc, data);
if((data->set.stream_weight != data->state.stream_weight) ||
(data->set.stream_depends_e != data->state.stream_depends_e) ||
(data->set.stream_depends_on != data->state.stream_depends_on) ) {
@@ -1551,7 +1591,7 @@ static int h2_session_send(struct Curl_easy *data,
h2_pri_spec(data, &pri_spec);
- H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
+ H2BUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)",
stream->stream_id, data));
DEBUGASSERT(stream->stream_id != -1);
rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
@@ -1575,7 +1615,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
if(should_close_session(httpc)) {
H2BUGF(infof(data,
- "http2_recv: nothing to do in this session\n"));
+ "http2_recv: nothing to do in this session"));
if(conn->bits.close) {
/* already marked for closure, return OK and we're done */
*err = CURLE_OK;
@@ -1605,12 +1645,12 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
stream->nread_header_recvbuf, ncopy);
stream->nread_header_recvbuf += ncopy;
- H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
+ H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf",
(int)ncopy));
return ncopy;
}
- H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u\n",
+ H2BUGF(infof(data, "http2_recv: easy %p (stream %u) win %u/%u",
data, stream->stream_id,
nghttp2_session_get_local_window_size(httpc->h2),
nghttp2_session_get_stream_local_window_size(httpc->h2,
@@ -1618,7 +1658,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
));
if((data->state.drain) && stream->memlen) {
- H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
+ H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)",
stream->memlen, stream->stream_id,
stream->mem, mem));
if(mem != stream->mem) {
@@ -1646,7 +1686,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
stream->pauselen -= nread;
if(stream->pauselen == 0) {
- H2BUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
+ H2BUGF(infof(data, "Unpaused by stream %u", stream->stream_id));
DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
httpc->pause_stream_id = 0;
@@ -1664,7 +1704,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
return -1;
}
}
- H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
+ H2BUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u",
nread, stream->stream_id));
return nread;
}
@@ -1680,7 +1720,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
if(stream->closed)
/* closed overrides paused */
return 0;
- H2BUGF(infof(data, "stream %x is paused, pause id: %x\n",
+ H2BUGF(infof(data, "stream %x is paused, pause id: %x",
stream->stream_id, httpc->pause_stream_id));
*err = CURLE_AGAIN;
return -1;
@@ -1707,12 +1747,23 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
}
if(nread == 0) {
- H2BUGF(infof(data, "end of stream\n"));
+ if(!stream->closed) {
+ /* This will happen when the server or proxy server is SIGKILLed
+ during data transfer. We should emit an error since our data
+ received may be incomplete. */
+ failf(data, "HTTP/2 stream %d was not closed cleanly before"
+ " end of the underlying stream",
+ stream->stream_id);
+ *err = CURLE_HTTP2_STREAM;
+ return -1;
+ }
+
+ H2BUGF(infof(data, "end of stream"));
*err = CURLE_OK;
return 0;
}
- H2BUGF(infof(data, "nread=%zd\n", nread));
+ H2BUGF(infof(data, "nread=%zd", nread));
httpc->inbuflen = nread;
@@ -1721,23 +1772,23 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
else {
nread = httpc->inbuflen - httpc->nread_inbuf;
(void)nread; /* silence warning, used in debug */
- H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
+ H2BUGF(infof(data, "Use data left in connection buffer, nread=%zd",
nread));
}
- if(h2_process_pending_input(data, httpc, err) != 0)
+ if(h2_process_pending_input(data, httpc, err))
return -1;
}
if(stream->memlen) {
ssize_t retlen = stream->memlen;
- H2BUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
+ H2BUGF(infof(data, "http2_recv: returns %zd for stream %u",
retlen, stream->stream_id));
stream->memlen = 0;
if(httpc->pause_stream_id == stream->stream_id) {
/* data for this stream is returned now, but this stream caused a pause
already so we need it called again asap */
- H2BUGF(infof(data, "Data returned for PAUSED stream %u\n",
+ H2BUGF(infof(data, "Data returned for PAUSED stream %u",
stream->stream_id));
}
else if(!stream->closed) {
@@ -1750,9 +1801,9 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
return retlen;
}
if(stream->closed)
- return 0;
+ return http2_handle_stream_close(conn, data, stream, err);
*err = CURLE_AGAIN;
- H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
+ H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u",
stream->stream_id));
return -1;
}
@@ -1856,11 +1907,11 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
(void)sockindex;
- H2BUGF(infof(data, "http2_send len=%zu\n", len));
+ H2BUGF(infof(data, "http2_send len=%zu", len));
if(stream->stream_id != -1) {
if(stream->close_handled) {
- infof(data, "stream %d closed\n", stream->stream_id);
+ infof(data, "stream %d closed", stream->stream_id);
*err = CURLE_HTTP2_STREAM;
return -1;
}
@@ -1889,7 +1940,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
stream->upload_len = 0;
if(should_close_session(httpc)) {
- H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
+ H2BUGF(infof(data, "http2_send: nothing to do in this session"));
*err = CURLE_HTTP2;
return -1;
}
@@ -1902,7 +1953,7 @@ 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\n", len,
+ H2BUGF(infof(data, "http2_send returns %zu for stream %u", len,
stream->stream_id));
return len;
}
@@ -1925,7 +1976,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
more space. */
nheader += 1;
nva = malloc(sizeof(nghttp2_nv) * nheader);
- if(nva == NULL) {
+ if(!nva) {
*err = CURLE_OUT_OF_MEMORY;
return -1;
}
@@ -2048,7 +2099,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
}
/* :authority must come before non-pseudo header fields */
- if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
+ if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
nghttp2_nv authority = nva[authority_idx];
for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
nva[i] = nva[i - 1];
@@ -2065,7 +2116,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
for(i = 0; i < nheader; ++i) {
acc += nva[i].namelen + nva[i].valuelen;
- H2BUGF(infof(data, "h2 header: %.*s:%.*s\n",
+ H2BUGF(infof(data, "h2 header: %.*s:%.*s",
nva[i].namelen, nva[i].name,
nva[i].valuelen, nva[i].value));
}
@@ -2073,13 +2124,13 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
if(acc > MAX_ACC) {
infof(data, "http2_send: Warning: The cumulative length of all "
"headers exceeds %d bytes and that could cause the "
- "stream to be rejected.\n", MAX_ACC);
+ "stream to be rejected.", MAX_ACC);
}
}
h2_pri_spec(data, &pri_spec);
- H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)\n",
+ H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)",
nghttp2_session_check_request_allowed(h2), (void *)data));
switch(data->state.httpreq) {
@@ -2107,22 +2158,20 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
if(stream_id < 0) {
H2BUGF(infof(data,
- "http2_send() nghttp2_submit_request error (%s)%d\n",
+ "http2_send() nghttp2_submit_request error (%s)%d",
nghttp2_strerror(stream_id), stream_id));
*err = CURLE_SEND_ERROR;
return -1;
}
- infof(data, "Using Stream ID: %x (easy handle %p)\n",
+ infof(data, "Using Stream ID: %x (easy handle %p)",
stream_id, (void *)data);
stream->stream_id = stream_id;
- /* this does not call h2_session_send() since there can not have been any
- * priority update since the nghttp2_submit_request() call above */
- rv = nghttp2_session_send(h2);
- if(rv != 0) {
+ rv = h2_session_send(data, h2);
+ if(rv) {
H2BUGF(infof(data,
- "http2_send() nghttp2_session_send error (%s)%d\n",
+ "http2_send() nghttp2_session_send error (%s)%d",
nghttp2_strerror(rv), rv));
*err = CURLE_SEND_ERROR;
@@ -2130,7 +2179,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
}
if(should_close_session(httpc)) {
- H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
+ H2BUGF(infof(data, "http2_send: nothing to do in this session"));
*err = CURLE_HTTP2;
return -1;
}
@@ -2166,6 +2215,22 @@ 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;
+
+ httpc->inbuflen = 0;
+ httpc->nread_inbuf = 0;
+
+ httpc->pause_stream_id = 0;
+ httpc->drain_total = 0;
+
+ 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 */
@@ -2181,25 +2246,13 @@ CURLcode Curl_http2_setup(struct Curl_easy *data,
return result;
}
- infof(data, "Using HTTP2, server supports multi-use\n");
- stream->upload_left = 0;
- stream->upload_mem = NULL;
- stream->upload_len = 0;
- stream->mem = data->state.buffer;
- stream->len = data->set.buffer_size;
-
- httpc->inbuflen = 0;
- httpc->nread_inbuf = 0;
-
- httpc->pause_stream_id = 0;
- httpc->drain_total = 0;
+ infof(data, "Using HTTP2, server supports multiplexing");
conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
conn->httpversion = 20;
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
- infof(data, "Connection state changed (HTTP/2 confirmed)\n");
- multi_connchanged(data->multi);
+ infof(data, "Connection state changed (HTTP/2 confirmed)");
return CURLE_OK;
}
@@ -2226,10 +2279,10 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
/* stream 1 is opened implicitly on upgrade */
stream->stream_id = 1;
/* queue SETTINGS frame (again) */
- rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
- httpc->binlen, NULL);
- if(rv != 0) {
- failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
+ rv = nghttp2_session_upgrade2(httpc->h2, httpc->binsettings, httpc->binlen,
+ data->state.httpreq == HTTPREQ_HEAD, NULL);
+ if(rv) {
+ failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
nghttp2_strerror(rv), rv);
return CURLE_HTTP2;
}
@@ -2238,20 +2291,20 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
stream->stream_id,
data);
if(rv) {
- infof(data, "http/2: failed to set user_data for stream %d!\n",
+ infof(data, "http/2: failed to set user_data for stream %d!",
stream->stream_id);
DEBUGASSERT(0);
}
}
else {
- populate_settings(conn, httpc);
+ populate_settings(data, httpc);
/* stream ID is unknown at this point */
stream->stream_id = -1;
rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
httpc->local_settings,
httpc->local_settings_num);
- if(rv != 0) {
+ if(rv) {
failf(data, "nghttp2_submit_settings() failed: %s(%d)",
nghttp2_strerror(rv), rv);
return CURLE_HTTP2;
@@ -2260,7 +2313,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
HTTP2_HUGE_WINDOW_SIZE);
- if(rv != 0) {
+ if(rv) {
failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
nghttp2_strerror(rv), rv);
return CURLE_HTTP2;
@@ -2278,7 +2331,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
}
infof(data, "Copying HTTP/2 data in stream buffer to connection buffer"
- " after upgrade: len=%zu\n",
+ " after upgrade: len=%zu",
nread);
if(nread)
@@ -2299,7 +2352,8 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
/* if it isn't HTTP/2, we're done */
- if(!data->conn->proto.httpc.h2)
+ if(!(data->conn->handler->protocol & PROTO_FAMILY_HTTP) ||
+ !data->conn->proto.httpc.h2)
return CURLE_OK;
#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
else {
@@ -2321,7 +2375,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
if(rv)
return CURLE_SEND_ERROR;
- DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u\n",
+ DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
window, stream->stream_id));
#ifdef DEBUGBUILD
@@ -2330,7 +2384,7 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
uint32_t window2 =
nghttp2_session_get_stream_local_window_size(httpc->h2,
stream->stream_id);
- DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u\n",
+ DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
window2, stream->stream_id));
}
#endif
@@ -2423,10 +2477,10 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
/* Only call this function for a transfer that already got a HTTP/2
CURLE_HTTP2_STREAM error! */
-bool Curl_h2_http_1_1_error(struct connectdata *conn)
+bool Curl_h2_http_1_1_error(struct Curl_easy *data)
{
- struct http_conn *httpc = &conn->proto.httpc;
- return (httpc->error_code == NGHTTP2_HTTP_1_1_REQUIRED);
+ struct HTTP *stream = data->req.p.http;
+ return (stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
}
#else /* !USE_NGHTTP2 */
diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h
index 119e584..d6986d9 100644
--- a/Utilities/cmcurl/lib/http2.h
+++ b/Utilities/cmcurl/lib/http2.h
@@ -29,13 +29,12 @@
/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting
from the peer */
-#define DEFAULT_MAX_CONCURRENT_STREAMS 13
+#define DEFAULT_MAX_CONCURRENT_STREAMS 100
/*
- * Store nghttp2 version info in this buffer, Prefix with a space. Return
- * total length written.
+ * Store nghttp2 version info in this buffer.
*/
-int Curl_http2_ver(char *p, size_t len);
+void Curl_http2_ver(char *p, size_t len);
const char *Curl_http2_strerror(uint32_t err);
@@ -43,7 +42,7 @@ CURLcode Curl_http2_init(struct connectdata *conn);
void Curl_http2_init_state(struct UrlState *state);
void Curl_http2_init_userset(struct UserDefined *set);
CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
- struct connectdata *conn);
+ struct Curl_easy *data);
CURLcode Curl_http2_setup(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_http2_switched(struct Curl_easy *data,
const char *ptr, size_t nread);
@@ -62,7 +61,7 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
/* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
-bool Curl_h2_http_1_1_error(struct connectdata *conn);
+bool Curl_h2_http_1_1_error(struct Curl_easy *data);
#else /* USE_NGHTTP2 */
#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
#define Curl_http2_setup(x,y) CURLE_UNSUPPORTED_PROTOCOL
diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c
index 8fd1c77..02663ab 100644
--- a/Utilities/cmcurl/lib/http_aws_sigv4.c
+++ b/Utilities/cmcurl/lib/http_aws_sigv4.c
@@ -99,8 +99,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char *request_type = NULL;
char *credential_scope = NULL;
char *str_to_sign = NULL;
- const char *user = conn->user ? conn->user : "";
- const char *passwd = conn->passwd ? conn->passwd : "";
+ const char *user = data->state.aptr.user ? data->state.aptr.user : "";
+ const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : "";
char *secret = NULL;
unsigned char tmp_sign0[32] = {0};
unsigned char tmp_sign1[32] = {0};
@@ -126,7 +126,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
tmp1 = strchr(tmp0, ':');
len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
if(len < 1) {
- infof(data, "first provider can't be empty\n");
+ infof(data, "first provider can't be empty");
ret = CURLE_BAD_FUNCTION_ARGUMENT;
goto fail;
}
@@ -145,7 +145,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
tmp1 = strchr(tmp0, ':');
len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
if(len < 1) {
- infof(data, "second provider can't be empty\n");
+ infof(data, "second provider can't be empty");
ret = CURLE_BAD_FUNCTION_ARGUMENT;
goto fail;
}
@@ -165,7 +165,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
tmp1 = strchr(tmp0, ':');
len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
if(len < 1) {
- infof(data, "region can't be empty\n");
+ infof(data, "region can't be empty");
ret = CURLE_BAD_FUNCTION_ARGUMENT;
goto fail;
}
@@ -182,7 +182,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
goto fail;
}
if(strlen(service) < 1) {
- infof(data, "service can't be empty\n");
+ infof(data, "service can't be empty");
ret = CURLE_BAD_FUNCTION_ARGUMENT;
goto fail;
}
@@ -203,7 +203,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
tmp1 = strchr(tmp0, '.');
len = tmp1 - tmp0;
if(!tmp1 || len < 1) {
- infof(data, "service missing in parameters or hostname\n");
+ infof(data, "service missing in parameters or hostname");
ret = CURLE_URL_MALFORMAT;
goto fail;
}
@@ -218,7 +218,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
tmp1 = strchr(tmp0, '.');
len = tmp1 - tmp0;
if(!tmp1 || len < 1) {
- infof(data, "region missing in parameters or hostname\n");
+ infof(data, "region missing in parameters or hostname");
ret = CURLE_URL_MALFORMAT;
goto fail;
}
diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c
index 596b215..34bb5a8 100644
--- a/Utilities/cmcurl/lib/http_digest.c
+++ b/Utilities/cmcurl/lib/http_digest.c
@@ -56,7 +56,7 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
digest = &data->state.digest;
}
- if(!checkprefix("Digest", header))
+ if(!checkprefix("Digest", header) || !ISSPACE(header[6]))
return CURLE_BAD_CONTENT_ENCODING;
header += strlen("Digest");
@@ -67,7 +67,6 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
}
CURLcode Curl_output_digest(struct Curl_easy *data,
- struct connectdata *conn,
bool proxy,
const unsigned char *request,
const unsigned char *uripath)
@@ -97,16 +96,16 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
#else
digest = &data->state.proxydigest;
allocuserpwd = &data->state.aptr.proxyuserpwd;
- userp = conn->http_proxy.user;
- passwdp = conn->http_proxy.passwd;
+ userp = data->state.aptr.proxyuser;
+ passwdp = data->state.aptr.proxypasswd;
authp = &data->state.authproxy;
#endif
}
else {
digest = &data->state.digest;
allocuserpwd = &data->state.aptr.userpwd;
- userp = conn->user;
- passwdp = conn->passwd;
+ userp = data->state.aptr.user;
+ passwdp = data->state.aptr.passwd;
authp = &data->state.authhost;
}
@@ -147,7 +146,8 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
tmp = strchr((char *)uripath, '?');
if(tmp) {
size_t urilen = tmp - (char *)uripath;
- path = (unsigned char *) aprintf("%.*s", urilen, uripath);
+ /* typecast is fine here since the value is always less than 32 bits */
+ path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath);
}
}
if(!tmp)
diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h
index 106caa7..89438d1 100644
--- a/Utilities/cmcurl/lib/http_digest.h
+++ b/Utilities/cmcurl/lib/http_digest.h
@@ -31,7 +31,6 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
/* this is for creating digest header output */
CURLcode Curl_output_digest(struct Curl_easy *data,
- struct connectdata *conn,
bool proxy,
const unsigned char *request,
const unsigned char *uripath);
diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c
index d759748..5f764dc 100644
--- a/Utilities/cmcurl/lib/http_negotiate.c
+++ b/Utilities/cmcurl/lib/http_negotiate.c
@@ -89,7 +89,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
neg_ctx->havenegdata = len != 0;
if(!len) {
if(state == GSS_AUTHSUCC) {
- infof(data, "Negotiate auth restarted\n");
+ infof(data, "Negotiate auth restarted");
Curl_http_auth_cleanup_negotiate(conn);
}
else if(state != GSS_AUTHNONE) {
@@ -142,11 +142,11 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
}
if(neg_ctx->noauthpersist ||
- (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
+ (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
infof(data, "Curl_output_negotiate, "
- "no persistent authentication: cleanup existing context");
+ "no persistent authentication: cleanup existing context");
Curl_http_auth_cleanup_negotiate(conn);
}
if(!neg_ctx->context) {
@@ -179,7 +179,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
free(base64);
- if(userp == NULL) {
+ if(!userp) {
return CURLE_OUT_OF_MEMORY;
}
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
index 6cb829e..627a11c 100644
--- a/Utilities/cmcurl/lib/http_ntlm.c
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -39,6 +39,7 @@
#include "http_ntlm.h"
#include "curl_ntlm_core.h"
#include "curl_ntlm_wb.h"
+#include "curl_base64.h"
#include "vauth/vauth.h"
#include "url.h"
@@ -80,7 +81,18 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
header++;
if(*header) {
- result = Curl_auth_decode_ntlm_type2_message(data, header, ntlm);
+ unsigned char *hdr;
+ size_t hdrlen;
+
+ result = Curl_base64_decode(header, &hdr, &hdrlen);
+ if(!result) {
+ struct bufref hdrbuf;
+
+ Curl_bufref_init(&hdrbuf);
+ Curl_bufref_set(&hdrbuf, hdr, hdrlen, curl_free);
+ result = Curl_auth_decode_ntlm_type2_message(data, &hdrbuf, ntlm);
+ Curl_bufref_free(&hdrbuf);
+ }
if(result)
return result;
@@ -88,17 +100,17 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
}
else {
if(*state == NTLMSTATE_LAST) {
- infof(data, "NTLM auth restarted\n");
+ infof(data, "NTLM auth restarted");
Curl_http_auth_cleanup_ntlm(conn);
}
else if(*state == NTLMSTATE_TYPE3) {
- infof(data, "NTLM handshake rejected\n");
+ infof(data, "NTLM handshake rejected");
Curl_http_auth_cleanup_ntlm(conn);
*state = NTLMSTATE_NONE;
return CURLE_REMOTE_ACCESS_DENIED;
}
else if(*state >= NTLMSTATE_TYPE1) {
- infof(data, "NTLM handshake failure (internal error)\n");
+ infof(data, "NTLM handshake failure (internal error)");
return CURLE_REMOTE_ACCESS_DENIED;
}
@@ -116,7 +128,8 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
{
char *base64 = NULL;
size_t len = 0;
- CURLcode result;
+ CURLcode result = CURLE_OK;
+ struct bufref ntlmmsg;
/* point to the address of the pointer that holds the string to send to the
server, which is for a plain host or for a HTTP proxy */
@@ -140,10 +153,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
if(proxy) {
#ifndef CURL_DISABLE_PROXY
allocuserpwd = &data->state.aptr.proxyuserpwd;
- userp = conn->http_proxy.user;
- passwdp = conn->http_proxy.passwd;
+ userp = data->state.aptr.proxyuser;
+ passwdp = data->state.aptr.proxypasswd;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
- data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+ data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
hostname = conn->http_proxy.host.name;
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
@@ -154,10 +167,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
}
else {
allocuserpwd = &data->state.aptr.userpwd;
- userp = conn->user;
- passwdp = conn->passwd;
+ userp = data->state.aptr.user;
+ passwdp = data->state.aptr.passwd;
service = data->set.str[STRING_SERVICE_NAME] ?
- data->set.str[STRING_SERVICE_NAME] : "HTTP";
+ data->set.str[STRING_SERVICE_NAME] : "HTTP";
hostname = conn->host.name;
ntlm = &conn->ntlm;
state = &conn->http_ntlm_state;
@@ -173,10 +186,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
passwdp = "";
#ifdef USE_WINDOWS_SSPI
- if(s_hSecDll == NULL) {
+ if(!s_hSecDll) {
/* not thread safe and leaks - use curl_global_init() to avoid */
CURLcode err = Curl_sspi_global_init();
- if(s_hSecDll == NULL)
+ if(!s_hSecDll)
return err;
}
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
@@ -184,50 +197,52 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
#endif
#endif
+ Curl_bufref_init(&ntlmmsg);
switch(*state) {
case NTLMSTATE_TYPE1:
default: /* for the weird cases we (re)start here */
/* Create a type-1 message */
result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
service, hostname,
- ntlm, &base64,
- &len);
- if(result)
- return result;
-
- if(base64) {
- free(*allocuserpwd);
- *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
- proxy ? "Proxy-" : "",
- base64);
- free(base64);
- if(!*allocuserpwd)
- return CURLE_OUT_OF_MEMORY;
-
- DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+ ntlm, &ntlmmsg);
+ if(!result) {
+ DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
+ result = Curl_base64_encode(data,
+ (const char *) Curl_bufref_ptr(&ntlmmsg),
+ Curl_bufref_len(&ntlmmsg), &base64, &len);
+ if(!result) {
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ base64);
+ free(base64);
+ if(!*allocuserpwd)
+ result = CURLE_OUT_OF_MEMORY;
+ }
}
break;
case NTLMSTATE_TYPE2:
/* We already received the type-2 message, create a type-3 message */
result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
- ntlm, &base64, &len);
- if(result)
- return result;
-
- if(base64) {
- free(*allocuserpwd);
- *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
- proxy ? "Proxy-" : "",
- base64);
- free(base64);
- if(!*allocuserpwd)
- return CURLE_OUT_OF_MEMORY;
-
- DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
-
- *state = NTLMSTATE_TYPE3; /* we send a type-3 */
- authp->done = TRUE;
+ ntlm, &ntlmmsg);
+ if(!result && Curl_bufref_len(&ntlmmsg)) {
+ result = Curl_base64_encode(data,
+ (const char *) Curl_bufref_ptr(&ntlmmsg),
+ Curl_bufref_len(&ntlmmsg), &base64, &len);
+ if(!result) {
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ base64);
+ free(base64);
+ if(!*allocuserpwd)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ *state = NTLMSTATE_TYPE3; /* we send a type-3 */
+ authp->done = TRUE;
+ }
+ }
}
break;
@@ -241,8 +256,9 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
authp->done = TRUE;
break;
}
+ Curl_bufref_free(&ntlmmsg);
- return CURLE_OK;
+ return result;
}
void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
index a03a27f..58489ab 100644
--- a/Utilities/cmcurl/lib/http_proxy.c
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -39,6 +39,8 @@
#include "connect.h"
#include "curlx.h"
#include "vtls/vtls.h"
+#include "transfer.h"
+#include "multiif.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -59,7 +61,7 @@ static CURLcode https_proxy_connect(struct Curl_easy *data, int sockindex)
if(!conn->bits.proxy_ssl_connected[sockindex]) {
/* perform SSL initialization for this socket */
result =
- Curl_ssl_connect_nonblocking(data, conn, sockindex,
+ Curl_ssl_connect_nonblocking(data, conn, TRUE, sockindex,
&conn->bits.proxy_ssl_connected[sockindex]);
if(result)
/* a failed connection is marked for closure to prevent (bad) re-use or
@@ -88,29 +90,12 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
#ifndef CURL_DISABLE_PROXY
/* for [protocol] tunneled through HTTP proxy */
- struct HTTP http_proxy;
- void *prot_save;
const char *hostname;
int remote_port;
CURLcode result;
- /* BLOCKING */
/* We want "seamless" operations through HTTP proxy tunnel */
- /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
- * member conn->proto.http; we want [protocol] through HTTP and we have
- * to change the member temporarily for connecting to the HTTP
- * proxy. After Curl_proxyCONNECT we have to set back the member to the
- * original pointer
- *
- * This function might be called several times in the multi interface case
- * if the proxy's CONNECT response is not instant.
- */
- prot_save = data->req.p.http;
- memset(&http_proxy, 0, sizeof(http_proxy));
- data->req.p.http = &http_proxy;
- connkeep(conn, "HTTP proxy CONNECT");
-
/* for the secondary socket (FTP), use the "connect to host"
* but ignore the "connect to port" (use the secondary port)
*/
@@ -128,8 +113,8 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
remote_port = conn->conn_to_port;
else
remote_port = conn->remote_port;
+
result = Curl_proxyCONNECT(data, sockindex, hostname, remote_port);
- data->req.p.http = prot_save;
if(CURLE_OK != result)
return result;
Curl_safefree(data->state.aptr.proxyuserpwd);
@@ -144,13 +129,29 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
bool Curl_connect_complete(struct connectdata *conn)
{
return !conn->connect_state ||
- (conn->connect_state->tunnel_state == TUNNEL_COMPLETE);
+ (conn->connect_state->tunnel_state >= TUNNEL_COMPLETE);
}
bool Curl_connect_ongoing(struct connectdata *conn)
{
return conn->connect_state &&
- (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
+ (conn->connect_state->tunnel_state <= TUNNEL_COMPLETE);
+}
+
+/* when we've sent a CONNECT to a proxy, we should rather either wait for the
+ socket to become readable to be able to get the response headers or if
+ we're still sending the request, wait for write. */
+int Curl_connect_getsock(struct connectdata *conn)
+{
+ struct HTTP *http;
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->connect_state);
+ http = &conn->connect_state->http_proxy;
+
+ if(http->sending == HTTPSEND_REQUEST)
+ return GETSOCK_WRITESOCK(0);
+
+ return GETSOCK_READSOCK(0);
}
static CURLcode connect_init(struct Curl_easy *data, bool reinit)
@@ -158,13 +159,32 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
struct http_connect_state *s;
struct connectdata *conn = data->conn;
if(!reinit) {
+ CURLcode result;
DEBUGASSERT(!conn->connect_state);
+ /* we might need the upload buffer for streaming a partial request */
+ result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+
s = calloc(1, sizeof(struct http_connect_state));
if(!s)
return CURLE_OUT_OF_MEMORY;
- infof(data, "allocate connect buffer!\n");
+ infof(data, "allocate connect buffer!");
conn->connect_state = s;
Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
+
+ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
+ * member conn->proto.http; we want [protocol] through HTTP and we have
+ * to change the member temporarily for connecting to the HTTP
+ * proxy. After Curl_proxyCONNECT we have to set back the member to the
+ * original pointer
+ *
+ * This function might be called several times in the multi interface case
+ * if the proxy's CONNECT response is not instant.
+ */
+ s->prot_save = data->req.p.http;
+ data->req.p.http = &s->http_proxy;
+ connkeep(conn, "HTTP proxy CONNECT");
}
else {
DEBUGASSERT(conn->connect_state);
@@ -182,9 +202,16 @@ static void connect_done(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct http_connect_state *s = conn->connect_state;
- s->tunnel_state = TUNNEL_COMPLETE;
- Curl_dyn_free(&s->rcvbuf);
- infof(data, "CONNECT phase completed!\n");
+ if(s->tunnel_state != TUNNEL_EXIT) {
+ s->tunnel_state = TUNNEL_EXIT;
+ Curl_dyn_free(&s->rcvbuf);
+ Curl_dyn_free(&s->req);
+
+ /* retore the protocol pointer */
+ data->req.p.http = s->prot_save;
+ s->prot_save = NULL;
+ infof(data, "CONNECT phase completed!");
+ }
}
static CURLcode CONNECT_host(struct Curl_easy *data,
@@ -219,11 +246,11 @@ static CURLcode CONNECT_host(struct Curl_easy *data,
return CURLE_OK;
}
+#ifndef USE_HYPER
static CURLcode CONNECT(struct Curl_easy *data,
int sockindex,
const char *hostname,
int remote_port)
-#ifndef USE_HYPER
{
int subversion = 0;
struct SingleRequest *k = &data->req;
@@ -231,6 +258,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
struct connectdata *conn = data->conn;
curl_socket_t tunnelsocket = conn->sock[sockindex];
struct http_connect_state *s = conn->connect_state;
+ struct HTTP *http = data->req.p.http;
char *linep;
size_t perline;
@@ -246,11 +274,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
timediff_t check;
if(TUNNEL_INIT == s->tunnel_state) {
/* BEGIN CONNECT PHASE */
- struct dynbuf req;
+ struct dynbuf *req = &s->req;
char *hostheader = NULL;
char *host = NULL;
- infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
+ infof(data, "Establish HTTP proxy tunnel to %s:%d",
hostname, remote_port);
/* This only happens if we've looped here due to authentication
@@ -259,8 +287,8 @@ static CURLcode CONNECT(struct Curl_easy *data,
free(data->req.newurl);
data->req.newurl = NULL;
- /* initialize a dynamic send-buffer */
- Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+ /* initialize send-buffer */
+ Curl_dyn_init(req, DYN_HTTP_REQUEST);
result = CONNECT_host(data, conn,
hostname, remote_port, &hostheader, &host);
@@ -272,44 +300,38 @@ 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,
+ 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);
+ result = Curl_add_custom_headers(data, TRUE, req);
if(!result)
/* CRLF terminate the request */
- result = Curl_dyn_add(&req, "\r\n");
+ result = Curl_dyn_add(req, "\r\n");
if(!result) {
/* Send the connect request to the proxy */
- /* BLOCKING */
- result = Curl_buffer_send(&req, data, &data->info.request_size, 0,
+ result = Curl_buffer_send(req, data, &data->info.request_size, 0,
sockindex);
}
if(result)
@@ -317,7 +339,6 @@ static CURLcode CONNECT(struct Curl_easy *data,
}
free(host);
free(hostheader);
- Curl_dyn_free(&req);
if(result)
return result;
@@ -330,12 +351,43 @@ static CURLcode CONNECT(struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- if(!Curl_conn_data_pending(conn, sockindex))
+ if(!Curl_conn_data_pending(conn, sockindex) && !http->sending)
/* return so we'll be called again polling-style */
return CURLE_OK;
/* at this point, the tunnel_connecting phase is over. */
+ if(http->sending == HTTPSEND_REQUEST) {
+ if(!s->nsend) {
+ size_t fillcount;
+ k->upload_fromhere = data->state.ulbuf;
+ result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
+ &fillcount);
+ if(result)
+ return result;
+ s->nsend = fillcount;
+ }
+ if(s->nsend) {
+ ssize_t bytes_written;
+ /* write to socket (send away data) */
+ result = Curl_write(data,
+ conn->writesockfd, /* socket to send to */
+ k->upload_fromhere, /* buffer pointer */
+ s->nsend, /* buffer size */
+ &bytes_written); /* actually sent */
+
+ if(!result)
+ /* send to debug callback! */
+ result = Curl_debug(data, CURLINFO_HEADER_OUT,
+ k->upload_fromhere, bytes_written);
+
+ s->nsend -= bytes_written;
+ k->upload_fromhere += bytes_written;
+ return result;
+ }
+ http->sending = HTTPSEND_NADA;
+ /* if nothing left to send, continue */
+ }
{ /* READING RESPONSE PHASE */
int error = SELECT_OK;
@@ -358,11 +410,12 @@ static CURLcode CONNECT(struct Curl_easy *data,
break;
}
else if(gotbytes <= 0) {
- if(data->set.proxyauth && data->state.authproxy.avail) {
+ if(data->set.proxyauth && data->state.authproxy.avail &&
+ data->state.aptr.proxyuserpwd) {
/* proxy auth was requested and there was proxy auth available,
then deem this as "mere" proxy disconnect */
conn->bits.proxy_connect_closed = TRUE;
- infof(data, "Proxy CONNECT connection closed\n");
+ infof(data, "Proxy CONNECT connection closed");
}
else {
error = SELECT_ERROR;
@@ -397,7 +450,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
- infof(data, "chunk reading DONE\n");
+ infof(data, "chunk reading DONE");
s->keepon = KEEPON_DONE;
/* we did the full CONNECT treatment, go COMPLETE */
s->tunnel_state = TUNNEL_COMPLETE;
@@ -456,13 +509,13 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(s->cl) {
infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
- " bytes of response-body\n", s->cl);
+ " bytes of response-body", s->cl);
}
else if(s->chunked_encoding) {
CHUNKcode r;
CURLcode extra;
- infof(data, "Ignore chunked response-body\n");
+ infof(data, "Ignore chunked response-body");
/* We set ignorebody true here since the chunked decoder
function will acknowledge that. Pay attention so that this is
@@ -479,7 +532,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
&extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
- infof(data, "chunk reading DONE\n");
+ infof(data, "chunk reading DONE");
s->keepon = KEEPON_DONE;
/* we did the full CONNECT treatment, go to COMPLETE */
s->tunnel_state = TUNNEL_COMPLETE;
@@ -525,7 +578,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
/* A client MUST ignore any Content-Length or Transfer-Encoding
header fields received in a successful response to CONNECT.
"Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
- infof(data, "Ignoring Content-Length in CONNECT %03d response\n",
+ infof(data, "Ignoring Content-Length in CONNECT %03d response",
k->httpcode);
}
else {
@@ -541,11 +594,11 @@ static CURLcode CONNECT(struct Curl_easy *data,
header fields received in a successful response to CONNECT.
"Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
infof(data, "Ignoring Transfer-Encoding in "
- "CONNECT %03d response\n", k->httpcode);
+ "CONNECT %03d response", k->httpcode);
}
else if(Curl_compareheader(linep,
"Transfer-Encoding:", "chunked")) {
- infof(data, "CONNECT responded chunked\n");
+ infof(data, "CONNECT responded chunked");
s->chunked_encoding = TRUE;
/* init our chunky engine */
Curl_httpchunk_init(data);
@@ -603,7 +656,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
if(data->info.httpproxycode/100 != 2) {
if(s->close_connection && data->req.newurl) {
conn->bits.proxy_connect_closed = TRUE;
- infof(data, "Connect me again please\n");
+ infof(data, "Connect me again please");
connect_done(data);
}
else {
@@ -638,7 +691,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
- infof(data, "Proxy replied %d to CONNECT request\n",
+ infof(data, "Proxy replied %d to CONNECT request",
data->info.httpproxycode);
data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
@@ -648,6 +701,10 @@ static CURLcode CONNECT(struct Curl_easy *data,
}
#else
/* The Hyper version of CONNECT */
+static CURLcode CONNECT(struct Curl_easy *data,
+ int sockindex,
+ const char *hostname,
+ int remote_port)
{
struct connectdata *conn = data->conn;
struct hyptransfer *h = &data->hyp;
@@ -686,6 +743,8 @@ static CURLcode CONNECT(struct Curl_easy *data,
hyper_io_set_write(io, Curl_hyper_send);
conn->sockfd = tunnelsocket;
+ data->state.hconnect = TRUE;
+
/* create an executor to poll futures */
if(!h->exec) {
h->exec = hyper_executor_new();
@@ -759,7 +818,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
(HYPERE_OK != hyper_request_set_version(req,
HYPER_HTTP_VERSION_1_0))) {
- failf(data, "error settting HTTP version");
+ failf(data, "error setting HTTP version");
goto error;
}
@@ -776,16 +835,26 @@ static CURLcode CONNECT(struct Curl_easy *data,
Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
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;
+ if(Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua)))
+ goto error;
+ Curl_dyn_free(&ua);
+ }
if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
goto error;
+ if(Curl_add_custom_headers(data, TRUE, headers))
+ goto error;
+
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
@@ -821,7 +890,6 @@ static CURLcode CONNECT(struct Curl_easy *data,
goto error;
if(!done)
break;
- fprintf(stderr, "done\n");
s->tunnel_state = TUNNEL_COMPLETE;
if(h->exec) {
hyper_executor_free(h->exec);
@@ -843,6 +911,33 @@ static CURLcode CONNECT(struct Curl_easy *data,
} 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;
+ infof(data, "Connect me again please");
+ connect_done(data);
+ }
+ else {
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ /* failure, close this connection to avoid re-use */
+ streamclose(conn, "proxy CONNECT failure");
+ Curl_closesocket(data, conn, conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ }
+
+ /* to back to init state */
+ s->tunnel_state = TUNNEL_INIT;
+
+ if(!conn->bits.proxy_connect_closed) {
+ failf(data, "Received HTTP code %d from proxy after CONNECT",
+ data->req.httpcode);
+ result = CURLE_RECV_ERROR;
+ }
+ }
+ }
error:
free(host);
free(hostheader);
@@ -863,7 +958,6 @@ static CURLcode CONNECT(struct Curl_easy *data,
}
return result;
}
-
#endif
void Curl_connect_free(struct Curl_easy *data)
diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
index a78db0d..cdf8de4 100644
--- a/Utilities/cmcurl/lib/http_proxy.h
+++ b/Utilities/cmcurl/lib/http_proxy.h
@@ -38,15 +38,40 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex);
bool Curl_connect_complete(struct connectdata *conn);
bool Curl_connect_ongoing(struct connectdata *conn);
+int Curl_connect_getsock(struct connectdata *conn);
#else
#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
#define Curl_proxy_connect(x,y) CURLE_OK
#define Curl_connect_complete(x) CURLE_OK
#define Curl_connect_ongoing(x) FALSE
+#define Curl_connect_getsock(x) 0
#endif
void Curl_connect_free(struct Curl_easy *data);
void Curl_connect_done(struct Curl_easy *data);
+/* struct for HTTP CONNECT state data */
+struct http_connect_state {
+ struct HTTP http_proxy;
+ struct HTTP *prot_save;
+ struct dynbuf rcvbuf;
+ struct dynbuf req;
+ size_t nsend;
+ enum keeponval {
+ KEEPON_DONE,
+ KEEPON_CONNECT,
+ KEEPON_IGNORE
+ } keepon;
+ curl_off_t cl; /* size of content to read and ignore */
+ enum {
+ TUNNEL_INIT, /* init/default/no tunnel state */
+ TUNNEL_CONNECT, /* CONNECT has been sent off */
+ TUNNEL_COMPLETE, /* CONNECT response received completely */
+ TUNNEL_EXIT
+ } tunnel_state;
+ BIT(chunked_encoding);
+ BIT(close_connection);
+};
+
#endif /* HEADER_CURL_HTTP_PROXY_H */
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
index 2d80699..6163899 100644
--- a/Utilities/cmcurl/lib/imap.c
+++ b/Utilities/cmcurl/lib/imap.c
@@ -74,7 +74,6 @@
#include "strcase.h"
#include "vtls/vtls.h"
#include "connect.h"
-#include "strerror.h"
#include "select.h"
#include "multiif.h"
#include "url.h"
@@ -136,6 +135,7 @@ const struct Curl_handler Curl_handler_imap = {
imap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_IMAP, /* defport */
CURLPROTO_IMAP, /* protocol */
CURLPROTO_IMAP, /* family */
@@ -164,6 +164,7 @@ const struct Curl_handler Curl_handler_imaps = {
imap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_IMAPS, /* defport */
CURLPROTO_IMAPS, /* protocol */
CURLPROTO_IMAP, /* family */
@@ -412,7 +413,7 @@ static void state(struct Curl_easy *data, imapstate newstate)
};
if(imapc->state != newstate)
- infof(data, "IMAP %p state change from %s to %s\n",
+ infof(data, "IMAP %p state change from %s to %s",
(void *)imapc, names[imapc->state], names[newstate]);
#endif
@@ -473,8 +474,8 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
{
/* Start the SSL connection */
struct imap_conn *imapc = &conn->proto.imapc;
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
- &imapc->ssldone);
+ CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+ FIRSTSOCKET, &imapc->ssldone);
if(!result) {
if(imapc->state != IMAP_UPGRADETLS)
@@ -604,7 +605,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
result = imap_perform_login(data, conn);
else {
/* Other mechanisms not supported */
- infof(data, "No known authentication mechanisms supported!\n");
+ infof(data, "No known authentication mechanisms supported!");
result = CURLE_LOGIN_DENIED;
}
}
@@ -859,7 +860,7 @@ static CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
/* PREAUTH */
struct imap_conn *imapc = &conn->proto.imapc;
imapc->preauth = TRUE;
- infof(data, "PREAUTH connection, already authenticated!\n");
+ infof(data, "PREAUTH connection, already authenticated!");
}
else if(imapcode != IMAP_RESP_OK) {
failf(data, "Got unexpected imap-server response");
@@ -919,7 +920,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
/* Do we have a SASL based authentication mechanism? */
else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
size_t llen;
- unsigned int mechbit;
+ unsigned short mechbit;
line += 5;
wordlen -= 5;
@@ -933,22 +934,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, conn);
}
- 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);
@@ -966,6 +963,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");
@@ -1141,7 +1142,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
}
if(parsed) {
- infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download\n",
+ infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download",
size);
Curl_pgrsSetDownloadSize(data, size);
@@ -1167,7 +1168,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
data->req.bytecount += chunk;
infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
- " bytes are left for transfer\n", chunk, size - chunk);
+ " bytes are left for transfer", chunk, size - chunk);
/* Have we used the entire cache or just part of it?*/
if(pp->cache_size > chunk) {
@@ -1367,7 +1368,7 @@ static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done)
struct imap_conn *imapc = &conn->proto.imapc;
if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
- result = Curl_ssl_connect_nonblocking(data, conn,
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
FIRSTSOCKET, &imapc->ssldone);
if(result || !imapc->ssldone)
return result;
@@ -1519,7 +1520,7 @@ static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
Curl_safefree(imap->custom_params);
/* Clear the transfer mode for the next request */
- imap->transfer = FTPTRANSFER_BODY;
+ imap->transfer = PPTRANSFER_BODY;
return result;
}
@@ -1541,11 +1542,11 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
struct imap_conn *imapc = &conn->proto.imapc;
bool selected = FALSE;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
if(data->set.opt_no_body) {
/* Requested no body means no transfer */
- imap->transfer = FTPTRANSFER_INFO;
+ imap->transfer = PPTRANSFER_INFO;
}
*dophase_done = FALSE; /* not done yet */
@@ -1588,7 +1589,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done)
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
return result;
}
@@ -1667,7 +1668,7 @@ static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
(void)connected;
- if(imap->transfer != FTPTRANSFER_BODY)
+ if(imap->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
@@ -1680,11 +1681,11 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done)
CURLcode result = imap_multi_statemach(data, dophase_done);
if(result)
- DEBUGF(infof(data, "DO phase failed\n"));
+ DEBUGF(infof(data, "DO phase failed"));
else if(*dophase_done) {
result = imap_dophase_done(data, FALSE /* not connected */);
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -2015,7 +2016,7 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data)
return result;
}
- DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'\n", name, value));
+ DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value));
/* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
PARTIAL) stripping of the trailing slash character if it is present.
diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c
index 9a5af7f..b5f9b80 100644
--- a/Utilities/cmcurl/lib/inet_ntop.c
+++ b/Utilities/cmcurl/lib/inet_ntop.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1996-2019 Internet Software Consortium.
+ * Copyright (C) 1996-2021 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -40,7 +40,7 @@
#define INT16SZ 2
/*
- * Format an IPv4 address, more or less like inet_ntoa().
+ * Format an IPv4 address, more or less like inet_ntop().
*
* Returns `dst' (as a const)
* Note:
@@ -134,7 +134,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
/* Are we following an initial run of 0x00s or any real hex?
*/
- if(i != 0)
+ if(i)
*tp++ = ':';
/* Is this address an encapsulated IPv4?
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
index 46116ce..659947d 100644
--- a/Utilities/cmcurl/lib/krb5.c
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -160,16 +160,6 @@ krb5_decode(void *app_data, void *buf, int len,
}
static int
-krb5_overhead(void *app_data, int level, int len)
-{
- /* no arguments are used */
- (void)app_data;
- (void)level;
- (void)len;
- return 0;
-}
-
-static int
krb5_encode(void *app_data, const void *from, int length, int level, void **to)
{
gss_ctx_id_t *context = app_data;
@@ -273,7 +263,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
}
/* We pass NULL as |output_name_type| to avoid a leak. */
gss_display_name(&min, gssname, &output_buffer, NULL);
- Curl_infof(data, "Trying against %s\n", output_buffer.value);
+ infof(data, "Trying against %s", output_buffer.value);
gssresp = GSS_C_NO_BUFFER;
*context = GSS_C_NO_CONTEXT;
@@ -300,19 +290,18 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
}
if(GSS_ERROR(maj)) {
- Curl_infof(data, "Error creating security context\n");
+ infof(data, "Error creating security context");
ret = AUTH_ERROR;
break;
}
- if(output_buffer.length != 0) {
+ if(output_buffer.length) {
char *cmd;
result = Curl_base64_encode(data, (char *)output_buffer.value,
output_buffer.length, &p, &base64_sz);
if(result) {
- Curl_infof(data, "base64-encoding: %s\n",
- curl_easy_strerror(result));
+ infof(data, "base64-encoding: %s", curl_easy_strerror(result));
ret = AUTH_ERROR;
break;
}
@@ -337,7 +326,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
}
if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') {
- Curl_infof(data, "Server didn't accept auth data\n");
+ infof(data, "Server didn't accept auth data");
ret = AUTH_ERROR;
break;
}
@@ -392,7 +381,7 @@ static struct Curl_sec_client_mech Curl_krb5_client_mech = {
krb5_auth,
krb5_end,
krb5_check_prot,
- krb5_overhead,
+
krb5_encode,
krb5_decode
};
@@ -412,7 +401,7 @@ name_to_level(const char *name)
{
int i;
for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
- if(checkprefix(name, level_names[i].name))
+ if(curl_strequal(name, level_names[i].name))
return level_names[i].level;
return PROT_NONE;
}
@@ -639,7 +628,7 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
socket_write(data, fd, cmd_buffer, cmd_size);
socket_write(data, fd, "\r\n", 2);
- infof(data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+ infof(data, "Send: %s%s", prot_level == PROT_PRIVATE?enc:mic,
cmd_buffer);
free(cmd_buffer);
}
@@ -657,8 +646,6 @@ static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
{
ssize_t tx = 0, len = conn->buffer_size;
- len -= conn->mech->overhead(conn->app_data, conn->data_prot,
- curlx_sztosi(len));
if(len <= 0)
len = length;
while(length) {
@@ -750,7 +737,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
if(!conn->sec_complete) {
infof(data, "Trying to change the protection level after the"
- " completion of the data exchange.\n");
+ " completion of the data exchange.");
return -1;
}
@@ -760,7 +747,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
if(level) {
char *pbsz;
- static unsigned int buffer_size = 1 << 20; /* 1048576 */
+ unsigned int buffer_size = 1 << 20; /* 1048576 */
code = ftp_send_command(data, "PBSZ %u", buffer_size);
if(code < 0)
@@ -817,7 +804,7 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
tmp_allocation = realloc(conn->app_data, mech->size);
- if(tmp_allocation == NULL) {
+ if(!tmp_allocation) {
failf(data, "Failed realloc of size %zu", mech->size);
mech = NULL;
return CURLE_OUT_OF_MEMORY;
@@ -827,13 +814,13 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
if(mech->init) {
ret = mech->init(conn->app_data);
if(ret) {
- infof(data, "Failed initialization for %s. Skipping it.\n",
+ infof(data, "Failed initialization for %s. Skipping it.",
mech->name);
return CURLE_FAILED_INIT;
}
}
- infof(data, "Trying mechanism %s...\n", mech->name);
+ infof(data, "Trying mechanism %s...", mech->name);
ret = ftp_send_command(data, "AUTH %s", mech->name);
if(ret < 0)
return CURLE_COULDNT_CONNECT;
@@ -842,15 +829,15 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
switch(ret) {
case 504:
infof(data, "Mechanism %s is not supported by the server (server "
- "returned ftp code: 504).\n", mech->name);
+ "returned ftp code: 504).", mech->name);
break;
case 534:
infof(data, "Mechanism %s was rejected by the server (server returned "
- "ftp code: 534).\n", mech->name);
+ "ftp code: 534).", mech->name);
break;
default:
if(ret/100 == 5) {
- infof(data, "server does not support the security extensions\n");
+ infof(data, "server does not support the security extensions");
return CURLE_USE_SSL_FAILED;
}
break;
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
index 307ebeb..1d9e44c 100644
--- a/Utilities/cmcurl/lib/ldap.c
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -149,6 +149,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
CURLPROTO_LDAP, /* protocol */
CURLPROTO_LDAP, /* family */
@@ -176,6 +177,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
CURLPROTO_LDAPS, /* protocol */
CURLPROTO_LDAP, /* family */
@@ -294,16 +296,16 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
char *passwd = NULL;
*done = TRUE; /* unconditionally */
- infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
+ infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d",
LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
- infof(data, "LDAP local: %s\n", data->change.url);
+ infof(data, "LDAP local: %s", data->state.url);
#ifdef HAVE_LDAP_URL_PARSE
- rc = ldap_url_parse(data->change.url, &ludp);
+ rc = ldap_url_parse(data->state.url, &ludp);
#else
rc = _ldap_url_parse(data, conn, &ludp);
#endif
- if(rc != 0) {
+ if(rc) {
failf(data, "LDAP local: %s", ldap_err2string(rc));
result = CURLE_LDAP_INVALID_URL;
goto quit;
@@ -312,7 +314,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
/* Get the URL scheme (either ldap or ldaps) */
if(conn->given->flags & PROTOPT_SSL)
ldap_ssl = 1;
- infof(data, "LDAP local: trying to establish %s connection\n",
+ infof(data, "LDAP local: trying to establish %s connection",
ldap_ssl ? "encrypted" : "cleartext");
#if defined(USE_WIN32_LDAP)
@@ -364,14 +366,14 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = CURLE_SSL_CERTPROBLEM;
goto quit;
}
- infof(data, "LDAP local: using %s CA cert '%s'\n",
- (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
- ldap_ca);
+ infof(data, "LDAP local: using %s CA cert '%s'",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+ ldap_ca);
rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
if(rc != LDAP_SUCCESS) {
failf(data, "LDAP local: ERROR setting %s CA cert: %s",
- (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
- ldap_err2string(rc));
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+ ldap_err2string(rc));
result = CURLE_SSL_CERTPROBLEM;
goto quit;
}
@@ -387,7 +389,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
server = ldapssl_init(host, (int)conn->port, 1);
- if(server == NULL) {
+ if(!server) {
failf(data, "LDAP local: Cannot connect to %s:%ld",
conn->host.dispname, conn->port);
result = CURLE_COULDNT_CONNECT;
@@ -407,7 +409,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = CURLE_SSL_CERTPROBLEM;
goto quit;
}
- infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
+ infof(data, "LDAP local: using PEM CA cert: %s", ldap_ca);
rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
if(rc != LDAP_SUCCESS) {
failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
@@ -428,7 +430,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
server = ldap_init(host, (int)conn->port);
- if(server == NULL) {
+ if(!server) {
failf(data, "LDAP local: Cannot connect to %s:%ld",
conn->host.dispname, conn->port);
result = CURLE_COULDNT_CONNECT;
@@ -464,7 +466,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
}
else {
server = ldap_init(host, (int)conn->port);
- if(server == NULL) {
+ if(!server) {
failf(data, "LDAP local: Cannot connect to %s:%ld",
conn->host.dispname, conn->port);
result = CURLE_COULDNT_CONNECT;
@@ -477,7 +479,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
#else
rc = ldap_simple_bind_s(server, user, passwd);
#endif
- if(!ldap_ssl && rc != 0) {
+ if(!ldap_ssl && rc) {
ldap_proto = LDAP_VERSION2;
ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
#ifdef USE_WIN32_LDAP
@@ -486,7 +488,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
rc = ldap_simple_bind_s(server, user, passwd);
#endif
}
- if(rc != 0) {
+ if(rc) {
#ifdef USE_WIN32_LDAP
failf(data, "LDAP local: bind via ldap_win_bind %s",
ldap_err2string(rc));
@@ -501,7 +503,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
- if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
+ if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) {
failf(data, "LDAP remote: %s", ldap_err2string(rc));
result = CURLE_LDAP_SEARCH_FAILED;
goto quit;
@@ -581,7 +583,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = CURLE_OUT_OF_MEMORY;
goto quit;
- }
+ }
#else
char *attr = attribute;
#endif
@@ -716,7 +718,7 @@ quit:
LDAP_TRACE(("Received %d entries\n", num));
}
if(rc == LDAP_SIZELIMIT_EXCEEDED)
- infof(data, "There are more than %d entries\n", num);
+ infof(data, "There are more than %d entries", num);
if(ludp)
ldap_free_urldesc(ludp);
if(server)
@@ -875,7 +877,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped);
/* Free the unescaped string as we are done with it */
- curlx_unicodefree(unescaped);
+ free(unescaped);
if(!ludp->lud_dn) {
rc = LDAP_NO_MEMORY;
@@ -943,7 +945,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped);
/* Free the unescaped string as we are done with it */
- curlx_unicodefree(unescaped);
+ free(unescaped);
if(!ludp->lud_attrs[i]) {
free(attributes);
@@ -1010,7 +1012,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped);
/* Free the unescaped string as we are done with it */
- curlx_unicodefree(unescaped);
+ free(unescaped);
if(!ludp->lud_filter) {
rc = LDAP_NO_MEMORY;
@@ -1061,13 +1063,23 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp)
if(!ludp)
return;
+#if defined(USE_WIN32_LDAP)
+ curlx_unicodefree(ludp->lud_dn);
+ curlx_unicodefree(ludp->lud_filter);
+#else
free(ludp->lud_dn);
free(ludp->lud_filter);
+#endif
if(ludp->lud_attrs) {
size_t i;
- for(i = 0; i < ludp->lud_attrs_dups; i++)
+ for(i = 0; i < ludp->lud_attrs_dups; i++) {
+#if defined(USE_WIN32_LDAP)
+ curlx_unicodefree(ludp->lud_attrs[i]);
+#else
free(ludp->lud_attrs[i]);
+#endif
+ }
free(ludp->lud_attrs);
}
diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c
index 17a7be1..e0ec739 100644
--- a/Utilities/cmcurl/lib/llist.c
+++ b/Utilities/cmcurl/lib/llist.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
@@ -94,13 +94,13 @@ Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
void *user)
{
void *ptr;
- if(e == NULL || list->size == 0)
+ if(!e || list->size == 0)
return;
if(e == list->head) {
list->head = e->next;
- if(list->head == NULL)
+ if(!list->head)
list->tail = NULL;
else
e->next->prev = NULL;
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
index 8ae6ac3..e7a428f 100644
--- a/Utilities/cmcurl/lib/md4.c
+++ b/Utilities/cmcurl/lib/md4.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
@@ -36,15 +36,19 @@
#endif /* USE_OPENSSL */
#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
#endif
#endif /* USE_MBEDTLS */
-#if defined(USE_GNUTLS_NETTLE)
+#if defined(USE_GNUTLS)
#include <nettle/md4.h>
@@ -70,33 +74,6 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
md4_digest(ctx, MD4_DIGEST_SIZE, result);
}
-#elif defined(USE_GNUTLS)
-
-#include <gcrypt.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-typedef gcry_md_hd_t MD4_CTX;
-
-static void MD4_Init(MD4_CTX *ctx)
-{
- gcry_md_open(ctx, GCRY_MD_MD4, 0);
-}
-
-static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
-{
- gcry_md_write(*ctx, data, size);
-}
-
-static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
-{
- memcpy(result, gcry_md_read(*ctx, 0), MD4_DIGEST_LENGTH);
- gcry_md_close(*ctx);
-}
-
#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
/* When OpenSSL is available we use the MD4-functions from OpenSSL */
#include <openssl/md4.h>
@@ -201,7 +178,7 @@ static void MD4_Init(MD4_CTX *ctx)
static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
{
- if(ctx->data == NULL) {
+ if(!ctx->data) {
ctx->data = malloc(size);
if(ctx->data != NULL) {
memcpy(ctx->data, data, size);
diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
index 513ffb2..983ed97 100644
--- a/Utilities/cmcurl/lib/md5.c
+++ b/Utilities/cmcurl/lib/md5.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
@@ -33,12 +33,13 @@
#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_GNUTLS_NETTLE)
+#if defined(USE_GNUTLS)
#include <nettle/md5.h>
#include "curl_memory.h"
@@ -64,33 +65,6 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
md5_digest(ctx, 16, digest);
}
-#elif defined(USE_GNUTLS)
-
-#include <gcrypt.h>
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-typedef gcry_md_hd_t MD5_CTX;
-
-static void MD5_Init(MD5_CTX *ctx)
-{
- gcry_md_open(ctx, GCRY_MD_MD5, 0);
-}
-
-static void MD5_Update(MD5_CTX *ctx,
- const unsigned char *input,
- unsigned int inputLen)
-{
- gcry_md_write(*ctx, input, inputLen);
-}
-
-static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
-{
- memcpy(digest, gcry_md_read(*ctx, 0), 16);
- gcry_md_close(*ctx);
-}
-
#elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
/* When OpenSSL is available we use the MD5-function from OpenSSL */
#include <openssl/md5.h>
@@ -112,7 +86,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
@@ -123,7 +97,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
@@ -132,7 +106,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/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c
index 881ee85..050c5d4 100644
--- a/Utilities/cmcurl/lib/memdebug.c
+++ b/Utilities/cmcurl/lib/memdebug.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
@@ -55,9 +55,24 @@ struct memdebug {
*/
FILE *curl_dbg_logfile = NULL;
+static bool registered_cleanup = FALSE; /* atexit registered cleanup */
static bool memlimit = FALSE; /* enable memory limit */
static long memsize = 0; /* set number of mallocs allowed */
+/* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected
+ on exit so the logfile must be closed explicitly or data could be lost.
+ Though _exit() does not call atexit handlers such as this, LSAN's call to
+ _exit() comes after the atexit handlers are called. curl/curl#6620 */
+static void curl_dbg_cleanup(void)
+{
+ if(curl_dbg_logfile &&
+ curl_dbg_logfile != stderr &&
+ curl_dbg_logfile != stdout) {
+ fclose(curl_dbg_logfile);
+ }
+ curl_dbg_logfile = NULL;
+}
+
/* this sets the log file name */
void curl_dbg_memdebug(const char *logname)
{
@@ -72,6 +87,8 @@ void curl_dbg_memdebug(const char *logname)
setbuf(curl_dbg_logfile, (char *)NULL);
#endif
}
+ if(!registered_cleanup)
+ registered_cleanup = !atexit(curl_dbg_cleanup);
}
/* This function sets the number of malloc() calls that should return
@@ -91,15 +108,13 @@ static bool countcheck(const char *func, int line, const char *source)
should not be made */
if(memlimit && source) {
if(!memsize) {
- if(source) {
- /* log to file */
- curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
- source, line, func);
- /* log to stderr also */
- fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
- source, line, func);
- fflush(curl_dbg_logfile); /* because it might crash now */
- }
+ /* log to file */
+ curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ /* log to stderr also */
+ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ fflush(curl_dbg_logfile); /* because it might crash now */
errno = ENOMEM;
return TRUE; /* RETURN ERROR! */
}
diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c
index abadcb0..0bf1b46 100644
--- a/Utilities/cmcurl/lib/mime.c
+++ b/Utilities/cmcurl/lib/mime.c
@@ -152,14 +152,14 @@ curl_off_t VmsRealFileSize(const char *name,
FILE * file;
file = fopen(name, FOPEN_READTEXT); /* VMS */
- if(file == NULL)
+ if(!file)
return 0;
count = 0;
ret_stat = 1;
while(ret_stat > 0) {
ret_stat = fread(buffer, 1, sizeof(buffer), file);
- if(ret_stat != 0)
+ if(ret_stat)
count += ret_stat;
}
fclose(file);
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
index c681248..7a1aec5 100644
--- a/Utilities/cmcurl/lib/mprintf.c
+++ b/Utilities/cmcurl/lib/mprintf.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1999 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1999 - 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
@@ -815,7 +815,7 @@ static int dprintf_formatf(
size_t len;
str = (char *) p->data.str;
- if(str == NULL) {
+ if(!str) {
/* Write null[] if there's space. */
if(prec == -1 || prec >= (long) sizeof(null) - 1) {
str = null;
@@ -1017,9 +1017,11 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
retcode = dprintf_formatf(&info, addbyter, format, ap_save);
if((retcode != -1) && info.max) {
/* we terminate this with a zero byte */
- if(info.max == info.length)
+ if(info.max == info.length) {
/* we're at maximum, scrap the last letter */
info.buffer[-1] = 0;
+ retcode--; /* don't count the nul byte */
+ }
else
info.buffer[0] = 0;
}
diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c
index 2134409..fcd40b4 100644
--- a/Utilities/cmcurl/lib/mqtt.c
+++ b/Utilities/cmcurl/lib/mqtt.c
@@ -86,6 +86,7 @@ const struct Curl_handler Curl_handler_mqtt = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_MQTT, /* defport */
CURLPROTO_MQTT, /* protocol */
CURLPROTO_MQTT, /* family */
@@ -127,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;
}
@@ -142,32 +147,197 @@ static int mqtt_getsock(struct Curl_easy *data,
return GETSOCK_READSOCK(FIRSTSOCKET);
}
+static int mqtt_encode_len(char *buf, size_t len)
+{
+ unsigned char encoded;
+ int i;
+
+ for(i = 0; (len > 0) && (i<4); i++) {
+ encoded = len % 0x80;
+ len /= 0x80;
+ if(len)
+ encoded |= 0x80;
+ buf[i] = encoded;
+ }
+
+ return i;
+}
+
+/* add the passwd to the CONNECT packet */
+static int add_passwd(const char *passwd, const size_t plen,
+ char *pkt, const size_t start, int remain_pos)
+{
+ /* magic number that need to be set properly */
+ const size_t conn_flags_pos = remain_pos + 8;
+ if(plen > 0xffff)
+ return 1;
+
+ /* set password flag */
+ pkt[conn_flags_pos] |= 0x40;
+
+ /* length of password provided */
+ pkt[start] = (char)((plen >> 8) & 0xFF);
+ pkt[start + 1] = (char)(plen & 0xFF);
+ memcpy(&pkt[start + 2], passwd, plen);
+ return 0;
+}
+
+/* add user to the CONN packet */
+static int add_user(const char *username, const size_t ulen,
+ unsigned char *pkt, const size_t start, int remain_pos)
+{
+ /* magic number that need to be set properly */
+ const size_t conn_flags_pos = remain_pos + 8;
+ if(ulen > 0xffff)
+ return 1;
+
+ /* set username flag */
+ pkt[conn_flags_pos] |= 0x80;
+ /* length of username provided */
+ pkt[start] = (unsigned char)((ulen >> 8) & 0xFF);
+ pkt[start + 1] = (unsigned char)(ulen & 0xFF);
+ memcpy(&pkt[start + 2], username, ulen);
+ return 0;
+}
+
+/* add client ID to the CONN packet */
+static int add_client_id(const char *client_id, const size_t client_id_len,
+ char *pkt, const size_t start)
+{
+ if(client_id_len != MQTT_CLIENTID_LEN)
+ return 1;
+ pkt[start] = 0x00;
+ pkt[start + 1] = MQTT_CLIENTID_LEN;
+ memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN);
+ return 0;
+}
+
+/* Set initial values of CONN packet */
+static int init_connpack(char *packet, char *remain, int remain_pos)
+{
+ /* Fixed header starts */
+ /* packet type */
+ packet[0] = MQTT_MSG_CONNECT;
+ /* remaining length field */
+ memcpy(&packet[1], remain, remain_pos);
+ /* Fixed header ends */
+
+ /* Variable header starts */
+ /* protocol length */
+ packet[remain_pos + 1] = 0x00;
+ packet[remain_pos + 2] = 0x04;
+ /* protocol name */
+ packet[remain_pos + 3] = 'M';
+ packet[remain_pos + 4] = 'Q';
+ packet[remain_pos + 5] = 'T';
+ packet[remain_pos + 6] = 'T';
+ /* protocol level */
+ packet[remain_pos + 7] = 0x04;
+ /* CONNECT flag: CleanSession */
+ packet[remain_pos + 8] = 0x02;
+ /* keep-alive 0 = disabled */
+ packet[remain_pos + 9] = 0x00;
+ packet[remain_pos + 10] = 0x3c;
+ /*end of variable header*/
+ return remain_pos + 10;
+}
+
static CURLcode mqtt_connect(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- const size_t client_id_offset = 14;
- const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN;
+ int pos = 0;
+ int rc = 0;
+ /*remain length*/
+ int remain_pos = 0;
+ char remain[4] = {0};
+ size_t packetlen = 0;
+ size_t payloadlen = 0;
+ size_t start_user = 0;
+ size_t start_pwd = 0;
char client_id[MQTT_CLIENTID_LEN + 1] = "curl";
const size_t clen = strlen("curl");
- char packet[32] = {
- MQTT_MSG_CONNECT, /* packet type */
- 0x00, /* remaining length */
- 0x00, 0x04, /* protocol length */
- 'M','Q','T','T', /* protocol name */
- 0x04, /* protocol level */
- 0x02, /* CONNECT flag: CleanSession */
- 0x00, 0x3c, /* keep-alive 0 = disabled */
- 0x00, 0x00 /* payload1 length */
- };
- packet[1] = (packetlen - 2) & 0x7f;
- packet[client_id_offset - 1] = MQTT_CLIENTID_LEN;
+ char *packet = NULL;
+
+ /* extracting username from request */
+ const char *username = data->state.aptr.user ?
+ data->state.aptr.user : "";
+ const size_t ulen = strlen(username);
+ /* extracting password from request */
+ const char *passwd = data->state.aptr.passwd ?
+ data->state.aptr.passwd : "";
+ const size_t plen = strlen(passwd);
+
+ payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2;
+ /* The plus 2 are for the MSB and LSB describing the length of the string to
+ * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */
+ if(ulen)
+ payloadlen += 2;
+ if(plen)
+ payloadlen += 2;
+
+ /* getting how much occupy the remain length */
+ remain_pos = mqtt_encode_len(remain, payloadlen + 10);
+
+ /* 10 length of variable header and 1 the first byte of the fixed header */
+ packetlen = payloadlen + 10 + remain_pos + 1;
+
+ /* allocating packet */
+ if(packetlen > 268435455)
+ return CURLE_WEIRD_SERVER_REPLY;
+ packet = malloc(packetlen);
+ if(!packet)
+ return CURLE_OUT_OF_MEMORY;
+ memset(packet, 0, packetlen);
+
+ /* set initial values for CONN pack */
+ pos = init_connpack(packet, remain, remain_pos);
result = Curl_rand_hex(data, (unsigned char *)&client_id[clen],
MQTT_CLIENTID_LEN - clen + 1);
- memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN);
- infof(data, "Using client id '%s'\n", client_id);
+ /* add client id */
+ rc = add_client_id(client_id, strlen(client_id), packet, pos + 1);
+ if(rc) {
+ failf(data, "Client ID length mismatched: [%lu]", strlen(client_id));
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto end;
+ }
+ infof(data, "Using client id '%s'", client_id);
+
+ /* position where starts the user payload */
+ start_user = pos + 3 + MQTT_CLIENTID_LEN;
+ /* position where starts the password payload */
+ start_pwd = start_user + ulen;
+ /* if user name was provided, add it to the packet */
+ if(ulen) {
+ start_pwd += 2;
+
+ rc = add_user(username, ulen,
+ (unsigned char *)packet, start_user, remain_pos);
+ if(rc) {
+ failf(data, "Username is too large: [%lu]", ulen);
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto end;
+ }
+ }
+
+ /* if passwd was provided, add it to the packet */
+ if(plen) {
+ rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos);
+ if(rc) {
+ failf(data, "Password is too large: [%lu]", plen);
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto end;
+ }
+ }
+
if(!result)
result = mqtt_send(data, packet, packetlen);
+
+end:
+ if(packet)
+ free(packet);
+ Curl_safefree(data->state.aptr.user);
+ Curl_safefree(data->state.aptr.passwd);
return result;
}
@@ -212,35 +382,12 @@ fail:
static CURLcode mqtt_get_topic(struct Curl_easy *data,
char **topic, size_t *topiclen)
{
- CURLcode result = CURLE_OK;
char *path = data->state.up.path;
-
- if(strlen(path) > 1) {
- result = Curl_urldecode(data, path + 1, 0, topic, topiclen,
- REJECT_NADA);
- }
- else {
- failf(data, "Error: No topic specified.");
- result = CURLE_URL_MALFORMAT;
- }
- return result;
-}
-
-
-static int mqtt_encode_len(char *buf, size_t len)
-{
- unsigned char encoded;
- int i;
-
- for(i = 0; (len > 0) && (i<4); i++) {
- encoded = len % 0x80;
- len /= 0x80;
- if(len)
- encoded |= 0x80;
- buf[i] = encoded;
- }
-
- return i;
+ if(strlen(path) > 1)
+ return Curl_urldecode(data, path + 1, 0, topic, topiclen,
+ REJECT_NADA);
+ failf(data, "No MQTT topic found. Forgot to URL encode it?");
+ return CURLE_URL_MALFORMAT;
}
static CURLcode mqtt_subscribe(struct Curl_easy *data)
@@ -417,7 +564,7 @@ static void mqstate(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
#ifdef CURLDEBUG
- infof(data, "%s (from %s) (next is %s)\n",
+ infof(data, "%s (from %s) (next is %s)",
statenames[state],
statenames[mqtt->state],
(state == MQTT_FIRST)? statenames[nextstate] : "");
@@ -464,7 +611,7 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
goto MQTT_SUBACK_COMING;
}
else if(packet == MQTT_MSG_DISCONNECT) {
- infof(data, "Got DISCONNECT\n");
+ infof(data, "Got DISCONNECT");
*done = TRUE;
goto end;
}
@@ -475,7 +622,13 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
/* -- switched state -- */
remlen = mq->remaining_length;
- infof(data, "Remaining length: %zd bytes\n", remlen);
+ infof(data, "Remaining length: %zd bytes", remlen);
+ if(data->set.max_filesize &&
+ (curl_off_t)remlen > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ result = CURLE_FILESIZE_EXCEEDED;
+ goto end;
+ }
Curl_pgrsSetDownloadSize(data, remlen);
data->req.bytecount = 0;
data->req.size = remlen;
@@ -490,12 +643,12 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
if(result) {
if(CURLE_AGAIN == result) {
- infof(data, "EEEE AAAAGAIN\n");
+ infof(data, "EEEE AAAAGAIN");
}
goto end;
}
if(!nread) {
- infof(data, "server disconnected\n");
+ infof(data, "server disconnected");
result = CURLE_PARTIAL_FILE;
goto end;
}
@@ -561,7 +714,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
return result;
}
- infof(data, "mqtt_doing: state [%d]\n", (int) mqtt->state);
+ infof(data, "mqtt_doing: state [%d]", (int) mqtt->state);
switch(mqtt->state) {
case MQTT_FIRST:
/* Read the initial byte only */
@@ -581,6 +734,10 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
pkt[mq->npacket++] = byte;
} while((byte & 0x80) && (mq->npacket < 4));
+ if(nread && (byte & 0x80))
+ /* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
+ 127 * 128^3 bytes. server tried to send more */
+ result = CURLE_WEIRD_SERVER_REPLY;
if(result)
break;
mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
@@ -592,7 +749,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
mqstate(data, MQTT_FIRST, MQTT_FIRST);
if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
- infof(data, "Got DISCONNECT\n");
+ infof(data, "Got DISCONNECT");
*done = TRUE;
}
break;
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 85707a1..8509781 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -83,19 +83,19 @@ static void process_pending_handles(struct Curl_multi *multi);
#ifdef DEBUGBUILD
static const char * const statename[]={
"INIT",
- "CONNECT_PEND",
+ "PENDING",
"CONNECT",
- "WAITRESOLVE",
- "WAITCONNECT",
- "WAITPROXYCONNECT",
- "SENDPROTOCONNECT",
+ "RESOLVING",
+ "CONNECTING",
+ "TUNNELING",
"PROTOCONNECT",
+ "PROTOCONNECTING",
"DO",
"DOING",
- "DO_MORE",
- "DO_DONE",
- "PERFORM",
- "TOOFAST",
+ "DOING_MORE",
+ "DID",
+ "PERFORMING",
+ "RATELIMITING",
"DONE",
"COMPLETED",
"MSGSENT",
@@ -105,8 +105,8 @@ static const char * const statename[]={
/* function pointer called once when switching TO a state */
typedef void (*init_multistate_func)(struct Curl_easy *data);
-/* called when the PERFORM state starts */
-static void init_perform(struct Curl_easy *data)
+/* called in DID state, before PERFORMING state */
+static void before_perform(struct Curl_easy *data)
{
data->req.chunk = FALSE;
Curl_pgrsTime(data, TIMER_PRETRANSFER);
@@ -130,21 +130,21 @@ static void mstate(struct Curl_easy *data, CURLMstate state
)
{
CURLMstate oldstate = data->mstate;
- static const init_multistate_func finit[CURLM_STATE_LAST] = {
+ static const init_multistate_func finit[MSTATE_LAST] = {
NULL, /* INIT */
- NULL, /* CONNECT_PEND */
+ NULL, /* PENDING */
Curl_init_CONNECT, /* CONNECT */
- NULL, /* WAITRESOLVE */
- NULL, /* WAITCONNECT */
- NULL, /* WAITPROXYCONNECT */
- NULL, /* SENDPROTOCONNECT */
+ NULL, /* RESOLVING */
+ NULL, /* CONNECTING */
+ NULL, /* TUNNELING */
NULL, /* PROTOCONNECT */
+ NULL, /* PROTOCONNECTING */
Curl_connect_free, /* DO */
NULL, /* DOING */
- NULL, /* DO_MORE */
- NULL, /* DO_DONE */
- init_perform, /* PERFORM */
- NULL, /* TOOFAST */
+ NULL, /* DOING_MORE */
+ before_perform, /* DID */
+ NULL, /* PERFORMING */
+ NULL, /* RATELIMITING */
NULL, /* DONE */
init_completed, /* COMPLETED */
NULL /* MSGSENT */
@@ -161,21 +161,21 @@ static void mstate(struct Curl_easy *data, CURLMstate state
data->mstate = state;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
- data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate >= MSTATE_PENDING &&
+ data->mstate < MSTATE_COMPLETED) {
long connection_id = -5000;
if(data->conn)
connection_id = data->conn->connection_id;
infof(data,
- "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
+ "STATE: %s => %s handle %p; line %d (connection #%ld)",
statename[oldstate], statename[data->mstate],
(void *)data, lineno, connection_id);
}
#endif
- if(state == CURLM_STATE_COMPLETED) {
+ if(state == MSTATE_COMPLETED) {
/* changing to COMPLETED means there's one less easy handle 'alive' */
DEBUGASSERT(data->multi->num_alive > 0);
data->multi->num_alive--;
@@ -381,6 +381,11 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
multi->max_concurrent_streams = 100;
multi->ipv6_works = Curl_ipv6works(NULL);
+#ifdef USE_WINSOCK
+ multi->wsa_event = WSACreateEvent();
+ if(multi->wsa_event == WSA_INVALID_EVENT)
+ goto error;
+#else
#ifdef ENABLE_WAKEUP
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) {
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
@@ -394,6 +399,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
}
#endif
+#endif
return multi;
@@ -447,7 +453,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->set.errorbuffer[0] = 0;
/* set the easy handle */
- multistate(data, CURLM_STATE_INIT);
+ multistate(data, MSTATE_INIT);
/* for multi interface connections, we share DNS cache automatically if the
easy handle's one is currently not set. */
@@ -556,14 +562,12 @@ static CURLcode multi_done(struct Curl_easy *data,
struct connectdata *conn = data->conn;
unsigned int i;
- DEBUGF(infof(data, "multi_done\n"));
+ DEBUGF(infof(data, "multi_done"));
if(data->state.done)
/* Stop if multi_done() has already been called */
return CURLE_OK;
- conn->data = data; /* ensure the connection uses this transfer now */
-
/* Stop the resolver and free its own resources (but not dns_entry yet). */
Curl_resolver_kill(data);
@@ -604,16 +608,13 @@ static CURLcode multi_done(struct Curl_easy *data,
Curl_detach_connnection(data);
if(CONN_INUSE(conn)) {
/* Stop if still used. */
- /* conn->data must not remain pointing to this transfer since it is going
- away! Find another to own it! */
- conn->data = conn->easyq.head->ptr;
CONNCACHE_UNLOCK(data);
DEBUGF(infof(data, "Connection still in use %zu, "
- "no more multi_done now!\n",
+ "no more multi_done now!",
conn->easyq.size));
return CURLE_OK;
}
- conn->data = NULL; /* the connection now has no owner */
+
data->state.done = TRUE; /* called just now! */
if(conn->dns_entry) {
@@ -686,7 +687,7 @@ static CURLcode multi_done(struct Curl_easy *data,
if(Curl_conncache_return_conn(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect_id = conn->connection_id;
- infof(data, "%s\n", buffer);
+ infof(data, "%s", buffer);
}
else
data->state.lastconnect_id = -1;
@@ -708,7 +709,6 @@ static int close_connect_only(struct Curl_easy *data,
return 1;
connclose(conn, "Removing connect-only easy handle");
- conn->bits.connect_only = FALSE;
return 1;
}
@@ -718,7 +718,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
{
struct Curl_easy *easy = data;
bool premature;
- bool easy_owns_conn;
struct Curl_llist_element *e;
/* First, make some basic checks that the CURLM handle is a good handle */
@@ -740,9 +739,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
- easy_owns_conn = (data->conn && (data->conn->data == easy)) ?
- TRUE : FALSE;
+ premature = (data->mstate < MSTATE_COMPLETED) ? TRUE : FALSE;
/* If the 'state' is not INIT or COMPLETED, we might need to do something
nice to put the easy_handle in a good known state when this returns. */
@@ -753,28 +750,20 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
}
if(data->conn &&
- data->mstate > CURLM_STATE_DO &&
- data->mstate < CURLM_STATE_COMPLETED) {
+ data->mstate > MSTATE_DO &&
+ data->mstate < MSTATE_COMPLETED) {
/* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
- data->conn->data = easy;
streamclose(data->conn, "Removed with partial response");
- easy_owns_conn = TRUE;
}
if(data->conn) {
+ /* multi_done() clears the association between the easy handle and the
+ connection.
- /* we must call multi_done() here (if we still own the connection) so that
- we don't leave a half-baked one around */
- if(easy_owns_conn) {
-
- /* multi_done() clears the association between the easy handle and the
- connection.
-
- Note that this ignores the return code simply because there's
- nothing really useful to do with it anyway! */
- (void)multi_done(data, data->result, premature);
- }
+ Note that this ignores the return code simply because there's
+ nothing really useful to do with it anyway! */
+ (void)multi_done(data, data->result, premature);
}
/* The timer must be shut down before data->multi is set to NULL, else the
@@ -802,7 +791,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* change state without using multistate(), only to make singlesocket() do
what we want */
- data->mstate = CURLM_STATE_COMPLETED;
+ data->mstate = MSTATE_COMPLETED;
singlesocket(multi, easy); /* to let the application know what sockets that
vanish with this handle */
@@ -840,6 +829,17 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
}
}
+ /* Remove from the pending list if it is there. Otherwise this will
+ remain on the pending list forever due to the state change. */
+ for(e = multi->pending.head; e; e = e->next) {
+ struct Curl_easy *curr_data = e->ptr;
+
+ if(curr_data == data) {
+ Curl_llist_remove(&multi->pending, e, NULL);
+ break;
+ }
+ }
+
/* make the previous node point to our next */
if(data->prev)
data->prev->next = data->next;
@@ -856,6 +856,8 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
We do not touch the easy handle here! */
multi->num_easy--; /* one less to care about now */
+ process_pending_handles(multi);
+
Curl_update_timer(multi);
return CURLM_OK;
}
@@ -875,8 +877,10 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi)
void Curl_detach_connnection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
- if(conn)
+ if(conn) {
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
+ Curl_ssl_detach_conn(data, conn);
+ }
data->conn = NULL;
}
@@ -893,6 +897,9 @@ void Curl_attach_connnection(struct Curl_easy *data,
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
+ if(conn->handler->attach)
+ conn->handler->attach(data, conn);
+ Curl_ssl_associate_conn(data, conn);
}
static int waitconnect_getsock(struct connectdata *conn,
@@ -905,7 +912,7 @@ static int waitconnect_getsock(struct connectdata *conn,
#ifdef USE_SSL
#ifndef CURL_DISABLE_PROXY
if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- return Curl_ssl_getsock(conn, sock);
+ return Curl_ssl->getsock(conn, sock);
#endif
#endif
@@ -933,10 +940,8 @@ static int waitproxyconnect_getsock(struct connectdata *conn,
{
sock[0] = conn->sock[FIRSTSOCKET];
- /* when we've sent a CONNECT to a proxy, we should rather wait for the
- socket to become readable to be able to get the response headers */
if(conn->connect_state)
- return GETSOCK_READSOCK(0);
+ return Curl_connect_getsock(conn);
return GETSOCK_WRITESOCK(0);
}
@@ -984,40 +989,33 @@ static int multi_getsock(struct Curl_easy *data,
if(!conn)
return 0;
- if(data->mstate > CURLM_STATE_CONNECT &&
- data->mstate < CURLM_STATE_COMPLETED) {
- /* Set up ownership correctly */
- data->conn->data = data;
- }
-
switch(data->mstate) {
default:
return 0;
- case CURLM_STATE_WAITRESOLVE:
+ case MSTATE_RESOLVING:
return Curl_resolv_getsock(data, socks);
- case CURLM_STATE_PROTOCONNECT:
- case CURLM_STATE_SENDPROTOCONNECT:
+ case MSTATE_PROTOCONNECTING:
+ case MSTATE_PROTOCONNECT:
return protocol_getsock(data, conn, socks);
- case CURLM_STATE_DO:
- case CURLM_STATE_DOING:
+ case MSTATE_DO:
+ case MSTATE_DOING:
return doing_getsock(data, conn, socks);
- case CURLM_STATE_WAITPROXYCONNECT:
+ case MSTATE_TUNNELING:
return waitproxyconnect_getsock(conn, socks);
- case CURLM_STATE_WAITCONNECT:
+ case MSTATE_CONNECTING:
return waitconnect_getsock(conn, socks);
- case CURLM_STATE_DO_MORE:
+ case MSTATE_DOING_MORE:
return domore_getsock(data, conn, socks);
- case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
- to waiting for the same as the *PERFORM
- states */
- case CURLM_STATE_PERFORM:
+ case MSTATE_DID: /* since is set after DO is completed, we switch to
+ waiting for the same as the PERFORMING state */
+ case MSTATE_PERFORMING:
return Curl_single_getsock(data, conn, socks);
}
@@ -1044,7 +1042,12 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
data = multi->easyp;
while(data) {
- int bitmap = multi_getsock(data, sockbunch);
+ int bitmap;
+#ifdef __clang_analyzer_
+ /* to prevent "The left operand of '>=' is a garbage value" warnings */
+ memset(sockbunch, 0, sizeof(sockbunch));
+#endif
+ bitmap = multi_getsock(data, sockbunch);
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
@@ -1093,6 +1096,13 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct pollfd *ufds = &a_few_on_stack[0];
bool ufds_malloc = FALSE;
+#ifdef USE_WINSOCK
+ 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;
@@ -1111,11 +1121,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
- if(bitmap & GETSOCK_READSOCK(i)) {
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
++nfds;
s = sockbunch[i];
}
- if(bitmap & GETSOCK_WRITESOCK(i)) {
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
++nfds;
s = sockbunch[i];
}
@@ -1138,7 +1148,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
nfds += extra_nfds; /* add the externally provided ones */
#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+ if(use_wakeup) {
+#else
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+#endif
++nfds;
}
#endif
@@ -1166,22 +1180,40 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
-
- if(bitmap & GETSOCK_READSOCK(i)) {
- ufds[nfds].fd = sockbunch[i];
+#ifdef USE_WINSOCK
+ long mask = 0;
+#endif
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ s = sockbunch[i];
+#ifdef USE_WINSOCK
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+#endif
+ ufds[nfds].fd = s;
ufds[nfds].events = POLLIN;
++nfds;
- s = sockbunch[i];
}
- if(bitmap & GETSOCK_WRITESOCK(i)) {
- ufds[nfds].fd = sockbunch[i];
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ s = sockbunch[i];
+#ifdef USE_WINSOCK
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ send(s, NULL, 0, 0); /* reset FD_WRITE */
+#endif
+ ufds[nfds].fd = s;
ufds[nfds].events = POLLOUT;
++nfds;
- s = sockbunch[i];
}
+ /* s is only set if either being readable or writable is checked */
if(s == CURL_SOCKET_BAD) {
+ /* break on entry not checked for being readable or writable */
break;
}
+#ifdef USE_WINSOCK
+ if(WSAEventSelect(s, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
+ }
+#endif
}
data = data->next; /* check next handle */
@@ -1190,6 +1222,22 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
/* Add external file descriptions from poll-like struct curl_waitfd */
for(i = 0; i < extra_nfds; i++) {
+#ifdef USE_WINSOCK
+ long mask = 0;
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+ mask |= FD_OOB;
+ if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ send(extra_fds[i].fd, NULL, 0, 0); /* reset FD_WRITE */
+ }
+ if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
+ }
+#endif
ufds[nfds].fd = extra_fds[i].fd;
ufds[nfds].events = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN)
@@ -1202,25 +1250,62 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
#ifdef ENABLE_WAKEUP
+#ifndef USE_WINSOCK
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
ufds[nfds].fd = multi->wakeup_pair[0];
ufds[nfds].events = POLLIN;
++nfds;
}
#endif
+#endif
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+ if(nfds || use_wakeup) {
+#else
if(nfds) {
- /* wait... */
- int pollrc = Curl_poll(ufds, nfds, timeout_ms);
+#endif
+ int pollrc;
+#ifdef USE_WINSOCK
+ if(nfds)
+ pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
+ else
+ pollrc = 0;
+ if(pollrc <= 0) /* now wait... if not ready during the pre-check above */
+ WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
+#else
+ pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
+#endif
+
if(pollrc > 0) {
retcode = pollrc;
+#ifdef USE_WINSOCK
+ }
+ /* With WinSock, we have to run the following section unconditionally
+ to call WSAEventSelect(fd, event, 0) on all the sockets */
+ {
+#endif
/* copy revents results from the poll to the curl_multi_wait poll
struct, the bit values of the actual underlying poll() implementation
may not be the same as the ones in the public libcurl API! */
for(i = 0; i < extra_nfds; i++) {
- unsigned short mask = 0;
unsigned r = ufds[curlfds + i].revents;
-
+ unsigned short mask = 0;
+#ifdef USE_WINSOCK
+ wsa_events.lNetworkEvents = 0;
+ if(WSAEnumNetworkEvents(extra_fds[i].fd, NULL, &wsa_events) == 0) {
+ if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
+ mask |= CURL_WAIT_POLLIN;
+ if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
+ mask |= CURL_WAIT_POLLOUT;
+ if(wsa_events.lNetworkEvents & FD_OOB)
+ mask |= CURL_WAIT_POLLPRI;
+ if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
+ retcode++;
+ }
+ WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0);
+ if(pollrc <= 0)
+ continue;
+#endif
if(r & POLLIN)
mask |= CURL_WAIT_POLLIN;
if(r & POLLOUT)
@@ -1230,6 +1315,35 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
extra_fds[i].revents = mask;
}
+#ifdef USE_WINSOCK
+ /* Count up all our own sockets that had activity,
+ and remove them from the event. */
+ if(curlfds) {
+ data = multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch);
+
+ for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
+ if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) {
+ wsa_events.lNetworkEvents = 0;
+ if(WSAEnumNetworkEvents(sockbunch[i], NULL, &wsa_events) == 0) {
+ if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
+ retcode++;
+ }
+ WSAEventSelect(sockbunch[i], multi->wsa_event, 0);
+ }
+ else {
+ /* break on entry not checked for being readable or writable */
+ break;
+ }
+ }
+
+ data = data->next;
+ }
+ }
+
+ WSAResetEvent(multi->wsa_event);
+#else
#ifdef ENABLE_WAKEUP
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
if(ufds[curlfds + extra_nfds].revents & POLLIN) {
@@ -1242,10 +1356,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
when there is no more data, breaking the loop. */
nread = sread(multi->wakeup_pair[0], buf, sizeof(buf));
if(nread <= 0) {
-#ifndef USE_WINSOCK
if(nread < 0 && EINTR == SOCKERRNO)
continue;
-#endif
break;
}
}
@@ -1254,6 +1366,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
}
#endif
+#endif
}
}
@@ -1261,10 +1374,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
free(ufds);
if(ret)
*ret = retcode;
- if(!extrawait || nfds)
- /* if any socket was checked */
- ;
- else {
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+ if(extrawait && !nfds && !use_wakeup) {
+#else
+ if(extrawait && !nfds) {
+#endif
long sleep_ms = 0;
/* Avoid busy-looping when there's nothing particular to wait for */
@@ -1313,6 +1427,10 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
return CURLM_BAD_HANDLE;
#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+ if(WSASetEvent(multi->wsa_event))
+ return CURLM_OK;
+#else
/* the wakeup_pair variable is only written during init and cleanup,
making it safe to access from another thread after the init part
and before cleanup */
@@ -1346,6 +1464,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
}
}
#endif
+#endif
return CURLM_WAKEUP_FAILURE;
}
@@ -1383,7 +1502,7 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
Curl_init_do(data, NULL);
/* take this handle to the perform state right away */
- multistate(data, CURLM_STATE_PERFORM);
+ multistate(data, MSTATE_PERFORMING);
Curl_attach_connnection(data, conn);
k->keepon |= KEEP_RECV; /* setup to receive! */
}
@@ -1397,7 +1516,6 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
DEBUGASSERT(conn);
DEBUGASSERT(conn->handler);
- DEBUGASSERT(conn->data == data);
if(conn->handler->do_it)
/* generic protocol-specific function pointer set in curl_connect() */
@@ -1429,6 +1547,58 @@ static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
}
/*
+ * Check whether a timeout occurred, and handle it if it did
+ */
+static bool multi_handle_timeout(struct Curl_easy *data,
+ struct curltime *now,
+ bool *stream_error,
+ CURLcode *result,
+ bool connect_timeout)
+{
+ timediff_t timeout_ms;
+ timeout_ms = Curl_timeleft(data, now, connect_timeout);
+
+ if(timeout_ms < 0) {
+ /* Handle timed out */
+ if(data->mstate == MSTATE_RESOLVING)
+ failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
+ else if(data->mstate == MSTATE_CONNECTING)
+ failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
+ else {
+ struct SingleRequest *k = &data->req;
+ if(k->size != -1) {
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount, k->size);
+ }
+ else {
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+ " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount);
+ }
+ }
+
+ /* Force connection closed if the connection has indeed been used */
+ if(data->mstate > MSTATE_DO) {
+ streamclose(data->conn, "Disconnected with pending data");
+ *stream_error = TRUE;
+ }
+ *result = CURLE_OPERATION_TIMEDOUT;
+ (void)multi_done(data, *result, TRUE);
+ }
+
+ return (timeout_ms < 0);
+}
+
+/*
* We are doing protocol-specific connecting and this is being called over and
* over from the multi interface until the connection phase is done on
* protocol layer.
@@ -1559,7 +1729,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
timediff_t recv_timeout_ms;
timediff_t send_timeout_ms;
int control;
@@ -1574,87 +1743,55 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_OK;
if(multi_ischanged(multi, TRUE)) {
- DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+ DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!"));
process_pending_handles(multi); /* multiplexed */
}
- if(data->mstate > CURLM_STATE_CONNECT &&
- data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate > MSTATE_CONNECT &&
+ data->mstate < MSTATE_COMPLETED) {
/* Make sure we set the connection's current owner */
DEBUGASSERT(data->conn);
if(!data->conn)
return CURLM_INTERNAL_ERROR;
- data->conn->data = data;
}
if(data->conn &&
- (data->mstate >= CURLM_STATE_CONNECT) &&
- (data->mstate < CURLM_STATE_COMPLETED)) {
+ (data->mstate >= MSTATE_CONNECT) &&
+ (data->mstate < MSTATE_COMPLETED)) {
+ /* Check for overall operation timeout here but defer handling the
+ * connection timeout to later, to allow for a connection to be set up
+ * in the window since we last checked timeout. This prevents us
+ * tearing down a completed connection in the case where we were slow
+ * to check the timeout (e.g. process descheduled during this loop).
+ * We set connect_timeout=FALSE to do this. */
+
/* we need to wait for the connect state as only then is the start time
stored, but we must not check already completed handles */
- timeout_ms = Curl_timeleft(data, nowp,
- (data->mstate <= CURLM_STATE_DO)?
- TRUE:FALSE);
-
- if(timeout_ms < 0) {
- /* Handle timed out */
- if(data->mstate == CURLM_STATE_WAITRESOLVE)
- failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*nowp, data->progress.t_startsingle));
- else if(data->mstate == CURLM_STATE_WAITCONNECT)
- failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds",
- Curl_timediff(*nowp, data->progress.t_startsingle));
- else {
- struct SingleRequest *k = &data->req;
- if(k->size != -1) {
- failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
- k->bytecount, k->size);
- }
- else {
- failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
- " milliseconds with %" CURL_FORMAT_CURL_OFF_T
- " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
- k->bytecount);
- }
- }
-
- /* Force connection closed if the connection has indeed been used */
- if(data->mstate > CURLM_STATE_DO) {
- streamclose(data->conn, "Disconnected with pending data");
- stream_error = TRUE;
- }
- result = CURLE_OPERATION_TIMEDOUT;
- (void)multi_done(data, result, TRUE);
+ if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
}
switch(data->mstate) {
- case CURLM_STATE_INIT:
+ case MSTATE_INIT:
/* init this transfer. */
result = Curl_pretransfer(data);
if(!result) {
/* after init, go CONNECT */
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
*nowp = Curl_pgrsTime(data, TIMER_STARTOP);
rc = CURLM_CALL_MULTI_PERFORM;
}
break;
- case CURLM_STATE_CONNECT_PEND:
+ case MSTATE_PENDING:
/* We will stay here until there is a connection available. Then
- we try again in the CURLM_STATE_CONNECT state. */
+ we try again in the MSTATE_CONNECT state. */
break;
- case CURLM_STATE_CONNECT:
+ case MSTATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. */
/* init this transfer. */
result = Curl_preconnect(data);
@@ -1672,7 +1809,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
- multistate(data, CURLM_STATE_CONNECT_PEND);
+ multistate(data, MSTATE_PENDING);
/* add this handle to the list of connect-pending handles */
Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
@@ -1682,14 +1819,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else if(data->state.previouslypending) {
/* this transfer comes from the pending queue so try move another */
- infof(data, "Transfer was pending, now try another\n");
+ infof(data, "Transfer was pending, now try another");
process_pending_handles(data->multi);
}
if(!result) {
if(async)
/* We're now waiting for an asynchronous name lookup */
- multistate(data, CURLM_STATE_WAITRESOLVE);
+ multistate(data, MSTATE_RESOLVING);
else {
/* after the connect has been sent off, go WAITCONNECT unless the
protocol connect is already done and we can go directly to
@@ -1697,20 +1834,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connected)
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
if(Curl_connect_ongoing(data->conn))
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ multistate(data, MSTATE_TUNNELING);
else
#endif
- multistate(data, CURLM_STATE_WAITCONNECT);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
break;
- case CURLM_STATE_WAITRESOLVE:
+ case MSTATE_RESOLVING:
/* awaiting an asynch name resolve to complete */
{
struct Curl_dns_entry *dns = NULL;
@@ -1737,7 +1874,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->state.async.done = TRUE;
#endif
result = CURLE_OK;
- infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
+ infof(data, "Hostname '%s' was found in DNS cache", hostname);
}
if(!dns)
@@ -1764,14 +1901,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
if(protocol_connected)
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
if(Curl_connect_ongoing(data->conn))
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ multistate(data, MSTATE_TUNNELING);
else
#endif
- multistate(data, CURLM_STATE_WAITCONNECT);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
@@ -1785,7 +1922,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
#ifndef CURL_DISABLE_HTTP
- case CURLM_STATE_WAITPROXYCONNECT:
+ case MSTATE_TUNNELING:
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
DEBUGASSERT(data->conn);
result = Curl_http_connect(data, &protocol_connected);
@@ -1795,7 +1932,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* connect back to proxy again */
result = CURLE_OK;
multi_done(data, CURLE_OK, FALSE);
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
}
else
#endif
@@ -1808,7 +1945,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_connect_complete(data->conn)) {
rc = CURLM_CALL_MULTI_PERFORM;
/* initiate protocol connect phase */
- multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ multistate(data, MSTATE_PROTOCONNECT);
}
}
else
@@ -1816,7 +1953,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
#endif
- case CURLM_STATE_WAITCONNECT:
+ case MSTATE_CONNECTING:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
@@ -1828,7 +1965,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
!data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
#endif
Curl_connect_ongoing(data->conn)) {
- multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ multistate(data, MSTATE_TUNNELING);
break;
}
#endif
@@ -1836,10 +1973,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_PROXY
multistate(data,
data->conn->bits.tunnel_proxy?
- CURLM_STATE_WAITPROXYCONNECT:
- CURLM_STATE_SENDPROTOCONNECT);
+ MSTATE_TUNNELING : MSTATE_PROTOCONNECT);
#else
- multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ multistate(data, MSTATE_PROTOCONNECT);
#endif
}
else if(result) {
@@ -1851,14 +1987,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_SENDPROTOCONNECT:
+ case MSTATE_PROTOCONNECT:
result = protocol_connect(data, &protocol_connected);
if(!result && !protocol_connected)
/* switch to waiting state */
- multistate(data, CURLM_STATE_PROTOCONNECT);
+ multistate(data, MSTATE_PROTOCONNECTING);
else if(!result) {
/* protocol connect has completed, go WAITDO or DO */
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else {
@@ -1869,12 +2005,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_PROTOCONNECT:
+ case MSTATE_PROTOCONNECTING:
/* protocol-specific connect phase */
result = protocol_connecting(data, &protocol_connected);
if(!result && protocol_connected) {
/* after the connect has completed, go WAITDO or DO */
- multistate(data, CURLM_STATE_DO);
+ multistate(data, MSTATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
}
else if(result) {
@@ -1885,11 +2021,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DO:
+ case MSTATE_DO:
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
connkeep(data->conn, "CONNECT_ONLY");
- multistate(data, CURLM_STATE_DONE);
+ multistate(data, MSTATE_DONE);
result = CURLE_OK;
rc = CURLM_CALL_MULTI_PERFORM;
}
@@ -1911,7 +2047,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* if there's no connection left, skip the DONE state */
multistate(data, data->conn ?
- CURLM_STATE_DONE : CURLM_STATE_COMPLETED);
+ MSTATE_DONE : MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
break;
}
@@ -1919,7 +2055,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#endif
/* DO was not completed in one function call, we must continue
DOING... */
- multistate(data, CURLM_STATE_DOING);
+ multistate(data, MSTATE_DOING);
rc = CURLM_OK;
}
@@ -1927,12 +2063,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(data->conn->bits.do_more) {
/* we're supposed to do more, but we need to sit down, relax
and wait a little while first */
- multistate(data, CURLM_STATE_DO_MORE);
+ multistate(data, MSTATE_DOING_MORE);
rc = CURLM_OK;
}
else {
- /* we're done with the DO, now DO_DONE */
- multistate(data, CURLM_STATE_DO_DONE);
+ /* we're done with the DO, now DID */
+ multistate(data, MSTATE_DID);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
@@ -1964,7 +2100,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
if(!drc) {
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
rc = CURLM_CALL_MULTI_PERFORM;
result = CURLE_OK;
}
@@ -1994,7 +2130,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DOING:
+ case MSTATE_DOING:
/* we continue DOING until the DO phase is complete */
DEBUGASSERT(data->conn);
result = protocol_doing(data, &dophase_done);
@@ -2002,8 +2138,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dophase_done) {
/* after DO, go DO_DONE or DO_MORE */
multistate(data, data->conn->bits.do_more?
- CURLM_STATE_DO_MORE:
- CURLM_STATE_DO_DONE);
+ MSTATE_DOING_MORE : MSTATE_DID);
rc = CURLM_CALL_MULTI_PERFORM;
} /* dophase_done */
}
@@ -2015,9 +2150,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DO_MORE:
+ case MSTATE_DOING_MORE:
/*
- * When we are connected, DO MORE and then go DO_DONE
+ * When we are connected, DOING MORE and then go DID
*/
DEBUGASSERT(data->conn);
result = multi_do_more(data, &control);
@@ -2027,8 +2162,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* if positive, advance to DO_DONE
if negative, go back to DOING */
multistate(data, control == 1?
- CURLM_STATE_DO_DONE:
- CURLM_STATE_DOING);
+ MSTATE_DID : MSTATE_DOING);
rc = CURLM_CALL_MULTI_PERFORM;
}
else
@@ -2043,7 +2177,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_DO_DONE:
+ case MSTATE_DID:
DEBUGASSERT(data->conn);
if(data->conn->bits.multiplex)
/* Check if we can move pending requests to send pipe */
@@ -2053,7 +2187,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Having both BAD is a signal to skip immediately to DONE */
if((data->conn->sockfd != CURL_SOCKET_BAD) ||
(data->conn->writesockfd != CURL_SOCKET_BAD))
- multistate(data, CURLM_STATE_PERFORM);
+ multistate(data, MSTATE_PERFORMING);
else {
#ifndef CURL_DISABLE_FTP
if(data->state.wildcardmatch &&
@@ -2061,12 +2195,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->wildcard.state = CURLWC_DONE;
}
#endif
- multistate(data, CURLM_STATE_DONE);
+ multistate(data, MSTATE_DONE);
}
rc = CURLM_CALL_MULTI_PERFORM;
break;
- case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
+ case MSTATE_RATELIMITING: /* limit-rate exceeded in either direction */
DEBUGASSERT(data->conn);
/* if both rates are within spec, resume transfer */
if(Curl_pgrsUpdate(data))
@@ -2084,7 +2218,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else {
send_timeout_ms = 0;
- if(data->set.max_send_speed > 0)
+ if(data->set.max_send_speed)
send_timeout_ms =
Curl_pgrsLimitWaitTime(data->progress.uploaded,
data->progress.ul_limit_size,
@@ -2093,7 +2227,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
*nowp);
recv_timeout_ms = 0;
- if(data->set.max_recv_speed > 0)
+ if(data->set.max_recv_speed)
recv_timeout_ms =
Curl_pgrsLimitWaitTime(data->progress.downloaded,
data->progress.dl_limit_size,
@@ -2102,7 +2236,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
*nowp);
if(!send_timeout_ms && !recv_timeout_ms) {
- multistate(data, CURLM_STATE_PERFORM);
+ multistate(data, MSTATE_PERFORMING);
Curl_ratelimit(data, *nowp);
}
else if(send_timeout_ms >= recv_timeout_ms)
@@ -2112,7 +2246,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
break;
- case CURLM_STATE_PERFORM:
+ case MSTATE_PERFORMING:
{
char *newurl = NULL;
bool retry = FALSE;
@@ -2120,7 +2254,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
- if(data->set.max_send_speed > 0)
+ if(data->set.max_send_speed)
send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
data->progress.ul_limit_size,
data->set.max_send_speed,
@@ -2129,7 +2263,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* check if over recv speed */
recv_timeout_ms = 0;
- if(data->set.max_recv_speed > 0)
+ if(data->set.max_recv_speed)
recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
data->progress.dl_limit_size,
data->set.max_recv_speed,
@@ -2138,7 +2272,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(send_timeout_ms || recv_timeout_ms) {
Curl_ratelimit(data, *nowp);
- multistate(data, CURLM_STATE_TOOFAST);
+ multistate(data, MSTATE_RATELIMITING);
if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
else
@@ -2168,17 +2302,18 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else if((CURLE_HTTP2_STREAM == result) &&
- Curl_h2_http_1_1_error(data->conn)) {
+ Curl_h2_http_1_1_error(data)) {
CURLcode ret = Curl_retry_request(data, &newurl);
if(!ret) {
- infof(data, "Downgrades to HTTP/1.1!\n");
- data->set.httpversion = CURL_HTTP_VERSION_1_1;
+ infof(data, "Downgrades to HTTP/1.1!");
+ streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
+ data->state.httpwant = CURL_HTTP_VERSION_1_1;
/* clear the error message bit too as we ignore the one we got */
data->state.errorbuf = FALSE;
if(!newurl)
/* typically for HTTP_1_1_REQUIRED error on first flight */
- newurl = strdup(data->change.url);
+ newurl = strdup(data->state.url);
/* if we are to retry, set the result to OK and consider the request
as done */
retry = TRUE;
@@ -2228,7 +2363,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* multi_done() might return CURLE_GOT_NOTHING */
result = Curl_follow(data, newurl, follow);
if(!result) {
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
rc = CURLM_CALL_MULTI_PERFORM;
}
free(newurl);
@@ -2251,7 +2386,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!result) {
- multistate(data, CURLM_STATE_DONE);
+ multistate(data, MSTATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
@@ -2266,7 +2401,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
}
- case CURLM_STATE_DONE:
+ case MSTATE_DONE:
/* this state is highly transient, so run another loop after this */
rc = CURLM_CALL_MULTI_PERFORM;
@@ -2289,30 +2424,45 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->state.wildcardmatch) {
if(data->wildcard.state != CURLWC_DONE) {
/* if a wildcard is set and we are not ending -> lets start again
- with CURLM_STATE_INIT */
- multistate(data, CURLM_STATE_INIT);
+ with MSTATE_INIT */
+ multistate(data, MSTATE_INIT);
break;
}
}
#endif
/* after we have DONE what we're supposed to do, go COMPLETED, and
it doesn't matter what the multi_done() returned! */
- multistate(data, CURLM_STATE_COMPLETED);
+ multistate(data, MSTATE_COMPLETED);
break;
- case CURLM_STATE_COMPLETED:
+ case MSTATE_COMPLETED:
break;
- case CURLM_STATE_MSGSENT:
+ case MSTATE_MSGSENT:
data->result = result;
return CURLM_OK; /* do nothing */
default:
return CURLM_INTERNAL_ERROR;
}
+
+ if(data->conn &&
+ data->mstate >= MSTATE_CONNECT &&
+ data->mstate < MSTATE_DO &&
+ rc != CURLM_CALL_MULTI_PERFORM &&
+ !multi_ischanged(multi, false)) {
+ /* We now handle stream timeouts if and only if this will be the last
+ * loop iteration. We only check this on the last iteration to ensure
+ * that if we know we have additional work to do immediately
+ * (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
+ * declaring the connection timed out as we may almost have a completed
+ * connection. */
+ multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
+ }
+
statemachine_end:
- if(data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate < MSTATE_COMPLETED) {
if(result) {
/*
* If an error was returned, and we aren't in completed state now,
@@ -2343,12 +2493,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_disconnect(data, conn, dead_connection);
}
}
- else if(data->mstate == CURLM_STATE_CONNECT) {
+ else if(data->mstate == MSTATE_CONNECT) {
/* Curl_connect() failed */
(void)Curl_posttransfer(data);
}
- multistate(data, CURLM_STATE_COMPLETED);
+ multistate(data, MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
}
/* if there's still a connection to use, call the progress function */
@@ -2359,13 +2509,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
streamclose(data->conn, "Aborted by callback");
/* if not yet in DONE state, go there, otherwise COMPLETED */
- multistate(data, (data->mstate < CURLM_STATE_DONE)?
- CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
+ multistate(data, (data->mstate < MSTATE_DONE)?
+ MSTATE_DONE: MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
- if(CURLM_STATE_COMPLETED == data->mstate) {
+ if(MSTATE_COMPLETED == data->mstate) {
if(data->set.fmultidone) {
/* signal via callback instead */
data->set.fmultidone(data, result);
@@ -2381,7 +2531,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = multi_addmsg(multi, msg);
DEBUGASSERT(!data->conn);
}
- multistate(data, CURLM_STATE_MSGSENT);
+ multistate(data, MSTATE_MSGSENT);
}
} while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
@@ -2492,10 +2642,14 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
+#ifdef USE_WINSOCK
+ WSACloseEvent(multi->wsa_event);
+#else
#ifdef ENABLE_WAKEUP
sclose(multi->wakeup_pair[0]);
sclose(multi->wakeup_pair[1]);
#endif
+#endif
free(multi);
return CURLM_OK;
@@ -2554,7 +2708,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
curl_socket_t s;
int num;
unsigned int curraction;
- int actions[MAX_SOCKSPEREASYHANDLE];
+ unsigned char actions[MAX_SOCKSPEREASYHANDLE];
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
socks[i] = CURL_SOCKET_BAD;
@@ -2571,9 +2725,9 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
(curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
i++) {
- unsigned int action = CURL_POLL_NONE;
- unsigned int prevaction = 0;
- unsigned int comboaction;
+ unsigned char action = CURL_POLL_NONE;
+ unsigned char prevaction = 0;
+ int comboaction;
bool sincebefore = FALSE;
s = socks[i];
@@ -2631,10 +2785,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
}
comboaction = (entry->writers? CURL_POLL_OUT : 0) |
- (entry->readers ? CURL_POLL_IN : 0);
+ (entry->readers ? CURL_POLL_IN : 0);
/* socket existed before and has the same action set as before */
- if(sincebefore && (entry->action == comboaction))
+ if(sincebefore && ((int)entry->action == comboaction))
/* same, continue */
continue;
@@ -2667,7 +2821,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
/* if this is NULL here, the socket has been closed and notified so
already by Curl_multi_closed() */
if(entry) {
- int oldactions = data->actions[i];
+ unsigned char oldactions = data->actions[i];
/* this socket has been removed. Decrease user count */
entry->users--;
if(oldactions & CURL_POLL_OUT)
@@ -2692,7 +2846,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
} /* for loop over numsocks */
memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
- memcpy(data->actions, actions, num*sizeof(int));
+ memcpy(data->actions, actions, num*sizeof(char));
data->numsocks = num;
return CURLM_OK;
}
@@ -3227,7 +3381,7 @@ void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
rc = Curl_splayremove(multi->timetree, &data->state.timenode,
&multi->timetree);
if(rc)
- infof(data, "Internal error removing splay node = %d\n", rc);
+ infof(data, "Internal error removing splay node = %d", rc);
}
/* Indicate that we are in the splay tree and insert the new timer expiry
@@ -3274,7 +3428,7 @@ void Curl_expire_clear(struct Curl_easy *data)
rc = Curl_splayremove(multi->timetree, &data->state.timenode,
&multi->timetree);
if(rc)
- infof(data, "Internal error clearing splay node = %d\n", rc);
+ infof(data, "Internal error clearing splay node = %d", rc);
/* flush the timeout list too */
while(list->size > 0) {
@@ -3282,7 +3436,7 @@ void Curl_expire_clear(struct Curl_easy *data)
}
#ifdef DEBUGBUILD
- infof(data, "Expire cleared (transfer %p)\n", data);
+ infof(data, "Expire cleared (transfer %p)", data);
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;
@@ -3344,9 +3498,9 @@ static void process_pending_handles(struct Curl_multi *multi)
if(e) {
struct Curl_easy *data = e->ptr;
- DEBUGASSERT(data->mstate == CURLM_STATE_CONNECT_PEND);
+ DEBUGASSERT(data->mstate == MSTATE_PENDING);
- multistate(data, CURLM_STATE_CONNECT);
+ multistate(data, MSTATE_CONNECT);
/* Remove this node from the list */
Curl_llist_remove(&multi->pending, e, NULL);
@@ -3384,7 +3538,7 @@ void Curl_multi_dump(struct Curl_multi *multi)
fprintf(stderr, "* Multi status: %d handles, %d alive\n",
multi->num_easy, multi->num_alive);
for(data = multi->easyp; data; data = data->next) {
- if(data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->mstate < MSTATE_COMPLETED) {
/* only display handles that are not completed */
fprintf(stderr, "handle %p, state %s, %d sockets\n",
(void *)data,
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
index f28c589..2e4a6ff 100644
--- a/Utilities/cmcurl/lib/multihandle.h
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -40,27 +40,26 @@ struct Curl_message {
well!
*/
typedef enum {
- CURLM_STATE_INIT, /* 0 - start in this state */
- CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */
- CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */
- CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */
- CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */
- CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization
- to complete and/or proxy CONNECT to
- finalize */
- CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */
- CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect
- phase */
- CURLM_STATE_DO, /* 8 - start send off the request (part 1) */
- CURLM_STATE_DOING, /* 9 - sending off the request (part 1) */
- CURLM_STATE_DO_MORE, /* 10 - send off the request (part 2) */
- CURLM_STATE_DO_DONE, /* 11 - done sending off request */
- CURLM_STATE_PERFORM, /* 12 - transfer data */
- CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */
- CURLM_STATE_DONE, /* 14 - post data transfer operation */
- CURLM_STATE_COMPLETED, /* 15 - operation complete */
- CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */
- CURLM_STATE_LAST /* 17 - not a true state, never use this */
+ MSTATE_INIT, /* 0 - start in this state */
+ MSTATE_PENDING, /* 1 - no connections, waiting for one */
+ MSTATE_CONNECT, /* 2 - resolve/connect has been sent off */
+ MSTATE_RESOLVING, /* 3 - awaiting the resolve to finalize */
+ MSTATE_CONNECTING, /* 4 - awaiting the TCP connect to finalize */
+ MSTATE_TUNNELING, /* 5 - awaiting HTTPS proxy SSL initialization to
+ complete and/or proxy CONNECT to finalize */
+ MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */
+ MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect
+ phase */
+ MSTATE_DO, /* 8 - start send off the request (part 1) */
+ MSTATE_DOING, /* 9 - sending off the request (part 1) */
+ MSTATE_DOING_MORE, /* 10 - send off the request (part 2) */
+ MSTATE_DID, /* 11 - done sending off request */
+ MSTATE_PERFORMING, /* 12 - transfer data */
+ MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */
+ MSTATE_DONE, /* 14 - post data transfer operation */
+ MSTATE_COMPLETED, /* 15 - operation complete */
+ MSTATE_MSGSENT, /* 16 - the operation complete message is sent */
+ MSTATE_LAST /* 17 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
@@ -71,8 +70,7 @@ typedef enum {
#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
-#if defined(USE_SOCKETPAIR) && !defined(USE_BLOCKING_SOCKETS) && \
- !defined(CURL_DISABLE_SOCKETPAIR)
+#if !defined(CURL_DISABLE_SOCKETPAIR)
#define ENABLE_WAKEUP
#endif
@@ -96,7 +94,7 @@ struct Curl_multi {
struct Curl_llist msglist; /* a list of messages from completed transfers */
struct Curl_llist pending; /* Curl_easys that are in the
- CURLM_STATE_CONNECT_PEND state */
+ MSTATE_PENDING state */
/* callback function and user data pointer for the *socket() API */
curl_socket_callback socket_cb;
@@ -142,15 +140,22 @@ struct Curl_multi {
previous callback */
unsigned int max_concurrent_streams;
+#ifdef USE_WINSOCK
+ WSAEVENT wsa_event; /* winsock event used for waits */
+#else
#ifdef ENABLE_WAKEUP
curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
0 is used for read, 1 is used for write */
#endif
+#endif
/* multiplexing wanted */
bool multiplexing;
bool recheckstate; /* see Curl_multi_connchanged */
bool in_callback; /* true while executing a callback */
bool ipv6_works;
+#ifdef USE_OPENSSL
+ bool ssl_seeded;
+#endif
};
#endif /* HEADER_CURL_MULTIHANDLE_H */
diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c
index 13610bb..0a4ae2c 100644
--- a/Utilities/cmcurl/lib/netrc.c
+++ b/Utilities/cmcurl/lib/netrc.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
@@ -42,7 +42,8 @@
enum host_lookup_state {
NOTHING,
HOSTFOUND, /* the 'machine' keyword was found */
- HOSTVALID /* this is "our" machine! */
+ HOSTVALID, /* this is "our" machine! */
+ MACDEF
};
#define NETRC_FILE_MISSING 1
@@ -84,12 +85,17 @@ static int parsenetrc(const char *host,
int netrcbuffsize = (int)sizeof(netrcbuffer);
while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
+ if(state == MACDEF) {
+ if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
+ state = NOTHING;
+ else
+ continue;
+ }
tok = strtok_r(netrcbuffer, " \t\n", &tok_buf);
if(tok && *tok == '#')
/* treat an initial hash as a comment line */
continue;
while(tok) {
-
if((login && *login) && (password && *password)) {
done = TRUE;
break;
@@ -97,7 +103,13 @@ static int parsenetrc(const char *host,
switch(state) {
case NOTHING:
- if(strcasecompare("machine", tok)) {
+ if(strcasecompare("macdef", tok)) {
+ /* Define a macro. A macro is defined with the specified name; its
+ contents begin with the next .netrc line and continue until a
+ null line (consecutive new-line characters) is encountered. */
+ state = MACDEF;
+ }
+ else if(strcasecompare("machine", tok)) {
/* the next tok is the machine name, this is in itself the
delimiter that starts the stuff entered for this machine,
after this we need to search for 'login' and
@@ -109,6 +121,11 @@ static int parsenetrc(const char *host,
retcode = NETRC_SUCCESS; /* we did find our host */
}
break;
+ case MACDEF:
+ if(!strlen(tok)) {
+ state = NOTHING;
+ }
+ break;
case HOSTFOUND:
if(strcasecompare(host, tok)) {
/* and yes, this is our host! */
diff --git a/Utilities/cmcurl/lib/non-ascii.c b/Utilities/cmcurl/lib/non-ascii.c
index 30c240b..3b77ae9 100644
--- a/Utilities/cmcurl/lib/non-ascii.c
+++ b/Utilities/cmcurl/lib/non-ascii.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
@@ -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;
}
}
@@ -127,10 +129,10 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
&output_ptr, &out_bytes);
if(!data)
iconv_close(tmpcd);
- if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ 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;
}
}
@@ -193,10 +196,10 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
&output_ptr, &out_bytes);
if(!data)
iconv_close(tmpcd);
- if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ 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;
}
}
@@ -260,10 +264,10 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
&output_ptr, &out_bytes);
if(!data)
iconv_close(tmpcd);
- if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ 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/Utilities/cmcurl/lib/nonblock.c b/Utilities/cmcurl/lib/nonblock.c
index 4a7bde5..fda2e9a 100644
--- a/Utilities/cmcurl/lib/nonblock.c
+++ b/Utilities/cmcurl/lib/nonblock.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
@@ -47,13 +47,7 @@
int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */)
{
-#if defined(USE_BLOCKING_SOCKETS)
- (void)sockfd;
- (void)nonblock;
- return 0; /* returns success */
-
-#elif defined(HAVE_FCNTL_O_NONBLOCK)
-
+#if defined(HAVE_FCNTL_O_NONBLOCK)
/* most recent unix versions */
int flags;
flags = sfcntl(sockfd, F_GETFL, 0);
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
index 4070bbf..fb5e743 100644
--- a/Utilities/cmcurl/lib/openldap.c
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -76,16 +76,16 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
LDAP **ld);
#endif
-static CURLcode ldap_setup_connection(struct Curl_easy *data,
- struct connectdata *conn);
-static CURLcode ldap_do(struct Curl_easy *data, bool *done);
-static CURLcode ldap_done(struct Curl_easy *data, CURLcode, bool);
-static CURLcode ldap_connect(struct Curl_easy *data, bool *done);
-static CURLcode ldap_connecting(struct Curl_easy *data, bool *done);
-static CURLcode ldap_disconnect(struct Curl_easy *data,
- struct connectdata *conn, bool dead);
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+ struct connectdata *conn);
+static CURLcode oldap_do(struct Curl_easy *data, bool *done);
+static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done);
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
+static CURLcode oldap_disconnect(struct Curl_easy *data,
+ struct connectdata *conn, bool dead);
-static Curl_recv ldap_recv;
+static Curl_recv oldap_recv;
/*
* LDAP protocol handler.
@@ -93,20 +93,21 @@ static Curl_recv ldap_recv;
const struct Curl_handler Curl_handler_ldap = {
"LDAP", /* scheme */
- ldap_setup_connection, /* setup_connection */
- ldap_do, /* do_it */
- ldap_done, /* done */
+ oldap_setup_connection, /* setup_connection */
+ oldap_do, /* do_it */
+ oldap_done, /* done */
ZERO_NULL, /* do_more */
- ldap_connect, /* connect_it */
- ldap_connecting, /* connecting */
+ oldap_connect, /* connect_it */
+ oldap_connecting, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
- ldap_disconnect, /* disconnect */
+ oldap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
CURLPROTO_LDAP, /* protocol */
CURLPROTO_LDAP, /* family */
@@ -120,20 +121,21 @@ const struct Curl_handler Curl_handler_ldap = {
const struct Curl_handler Curl_handler_ldaps = {
"LDAPS", /* scheme */
- ldap_setup_connection, /* setup_connection */
- ldap_do, /* do_it */
- ldap_done, /* done */
+ oldap_setup_connection, /* setup_connection */
+ oldap_do, /* do_it */
+ oldap_done, /* done */
ZERO_NULL, /* do_more */
- ldap_connect, /* connect_it */
- ldap_connecting, /* connecting */
+ oldap_connect, /* connect_it */
+ oldap_connecting, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
- ldap_disconnect, /* disconnect */
+ oldap_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
CURLPROTO_LDAPS, /* protocol */
CURLPROTO_LDAP, /* family */
@@ -171,15 +173,15 @@ struct ldapreqinfo {
int nument;
};
-static CURLcode ldap_setup_connection(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+ struct connectdata *conn)
{
struct ldapconninfo *li;
LDAPURLDesc *lud;
int rc, proto;
CURLcode status;
- rc = ldap_url_parse(data->change.url, &lud);
+ rc = ldap_url_parse(data->state.url, &lud);
if(rc != LDAP_URL_SUCCESS) {
const char *msg = "url parsing problem";
status = CURLE_URL_MALFORMAT;
@@ -207,7 +209,7 @@ static CURLcode ldap_setup_connection(struct Curl_easy *data,
static Sockbuf_IO ldapsb_tls;
#endif
-static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
@@ -245,7 +247,7 @@ static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
#ifdef USE_SSL
if(conn->handler->flags & PROTOPT_SSL) {
CURLcode result;
- result = Curl_ssl_connect_nonblocking(data, conn,
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
FIRSTSOCKET, &li->ssldone);
if(result)
return result;
@@ -255,7 +257,7 @@ static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
return CURLE_OK;
}
-static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
@@ -268,7 +270,8 @@ static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
if(conn->handler->flags & PROTOPT_SSL) {
/* Is the SSL handshake complete yet? */
if(!li->ssldone) {
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
+ CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+ FIRSTSOCKET,
&li->ssldone);
if(result || !li->ssldone)
return result;
@@ -278,7 +281,7 @@ static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
if(!li->sslinst) {
Sockbuf *sb;
ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
- ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
li->sslinst = TRUE;
li->recv = conn->recv[FIRSTSOCKET];
li->send = conn->send[FIRSTSOCKET];
@@ -354,21 +357,28 @@ static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
if(info)
ldap_memfree(info);
- conn->recv[FIRSTSOCKET] = ldap_recv;
+ conn->recv[FIRSTSOCKET] = oldap_recv;
*done = TRUE;
return CURLE_OK;
}
-static CURLcode ldap_disconnect(struct Curl_easy *data,
- struct connectdata *conn, bool dead_connection)
+static CURLcode oldap_disconnect(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool dead_connection)
{
struct ldapconninfo *li = conn->proto.ldapc;
(void) dead_connection;
- (void) data;
if(li) {
if(li->ld) {
+#ifdef USE_SSL
+ if(conn->ssl[FIRSTSOCKET].use) {
+ Sockbuf *sb;
+ ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+ }
+#endif
ldap_unbind_ext(li->ld, NULL, NULL);
li->ld = NULL;
}
@@ -378,7 +388,7 @@ static CURLcode ldap_disconnect(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode ldap_do(struct Curl_easy *data, bool *done)
+static CURLcode oldap_do(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
@@ -390,9 +400,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
connkeep(conn, "OpenLDAP do");
- infof(data, "LDAP local: %s\n", data->change.url);
+ infof(data, "LDAP local: %s", data->state.url);
- rc = ldap_url_parse(data->change.url, &ludp);
+ rc = ldap_url_parse(data->state.url, &ludp);
if(rc != LDAP_URL_SUCCESS) {
const char *msg = "url parsing problem";
status = CURLE_URL_MALFORMAT;
@@ -423,8 +433,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
return CURLE_OK;
}
-static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
- bool premature)
+static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
+ bool premature)
{
struct connectdata *conn = data->conn;
struct ldapreqinfo *lr = data->req.p.ldap;
@@ -446,8 +456,8 @@ static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
return CURLE_OK;
}
-static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
- size_t len, CURLcode *err)
+static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
+ size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
@@ -500,7 +510,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
else {
/* successful */
if(code == LDAP_SIZELIMIT_EXCEEDED)
- infof(data, "There are more than %d entries\n", lr->nument);
+ infof(data, "There are more than %d entries", lr->nument);
data->req.size = data->req.bytecount;
*err = CURLE_OK;
ret = 0;
@@ -543,7 +553,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
int i;
- if(bv.bv_val == NULL)
+ if(!bv.bv_val)
break;
if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
@@ -551,7 +561,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
else
binary = 0;
- if(bvals == NULL) {
+ if(!bvals) {
writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
if(writeerr) {
*err = writeerr;
@@ -660,7 +670,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
data->req.bytecount += bvals[i].bv_len + 1;
}
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
if(writeerr) {
*err = writeerr;
return -1;
@@ -669,14 +679,14 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
data->req.bytecount++;
}
ber_memfree(bvals);
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
if(writeerr) {
*err = writeerr;
return -1;
}
data->req.bytecount++;
}
- writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
if(writeerr) {
*err = writeerr;
return -1;
@@ -716,8 +726,8 @@ ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
{
(void)arg;
if(opt == LBER_SB_OPT_DATA_READY) {
- struct connectdata *conn = sbiod->sbiod_pvt;
- return Curl_ssl_data_pending(conn, FIRSTSOCKET);
+ struct Curl_easy *data = sbiod->sbiod_pvt;
+ return Curl_ssl_data_pending(data->conn, FIRSTSOCKET);
}
return 0;
}
@@ -725,14 +735,19 @@ ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
static ber_slen_t
ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
- struct connectdata *conn = sbiod->sbiod_pvt;
- struct ldapconninfo *li = conn->proto.ldapc;
- ber_slen_t ret;
- CURLcode err = CURLE_RECV_ERROR;
+ struct Curl_easy *data = sbiod->sbiod_pvt;
+ ber_slen_t ret = 0;
+ if(data) {
+ struct connectdata *conn = data->conn;
+ if(conn) {
+ struct ldapconninfo *li = conn->proto.ldapc;
+ CURLcode err = CURLE_RECV_ERROR;
- ret = (li->recv)(conn->data, FIRSTSOCKET, buf, len, &err);
- if(ret < 0 && err == CURLE_AGAIN) {
- SET_SOCKERRNO(EWOULDBLOCK);
+ ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
+ if(ret < 0 && err == CURLE_AGAIN) {
+ SET_SOCKERRNO(EWOULDBLOCK);
+ }
+ }
}
return ret;
}
@@ -740,14 +755,18 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
static ber_slen_t
ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
- struct connectdata *conn = sbiod->sbiod_pvt;
- struct ldapconninfo *li = conn->proto.ldapc;
- ber_slen_t ret;
- CURLcode err = CURLE_SEND_ERROR;
-
- ret = (li->send)(conn->data, FIRSTSOCKET, buf, len, &err);
- if(ret < 0 && err == CURLE_AGAIN) {
- SET_SOCKERRNO(EWOULDBLOCK);
+ struct Curl_easy *data = sbiod->sbiod_pvt;
+ ber_slen_t ret = 0;
+ if(data) {
+ struct connectdata *conn = data->conn;
+ if(conn) {
+ struct ldapconninfo *li = conn->proto.ldapc;
+ CURLcode err = CURLE_SEND_ERROR;
+ ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
+ if(ret < 0 && err == CURLE_AGAIN) {
+ SET_SOCKERRNO(EWOULDBLOCK);
+ }
+ }
}
return ret;
}
diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c
index 4811739..84c7f51 100644
--- a/Utilities/cmcurl/lib/pingpong.c
+++ b/Utilities/cmcurl/lib/pingpong.c
@@ -402,7 +402,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
clipamount = gotbytes - i;
restart = TRUE;
DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
- "server response left\n",
+ "server response left",
(int)clipamount));
}
else if(keepon) {
@@ -412,7 +412,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
with it. We keep the first bytes of the line then we throw
away the rest. */
infof(data, "Excessive server response line length received, "
- "%zd bytes. Stripping\n", gotbytes);
+ "%zd bytes. Stripping", gotbytes);
restart = TRUE;
/* we keep 40 bytes since all our pingpong protocols are only
diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h
index 4f7d7ea..8f56f3f 100644
--- a/Utilities/cmcurl/lib/pingpong.h
+++ b/Utilities/cmcurl/lib/pingpong.h
@@ -33,10 +33,9 @@
struct connectdata;
typedef enum {
- FTPTRANSFER_BODY, /* yes do transfer a body */
- FTPTRANSFER_INFO, /* do still go through to get info/headers */
- FTPTRANSFER_NONE, /* don't get anything and don't get info */
- FTPTRANSFER_LAST /* end of list marker, never used */
+ PPTRANSFER_BODY, /* yes do transfer a body */
+ PPTRANSFER_INFO, /* do still go through to get info/headers */
+ PPTRANSFER_NONE /* don't get anything and don't get info */
} curl_pp_transfer;
/*
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
index 0ed3d3e..d3f3de6 100644
--- a/Utilities/cmcurl/lib/pop3.c
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -75,7 +75,6 @@
#include "strcase.h"
#include "vtls/vtls.h"
#include "connect.h"
-#include "strerror.h"
#include "select.h"
#include "multiif.h"
#include "url.h"
@@ -131,6 +130,7 @@ const struct Curl_handler Curl_handler_pop3 = {
pop3_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_POP3, /* defport */
CURLPROTO_POP3, /* protocol */
CURLPROTO_POP3, /* family */
@@ -159,6 +159,7 @@ const struct Curl_handler Curl_handler_pop3s = {
pop3_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_POP3S, /* defport */
CURLPROTO_POP3S, /* protocol */
CURLPROTO_POP3, /* family */
@@ -306,7 +307,7 @@ static void state(struct Curl_easy *data, pop3state newstate)
};
if(pop3c->state != newstate)
- infof(data, "POP3 %p state change from %s to %s\n",
+ infof(data, "POP3 %p state change from %s to %s",
(void *)pop3c, names[pop3c->state], names[newstate]);
#endif
@@ -368,8 +369,9 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
{
/* Start the SSL connection */
struct pop3_conn *pop3c = &conn->proto.pop3c;
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
- &pop3c->ssldone);
+ CURLcode result =
+ Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET,
+ &pop3c->ssldone);
if(!result) {
if(pop3c->state != POP3_UPGRADETLS)
@@ -549,7 +551,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
result = pop3_perform_user(data, conn);
else {
/* Other mechanisms not supported */
- infof(data, "No known authentication mechanisms supported!\n");
+ infof(data, "No known authentication mechanisms supported!");
result = CURLE_LOGIN_DENIED;
}
}
@@ -571,12 +573,12 @@ static CURLcode pop3_perform_command(struct Curl_easy *data)
const char *command = NULL;
/* Calculate the default command */
- if(pop3->id[0] == '\0' || data->set.ftp_list_only) {
+ if(pop3->id[0] == '\0' || data->set.list_only) {
command = "LIST";
if(pop3->id[0] != '\0')
/* Message specific LIST so skip the BODY transfer */
- pop3->transfer = FTPTRANSFER_INFO;
+ pop3->transfer = PPTRANSFER_INFO;
}
else
command = "RETR";
@@ -709,7 +711,7 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
for(;;) {
size_t llen;
size_t wordlen;
- unsigned int mechbit;
+ unsigned short mechbit;
while(len &&
(*line == ' ' || *line == '\t' ||
@@ -738,28 +740,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;
@@ -774,6 +771,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");
@@ -916,7 +917,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
the strip counter here so that these bytes won't be delivered. */
pop3c->strip = 2;
- if(pop3->transfer == FTPTRANSFER_BODY) {
+ if(pop3->transfer == PPTRANSFER_BODY) {
/* POP3 download */
Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
@@ -1029,7 +1030,7 @@ static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done)
struct pop3_conn *pop3c = &conn->proto.pop3c;
if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
- result = Curl_ssl_connect_nonblocking(data, conn,
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
FIRSTSOCKET, &pop3c->ssldone);
if(result || !pop3c->ssldone)
return result;
@@ -1150,7 +1151,7 @@ static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
Curl_safefree(pop3->custom);
/* Clear the transfer mode for the next request */
- pop3->transfer = FTPTRANSFER_BODY;
+ pop3->transfer = PPTRANSFER_BODY;
return result;
}
@@ -1170,11 +1171,11 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
struct connectdata *conn = data->conn;
struct POP3 *pop3 = data->req.p.pop3;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
if(data->set.opt_no_body) {
/* Requested no body means no transfer */
- pop3->transfer = FTPTRANSFER_INFO;
+ pop3->transfer = PPTRANSFER_INFO;
}
*dophase_done = FALSE; /* not done yet */
@@ -1189,7 +1190,7 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done)
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
return result;
}
@@ -1272,11 +1273,11 @@ static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done)
CURLcode result = pop3_multi_statemach(data, dophase_done);
if(result)
- DEBUGF(infof(data, "DO phase failed\n"));
+ DEBUGF(infof(data, "DO phase failed"));
else if(*dophase_done) {
result = pop3_dophase_done(data, FALSE /* not connected */);
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -1515,8 +1516,17 @@ CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
if(prev) {
/* If the partial match was the CRLF and dot then only write the CRLF
as the server would have inserted the dot */
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
- strip_dot ? prev - 1 : prev);
+ if(strip_dot && prev - 1 > 0) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+ prev - 1);
+ }
+ else if(!strip_dot) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+ prev);
+ }
+ else {
+ result = CURLE_OK;
+ }
if(result)
return result;
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
index 55e8ded..f5ef6bd 100644
--- a/Utilities/cmcurl/lib/progress.c
+++ b/Utilities/cmcurl/lib/progress.c
@@ -85,7 +85,7 @@ static char *max5data(curl_off_t bytes, char *max5)
CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
(bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
-#if (CURL_SIZEOF_CURL_OFF_T > 4)
+#if (SIZEOF_CURL_OFF_T > 4)
else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
/* 'XXXXM' is good until we're at 10000MB or above */
@@ -241,6 +241,8 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
data->progress.is_t_startransfer_set = false;
data->progress.ul_limit_start = data->progress.start;
data->progress.dl_limit_start = data->progress.start;
+ data->progress.ul_limit_size = 0;
+ data->progress.dl_limit_size = 0;
data->progress.downloaded = 0;
data->progress.uploaded = 0;
/* clear all bits except HIDE and HEADERS_OUT */
@@ -321,14 +323,14 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
{
/* don't set a new stamp unless the time since last update is long enough */
- if(data->set.max_recv_speed > 0) {
+ if(data->set.max_recv_speed) {
if(Curl_timediff(now, data->progress.dl_limit_start) >=
MIN_RATE_LIMIT_PERIOD) {
data->progress.dl_limit_start = now;
data->progress.dl_limit_size = data->progress.downloaded;
}
}
- if(data->set.max_send_speed > 0) {
+ if(data->set.max_send_speed) {
if(Curl_timediff(now, data->progress.ul_limit_start) >=
MIN_RATE_LIMIT_PERIOD) {
data->progress.ul_limit_start = now;
@@ -369,94 +371,87 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
}
}
+/* returns the average speed in bytes / second */
+static curl_off_t trspeed(curl_off_t size, /* number of bytes */
+ curl_off_t us) /* microseconds */
+{
+ if(us < 1)
+ return size * 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 */
static bool progress_calc(struct Curl_easy *data, struct curltime now)
{
- curl_off_t timespent;
- curl_off_t timespent_ms; /* milliseconds */
- curl_off_t dl = data->progress.downloaded;
- curl_off_t ul = data->progress.uploaded;
bool timetoshow = FALSE;
+ struct Progress * const p = &data->progress;
- /* The time spent so far (from the start) */
- data->progress.timespent = Curl_timediff_us(now, data->progress.start);
- timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */
- timespent_ms = (curl_off_t)data->progress.timespent/1000; /* ms */
-
- /* The average download speed this far */
- if(dl < CURL_OFF_T_MAX/1000)
- data->progress.dlspeed = (dl * 1000 / (timespent_ms>0?timespent_ms:1));
- else
- data->progress.dlspeed = (dl / (timespent>0?timespent:1));
-
- /* The average upload speed this far */
- if(ul < CURL_OFF_T_MAX/1000)
- data->progress.ulspeed = (ul * 1000 / (timespent_ms>0?timespent_ms:1));
- else
- data->progress.ulspeed = (ul / (timespent>0?timespent:1));
+ /* The time spent so far (from the start) in microseconds */
+ p->timespent = Curl_timediff_us(now, p->start);
+ p->dlspeed = trspeed(p->downloaded, p->timespent);
+ p->ulspeed = trspeed(p->uploaded, p->timespent);
/* Calculations done at most once a second, unless end is reached */
- if(data->progress.lastshow != now.tv_sec) {
+ if(p->lastshow != now.tv_sec) {
int countindex; /* amount of seconds stored in the speeder array */
- int nowindex = data->progress.speeder_c% CURR_TIME;
- data->progress.lastshow = now.tv_sec;
+ int nowindex = p->speeder_c% CURR_TIME;
+ p->lastshow = now.tv_sec;
timetoshow = TRUE;
/* Let's do the "current speed" thing, with the dl + ul speeds
combined. Store the speed at entry 'nowindex'. */
- data->progress.speeder[ nowindex ] =
- data->progress.downloaded + data->progress.uploaded;
+ p->speeder[ nowindex ] = p->downloaded + p->uploaded;
/* remember the exact time for this moment */
- data->progress.speeder_time [ nowindex ] = now;
+ p->speeder_time [ nowindex ] = now;
/* advance our speeder_c counter, which is increased every time we get
here and we expect it to never wrap as 2^32 is a lot of seconds! */
- data->progress.speeder_c++;
+ p->speeder_c++;
/* figure out how many index entries of data we have stored in our speeder
array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
transfer. Imagine, after one second we have filled in two entries,
after two seconds we've filled in three entries etc. */
- countindex = ((data->progress.speeder_c >= CURR_TIME)?
- CURR_TIME:data->progress.speeder_c) - 1;
+ countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;
/* first of all, we don't do this if there's no counted seconds yet */
if(countindex) {
int checkindex;
timediff_t span_ms;
+ curl_off_t amount;
/* Get the index position to compare with the 'nowindex' position.
Get the oldest entry possible. While we have less than CURR_TIME
entries, the first entry will remain the oldest. */
- checkindex = (data->progress.speeder_c >= CURR_TIME)?
- data->progress.speeder_c%CURR_TIME:0;
+ checkindex = (p->speeder_c >= CURR_TIME)? p->speeder_c%CURR_TIME:0;
/* Figure out the exact time for the time span */
- span_ms = Curl_timediff(now, data->progress.speeder_time[checkindex]);
+ span_ms = Curl_timediff(now, p->speeder_time[checkindex]);
if(0 == span_ms)
span_ms = 1; /* at least one millisecond MUST have passed */
/* Calculate the average speed the last 'span_ms' milliseconds */
- {
- curl_off_t amount = data->progress.speeder[nowindex]-
- data->progress.speeder[checkindex];
-
- if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
- /* the 'amount' value is bigger than would fit in 32 bits if
- multiplied with 1000, so we use the double math for this */
- data->progress.current_speed = (curl_off_t)
- ((double)amount/((double)span_ms/1000.0));
- else
- /* the 'amount' value is small enough to fit within 32 bits even
- when multiplied with 1000 */
- data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
- }
+ amount = p->speeder[nowindex]- p->speeder[checkindex];
+
+ if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
+ /* the 'amount' value is bigger than would fit in 32 bits if
+ multiplied with 1000, so we use the double math for this */
+ p->current_speed = (curl_off_t)
+ ((double)amount/((double)span_ms/1000.0));
+ else
+ /* the 'amount' value is small enough to fit within 32 bits even
+ when multiplied with 1000 */
+ p->current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
}
else
/* the first second we use the average */
- data->progress.current_speed =
- data->progress.ulspeed + data->progress.dlspeed;
+ p->current_speed = p->ulspeed + p->dlspeed;
} /* Calculations end */
return timetoshow;
diff --git a/Utilities/cmcurl/lib/quic.h b/Utilities/cmcurl/lib/quic.h
index 947f13e..b030359 100644
--- a/Utilities/cmcurl/lib/quic.h
+++ b/Utilities/cmcurl/lib/quic.h
@@ -45,7 +45,7 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
struct connectdata *conn,
int sockindex,
bool *connected);
-int Curl_quic_ver(char *p, size_t len);
+void Curl_quic_ver(char *p, size_t len);
CURLcode Curl_quic_done_sending(struct Curl_easy *data);
void Curl_quic_done(struct Curl_easy *data, bool premature);
bool Curl_quic_data_pending(const struct Curl_easy *data);
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
index 951fedb..8f2c1ba 100644
--- a/Utilities/cmcurl/lib/rand.c
+++ b/Utilities/cmcurl/lib/rand.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
@@ -87,7 +87,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
if(!seeded) {
struct curltime now = Curl_now();
- infof(data, "WARNING: Using weak random seed\n");
+ infof(data, "WARNING: Using weak random seed");
randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
randseed = randseed * 1103515245 + 12345;
randseed = randseed * 1103515245 + 12345;
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index 5576675..30fefb9 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -109,6 +109,7 @@ const struct Curl_handler Curl_handler_rtsp = {
rtsp_disconnect, /* disconnect */
rtsp_rtp_readwrite, /* readwrite */
rtsp_conncheck, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_RTSP, /* defport */
CURLPROTO_RTSP, /* protocol */
CURLPROTO_RTSP, /* family */
@@ -230,7 +231,7 @@ static CURLcode rtsp_done(struct Curl_easy *data,
}
if(data->set.rtspreq == RTSPREQ_RECEIVE &&
(data->conn->proto.rtspc.rtp_channel == -1)) {
- infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
+ infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv);
}
}
@@ -404,8 +405,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
/* Referrer */
Curl_safefree(data->state.aptr.ref);
- if(data->change.referer && !Curl_checkheaders(data, "Referer"))
- data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ if(data->state.referer && !Curl_checkheaders(data, "Referer"))
+ data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
else
data->state.aptr.ref = NULL;
@@ -650,7 +651,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
}
/* We have the full RTP interleaved packet
* Write out the header including the leading '$' */
- DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
+ DEBUGF(infof(data, "RTP write channel %d rtp_length %d",
rtspc->rtp_channel, rtp_length));
result = rtp_client_write(data, &rtp[0], rtp_length + 4);
if(result) {
@@ -680,8 +681,8 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
}
}
- if(rtp_dataleft != 0 && rtp[0] == '$') {
- DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft,
+ if(rtp_dataleft && rtp[0] == '$') {
+ DEBUGF(infof(data, "RTP Rewinding %zd %s", rtp_dataleft,
*readmore ? "(READMORE)" : ""));
/* Store the incomplete RTP packet for a "rewind" */
@@ -824,7 +825,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
/* Copy the id substring into a new buffer */
data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1);
- if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
+ if(!data->set.str[STRING_RTSP_SESSION_ID])
return CURLE_OUT_OF_MEMORY;
memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen);
(data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';
diff --git a/Utilities/cmcurl/lib/rtsp.h b/Utilities/cmcurl/lib/rtsp.h
index 1e9cb7d..da11ade 100644
--- a/Utilities/cmcurl/lib/rtsp.h
+++ b/Utilities/cmcurl/lib/rtsp.h
@@ -22,7 +22,7 @@
*
***************************************************************************/
#ifdef USE_HYPER
-#define CURL_DISABLE_RTSP
+#define CURL_DISABLE_RTSP 1
#endif
#ifndef CURL_DISABLE_RTSP
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
index 44fe229..84d0b8f 100644
--- a/Utilities/cmcurl/lib/select.c
+++ b/Utilities/cmcurl/lib/select.c
@@ -442,7 +442,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
if(ufds[i].events & POLLPRI)
ufds[i].revents |= POLLPRI;
}
- if(ufds[i].revents != 0)
+ if(ufds[i].revents)
r++;
}
diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h
index 4db6487..19da1e7 100644
--- a/Utilities/cmcurl/lib/select.h
+++ b/Utilities/cmcurl/lib/select.h
@@ -106,7 +106,11 @@ 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); \
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
index b3c7fe3..14ca84b 100644
--- a/Utilities/cmcurl/lib/sendf.c
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -65,7 +65,7 @@ static size_t convert_lineends(struct Curl_easy *data,
char *inPtr, *outPtr;
/* sanity check */
- if((startPtr == NULL) || (size < 1)) {
+ if(!startPtr || (size < 1)) {
return size;
}
@@ -236,29 +236,21 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
/* Curl_infof() is for info message along the way */
+#define MAXINFO 2048
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
+ DEBUGASSERT(!strchr(fmt, '\n'));
if(data && data->set.verbose) {
va_list ap;
size_t len;
- char print_buffer[2048 + 1];
+ char buffer[MAXINFO + 2];
va_start(ap, fmt);
- len = mvsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
- /*
- * Indicate truncation of the input by replacing the last 3 characters
- * with "...", and transfer the newline over in case the format had one.
- */
- if(len >= sizeof(print_buffer)) {
- len = strlen(fmt);
- if(fmt[--len] == '\n')
- msnprintf(print_buffer + (sizeof(print_buffer) - 5), 5, "...\n");
- else
- msnprintf(print_buffer + (sizeof(print_buffer) - 4), 4, "...");
- }
+ len = mvsnprintf(buffer, MAXINFO, fmt, ap);
va_end(ap);
- len = strlen(print_buffer);
- Curl_debug(data, CURLINFO_TEXT, print_buffer, len);
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+ Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
}
@@ -274,14 +266,14 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
size_t len;
char error[CURL_ERROR_SIZE + 2];
va_start(ap, fmt);
- (void)mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
- len = strlen(error);
+ len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
if(data->set.errorbuffer && !data->state.errorbuf) {
strcpy(data->set.errorbuffer, error);
data->state.errorbuf = TRUE; /* wrote error string */
}
error[len++] = '\n';
+ error[len] = '\0';
Curl_debug(data, CURLINFO_TEXT, error, len);
va_end(ap);
}
@@ -309,6 +301,18 @@ CURLcode Curl_write(struct Curl_easy *data,
conn = data->conn;
num = (sockfd == conn->sock[SECONDARYSOCKET]);
+#ifdef CURLDEBUG
+ {
+ /* Allow debug builds to override this logic to force short sends
+ */
+ char *p = getenv("CURL_SMALLSENDS");
+ if(p) {
+ size_t altsize = (size_t)strtoul(p, NULL, 10);
+ if(altsize)
+ len = CURLMIN(len, altsize);
+ }
+ }
+#endif
bytes_written = conn->send[num](data, num, mem, len, &result);
*written = bytes_written;
@@ -498,9 +502,7 @@ static CURLcode pausewrite(struct Curl_easy *data,
/* store this information in the state struct for later use */
Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
s->tempwrite[i].type = type;
-
- if(newtype)
- s->tempcount++;
+ s->tempcount++;
}
if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
@@ -606,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.
+ The defines are in sendf.h of course. "len" is not allowed to be 0.
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
@@ -618,9 +620,8 @@ CURLcode Curl_client_write(struct Curl_easy *data,
size_t len)
{
struct connectdata *conn = data->conn;
- if(0 == len)
- len = strlen(ptr);
+ DEBUGASSERT(len);
DEBUGASSERT(type <= 3);
/* FTP data may need conversion. */
diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c
index ce73a34..08827d1 100644
--- a/Utilities/cmcurl/lib/setopt.c
+++ b/Utilities/cmcurl/lib/setopt.c
@@ -177,7 +177,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
- result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
va_arg(param, char *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -190,7 +190,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_TLS13_CIPHERS:
if(Curl_ssl_tls13_ciphersuites()) {
/* set preferred list of TLS 1.3 cipher suites */
- result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST],
va_arg(param, char *));
}
else
@@ -426,6 +426,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
version_max = C_SSLVERSION_MAX_VALUE(arg);
if(version < CURL_SSLVERSION_DEFAULT ||
+ version == CURL_SSLVERSION_SSLv2 ||
+ version == CURL_SSLVERSION_SSLv3 ||
version >= CURL_SSLVERSION_LAST ||
version_max < CURL_SSLVERSION_MAX_NONE ||
version_max >= CURL_SSLVERSION_MAX_LAST)
@@ -653,8 +655,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.httpauth = CURLAUTH_AWS_SIGV4;
break;
-#endif /* CURL_DISABLE_HTTP */
-
case CURLOPT_MIMEPOST:
/*
* Set to make us do MIME/form POST
@@ -671,13 +671,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* String to set in the HTTP Referer: field.
*/
- if(data->change.referer_alloc) {
- Curl_safefree(data->change.referer);
- data->change.referer_alloc = FALSE;
+ if(data->state.referer_alloc) {
+ Curl_safefree(data->state.referer);
+ data->state.referer_alloc = FALSE;
}
result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
va_arg(param, char *));
- data->change.referer = data->set.str[STRING_SET_REFERER];
+ data->state.referer = data->set.str[STRING_SET_REFERER];
break;
case CURLOPT_USERAGENT:
@@ -695,7 +695,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.headers = va_arg(param, struct curl_slist *);
break;
-#ifndef CURL_DISABLE_HTTP
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXYHEADER:
/*
@@ -747,13 +746,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_BAD_FUNCTION_ARGUMENT;
/* append the cookie file name to the list of file names, and deal with
them later */
- cl = curl_slist_append(data->change.cookielist, argptr);
+ cl = curl_slist_append(data->state.cookielist, argptr);
if(!cl) {
- curl_slist_free_all(data->change.cookielist);
- data->change.cookielist = NULL;
+ curl_slist_free_all(data->state.cookielist);
+ data->state.cookielist = NULL;
return CURLE_OUT_OF_MEMORY;
}
- data->change.cookielist = cl; /* store the list for later use */
+ data->state.cookielist = cl; /* store the list for later use */
+ }
+ else {
+ /* clear the list of cookie files */
+ curl_slist_free_all(data->state.cookielist);
+ data->state.cookielist = NULL;
+
+ if(!data->share || !data->share->cookies) {
+ /* throw away all existing cookies if this isn't a shared cookie
+ container */
+ Curl_cookie_clearall(data->cookies);
+ Curl_cookie_cleanup(data->cookies);
+ }
+ /* disable the cookie engine */
+ data->cookies = NULL;
}
break;
@@ -800,7 +813,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_COOKIELIST:
argptr = va_arg(param, char *);
- if(argptr == NULL)
+ if(!argptr)
break;
if(strcasecompare(argptr, "ALL")) {
@@ -891,7 +904,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(arg == CURL_HTTP_VERSION_NONE)
arg = CURL_HTTP_VERSION_2TLS;
#endif
- data->set.httpversion = arg;
+ data->set.httpwant = (unsigned char)arg;
break;
case CURLOPT_EXPECT_100_TIMEOUT_MS:
@@ -909,7 +922,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, unsigned long);
if(arg > 1L)
return CURLE_BAD_FUNCTION_ARGUMENT;
+#ifdef USE_HYPER
+ /* Hyper does not support HTTP/0.9 */
+ if(arg)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+#else
data->set.http09_allowed = arg ? TRUE : FALSE;
+#endif
break;
#endif /* CURL_DISABLE_HTTP */
@@ -1160,7 +1179,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* An option that changes the command to one that asks for a list only, no
* file info details. Used for FTP, POP3 and SFTP.
*/
- data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_APPEND:
@@ -1168,7 +1187,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* We want to upload and append to an existing file. Used for FTP and
* SFTP.
*/
- data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ data->set.remote_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
#ifndef CURL_DISABLE_FTP
@@ -1335,14 +1354,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* The URL to fetch.
*/
- if(data->change.url_alloc) {
+ if(data->state.url_alloc) {
/* the already set URL is allocated, free it first! */
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
+ Curl_safefree(data->state.url);
+ data->state.url_alloc = FALSE;
}
result = Curl_setstropt(&data->set.str[STRING_SET_URL],
va_arg(param, char *));
- data->change.url = data->set.str[STRING_SET_URL];
+ data->state.url = data->set.str[STRING_SET_URL];
break;
case CURLOPT_PORT:
/*
@@ -1416,7 +1435,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_USERNAME],
va_arg(param, char *));
break;
-
case CURLOPT_PASSWORD:
/*
* authentication password to use in the operation
@@ -1474,7 +1492,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* that aren't actually in use right now will be pruned immediately.
*/
data->set.resolve = va_arg(param, struct curl_slist *);
- data->change.resolve = data->set.resolve;
+ data->state.resolve = data->set.resolve;
break;
case CURLOPT_PROGRESSFUNCTION:
/*
@@ -1666,14 +1684,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* String that holds file name of the SSL certificate to use
*/
- result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_CERT],
va_arg(param, char *));
break;
case CURLOPT_SSLCERT_BLOB:
/*
- * Blob that holds file name of the SSL certificate to use
+ * Blob that holds file content of the SSL certificate to use
*/
- result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_ORIG],
+ result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
va_arg(param, struct curl_blob *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -1686,7 +1704,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_PROXY_SSLCERT_BLOB:
/*
- * Blob that holds file name of the SSL certificate to use for proxy
+ * Blob that holds file content of the SSL certificate to use for proxy
*/
result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
va_arg(param, struct curl_blob *));
@@ -1696,7 +1714,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* String that holds file type of the SSL certificate to use
*/
- result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE],
va_arg(param, char *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -1712,14 +1730,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* String that holds file name of the SSL key to use
*/
- result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_KEY],
va_arg(param, char *));
break;
case CURLOPT_SSLKEY_BLOB:
/*
- * Blob that holds file name of the SSL key to use
+ * Blob that holds file content of the SSL key to use
*/
- result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_ORIG],
+ result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
va_arg(param, struct curl_blob *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -1732,7 +1750,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_PROXY_SSLKEY_BLOB:
/*
- * Blob that holds file name of the SSL key to use for proxy
+ * Blob that holds file content of the SSL key to use for proxy
*/
result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
va_arg(param, struct curl_blob *));
@@ -1742,7 +1760,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* String that holds file type of the SSL key to use
*/
- result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE],
va_arg(param, char *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -1758,7 +1776,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* String that holds the SSL or SSH private key password.
*/
- result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD],
va_arg(param, char *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -1852,6 +1870,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.primary.verifypeer;
}
break;
+ case CURLOPT_DOH_SSL_VERIFYPEER:
+ /*
+ * Enable peer SSL verifying for DoH.
+ */
+ data->set.doh_verifypeer = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYPEER:
/*
@@ -1884,6 +1909,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.primary.verifyhost;
}
break;
+ case CURLOPT_DOH_SSL_VERIFYHOST:
+ /*
+ * Enable verification of the host name in the peer certificate for DoH
+ */
+ arg = va_arg(param, long);
+
+ /* Treat both 1 and 2 as TRUE */
+ data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
+ break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYHOST:
/*
@@ -1919,6 +1953,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.primary.verifystatus;
}
break;
+ case CURLOPT_DOH_SSL_VERIFYSTATUS:
+ /*
+ * Enable certificate status verifying for DoH.
+ */
+ if(!Curl_ssl_cert_status_request()) {
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ }
+
+ data->set.doh_verifystatus = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
case CURLOPT_SSL_CTX_FUNCTION:
/*
* Set a SSL_CTX callback
@@ -1967,7 +2013,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
#ifdef USE_SSL
if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
- result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
va_arg(param, char *));
else
#endif
@@ -1992,9 +2038,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Set CA info for SSL connection. Specify file name of the CA certificate
*/
- result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
va_arg(param, char *));
break;
+ case CURLOPT_CAINFO_BLOB:
+ /*
+ * Blob that holds CA info for SSL connection.
+ * Specify entire PEM of the CA certificate
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
+ result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
+ va_arg(param, struct curl_blob *));
+ else
+#endif
+ return CURLE_NOT_BUILT_IN;
+
+ break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CAINFO:
/*
@@ -2004,6 +2064,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
va_arg(param, char *));
break;
+ case CURLOPT_PROXY_CAINFO_BLOB:
+ /*
+ * Blob that holds CA info for SSL connection proxy.
+ * Specify entire PEM of the CA certificate
+ */
+#ifdef USE_SSL
+ if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
+ result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
+ va_arg(param, struct curl_blob *));
+ else
+#endif
+ return CURLE_NOT_BUILT_IN;
+ break;
#endif
case CURLOPT_CAPATH:
/*
@@ -2013,7 +2086,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifdef USE_SSL
if(Curl_ssl->supports & SSLSUPP_CA_PATH)
/* This does not work on windows. */
- result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
va_arg(param, char *));
else
#endif
@@ -2040,7 +2113,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set CRL file info for SSL connection. Specify file name of the CRL
* to check certificates revocation
*/
- result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
va_arg(param, char *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -2058,14 +2131,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set Issuer certificate file
* to check certificates issuer
*/
- result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
va_arg(param, char *));
break;
case CURLOPT_ISSUERCERT_BLOB:
/*
* Blob that holds Issuer certificate to check certificates issuer
*/
- result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG],
+ result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT],
va_arg(param, struct curl_blob *));
break;
#ifndef CURL_DISABLE_PROXY
@@ -2125,7 +2198,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
else if(arg < UPLOADBUFFER_MIN)
arg = UPLOADBUFFER_MIN;
- data->set.upload_buffer_size = arg;
+ data->set.upload_buffer_size = (unsigned int)arg;
Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
break;
@@ -2238,24 +2311,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_SSL_OPTIONS:
arg = va_arg(param, long);
- data->set.ssl.enable_beast =
- (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
+ data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+ data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
+ /* If a setting is added here it should also be added in dohprobe()
+ which sets its own CURLOPT_SSL_OPTIONS based on these settings. */
break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_OPTIONS:
arg = va_arg(param, long);
- data->set.proxy_ssl.enable_beast =
- (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
+ data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
- data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
data->set.proxy_ssl.revoke_best_effort =
!!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
+ data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+ data->set.proxy_ssl.auto_client_cert =
+ !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
break;
#endif
@@ -2662,9 +2738,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
#ifdef USE_TLS_SRP
case CURLOPT_TLSAUTH_USERNAME:
- result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME],
va_arg(param, char *));
- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+ if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
break;
case CURLOPT_PROXY_TLSAUTH_USERNAME:
@@ -2677,9 +2753,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
break;
case CURLOPT_TLSAUTH_PASSWORD:
- result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
+ result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
va_arg(param, char *));
- if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+ if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
break;
case CURLOPT_PROXY_TLSAUTH_PASSWORD:
@@ -2863,7 +2939,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.trailer_data = va_arg(param, void *);
#endif
break;
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
case CURLOPT_HSTSREADFUNCTION:
data->set.hsts_read = va_arg(param, curl_hstsread_callback);
break;
diff --git a/Utilities/cmcurl/lib/setup-vms.h b/Utilities/cmcurl/lib/setup-vms.h
index ba75dc2..a6710d9 100644
--- a/Utilities/cmcurl/lib/setup-vms.h
+++ b/Utilities/cmcurl/lib/setup-vms.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
@@ -87,7 +87,7 @@ static char *vms_translate_path(const char *path)
/* See if the result is in VMS format, if not, we are done */
/* Assume that this is a PATH, not just some data */
test_str = strpbrk(path, ":[<^");
- if(test_str == NULL) {
+ if(!test_str) {
return (char *)path;
}
@@ -119,7 +119,7 @@ static char *vms_getenv(const char *envvar)
/* first use the DECC getenv() function */
result = decc$getenv(envvar);
- if(result == NULL) {
+ if(!result) {
return result;
}
@@ -154,7 +154,7 @@ static struct passwd *vms_getpwuid(uid_t uid)
#endif
my_passwd = decc_getpwuid(uid);
- if(my_passwd == NULL) {
+ if(!my_passwd) {
return my_passwd;
}
diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c
index d915117..a2e7e41 100644
--- a/Utilities/cmcurl/lib/sha256.c
+++ b/Utilities/cmcurl/lib/sha256.c
@@ -6,7 +6,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
@@ -42,19 +42,19 @@
#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 */
/* Please keep the SSL backend-specific #if branches in this order:
*
* 1. USE_OPENSSL
- * 2. USE_GNUTLS_NETTLE
- * 3. USE_GNUTLS
- * 4. USE_MBEDTLS
- * 5. USE_COMMON_CRYPTO
- * 6. USE_WIN32_CRYPTO
+ * 2. USE_GNUTLS
+ * 3. USE_MBEDTLS
+ * 4. USE_COMMON_CRYPTO
+ * 5. USE_WIN32_CRYPTO
*
* This ensures that the same SSL branch gets activated throughout this source
* file even if multiple backends are enabled at the same time.
@@ -65,7 +65,7 @@
/* When OpenSSL is available we use the SHA256-function from OpenSSL */
#include <openssl/sha.h>
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
#include <nettle/sha.h>
@@ -93,35 +93,6 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
}
-#elif defined(USE_GNUTLS)
-
-#include <gcrypt.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-typedef gcry_md_hd_t SHA256_CTX;
-
-static void SHA256_Init(SHA256_CTX *ctx)
-{
- gcry_md_open(ctx, GCRY_MD_SHA256, 0);
-}
-
-static void SHA256_Update(SHA256_CTX *ctx,
- const unsigned char *data,
- unsigned int length)
-{
- gcry_md_write(*ctx, data, length);
-}
-
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
-{
- memcpy(digest, gcry_md_read(*ctx, 0), SHA256_DIGEST_LENGTH);
- gcry_md_close(*ctx);
-}
-
#elif defined(USE_MBEDTLS)
#include <mbedtls/sha256.h>
@@ -135,8 +106,8 @@ typedef mbedtls_sha256_context SHA256_CTX;
static void SHA256_Init(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
@@ -146,8 +117,8 @@ static void SHA256_Update(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
@@ -155,8 +126,8 @@ static void SHA256_Update(SHA256_CTX *ctx,
static void SHA256_Final(unsigned char *digest, 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
diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c
index 4f1804d..9c43c8f 100644
--- a/Utilities/cmcurl/lib/share.c
+++ b/Utilities/cmcurl/lib/share.c
@@ -235,7 +235,7 @@ Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
{
struct Curl_share *share = data->share;
- if(share == NULL)
+ if(!share)
return CURLSHE_INVALID;
if(share->specifier & (1<<type)) {
@@ -252,7 +252,7 @@ Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
{
struct Curl_share *share = data->share;
- if(share == NULL)
+ if(!share)
return CURLSHE_INVALID;
if(share->specifier & (1<<type)) {
diff --git a/Utilities/cmcurl/lib/sigpipe.h b/Utilities/cmcurl/lib/sigpipe.h
index 430cfc6..d6ec5fc 100644
--- a/Utilities/cmcurl/lib/sigpipe.h
+++ b/Utilities/cmcurl/lib/sigpipe.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
@@ -24,7 +24,7 @@
#include "curl_setup.h"
#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && \
- (defined(USE_OPENSSL) || defined(USE_MBEDTLS))
+ (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL))
#include <signal.h>
struct sigpipe_ignore {
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
index dd4e4fd..fd49cf6 100644
--- a/Utilities/cmcurl/lib/smb.c
+++ b/Utilities/cmcurl/lib/smb.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (CURL_SIZEOF_CURL_OFF_T > 4)
+ (SIZEOF_CURL_OFF_T > 4)
#define BUILDING_CURL_SMB_C
@@ -88,6 +88,7 @@ const struct Curl_handler Curl_handler_smb = {
smb_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SMB, /* defport */
CURLPROTO_SMB, /* protocol */
CURLPROTO_SMB, /* family */
@@ -114,6 +115,7 @@ const struct Curl_handler Curl_handler_smbs = {
smb_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SMBS, /* defport */
CURLPROTO_SMBS, /* protocol */
CURLPROTO_SMB, /* family */
@@ -202,7 +204,7 @@ static void conn_state(struct Curl_easy *data, enum smb_conn_state newstate)
};
if(smbc->state != newstate)
- infof(data, "SMB conn %p state change from %s to %s\n",
+ infof(data, "SMB conn %p state change from %s to %s",
(void *)smbc, names[smbc->state], names[newstate]);
#endif
@@ -228,7 +230,7 @@ static void request_state(struct Curl_easy *data,
};
if(req->state != newstate)
- infof(data, "SMB request %p state change from %s to %s\n",
+ infof(data, "SMB request %p state change from %s to %s",
(void *)req, names[req->state], names[newstate]);
#endif
@@ -627,9 +629,8 @@ static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
/* Check if there is data in the transfer buffer */
if(!smbc->send_size && smbc->upload_size) {
- size_t nread = smbc->upload_size > data->set.upload_buffer_size ?
- data->set.upload_buffer_size :
- smbc->upload_size;
+ size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ?
+ (size_t)data->set.upload_buffer_size : smbc->upload_size;
data->req.upload_fromhere = data->state.ulbuf;
result = Curl_fillreadbuffer(data, nread, &nread);
if(result && result != CURLE_AGAIN)
@@ -669,7 +670,7 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
#ifdef USE_SSL
if((conn->handler->flags & PROTOPT_SSL)) {
bool ssl_done = FALSE;
- result = Curl_ssl_connect_nonblocking(data, conn,
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
FIRSTSOCKET, &ssl_done);
if(result && result != CURLE_AGAIN)
return result;
@@ -1022,4 +1023,4 @@ static CURLcode smb_parse_url_path(struct Curl_easy *data,
}
#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
- CURL_SIZEOF_CURL_OFF_T > 4 */
+ SIZEOF_CURL_OFF_T > 4 */
diff --git a/Utilities/cmcurl/lib/smb.h b/Utilities/cmcurl/lib/smb.h
index 907cf0c..0e3c2ec 100644
--- a/Utilities/cmcurl/lib/smb.h
+++ b/Utilities/cmcurl/lib/smb.h
@@ -8,7 +8,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
- * 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
@@ -244,12 +244,12 @@ struct smb_tree_disconnect {
#endif /* BUILDING_CURL_SMB_C */
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (CURL_SIZEOF_CURL_OFF_T > 4)
+ (SIZEOF_CURL_OFF_T > 4)
extern const struct Curl_handler Curl_handler_smb;
extern const struct Curl_handler Curl_handler_smbs;
#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
- CURL_SIZEOF_CURL_OFF_T > 4 */
+ SIZEOF_CURL_OFF_T > 4 */
#endif /* HEADER_CURL_SMB_H */
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
index 1fc8800..02ddaca 100644
--- a/Utilities/cmcurl/lib/smtp.c
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -78,7 +78,6 @@
#include "strcase.h"
#include "vtls/vtls.h"
#include "connect.h"
-#include "strerror.h"
#include "select.h"
#include "multiif.h"
#include "url.h"
@@ -136,6 +135,7 @@ const struct Curl_handler Curl_handler_smtp = {
smtp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SMTP, /* defport */
CURLPROTO_SMTP, /* protocol */
CURLPROTO_SMTP, /* family */
@@ -164,6 +164,7 @@ const struct Curl_handler Curl_handler_smtps = {
smtp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SMTPS, /* defport */
CURLPROTO_SMTPS, /* protocol */
CURLPROTO_SMTP, /* family */
@@ -306,7 +307,7 @@ static void state(struct Curl_easy *data, smtpstate newstate)
};
if(smtpc->state != newstate)
- infof(data, "SMTP %p state change from %s to %s\n",
+ infof(data, "SMTP %p state change from %s to %s",
(void *)smtpc, names[smtpc->state], names[newstate]);
#endif
@@ -395,7 +396,8 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data)
/* Start the SSL connection */
struct connectdata *conn = data->conn;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
+ CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
+ FIRSTSOCKET,
&smtpc->ssldone);
if(!result) {
@@ -482,7 +484,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
state(data, SMTP_AUTH);
else {
/* Other mechanisms not supported */
- infof(data, "No known authentication mechanisms supported!\n");
+ infof(data, "No known authentication mechanisms supported!");
result = CURLE_LOGIN_DENIED;
}
}
@@ -832,6 +834,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);
@@ -894,7 +900,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
for(;;) {
size_t llen;
size_t wordlen;
- unsigned int mechbit;
+ unsigned short mechbit;
while(len &&
(*line == ' ' || *line == '\t' ||
@@ -1256,7 +1262,7 @@ static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done)
struct smtp_conn *smtpc = &conn->proto.smtpc;
if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
- result = Curl_ssl_connect_nonblocking(data, conn,
+ result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
FIRSTSOCKET, &smtpc->ssldone);
if(result || !smtpc->ssldone)
return result;
@@ -1433,7 +1439,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
}
/* Clear the transfer mode for the next request */
- smtp->transfer = FTPTRANSFER_BODY;
+ smtp->transfer = PPTRANSFER_BODY;
return result;
}
@@ -1453,11 +1459,11 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
struct connectdata *conn = data->conn;
struct SMTP *smtp = data->req.p.smtp;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
if(data->set.opt_no_body) {
/* Requested no body means no transfer */
- smtp->transfer = FTPTRANSFER_INFO;
+ smtp->transfer = PPTRANSFER_INFO;
}
*dophase_done = FALSE; /* not done yet */
@@ -1493,7 +1499,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done)
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
return result;
}
@@ -1564,7 +1570,7 @@ static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
(void)connected;
- if(smtp->transfer != FTPTRANSFER_BODY)
+ if(smtp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
@@ -1577,11 +1583,11 @@ static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
CURLcode result = smtp_multi_statemach(data, dophase_done);
if(result)
- DEBUGF(infof(data, "DO phase failed\n"));
+ DEBUGF(infof(data, "DO phase failed"));
else if(*dophase_done) {
result = smtp_dophase_done(data, FALSE /* not connected */);
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -1821,7 +1827,7 @@ CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread)
return CURLE_OUT_OF_MEMORY;
}
}
- DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread);
+ DEBUGASSERT((size_t)data->set.upload_buffer_size >= (size_t)nread);
/* Have we already sent part of the EOB? */
eob_sent = smtp->eob;
diff --git a/Utilities/cmcurl/lib/socketpair.c b/Utilities/cmcurl/lib/socketpair.c
index 2c580ad..409d2ad 100644
--- a/Utilities/cmcurl/lib/socketpair.c
+++ b/Utilities/cmcurl/lib/socketpair.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 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
@@ -48,6 +48,10 @@
#endif /* !INADDR_LOOPBACK */
#endif /* !WIN32 */
+#include "nonblock.h" /* for curlx_nonblock */
+#include "timeval.h" /* needed before select.h */
+#include "select.h" /* for Curl_poll */
+
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -59,12 +63,11 @@ int Curl_socketpair(int domain, int type, int protocol,
union {
struct sockaddr_in inaddr;
struct sockaddr addr;
- } a;
+ } a, a2;
curl_socket_t listener;
curl_socklen_t addrlen = sizeof(a.inaddr);
int reuse = 1;
- char data[2][12];
- ssize_t dlen;
+ struct pollfd pfd[1];
(void)domain;
(void)type;
(void)protocol;
@@ -85,7 +88,8 @@ int Curl_socketpair(int domain, int type, int protocol,
goto error;
if(bind(listener, &a.addr, sizeof(a.inaddr)) == -1)
goto error;
- if(getsockname(listener, &a.addr, &addrlen) == -1)
+ if(getsockname(listener, &a.addr, &addrlen) == -1 ||
+ addrlen < (int)sizeof(a.inaddr))
goto error;
if(listen(listener, 1) == -1)
goto error;
@@ -94,18 +98,30 @@ int Curl_socketpair(int domain, int type, int protocol,
goto error;
if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
goto error;
+
+ /* use non-blocking accept to make sure we don't block forever */
+ if(curlx_nonblock(listener, TRUE) < 0)
+ goto error;
+ pfd[0].fd = listener;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+ (void)Curl_poll(pfd, 1, 10*1000); /* 10 seconds */
socks[1] = accept(listener, NULL, NULL);
if(socks[1] == CURL_SOCKET_BAD)
goto error;
/* verify that nothing else connected */
- msnprintf(data[0], sizeof(data[0]), "%p", socks);
- dlen = strlen(data[0]);
- if(swrite(socks[0], data[0], dlen) != dlen)
+ addrlen = sizeof(a.inaddr);
+ if(getsockname(socks[0], &a.addr, &addrlen) == -1 ||
+ addrlen < (int)sizeof(a.inaddr))
goto error;
- if(sread(socks[1], data[1], sizeof(data[1])) != dlen)
+ addrlen = sizeof(a2.inaddr);
+ if(getpeername(socks[1], &a2.addr, &addrlen) == -1 ||
+ addrlen < (int)sizeof(a2.inaddr))
goto error;
- if(memcmp(data[0], data[1], dlen))
+ if(a.inaddr.sin_family != a2.inaddr.sin_family ||
+ a.inaddr.sin_addr.s_addr != a2.inaddr.sin_addr.s_addr ||
+ a.inaddr.sin_port != a2.inaddr.sin_port)
goto error;
sclose(listener);
diff --git a/Utilities/cmcurl/lib/socketpair.h b/Utilities/cmcurl/lib/socketpair.h
index 033a235..cdcc0b9 100644
--- a/Utilities/cmcurl/lib/socketpair.h
+++ b/Utilities/cmcurl/lib/socketpair.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2019 - 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,4 @@ int Curl_socketpair(int domain, int type, int protocol,
#define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d)
#endif
-/* Defined here to allow specific build configs to disable it completely */
-#define USE_SOCKETPAIR 1
-
#endif /* HEADER_CURL_SOCKETPAIR_H */
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
index d1c2a2e..db4c808 100644
--- a/Utilities/cmcurl/lib/socks.c
+++ b/Utilities/cmcurl/lib/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,9 +146,9 @@ 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\n",
+ "SXSTATE: %s => %s conn %p; line %d",
statename[oldstate], statename[conn->cnnct.state], conn,
lineno);
#endif
@@ -214,10 +214,10 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
/* SOCKS4 can only do IPv4, insist! */
conn->ip_version = CURL_IPRESOLVE_V4;
if(conn->bits.httpproxy)
- infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
+ infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d",
protocol4a ? "a" : "", hostname, remote_port);
- infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
+ infof(data, "SOCKS4 communication to %s:%d", hostname, remote_port);
/*
* Compose socks4 request
@@ -244,7 +244,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
return CURLPX_RESOLVE_HOST;
else if(rc == CURLRESOLV_PENDING) {
sxstate(data, CONNECT_RESOLVING);
- infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
+ infof(data, "SOCKS4 non-blocking resolve of %s", hostname);
return CURLPX_OK;
}
sxstate(data, CONNECT_RESOLVED);
@@ -264,7 +264,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
- infof(data, "Hostname '%s' was found\n", hostname);
+ infof(data, "Hostname '%s' was found", hostname);
sxstate(data, CONNECT_RESOLVED);
}
else {
@@ -279,18 +279,21 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
CONNECT_RESOLVED:
case CONNECT_RESOLVED: {
struct Curl_addrinfo *hp = NULL;
- char buf[64];
/*
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
* returns a Curl_addrinfo pointer that may not always look the same.
*/
- if(dns)
+ if(dns) {
hp = dns->addr;
- if(hp) {
- Curl_printable_address(hp, buf, sizeof(buf));
- if(hp->ai_family == AF_INET) {
+ /* scan for the first IPv4 address */
+ while(hp && (hp->ai_family != AF_INET))
+ hp = hp->ai_next;
+
+ if(hp) {
struct sockaddr_in *saddr_in;
+ char buf[64];
+ Curl_printable_address(hp, buf, sizeof(buf));
saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
@@ -298,20 +301,19 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
- infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
- }
- else {
- hp = NULL; /* fail! */
- failf(data, "SOCKS4 connection to %s not supported", buf);
- }
+ infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf);
- Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+ }
+ else
+ failf(data, "SOCKS4 connection to %s not supported", hostname);
}
- if(!hp) {
+ else
failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
hostname);
+
+ if(!hp)
return CURLPX_RESOLVE_HOST;
- }
}
/* FALLTHROUGH */
CONNECT_REQ_INIT:
@@ -426,7 +428,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
*/
/* wrong version ? */
- if(socksreq[0] != 0) {
+ if(socksreq[0]) {
failf(data,
"SOCKS4 reply has wrong version, version should be 0.");
return CURLPX_BAD_VERSION;
@@ -435,7 +437,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
/* Result */
switch(socksreq[1]) {
case 90:
- infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
+ infof(data, "SOCKS4%s request granted.", protocol4a?"a":"");
break;
case 91:
failf(data,
@@ -528,19 +530,19 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
switch(sx->state) {
case CONNECT_SOCKS_INIT:
if(conn->bits.httpproxy)
- infof(data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
+ infof(data, "SOCKS5: connecting to HTTP proxy %s port %d",
hostname, remote_port);
/* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
if(!socks5_resolve_local && hostname_len > 255) {
infof(data, "SOCKS5: server resolving disabled for hostnames of "
- "length > 255 [actual len=%zu]\n", hostname_len);
+ "length > 255 [actual len=%zu]", hostname_len);
socks5_resolve_local = TRUE;
}
if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
infof(data,
- "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
+ "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu",
auth);
if(!(auth & CURLAUTH_BASIC))
/* disable username/password auth */
@@ -742,7 +744,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
return CURLPX_OK;
}
/* ignore the first (VER) byte */
- else if(socksreq[1] != 0) { /* status */
+ else if(socksreq[1]) { /* status */
failf(data, "User was rejected by the SOCKS5 server (%d %d).",
socksreq[0], socksreq[1]);
return CURLPX_USER_REJECTED;
@@ -778,7 +780,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
data->state.async.dns = dns;
data->state.async.done = TRUE;
#endif
- infof(data, "SOCKS5: hostname '%s' found\n", hostname);
+ infof(data, "SOCKS5: hostname '%s' found", hostname);
}
if(!dns) {
@@ -820,7 +822,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
}
- infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", dest);
+ infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)", dest);
}
#ifdef ENABLE_IPV6
else if(hp->ai_family == AF_INET6) {
@@ -834,7 +836,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
}
- infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", dest);
+ infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)", dest);
}
#endif
else {
@@ -858,7 +860,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
socksreq[len++] = (char) hostname_len; /* one byte address length */
memcpy(&socksreq[len], hostname, hostname_len); /* address w/o NULL */
len += hostname_len;
- infof(data, "SOCKS5 connect to %s:%d (remotely resolved)\n",
+ infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
hostname, remote_port);
}
/* FALLTHROUGH */
@@ -927,7 +929,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
"SOCKS5 reply has wrong version, version should be 5.");
return CURLPX_BAD_VERSION;
}
- else if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+ else if(socksreq[1]) { /* Anything besides 0 is an error */
CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
int code = socksreq[1];
failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
@@ -1022,7 +1024,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
}
sxstate(data, CONNECT_DONE);
}
- infof(data, "SOCKS5 request granted.\n");
+ infof(data, "SOCKS5 request granted.");
*done = TRUE;
return CURLPX_OK; /* Proxy was successful! */
diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
index 3ab786d..34bfa37 100644
--- a/Utilities/cmcurl/lib/socks_gssapi.c
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -195,7 +195,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(gss_send_token.length != 0) {
+ if(gss_send_token.length) {
socksreq[0] = 1; /* GSS-API subnegotiation version */
socksreq[1] = 1; /* authentication message type */
us_length = htons((short)gss_send_token.length);
@@ -328,7 +328,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
user[gss_send_token.length] = '\0';
gss_release_name(&gss_status, &gss_client_name);
gss_release_buffer(&gss_status, &gss_send_token);
- infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",user);
+ infof(data, "SOCKS5 server authenticated user %s with GSS-API.",user);
free(user);
user = NULL;
@@ -344,7 +344,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
else if(gss_ret_flags & GSS_C_INTEG_FLAG)
gss_enc = 1;
- infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
+ infof(data, "SOCKS5 server supports GSS-API %s data protection.",
(gss_enc == 0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
/* force for the moment to no data protection */
gss_enc = 0;
@@ -518,7 +518,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
(void)curlx_nonblock(sock, TRUE);
- infof(data, "SOCKS5 access with%s protection granted.\n",
+ infof(data, "SOCKS5 access with%s protection granted.",
(socksreq[0] == 0)?"out GSS-API data":
((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
index b343538..cb225b9 100644
--- a/Utilities/cmcurl/lib/socks_sspi.c
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -198,7 +198,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
return CURLE_COULDNT_CONNECT;
}
- if(sspi_send_token.cbBuffer != 0) {
+ if(sspi_send_token.cbBuffer) {
socksreq[0] = 1; /* GSS-API subnegotiation version */
socksreq[1] = 1; /* authentication message type */
us_length = htons((short)sspi_send_token.cbBuffer);
@@ -327,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
- infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",
+ infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
names.sUserName);
s_pSecFn->FreeContextBuffer(names.sUserName);
@@ -343,7 +343,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
gss_enc = 1;
- infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
+ infof(data, "SOCKS5 server supports GSS-API %s data protection.",
(gss_enc == 0)?"no":((gss_enc == 1)?"integrity":"confidentiality") );
/* force to no data protection, avoid encryption/decryption for now */
gss_enc = 0;
@@ -591,7 +591,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
}
(void)curlx_nonblock(sock, TRUE);
- infof(data, "SOCKS5 access with%s protection granted.\n",
+ infof(data, "SOCKS5 access with%s protection granted.",
(socksreq[0] == 0)?"out GSS-API data":
((socksreq[0] == 1)?" GSS-API integrity":" GSS-API confidentiality"));
diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c
index 98baf5d..a94e2c8 100644
--- a/Utilities/cmcurl/lib/splay.c
+++ b/Utilities/cmcurl/lib/splay.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1997 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1997 - 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
@@ -42,7 +42,7 @@ struct Curl_tree *Curl_splay(struct curltime i,
{
struct Curl_tree N, *l, *r, *y;
- if(t == NULL)
+ if(!t)
return t;
N.smaller = N.larger = NULL;
l = r = &N;
@@ -50,14 +50,14 @@ struct Curl_tree *Curl_splay(struct curltime i,
for(;;) {
long comp = compare(i, t->key);
if(comp < 0) {
- if(t->smaller == NULL)
+ if(!t->smaller)
break;
if(compare(i, t->smaller->key) < 0) {
y = t->smaller; /* rotate smaller */
t->smaller = y->larger;
y->larger = t;
t = y;
- if(t->smaller == NULL)
+ if(!t->smaller)
break;
}
r->smaller = t; /* link smaller */
@@ -65,14 +65,14 @@ struct Curl_tree *Curl_splay(struct curltime i,
t = t->smaller;
}
else if(comp > 0) {
- if(t->larger == NULL)
+ if(!t->larger)
break;
if(compare(i, t->larger->key) > 0) {
y = t->larger; /* rotate larger */
t->larger = y->smaller;
y->smaller = t;
t = y;
- if(t->larger == NULL)
+ if(!t->larger)
break;
}
l->larger = t; /* link larger */
@@ -104,7 +104,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
(time_t)-1, (unsigned int)-1
}; /* will *NEVER* appear */
- if(node == NULL)
+ if(!node)
return t;
if(t != NULL) {
@@ -125,7 +125,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
}
}
- if(t == NULL) {
+ if(!t) {
node->smaller = node->larger = NULL;
}
else if(compare(i, t->key) < 0) {
@@ -262,7 +262,7 @@ int Curl_splayremove(struct Curl_tree *t,
}
else {
/* Remove the root node */
- if(t->smaller == NULL)
+ if(!t->smaller)
x = t->larger;
else {
x = Curl_splay(removenode->key, t->smaller);
diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c
index 9af47ea..85cf33b 100644
--- a/Utilities/cmcurl/lib/strdup.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h
index 0936956..8c8a6f2 100644
--- a/Utilities/cmcurl/lib/strdup.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
index 3862aab..431ff1c 100644
--- a/Utilities/cmcurl/lib/strerror.c
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -188,8 +188,8 @@ curl_easy_strerror(CURLcode error)
case CURLE_UNKNOWN_OPTION:
return "An unknown option was passed in to libcurl";
- case CURLE_TELNET_OPTION_SYNTAX :
- return "Malformed telnet option";
+ case CURLE_SETOPT_OPTION_SYNTAX :
+ return "Malformed option provided in a setopt";
case CURLE_GOT_NOTHING:
return "Server returned nothing (no headers, no data)";
@@ -320,9 +320,12 @@ curl_easy_strerror(CURLcode error)
case CURLE_QUIC_CONNECT_ERROR:
return "QUIC connection error";
- case CURLE_PROXY:
+ case CURLE_PROXY:
return "proxy handshake error";
+ case CURLE_SSL_CLIENTCERT:
+ return "SSL Client Certificate required";
+
/* error codes not used by current libcurl */
case CURLE_OBSOLETE20:
case CURLE_OBSOLETE24:
@@ -728,6 +731,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
max = buflen - 1;
*buf = '\0';
+ /* !checksrc! disable STRERROR 2 */
#if defined(WIN32) || defined(_WIN32_WCE)
#if defined(WIN32)
/* 'sys_nerr' is the maximum errno number, it is not widely portable */
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
index 2132f43..2939fd0 100644
--- a/Utilities/cmcurl/lib/system_win32.c
+++ b/Utilities/cmcurl/lib/system_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
@@ -58,7 +58,7 @@ CURLcode Curl_win32_init(long flags)
wVersionRequested = MAKEWORD(2, 2);
res = WSAStartup(wVersionRequested, &wsaData);
- if(res != 0)
+ if(res)
/* Tell the user that we couldn't find a usable */
/* winsock.dll. */
return CURLE_FAILED_INIT;
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
index f96a4cb..a81bb81 100644
--- a/Utilities/cmcurl/lib/telnet.c
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -185,6 +185,7 @@ const struct Curl_handler Curl_handler_telnet = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_TELNET, /* defport */
CURLPROTO_TELNET, /* protocol */
CURLPROTO_TELNET, /* family */
@@ -267,9 +268,9 @@ static void printoption(struct Curl_easy *data,
if(data->set.verbose) {
if(cmd == CURL_IAC) {
if(CURL_TELCMD_OK(option))
- infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
+ infof(data, "%s IAC %s", direction, CURL_TELCMD(option));
else
- infof(data, "%s IAC %d\n", direction, option);
+ infof(data, "%s IAC %d", direction, option);
}
else {
const char *fmt = (cmd == CURL_WILL) ? "WILL" :
@@ -286,12 +287,12 @@ static void printoption(struct Curl_easy *data,
opt = NULL;
if(opt)
- infof(data, "%s %s %s\n", direction, fmt, opt);
+ infof(data, "%s %s %s", direction, fmt, opt);
else
- infof(data, "%s %s %d\n", direction, fmt, option);
+ infof(data, "%s %s %d", direction, fmt, option);
}
else
- infof(data, "%s %d %d\n", direction, cmd, option);
+ infof(data, "%s %d %d", direction, cmd, option);
}
}
}
@@ -764,8 +765,6 @@ static void printsub(struct Curl_easy *data,
break;
}
}
- if(direction)
- infof(data, "\n");
}
}
@@ -833,7 +832,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
else {
failf(data, "Syntax error in telnet option: %s", head->data);
- result = CURLE_TELNET_OPTION_SYNTAX;
+ result = CURLE_SETOPT_OPTION_SYNTAX;
break;
}
continue;
@@ -854,7 +853,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
break;
}
failf(data, "Syntax error in telnet option: %s", head->data);
- result = CURLE_TELNET_OPTION_SYNTAX;
+ result = CURLE_SETOPT_OPTION_SYNTAX;
break;
}
@@ -921,12 +920,17 @@ static void suboption(struct Curl_easy *data)
size_t tmplen = (strlen(v->data) + 1);
/* Add the variable only if it fits */
if(len + tmplen < (int)sizeof(temp)-6) {
- if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
- msnprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
- CURL_NEW_ENV_VALUE, varval);
- len += tmplen;
- }
+ int rv;
+ char sep[2] = "";
+ varval[0] = 0;
+ rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval);
+ if(rv == 1)
+ len += msnprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%s", CURL_NEW_ENV_VAR, varname);
+ else if(rv >= 2)
+ len += msnprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+ CURL_NEW_ENV_VALUE, varval);
}
}
msnprintf((char *)&temp[len], sizeof(temp) - len,
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
index 3f1d1b5..aae997d 100644
--- a/Utilities/cmcurl/lib/tftp.c
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -129,8 +129,6 @@ struct tftp_state_data {
int retries;
int retry_time;
int retry_max;
- time_t start_time;
- time_t max_time;
time_t rx_time;
struct Curl_sockaddr_storage local_addr;
struct Curl_sockaddr_storage remote_addr;
@@ -184,6 +182,7 @@ const struct Curl_handler Curl_handler_tftp = {
tftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_TFTP, /* defport */
CURLPROTO_TFTP, /* protocol */
CURLPROTO_TFTP, /* family */
@@ -206,8 +205,6 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
timediff_t timeout_ms;
bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
- time(&state->start_time);
-
/* Compute drop-dead time */
timeout_ms = Curl_timeleft(state->data, NULL, start);
@@ -217,41 +214,17 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
return CURLE_OPERATION_TIMEDOUT;
}
- if(start) {
-
+ if(timeout_ms > 0)
maxtime = (time_t)(timeout_ms + 500) / 1000;
- state->max_time = state->start_time + maxtime;
-
- /* Set per-block timeout to total */
- timeout = maxtime;
-
- /* Average restart after 5 seconds */
- state->retry_max = (int)timeout/5;
-
- if(state->retry_max < 1)
- /* avoid division by zero below */
- state->retry_max = 1;
-
- /* Compute the re-start interval to suit the timeout */
- state->retry_time = (int)timeout/state->retry_max;
- if(state->retry_time<1)
- state->retry_time = 1;
-
- }
- else {
- if(timeout_ms > 0)
- maxtime = (time_t)(timeout_ms + 500) / 1000;
- else
- maxtime = 3600;
+ else
+ maxtime = 3600; /* use for calculating block timeouts */
- state->max_time = state->start_time + maxtime;
+ /* Set per-block timeout to total */
+ timeout = maxtime;
- /* Set per-block timeout to total */
- timeout = maxtime;
+ /* Average reposting an ACK after 5 seconds */
+ state->retry_max = (int)timeout/5;
- /* Average reposting an ACK after 5 seconds */
- state->retry_max = (int)timeout/5;
- }
/* But bound the total number */
if(state->retry_max<3)
state->retry_max = 3;
@@ -265,9 +238,9 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
state->retry_time = 1;
infof(state->data,
- "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
- (int)state->state, (long)(state->max_time-state->start_time),
- state->retry_time, state->retry_max);
+ "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
+ ", retry %d maxtry %d",
+ (int)state->state, timeout_ms, state->retry_time, state->retry_max);
/* init RX time */
time(&state->rx_time);
@@ -347,12 +320,12 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
const char *option, *value;
tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
- if(tmp == NULL) {
+ if(!tmp) {
failf(data, "Malformed ACK packet, rejecting");
return CURLE_TFTP_ILLEGAL;
}
- infof(data, "got option=(%s) value=(%s)\n", option, value);
+ infof(data, "got option=(%s) value=(%s)", option, value);
if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
long blksize;
@@ -383,14 +356,14 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
}
state->blksize = (int)blksize;
- infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
+ infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
state->blksize, "requested", state->requested_blksize);
}
else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
long tsize = 0;
tsize = strtol(value, NULL, 10);
- infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
+ infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
/* tsize should be ignored on upload: Who cares about the size of the
remote file? */
@@ -424,7 +397,7 @@ static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
struct Curl_easy *data = state->data;
- infof(data, "%s\n", "Connected for transmit");
+ infof(data, "%s", "Connected for transmit");
#endif
state->state = TFTP_STATE_TX;
result = tftp_set_timeouts(state);
@@ -440,7 +413,7 @@ static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
struct Curl_easy *data = state->data;
- infof(data, "%s\n", "Connected for receive");
+ infof(data, "%s", "Connected for receive");
#endif
state->state = TFTP_STATE_RX;
result = tftp_set_timeouts(state);
@@ -460,7 +433,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
CURLcode result = CURLE_OK;
/* Set ascii mode if -B flag was used */
- if(data->set.prefer_ascii)
+ if(data->state.prefer_ascii)
mode = "netascii";
switch(event) {
@@ -623,12 +596,12 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
else if(state->block == rblock) {
/* This is the last recently received block again. Log it and ACK it
again. */
- infof(data, "Received last DATA packet block %d again.\n", rblock);
+ infof(data, "Received last DATA packet block %d again.", rblock);
}
else {
/* totally unexpected, just log it */
infof(data,
- "Received unexpected DATA packet block %d, expecting block %d\n",
+ "Received unexpected DATA packet block %d, expecting block %d",
rblock, NEXT_BLOCKNUM(state->block));
break;
}
@@ -680,7 +653,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
/* Increment the retry count and fail if over the limit */
state->retries++;
infof(data,
- "Timeout waiting for block %d ACK. Retries = %d\n",
+ "Timeout waiting for block %d ACK. Retries = %d",
NEXT_BLOCKNUM(state->block), state->retries);
if(state->retries > state->retry_max) {
state->error = TFTP_ERR_TIMEOUT;
@@ -747,11 +720,11 @@ 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 */
- infof(data, "Received ACK for block %d, expecting %d\n",
+ infof(data, "Received ACK for block %d, expecting %d",
rblock, state->block);
state->retries++;
/* Bail out if over the maximum */
@@ -804,7 +777,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
return result;
state->sbytes += (int)cb;
state->data->req.upload_fromhere += cb;
- } while(state->sbytes < state->blksize && cb != 0);
+ } while(state->sbytes < state->blksize && cb);
sbytes = sendto(state->sockfd, (void *) state->spacket.data,
4 + state->sbytes, SEND_4TH_ARG,
@@ -824,7 +797,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
/* Increment the retry counter and log the timeout */
state->retries++;
infof(data, "Timeout waiting for block %d ACK. "
- " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
+ " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
/* Decide if we've had enough */
if(state->retries > state->retry_max) {
state->error = TFTP_ERR_TIMEOUT;
@@ -933,22 +906,22 @@ static CURLcode tftp_state_machine(struct tftp_state_data *state,
switch(state->state) {
case TFTP_STATE_START:
- DEBUGF(infof(data, "TFTP_STATE_START\n"));
+ DEBUGF(infof(data, "TFTP_STATE_START"));
result = tftp_send_first(state, event);
break;
case TFTP_STATE_RX:
- DEBUGF(infof(data, "TFTP_STATE_RX\n"));
+ DEBUGF(infof(data, "TFTP_STATE_RX"));
result = tftp_rx(state, event);
break;
case TFTP_STATE_TX:
- DEBUGF(infof(data, "TFTP_STATE_TX\n"));
+ DEBUGF(infof(data, "TFTP_STATE_TX"));
result = tftp_tx(state, event);
break;
case TFTP_STATE_FIN:
- infof(data, "%s\n", "TFTP finished");
+ infof(data, "%s", "TFTP finished");
break;
default:
- DEBUGF(infof(data, "STATE: %d\n", state->state));
+ DEBUGF(infof(data, "STATE: %d", state->state));
failf(data, "%s", "Internal state machine error");
result = CURLE_TFTP_ILLEGAL;
break;
@@ -1180,7 +1153,7 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
size_t strn = state->rbytes - 4;
state->error = (tftp_error_t)error;
if(tftp_strnlen(str, strn) < strn)
- infof(data, "TFTP error: %s\n", str);
+ infof(data, "TFTP error: %s", str);
break;
}
case TFTP_EVENT_ACK:
@@ -1215,33 +1188,32 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
* Check if timeouts have been reached
*
**********************************************************/
-static long tftp_state_timeout(struct Curl_easy *data, tftp_event_t *event)
+static timediff_t tftp_state_timeout(struct Curl_easy *data,
+ tftp_event_t *event)
{
time_t current;
struct connectdata *conn = data->conn;
struct tftp_state_data *state = conn->proto.tftpc;
+ timediff_t timeout_ms;
if(event)
*event = TFTP_EVENT_NONE;
- time(&current);
- if(current > state->max_time) {
- DEBUGF(infof(data, "timeout: %ld > %ld\n",
- (long)current, (long)state->max_time));
+ timeout_ms = Curl_timeleft(state->data, NULL,
+ (state->state == TFTP_STATE_START));
+ if(timeout_ms < 0) {
state->error = TFTP_ERR_TIMEOUT;
state->state = TFTP_STATE_FIN;
return 0;
}
+ time(&current);
if(current > state->rx_time + state->retry_time) {
if(event)
*event = TFTP_EVENT_TIMEOUT;
time(&state->rx_time); /* update even though we received nothing */
}
- /* there's a typecast below here since 'time_t' may in fact be larger than
- 'long', but we estimate that a 'long' will still be able to hold number
- of seconds even if "only" 32 bit */
- return (long)(state->max_time - current);
+ return timeout_ms;
}
/**********************************************************
@@ -1257,11 +1229,11 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct tftp_state_data *state = conn->proto.tftpc;
- long timeout_ms = tftp_state_timeout(data, &event);
+ timediff_t timeout_ms = tftp_state_timeout(data, &event);
*done = FALSE;
- if(timeout_ms <= 0) {
+ if(timeout_ms < 0) {
failf(data, "TFTP response timeout");
return CURLE_OPERATION_TIMEDOUT;
}
@@ -1285,7 +1257,7 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
state->event = TFTP_EVENT_ERROR;
}
- else if(rc != 0) {
+ else if(rc) {
result = tftp_receive_packet(data);
if(result)
return result;
@@ -1316,7 +1288,7 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
result = tftp_multi_statemach(data, dophase_done);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
else if(!result) {
/* The multi code doesn't have this logic for the DOING state so we
@@ -1353,7 +1325,7 @@ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
tftp_multi_statemach(data, dophase_done);
if(*dophase_done)
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
return result;
}
@@ -1420,14 +1392,14 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data,
switch(command) {
case 'A': /* ASCII mode */
case 'N': /* NETASCII mode */
- data->set.prefer_ascii = TRUE;
+ data->state.prefer_ascii = TRUE;
break;
case 'O': /* octet mode */
case 'I': /* binary mode */
default:
/* switch off ASCII */
- data->set.prefer_ascii = FALSE;
+ data->state.prefer_ascii = FALSE;
break;
}
}
diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c
index 8523dad..ca98fe5 100644
--- a/Utilities/cmcurl/lib/timeval.c
+++ b/Utilities/cmcurl/lib/timeval.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
@@ -78,14 +78,16 @@ struct curltime Curl_now(void)
** code compiles but fails during run-time if clock_gettime() is
** called on unsupported OS version.
*/
-#if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1)
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+ (HAVE_BUILTIN_AVAILABLE == 1)
bool have_clock_gettime = FALSE;
if(__builtin_available(macOS 10.12, iOS 10, tvOS 10, watchOS 3, *))
have_clock_gettime = TRUE;
#endif
if(
-#if defined(__APPLE__) && (HAVE_BUILTIN_AVAILABLE == 1)
+#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
+ (HAVE_BUILTIN_AVAILABLE == 1)
have_clock_gettime &&
#endif
(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
index 2f29b29..3e650b5 100644
--- a/Utilities/cmcurl/lib/transfer.c
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -79,6 +79,7 @@
#include "strcase.h"
#include "urlapi-int.h"
#include "hsts.h"
+#include "setopt.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -98,6 +99,8 @@ char *Curl_checkheaders(const struct Curl_easy *data,
{
struct curl_slist *head;
size_t thislen = strlen(thisheader);
+ DEBUGASSERT(thislen);
+ DEBUGASSERT(thisheader[thislen-1] != ':');
for(head = data->set.headers; head; head = head->next) {
if(strncasecompare(head->data, thisheader, thislen) &&
@@ -185,7 +188,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
/* at this point we already verified that the callback exists
so we compile and store the trailers buffer, then proceed */
infof(data,
- "Moving trailers state machine from initialized to sending.\n");
+ "Moving trailers state machine from initialized to sending.");
data->state.trailers_state = TRAILERS_SENDING;
Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS);
@@ -208,7 +211,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
curl_slist_free_all(trailers);
return result;
}
- infof(data, "Successfully compiled trailers.\r\n");
+ infof(data, "Successfully compiled trailers.");
curl_slist_free_all(trailers);
}
#endif
@@ -286,7 +289,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
* <DATA> CRLF
*/
/* On non-ASCII platforms the <DATA> may or may not be
- translated based on set.prefer_ascii while the protocol
+ translated based on state.prefer_ascii while the protocol
portion must always be translated to the network encoding.
To further complicate matters, line end conversion might be
done later on, so we need to prevent CRLFs from becoming
@@ -301,7 +304,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
if(
#ifdef CURL_DO_LINEEND_CONV
- (data->set.prefer_ascii) ||
+ (data->state.prefer_ascii) ||
#endif
(data->set.crlf)) {
/* \n will become \r\n later on */
@@ -348,7 +351,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
{
CURLcode result;
size_t length;
- if(data->set.prefer_ascii)
+ if(data->state.prefer_ascii)
/* translate the protocol and data */
length = nread;
else
@@ -373,7 +376,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
data->set.trailer_callback = NULL;
/* mark the transfer as done */
data->req.upload_done = TRUE;
- infof(data, "Signaling end of chunked upload after trailers.\n");
+ infof(data, "Signaling end of chunked upload after trailers.");
}
else
#endif
@@ -382,14 +385,14 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
/* mark this as done once this chunk is transferred */
data->req.upload_done = TRUE;
infof(data,
- "Signaling end of chunked upload via terminating chunk.\n");
+ "Signaling end of chunked upload via terminating chunk.");
}
if(added_crlf)
nread += strlen(endofline_network); /* for the added end of line */
}
#ifdef CURL_DOES_CONVERSIONS
- else if((data->set.prefer_ascii) && (!sending_http_headers)) {
+ else if((data->state.prefer_ascii) && (!sending_http_headers)) {
CURLcode result;
result = Curl_convert_to_network(data, data->req.upload_fromhere, nread);
/* Curl_convert_to_network calls failf if unsuccessful */
@@ -460,7 +463,7 @@ CURLcode Curl_readrewind(struct Curl_easy *data)
err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
data->set.ioctl_client);
Curl_set_in_callback(data, false);
- infof(data, "the ioctl callback returned %d\n", (int)err);
+ infof(data, "the ioctl callback returned %d", (int)err);
if(err) {
failf(data, "ioctl callback returned error %d", (int)err);
@@ -494,11 +497,13 @@ static int data_pending(const struct Curl_easy *data)
return Curl_quic_data_pending(data);
#endif
+ if(conn->handler->protocol&PROTO_FAMILY_FTP)
+ return Curl_ssl_data_pending(conn, SECONDARYSOCKET);
+
/* in the case of libssh2, we can never be really sure that we have emptied
its internal buffers so we MUST always try until we get EAGAIN back */
return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
#if defined(USE_NGHTTP2)
- Curl_ssl_data_pending(conn, FIRSTSOCKET) ||
/* For HTTP/2, we may read up everything including response body
with header fields in Curl_http_readwrite_headers. If no
content-length is provided, curl waits for the connection
@@ -506,10 +511,9 @@ static int data_pending(const struct Curl_easy *data)
TRUE. The thing is if we read everything, then http2_recv won't
be called and we cannot signal the HTTP/2 stream has closed. As
a workaround, we return nonzero here to call http2_recv. */
- ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20);
-#else
- Curl_ssl_data_pending(conn, FIRSTSOCKET);
+ ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20) ||
#endif
+ Curl_ssl_data_pending(conn, FIRSTSOCKET);
}
/*
@@ -526,7 +530,7 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
default:
if(timeofdoc <= data->set.timevalue) {
infof(data,
- "The requested document is not new enough\n");
+ "The requested document is not new enough");
data->info.timecond = TRUE;
return FALSE;
}
@@ -534,7 +538,7 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
case CURL_TIMECOND_IFUNMODSINCE:
if(timeofdoc >= data->set.timevalue) {
infof(data,
- "The requested document is not old enough\n");
+ "The requested document is not old enough");
data->info.timecond = TRUE;
return FALSE;
}
@@ -611,7 +615,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
else {
/* read nothing but since we wanted nothing we consider this an OK
situation to proceed from */
- DEBUGF(infof(data, "readwrite_data: we're done!\n"));
+ DEBUGF(infof(data, "readwrite_data: we're done!"));
nread = 0;
}
@@ -634,10 +638,10 @@ static CURLcode readwrite_data(struct Curl_easy *data,
server closed the connection and we bail out from this! */
#ifdef USE_NGHTTP2
if(is_http2 && !nread)
- DEBUGF(infof(data, "nread == 0, stream closed, bailing\n"));
+ DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
else
#endif
- DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
+ DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
k->keepon &= ~KEEP_RECV;
break;
}
@@ -680,7 +684,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data,
"Excess found:"
" excess = %zd"
- " url = %s (zero-length body)\n",
+ " url = %s (zero-length body)",
nread, data->state.up.path);
}
@@ -760,7 +764,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
written to the client. */
if(conn->chunk.datasize) {
infof(data, "Leftovers after chunking: % "
- CURL_FORMAT_CURL_OFF_T "u bytes\n",
+ CURL_FORMAT_CURL_OFF_T "u bytes",
conn->chunk.datasize);
}
}
@@ -771,7 +775,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* Account for body content stored in the header buffer */
if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) {
size_t headlen = Curl_dyn_len(&data->state.headerb);
- DEBUGF(infof(data, "Increasing bytecount by %zu\n", headlen));
+ DEBUGF(infof(data, "Increasing bytecount by %zu", headlen));
k->bytecount += headlen;
}
@@ -785,7 +789,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
" excess = %zu"
", size = %" CURL_FORMAT_CURL_OFF_T
", maxdownload = %" CURL_FORMAT_CURL_OFF_T
- ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n",
+ ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
excess, k->size, k->maxdownload, k->bytecount);
connclose(conn, "excess found in a read");
}
@@ -829,7 +833,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
Make sure that ALL_CONTENT_ENCODINGS contains all the
encodings handled here. */
if(data->set.http_ce_skip || !k->writer_stack) {
- if(!k->ignorebody) {
+ if(!k->ignorebody && nread) {
#ifndef CURL_DISABLE_POP3
if(conn->handler->protocol & PROTO_FAMILY_POP3)
result = Curl_pop3_write(data, k->str, nread);
@@ -839,7 +843,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
nread);
}
}
- else if(!k->ignorebody)
+ else if(!k->ignorebody && nread)
result = Curl_unencode_write(data, k->writer_stack, k->str, nread);
}
k->badheader = HEADER_NORMAL; /* taken care of now */
@@ -894,7 +898,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* When we've read the entire thing and the close bit is set, the server
may now close the connection. If there's now any kind of sending going
on from our side, we need to stop that immediately. */
- infof(data, "we are done reading and this is set to close, stop send\n");
+ infof(data, "we are done reading and this is set to close, stop send");
k->keepon &= ~KEEP_SEND; /* no writing anymore either */
}
@@ -919,7 +923,7 @@ CURLcode Curl_done_sending(struct Curl_easy *data,
return CURLE_OK;
}
-#if defined(WIN32) && !defined(USE_LWIPSOCK)
+#if defined(WIN32) && defined(USE_WINSOCK)
#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
#endif
@@ -1028,7 +1032,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
if((!sending_http_headers) && (
#ifdef CURL_DO_LINEEND_CONV
/* always convert if we're FTPing in ASCII mode */
- (data->set.prefer_ascii) ||
+ (data->state.prefer_ascii) ||
#endif
(data->set.crlf))) {
/* Do we need to allocate a scratch buffer? */
@@ -1124,7 +1128,7 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
(k->writebytecount == data->state.infilesize)) {
/* we have sent all data we were supposed to */
k->upload_done = TRUE;
- infof(data, "We are completely uploaded and fine\n");
+ infof(data, "We are completely uploaded and fine");
}
if(k->upload_present != bytes_written) {
@@ -1195,7 +1199,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(data->state.drain) {
select_res |= CURL_CSELECT_IN;
- DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n"));
+ DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data"));
}
if(!select_res) /* Call for select()/poll() only, if read/write/error
@@ -1208,8 +1212,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
}
#ifdef USE_HYPER
- if(conn->datastream)
- return conn->datastream(data, conn, &didwhat, done, select_res);
+ if(conn->datastream) {
+ result = conn->datastream(data, conn, &didwhat, done, select_res);
+ if(result || *done)
+ return result;
+ }
+ else {
#endif
/* We go ahead and do a read if we have a readable socket or if
the stream was rewound (in which case we have data in a
@@ -1228,6 +1236,9 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(result)
return result;
}
+#ifdef USE_HYPER
+ }
+#endif
k->now = Curl_now();
if(!didwhat) {
@@ -1252,7 +1263,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
k->exp100 = EXP100_SEND_DATA;
k->keepon |= KEEP_SEND;
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
- infof(data, "Done waiting for 100-continue\n");
+ infof(data, "Done waiting for 100-continue");
}
}
}
@@ -1391,20 +1402,20 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
{
CURLcode result;
- if(!data->change.url && !data->set.uh) {
+ if(!data->state.url && !data->set.uh) {
/* we can't do anything without URL */
failf(data, "No URL set!");
return CURLE_URL_MALFORMAT;
}
/* since the URL may have been redirected in a previous use of this handle */
- if(data->change.url_alloc) {
+ if(data->state.url_alloc) {
/* the already set URL is allocated, free it first! */
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
+ Curl_safefree(data->state.url);
+ data->state.url_alloc = FALSE;
}
- if(!data->change.url && data->set.uh) {
+ if(!data->state.url && data->set.uh) {
CURLUcode uc;
free(data->set.str[STRING_SET_URL]);
uc = curl_url_get(data->set.uh,
@@ -1415,8 +1426,10 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
}
+ data->state.prefer_ascii = data->set.prefer_ascii;
+ data->state.list_only = data->set.list_only;
data->state.httpreq = data->set.method;
- data->change.url = data->set.str[STRING_SET_URL];
+ data->state.url = data->set.str[STRING_SET_URL];
/* Init the SSL session ID cache here. We do it here since we want to do it
after the *_setopt() calls (that could specify the size of the cache) but
@@ -1426,11 +1439,11 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return result;
data->state.wildcardmatch = data->set.wildcard_enabled;
- data->set.followlocation = 0; /* reset the location-follow counter */
+ data->state.followlocation = 0; /* reset the location-follow counter */
data->state.this_is_a_follow = FALSE; /* reset this */
data->state.errorbuf = FALSE; /* no error has occurred */
- data->state.httpversion = 0; /* don't assume any particular server version */
-
+ data->state.httpwant = data->set.httpwant;
+ data->state.httpversion = 0;
data->state.authproblem = FALSE;
data->state.authhost.want = data->set.httpauth;
data->state.authproxy.want = data->set.proxyauth;
@@ -1448,11 +1461,11 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
data->state.infilesize = 0;
/* If there is a list of cookie files to read, do it now! */
- if(data->change.cookielist)
+ if(data->state.cookielist)
Curl_cookie_loadfiles(data);
/* If there is a list of host pairs to deal with */
- if(data->change.resolve)
+ if(data->state.resolve)
result = Curl_loadhostpairs(data);
if(!result) {
@@ -1506,6 +1519,19 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.user,
+ data->set.str[STRING_USERNAME]);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.passwd,
+ data->set.str[STRING_PASSWORD]);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxyuser,
+ data->set.str[STRING_PROXYUSERNAME]);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxypasswd,
+ data->set.str[STRING_PROXYPASSWORD]);
+
data->req.headerbytecount = 0;
return result;
}
@@ -1553,7 +1579,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
if(type == FOLLOW_REDIR) {
if((data->set.maxredirs != -1) &&
- (data->set.followlocation >= data->set.maxredirs)) {
+ (data->state.followlocation >= data->set.maxredirs)) {
reachedmax = TRUE;
type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
to URL */
@@ -1562,22 +1588,43 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* mark the next request as a followed location: */
data->state.this_is_a_follow = TRUE;
- data->set.followlocation++; /* count location-followers */
+ data->state.followlocation++; /* count location-followers */
if(data->set.http_auto_referer) {
+ CURLU *u;
+ char *referer = NULL;
+
/* We are asked to automatically set the previous URL as the referer
when we get the next URL. We pick the ->url field, which may or may
not be 100% correct */
- if(data->change.referer_alloc) {
- Curl_safefree(data->change.referer);
- data->change.referer_alloc = FALSE;
+ if(data->state.referer_alloc) {
+ Curl_safefree(data->state.referer);
+ data->state.referer_alloc = FALSE;
}
- data->change.referer = strdup(data->change.url);
- if(!data->change.referer)
+ /* Make a copy of the URL without crenditals and fragment */
+ u = curl_url();
+ if(!u)
return CURLE_OUT_OF_MEMORY;
- data->change.referer_alloc = TRUE; /* yes, free this later */
+
+ uc = curl_url_set(u, CURLUPART_URL, data->state.url, 0);
+ if(!uc)
+ uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
+ if(!uc)
+ uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
+ if(!uc)
+ uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
+ if(!uc)
+ uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
+
+ curl_url_cleanup(u);
+
+ if(uc || !referer)
+ return CURLE_OUT_OF_MEMORY;
+
+ data->state.referer = referer;
+ data->state.referer_alloc = TRUE; /* yes, free this later */
}
}
}
@@ -1592,7 +1639,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
DEBUGASSERT(data->state.uh);
uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
(type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
- ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) );
+ ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
+ CURLU_ALLOW_SPACE);
if(uc) {
if(type != FOLLOW_FAKE)
return Curl_uc_to_curlcode(uc);
@@ -1625,13 +1673,13 @@ CURLcode Curl_follow(struct Curl_easy *data,
if(disallowport)
data->state.allow_port = FALSE;
- if(data->change.url_alloc)
- Curl_safefree(data->change.url);
+ if(data->state.url_alloc)
+ Curl_safefree(data->state.url);
- data->change.url = newurl;
- data->change.url_alloc = TRUE;
+ data->state.url = newurl;
+ data->state.url_alloc = TRUE;
- infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
+ infof(data, "Issue another request to this URL: '%s'", data->state.url);
/*
* We get here when the HTTP code is 300-399 (and 401). We need to perform
@@ -1674,7 +1722,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
|| data->state.httpreq == HTTPREQ_POST_FORM
|| data->state.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
- infof(data, "Switch from POST to GET\n");
+ infof(data, "Switch from POST to GET");
data->state.httpreq = HTTPREQ_GET;
}
break;
@@ -1699,7 +1747,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
|| data->state.httpreq == HTTPREQ_POST_FORM
|| data->state.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
- infof(data, "Switch from POST to GET\n");
+ infof(data, "Switch from POST to GET");
data->state.httpreq = HTTPREQ_GET;
}
break;
@@ -1717,7 +1765,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
!(data->set.keep_post & CURL_REDIR_POST_303))) {
data->state.httpreq = HTTPREQ_GET;
data->set.upload = false;
- infof(data, "Switch to %s\n",
+ infof(data, "Switch to %s",
data->set.opt_no_body?"HEAD":"GET");
}
break;
@@ -1778,7 +1826,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
to issue again, but the nghttp2 API can deliver the message to other
streams as well, which is why this adds the check the data counters
too. */
- infof(data, "REFUSED_STREAM, retrying a fresh connect\n");
+ infof(data, "REFUSED_STREAM, retrying a fresh connect");
data->state.refused_stream = FALSE; /* clear again */
retry = TRUE;
}
@@ -1790,9 +1838,9 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
data->state.retrycount = 0;
return CURLE_SEND_ERROR;
}
- infof(data, "Connection died, retrying a fresh connect\
-(retry count: %d)\n", data->state.retrycount);
- *url = strdup(data->change.url);
+ infof(data, "Connection died, retrying a fresh connect (retry count: %d)",
+ data->state.retrycount);
+ *url = strdup(data->state.url);
if(!*url)
return CURLE_OUT_OF_MEMORY;
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index c02d2c2..37b6c0e 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -62,6 +62,14 @@
#ifdef USE_LIBIDN2
#include <idn2.h>
+#if defined(WIN32) && defined(UNICODE)
+#define IDN2_LOOKUP(name, host, flags) \
+ idn2_lookup_u8((const uint8_t *)name, (uint8_t **)host, flags)
+#else
+#define IDN2_LOOKUP(name, host, flags) \
+ idn2_lookup_ul((const char *)name, (char **)host, flags)
+#endif
+
#elif defined(USE_WIN32_IDN)
/* prototype for curl_win32_idn_to_ascii() */
bool curl_win32_idn_to_ascii(const char *in, char **out);
@@ -92,7 +100,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "speedcheck.h"
#include "warnless.h"
#include "non-ascii.h"
-#include "inet_pton.h"
#include "getinfo.h"
#include "urlapi-int.h"
#include "system_win32.h"
@@ -234,7 +241,7 @@ static const struct Curl_handler * const protocols[] = {
#endif
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (CURL_SIZEOF_CURL_OFF_T > 4)
+ (SIZEOF_CURL_OFF_T > 4)
&Curl_handler_smb,
#ifdef USE_SSL
&Curl_handler_smbs,
@@ -292,6 +299,7 @@ static const struct Curl_handler Curl_handler_dummy = {
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
0, /* defport */
0, /* protocol */
0, /* family */
@@ -312,16 +320,16 @@ void Curl_freeset(struct Curl_easy *data)
Curl_safefree(data->set.blobs[j]);
}
- if(data->change.referer_alloc) {
- Curl_safefree(data->change.referer);
- data->change.referer_alloc = FALSE;
+ if(data->state.referer_alloc) {
+ Curl_safefree(data->state.referer);
+ data->state.referer_alloc = FALSE;
}
- data->change.referer = NULL;
- if(data->change.url_alloc) {
- Curl_safefree(data->change.url);
- data->change.url_alloc = FALSE;
+ data->state.referer = NULL;
+ if(data->state.url_alloc) {
+ Curl_safefree(data->state.url);
+ data->state.url_alloc = FALSE;
}
- data->change.url = NULL;
+ data->state.url = NULL;
Curl_mime_cleanpart(&data->set.mimepost);
}
@@ -405,11 +413,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
free(data->req.newurl);
data->req.newurl = NULL;
- if(data->change.referer_alloc) {
- Curl_safefree(data->change.referer);
- data->change.referer_alloc = FALSE;
+ if(data->state.referer_alloc) {
+ Curl_safefree(data->state.referer);
+ data->state.referer_alloc = FALSE;
}
- data->change.referer = NULL;
+ data->state.referer = NULL;
up_free(data);
Curl_safefree(data->state.buffer);
@@ -449,6 +457,10 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.host);
Curl_safefree(data->state.aptr.cookiehost);
Curl_safefree(data->state.aptr.rtsp_transport);
+ Curl_safefree(data->state.aptr.user);
+ Curl_safefree(data->state.aptr.passwd);
+ Curl_safefree(data->state.aptr.proxyuser);
+ Curl_safefree(data->state.aptr.proxypasswd);
#ifndef CURL_DISABLE_DOH
if(data->req.doh) {
@@ -530,6 +542,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
* libcurl 7.10 introduced SSL verification *by default*! This needs to be
* switched off unless wanted.
*/
+ set->doh_verifyhost = TRUE;
+ set->doh_verifypeer = TRUE;
set->ssl.primary.verifypeer = TRUE;
set->ssl.primary.verifyhost = TRUE;
#ifdef USE_TLS_SRP
@@ -569,7 +583,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
*/
if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
#if defined(CURL_CA_BUNDLE)
- result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
+ result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
if(result)
return result;
@@ -579,7 +593,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
return result;
#endif
#if defined(CURL_CA_PATH)
- result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
+ result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
if(result)
return result;
@@ -609,7 +623,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
set->http09_allowed = FALSE;
- set->httpversion =
+ set->httpwant =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
#else
@@ -719,7 +733,16 @@ static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
{
DEBUGASSERT(conn);
DEBUGASSERT(data);
- infof(data, "Closing connection %ld\n", conn->connection_id);
+ infof(data, "Closing connection %ld", conn->connection_id);
+
+#ifndef USE_HYPER
+ if(conn->connect_state && conn->connect_state->prot_save) {
+ /* If this was closed with a CONNECT in progress, cleanup this temporary
+ struct arrangement */
+ data->req.p.http = NULL;
+ Curl_safefree(conn->connect_state->prot_save);
+ }
+#endif
/* possible left-overs from the async name resolvers */
Curl_resolver_cancel(data);
@@ -817,7 +840,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
* are other users of it
*/
if(CONN_INUSE(conn) && !dead_connection) {
- DEBUGF(infof(data, "Curl_disconnect when inuse: %zu\n", CONN_INUSE(conn)));
+ DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
return CURLE_OK;
}
@@ -837,7 +860,7 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
dead_connection = TRUE;
/* temporarily attach the connection to this transfer handle for the
- disonnect and shutdown */
+ disconnect and shutdown */
Curl_attach_connnection(data, conn);
if(conn->handler->disconnect)
@@ -887,7 +910,7 @@ static int IsMultiplexingPossible(const struct Curl_easy *handle,
(!conn->bits.protoconnstart || !conn->bits.close)) {
if(Curl_multiplex_wanted(handle->multi) &&
- (handle->set.httpversion >= CURL_HTTP_VERSION_2))
+ (handle->state.httpwant >= CURL_HTTP_VERSION_2))
/* allows HTTP/2 */
avail |= CURLPIPE_MULTIPLEX;
}
@@ -917,14 +940,14 @@ socks_proxy_info_matches(const struct proxy_info *data,
/* the user information is case-sensitive
or at least it is not defined as case-insensitive
see https://tools.ietf.org/html/rfc3986#section-3.2.1 */
- if((data->user == NULL) != (needle->user == NULL))
+ if(!data->user != !needle->user)
return FALSE;
/* curl_strequal does a case insentive comparison, so do not use it here! */
if(data->user &&
needle->user &&
strcmp(data->user, needle->user) != 0)
return FALSE;
- if((data->passwd == NULL) != (needle->passwd == NULL))
+ if(!data->passwd != !needle->passwd)
return FALSE;
/* curl_strequal does a case insentive comparison, so do not use it here! */
if(data->passwd &&
@@ -950,7 +973,7 @@ static bool conn_maxage(struct Curl_easy *data,
idletime /= 1000; /* integer seconds is fine */
if(idletime > data->set.maxage_conn) {
- infof(data, "Too old connection (%ld seconds), disconnect it\n",
+ infof(data, "Too old connection (%ld seconds), disconnect it",
idletime);
return TRUE;
}
@@ -986,12 +1009,12 @@ static bool extract_if_dead(struct connectdata *conn,
/* briefly attach the connection to this transfer for the purpose of
checking it */
Curl_attach_connnection(data, conn);
- conn->data = data; /* find the way back if necessary */
+
state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
dead = (state & CONNRESULT_DEAD);
/* detach the connection again */
Curl_detach_connnection(data);
- conn->data = NULL; /* clear it again */
+
}
else {
/* Use the general method for determining the death of a connection */
@@ -999,7 +1022,7 @@ static bool extract_if_dead(struct connectdata *conn,
}
if(dead) {
- infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
+ infof(data, "Connection %ld seems to be dead!", conn->connection_id);
Curl_conncache_remove_conn(data, conn, FALSE);
return TRUE;
}
@@ -1092,13 +1115,13 @@ ConnectionExists(struct Curl_easy *data,
#ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want &
- (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP));
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP));
#ifndef CURL_DISABLE_PROXY
bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
- ((data->state.authproxy.want &
- (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP)));
+ ((data->state.authproxy.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP)));
#else
bool wantProxyNTLMhttp = FALSE;
#endif
@@ -1115,7 +1138,7 @@ ConnectionExists(struct Curl_easy *data,
/* Max pipe length is zero (unlimited) for multiplexed connections */
struct Curl_llist_element *curr;
- infof(data, "Found bundle for host %s: %p [%s]\n",
+ infof(data, "Found bundle for host %s: %p [%s]",
hostbundle, (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
"can multiplex" : "serially"));
@@ -1123,22 +1146,22 @@ ConnectionExists(struct Curl_easy *data,
if(canmultiplex) {
if(bundle->multiuse == BUNDLE_UNKNOWN) {
if(data->set.pipewait) {
- infof(data, "Server doesn't support multiplex yet, wait\n");
+ infof(data, "Server doesn't support multiplex yet, wait");
*waitpipe = TRUE;
CONNCACHE_UNLOCK(data);
return FALSE; /* no re-use */
}
- infof(data, "Server doesn't support multiplex (yet)\n");
+ infof(data, "Server doesn't support multiplex (yet)");
canmultiplex = FALSE;
}
if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
!Curl_multiplex_wanted(data->multi)) {
- infof(data, "Could multiplex, but not asked to!\n");
+ infof(data, "Could multiplex, but not asked to!");
canmultiplex = FALSE;
}
if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
- infof(data, "Can not multiplex, even if we wanted to!\n");
+ infof(data, "Can not multiplex, even if we wanted to!");
canmultiplex = FALSE;
}
}
@@ -1165,6 +1188,12 @@ ConnectionExists(struct Curl_easy *data,
continue;
}
+ if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
+ && data->set.ipver != check->ip_version) {
+ /* skip because the connection is not via the requested IP version */
+ continue;
+ }
+
if(bundle->multiuse == BUNDLE_MULTIPLEX)
multiplexed = CONN_INUSE(check);
@@ -1180,7 +1209,7 @@ ConnectionExists(struct Curl_easy *data,
completed yet and until then we don't re-use this connection */
if(!check->primary_ip[0]) {
infof(data,
- "Connection #%ld is still name resolving, can't reuse\n",
+ "Connection #%ld is still name resolving, can't reuse",
check->connection_id);
continue;
}
@@ -1189,7 +1218,7 @@ ConnectionExists(struct Curl_easy *data,
if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) {
foundPendingCandidate = TRUE;
/* Don't pick a connection that hasn't connected yet */
- infof(data, "Connection #%ld isn't open enough, can't reuse\n",
+ infof(data, "Connection #%ld isn't open enough, can't reuse",
check->connection_id);
continue;
}
@@ -1266,17 +1295,19 @@ ConnectionExists(struct Curl_easy *data,
}
#endif
- DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data));
-
- if(!canmultiplex && check->data)
+ if(!canmultiplex && CONN_INUSE(check))
/* this request can't be multiplexed but the checked connection is
already in use so we skip it */
continue;
- if(check->data && (check->data->multi != needle->data->multi))
- /* this could be subject for multiplex use, but only if they belong to
- * the same multi handle */
- continue;
+ if(CONN_INUSE(check)) {
+ /* Subject for multiplex use if 'checks' belongs to the same multi
+ handle as 'data' is. */
+ struct Curl_llist_element *e = check->easyq.head;
+ struct Curl_easy *entry = e->ptr;
+ if(entry->multi != data->multi)
+ continue;
+ }
if(needle->localdev || needle->localport) {
/* If we are bound to a specific local end (IP+port), we must not
@@ -1307,6 +1338,13 @@ ConnectionExists(struct Curl_easy *data,
}
}
+ /* If multiplexing isn't enabled on the h2 connection and h1 is
+ explicitly requested, handle it: */
+ if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (check->httpversion >= 20) &&
+ (data->state.httpwant < CURL_HTTP_VERSION_2_0))
+ continue;
+
if((needle->handler->flags&PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
|| !needle->bits.httpproxy || needle->bits.tunnel_proxy
@@ -1335,7 +1373,7 @@ ConnectionExists(struct Curl_easy *data,
&check->ssl_config)) {
DEBUGF(infof(data,
"Connection #%ld has different SSL parameters, "
- "can't reuse\n",
+ "can't reuse",
check->connection_id));
continue;
}
@@ -1343,7 +1381,7 @@ ConnectionExists(struct Curl_easy *data,
foundPendingCandidate = TRUE;
DEBUGF(infof(data,
"Connection #%ld has not started SSL connect, "
- "can't reuse\n",
+ "can't reuse",
check->connection_id));
continue;
}
@@ -1430,14 +1468,14 @@ ConnectionExists(struct Curl_easy *data,
/* Multiplexed connections can only be HTTP/2 for now */
struct http_conn *httpc = &check->proto.httpc;
if(multiplexed >= httpc->settings.max_concurrent_streams) {
- infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n",
+ infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
multiplexed);
continue;
}
else if(multiplexed >=
- Curl_multi_max_concurrent_streams(needle->data->multi)) {
+ Curl_multi_max_concurrent_streams(data->multi)) {
infof(data, "client side MAX_CONCURRENT_STREAMS reached"
- ", skip (%zu)\n",
+ ", skip (%zu)",
multiplexed);
continue;
}
@@ -1445,7 +1483,7 @@ ConnectionExists(struct Curl_easy *data,
#endif
/* When not multiplexed, we have a match here! */
chosen = check;
- infof(data, "Multiplexed connection found!\n");
+ infof(data, "Multiplexed connection found!");
break;
}
else {
@@ -1459,7 +1497,6 @@ ConnectionExists(struct Curl_easy *data,
if(chosen) {
/* mark it as used before releasing the lock */
- chosen->data = data; /* own it! */
Curl_attach_connnection(data, chosen);
CONNCACHE_UNLOCK(data);
*usethis = chosen;
@@ -1469,7 +1506,7 @@ ConnectionExists(struct Curl_easy *data,
if(foundPendingCandidate && data->set.pipewait) {
infof(data,
- "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n");
+ "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
*waitpipe = TRUE;
}
@@ -1484,7 +1521,7 @@ void Curl_verboseconnect(struct Curl_easy *data,
struct connectdata *conn)
{
if(data->set.verbose)
- infof(data, "Connected to %s (%s) port %ld (#%ld)\n",
+ infof(data, "Connected to %s (%s) port %u (#%ld)",
#ifndef CURL_DISABLE_PROXY
conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
conn->bits.httpproxy ? conn->http_proxy.host.dispname :
@@ -1556,12 +1593,12 @@ CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
#else
int flags = IDN2_NFC_INPUT;
#endif
- int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags);
+ int rc = IDN2_LOOKUP(host->name, &ace_hostname, flags);
if(rc != IDN2_OK)
/* fallback to TR46 Transitional mode for better IDNA2003
compatibility */
- rc = idn2_lookup_ul((const char *)host->name, &ace_hostname,
- IDN2_TRANSITIONAL);
+ rc = IDN2_LOOKUP(host->name, &ace_hostname,
+ IDN2_TRANSITIONAL);
if(rc == IDN2_OK) {
host->encalloc = (char *)ace_hostname;
/* change the name pointer to point to the encoded hostname */
@@ -1588,7 +1625,7 @@ CURLcode Curl_idnconvert_hostname(struct Curl_easy *data,
return CURLE_URL_MALFORMAT;
}
#else
- infof(data, "IDN support not present, can't parse Unicode domains\n");
+ infof(data, "IDN support not present, can't parse Unicode domains");
#endif
}
return CURLE_OK;
@@ -1674,9 +1711,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
/* Store current time to give a baseline to keepalive connection times. */
conn->keepalive = Curl_now();
- conn->data = data; /* Setup the association between this connection
- and the Curl_easy */
-
#ifndef CURL_DISABLE_PROXY
conn->http_proxy.proxytype = data->set.proxytype;
conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
@@ -1699,11 +1733,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
}
conn->bits.proxy_user_passwd =
- (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE;
+ (data->state.aptr.proxyuser) ? TRUE : FALSE;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
#endif /* CURL_DISABLE_PROXY */
- conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE;
+ conn->bits.user_passwd = (data->state.aptr.user) ? TRUE : FALSE;
#ifndef CURL_DISABLE_FTP
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
@@ -1858,9 +1892,13 @@ static void zonefrom_url(CURLU *uh, struct Curl_easy *data,
#else
scopeidx = if_nametoindex(zoneid);
#endif
- if(!scopeidx)
- infof(data, "Invalid zoneid: %s; %s\n", zoneid,
- strerror(errno));
+ if(!scopeidx) {
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ char buffer[STRERROR_LEN];
+ infof(data, "Invalid zoneid: %s; %s", zoneid,
+ Curl_strerror(errno, buffer, sizeof(buffer)));
+#endif
+ }
else
conn->scope_id = scopeidx;
}
@@ -1896,28 +1934,27 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
if(data->set.str[STRING_DEFAULT_PROTOCOL] &&
- !Curl_is_absolute_url(data->change.url, NULL, MAX_SCHEME_LEN)) {
- char *url;
- if(data->change.url_alloc)
- free(data->change.url);
- url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
- data->change.url);
+ !Curl_is_absolute_url(data->state.url, NULL, MAX_SCHEME_LEN)) {
+ char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL],
+ data->state.url);
if(!url)
return CURLE_OUT_OF_MEMORY;
- data->change.url = url;
- data->change.url_alloc = TRUE;
+ if(data->state.url_alloc)
+ free(data->state.url);
+ data->state.url = url;
+ data->state.url_alloc = TRUE;
}
if(!use_set_uh) {
char *newurl;
- uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
+ uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
(data->set.disallow_username_in_url ?
CURLU_DISALLOW_USER : 0) |
(data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
if(uc) {
- DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
+ DEBUGF(infof(data, "curl_url_set rejected %s", data->state.url));
return Curl_uc_to_curlcode(uc);
}
@@ -1925,10 +1962,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
- if(data->change.url_alloc)
- free(data->change.url);
- data->change.url = newurl;
- data->change.url_alloc = TRUE;
+ if(data->state.url_alloc)
+ free(data->state.url);
+ data->state.url = newurl;
+ data->state.url_alloc = TRUE;
}
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
@@ -1941,7 +1978,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
if(data->hsts && strcasecompare("http", data->state.up.scheme)) {
if(Curl_hsts(data->hsts, data->state.up.hostname, TRUE)) {
char *url;
@@ -1949,19 +1986,21 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0);
if(uc)
return Curl_uc_to_curlcode(uc);
- if(data->change.url_alloc)
- Curl_safefree(data->change.url);
+ if(data->state.url_alloc)
+ Curl_safefree(data->state.url);
/* after update, get the updated version */
uc = curl_url_get(uh, CURLUPART_URL, &url, 0);
if(uc)
return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
- if(uc)
+ if(uc) {
+ free(url);
return Curl_uc_to_curlcode(uc);
- data->change.url = url;
- data->change.url_alloc = TRUE;
- infof(data, "Switched from HTTP to HTTPS due to HSTS => %s\n",
- data->change.url);
+ }
+ data->state.url = url;
+ data->state.url_alloc = TRUE;
+ infof(data, "Switched from HTTP to HTTPS due to HSTS => %s",
+ data->state.url);
}
}
#endif
@@ -1970,36 +2009,50 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(result)
return result;
- /* we don't use the URL API's URL decoder option here since it rejects
- control codes and we want to allow them for some schemes in the user and
- password fields */
- uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
- if(!uc) {
- char *decoded;
- result = Curl_urldecode(NULL, data->state.up.user, 0, &decoded, NULL,
- conn->handler->flags&PROTOPT_USERPWDCTRL ?
- REJECT_ZERO : REJECT_CTRL);
- if(result)
- return result;
- conn->user = decoded;
- conn->bits.user_passwd = TRUE;
+ /*
+ * User name and password set with their own options override the
+ * credentials possibly set in the URL.
+ */
+ if(!data->state.aptr.user) {
+ /* we don't use the URL API's URL decoder option here since it rejects
+ control codes and we want to allow them for some schemes in the user
+ and password fields */
+ uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
+ if(!uc) {
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.user, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->user = decoded;
+ conn->bits.user_passwd = TRUE;
+ result = Curl_setstropt(&data->state.aptr.user, decoded);
+ if(result)
+ return result;
+ }
+ else if(uc != CURLUE_NO_USER)
+ return Curl_uc_to_curlcode(uc);
}
- else if(uc != CURLUE_NO_USER)
- return Curl_uc_to_curlcode(uc);
- uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
- if(!uc) {
- char *decoded;
- result = Curl_urldecode(NULL, data->state.up.password, 0, &decoded, NULL,
- conn->handler->flags&PROTOPT_USERPWDCTRL ?
- REJECT_ZERO : REJECT_CTRL);
- if(result)
- return result;
- conn->passwd = decoded;
- conn->bits.user_passwd = TRUE;
+ if(!data->state.aptr.passwd) {
+ uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
+ if(!uc) {
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.password, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->passwd = decoded;
+ conn->bits.user_passwd = TRUE;
+ result = Curl_setstropt(&data->state.aptr.passwd, decoded);
+ if(result)
+ return result;
+ }
+ else if(uc != CURLUE_NO_PASSWORD)
+ return Curl_uc_to_curlcode(uc);
}
- else if(uc != CURLUE_NO_PASSWORD)
- return Curl_uc_to_curlcode(uc);
uc = curl_url_get(uh, CURLUPART_OPTIONS, &data->state.up.options,
CURLU_URLDECODE);
@@ -2300,7 +2353,7 @@ static char *detect_proxy(struct Curl_easy *data,
}
}
if(proxy)
- infof(data, "Uses proxy env variable %s == '%s'\n", envp, proxy);
+ infof(data, "Uses proxy env variable %s == '%s'", envp, proxy);
return proxy;
}
@@ -2385,11 +2438,20 @@ static CURLcode parse_proxy(struct Curl_easy *data,
proxyinfo->proxytype = proxytype;
/* Is there a username and password given in this proxy url? */
- curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
- curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
+ uc = curl_url_get(uhp, CURLUPART_USER, &proxyuser, CURLU_URLDECODE);
+ if(uc && (uc != CURLUE_NO_USER))
+ goto error;
+ uc = curl_url_get(uhp, CURLUPART_PASSWORD, &proxypasswd, CURLU_URLDECODE);
+ if(uc && (uc != CURLUE_NO_PASSWORD))
+ goto error;
+
if(proxyuser || proxypasswd) {
Curl_safefree(proxyinfo->user);
proxyinfo->user = proxyuser;
+ result = Curl_setstropt(&data->state.aptr.proxyuser, proxyuser);
+ proxyuser = NULL;
+ if(result)
+ goto error;
Curl_safefree(proxyinfo->passwd);
if(!proxypasswd) {
proxypasswd = strdup("");
@@ -2399,10 +2461,14 @@ static CURLcode parse_proxy(struct Curl_easy *data,
}
}
proxyinfo->passwd = proxypasswd;
+ result = Curl_setstropt(&data->state.aptr.proxypasswd, proxypasswd);
+ proxypasswd = NULL;
+ if(result)
+ goto error;
conn->bits.proxy_user_passwd = TRUE; /* enable it */
}
- curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
+ (void)curl_url_get(uhp, CURLUPART_PORT, &portptr, 0);
if(portptr) {
port = (int)strtol(portptr, NULL, 10);
@@ -2444,6 +2510,8 @@ static CURLcode parse_proxy(struct Curl_easy *data,
proxyinfo->host.name = host;
error:
+ free(proxyuser);
+ free(proxypasswd);
free(scheme);
curl_url_cleanup(uhp);
return result;
@@ -2455,18 +2523,26 @@ static CURLcode parse_proxy(struct Curl_easy *data,
static CURLcode parse_proxy_auth(struct Curl_easy *data,
struct connectdata *conn)
{
- const char *proxyuser = data->set.str[STRING_PROXYUSERNAME] ?
- data->set.str[STRING_PROXYUSERNAME] : "";
- const char *proxypasswd = data->set.str[STRING_PROXYPASSWORD] ?
- data->set.str[STRING_PROXYPASSWORD] : "";
+ const char *proxyuser = data->state.aptr.proxyuser ?
+ data->state.aptr.proxyuser : "";
+ const char *proxypasswd = data->state.aptr.proxypasswd ?
+ data->state.aptr.proxypasswd : "";
CURLcode result = CURLE_OK;
- if(proxyuser)
+ if(proxyuser) {
result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
REJECT_ZERO);
- if(!result && proxypasswd)
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxyuser,
+ conn->http_proxy.user);
+ }
+ if(!result && proxypasswd) {
result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd,
NULL, REJECT_ZERO);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxypasswd,
+ conn->http_proxy.passwd);
+ }
return result;
}
@@ -2520,7 +2596,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
no_proxy = curl_getenv(p);
}
if(no_proxy) {
- infof(data, "Uses proxy env variable %s == '%s'\n", p, no_proxy);
+ infof(data, "Uses proxy env variable %s == '%s'", p, no_proxy);
}
}
@@ -2808,43 +2884,20 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
* option or a .netrc file, if applicable.
*/
static CURLcode override_login(struct Curl_easy *data,
- struct connectdata *conn,
- char **userp, char **passwdp, char **optionsp)
+ struct connectdata *conn)
{
- bool user_changed = FALSE;
- bool passwd_changed = FALSE;
CURLUcode uc;
+ char **userp = &conn->user;
+ char **passwdp = &conn->passwd;
+ char **optionsp = &conn->options;
+#ifndef CURL_DISABLE_NETRC
if(data->set.use_netrc == CURL_NETRC_REQUIRED && conn->bits.user_passwd) {
- /* ignore user+password in the URL */
- if(*userp) {
- Curl_safefree(*userp);
- user_changed = TRUE;
- }
- if(*passwdp) {
- Curl_safefree(*passwdp);
- passwd_changed = TRUE;
- }
+ Curl_safefree(*userp);
+ Curl_safefree(*passwdp);
conn->bits.user_passwd = FALSE; /* disable user+password */
}
-
- if(data->set.str[STRING_USERNAME]) {
- free(*userp);
- *userp = strdup(data->set.str[STRING_USERNAME]);
- if(!*userp)
- return CURLE_OUT_OF_MEMORY;
- conn->bits.user_passwd = TRUE; /* enable user+password */
- user_changed = TRUE;
- }
-
- if(data->set.str[STRING_PASSWORD]) {
- free(*passwdp);
- *passwdp = strdup(data->set.str[STRING_PASSWORD]);
- if(!*passwdp)
- return CURLE_OUT_OF_MEMORY;
- conn->bits.user_passwd = TRUE; /* enable user+password */
- passwd_changed = TRUE;
- }
+#endif
if(data->set.str[STRING_OPTIONS]) {
free(*optionsp);
@@ -2853,9 +2906,9 @@ static CURLcode override_login(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
+#ifndef CURL_DISABLE_NETRC
conn->bits.netrc = FALSE;
- if(data->set.use_netrc != CURL_NETRC_IGNORED &&
- (!*userp || !**userp || !*passwdp || !**passwdp)) {
+ if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
bool netrc_user_changed = FALSE;
bool netrc_passwd_changed = FALSE;
int ret;
@@ -2865,8 +2918,8 @@ static CURLcode override_login(struct Curl_easy *data,
&netrc_user_changed, &netrc_passwd_changed,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
- infof(data, "Couldn't find host %s in the .netrc file; using defaults\n",
- conn->host.name);
+ infof(data, "Couldn't find host %s in the %s file; using defaults",
+ conn->host.name, data->set.str[STRING_NETRC_FILE]);
}
else if(ret < 0) {
return CURLE_OUT_OF_MEMORY;
@@ -2877,29 +2930,45 @@ static CURLcode override_login(struct Curl_easy *data,
different host or similar. */
conn->bits.netrc = TRUE;
conn->bits.user_passwd = TRUE; /* enable user+password */
-
- if(netrc_user_changed) {
- user_changed = TRUE;
- }
- if(netrc_passwd_changed) {
- passwd_changed = TRUE;
- }
}
}
+#endif
/* for updated strings, we update them in the URL */
- if(user_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp,
+ if(*userp) {
+ CURLcode result = Curl_setstropt(&data->state.aptr.user, *userp);
+ if(result)
+ return result;
+ }
+ if(data->state.aptr.user) {
+ uc = curl_url_set(data->state.uh, CURLUPART_USER, data->state.aptr.user,
CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
+ if(!*userp) {
+ *userp = strdup(data->state.aptr.user);
+ if(!*userp)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
- if(passwd_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp,
- CURLU_URLENCODE);
+
+ if(*passwdp) {
+ CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
+ if(result)
+ return result;
+ }
+ if(data->state.aptr.passwd) {
+ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
+ data->state.aptr.passwd, CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
+ if(!*passwdp) {
+ *passwdp = strdup(data->state.aptr.passwd);
+ if(!*passwdp)
+ return CURLE_OUT_OF_MEMORY;
+ }
}
+
return CURLE_OK;
}
@@ -2951,6 +3020,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
char *host_portno;
char *portptr;
int port = -1;
+ CURLcode result = CURLE_OK;
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) data;
@@ -2980,7 +3050,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
if(*ptr == '%') {
/* There might be a zone identifier */
if(strncmp("%25", ptr, 3))
- infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+ infof(data, "Please URL encode %% as %%25, see RFC 6874.");
ptr++;
/* Allow unreserved characters as defined in RFC 3986 */
while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
@@ -2991,7 +3061,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
/* yeps, it ended nicely with a bracket as well */
*ptr++ = '\0';
else
- infof(data, "Invalid IPv6 address format\n");
+ infof(data, "Invalid IPv6 address format");
portptr = ptr;
/* Note that if this didn't end with a bracket, we still advanced the
* hostptr first, but I can't see anything wrong with that as no host
@@ -2999,8 +3069,8 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
*/
#else
failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in!");
- free(host_dup);
- return CURLE_NOT_BUILT_IN;
+ result = CURLE_NOT_BUILT_IN;
+ goto error;
#endif
}
@@ -3013,10 +3083,10 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
if(*host_portno) {
long portparse = strtol(host_portno, &endp, 10);
if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
- infof(data, "No valid port number in connect to host string (%s)\n",
+ failf(data, "No valid port number in connect to host string (%s)",
host_portno);
- hostptr = NULL;
- port = -1;
+ result = CURLE_SETOPT_OPTION_SYNTAX;
+ goto error;
}
else
port = (int)portparse; /* we know it will fit */
@@ -3027,15 +3097,16 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
if(hostptr) {
*hostname_result = strdup(hostptr);
if(!*hostname_result) {
- free(host_dup);
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
}
}
*port_result = port;
+ error:
free(host_dup);
- return CURLE_OK;
+ return result;
}
/*
@@ -3131,7 +3202,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
conn->conn_to_host.name = host;
conn->bits.conn_to_host = TRUE;
- infof(data, "Connecting to hostname: %s\n", host);
+ infof(data, "Connecting to hostname: %s", host);
}
else {
/* no "connect to host" */
@@ -3142,7 +3213,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
if(port >= 0) {
conn->conn_to_port = port;
conn->bits.conn_to_port = TRUE;
- infof(data, "Connecting to port: %d\n", port);
+ infof(data, "Connecting to port: %d", port);
}
else {
/* no "connect to port" */
@@ -3203,7 +3274,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
conn->conn_to_port = as->dst.port;
conn->bits.conn_to_port = TRUE;
conn->bits.altused = TRUE;
- infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
+ infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d",
Curl_alpnid2str(srcalpnid), host, conn->remote_port,
Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
if(srcalpnid != as->dst.alpnid) {
@@ -3311,11 +3382,14 @@ static CURLcode resolve_server(struct Curl_easy *data,
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
- else if(rc == CURLRESOLV_TIMEDOUT)
+ else if(rc == CURLRESOLV_TIMEDOUT) {
+ failf(data, "Failed to resolve host '%s' with timeout after %ld ms",
+ connhost->dispname,
+ Curl_timediff(Curl_now(), data->progress.t_startsingle));
result = CURLE_OPERATION_TIMEDOUT;
-
+ }
else if(!hostaddr) {
- failf(data, "Couldn't resolve host '%s'", connhost->dispname);
+ failf(data, "Could not resolve host: %s", connhost->dispname);
result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
@@ -3367,7 +3441,7 @@ static void reuse_conn(struct Curl_easy *data,
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] = "";
- long local_port = -1;
+ int local_port = -1;
#ifndef CURL_DISABLE_PROXY
Curl_free_idnconverted_hostname(&old_conn->http_proxy.host);
Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host);
@@ -3380,8 +3454,6 @@ static void reuse_conn(struct Curl_easy *data,
allocated in vain and is targeted for destruction */
Curl_free_primary_ssl_config(&old_conn->ssl_config);
- conn->data = data;
-
/* get the user+password information from the old_conn struct since it may
* be new for this request even when we re-use an existing connection */
conn->bits.user_passwd = old_conn->bits.user_passwd;
@@ -3469,7 +3541,6 @@ static void reuse_conn(struct Curl_easy *data,
* @param async is set TRUE when an async DNS resolution is pending
* @see Curl_setup_conn()
*
- * *NOTE* this function assigns the conn->data pointer!
*/
static CURLcode create_conn(struct Curl_easy *data,
@@ -3492,7 +3563,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/*************************************************************
* Check input data
*************************************************************/
- if(!data->change.url) {
+ if(!data->state.url) {
result = CURLE_URL_MALFORMAT;
goto out;
}
@@ -3528,7 +3599,7 @@ static CURLcode create_conn(struct Curl_easy *data,
#ifdef USE_UNIX_SOCKETS
if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
- if(conn->unix_domain_socket == NULL) {
+ if(!conn->unix_domain_socket) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
@@ -3558,10 +3629,9 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
- /* Check for overridden login details and set them accordingly so they
+ /* Check for overridden login details and set them accordingly so that
they are known when protocol->setup_connection is called! */
- result = override_login(data, conn, &conn->user, &conn->passwd,
- &conn->options);
+ result = override_login(data, conn);
if(result)
goto out;
@@ -3693,17 +3763,20 @@ static CURLcode create_conn(struct Curl_easy *data,
that will be freed as part of the Curl_easy struct, but all cloned
copies will be separately allocated.
*/
- data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG];
- data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
+ data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
+ data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
+ data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+ data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.primary.cipher_list =
- data->set.str[STRING_SSL_CIPHER_LIST_ORIG];
+ data->set.str[STRING_SSL_CIPHER_LIST];
data->set.ssl.primary.cipher_list13 =
- data->set.str[STRING_SSL_CIPHER13_LIST_ORIG];
+ data->set.str[STRING_SSL_CIPHER13_LIST];
data->set.ssl.primary.pinned_key =
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
- data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY];
+ data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
+ data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
#ifndef CURL_DISABLE_PROXY
@@ -3719,8 +3792,13 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.proxy_ssl.primary.pinned_key =
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+ data->set.proxy_ssl.primary.ca_info_blob =
+ data->set.blobs[BLOB_CAINFO_PROXY];
+ data->set.proxy_ssl.primary.issuercert =
+ data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+ data->set.proxy_ssl.primary.issuercert_blob =
+ data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
- data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
@@ -3728,24 +3806,21 @@ static CURLcode create_conn(struct Curl_easy *data,
data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
#endif
- data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
- data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
- data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
- data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
- data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
- data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG];
- data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG];
+ data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+ data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
+ data->set.ssl.key = data->set.str[STRING_KEY];
+ data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
+ data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
+ data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
#ifdef USE_TLS_SRP
- data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG];
- data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG];
+ data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME];
+ data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD];
#ifndef CURL_DISABLE_PROXY
data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
#endif
#endif
-
- data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG];
- data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG];
+ data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
&conn->ssl_config)) {
@@ -3797,14 +3872,14 @@ static CURLcode create_conn(struct Curl_easy *data,
*in_connect = conn;
#ifndef CURL_DISABLE_PROXY
- infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
+ infof(data, "Re-using existing connection! (#%ld) with %s %s",
conn->connection_id,
conn->bits.proxy?"proxy":"host",
conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
conn->host.dispname);
#else
- infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+ infof(data, "Re-using existing connection! (#%ld) with host %s",
conn->connection_id, conn->host.dispname);
#endif
}
@@ -3844,7 +3919,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(conn_candidate)
(void)Curl_disconnect(data, conn_candidate, FALSE);
else {
- infof(data, "No more connections allowed to host %s: %zu\n",
+ infof(data, "No more connections allowed to host %s: %zu",
bundlehost, max_host_connections);
connections_available = FALSE;
}
@@ -3864,13 +3939,13 @@ static CURLcode create_conn(struct Curl_easy *data,
if(conn_candidate)
(void)Curl_disconnect(data, conn_candidate, FALSE);
else {
- infof(data, "No connections available in cache\n");
+ infof(data, "No connections available in cache");
connections_available = FALSE;
}
}
if(!connections_available) {
- infof(data, "No connections available.\n");
+ infof(data, "No connections available.");
conn_free(conn);
*in_connect = NULL;
@@ -3895,14 +3970,14 @@ static CURLcode create_conn(struct Curl_easy *data,
connection based. */
if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
data->state.authhost.done) {
- infof(data, "NTLM picked AND auth done set, clear picked!\n");
+ infof(data, "NTLM picked AND auth done set, clear picked!");
data->state.authhost.picked = CURLAUTH_NONE;
data->state.authhost.done = FALSE;
}
if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
data->state.authproxy.done) {
- infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n");
+ infof(data, "NTLM-proxy picked AND auth done set, clear picked!");
data->state.authproxy.picked = CURLAUTH_NONE;
data->state.authproxy.done = FALSE;
}
@@ -3952,10 +4027,7 @@ out:
* create_conn() is all done.
*
* Curl_setup_conn() also handles reused connections
- *
- * conn->data MUST already have been setup fine (in create_conn)
*/
-
CURLcode Curl_setup_conn(struct Curl_easy *data,
bool *protocol_done)
{
diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c
index e3a7882..7f03862 100644
--- a/Utilities/cmcurl/lib/urlapi.c
+++ b/Utilities/cmcurl/lib/urlapi.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
@@ -131,7 +131,7 @@ static const char *find_host_sep(const char *url)
*/
static bool urlchar_needs_escaping(int c)
{
- return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
+ return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c));
}
/*
@@ -580,7 +580,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname,
}
/* scan for byte values < 31 or 127 */
-static CURLUcode junkscan(const char *part)
+static bool junkscan(const char *part, unsigned int flags)
{
if(part) {
static const char badbytes[]={
@@ -588,17 +588,18 @@ static CURLUcode junkscan(const char *part)
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x7f,
- 0x00 /* null-terminate */
+ 0x7f, 0x00 /* null-terminate */
};
size_t n = strlen(part);
size_t nfine = strcspn(part, badbytes);
if(nfine != n)
/* since we don't know which part is scanned, return a generic error
code */
- return CURLUE_MALFORMED_INPUT;
+ return TRUE;
+ if(!(flags & CURLU_ALLOW_SPACE) && strchr(part, ' '))
+ return TRUE;
}
- return CURLUE_OK;
+ return FALSE;
}
static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
@@ -667,6 +668,94 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
#define HOSTNAME_END(x) (((x) == '/') || ((x) == '?') || ((x) == '#'))
+/*
+ * Handle partial IPv4 numerical addresses and different bases, like
+ * '16843009', '0x7f', '0x7f.1' '0177.1.1.1' etc.
+ *
+ * If the given input string is syntactically wrong or any part for example is
+ * too big, this function returns FALSE and doesn't create any output.
+ *
+ * Output the "normalized" version of that input string in plain quad decimal
+ * integers and return TRUE.
+ */
+static bool ipv4_normalize(const char *hostname, char *outp, size_t olen)
+{
+ bool done = FALSE;
+ int n = 0;
+ const char *c = hostname;
+ unsigned long parts[4] = {0, 0, 0, 0};
+
+ while(!done) {
+ char *endp;
+ unsigned long l;
+ if((*c < '0') || (*c > '9'))
+ /* most importantly this doesn't allow a leading plus or minus */
+ return FALSE;
+ l = strtoul(c, &endp, 0);
+
+ /* overflow or nothing parsed at all */
+ if(((l == ULONG_MAX) && (errno == ERANGE)) || (endp == c))
+ return FALSE;
+
+#if SIZEOF_LONG > 4
+ /* a value larger than 32 bits */
+ if(l > UINT_MAX)
+ return FALSE;
+#endif
+
+ parts[n] = l;
+ c = endp;
+
+ switch (*c) {
+ case '.' :
+ if(n == 3)
+ return FALSE;
+ n++;
+ c++;
+ break;
+
+ case '\0':
+ done = TRUE;
+ break;
+
+ default:
+ return FALSE;
+ }
+ }
+
+ /* this is deemed a valid IPv4 numerical address */
+
+ switch(n) {
+ case 0: /* a -- 32 bits */
+ msnprintf(outp, olen, "%u.%u.%u.%u",
+ parts[0] >> 24, (parts[0] >> 16) & 0xff,
+ (parts[0] >> 8) & 0xff, parts[0] & 0xff);
+ break;
+ case 1: /* a.b -- 8.24 bits */
+ if((parts[0] > 0xff) || (parts[1] > 0xffffff))
+ return FALSE;
+ msnprintf(outp, olen, "%u.%u.%u.%u",
+ parts[0], (parts[1] >> 16) & 0xff,
+ (parts[1] >> 8) & 0xff, parts[1] & 0xff);
+ break;
+ case 2: /* a.b.c -- 8.8.16 bits */
+ if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
+ return FALSE;
+ msnprintf(outp, olen, "%u.%u.%u.%u",
+ parts[0], parts[1], (parts[2] >> 8) & 0xff,
+ parts[2] & 0xff);
+ break;
+ case 3: /* a.b.c.d -- 8.8.8.8 bits */
+ if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
+ (parts[3] > 0xff))
+ return FALSE;
+ msnprintf(outp, olen, "%u.%u.%u.%u",
+ parts[0], parts[1], parts[2], parts[3]);
+ break;
+ }
+ return TRUE;
+}
+
static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
{
char *path;
@@ -681,8 +770,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.
@@ -796,9 +884,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
!(flags & CURLU_NON_SUPPORT_SCHEME))
return CURLUE_UNSUPPORTED_SCHEME;
- if(junkscan(schemep))
+ if(junkscan(schemep, flags))
return CURLUE_MALFORMED_INPUT;
-
}
else {
/* no scheme! */
@@ -839,7 +926,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
}
- if(junkscan(path))
+ if(junkscan(path, flags))
return CURLUE_MALFORMED_INPUT;
if((flags & CURLU_URLENCODE) && path[0]) {
@@ -899,10 +986,11 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
}
if(hostname) {
+ char normalized_ipv4[sizeof("255.255.255.255") + 1];
/*
* Parse the login details and strip them out of the host name.
*/
- if(junkscan(hostname))
+ if(junkscan(hostname, flags))
return CURLUE_MALFORMED_INPUT;
result = parse_hostname_login(u, &hostname, flags);
@@ -922,7 +1010,10 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
return result;
}
- u->host = strdup(hostname);
+ 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;
@@ -1063,7 +1154,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
const struct Curl_handler *h =
Curl_builtin_scheme(u->scheme);
if(h) {
- msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
ptr = portbuf;
}
}
@@ -1122,7 +1213,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
/* there's no stored port number, but asked to deliver
a default one for the scheme */
if(h) {
- msnprintf(portbuf, sizeof(portbuf), "%ld", h->defport);
+ msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
port = portbuf;
}
}
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
index f7d60b2..6ffd976 100644
--- a/Utilities/cmcurl/lib/urldata.h
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -246,6 +246,7 @@ struct ssl_primary_config {
long version_max; /* max supported version the client wants to use*/
char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
+ char *issuercert; /* optional issuer certificate filename */
char *clientcert;
char *random_file; /* path to file containing "random" data */
char *egdsocket; /* path to file containing the EGD daemon socket */
@@ -253,6 +254,8 @@ struct ssl_primary_config {
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
char *pinned_key;
struct curl_blob *cert_blob;
+ struct curl_blob *ca_info_blob;
+ struct curl_blob *issuercert_blob;
char *curves; /* list of curves to use */
BIT(verifypeer); /* set TRUE if this is desired */
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
@@ -264,8 +267,6 @@ struct ssl_config_data {
struct ssl_primary_config primary;
long certverifyresult; /* result from the certificate verification */
char *CRLfile; /* CRL to check certificate revocation */
- char *issuercert;/* optional issuer certificate filename */
- struct curl_blob *issuercert_blob;
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
void *fsslctxp; /* parameter for call back */
char *cert_type; /* format for certificate (default: PEM)*/
@@ -286,6 +287,8 @@ struct ssl_config_data {
BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
list errors */
BIT(native_ca_store); /* use the native ca store of operating system */
+ BIT(auto_client_cert); /* automatically locate and use a client
+ certificate for authentication (Schannel) */
};
struct ssl_general_config {
@@ -371,6 +374,15 @@ struct kerberos5data {
};
#endif
+/* Struct used for SCRAM-SHA-1 authentication */
+#ifdef USE_GSASL
+#include <gsasl.h>
+struct gsasldata {
+ Gsasl *ctx;
+ Gsasl_session *client;
+};
+#endif
+
/* Struct used for NTLM challenge-response authentication */
#if defined(USE_NTLM)
struct ntlmdata {
@@ -496,7 +508,9 @@ struct ConnectBits {
BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
#endif
+#ifndef CURL_DISABLE_NETRC
BIT(netrc); /* name+password provided by netrc */
+#endif
BIT(bound); /* set true if bind() has already been done on this socket/
connection */
BIT(multiplex); /* connection is multiplexed */
@@ -690,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 */
@@ -782,12 +797,16 @@ struct Curl_handler {
struct connectdata *conn,
unsigned int checks_to_perform);
+ /* attach() attaches this transfer to this connection */
+ void (*attach)(struct Curl_easy *data, struct connectdata *conn);
+
int defport; /* Default port. */
unsigned int protocol; /* See CURLPROTO_* - this needs to be the single
specific protocol bit */
unsigned int family; /* single bit for protocol family; basically the
non-TLS name of the protocol this is */
unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */
+
};
#define PROTOPT_NONE 0 /* nothing extra */
@@ -846,25 +865,8 @@ struct proxy_info {
char *passwd; /* proxy password string, allocated */
};
-/* struct for HTTP CONNECT state data */
-struct http_connect_state {
- struct dynbuf rcvbuf;
- enum keeponval {
- KEEPON_DONE,
- KEEPON_CONNECT,
- KEEPON_IGNORE
- } keepon;
- curl_off_t cl; /* size of content to read and ignore */
- enum {
- TUNNEL_INIT, /* init/default/no tunnel state */
- TUNNEL_CONNECT, /* CONNECT has been sent off */
- TUNNEL_COMPLETE /* CONNECT response received completely */
- } tunnel_state;
- BIT(chunked_encoding);
- BIT(close_connection);
-};
-
struct ldapconninfo;
+struct http_connect_state;
/* for the (SOCKS) connect state machine */
enum connect_t {
@@ -902,10 +904,6 @@ struct connstate {
* unique for an entire connection.
*/
struct connectdata {
- /* 'data' is the CURRENT Curl_easy using this connection -- take great
- caution that this might very well vary between different times this
- connection is used! */
- struct Curl_easy *data;
struct connstate cnnct;
struct Curl_llist_element bundle_node; /* conncache */
@@ -981,12 +979,8 @@ struct connectdata {
char *user; /* user name string, allocated */
char *passwd; /* password string, allocated */
char *options; /* options string, allocated */
-
char *sasl_authzid; /* authorisation identity string, allocated */
-
- int httpversion; /* the HTTP version*10 reported by the server */
- int rtspversion; /* the RTSP version*10 reported by the server */
-
+ unsigned char httpversion; /* the HTTP version*10 reported by the server */
struct curltime now; /* "current" time */
struct curltime created; /* creation time */
struct curltime lastused; /* when returned to the connection cache */
@@ -1065,6 +1059,10 @@ struct connectdata {
CtxtHandle *sslContext;
#endif
+#ifdef USE_GSASL
+ struct gsasldata gsasl;
+#endif
+
#if defined(USE_NTLM)
curlntlm http_ntlm_state;
curlntlm proxy_ntlm_state;
@@ -1157,9 +1155,9 @@ struct PureInfo {
reused, in the connection cache. */
char conn_primary_ip[MAX_IPADR_LEN];
- long conn_primary_port;
+ int conn_primary_port;
char conn_local_ip[MAX_IPADR_LEN];
- long conn_local_port;
+ int conn_local_port;
const char *conn_scheme;
unsigned int conn_protocol;
struct curl_certinfo certs; /* info about the certs, only populated in
@@ -1316,8 +1314,6 @@ struct urlpieces {
struct UrlState {
/* Points to the connection cache */
struct conncache *conn_cache;
- int retrycount; /* number of retries on a new connection */
-
/* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */
@@ -1334,6 +1330,7 @@ struct UrlState {
following not keep sending user+password... This is
strdup() data.
*/
+ int retrycount; /* number of retries on a new connection */
int first_remote_port; /* remote port of the first (not followed) request */
struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
long sessionage; /* number of the most recent session */
@@ -1341,6 +1338,7 @@ struct UrlState {
unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */
int os_errno; /* filled in with errno whenever an error occurs */
char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
+ long followlocation; /* redirect counter */
#ifdef HAVE_SIGNAL
/* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
void (*prev_signal)(int sig);
@@ -1365,9 +1363,10 @@ struct UrlState {
/* a place to store the most recently set FTP entrypath */
char *most_recent_ftp_entrypath;
-
- int httpversion; /* the lowest HTTP version*10 reported by any server
- involved in this request */
+ unsigned char httpwant; /* when non-zero, a specific HTTP version requested
+ to be used in the library's request(s) */
+ unsigned char httpversion; /* the lowest HTTP version*10 reported by any
+ server involved in this request */
#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__)
/* do FTP line-end conversions on most platforms */
@@ -1400,9 +1399,13 @@ struct UrlState {
int stream_weight;
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
-#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
-#endif
+ char *url; /* work URL, copied from UserDefined */
+ char *referer; /* referer string */
+ struct curl_slist *cookielist; /* list of cookie files set by
+ curl_easy_setopt(COOKIEFILE) calls */
+ struct curl_slist *resolve; /* set to point to the set.resolve list when
+ this should be dealt with in pretransfer */
#ifndef CURL_DISABLE_HTTP
size_t trailers_bytes_sent;
struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
@@ -1411,6 +1414,7 @@ struct UrlState {
trailers_state trailers_state; /* whether we are sending trailers
and what stage are we at */
#ifdef USE_HYPER
+ bool hconnect; /* set if a CONNECT request */
CURLcode hresult; /* used to pass return codes back from hyper callbacks */
#endif
@@ -1427,6 +1431,12 @@ struct UrlState {
char *cookiehost;
char *rtsp_transport;
char *te; /* TE: request header */
+
+ /* transfer credentials */
+ char *user;
+ char *passwd;
+ char *proxyuser;
+ char *proxypasswd;
} aptr;
#ifdef CURLDEBUG
@@ -1454,32 +1464,16 @@ struct UrlState {
BIT(use_range);
BIT(rangestringalloc); /* the range string is malloc()'ed */
BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE
- when multi_done() is called, to prevent multi_done() to get
- invoked twice when the multi interface is used. */
+ when multi_done() is called, to prevent multi_done() to get
+ invoked twice when the multi interface is used. */
BIT(stream_depends_e); /* set or don't set the Exclusive bit */
BIT(previouslypending); /* this transfer WAS in the multi->pending queue */
BIT(cookie_engine);
-};
-
-
-/*
- * This 'DynamicStatic' struct defines dynamic states that actually change
- * values in the 'UserDefined' area, which MUST be taken into consideration
- * if the UserDefined struct is cloned or similar. You can probably just
- * copy these, but each one indicate a special action on other data.
- */
-
-struct DynamicStatic {
- char *url; /* work URL, copied from UserDefined */
- char *referer; /* referer string */
- struct curl_slist *cookielist; /* list of cookie files set by
- curl_easy_setopt(COOKIEFILE) calls */
- struct curl_slist *resolve; /* set to point to the set.resolve list when
- this should be dealt with in pretransfer */
+ BIT(prefer_ascii); /* ASCII rather than binary */
+ BIT(list_only); /* list directory contents */
BIT(url_alloc); /* URL string is malloc()'ed */
BIT(referer_alloc); /* referer string is malloc()ed */
- BIT(wildcard_resolve); /* Set to true if any resolve change is a
- wildcard */
+ BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */
};
/*
@@ -1502,9 +1496,9 @@ struct Curl_multi; /* declared and used only in multi.c */
* are catered for in curl_easy_setopt_ccsid()
*/
enum dupstring {
- STRING_CERT_ORIG, /* client certificate file name */
+ STRING_CERT, /* client certificate file name */
STRING_CERT_PROXY, /* client certificate file name */
- STRING_CERT_TYPE_ORIG, /* format for certificate (default: PEM)*/
+ STRING_CERT_TYPE, /* format for certificate (default: PEM)*/
STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
STRING_COOKIE, /* HTTP cookie string to send */
STRING_COOKIEJAR, /* dump all cookies to this file */
@@ -1515,11 +1509,11 @@ enum dupstring {
STRING_FTP_ACCOUNT, /* ftp account data */
STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
STRING_FTPPORT, /* port to send with the FTP PORT command */
- STRING_KEY_ORIG, /* private key file name */
+ STRING_KEY, /* private key file name */
STRING_KEY_PROXY, /* private key file name */
- STRING_KEY_PASSWD_ORIG, /* plain text private key password */
+ STRING_KEY_PASSWD, /* plain text private key password */
STRING_KEY_PASSWD_PROXY, /* plain text private key password */
- STRING_KEY_TYPE_ORIG, /* format for private key (default: PEM) */
+ STRING_KEY_TYPE, /* format for private key (default: PEM) */
STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */
STRING_KRB_LEVEL, /* krb security level */
STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find
@@ -1529,22 +1523,22 @@ enum dupstring {
STRING_SET_RANGE, /* range, if used */
STRING_SET_REFERER, /* custom string for the HTTP referer field */
STRING_SET_URL, /* what original URL to work on */
- STRING_SSL_CAPATH_ORIG, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */
STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
- STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */
+ STRING_SSL_CAFILE, /* certificate file to verify peer against */
STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
- STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
- STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */
+ STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
- STRING_SSL_CIPHER13_LIST_ORIG, /* list of TLS 1.3 ciphers to use */
+ STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */
STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */
STRING_USERAGENT, /* User-Agent string */
- STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */
+ STRING_SSL_CRLFILE, /* crl file to check certificate */
STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
- STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */
+ STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
STRING_SSL_ENGINE, /* name of ssl engine */
STRING_USERNAME, /* <username>, if used */
@@ -1565,9 +1559,9 @@ enum dupstring {
STRING_SERVICE_NAME, /* Service name */
STRING_MAIL_FROM,
STRING_MAIL_AUTH,
- STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth <username> */
+ STRING_TLSAUTH_USERNAME, /* TLS auth <username> */
STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
- STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth <password> */
+ STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */
STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth <password> */
STRING_BEARER, /* <bearer>, if used */
STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
@@ -1596,12 +1590,14 @@ enum dupstring {
};
enum dupblob {
- BLOB_CERT_ORIG,
+ BLOB_CERT,
BLOB_CERT_PROXY,
- BLOB_KEY_ORIG,
+ BLOB_KEY,
BLOB_KEY_PROXY,
- BLOB_SSL_ISSUERCERT_ORIG,
+ BLOB_SSL_ISSUERCERT,
BLOB_SSL_ISSUERCERT_PROXY,
+ BLOB_CAINFO,
+ BLOB_CAINFO_PROXY,
BLOB_LAST
};
@@ -1625,7 +1621,6 @@ struct UserDefined {
unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */
unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */
unsigned long socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */
- long followlocation; /* as in HTTP Location: */
long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1
for infinity */
@@ -1665,7 +1660,7 @@ struct UserDefined {
curl_conv_callback convtonetwork;
/* function to convert from UTF-8 encoding: */
curl_conv_callback convfromutf8;
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
curl_hstsread_callback hsts_read;
void *hsts_read_userp;
curl_hstswrite_callback hsts_write;
@@ -1708,11 +1703,9 @@ struct UserDefined {
curl_TimeCond timecondition; /* kind of time/date comparison */
curl_proxytype proxytype; /* what kind of proxy that is in use */
time_t timevalue; /* what time to compare with */
-#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT)
Curl_HttpReq method; /* what kind of HTTP request (if any) is this */
-#endif
- long httpversion; /* when non-zero, a specific HTTP version requested to
- be used in the library's request(s) */
+ unsigned char httpwant; /* when non-zero, a specific HTTP version requested
+ to be used in the library's request(s) */
struct ssl_config_data ssl; /* user defined SSL stuff */
#ifndef CURL_DISABLE_PROXY
struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */
@@ -1720,8 +1713,8 @@ struct UserDefined {
struct ssl_general_config general_ssl; /* general user defined SSL stuff */
long dns_cache_timeout; /* DNS cache timeout */
long buffer_size; /* size of receive buffer to use */
- size_t upload_buffer_size; /* size of upload buffer to use,
- keep it >= CURL_MAX_WRITE_SIZE */
+ unsigned int upload_buffer_size; /* size of upload buffer to use,
+ keep it >= CURL_MAX_WRITE_SIZE */
void *private_data; /* application-private data */
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
unsigned char ipver; /* the CURL_IPRESOLVE_* defines in the public header
@@ -1737,8 +1730,10 @@ struct UserDefined {
*/
curl_sshkeycallback ssh_keyfunc; /* key matching callback */
void *ssh_keyfunc_userp; /* custom pointer to callback */
+#ifndef CURL_DISABLE_NETRC
enum CURL_NETRC_OPTION
use_netrc; /* defined in include/curl.h */
+#endif
curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
IMAP or POP3 or others! */
long new_file_perms; /* Permissions to use when creating remote files */
@@ -1800,8 +1795,8 @@ struct UserDefined {
BIT(get_filetime); /* get the time and get of the remote file */
BIT(tunnel_thru_httpproxy); /* use CONNECT through a HTTP proxy */
BIT(prefer_ascii); /* ASCII rather than binary */
- BIT(ftp_append); /* append, not overwrite, on upload */
- BIT(ftp_list_only); /* switch FTP command for listing directories */
+ BIT(remote_append); /* append, not overwrite, on upload */
+ BIT(list_only); /* list directory */
#ifndef CURL_DISABLE_FTP
BIT(ftp_use_port); /* use the FTP PORT command */
BIT(ftp_use_epsv); /* if EPSV is to be attempted or not */
@@ -1858,6 +1853,9 @@ struct UserDefined {
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 */
BIT(http09_allowed); /* allow HTTP/0.9 responses */
BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
recipients */
@@ -1905,8 +1903,8 @@ struct Curl_easy {
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
- int actions[MAX_SOCKSPEREASYHANDLE]; /* action for each socket in
- sockets[] */
+ unsigned char actions[MAX_SOCKSPEREASYHANDLE]; /* action for each socket in
+ sockets[] */
int numsocks;
struct Names dns;
@@ -1922,12 +1920,11 @@ struct Curl_easy {
#endif
struct SingleRequest req; /* Request-specific data */
struct UserDefined set; /* values set by the libcurl user */
- struct DynamicStatic change; /* possibly modified userdefined data */
struct CookieInfo *cookies; /* the cookies, read from files and servers.
NOTE that the 'cookie' field in the
UserDefined struct defines if the "engine"
is to be used or not. */
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
struct hsts *hsts;
#endif
#ifndef CURL_DISABLE_ALTSVC
diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c
index 620dba0..d17e16f 100644
--- a/Utilities/cmcurl/lib/vauth/cleartext.c
+++ b/Utilities/cmcurl/lib/vauth/cleartext.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
@@ -32,7 +32,6 @@
#include "urldata.h"
#include "vauth/vauth.h"
-#include "curl_base64.h"
#include "curl_md5.h"
#include "warnless.h"
#include "strtok.h"
@@ -51,31 +50,24 @@
*
* Parameters:
*
- * data [in] - The session handle.
* authzid [in] - The authorization identity.
* authcid [in] - The authentication identity.
* passwd [in] - The password.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
- const char *authzid,
+CURLcode Curl_auth_create_plain_message(const char *authzid,
const char *authcid,
const char *passwd,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
- CURLcode result;
char *plainauth;
+ size_t plainlen;
size_t zlen;
size_t clen;
size_t plen;
- size_t plainlen;
- *outlen = 0;
- *outptr = NULL;
zlen = (authzid == NULL ? 0 : strlen(authzid));
clen = strlen(authcid);
plen = strlen(passwd);
@@ -86,23 +78,20 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
plainlen = zlen + clen + plen + 2;
- plainauth = malloc(plainlen);
+ plainauth = malloc(plainlen + 1);
if(!plainauth)
return CURLE_OUT_OF_MEMORY;
/* Calculate the reply */
- if(zlen != 0)
+ if(zlen)
memcpy(plainauth, authzid, zlen);
plainauth[zlen] = '\0';
memcpy(plainauth + zlen + 1, authcid, clen);
plainauth[zlen + clen + 1] = '\0';
memcpy(plainauth + zlen + clen + 2, passwd, plen);
-
- /* Base64 encode the reply */
- result = Curl_base64_encode(data, plainauth, plainlen, outptr, outlen);
- free(plainauth);
-
- return result;
+ plainauth[plainlen] = '\0';
+ Curl_bufref_set(out, plainauth, plainlen, curl_free);
+ return CURLE_OK;
}
/*
@@ -113,34 +102,15 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
*
* Parameters:
*
- * data [in] - The session handle.
* valuep [in] - The user name or user's password.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_login_message(struct Curl_easy *data,
- const char *valuep, char **outptr,
- size_t *outlen)
+CURLcode Curl_auth_create_login_message(const char *valuep, struct bufref *out)
{
- size_t vlen = strlen(valuep);
-
- if(!vlen) {
- /* Calculate an empty reply */
- *outptr = strdup("=");
- if(*outptr) {
- *outlen = (size_t) 1;
- return CURLE_OK;
- }
-
- *outlen = 0;
- return CURLE_OUT_OF_MEMORY;
- }
-
- /* Base64 encode the value */
- return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
+ Curl_bufref_set(out, valuep, strlen(valuep), NULL);
+ return CURLE_OK;
}
/*
@@ -151,20 +121,16 @@ CURLcode Curl_auth_create_login_message(struct Curl_easy *data,
*
* Parameters:
*
- * data [in] - The session handle.
* user [in] - The user name.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_external_message(struct Curl_easy *data,
- const char *user, char **outptr,
- size_t *outlen)
+CURLcode Curl_auth_create_external_message(const char *user,
+ struct bufref *out)
{
/* This is the same formatting as the login message */
- return Curl_auth_create_login_message(data, user, outptr, outlen);
+ return Curl_auth_create_login_message(user, out);
}
#endif /* if no users */
diff --git a/Utilities/cmcurl/lib/vauth/cram.c b/Utilities/cmcurl/lib/vauth/cram.c
index 1a37625..9ddb0ac 100644
--- a/Utilities/cmcurl/lib/vauth/cram.c
+++ b/Utilities/cmcurl/lib/vauth/cram.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
@@ -30,7 +30,6 @@
#include "urldata.h"
#include "vauth/vauth.h"
-#include "curl_base64.h"
#include "curl_hmac.h"
#include "curl_md5.h"
#include "warnless.h"
@@ -40,69 +39,31 @@
#include "curl_memory.h"
#include "memdebug.h"
-/*
- * Curl_auth_decode_cram_md5_message()
- *
- * This is used to decode an already encoded CRAM-MD5 challenge message.
- *
- * Parameters:
- *
- * chlg64 [in] - The base64 encoded challenge message.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
- *
- * Returns CURLE_OK on success.
- */
-CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
- size_t *outlen)
-{
- CURLcode result = CURLE_OK;
- size_t chlg64len = strlen(chlg64);
-
- *outptr = NULL;
- *outlen = 0;
-
- /* Decode the challenge if necessary */
- if(chlg64len && *chlg64 != '=')
- result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);
-
- return result;
-}
/*
* Curl_auth_create_cram_md5_message()
*
- * This is used to generate an already encoded CRAM-MD5 response message ready
- * for sending to the recipient.
+ * This is used to generate a CRAM-MD5 response message ready for sending to
+ * the recipient.
*
* Parameters:
*
- * data [in] - The session handle.
* chlg [in] - The challenge.
* userp [in] - The user name.
* passwdp [in] - The user's password.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
- const char *chlg,
+CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
const char *userp,
const char *passwdp,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
- CURLcode result = CURLE_OK;
- size_t chlglen = 0;
struct HMAC_context *ctxt;
unsigned char digest[MD5_DIGEST_LEN];
char *response;
- if(chlg)
- chlglen = strlen(chlg);
-
/* Compute the digest using the password as the key */
ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
(const unsigned char *) passwdp,
@@ -111,9 +72,9 @@ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Update the digest with the given challenge */
- if(chlglen > 0)
- Curl_HMAC_update(ctxt, (const unsigned char *) chlg,
- curlx_uztoui(chlglen));
+ if(Curl_bufref_len(chlg))
+ Curl_HMAC_update(ctxt, Curl_bufref_ptr(chlg),
+ curlx_uztoui(Curl_bufref_len(chlg)));
/* Finalise the digest */
Curl_HMAC_final(ctxt, digest);
@@ -127,12 +88,8 @@ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
if(!response)
return CURLE_OUT_OF_MEMORY;
- /* Base64 encode the response */
- result = Curl_base64_encode(data, response, 0, outptr, outlen);
-
- free(response);
-
- return result;
+ Curl_bufref_set(out, response, strlen(response), curl_free);
+ return CURLE_OK;
}
#endif /* !CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
index 559852f..a04ffab 100644
--- a/Utilities/cmcurl/lib/vauth/digest.c
+++ b/Utilities/cmcurl/lib/vauth/digest.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
@@ -254,7 +254,7 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value)
*
* Parameters:
*
- * chlg64 [in] - The base64 encoded challenge message.
+ * chlgref [in] - The challenge message.
* nonce [in/out] - The buffer where the nonce will be stored.
* nlen [in] - The length of the nonce buffer.
* realm [in/out] - The buffer where the realm will be stored.
@@ -266,55 +266,35 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value)
*
* Returns CURLE_OK on success.
*/
-static CURLcode auth_decode_digest_md5_message(const char *chlg64,
+static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
char *nonce, size_t nlen,
char *realm, size_t rlen,
char *alg, size_t alen,
char *qop, size_t qlen)
{
- CURLcode result = CURLE_OK;
- unsigned char *chlg = NULL;
- size_t chlglen = 0;
- size_t chlg64len = strlen(chlg64);
-
- /* Decode the base-64 encoded challenge message */
- if(chlg64len && *chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &chlg, &chlglen);
- if(result)
- return result;
- }
+ const char *chlg = (const char *) Curl_bufref_ptr(chlgref);
/* Ensure we have a valid challenge message */
- if(!chlg)
+ if(!Curl_bufref_len(chlgref))
return CURLE_BAD_CONTENT_ENCODING;
/* Retrieve nonce string from the challenge */
- if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen,
- '\"')) {
- free(chlg);
+ if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"'))
return CURLE_BAD_CONTENT_ENCODING;
- }
/* Retrieve realm string from the challenge */
- if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen,
- '\"')) {
+ if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
/* Challenge does not have a realm, set empty string [RFC2831] page 6 */
strcpy(realm, "");
}
/* Retrieve algorithm string from the challenge */
- if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) {
- free(chlg);
+ if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ','))
return CURLE_BAD_CONTENT_ENCODING;
- }
/* Retrieve qop-options string from the challenge */
- if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) {
- free(chlg);
+ if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"'))
return CURLE_BAD_CONTENT_ENCODING;
- }
-
- free(chlg);
return CURLE_OK;
}
@@ -342,22 +322,20 @@ bool Curl_auth_is_digest_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * chlg64 [in] - The base64 encoded challenge message.
+ * chlg [in] - The challenge message.
* userp [in] - The user name.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
- const char *chlg64,
+ const struct bufref *chlg,
const char *userp,
const char *passwdp,
const char *service,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
size_t i;
struct MD5_context *ctxt;
@@ -378,9 +356,10 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
char *spn = NULL;
/* Decode the challenge message */
- CURLcode result = auth_decode_digest_md5_message(chlg64, nonce,
- sizeof(nonce), realm,
- sizeof(realm), algorithm,
+ CURLcode result = auth_decode_digest_md5_message(chlg,
+ nonce, sizeof(nonce),
+ realm, sizeof(realm),
+ algorithm,
sizeof(algorithm),
qop_options,
sizeof(qop_options));
@@ -500,11 +479,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
if(!response)
return CURLE_OUT_OF_MEMORY;
- /* Base64 encode the response */
- result = Curl_base64_encode(data, response, 0, outptr, outlen);
-
- free(response);
-
+ /* Return the response. */
+ Curl_bufref_set(out, response, strlen(response), curl_free);
return result;
}
diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c
index dad947a..94f8f8c 100644
--- a/Utilities/cmcurl/lib/vauth/digest_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 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
@@ -32,7 +32,6 @@
#include "vauth/vauth.h"
#include "vauth/digest.h"
#include "urldata.h"
-#include "curl_base64.h"
#include "warnless.h"
#include "curl_multibyte.h"
#include "sendf.h"
@@ -79,28 +78,24 @@ bool Curl_auth_is_digest_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * chlg64 [in] - The base64 encoded challenge message.
+ * chlg [in] - The challenge message.
* userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
- const char *chlg64,
+ const struct bufref *chlg,
const char *userp,
const char *passwdp,
const char *service,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
CURLcode result = CURLE_OK;
TCHAR *spn = NULL;
- size_t chlglen = 0;
size_t token_max = 0;
- unsigned char *input_token = NULL;
unsigned char *output_token = NULL;
CredHandle credentials;
CtxtHandle context;
@@ -115,17 +110,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
unsigned long attrs;
TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
- /* Decode the base-64 encoded challenge message */
- if(strlen(chlg64) && *chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &input_token, &chlglen);
- if(result)
- return result;
- }
-
/* Ensure we have a valid challenge message */
- if(!input_token) {
- infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
-
+ if(!Curl_bufref_len(chlg)) {
+ infof(data, "DIGEST-MD5 handshake failure (empty challenge message)");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -133,8 +120,6 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
&SecurityPackage);
if(status != SEC_E_OK) {
- free(input_token);
-
failf(data, "SSPI: couldn't get auth info");
return CURLE_AUTH_ERROR;
}
@@ -146,18 +131,13 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
/* Allocate our response buffer */
output_token = malloc(token_max);
- if(!output_token) {
- free(input_token);
-
+ if(!output_token)
return CURLE_OUT_OF_MEMORY;
- }
/* Generate our SPN */
spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
if(!spn) {
free(output_token);
- free(input_token);
-
return CURLE_OUT_OF_MEMORY;
}
@@ -167,8 +147,6 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
if(result) {
free(spn);
free(output_token);
- free(input_token);
-
return result;
}
@@ -190,8 +168,6 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
Curl_sspi_free_identity(p_identity);
free(spn);
free(output_token);
- free(input_token);
-
return CURLE_LOGIN_DENIED;
}
@@ -200,8 +176,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
chlg_desc.cBuffers = 1;
chlg_desc.pBuffers = &chlg_buf;
chlg_buf.BufferType = SECBUFFER_TOKEN;
- chlg_buf.pvBuffer = input_token;
- chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+ chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg);
+ chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
/* Setup the response "output" security buffer */
resp_desc.ulVersion = SECBUFFER_VERSION;
@@ -221,26 +197,26 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
status == SEC_I_COMPLETE_AND_CONTINUE)
s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
+#endif
s_pSecFn->FreeCredentialsHandle(&credentials);
Curl_sspi_free_identity(p_identity);
free(spn);
free(output_token);
- free(input_token);
if(status == SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
- infof(data, "schannel: InitializeSecurityContext failed: %s\n",
+ infof(data, "schannel: InitializeSecurityContext failed: %s",
Curl_sspi_strerror(status, buffer, sizeof(buffer)));
return CURLE_AUTH_ERROR;
}
- /* Base64 encode the response */
- result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
- outptr, outlen);
+ /* Return the response. */
+ Curl_bufref_set(out, output_token, resp_buf.cbBuffer, curl_free);
/* Free our handles */
s_pSecFn->DeleteSecurityContext(&context);
@@ -252,12 +228,6 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
/* Free the SPN */
free(spn);
- /* Free the response buffer */
- free(output_token);
-
- /* Free the decoded challenge message */
- free(input_token);
-
return result;
}
@@ -493,7 +463,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
if(status == SEC_E_OK)
output_token_len = chlg_buf[4].cbBuffer;
else { /* delete the context so a new one can be made */
- infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n",
+ infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx",
(long)status);
s_pSecFn->DeleteSecurityContext(digest->http_context);
Curl_safefree(digest->http_context);
@@ -617,7 +587,9 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
status == SEC_I_COMPLETE_AND_CONTINUE)
s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
+#endif
s_pSecFn->FreeCredentialsHandle(&credentials);
@@ -629,7 +601,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
if(status == SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
- infof(data, "schannel: InitializeSecurityContext failed: %s\n",
+ infof(data, "schannel: InitializeSecurityContext failed: %s",
Curl_sspi_strerror(status, buffer, sizeof(buffer)));
return CURLE_AUTH_ERROR;
diff --git a/Utilities/cmcurl/lib/vauth/gsasl.c b/Utilities/cmcurl/lib/vauth/gsasl.c
new file mode 100644
index 0000000..40fef53
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/gsasl.c
@@ -0,0 +1,124 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020 - 2021, Simon Josefsson, <simon@josefsson.org>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC5802 SCRAM-SHA-1 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_GSASL
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "sendf.h"
+
+#include <gsasl.h>
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
+ const char *mech,
+ struct gsasldata *gsasl)
+{
+ int res;
+
+ res = gsasl_init(&gsasl->ctx);
+ if(res != GSASL_OK) {
+ failf(data, "gsasl init: %s\n", gsasl_strerror(res));
+ return FALSE;
+ }
+
+ res = gsasl_client_start(gsasl->ctx, mech, &gsasl->client);
+ if(res != GSASL_OK) {
+ gsasl_done(gsasl->ctx);
+ return FALSE;
+ }
+
+ return true;
+}
+
+CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ struct gsasldata *gsasl)
+{
+#if GSASL_VERSION_NUMBER >= 0x010b00
+ int res;
+ res =
+#endif
+ gsasl_property_set(gsasl->client, GSASL_AUTHID, userp);
+#if GSASL_VERSION_NUMBER >= 0x010b00
+ if(res != GSASL_OK) {
+ failf(data, "setting AUTHID failed: %s\n", gsasl_strerror(res));
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif
+
+#if GSASL_VERSION_NUMBER >= 0x010b00
+ res =
+#endif
+ gsasl_property_set(gsasl->client, GSASL_PASSWORD, passwdp);
+#if GSASL_VERSION_NUMBER >= 0x010b00
+ if(res != GSASL_OK) {
+ failf(data, "setting PASSWORD failed: %s\n", gsasl_strerror(res));
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif
+
+ (void)data;
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_auth_gsasl_token(struct Curl_easy *data,
+ const struct bufref *chlg,
+ struct gsasldata *gsasl,
+ struct bufref *out)
+{
+ int res;
+ char *response;
+ size_t outlen;
+
+ res = gsasl_step(gsasl->client,
+ (const char *) Curl_bufref_ptr(chlg), Curl_bufref_len(chlg),
+ &response, &outlen);
+ if(res != GSASL_OK && res != GSASL_NEEDS_MORE) {
+ failf(data, "GSASL step: %s\n", gsasl_strerror(res));
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ Curl_bufref_set(out, response, outlen, gsasl_free);
+ return CURLE_OK;
+}
+
+void Curl_auth_gsasl_cleanup(struct gsasldata *gsasl)
+{
+ gsasl_finish(gsasl->client);
+ gsasl->client = NULL;
+
+ gsasl_done(gsasl->ctx);
+ gsasl->ctx = NULL;
+}
+#endif
diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
index 0412815..67d43bd 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 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
@@ -32,7 +32,6 @@
#include "vauth/vauth.h"
#include "curl_sasl.h"
#include "urldata.h"
-#include "curl_base64.h"
#include "curl_gssapi.h"
#include "sendf.h"
#include "curl_printf.h"
@@ -70,12 +69,9 @@ bool Curl_auth_is_gssapi_supported(void)
* host [in[ - The host name.
* mutual_auth [in] - Flag specifying whether or not mutual authentication
* is enabled.
- * chlg64 [in] - Pointer to the optional base64 encoded challenge
- * message.
+ * chlg [in] - Optional challenge message.
* krb5 [in/out] - The Kerberos 5 data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
@@ -85,13 +81,11 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *service,
const char *host,
const bool mutual_auth,
- const char *chlg64,
+ const struct bufref *chlg,
struct kerberos5data *krb5,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
CURLcode result = CURLE_OK;
- size_t chlglen = 0;
- unsigned char *chlg = NULL;
OM_uint32 major_status;
OM_uint32 minor_status;
OM_uint32 unused_status;
@@ -127,24 +121,13 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
free(spn);
}
- if(chlg64 && *chlg64) {
- /* Decode the base-64 encoded challenge message */
- if(*chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &chlg, &chlglen);
- if(result)
- return result;
- }
-
- /* Ensure we have a valid challenge message */
- if(!chlg) {
- infof(data, "GSSAPI handshake failure (empty challenge message)\n");
-
+ if(chlg) {
+ if(!Curl_bufref_len(chlg)) {
+ infof(data, "GSSAPI handshake failure (empty challenge message)");
return CURLE_BAD_CONTENT_ENCODING;
}
-
- /* Setup the challenge "input" security buffer */
- input_token.value = chlg;
- input_token.length = chlglen;
+ input_token.value = (void *) Curl_bufref_ptr(chlg);
+ input_token.length = Curl_bufref_len(chlg);
}
major_status = Curl_gss_init_sec_context(data,
@@ -158,9 +141,6 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
mutual_auth,
NULL);
- /* Free the decoded challenge as it is not required anymore */
- free(input_token.value);
-
if(GSS_ERROR(major_status)) {
if(output_token.value)
gss_release_buffer(&unused_status, &output_token);
@@ -172,17 +152,11 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
}
if(output_token.value && output_token.length) {
- /* Base64 encode the response */
- result = Curl_base64_encode(data, (char *) output_token.value,
- output_token.length, outptr, outlen);
-
+ result = Curl_bufref_memdup(out, output_token.value, output_token.length);
gss_release_buffer(&unused_status, &output_token);
}
- else if(mutual_auth) {
- *outptr = strdup("");
- if(!*outptr)
- result = CURLE_OUT_OF_MEMORY;
- }
+ else
+ Curl_bufref_set(out, mutual_auth? "": NULL, 0, NULL);
return result;
}
@@ -196,80 +170,41 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
* Parameters:
*
* data [in] - The session handle.
- * chlg64 [in] - Pointer to the optional base64 encoded challenge message.
+ * authzid [in] - The authorization identity if some.
+ * chlg [in] - Optional challenge message.
* krb5 [in/out] - The Kerberos 5 data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
- const char *chlg64,
+ const char *authzid,
+ const struct bufref *chlg,
struct kerberos5data *krb5,
- char **outptr,
- size_t *outlen)
+ struct bufref *out)
{
CURLcode result = CURLE_OK;
- size_t chlglen = 0;
size_t messagelen = 0;
- unsigned char *chlg = NULL;
unsigned char *message = NULL;
OM_uint32 major_status;
OM_uint32 minor_status;
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;
-
- /* Decode the base-64 encoded input message */
- if(strlen(chlg64) && *chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &chlg, &chlglen);
- if(result)
- return result;
- }
/* Ensure we have a valid challenge message */
- if(!chlg) {
- infof(data, "GSSAPI handshake failure (empty security message)\n");
-
+ if(!Curl_bufref_len(chlg)) {
+ infof(data, "GSSAPI handshake failure (empty security message)");
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);
-
- free(chlg);
-
- 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);
-
- free(chlg);
-
- return CURLE_AUTH_ERROR;
- }
-
/* Setup the challenge "input" security buffer */
- input_token.value = chlg;
- input_token.length = chlglen;
+ input_token.value = (void *) Curl_bufref_ptr(chlg);
+ input_token.length = Curl_bufref_len(chlg);
/* Decrypt the inbound challenge and obtain the qop */
major_status = gss_unwrap(&minor_status, krb5->context, &input_token,
@@ -277,40 +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);
- free(chlg);
-
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)\n");
-
- gss_release_buffer(&unused_status, &username_token);
- free(chlg);
-
+ infof(data, "GSSAPI handshake failure (invalid security data)");
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);
- free(chlg);
- /* 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)\n");
-
- gss_release_buffer(&unused_status, &username_token);
+ infof(data, "GSSAPI handshake failure (invalid security layer)");
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
@@ -319,27 +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';
+ /* 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;
- /* Free the username token as it is not required anymore */
- gss_release_buffer(&unused_status, &username_token);
+ /* 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;
@@ -352,16 +276,12 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
if(GSS_ERROR(major_status)) {
Curl_gss_log_error(data, "gss_wrap() failed: ",
major_status, minor_status);
-
free(message);
-
return CURLE_AUTH_ERROR;
}
- /* Base64 encode the response */
- result = Curl_base64_encode(data, (char *) output_token.value,
- output_token.length, outptr, outlen);
-
+ /* Return the response. */
+ result = Curl_bufref_memdup(out, output_token.value, output_token.length);
/* Free the output buffer */
gss_release_buffer(&unused_status, &output_token);
diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
index b2d1635..c652fd7 100644
--- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 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
@@ -30,7 +30,6 @@
#include "vauth/vauth.h"
#include "urldata.h"
-#include "curl_base64.h"
#include "warnless.h"
#include "curl_multibyte.h"
#include "sendf.h"
@@ -81,11 +80,9 @@ bool Curl_auth_is_gssapi_supported(void)
* host [in] - The host name.
* mutual_auth [in] - Flag specifying whether or not mutual authentication
* is enabled.
- * chlg64 [in] - The optional base64 encoded challenge message.
+ * chlg [in] - Optional challenge message.
* krb5 [in/out] - The Kerberos 5 data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
@@ -95,13 +92,11 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *service,
const char *host,
const bool mutual_auth,
- const char *chlg64,
+ const struct bufref *chlg,
struct kerberos5data *krb5,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
CURLcode result = CURLE_OK;
- size_t chlglen = 0;
- unsigned char *chlg = NULL;
CtxtHandle context;
PSecPkgInfo SecurityPackage;
SecBuffer chlg_buf;
@@ -176,18 +171,9 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(chlg64 && *chlg64) {
- /* Decode the base-64 encoded challenge message */
- if(*chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &chlg, &chlglen);
- if(result)
- return result;
- }
-
- /* Ensure we have a valid challenge message */
- if(!chlg) {
- infof(data, "GSSAPI handshake failure (empty challenge message)\n");
-
+ if(chlg) {
+ if(!Curl_bufref_len(chlg)) {
+ infof(data, "GSSAPI handshake failure (empty challenge message)");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -196,8 +182,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
chlg_desc.cBuffers = 1;
chlg_desc.pBuffers = &chlg_buf;
chlg_buf.BufferType = SECBUFFER_TOKEN;
- chlg_buf.pvBuffer = chlg;
- chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+ chlg_buf.pvBuffer = (void *) Curl_bufref_ptr(chlg);
+ chlg_buf.cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
}
/* Setup the response "output" security buffer */
@@ -220,16 +206,11 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
&resp_desc, &attrs,
&expiry);
- /* Free the decoded challenge as it is not required anymore */
- free(chlg);
-
- if(status == SEC_E_INSUFFICIENT_MEMORY) {
+ if(status == SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
- }
- if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+ if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
return CURLE_AUTH_ERROR;
- }
if(memcmp(&context, krb5->context, sizeof(context))) {
s_pSecFn->DeleteSecurityContext(krb5->context);
@@ -238,15 +219,12 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
}
if(resp_buf.cbBuffer) {
- /* Base64 encode the response */
- result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer,
- resp_buf.cbBuffer, outptr, outlen);
- }
- else if(mutual_auth) {
- *outptr = strdup("");
- if(!*outptr)
- result = CURLE_OUT_OF_MEMORY;
+ result = Curl_bufref_memdup(out, resp_buf.pvBuffer, resp_buf.cbBuffer);
}
+ else if(mutual_auth)
+ Curl_bufref_set(out, "", 0, NULL);
+ else
+ Curl_bufref_set(out, NULL, 0, NULL);
return result;
}
@@ -260,26 +238,22 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
* Parameters:
*
* data [in] - The session handle.
- * chlg64 [in] - The optional base64 encoded 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.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
- const char *chlg64,
+ const char *authzid,
+ const struct bufref *chlg,
struct kerberos5data *krb5,
- char **outptr,
- size_t *outlen)
+ struct bufref *out)
{
- CURLcode result = CURLE_OK;
size_t offset = 0;
- size_t chlglen = 0;
size_t messagelen = 0;
size_t appdatalen = 0;
- unsigned char *chlg = NULL;
unsigned char *trailer = NULL;
unsigned char *message = NULL;
unsigned char *padding = NULL;
@@ -288,27 +262,20 @@ 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;
- /* Decode the base-64 encoded input message */
- if(strlen(chlg64) && *chlg64 != '=') {
- result = Curl_base64_decode(chlg64, &chlg, &chlglen);
- if(result)
- return result;
- }
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
/* Ensure we have a valid challenge message */
- if(!chlg) {
- infof(data, "GSSAPI handshake failure (empty security message)\n");
-
+ if(!Curl_bufref_len(chlg)) {
+ infof(data, "GSSAPI handshake failure (empty security message)");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -316,35 +283,20 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
status = s_pSecFn->QueryContextAttributes(krb5->context,
SECPKG_ATTR_SIZES,
&sizes);
- if(status != SEC_E_OK) {
- free(chlg);
-
- if(status == SEC_E_INSUFFICIENT_MEMORY)
- return CURLE_OUT_OF_MEMORY;
-
- 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_OK) {
- free(chlg);
- if(status == SEC_E_INSUFFICIENT_MEMORY)
- return CURLE_OUT_OF_MEMORY;
+ 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;
input_desc.pBuffers = input_buf;
input_buf[0].BufferType = SECBUFFER_STREAM;
- input_buf[0].pvBuffer = chlg;
- input_buf[0].cbBuffer = curlx_uztoul(chlglen);
+ input_buf[0].pvBuffer = (void *) Curl_bufref_ptr(chlg);
+ input_buf[0].cbBuffer = curlx_uztoul(Curl_bufref_len(chlg));
input_buf[1].BufferType = SECBUFFER_DATA;
input_buf[1].pvBuffer = NULL;
input_buf[1].cbBuffer = 0;
@@ -352,37 +304,32 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
/* Decrypt the inbound challenge and obtain the qop */
status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
if(status != SEC_E_OK) {
- infof(data, "GSSAPI handshake failure (empty security message)\n");
-
- free(chlg);
-
+ infof(data, "GSSAPI handshake failure (empty security message)");
return CURLE_BAD_CONTENT_ENCODING;
}
/* Not 4 octets long so fail as per RFC4752 Section 3.1 */
if(input_buf[1].cbBuffer != 4) {
- infof(data, "GSSAPI handshake failure (invalid security data)\n");
-
- free(chlg);
-
+ infof(data, "GSSAPI handshake failure (invalid security 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);
- free(chlg);
- /* 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)\n");
-
+ 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
@@ -395,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);
@@ -479,17 +421,14 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
offset += wrap_buf[1].cbBuffer;
memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
- /* Base64 encode the response */
- result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr,
- outlen);
-
/* Free all of our local buffers */
- free(appdata);
free(padding);
free(message);
free(trailer);
- return result;
+ /* Return the response. */
+ Curl_bufref_set(out, appdata, appdatalen, curl_free);
+ return CURLE_OK;
}
/*
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
index a3117f3..0aa3f1c 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm.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
@@ -36,7 +36,6 @@
#include "urldata.h"
#include "non-ascii.h"
#include "sendf.h"
-#include "curl_base64.h"
#include "curl_ntlm_core.h"
#include "curl_gethostname.h"
#include "curl_multibyte.h"
@@ -64,10 +63,6 @@
/* "NTLMSSP" signature is always in ASCII regardless of the platform */
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
-#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
-#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
- ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
-
#if DEBUG_ME
# define DEBUG_OUT(x) x
static void ntlm_print_flags(FILE *handle, unsigned long flags)
@@ -161,33 +156,33 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
* Parameters:
*
* data [in] - The session handle.
- * buffer [in] - The decoded type-2 message.
- * size [in] - The input buffer size, at least 32 bytes.
+ * type2ref [in] - The type-2 message.
* ntlm [in/out] - The NTLM data struct being used and modified.
*
* Returns CURLE_OK on success.
*/
static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
- unsigned char *buffer,
- size_t size,
+ const struct bufref *type2ref,
struct ntlmdata *ntlm)
{
unsigned short target_info_len = 0;
unsigned int target_info_offset = 0;
+ const unsigned char *type2 = Curl_bufref_ptr(type2ref);
+ size_t type2len = Curl_bufref_len(type2ref);
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) data;
#endif
- if(size >= 48) {
- target_info_len = Curl_read16_le(&buffer[40]);
- target_info_offset = Curl_read32_le(&buffer[44]);
+ if(type2len >= 48) {
+ target_info_len = Curl_read16_le(&type2[40]);
+ target_info_offset = Curl_read32_le(&type2[44]);
if(target_info_len > 0) {
- if((target_info_offset >= size) ||
- ((target_info_offset + target_info_len) > size) ||
- (target_info_offset < 48)) {
+ if((target_info_offset > type2len) ||
+ (target_info_offset + target_info_len) > type2len ||
+ target_info_offset < 48) {
infof(data, "NTLM handshake failure (bad type-2 message). "
- "Target Info Offset Len is set incorrect by the peer\n");
+ "Target Info Offset Len is set incorrect by the peer");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -196,7 +191,7 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
if(!ntlm->target_info)
return CURLE_OUT_OF_MEMORY;
- memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len);
+ memcpy(ntlm->target_info, &type2[target_info_offset], target_info_len);
}
}
@@ -238,21 +233,20 @@ bool Curl_auth_is_ntlm_supported(void)
/*
* Curl_auth_decode_ntlm_type2_message()
*
- * This is used to decode an already encoded NTLM type-2 message. The message
- * is first decoded from a base64 string into a raw NTLM message and checked
- * for validity before the appropriate data for creating a type-3 message is
- * written to the given NTLM data structure.
+ * This is used to decode an NTLM type-2 message. The raw NTLM message is
+ * checked * for validity before the appropriate data for creating a type-3
+ * message is * written to the given NTLM data structure.
*
* Parameters:
*
* data [in] - The session handle.
- * type2msg [in] - The base64 encoded type-2 message.
+ * type2ref [in] - The type-2 message.
* ntlm [in/out] - The NTLM data struct being used and modified.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
- const char *type2msg,
+ const struct bufref *type2ref,
struct ntlmdata *ntlm)
{
static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
@@ -274,8 +268,8 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
*/
CURLcode result = CURLE_OK;
- unsigned char *type2 = NULL;
- size_t type2_len = 0;
+ const unsigned char *type2 = Curl_bufref_ptr(type2ref);
+ size_t type2len = Curl_bufref_len(type2ref);
#if defined(NTLM_NEEDS_NSS_INIT)
/* Make sure the crypto backend is initialized */
@@ -286,27 +280,13 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
(void)data;
#endif
- /* Decode the base-64 encoded type-2 message */
- if(strlen(type2msg) && *type2msg != '=') {
- result = Curl_base64_decode(type2msg, &type2, &type2_len);
- if(result)
- return result;
- }
-
- /* Ensure we have a valid type-2 message */
- if(!type2) {
- infof(data, "NTLM handshake failure (empty type-2 message)\n");
- return CURLE_BAD_CONTENT_ENCODING;
- }
-
ntlm->flags = 0;
- if((type2_len < 32) ||
+ if((type2len < 32) ||
(memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
(memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
/* This was not a good enough type-2 message */
- free(type2);
- infof(data, "NTLM handshake failure (bad type-2 message)\n");
+ infof(data, "NTLM handshake failure (bad type-2 message)");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -314,10 +294,9 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
memcpy(ntlm->nonce, &type2[24], 8);
if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
- result = ntlm_decode_type2_target(data, type2, type2_len, ntlm);
+ result = ntlm_decode_type2_target(data, type2ref, ntlm);
if(result) {
- free(type2);
- infof(data, "NTLM handshake failure (bad type-2 message)\n");
+ infof(data, "NTLM handshake failure (bad type-2 message)");
return result;
}
}
@@ -331,8 +310,6 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
fprintf(stderr, "**** Header %s\n ", header);
});
- free(type2);
-
return result;
}
@@ -350,8 +327,8 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
/*
* Curl_auth_create_ntlm_type1_message()
*
- * This is used to generate an already encoded NTLM type-1 message ready for
- * sending to the recipient using the appropriate compile time crypto API.
+ * This is used to generate an NTLM type-1 message ready for sending to the
+ * recipient using the appropriate compile time crypto API.
*
* Parameters:
*
@@ -361,9 +338,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* ntlm [in/out] - The NTLM data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
@@ -373,7 +348,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *service,
const char *hostname,
struct ntlmdata *ntlm,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
/* NTLM type-1 message structure:
@@ -391,7 +366,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
size_t size;
- unsigned char ntlmbuf[NTLM_BUFSIZE];
+ char *ntlmbuf;
const char *host = ""; /* empty */
const char *domain = ""; /* empty */
size_t hostlen = 0;
@@ -399,6 +374,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
size_t hostoff = 0;
size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
domain are empty */
+ (void)data;
(void)userp;
(void)passwdp;
(void)service,
@@ -407,43 +383,46 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
/* Clean up any former leftovers and initialise to defaults */
Curl_auth_cleanup_ntlm(ntlm);
-#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
+#if defined(USE_NTRESPONSES) && \
+ (defined(USE_NTLM2SESSION) || defined(USE_NTLM_V2))
#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
#else
#define NTLM2FLAG 0
#endif
- msnprintf((char *)ntlmbuf, NTLM_BUFSIZE,
- NTLMSSP_SIGNATURE "%c"
- "\x01%c%c%c" /* 32-bit type = 1 */
- "%c%c%c%c" /* 32-bit NTLM flag field */
- "%c%c" /* domain length */
- "%c%c" /* domain allocated space */
- "%c%c" /* domain name offset */
- "%c%c" /* 2 zeroes */
- "%c%c" /* host length */
- "%c%c" /* host allocated space */
- "%c%c" /* host name offset */
- "%c%c" /* 2 zeroes */
- "%s" /* host name */
- "%s", /* domain string */
- 0, /* trailing zero */
- 0, 0, 0, /* part of type-1 long */
-
- LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
- NTLMFLAG_REQUEST_TARGET |
- NTLMFLAG_NEGOTIATE_NTLM_KEY |
- NTLM2FLAG |
- NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
- SHORTPAIR(domlen),
- SHORTPAIR(domlen),
- SHORTPAIR(domoff),
- 0, 0,
- SHORTPAIR(hostlen),
- SHORTPAIR(hostlen),
- SHORTPAIR(hostoff),
- 0, 0,
- host, /* this is empty */
- domain /* this is empty */);
+ ntlmbuf = aprintf(NTLMSSP_SIGNATURE "%c"
+ "\x01%c%c%c" /* 32-bit type = 1 */
+ "%c%c%c%c" /* 32-bit NTLM flag field */
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host name offset */
+ "%c%c" /* 2 zeroes */
+ "%s" /* host name */
+ "%s", /* domain string */
+ 0, /* trailing zero */
+ 0, 0, 0, /* part of type-1 long */
+
+ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0, 0,
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0, 0,
+ host, /* this is empty */
+ domain /* this is empty */);
+
+ if(!ntlmbuf)
+ return CURLE_OUT_OF_MEMORY;
/* Initial packet length */
size = 32 + hostlen + domlen;
@@ -470,8 +449,8 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
fprintf(stderr, "\n****\n");
});
- /* Return with binary blob encoded into base64 */
- return Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
+ Curl_bufref_set(out, ntlmbuf, size, curl_free);
+ return CURLE_OK;
}
/*
@@ -486,9 +465,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
* userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
@@ -496,7 +473,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct ntlmdata *ntlm,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
/* NTLM type-3 message structure:
@@ -556,19 +533,27 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
/* Get the machine's un-qualified host name as NTLM doesn't like the fully
qualified domain name */
if(Curl_gethostname(host, sizeof(host))) {
- infof(data, "gethostname() failed, continuing without!\n");
+ infof(data, "gethostname() failed, continuing without!");
hostlen = 0;
}
else {
hostlen = strlen(host);
}
-#if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2)
+#if defined(USE_NTRESPONSES) && \
+ (defined(USE_NTLM2SESSION) || defined(USE_NTLM_V2))
+ /* We don't support NTLM2 or extended security if we don't have
+ USE_NTRESPONSES */
if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+# if defined(USE_NTLM_V2)
unsigned char ntbuffer[0x18];
unsigned char entropy[8];
unsigned char ntlmv2hash[0x18];
+ /* Full NTLM version 2
+ Although this cannot be negotiated, it is used here if available, as
+ servers featuring extended security are likely supporting also
+ NTLMv2. */
result = Curl_rand(data, entropy, 8);
if(result)
return result;
@@ -595,21 +580,14 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
return result;
ptr_ntresp = ntlmv2resp;
- }
- else
-#endif
-
-#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
-
-#define CURL_MD5_DIGEST_LENGTH 16 /* fixed size */
-
- /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
- if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) {
+# else /* defined(USE_NTLM_V2) */
unsigned char ntbuffer[0x18];
unsigned char tmp[0x18];
- unsigned char md5sum[CURL_MD5_DIGEST_LENGTH];
+ unsigned char md5sum[MD5_DIGEST_LEN];
unsigned char entropy[8];
+ /* NTLM version 1 with extended security. */
+
/* Need to create 8 bytes random data */
result = Curl_rand(data, entropy, 8);
if(result)
@@ -639,6 +617,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
/* NTLM v2 session security is a misnomer because it is not NTLM v2.
It is NTLM v1 using the extended session security that is also
in NTLM v2 */
+# endif /* defined(USE_NTLM_V2) */
}
else
#endif
@@ -649,6 +628,8 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
#endif
unsigned char lmbuffer[0x18];
+ /* NTLM version 1 */
+
#ifdef USE_NTRESPONSES
result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
if(result)
@@ -662,6 +643,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
return result;
Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
+ ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY;
/* A safer but less compatible alternative is:
* Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
@@ -845,8 +827,8 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
if(result)
return CURLE_CONV_FAILED;
- /* Return with binary blob encoded into base64 */
- result = Curl_base64_encode(data, (char *)ntlmbuf, size, outptr, outlen);
+ /* Return the binary blob. */
+ result = Curl_bufref_memdup(out, ntlmbuf, size);
Curl_auth_cleanup_ntlm(ntlm);
diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
index 07dc973..3e39dad 100644
--- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.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
@@ -28,7 +28,6 @@
#include "vauth/vauth.h"
#include "urldata.h"
-#include "curl_base64.h"
#include "curl_ntlm_core.h"
#include "warnless.h"
#include "curl_multibyte.h"
@@ -78,9 +77,7 @@ bool Curl_auth_is_ntlm_supported(void)
* service [in] - The service type such as http, smtp, pop or imap.
* host [in] - The host name.
* ntlm [in/out] - The NTLM data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
@@ -90,7 +87,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *service,
const char *host,
struct ntlmdata *ntlm,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
PSecPkgInfo SecurityPackage;
SecBuffer type_1_buf;
@@ -181,9 +178,9 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
return CURLE_AUTH_ERROR;
- /* Base64 encode the response */
- return Curl_base64_encode(data, (char *) ntlm->output_token,
- type_1_buf.cbBuffer, outptr, outlen);
+ /* Return the response. */
+ Curl_bufref_set(out, ntlm->output_token, type_1_buf.cbBuffer, NULL);
+ return CURLE_OK;
}
/*
@@ -194,42 +191,34 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
* Parameters:
*
* data [in] - The session handle.
- * type2msg [in] - The base64 encoded type-2 message.
+ * type2 [in] - The type-2 message.
* ntlm [in/out] - The NTLM data struct being used and modified.
*
* Returns CURLE_OK on success.
*/
CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
- const char *type2msg,
+ const struct bufref *type2,
struct ntlmdata *ntlm)
{
- CURLcode result = CURLE_OK;
- unsigned char *type2 = NULL;
- size_t type2_len = 0;
-
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) data;
#endif
- /* Decode the base-64 encoded type-2 message */
- if(strlen(type2msg) && *type2msg != '=') {
- result = Curl_base64_decode(type2msg, &type2, &type2_len);
- if(result)
- return result;
- }
-
/* Ensure we have a valid type-2 message */
- if(!type2) {
- infof(data, "NTLM handshake failure (empty type-2 message)\n");
-
+ if(!Curl_bufref_len(type2)) {
+ infof(data, "NTLM handshake failure (empty type-2 message)");
return CURLE_BAD_CONTENT_ENCODING;
}
- /* Simply store the challenge for use later */
- ntlm->input_token = type2;
- ntlm->input_token_len = type2_len;
+ /* Store the challenge for later use */
+ ntlm->input_token = malloc(Curl_bufref_len(type2) + 1);
+ if(!ntlm->input_token)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(ntlm->input_token, Curl_bufref_ptr(type2), Curl_bufref_len(type2));
+ ntlm->input_token[Curl_bufref_len(type2)] = '\0';
+ ntlm->input_token_len = Curl_bufref_len(type2);
- return result;
+ return CURLE_OK;
}
/*
@@ -245,9 +234,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
* userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
- * outptr [in/out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen [out] - The length of the output message.
+ * out [out] - The result storage.
*
* Returns CURLE_OK on success.
*/
@@ -255,7 +242,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct ntlmdata *ntlm,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
CURLcode result = CURLE_OK;
SecBuffer type_2_bufs[2];
@@ -266,6 +253,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
unsigned long attrs;
TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
(void) passwdp;
(void) userp;
@@ -322,7 +312,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
&type_3_desc,
&attrs, &expiry);
if(status != SEC_E_OK) {
- infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
+ infof(data, "NTLM handshake failure (type-3 message): Status=%x",
status);
if(status == SEC_E_INSUFFICIENT_MEMORY)
@@ -331,12 +321,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
return CURLE_AUTH_ERROR;
}
- /* Base64 encode the response */
- result = Curl_base64_encode(data, (char *) ntlm->output_token,
- type_3_buf.cbBuffer, outptr, outlen);
-
+ /* Return the response. */
+ result = Curl_bufref_memdup(out, ntlm->output_token, type_3_buf.cbBuffer);
Curl_auth_cleanup_ntlm(ntlm);
-
return result;
}
diff --git a/Utilities/cmcurl/lib/vauth/oauth2.c b/Utilities/cmcurl/lib/vauth/oauth2.c
index ca5842a..a5f16a0 100644
--- a/Utilities/cmcurl/lib/vauth/oauth2.c
+++ b/Utilities/cmcurl/lib/vauth/oauth2.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
@@ -31,7 +31,6 @@
#include "urldata.h"
#include "vauth/vauth.h"
-#include "curl_base64.h"
#include "warnless.h"
#include "curl_printf.h"
@@ -42,31 +41,26 @@
/*
* Curl_auth_create_oauth_bearer_message()
*
- * This is used to generate an already encoded OAuth 2.0 message ready for
- * sending to the recipient.
+ * This is used to generate an OAuth 2.0 message ready for sending to the
+ * recipient.
*
* Parameters:
*
- * data[in] - The session handle.
* user[in] - The user name.
* host[in] - The host name.
* port[in] - The port(when not Port 80).
* bearer[in] - The bearer token.
- * outptr[in / out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen[out] - The length of the output message.
+ * out[out] - The result storage.
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
- const char *user,
+CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
const char *host,
const long port,
const char *bearer,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
- CURLcode result = CURLE_OK;
- char *oauth = NULL;
+ char *oauth;
/* Generate the message */
if(port == 0 || port == 80)
@@ -78,49 +72,34 @@ CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
if(!oauth)
return CURLE_OUT_OF_MEMORY;
- /* Base64 encode the reply */
- result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen);
-
- free(oauth);
-
- return result;
+ Curl_bufref_set(out, oauth, strlen(oauth), curl_free);
+ return CURLE_OK;
}
/*
* Curl_auth_create_xoauth_bearer_message()
*
- * This is used to generate an already encoded XOAuth 2.0 message ready for
- * sending to the recipient.
+ * This is used to generate a XOAuth 2.0 message ready for * sending to the
+ * recipient.
*
* Parameters:
*
- * data[in] - The session handle.
* user[in] - The user name.
* bearer[in] - The bearer token.
- * outptr[in / out] - The address where a pointer to newly allocated memory
- * holding the result will be stored upon completion.
- * outlen[out] - The length of the output message.
+ * out[out] - The result storage.
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_easy *data,
- const char *user,
+CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
const char *bearer,
- char **outptr, size_t *outlen)
+ struct bufref *out)
{
- CURLcode result = CURLE_OK;
-
/* Generate the message */
char *xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
if(!xoauth)
return CURLE_OUT_OF_MEMORY;
- /* Base64 encode the reply */
- result = Curl_base64_encode(data, xoauth, strlen(xoauth), outptr, outlen);
-
- free(xoauth);
-
- return result;
+ Curl_bufref_set(out, xoauth, strlen(xoauth), curl_free);
+ return CURLE_OK;
}
#endif /* disabled, no users */
-
diff --git a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
index 120925f..8e8932b 100644
--- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.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
@@ -137,8 +137,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
/* Ensure we have a valid challenge message */
if(!chlg) {
- infof(data, "SPNEGO handshake failure (empty challenge message)\n");
-
+ infof(data, "SPNEGO handshake failure (empty challenge message)");
return CURLE_BAD_CONTENT_ENCODING;
}
diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
index 4aa1ba9..68bb17d 100644
--- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c
+++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.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
@@ -191,8 +191,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
/* Ensure we have a valid challenge message */
if(!chlg) {
- infof(data, "SPNEGO handshake failure (empty challenge message)\n");
-
+ infof(data, "SPNEGO handshake failure (empty challenge message)");
return CURLE_BAD_CONTENT_ENCODING;
}
diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c
index 129b8f8..3624fb0 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.c
+++ b/Utilities/cmcurl/lib/vauth/vauth.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 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
@@ -72,6 +72,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
{
char *utf8_spn = NULL;
TCHAR *tchar_spn = NULL;
+ TCHAR *dupe_tchar_spn = NULL;
(void) realm;
@@ -84,23 +85,19 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
/* Generate our UTF8 based SPN */
utf8_spn = aprintf("%s/%s", service, host);
- if(!utf8_spn) {
+ if(!utf8_spn)
return NULL;
- }
- /* Allocate our TCHAR based SPN */
+ /* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar
+ must be freed by curlx_unicodefree we'll dupe the result so that the
+ pointer this function returns can be normally free'd. */
tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
- if(!tchar_spn) {
- free(utf8_spn);
-
+ free(utf8_spn);
+ if(!tchar_spn)
return NULL;
- }
-
- /* Release the UTF8 variant when operating with Unicode */
- curlx_unicodefree(utf8_spn);
-
- /* Return our newly allocated SPN */
- return tchar_spn;
+ dupe_tchar_spn = _tcsdup(tchar_spn);
+ curlx_unicodefree(tchar_spn);
+ return dupe_tchar_spn;
}
#endif /* USE_WINDOWS_SSPI */
diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h
index f25cfc3..47a7c0b 100644
--- a/Utilities/cmcurl/lib/vauth/vauth.h
+++ b/Utilities/cmcurl/lib/vauth/vauth.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 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
@@ -24,6 +24,8 @@
#include <curl/curl.h>
+#include "bufref.h"
+
struct Curl_easy;
#if !defined(CURL_DISABLE_CRYPTO_AUTH)
@@ -42,6 +44,10 @@ struct kerberos5data;
struct negotiatedata;
#endif
+#if defined(USE_GSASL)
+struct gsasldata;
+#endif
+
#if defined(USE_WINDOWS_SSPI)
#define GSS_ERROR(status) ((status) & 0x80000000)
#endif
@@ -58,45 +64,37 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
/* This is used to test if the user contains a Windows domain name */
bool Curl_auth_user_contains_domain(const char *user);
-/* This is used to generate a base64 encoded PLAIN cleartext message */
-CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
- const char *authzid,
+/* This is used to generate a PLAIN cleartext message */
+CURLcode Curl_auth_create_plain_message(const char *authzid,
const char *authcid,
const char *passwd,
- char **outptr, size_t *outlen);
+ struct bufref *out);
-/* This is used to generate a base64 encoded LOGIN cleartext message */
-CURLcode Curl_auth_create_login_message(struct Curl_easy *data,
- const char *valuep, char **outptr,
- size_t *outlen);
+/* This is used to generate a LOGIN cleartext message */
+CURLcode Curl_auth_create_login_message(const char *value,
+ struct bufref *out);
-/* This is used to generate a base64 encoded EXTERNAL cleartext message */
-CURLcode Curl_auth_create_external_message(struct Curl_easy *data,
- const char *user, char **outptr,
- size_t *outlen);
+/* This is used to generate an EXTERNAL cleartext message */
+CURLcode Curl_auth_create_external_message(const char *user,
+ struct bufref *out);
#if !defined(CURL_DISABLE_CRYPTO_AUTH)
-/* This is used to decode a CRAM-MD5 challenge message */
-CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
- size_t *outlen);
-
/* This is used to generate a CRAM-MD5 response message */
-CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
- const char *chlg,
+CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
const char *userp,
const char *passwdp,
- char **outptr, size_t *outlen);
+ struct bufref *out);
/* This is used to evaluate if DIGEST is supported */
bool Curl_auth_is_digest_supported(void);
/* This is used to generate a base64 encoded DIGEST-MD5 response message */
CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
- const char *chlg64,
+ const struct bufref *chlg,
const char *userp,
const char *passwdp,
const char *service,
- char **outptr, size_t *outlen);
+ struct bufref *out);
/* This is used to decode a HTTP DIGEST challenge message */
CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
@@ -115,6 +113,27 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
void Curl_auth_digest_cleanup(struct digestdata *digest);
#endif /* !CURL_DISABLE_CRYPTO_AUTH */
+#ifdef USE_GSASL
+/* This is used to evaluate if MECH is supported by gsasl */
+bool Curl_auth_gsasl_is_supported(struct Curl_easy *data,
+ const char *mech,
+ struct gsasldata *gsasl);
+/* This is used to start a gsasl method */
+CURLcode Curl_auth_gsasl_start(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ struct gsasldata *gsasl);
+
+/* This is used to process and generate a new SASL token */
+CURLcode Curl_auth_gsasl_token(struct Curl_easy *data,
+ const struct bufref *chlg,
+ struct gsasldata *gsasl,
+ struct bufref *out);
+
+/* This is used to clean up the gsasl specific data */
+void Curl_auth_gsasl_cleanup(struct gsasldata *digest);
+#endif
+
#if defined(USE_NTLM)
/* This is used to evaluate if NTLM is supported */
bool Curl_auth_is_ntlm_supported(void);
@@ -126,12 +145,11 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
const char *service,
const char *host,
struct ntlmdata *ntlm,
- char **outptr,
- size_t *outlen);
+ struct bufref *out);
/* This is used to decode a base64 encoded NTLM type-2 message */
CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
- const char *type2msg,
+ const struct bufref *type2,
struct ntlmdata *ntlm);
/* This is used to generate a base64 encoded NTLM type-3 message */
@@ -139,25 +157,23 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
const char *userp,
const char *passwdp,
struct ntlmdata *ntlm,
- char **outptr, size_t *outlen);
+ struct bufref *out);
/* This is used to clean up the NTLM specific data */
void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm);
#endif /* USE_NTLM */
/* This is used to generate a base64 encoded OAuth 2.0 message */
-CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
- const char *user,
+CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
const char *host,
const long port,
const char *bearer,
- char **outptr, size_t *outlen);
+ struct bufref *out);
/* This is used to generate a base64 encoded XOAuth 2.0 message */
-CURLcode Curl_auth_create_xoauth_bearer_message(struct Curl_easy *data,
- const char *user,
+CURLcode Curl_auth_create_xoauth_bearer_message(const char *user,
const char *bearer,
- char **outptr, size_t *outlen);
+ struct bufref *out);
#if defined(USE_KERBEROS5)
/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */
@@ -171,17 +187,17 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
const char *service,
const char *host,
const bool mutual,
- const char *chlg64,
+ const struct bufref *chlg,
struct kerberos5data *krb5,
- char **outptr, size_t *outlen);
+ struct bufref *out);
/* 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 *input,
+ const char *authzid,
+ const struct bufref *chlg,
struct kerberos5data *krb5,
- char **outptr,
- size_t *outlen);
+ struct bufref *out);
/* This is used to clean up the GSSAPI specific data */
void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5);
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
index a9102ec..c84ef85 100644
--- a/Utilities/cmcurl/lib/version.c
+++ b/Utilities/cmcurl/lib/version.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
@@ -66,29 +66,35 @@
#include <zstd.h>
#endif
+#ifdef USE_GSASL
+#include <gsasl.h>
+#endif
+
+#ifdef USE_OPENLDAP
+#include <ldap.h>
+#endif
+
#ifdef HAVE_BROTLI
-static size_t brotli_version(char *buf, size_t bufsz)
+static void brotli_version(char *buf, size_t bufsz)
{
uint32_t brotli_version = BrotliDecoderVersion();
unsigned int major = brotli_version >> 24;
unsigned int minor = (brotli_version & 0x00FFFFFF) >> 12;
unsigned int patch = brotli_version & 0x00000FFF;
-
- return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+ (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
}
#endif
#ifdef HAVE_ZSTD
-static size_t zstd_version(char *buf, size_t bufsz)
+static void zstd_version(char *buf, size_t bufsz)
{
unsigned long zstd_version = (unsigned long)ZSTD_versionNumber();
unsigned int major = (unsigned int)(zstd_version / (100 * 100));
unsigned int minor = (unsigned int)((zstd_version -
- (major * 100 * 100)) / 100);
+ (major * 100 * 100)) / 100);
unsigned int patch = (unsigned int)(zstd_version -
- (major * 100 * 100) - (minor * 100));
-
- return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+ (major * 100 * 100) - (minor * 100));
+ (void)msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
}
#endif
@@ -100,7 +106,7 @@ static size_t zstd_version(char *buf, size_t bufsz)
* zeros in the data.
*/
-#define VERSION_PARTS 15 /* number of substrings we can concatenate */
+#define VERSION_PARTS 17 /* number of substrings we can concatenate */
char *curl_version(void)
{
@@ -147,6 +153,12 @@ char *curl_version(void)
#ifdef USE_HYPER
char hyper_buf[30];
#endif
+#ifdef USE_GSASL
+ char gsasl_buf[30];
+#endif
+#ifdef USE_OPENLDAP
+ char ldap_buf[30];
+#endif
int i = 0;
int j;
@@ -235,6 +247,29 @@ char *curl_version(void)
msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s", hyper_version());
src[i++] = hyper_buf;
#endif
+#ifdef USE_GSASL
+ msnprintf(gsasl_buf, sizeof(gsasl_buf), "libgsasl/%s",
+ gsasl_check_version(NULL));
+ src[i++] = gsasl_buf;
+#endif
+#ifdef USE_OPENLDAP
+ {
+ LDAPAPIInfo api;
+ api.ldapai_info_version = LDAP_API_INFO_VERSION;
+
+ if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
+ unsigned int patch = api.ldapai_vendor_version % 100;
+ unsigned int major = api.ldapai_vendor_version / 10000;
+ unsigned int minor =
+ ((api.ldapai_vendor_version - major * 10000) - patch) / 100;
+ msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u",
+ api.ldapai_vendor_name, major, minor, patch);
+ src[i++] = ldap_buf;
+ ldap_memfree(api.ldapai_vendor_name);
+ ber_memvfree((void **)api.ldapai_extensions);
+ }
+ }
+#endif
DEBUGASSERT(i <= VERSION_PARTS);
@@ -326,7 +361,7 @@ static const char * const protocols[] = {
"sftp",
#endif
#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
- (CURL_SIZEOF_CURL_OFF_T > 4)
+ (SIZEOF_CURL_OFF_T > 4)
"smb",
# ifdef USE_SSL
"smbs",
@@ -391,7 +426,7 @@ static curl_version_info_data version_info = {
#ifdef CURLRES_ASYNCH
| CURL_VERSION_ASYNCHDNS
#endif
-#if (CURL_SIZEOF_CURL_OFF_T > 4) && \
+#if (SIZEOF_CURL_OFF_T > 4) && \
( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
| CURL_VERSION_LARGEFILE
#endif
@@ -428,9 +463,12 @@ static curl_version_info_data version_info = {
#ifndef CURL_DISABLE_ALTSVC
| CURL_VERSION_ALTSVC
#endif
-#if defined(USE_HSTS)
+#ifndef CURL_DISABLE_HSTS
| CURL_VERSION_HSTS
#endif
+#if defined(USE_GSASL)
+ | CURL_VERSION_GSASL
+#endif
,
NULL, /* ssl_version */
0, /* ssl_version_num, this is kept at zero */
@@ -458,7 +496,8 @@ static curl_version_info_data version_info = {
#endif
0, /* zstd_ver_num */
NULL, /* zstd version */
- NULL /* Hyper version */
+ NULL, /* Hyper version */
+ NULL /* gsasl version */
};
curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -562,6 +601,12 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
}
#endif
+#ifdef USE_GSASL
+ {
+ version_info.gsasl_version = gsasl_check_version(NULL);
+ }
+#endif
+
(void)stamp; /* avoid compiler warnings, we don't use this */
return &version_info;
}
diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c
index d4d0e8b..9fcfe81 100644
--- a/Utilities/cmcurl/lib/vquic/ngtcp2.c
+++ b/Utilities/cmcurl/lib/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"
@@ -57,6 +60,8 @@
#define H3BUGF(x) do { } while(0)
#endif
+#define H3_ALPN_H3_29 "\x5h3-29"
+
/*
* This holds outgoing HTTP/3 stream data that is used by nghttp3 until acked.
* It is used as a circular buffer. Add new bytes at the end until it reaches
@@ -84,7 +89,8 @@ struct h3out {
#define QUIC_PRIORITY \
"NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
"+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
- "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1"
+ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
+ "%DISABLE_TLS13_COMPAT_MODE"
#endif
static CURLcode ng_process_ingress(struct Curl_easy *data,
@@ -114,42 +120,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)
{
@@ -220,27 +190,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 == NULL) {
- 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"));
}
@@ -257,7 +209,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)
@@ -279,7 +231,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);
}
@@ -351,8 +304,8 @@ static int quic_init_ssl(struct quicsocket *qs)
SSL_set_app_data(qs->ssl, qs);
SSL_set_connect_state(qs->ssl);
- alpn = (const uint8_t *)NGHTTP3_ALPN_H3;
- alpnlen = sizeof(NGHTTP3_ALPN_H3) - 1;
+ alpn = (const uint8_t *)H3_ALPN_H3_29;
+ alpnlen = sizeof(H3_ALPN_H3_29) - 1;
if(alpn)
SSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen);
@@ -367,7 +320,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(
@@ -392,7 +346,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)
@@ -529,8 +484,8 @@ static int quic_init_ssl(struct quicsocket *qs)
}
/* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
- alpn.data = (unsigned char *)NGHTTP3_ALPN_H3 + 1;
- alpn.size = sizeof(NGHTTP3_ALPN_H3) - 2;
+ 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);
@@ -540,22 +495,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;
@@ -580,7 +519,7 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
{
struct quicsocket *qs = (struct quicsocket *)user_data;
ssize_t nconsumed;
- int fin = flags & NGTCP2_STREAM_DATA_FLAG_FIN ? 1 : 0;
+ int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
(void)offset;
(void)stream_user_data;
@@ -601,7 +540,7 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
static int
cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
- uint64_t offset, size_t datalen, void *user_data,
+ uint64_t offset, uint64_t datalen, void *user_data,
void *stream_user_data)
{
struct quicsocket *qs = (struct quicsocket *)user_data;
@@ -613,15 +552,15 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
(void)stream_user_data;
rv = nghttp3_conn_add_ack_offset(qs->h3conn, stream_id, datalen);
- if(rv != 0) {
+ if(rv) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
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;
@@ -630,9 +569,13 @@ 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 != 0) {
+ if(rv) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -650,8 +593,26 @@ 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);
- if(rv != 0) {
+ 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;
}
@@ -680,7 +641,7 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
(void)stream_user_data;
rv = nghttp3_conn_unblock_stream(qs->h3conn, stream_id);
- if(rv != 0) {
+ if(rv) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -710,14 +671,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,
@@ -739,7 +699,12 @@ static ngtcp2_callbacks ng_callbacks = {
NULL, /* handshake_confirmed */
NULL, /* recv_new_token */
ngtcp2_crypto_delete_crypto_aead_ctx_cb,
- ngtcp2_crypto_delete_crypto_cipher_ctx_cb
+ ngtcp2_crypto_delete_crypto_cipher_ctx_cb,
+ NULL, /* recv_datagram */
+ NULL, /* ack_datagram */
+ NULL, /* lost_datagram */
+ NULL, /* get_path_challenge_data */
+ cb_stream_stop_sending
};
/*
@@ -758,7 +723,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
ngtcp2_path path; /* TODO: this must be initialized properly */
struct quicsocket *qs = &conn->hequic[sockindex];
char ipbuf[40];
- long port;
+ int port;
int qfd;
if(qs->conn)
@@ -773,7 +738,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- infof(data, "Connect socket %d over QUIC to %s:%ld\n",
+ infof(data, "Connect socket %d over QUIC to %s:%d",
sockfd, ipbuf, port);
qs->version = NGTCP2_PROTO_VER_MAX;
@@ -807,8 +772,8 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
return CURLE_QUIC_CONNECT_ERROR;
ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
- qs->local_addrlen, NULL);
- ngtcp2_addr_init(&path.remote, addr, addrlen, NULL);
+ qs->local_addrlen);
+ 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,
@@ -822,15 +787,14 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
}
/*
- * Store ngtp2 version info in this buffer, Prefix with a space. Return total
- * length written.
+ * Store ngtcp2 version info in this buffer.
*/
-int Curl_quic_ver(char *p, size_t len)
+void Curl_quic_ver(char *p, size_t len)
{
- ngtcp2_info *ng2 = ngtcp2_version(0);
+ const ngtcp2_info *ng2 = ngtcp2_version(0);
nghttp3_info *ht3 = nghttp3_version(0);
- return msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
- ng2->version_str, ht3->version_str);
+ (void)msnprintf(p, len, "ngtcp2/%s nghttp3/%s",
+ ng2->version_str, ht3->version_str);
}
static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
@@ -854,7 +818,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;
@@ -870,11 +833,11 @@ static void qs_disconnect(struct quicsocket *qs)
#endif
qs->ssl = NULL;
#ifdef USE_GNUTLS
- if(qs->cred)
+ if(qs->cred) {
gnutls_certificate_free_credentials(qs->cred);
+ 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
@@ -927,6 +890,7 @@ static const struct Curl_handler Curl_handler_http3 = {
ng_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ng_conncheck, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
CURLPROTO_HTTPS, /* protocol */
CURLPROTO_HTTP, /* family */
@@ -943,7 +907,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
(void)stream_id;
(void)app_error_code;
(void)user_data;
- H3BUGF(infof(data, "cb_h3_stream_close CALLED\n"));
+ H3BUGF(infof(data, "cb_h3_stream_close CALLED"));
stream->closed = TRUE;
Curl_expire(data, 0, EXPIRE_QUIC);
@@ -1135,14 +1099,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)
@@ -1279,7 +1239,7 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data,
return 0;
}
- infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN\n");
+ infof(data, "ngh3_stream_recv returns 0 bytes and EAGAIN");
*curlcode = CURLE_AGAIN;
return -1;
}
@@ -1291,19 +1251,18 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
{
struct Curl_easy *data = stream_user_data;
struct HTTP *stream = data->req.p.http;
- int rv;
(void)user_data;
if(!data->set.postfields) {
stream->h3out->used -= datalen;
H3BUGF(infof(data,
- "cb_h3_acked_stream_data, %zd bytes, %zd left unacked\n",
+ "cb_h3_acked_stream_data, %zd bytes, %zd left unacked",
datalen, stream->h3out->used));
DEBUGASSERT(stream->h3out->used < H3_SEND_SIZE);
if(stream->h3out->used == 0) {
- rv = nghttp3_conn_resume_stream(conn, stream_id);
- if(rv != 0) {
+ int rv = nghttp3_conn_resume_stream(conn, stream_id);
+ if(rv) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
}
@@ -1359,13 +1318,13 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
if(!stream->upload_left)
*pflags = NGHTTP3_DATA_FLAG_EOF;
}
- H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)\n",
+ H3BUGF(infof(data, "cb_h3_readfunction %zd bytes%s (at %zd unacked)",
nread, *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
out->used));
}
if(stream->upload_done && !stream->upload_len &&
(stream->upload_left <= 0)) {
- H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF\n"));
+ H3BUGF(infof(data, "!!!!!!!!! cb_h3_readfunction sets EOF"));
*pflags = NGHTTP3_DATA_FLAG_EOF;
return nread ? 1 : 0;
}
@@ -1539,7 +1498,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
}
/* :authority must come before non-pseudo header fields */
- if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
+ if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
nghttp3_nv authority = nva[authority_idx];
for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
nva[i] = nva[i - 1];
@@ -1558,7 +1517,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
if(acc > MAX_ACC) {
infof(data, "http_request: Warning: The cumulative length of all "
"headers exceeds %d bytes and that could cause the "
- "stream to be rejected.\n", MAX_ACC);
+ "stream to be rejected.", MAX_ACC);
}
}
@@ -1604,7 +1563,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
Curl_safefree(nva);
- infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
+ infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
stream3_id, (void *)data);
return CURLE_OK;
@@ -1634,7 +1593,7 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
sent = len;
}
else {
- H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes\n",
+ H3BUGF(infof(data, "ngh3_stream_send() wants to send %zd bytes",
len));
if(!stream->upload_len) {
stream->upload_mem = mem;
@@ -1653,6 +1612,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;
}
@@ -1730,12 +1695,12 @@ static CURLcode ng_process_ingress(struct Curl_easy *data,
}
ngtcp2_addr_init(&path.local, (struct sockaddr *)&qs->local_addr,
- qs->local_addrlen, NULL);
+ qs->local_addrlen);
ngtcp2_addr_init(&path.remote, (struct sockaddr *)&remote_addr,
- remote_addrlen, NULL);
+ remote_addrlen);
rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts);
- if(rv != 0) {
+ if(rv) {
/* TODO Send CONNECTION_CLOSE if possible */
return CURLE_RECV_ERROR;
}
@@ -1751,8 +1716,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;
@@ -1765,21 +1729,8 @@ 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 != 0) {
+ if(rv) {
failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
ngtcp2_strerror(rv));
return CURLE_SEND_ERROR;
@@ -1788,7 +1739,6 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
ngtcp2_path_storage_zero(&ps);
for(;;) {
- outlen = -1;
veccnt = 0;
stream_id = -1;
fin = 0;
@@ -1805,35 +1755,44 @@ 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 != 0) {
+ if(rv) {
failf(data, "nghttp3_conn_block_stream returned error: %s\n",
nghttp3_strerror(rv));
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 != 0) {
+ if(rv) {
failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
nghttp3_strerror(rv));
return CURLE_SEND_ERROR;
}
continue;
- }
- else {
+ default:
assert(ndatalen == -1);
failf(data, "ngtcp2_conn_writev_stream returned error: %s",
ngtcp2_strerror((int)outlen));
@@ -1842,7 +1801,7 @@ static CURLcode ng_flush_egress(struct Curl_easy *data,
}
else if(ndatalen >= 0) {
rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
- if(rv != 0) {
+ if(rv) {
failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
nghttp3_strerror(rv));
return CURLE_SEND_ERROR;
diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.h b/Utilities/cmcurl/lib/vquic/ngtcp2.h
index cbede45..5014530 100644
--- a/Utilities/cmcurl/lib/vquic/ngtcp2.h
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vquic/quiche.c b/Utilities/cmcurl/lib/vquic/quiche.c
index d138dd3..f757760 100644
--- a/Utilities/cmcurl/lib/vquic/quiche.c
+++ b/Utilities/cmcurl/lib/vquic/quiche.c
@@ -157,6 +157,7 @@ static const struct Curl_handler Curl_handler_http3 = {
quiche_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
quiche_conncheck, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
CURLPROTO_HTTPS, /* protocol */
CURLPROTO_HTTP, /* family */
@@ -180,7 +181,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
struct quicsocket *qs = &conn->hequic[sockindex];
char *keylog_file = NULL;
char ipbuf[40];
- long port;
+ int port;
#ifdef DEBUG_QUICHE
/* initialize debug log callback only once */
@@ -225,7 +226,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
quiche_config_log_keys(qs->cfg);
qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid,
- sizeof(qs->scid), qs->cfg);
+ sizeof(qs->scid), addr, addrlen, qs->cfg);
if(!qs->conn) {
failf(data, "can't create quiche connection");
return CURLE_OUT_OF_MEMORY;
@@ -257,7 +258,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- infof(data, "Connect socket %d over QUIC to %s:%ld\n",
+ infof(data, "Connect socket %d over QUIC to %s:%ld",
sockfd, ipbuf, port);
Curl_persistconninfo(data, conn, NULL, -1);
@@ -276,7 +277,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data,
offset += 1 + alpn_len;
}
- infof(data, "Sent QUIC client Initial, ALPN: %s\n",
+ infof(data, "Sent QUIC client Initial, ALPN: %s",
alpn_protocols + 1);
}
@@ -344,7 +345,7 @@ CURLcode Curl_quic_is_connected(struct Curl_easy *data,
if(quiche_conn_is_established(qs->conn)) {
*done = TRUE;
result = quiche_has_connected(conn, 0, sockindex);
- DEBUGF(infof(data, "quiche established connection!\n"));
+ DEBUGF(infof(data, "quiche established connection!"));
}
return result;
@@ -359,22 +360,34 @@ static CURLcode process_ingress(struct Curl_easy *data, int sockfd,
ssize_t recvd;
uint8_t *buf = (uint8_t *)data->state.buffer;
size_t bufsize = data->set.buffer_size;
+ struct sockaddr_storage from;
+ socklen_t from_len;
+ quiche_recv_info recv_info;
+
+ DEBUGASSERT(qs->conn);
/* in case the timeout expired */
quiche_conn_on_timeout(qs->conn);
do {
- recvd = recv(sockfd, buf, bufsize, 0);
+ from_len = sizeof(from);
+
+ recvd = recvfrom(sockfd, buf, bufsize, 0,
+ (struct sockaddr *)&from, &from_len);
+
if((recvd < 0) && ((SOCKERRNO == EAGAIN) || (SOCKERRNO == EWOULDBLOCK)))
break;
if(recvd < 0) {
- failf(data, "quiche: recv() unexpectedly returned %zd "
+ failf(data, "quiche: recvfrom() unexpectedly returned %zd "
"(errno: %d, socket %d)", recvd, SOCKERRNO, sockfd);
return CURLE_RECV_ERROR;
}
- recvd = quiche_conn_recv(qs->conn, buf, recvd);
+ recv_info.from = (struct sockaddr *) &from;
+ recv_info.from_len = from_len;
+
+ recvd = quiche_conn_recv(qs->conn, buf, recvd, &recv_info);
if(recvd == QUICHE_ERR_DONE)
break;
@@ -397,9 +410,10 @@ static CURLcode flush_egress(struct Curl_easy *data, int sockfd,
ssize_t sent;
uint8_t out[1200];
int64_t timeout_ns;
+ quiche_send_info send_info;
do {
- sent = quiche_conn_send(qs->conn, out, sizeof(out));
+ sent = quiche_conn_send(qs->conn, out, sizeof(out), &send_info);
if(sent == QUICHE_ERR_DONE)
break;
@@ -477,7 +491,7 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
headers.nlen = 0;
if(process_ingress(data, sockfd, qs)) {
- infof(data, "h3_stream_recv returns on ingress\n");
+ infof(data, "h3_stream_recv returns on ingress");
*curlcode = CURLE_RECV_ERROR;
return -1;
}
@@ -490,7 +504,7 @@ static ssize_t h3_stream_recv(struct Curl_easy *data,
if(s != stream->stream3_id) {
/* another transfer, ignore for now */
- infof(data, "Got h3 for stream %u, expects %u\n",
+ infof(data, "Got h3 for stream %u, expects %u",
s, stream->stream3_id);
continue;
}
@@ -571,7 +585,7 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
sent = len;
}
else {
- H3BUGF(infof(data, "Pass on %zd body bytes to quiche\n", len));
+ H3BUGF(infof(data, "Pass on %zd body bytes to quiche", len));
sent = quiche_h3_send_body(qs->h3c, qs->conn, stream->stream3_id,
(uint8_t *)mem, len, FALSE);
if(sent < 0) {
@@ -590,12 +604,11 @@ static ssize_t h3_stream_send(struct Curl_easy *data,
}
/*
- * Store quiche version info in this buffer, Prefix with a space. Return total
- * length written.
+ * Store quiche version info in this buffer.
*/
-int Curl_quic_ver(char *p, size_t len)
+void Curl_quic_ver(char *p, size_t len)
{
- return msnprintf(p, len, "quiche/%s", quiche_version());
+ (void)msnprintf(p, len, "quiche/%s", quiche_version());
}
/* Index where :authority header field will appear in request header
@@ -748,7 +761,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
}
/* :authority must come before non-pseudo header fields */
- if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
+ if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
quiche_h3_header authority = nva[authority_idx];
for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
nva[i] = nva[i - 1];
@@ -765,7 +778,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
for(i = 0; i < nheader; ++i) {
acc += nva[i].name_len + nva[i].value_len;
- H3BUGF(infof(data, "h3 [%.*s: %.*s]\n",
+ H3BUGF(infof(data, "h3 [%.*s: %.*s]",
nva[i].name_len, nva[i].name,
nva[i].value_len, nva[i].value));
}
@@ -773,7 +786,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
if(acc > MAX_ACC) {
infof(data, "http_request: Warning: The cumulative length of all "
"headers exceeds %d bytes and that could cause the "
- "stream to be rejected.\n", MAX_ACC);
+ "stream to be rejected.", MAX_ACC);
}
}
@@ -810,13 +823,13 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem,
Curl_safefree(nva);
if(stream3_id < 0) {
- H3BUGF(infof(data, "quiche_h3_send_request returned %d\n",
+ H3BUGF(infof(data, "quiche_h3_send_request returned %d",
stream3_id));
result = CURLE_SEND_ERROR;
goto fail;
}
- infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)\n",
+ infof(data, "Using HTTP/3 Stream ID: %x (easy handle %p)",
stream3_id, (void *)data);
stream->stream3_id = stream3_id;
diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c
index 08896ab..3e317e8 100644
--- a/Utilities/cmcurl/lib/vssh/libssh.c
+++ b/Utilities/cmcurl/lib/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 */
@@ -159,6 +158,7 @@ const struct Curl_handler Curl_handler_scp = {
scp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
CURLPROTO_SCP, /* family */
@@ -185,6 +185,7 @@ const struct Curl_handler Curl_handler_sftp = {
sftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
@@ -301,7 +302,7 @@ static void mystate(struct Curl_easy *data, sshstate nowstate
if(sshc->state != nowstate) {
- infof(data, "SSH %p state change from %s to %s (line %d)\n",
+ infof(data, "SSH %p state change from %s to %s (line %d)",
(void *) sshc, names[sshc->state], names[nowstate],
lineno);
}
@@ -366,7 +367,7 @@ static int myssh_is_known(struct Curl_easy *data)
for(i = 0; i < 16; i++)
msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
- infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
+ infof(data, "SSH MD5 fingerprint: %s", md5buffer);
if(!strcasecompare(md5buffer, pubkey_md5)) {
failf(data,
@@ -549,49 +550,48 @@ cleanup:
return rc;
}
-#define MOVE_TO_ERROR_STATE(_r) { \
- state(data, SSH_SESSION_DISCONNECT); \
- sshc->actualcode = _r; \
- rc = SSH_ERROR; \
- break; \
-}
+#define MOVE_TO_ERROR_STATE(_r) do { \
+ state(data, SSH_SESSION_DISCONNECT); \
+ sshc->actualcode = _r; \
+ rc = SSH_ERROR; \
+ } while(0)
-#define MOVE_TO_SFTP_CLOSE_STATE() { \
- state(data, SSH_SFTP_CLOSE); \
- sshc->actualcode = sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
- rc = SSH_ERROR; \
- break; \
-}
+#define MOVE_TO_SFTP_CLOSE_STATE() do { \
+ state(data, SSH_SFTP_CLOSE); \
+ sshc->actualcode = \
+ sftp_error_to_CURLE(sftp_get_error(sshc->sftp_session)); \
+ rc = SSH_ERROR; \
+ } while(0)
-#define MOVE_TO_LAST_AUTH \
- if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
- rc = SSH_OK; \
- state(data, SSH_AUTH_PASS_INIT); \
- break; \
- } \
- else { \
- MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
- }
+#define MOVE_TO_LAST_AUTH do { \
+ if(sshc->auth_methods & SSH_AUTH_METHOD_PASSWORD) { \
+ rc = SSH_OK; \
+ state(data, SSH_AUTH_PASS_INIT); \
+ } \
+ else { \
+ MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED); \
+ } \
+ } while(0)
-#define MOVE_TO_TERTIARY_AUTH \
- if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
- rc = SSH_OK; \
- state(data, SSH_AUTH_KEY_INIT); \
- break; \
- } \
- else { \
- MOVE_TO_LAST_AUTH; \
- }
+#define MOVE_TO_TERTIARY_AUTH do { \
+ if(sshc->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { \
+ rc = SSH_OK; \
+ state(data, SSH_AUTH_KEY_INIT); \
+ } \
+ else { \
+ MOVE_TO_LAST_AUTH; \
+ } \
+ } while(0)
-#define MOVE_TO_SECONDARY_AUTH \
- if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
- rc = SSH_OK; \
- state(data, SSH_AUTH_GSSAPI); \
- break; \
- } \
- else { \
- MOVE_TO_TERTIARY_AUTH; \
- }
+#define MOVE_TO_SECONDARY_AUTH do { \
+ if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) { \
+ rc = SSH_OK; \
+ state(data, SSH_AUTH_GSSAPI); \
+ } \
+ else { \
+ MOVE_TO_TERTIARY_AUTH; \
+ } \
+ } while(0)
static
int myssh_auth_interactive(struct connectdata *conn)
@@ -629,7 +629,7 @@ restart:
rc = SSH_OK;
else if(rc == SSH_AUTH_INFO) {
nprompts = ssh_userauth_kbdint_getnprompts(sshc->ssh_session);
- if(nprompts != 0)
+ if(nprompts)
return SSH_ERROR;
sshc->kbd_state = 2;
@@ -704,6 +704,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc != SSH_OK) {
failf(data, "Failure establishing ssh session");
MOVE_TO_ERROR_STATE(CURLE_FAILED_INIT);
+ break;
}
state(data, SSH_HOSTKEY);
@@ -714,6 +715,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
rc = myssh_is_known(data);
if(rc != SSH_OK) {
MOVE_TO_ERROR_STATE(CURLE_PEER_FAILED_VERIFICATION);
+ break;
}
state(data, SSH_AUTHLIST);
@@ -729,18 +731,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
- infof(data, "Authenticated with none\n");
+ infof(data, "Authenticated with none");
state(data, SSH_AUTH_DONE);
break;
}
else if(rc == SSH_AUTH_ERROR) {
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+ break;
}
sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) {
state(data, SSH_AUTH_PKEY_INIT);
- infof(data, "Authentication using SSH public key file\n");
+ infof(data, "Authentication using SSH public key file");
}
else if(sshc->auth_methods & SSH_AUTH_METHOD_GSSAPI_MIC) {
state(data, SSH_AUTH_GSSAPI);
@@ -753,6 +756,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
else { /* unsupported authentication method */
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+ break;
}
break;
@@ -760,6 +764,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_AUTH_PKEY_INIT:
if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY)) {
MOVE_TO_SECONDARY_AUTH;
+ break;
}
/* Two choices, (1) private key was given on CMD,
@@ -775,6 +780,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc != SSH_OK) {
MOVE_TO_SECONDARY_AUTH;
+ break;
}
}
@@ -803,7 +809,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
rc = SSH_OK;
sshc->authed = TRUE;
- infof(data, "Completed public key authentication\n");
+ infof(data, "Completed public key authentication");
state(data, SSH_AUTH_DONE);
break;
}
@@ -820,12 +826,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
- infof(data, "Completed public key authentication\n");
+ infof(data, "Completed public key authentication");
state(data, SSH_AUTH_DONE);
break;
}
else {
- infof(data, "Failed public key authentication (rc: %d)\n", rc);
+ infof(data, "Failed public key authentication (rc: %d)", rc);
MOVE_TO_SECONDARY_AUTH;
}
break;
@@ -833,6 +839,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_AUTH_GSSAPI:
if(!(data->set.ssh_auth_types & CURLSSH_AUTH_GSSAPI)) {
MOVE_TO_TERTIARY_AUTH;
+ break;
}
rc = ssh_userauth_gssapi(sshc->ssh_session);
@@ -844,7 +851,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
rc = SSH_OK;
sshc->authed = TRUE;
- infof(data, "Completed gssapi authentication\n");
+ infof(data, "Completed gssapi authentication");
state(data, SSH_AUTH_DONE);
break;
}
@@ -870,7 +877,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(rc == SSH_OK) {
sshc->authed = TRUE;
- infof(data, "completed keyboard interactive authentication\n");
+ infof(data, "completed keyboard interactive authentication");
}
state(data, SSH_AUTH_DONE);
break;
@@ -879,6 +886,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(!(data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD)) {
/* Host key authentication is intentionally not implemented */
MOVE_TO_ERROR_STATE(CURLE_LOGIN_DENIED);
+ break;
}
state(data, SSH_AUTH_PASS);
/* FALLTHROUGH */
@@ -892,7 +900,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == SSH_AUTH_SUCCESS) {
sshc->authed = TRUE;
- infof(data, "Completed password authentication\n");
+ infof(data, "Completed password authentication");
state(data, SSH_AUTH_DONE);
}
else {
@@ -910,7 +918,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/*
* At this point we have an authenticated ssh session.
*/
- infof(data, "Authentication complete\n");
+ infof(data, "Authentication complete");
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
@@ -921,7 +929,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_SFTP_INIT);
break;
}
- infof(data, "SSH CONNECT phase done\n");
+ infof(data, "SSH CONNECT phase done");
state(data, SSH_STOP);
break;
@@ -951,8 +959,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
* Get the "home" directory
*/
sshc->homedir = sftp_canonicalize_path(sshc->sftp_session, ".");
- if(sshc->homedir == NULL) {
+ if(!sshc->homedir) {
MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
+ break;
}
data->state.most_recent_ftp_entrypath = sshc->homedir;
@@ -960,7 +969,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
we get the homedir here, we get the "workingpath" in the DO action
since the homedir will remain the same between request but the
working path will not. */
- DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+ DEBUGF(infof(data, "SSH CONNECT phase done"));
state(data, SSH_STOP);
break;
@@ -973,7 +982,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(data->set.quote) {
- infof(data, "Sending quote commands\n");
+ infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
state(data, SSH_SFTP_QUOTE);
}
@@ -984,7 +993,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_POSTQUOTE_INIT:
if(data->set.postquote) {
- infof(data, "Sending quote commands\n");
+ infof(data, "Sending quote commands");
sshc->quote_item = data->set.postquote;
state(data, SSH_SFTP_QUOTE);
}
@@ -1025,7 +1034,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_SETSTAT:
rc = sftp_setstat(sshc->sftp_session, sshc->quote_path2,
sshc->quote_attrs);
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to set SFTP stats failed: %s",
@@ -1044,7 +1053,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_SYMLINK:
rc = sftp_symlink(sshc->sftp_session, sshc->quote_path2,
sshc->quote_path1);
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "symlink command failed: %s",
@@ -1060,7 +1069,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_MKDIR:
rc = sftp_mkdir(sshc->sftp_session, sshc->quote_path1,
(mode_t)data->set.new_directory_perms);
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
failf(data, "mkdir command failed: %s",
ssh_get_error(sshc->ssh_session));
@@ -1075,7 +1084,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_RENAME:
rc = sftp_rename(sshc->sftp_session, sshc->quote_path1,
sshc->quote_path2);
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "rename command failed: %s",
@@ -1090,7 +1099,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_RMDIR:
rc = sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
failf(data, "rmdir command failed: %s",
ssh_get_error(sshc->ssh_session));
@@ -1104,7 +1113,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_UNLINK:
rc = sftp_unlink(sshc->sftp_session, sshc->quote_path1);
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1);
failf(data, "rm command failed: %s",
ssh_get_error(sshc->ssh_session));
@@ -1179,7 +1188,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sftp_attributes attrs;
attrs = sftp_stat(sshc->sftp_session, protop->path);
- if(attrs != 0) {
+ if(attrs) {
data->info.filetime = attrs->mtime;
sftp_attributes_free(attrs);
}
@@ -1203,16 +1212,17 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
{
int flags;
- if(data->state.resume_from != 0) {
+ if(data->state.resume_from) {
sftp_attributes attrs;
if(data->state.resume_from < 0) {
attrs = sftp_stat(sshc->sftp_session, protop->path);
- if(attrs != 0) {
+ if(attrs) {
curl_off_t size = attrs->size;
if(size < 0) {
failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
+ break;
}
data->state.resume_from = attrs->size;
@@ -1224,7 +1234,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
}
- if(data->set.ftp_append)
+ if(data->set.remote_append)
/* Try to open for append, but create if nonexisting */
flags = O_WRONLY|O_CREAT|O_APPEND;
else if(data->state.resume_from > 0)
@@ -1254,6 +1264,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
else {
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
}
@@ -1292,8 +1303,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
CURL_READFUNC_ABORT return code still aborts */
failf(data, "Failed to read data");
MOVE_TO_ERROR_STATE(CURLE_FTP_COULDNT_USE_REST);
+ break;
}
} while(passed < data->state.resume_from);
+ if(rc)
+ break;
}
/* now, decrease the size of the read */
@@ -1304,8 +1318,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
- if(rc != 0) {
+ if(rc) {
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
}
if(data->state.infilesize > 0) {
@@ -1351,7 +1366,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(sshc->slash_pos) {
*sshc->slash_pos = 0;
- infof(data, "Creating directory '%s'\n", protop->path);
+ infof(data, "Creating directory '%s'", protop->path);
state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
break;
}
@@ -1375,6 +1390,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
(err != SSH_FX_FAILURE) &&
(err != SSH_FX_PERMISSION_DENIED)) {
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
rc = 0; /* clear rc and continue */
}
@@ -1398,6 +1414,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "Could not open directory for reading: %s",
ssh_get_error(sshc->ssh_session));
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
state(data, SSH_SFTP_READDIR);
break;
@@ -1413,11 +1430,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->readdir_longentry = sshc->readdir_attrs->longname;
sshc->readdir_len = strlen(sshc->readdir_filename);
- if(data->set.ftp_list_only) {
+ if(data->set.list_only) {
char *tmpLine;
tmpLine = aprintf("%s\n", sshc->readdir_filename);
- if(tmpLine == NULL) {
+ if(!tmpLine) {
state(data, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
@@ -1453,16 +1470,15 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
((sshc->readdir_attrs->permissions & S_IFMT) ==
S_IFLNK)) {
- sshc->readdir_linkPath = malloc(PATH_MAX + 1);
- if(sshc->readdir_linkPath == NULL) {
+ sshc->readdir_linkPath = aprintf("%s%s", protop->path,
+ sshc->readdir_filename);
+
+ if(!sshc->readdir_linkPath) {
state(data, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
- msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", protop->path,
- sshc->readdir_filename);
-
state(data, SSH_SFTP_READDIR_LINK);
break;
}
@@ -1492,12 +1508,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "Could not read symlink for reading: %s",
ssh_get_error(sshc->ssh_session));
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
- if(sshc->readdir_link_attrs->name == NULL) {
+ if(!sshc->readdir_link_attrs->name) {
sshc->readdir_tmp = sftp_readlink(sshc->sftp_session,
sshc->readdir_linkPath);
- if(sshc->readdir_filename == NULL)
+ if(!sshc->readdir_filename)
sshc->readdir_len = 0;
else
sshc->readdir_len = strlen(sshc->readdir_tmp);
@@ -1587,6 +1604,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
ssh_get_error(sshc->ssh_session));
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
state(data, SSH_SFTP_DOWNLOAD_STAT);
@@ -1662,8 +1680,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
rc = sftp_seek64(sshc->sftp_file, from);
- if(rc != 0) {
+ if(rc) {
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
}
data->req.size = size;
@@ -1700,8 +1719,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
size - data->state.resume_from);
rc = sftp_seek64(sshc->sftp_file, data->state.resume_from);
- if(rc != 0) {
+ if(rc) {
MOVE_TO_SFTP_CLOSE_STATE();
+ break;
}
}
}
@@ -1710,7 +1730,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->req.size == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
- infof(data, "File already completely downloaded\n");
+ infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
@@ -1743,7 +1763,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
Curl_safefree(protop->path);
- DEBUGF(infof(data, "SFTP DONE done\n"));
+ DEBUGF(infof(data, "SFTP DONE done"));
/* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
After nextstate is executed, the control should come back to
@@ -1796,6 +1816,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "SCP requires a known file size for upload");
sshc->actualcode = CURLE_UPLOAD_FAILED;
MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+ break;
}
sshc->scp_session =
@@ -1823,6 +1844,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+ break;
}
rc = ssh_scp_push_file(sshc->scp_session, protop->path,
@@ -1832,6 +1854,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
MOVE_TO_ERROR_STATE(CURLE_UPLOAD_FAILED);
+ break;
}
/* upload data */
@@ -1860,6 +1883,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
err_msg = ssh_get_error(sshc->ssh_session);
failf(data, "%s", err_msg);
MOVE_TO_ERROR_STATE(CURLE_COULDNT_CONNECT);
+ break;
}
state(data, SSH_SCP_DOWNLOAD);
/* FALLTHROUGH */
@@ -1908,7 +1932,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
if(rc != SSH_OK) {
- infof(data, "Failed to close libssh scp channel: %s\n",
+ infof(data, "Failed to close libssh scp channel: %s",
ssh_get_error(sshc->ssh_session));
}
}
@@ -1921,7 +1945,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
ssh_scp_free(sshc->scp_session);
sshc->scp_session = NULL;
}
- DEBUGF(infof(data, "SCP DONE phase complete\n"));
+ DEBUGF(infof(data, "SCP DONE phase complete"));
ssh_set_blocking(sshc->ssh_session, 0);
@@ -2164,7 +2188,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
ssh = &conn->proto.sshc;
ssh->ssh_session = ssh_new();
- if(ssh->ssh_session == NULL) {
+ if(!ssh->ssh_session) {
failf(data, "Failure initialising ssh session");
return CURLE_FAILED_INIT;
}
@@ -2188,7 +2212,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
}
if(conn->user && conn->user[0] != '\0') {
- infof(data, "User: %s\n", conn->user);
+ infof(data, "User: %s", conn->user);
rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
if(rc != SSH_OK) {
failf(data, "Could not set user");
@@ -2197,7 +2221,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
}
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
- infof(data, "Known hosts: %s\n", data->set.str[STRING_SSH_KNOWNHOSTS]);
+ infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]);
rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS,
data->set.str[STRING_SSH_KNOWNHOSTS]);
if(rc != SSH_OK) {
@@ -2254,7 +2278,7 @@ static CURLcode scp_doing(struct Curl_easy *data, bool *dophase_done)
result = myssh_multi_statemach(data, dophase_done);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
}
@@ -2275,7 +2299,7 @@ CURLcode scp_perform(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
@@ -2287,7 +2311,7 @@ CURLcode scp_perform(struct Curl_easy *data,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -2456,7 +2480,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
@@ -2469,7 +2493,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -2481,7 +2505,7 @@ static CURLcode sftp_doing(struct Curl_easy *data,
{
CURLcode result = myssh_multi_statemach(data, dophase_done);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
}
@@ -2496,7 +2520,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
CURLcode result = CURLE_OK;
(void) dead_connection;
- DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
+ DEBUGF(infof(data, "SSH DISCONNECT starts now"));
if(conn->proto.sshc.ssh_session) {
/* only if there's a session still around to use! */
@@ -2504,7 +2528,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
result = myssh_block_statemach(data, TRUE);
}
- DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
+ DEBUGF(infof(data, "SSH DISCONNECT is done"));
return result;
@@ -2662,7 +2686,7 @@ static void sftp_quote(struct Curl_easy *data)
* command with a space so we can check for it unconditionally
*/
cp = strchr(cmd, ' ');
- if(cp == NULL) {
+ if(!cp) {
failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
state(data, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
@@ -2811,7 +2835,7 @@ static void sftp_quote_stat(struct Curl_easy *data)
if(sshc->quote_attrs)
sftp_attributes_free(sshc->quote_attrs);
sshc->quote_attrs = sftp_stat(sshc->sftp_session, sshc->quote_path2);
- if(sshc->quote_attrs == NULL) {
+ if(!sshc->quote_attrs) {
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to get SFTP stats failed: %d",
@@ -2915,9 +2939,9 @@ void Curl_ssh_cleanup(void)
(void)ssh_finalize();
}
-size_t Curl_ssh_version(char *buffer, size_t buflen)
+void Curl_ssh_version(char *buffer, size_t buflen)
{
- return msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
+ (void)msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION);
}
#endif /* USE_LIBSSH */
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index 3130dcc..a772f1f 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/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 */
@@ -121,6 +120,7 @@ static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *sock);
static CURLcode ssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
+static void ssh_attach(struct Curl_easy *data, struct connectdata *conn);
/*
* SCP protocol handler.
@@ -142,6 +142,7 @@ const struct Curl_handler Curl_handler_scp = {
scp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ssh_attach,
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
CURLPROTO_SCP, /* family */
@@ -170,6 +171,7 @@ const struct Curl_handler Curl_handler_sftp = {
sftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ssh_attach,
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
@@ -184,7 +186,7 @@ kbd_callback(const char *name, int name_len, const char *instruction,
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
void **abstract)
{
- struct connectdata *conn = (struct connectdata *)*abstract;
+ struct Curl_easy *data = (struct Curl_easy *)*abstract;
#ifdef CURL_LIBSSH2_DEBUG
fprintf(stderr, "name=%s\n", name);
@@ -199,11 +201,11 @@ kbd_callback(const char *name, int name_len, const char *instruction,
(void)instruction_len;
#endif /* CURL_LIBSSH2_DEBUG */
if(num_prompts == 1) {
+ struct connectdata *conn = data->conn;
responses[0].text = strdup(conn->passwd);
responses[0].length = curlx_uztoui(strlen(conn->passwd));
}
(void)prompts;
- (void)abstract;
} /* kbd_callback */
static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err)
@@ -375,7 +377,7 @@ static void state(struct Curl_easy *data, sshstate nowstate)
DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
if(sshc->state != nowstate) {
- infof(data, "SFTP %p state change from %s to %s\n",
+ infof(data, "SFTP %p state change from %s to %s",
(void *)sshc, names[sshc->state], names[nowstate]);
}
#endif
@@ -488,7 +490,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
break;
#endif
default:
- infof(data, "unsupported key type, can't check knownhosts!\n");
+ infof(data, "unsupported key type, can't check knownhosts!");
keybit = 0;
break;
}
@@ -516,7 +518,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
&host);
#endif
- infof(data, "SSH host check: %d, key: %s\n", keycheck,
+ infof(data, "SSH host check: %d, key: %s", keycheck,
(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
host->key:"<none>");
@@ -583,7 +585,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
LIBSSH2_KNOWNHOST_KEYENC_RAW|
keybit, NULL);
if(addrc)
- infof(data, "Warning adding the known host %s failed!\n",
+ infof(data, "Warning adding the known host %s failed!",
conn->host.name);
else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
rc == CURLKHSTAT_FINE_REPLACE) {
@@ -594,7 +596,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
data->set.str[STRING_SSH_KNOWNHOSTS],
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if(wrc) {
- infof(data, "Warning, writing %s failed!\n",
+ infof(data, "Warning, writing %s failed!",
data->set.str[STRING_SSH_KNOWNHOSTS]);
}
}
@@ -623,7 +625,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
int i;
for(i = 0; i < 16; i++)
msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
- infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
+ infof(data, "SSH MD5 fingerprint: %s", md5buffer);
}
/* Before we authenticate we check the hostkey's MD5 fingerprint
@@ -642,7 +644,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
- infof(data, "MD5 checksum match!\n");
+ infof(data, "MD5 checksum match!");
/* as we already matched, we skip the check for known hosts */
return CURLE_OK;
}
@@ -699,7 +701,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
if(store->name[0] == '[') {
kh_name_end = strstr(store->name, "]:");
if(!kh_name_end) {
- infof(data, "Invalid host pattern %s in %s\n",
+ infof(data, "Invalid host pattern %s in %s",
store->name, data->set.str[STRING_SSH_KNOWNHOSTS]);
continue;
}
@@ -726,7 +728,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
}
if(found) {
- infof(data, "Found host %s in %s\n",
+ infof(data, "Found host %s in %s",
conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
@@ -765,13 +767,13 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
return CURLE_SSH;
}
- infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method);
+ infof(data, "Set \"%s\" as SSH hostkey type", hostkey_method);
result = libssh2_session_error_to_CURLE(
libssh2_session_method_pref(
sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
}
else {
- infof(data, "Did not find host %s in %s\n",
+ infof(data, "Did not find host %s in %s",
conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
}
}
@@ -871,7 +873,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(!sshc->authlist) {
if(libssh2_userauth_authenticated(sshc->ssh_session)) {
sshc->authed = TRUE;
- infof(data, "SSH user accepted with no authentication\n");
+ infof(data, "SSH user accepted with no authentication");
state(data, SSH_AUTH_DONE);
break;
}
@@ -884,7 +886,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
break;
}
- infof(data, "SSH authentication methods available: %s\n",
+ infof(data, "SSH authentication methods available: %s",
sshc->authlist);
state(data, SSH_AUTH_PKEY_INIT);
@@ -956,7 +958,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
out_of_memory = TRUE;
}
- if(out_of_memory || sshc->rsa == NULL) {
+ if(out_of_memory || !sshc->rsa) {
Curl_safefree(sshc->rsa);
Curl_safefree(sshc->rsa_pub);
state(data, SSH_SESSION_FREE);
@@ -969,8 +971,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->passphrase = "";
if(sshc->rsa_pub)
- infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
- infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
+ infof(data, "Using SSH public key file '%s'", sshc->rsa_pub);
+ infof(data, "Using SSH private key file '%s'", sshc->rsa);
state(data, SSH_AUTH_PKEY);
}
@@ -997,14 +999,14 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == 0) {
sshc->authed = TRUE;
- infof(data, "Initialized SSH public key authentication\n");
+ infof(data, "Initialized SSH public key authentication");
state(data, SSH_AUTH_DONE);
}
else {
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "SSH public key authentication failed: %s\n", err_msg);
+ infof(data, "SSH public key authentication failed: %s", err_msg);
state(data, SSH_AUTH_PASS_INIT);
rc = 0; /* clear rc and continue */
}
@@ -1032,7 +1034,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(rc == 0) {
sshc->authed = TRUE;
- infof(data, "Initialized password authentication\n");
+ infof(data, "Initialized password authentication");
state(data, SSH_AUTH_DONE);
}
else {
@@ -1066,7 +1068,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(!sshc->ssh_agent) {
sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
if(!sshc->ssh_agent) {
- infof(data, "Could not create agent object\n");
+ infof(data, "Could not create agent object");
state(data, SSH_AUTH_KEY_INIT);
break;
@@ -1077,7 +1079,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN)
break;
if(rc < 0) {
- infof(data, "Failure connecting to agent\n");
+ infof(data, "Failure connecting to agent");
state(data, SSH_AUTH_KEY_INIT);
rc = 0; /* clear rc and continue */
}
@@ -1097,7 +1099,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN)
break;
if(rc < 0) {
- infof(data, "Failure requesting identities to agent\n");
+ infof(data, "Failure requesting identities to agent");
state(data, SSH_AUTH_KEY_INIT);
rc = 0; /* clear rc and continue */
}
@@ -1133,13 +1135,13 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(rc < 0)
- infof(data, "Failure requesting identities to agent\n");
+ infof(data, "Failure requesting identities to agent");
else if(rc == 1)
- infof(data, "No identity would match\n");
+ infof(data, "No identity would match");
if(rc == LIBSSH2_ERROR_NONE) {
sshc->authed = TRUE;
- infof(data, "Agent based authentication successful\n");
+ infof(data, "Agent based authentication successful");
state(data, SSH_AUTH_DONE);
}
else {
@@ -1171,7 +1173,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(rc == 0) {
sshc->authed = TRUE;
- infof(data, "Initialized keyboard interactive authentication\n");
+ infof(data, "Initialized keyboard interactive authentication");
}
state(data, SSH_AUTH_DONE);
break;
@@ -1187,7 +1189,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/*
* At this point we have an authenticated ssh session.
*/
- infof(data, "Authentication complete\n");
+ infof(data, "Authentication complete");
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */
@@ -1198,7 +1200,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_SFTP_INIT);
break;
}
- infof(data, "SSH CONNECT phase done\n");
+ infof(data, "SSH CONNECT phase done");
state(data, SSH_STOP);
break;
@@ -1258,7 +1260,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
a time-out or similar */
result = CURLE_SSH;
sshc->actualcode = result;
- DEBUGF(infof(data, "error = %lu makes libcurl = %d\n",
+ DEBUGF(infof(data, "error = %lu makes libcurl = %d",
sftperr, (int)result));
state(data, SSH_STOP);
break;
@@ -1268,7 +1270,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
we get the homedir here, we get the "workingpath" in the DO action
since the homedir will remain the same between request but the
working path will not. */
- DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+ DEBUGF(infof(data, "SSH CONNECT phase done"));
state(data, SSH_STOP);
break;
@@ -1282,7 +1284,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(data->set.quote) {
- infof(data, "Sending quote commands\n");
+ infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
state(data, SSH_SFTP_QUOTE);
}
@@ -1293,7 +1295,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_POSTQUOTE_INIT:
if(data->set.postquote) {
- infof(data, "Sending quote commands\n");
+ infof(data, "Sending quote commands");
sshc->quote_item = data->set.postquote;
state(data, SSH_SFTP_QUOTE);
}
@@ -1359,7 +1361,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
* command with a space so we can check for it unconditionally
*/
cp = strchr(cmd, ' ');
- if(cp == NULL) {
+ if(!cp) {
failf(data, "Syntax error command '%s'. Missing parameter!",
cmd);
state(data, SSH_SFTP_CLOSE);
@@ -1534,7 +1536,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) { /* get those attributes */
+ if(rc && !sshc->acceptfail) { /* get those attributes */
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
@@ -1633,7 +1635,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
@@ -1656,7 +1658,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
@@ -1677,7 +1679,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
failf(data, "mkdir command failed: %s",
@@ -1702,7 +1704,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
@@ -1722,7 +1724,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
failf(data, "rmdir command failed: %s",
@@ -1741,7 +1743,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
@@ -1764,7 +1766,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- if(rc != 0 && !sshc->acceptfail) {
+ if(rc && !sshc->acceptfail) {
sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
failf(data, "statvfs command failed: %s",
@@ -1857,7 +1859,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
* same name as the last directory in the path.
*/
- if(data->state.resume_from != 0) {
+ if(data->state.resume_from) {
LIBSSH2_SFTP_ATTRIBUTES attrs;
if(data->state.resume_from < 0) {
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
@@ -1880,7 +1882,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
}
- if(data->set.ftp_append)
+ if(data->set.remote_append)
/* Try to open for append, but create if nonexisting */
flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
else if(data->state.resume_from > 0)
@@ -2045,7 +2047,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(sshc->slash_pos) {
*sshc->slash_pos = 0;
- infof(data, "Creating directory '%s'\n", sshp->path);
+ infof(data, "Creating directory '%s'", sshp->path);
state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
break;
}
@@ -2143,7 +2145,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
readdir_len = (size_t) rc;
sshp->readdir_filename[readdir_len] = '\0';
- if(data->set.ftp_list_only) {
+ if(data->set.list_only) {
result = Curl_client_write(data, CLIENTWRITE_BODY,
sshp->readdir_filename,
readdir_len);
@@ -2408,7 +2410,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->req.size == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
- infof(data, "File already completely downloaded\n");
+ infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
@@ -2443,14 +2445,14 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
+ infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
}
sshc->sftp_handle = NULL;
}
Curl_safefree(sshp->path);
- DEBUGF(infof(data, "SFTP DONE done\n"));
+ DEBUGF(infof(data, "SFTP DONE done"));
/* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
After nextstate is executed, the control should come back to
@@ -2480,7 +2482,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session, &err_msg,
NULL, 0);
- infof(data, "Failed to close libssh2 file: %d %s\n", rc, err_msg);
+ infof(data, "Failed to close libssh2 file: %d %s", rc, err_msg);
}
sshc->sftp_handle = NULL;
}
@@ -2490,7 +2492,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
if(rc < 0) {
- infof(data, "Failed to stop libssh2 sftp subsystem\n");
+ infof(data, "Failed to stop libssh2 sftp subsystem");
}
sshc->sftp_session = NULL;
}
@@ -2665,7 +2667,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to send libssh2 channel EOF: %d %s\n",
+ infof(data, "Failed to send libssh2 channel EOF: %d %s",
rc, err_msg);
}
}
@@ -2682,7 +2684,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to get channel EOF: %d %s\n", rc, err_msg);
+ infof(data, "Failed to get channel EOF: %d %s", rc, err_msg);
}
}
state(data, SSH_SCP_WAIT_CLOSE);
@@ -2698,7 +2700,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Channel failed to close: %d %s\n", rc, err_msg);
+ infof(data, "Channel failed to close: %d %s", rc, err_msg);
}
}
state(data, SSH_SCP_CHANNEL_FREE);
@@ -2714,12 +2716,12 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
+ infof(data, "Failed to free libssh2 scp subsystem: %d %s",
rc, err_msg);
}
sshc->ssh_channel = NULL;
}
- DEBUGF(infof(data, "SCP DONE phase complete\n"));
+ DEBUGF(infof(data, "SCP DONE phase complete"));
#if 0 /* PREV */
state(data, SSH_SESSION_DISCONNECT);
#endif
@@ -2740,7 +2742,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to free libssh2 scp subsystem: %d %s\n",
+ infof(data, "Failed to free libssh2 scp subsystem: %d %s",
rc, err_msg);
}
sshc->ssh_channel = NULL;
@@ -2755,7 +2757,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to disconnect libssh2 session: %d %s\n",
+ infof(data, "Failed to disconnect libssh2 session: %d %s",
rc, err_msg);
}
}
@@ -2784,7 +2786,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to disconnect from libssh2 agent: %d %s\n",
+ infof(data, "Failed to disconnect from libssh2 agent: %d %s",
rc, err_msg);
}
libssh2_agent_free(sshc->ssh_agent);
@@ -2806,7 +2808,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
char *err_msg = NULL;
(void)libssh2_session_last_error(sshc->ssh_session,
&err_msg, NULL, 0);
- infof(data, "Failed to free libssh2 session: %d %s\n", rc, err_msg);
+ infof(data, "Failed to free libssh2 session: %d %s", rc, err_msg);
}
sshc->ssh_session = NULL;
}
@@ -2931,10 +2933,11 @@ static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
static CURLcode ssh_block_statemach(struct Curl_easy *data,
struct connectdata *conn,
- bool duringconnect)
+ bool disconnect)
{
struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
+ struct curltime dis = Curl_now();
while((sshc->state != SSH_STOP) && !result) {
bool block;
@@ -2945,17 +2948,25 @@ static CURLcode ssh_block_statemach(struct Curl_easy *data,
if(result)
break;
- if(Curl_pgrsUpdate(data))
- return CURLE_ABORTED_BY_CALLBACK;
+ if(!disconnect) {
+ if(Curl_pgrsUpdate(data))
+ return CURLE_ABORTED_BY_CALLBACK;
- result = Curl_speedcheck(data, now);
- if(result)
- break;
+ result = Curl_speedcheck(data, now);
+ if(result)
+ break;
- left = Curl_timeleft(data, NULL, duringconnect);
- if(left < 0) {
- failf(data, "Operation timed out");
- return CURLE_OPERATION_TIMEDOUT;
+ left = Curl_timeleft(data, NULL, FALSE);
+ if(left < 0) {
+ failf(data, "Operation timed out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ else if(Curl_timediff(now, dis) > 1000) {
+ /* disconnect timeout */
+ failf(data, "Disconnect timed out");
+ result = CURLE_OK;
+ break;
}
if(block) {
@@ -3054,17 +3065,15 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
#ifdef CURL_LIBSSH2_DEBUG
curl_socket_t sock;
#endif
- struct SSHPROTO *sshp = data->req.p.ssh;
struct ssh_conn *sshc;
CURLcode result;
struct connectdata *conn = data->conn;
/* initialize per-handle data if not already */
- if(!sshp) {
+ if(!data->req.p.ssh) {
result = ssh_setup_connection(data, conn);
if(result)
return result;
- sshp = data->req.p.ssh;
}
/* We default to persistent connections. We set this already in this connect
@@ -3075,10 +3084,10 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
#ifdef CURL_LIBSSH2_DEBUG
if(conn->user) {
- infof(data, "User: %s\n", conn->user);
+ infof(data, "User: %s", conn->user);
}
if(conn->passwd) {
- infof(data, "Password: %s\n", conn->passwd);
+ infof(data, "Password: %s", conn->passwd);
}
sock = conn->sock[FIRSTSOCKET];
#endif /* CURL_LIBSSH2_DEBUG */
@@ -3086,7 +3095,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
my_libssh2_free,
my_libssh2_realloc, data);
- if(sshc->ssh_session == NULL) {
+ if(!sshc->ssh_session) {
failf(data, "Failure initialising ssh session");
return CURLE_FAILED_INIT;
}
@@ -3112,7 +3121,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sshrecv.recvptr = ssh_tls_recv;
sshsend.sendptr = ssh_tls_send;
- infof(data, "Uses HTTPS proxy!\n");
+ infof(data, "Uses HTTPS proxy!");
/*
Setup libssh2 callbacks to make it read/write TLS from the socket.
@@ -3150,7 +3159,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
#if LIBSSH2_VERSION_NUM >= 0x010208
if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
#endif
- infof(data, "Failed to enable compression for ssh session\n");
+ infof(data, "Failed to enable compression for ssh session");
}
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
@@ -3159,6 +3168,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sshc->kh = libssh2_knownhost_init(sshc->ssh_session);
if(!sshc->kh) {
libssh2_session_free(sshc->ssh_session);
+ sshc->ssh_session = NULL;
return CURLE_FAILED_INIT;
}
@@ -3167,14 +3177,14 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
data->set.str[STRING_SSH_KNOWNHOSTS],
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if(rc < 0)
- infof(data, "Failed to read known hosts from %s\n",
+ infof(data, "Failed to read known hosts from %s",
data->set.str[STRING_SSH_KNOWNHOSTS]);
}
#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
#ifdef CURL_LIBSSH2_DEBUG
libssh2_trace(sshc->ssh_session, ~0);
- infof(data, "SSH socket: %d\n", (int)sock);
+ infof(data, "SSH socket: %d", (int)sock);
#endif /* CURL_LIBSSH2_DEBUG */
state(data, SSH_INIT);
@@ -3201,7 +3211,7 @@ CURLcode scp_perform(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
@@ -3214,7 +3224,7 @@ CURLcode scp_perform(struct Curl_easy *data,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -3228,7 +3238,7 @@ static CURLcode scp_doing(struct Curl_easy *data,
result = ssh_multi_statemach(data, dophase_done);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
}
@@ -3279,10 +3289,8 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
if(sshc->ssh_session) {
/* only if there's a session still around to use! */
-
state(data, SSH_SESSION_DISCONNECT);
-
- result = ssh_block_statemach(data, conn, FALSE);
+ result = ssh_block_statemach(data, conn, TRUE);
}
return result;
@@ -3296,10 +3304,9 @@ static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
struct SSHPROTO *sshp = data->req.p.ssh;
struct connectdata *conn = data->conn;
- if(!status) {
+ if(!status)
/* run the state-machine */
result = ssh_block_statemach(data, conn, FALSE);
- }
else
result = status;
@@ -3393,7 +3400,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
@@ -3406,7 +3413,7 @@ CURLcode sftp_perform(struct Curl_easy *data,
*connected = data->conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -3419,7 +3426,7 @@ static CURLcode sftp_doing(struct Curl_easy *data,
CURLcode result = ssh_multi_statemach(data, dophase_done);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
}
@@ -3434,15 +3441,15 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
struct ssh_conn *sshc = &conn->proto.sshc;
(void) dead_connection;
- DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
+ DEBUGF(infof(data, "SSH DISCONNECT starts now"));
if(sshc->ssh_session) {
/* only if there's a session still around to use! */
state(data, SSH_SFTP_SHUTDOWN);
- result = ssh_block_statemach(data, conn, FALSE);
+ result = ssh_block_statemach(data, conn, TRUE);
}
- DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
+ DEBUGF(infof(data, "SSH DISCONNECT is done"));
return result;
@@ -3601,9 +3608,26 @@ void Curl_ssh_cleanup(void)
#endif
}
-size_t Curl_ssh_version(char *buffer, size_t buflen)
+void Curl_ssh_version(char *buffer, size_t buflen)
{
- return msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
+ (void)msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
}
+/* The SSH session is associated with the *CONNECTION* but the callback user
+ * pointer is an easy handle pointer. This function allows us to reassign the
+ * user pointer to the *CURRENT* (new) easy handle.
+ */
+static void ssh_attach(struct Curl_easy *data, struct connectdata *conn)
+{
+ DEBUGASSERT(data);
+ DEBUGASSERT(conn);
+ if(conn->handler->protocol & PROTO_FAMILY_SSH) {
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ if(sshc->ssh_session) {
+ /* only re-attach if the session already exists */
+ void **abstract = libssh2_session_abstract(sshc->ssh_session);
+ *abstract = data;
+ }
+ }
+}
#endif /* USE_LIBSSH2 */
diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h
index 52e1ee6..7972081 100644
--- a/Utilities/cmcurl/lib/vssh/ssh.h
+++ b/Utilities/cmcurl/lib/vssh/ssh.h
@@ -262,10 +262,13 @@ extern const struct Curl_handler Curl_handler_sftp;
/* generic SSH backend functions */
CURLcode Curl_ssh_init(void);
void Curl_ssh_cleanup(void);
-size_t Curl_ssh_version(char *buffer, size_t buflen);
+void Curl_ssh_version(char *buffer, size_t buflen);
+void Curl_ssh_attach(struct Curl_easy *data,
+ struct connectdata *conn);
#else
/* for non-SSH builds */
#define Curl_ssh_cleanup()
+#define Curl_ssh_attach(x,y)
#endif
#endif /* HEADER_CURL_SSH_H */
diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c
index 6020180..4b1e2ec 100644
--- a/Utilities/cmcurl/lib/vssh/wolfssh.c
+++ b/Utilities/cmcurl/lib/vssh/wolfssh.c
@@ -91,6 +91,7 @@ const struct Curl_handler Curl_handler_scp = {
wscp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
CURLPROTO_SCP, /* protocol */
PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
@@ -119,6 +120,7 @@ const struct Curl_handler Curl_handler_sftp = {
wsftp_disconnect, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
CURLPROTO_SFTP, /* protocol */
CURLPROTO_SFTP, /* family */
@@ -203,7 +205,7 @@ static void state(struct Curl_easy *data, sshstate nowstate)
DEBUGASSERT(sizeof(names)/sizeof(names[0]) == SSH_LAST);
if(sshc->state != nowstate) {
- infof(data, "wolfssh %p state change from %s to %s\n",
+ infof(data, "wolfssh %p state change from %s to %s",
(void *)sshc, names[sshc->state], names[nowstate]);
}
#endif
@@ -272,7 +274,7 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
return -1;
}
DEBUGASSERT(rc == (int)len);
- infof(data, "sent %zd bytes SFTP from offset %zd\n",
+ infof(data, "sent %zd bytes SFTP from offset %zd",
len, sshc->offset);
sshc->offset += len;
return (ssize_t)rc;
@@ -346,7 +348,7 @@ static int userauth(byte authtype,
void *ctx)
{
struct Curl_easy *data = ctx;
- DEBUGF(infof(data, "wolfssh callback: type %s\n",
+ DEBUGF(infof(data, "wolfssh callback: type %s",
authtype == WOLFSSH_USERAUTH_PASSWORD ? "PASSWORD" :
"PUBLICCKEY"));
if(authtype == WOLFSSH_USERAUTH_PASSWORD) {
@@ -388,7 +390,7 @@ static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
}
sshc->ssh_session = wolfSSH_new(sshc->ctx);
- if(sshc->ssh_session == NULL) {
+ if(!sshc->ssh_session) {
failf(data, "No wolfSSH session");
goto error;
}
@@ -466,7 +468,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_STOP);
return CURLE_SSH;
}
- infof(data, "wolfssh connected!\n");
+ infof(data, "wolfssh connected!");
state(data, SSH_STOP);
break;
case SSH_STOP:
@@ -487,7 +489,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
return CURLE_OK;
}
else if(rc == WS_SUCCESS) {
- infof(data, "wolfssh SFTP connected!\n");
+ infof(data, "wolfssh SFTP connected!");
state(data, SSH_SFTP_REALPATH);
}
else {
@@ -516,7 +518,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
else {
memcpy(sshc->homedir, name->fName, name->fSz);
sshc->homedir[name->fSz] = 0;
- infof(data, "wolfssh SFTP realpath succeeded!\n");
+ infof(data, "wolfssh SFTP realpath succeeded!");
}
wolfSSH_SFTPNAME_list_free(name);
state(data, SSH_STOP);
@@ -534,7 +536,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
}
if(data->set.quote) {
- infof(data, "Sending quote commands\n");
+ infof(data, "Sending quote commands");
sshc->quote_item = data->set.quote;
state(data, SSH_SFTP_QUOTE);
}
@@ -585,7 +587,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
}
}
- if(data->set.ftp_append)
+ if(data->set.remote_append)
/* Try to open for append, but create if nonexisting */
flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND;
else if(data->state.resume_from > 0)
@@ -614,7 +616,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
return CURLE_OK;
}
else if(rc == WS_SUCCESS) {
- infof(data, "wolfssh SFTP open succeeded!\n");
+ infof(data, "wolfssh SFTP open succeeded!");
}
else {
failf(data, "wolfssh SFTP upload open failed: %d", rc);
@@ -725,7 +727,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
return CURLE_OK;
}
else if(rc == WS_SUCCESS) {
- infof(data, "wolfssh SFTP open succeeded!\n");
+ infof(data, "wolfssh SFTP open succeeded!");
state(data, SSH_SFTP_DOWNLOAD_STAT);
return CURLE_OK;
}
@@ -751,7 +753,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
return CURLE_OK;
}
else if(rc == WS_SUCCESS) {
- infof(data, "wolfssh STAT succeeded!\n");
+ infof(data, "wolfssh STAT succeeded!");
}
else {
failf(data, "wolfssh SFTP open failed: %d", rc);
@@ -767,12 +769,12 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
data->req.maxdownload = size;
Curl_pgrsSetDownloadSize(data, size);
- infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes\n", size);
+ infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size);
/* We cannot seek with wolfSSH so resuming and range requests are not
possible */
if(data->state.use_range || data->state.resume_from) {
- infof(data, "wolfSSH cannot do range/seek on SFTP\n");
+ infof(data, "wolfSSH cannot do range/seek on SFTP");
return CURLE_BAD_DOWNLOAD_RESUME;
}
@@ -780,7 +782,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->req.size == 0) {
/* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1);
- infof(data, "File already completely downloaded\n");
+ infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
@@ -859,9 +861,9 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
result = CURLE_OK;
while(name) {
char *line = aprintf("%s\n",
- data->set.ftp_list_only ?
+ data->set.list_only ?
name->fName : name->lName);
- if(line == NULL) {
+ if(!line) {
state(data, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
@@ -909,7 +911,7 @@ static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
/* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
try again */
if(*done) {
- DEBUGF(infof(data, "wssh_statemach_act says DONE\n"));
+ DEBUGF(infof(data, "wssh_statemach_act says DONE"));
}
} while(!result && !*done && !block);
@@ -935,7 +937,7 @@ CURLcode wsftp_perform(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- DEBUGF(infof(data, "DO phase starts\n"));
+ DEBUGF(infof(data, "DO phase starts"));
*dophase_done = FALSE; /* not done yet */
@@ -948,7 +950,7 @@ CURLcode wsftp_perform(struct Curl_easy *data,
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
@@ -1105,7 +1107,7 @@ static CURLcode wsftp_doing(struct Curl_easy *data,
CURLcode result = wssh_multi_statemach(data, dophase_done);
if(*dophase_done) {
- DEBUGF(infof(data, "DO phase is complete\n"));
+ DEBUGF(infof(data, "DO phase is complete"));
}
return result;
}
@@ -1117,7 +1119,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
CURLcode result = CURLE_OK;
(void)dead;
- DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
+ DEBUGF(infof(data, "SSH DISCONNECT starts now"));
if(conn->proto.sshc.ssh_session) {
/* only if there's a session still around to use! */
@@ -1125,7 +1127,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
result = wssh_block_statemach(data, TRUE);
}
- DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
+ DEBUGF(infof(data, "SSH DISCONNECT is done"));
return result;
}
@@ -1146,9 +1148,9 @@ static int wssh_getsock(struct Curl_easy *data,
return bitmap;
}
-size_t Curl_ssh_version(char *buffer, size_t buflen)
+void Curl_ssh_version(char *buffer, size_t buflen)
{
- return msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
+ (void)msnprintf(buffer, buflen, "wolfssh/%s", LIBWOLFSSH_VERSION_STRING);
}
CURLcode Curl_ssh_init(void)
diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c
index 29b08c0..e87649e 100644
--- a/Utilities/cmcurl/lib/vtls/bearssl.c
+++ b/Utilities/cmcurl/lib/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,13 +324,11 @@ 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);
-#ifndef CURL_DISABLE_PROXY
- const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- const char *hostname = conn->host.name;
-#endif
+ 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);
CURLcode ret;
@@ -345,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."
@@ -354,7 +399,7 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
return ret;
}
infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
+ " continuing anyway:");
}
}
@@ -375,9 +420,10 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
void *session;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, &session, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
+ &session, NULL, sockindex)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
- infof(data, "BearSSL: re-using session ID\n");
+ infof(data, "BearSSL: re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -389,19 +435,19 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
* protocols array in `struct ssl_backend_data`.
*/
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif
) {
- backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ backend->protocols[cur++] = ALPN_H2;
+ infof(data, "ALPN, offering %s", ALPN_H2);
}
#endif
backend->protocols[cur++] = ALPN_HTTP_1_1;
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
br_ssl_engine_set_protocol_names(&backend->ctx.eng,
backend->protocols, cur);
@@ -542,22 +588,22 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
protocol = br_ssl_engine_get_selected_protocol(&backend->ctx.eng);
if(protocol) {
- infof(data, "ALPN, server accepted to use %s\n", protocol);
+ infof(data, "ALPN, server accepted to use %s", protocol);
-#ifdef USE_NGHTTP2
- if(!strcmp(protocol, NGHTTP2_PROTO_VERSION_ID))
+#ifdef USE_HTTP2
+ if(!strcmp(protocol, ALPN_H2))
conn->negnpn = CURL_HTTP_VERSION_2;
else
#endif
if(!strcmp(protocol, ALPN_HTTP_1_1))
conn->negnpn = CURL_HTTP_VERSION_1_1;
else
- infof(data, "ALPN, unrecognized protocol %s\n", protocol);
+ infof(data, "ALPN, unrecognized protocol %s", protocol);
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
}
if(SSL_SET_OPTION(primary.sessionid)) {
@@ -571,10 +617,13 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
incache = !(Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
&oldsession, NULL, sockindex));
if(incache)
Curl_ssl_delsessionid(data, oldsession);
- ret = Curl_ssl_addsessionid(data, conn, session, 0, sockindex);
+ ret = Curl_ssl_addsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ session, 0, sockindex);
Curl_ssl_sessionid_unlock(data);
if(ret) {
free(session);
@@ -841,29 +890,32 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
}
const struct Curl_ssl Curl_ssl_bearssl = {
- { CURLSSLBACKEND_BEARSSL, "bearssl" },
- 0,
+ { CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
+ SSLSUPP_CAINFO_BLOB,
sizeof(struct ssl_backend_data),
- Curl_none_init,
- Curl_none_cleanup,
- bearssl_version,
- Curl_none_check_cxn,
- Curl_none_shutdown,
- bearssl_data_pending,
- bearssl_random,
- Curl_none_cert_status_request,
- bearssl_connect,
- bearssl_connect_nonblocking,
- bearssl_get_internals,
- bearssl_close,
- Curl_none_close_all,
- bearssl_session_free,
- Curl_none_set_engine,
- Curl_none_set_engine_default,
- Curl_none_engines_list,
- Curl_none_false_start,
- bearssl_sha256sum
+ Curl_none_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ bearssl_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_none_shutdown, /* shutdown */
+ bearssl_data_pending, /* data_pending */
+ bearssl_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ bearssl_connect, /* connect */
+ bearssl_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
+ bearssl_get_internals, /* get_internals */
+ bearssl_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ bearssl_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ bearssl_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_BEARSSL */
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
index 9b5f649..e451f6a 100644
--- a/Utilities/cmcurl/lib/vtls/gskit.c
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -101,8 +101,10 @@
struct ssl_backend_data {
gsk_handle handle;
int iocport;
+#ifndef CURL_DISABLE_PROXY
int localfd;
int remotefd;
+#endif
};
#define BACKEND connssl->backend
@@ -178,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:
@@ -206,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;
@@ -221,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)
@@ -243,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)
@@ -265,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) {
@@ -272,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));
@@ -285,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));
@@ -302,8 +313,9 @@ static CURLcode set_callback(struct Curl_easy *data,
static CURLcode set_ciphers(struct Curl_easy *data,
- gsk_handle h, unsigned int *protoflags)
+ gsk_handle h, unsigned int *protoflags)
{
+ struct connectdata *conn = data->conn;
const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
const char *clp;
const struct gskit_cipher *ctp;
@@ -515,6 +527,7 @@ static void close_async_handshake(struct ssl_connect_data *connssl)
static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
int directions)
{
+#ifndef CURL_DISABLE_PROXY
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
fd_set fds_read;
@@ -583,6 +596,9 @@ static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
}
return ret; /* OK */
+#else
+ return 0;
+#endif
}
@@ -596,6 +612,7 @@ static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
;
BACKEND->handle = (gsk_handle) NULL;
+#ifndef CURL_DISABLE_PROXY
if(BACKEND->localfd >= 0) {
close(BACKEND->localfd);
BACKEND->localfd = -1;
@@ -604,13 +621,14 @@ static void close_one(struct ssl_connect_data *connssl, struct Curl_easy *data,
close(BACKEND->remotefd);
BACKEND->remotefd = -1;
}
+#endif
}
if(BACKEND->iocport >= 0)
close_async_handshake(connssl);
}
-static ssize_t gskit_send(struct connectdata *conn, int sockindex,
+static ssize_t gskit_send(struct Curl_easy *data, int sockindex,
const void *mem, size_t len, CURLcode *curlcode)
{
struct connectdata *conn = data->conn;
@@ -665,6 +683,7 @@ static ssize_t gskit_recv(struct Curl_easy *data, int num, char *buf,
static CURLcode
set_ssl_version_min_max(unsigned int *protoflags, struct Curl_easy *data)
{
+ struct connectdata *conn = data->conn;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
long i = ssl_version;
@@ -700,26 +719,28 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
gsk_handle envir;
CURLcode result;
- int rc;
const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
const char * const keyringlabel = SSL_SET_OPTION(primary.clientcert);
const long int ssl_version = SSL_CONN_CONFIG(version);
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
- const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
- conn->host.name;
+ const char * const hostname = SSL_HOST_NAME();
const char *sni;
unsigned int protoflags = 0;
Qso_OverlappedIO_t commarea;
+#ifndef CURL_DISABLE_PROXY
int sockpair[2];
static const int sobufsize = CURL_MAX_WRITE_SIZE;
+#endif
/* Create SSL environment, start (preferably asynchronous) handshake. */
BACKEND->handle = (gsk_handle) NULL;
BACKEND->iocport = -1;
+#ifndef CURL_DISABLE_PROXY
BACKEND->localfd = -1;
BACKEND->remotefd = -1;
+#endif
/* GSKit supports two ways of specifying an SSL context: either by
* application identifier (that should have been defined at the system
@@ -758,6 +779,7 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
if(result)
return result;
+#ifndef CURL_DISABLE_PROXY
/* Establish a pipelining socket pair for SSL over SSL. */
if(conn->proxy_ssl[sockindex].use) {
if(Curl_socketpair(0, 0, 0, sockpair))
@@ -775,6 +797,7 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
curlx_nonblock(BACKEND->localfd, TRUE);
curlx_nonblock(BACKEND->remotefd, TRUE);
}
+#endif
/* Determine which SSL/TLS version should be enabled. */
sni = hostname;
@@ -827,8 +850,13 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
if(!result)
result = set_numeric(data, BACKEND->handle, GSK_OS400_READ_TIMEOUT, 1);
if(!result)
+#ifndef CURL_DISABLE_PROXY
result = set_numeric(data, BACKEND->handle, GSK_FD, BACKEND->localfd >= 0?
BACKEND->localfd: conn->sock[sockindex]);
+#else
+ result = set_numeric(data, BACKEND->handle, GSK_FD,
+ conn->sock[sockindex]);
+#endif
if(!result)
result = set_ciphers(data, BACKEND->handle, &protoflags);
if(!protoflags) {
@@ -897,10 +925,12 @@ static CURLcode gskit_connect_step1(struct Curl_easy *data,
else if(errno != ENOBUFS)
result = gskit_status(data, GSK_ERROR_IO,
"QsoCreateIOCompletionPort()", 0);
+#ifndef CURL_DISABLE_PROXY
else if(conn->proxy_ssl[sockindex].use) {
/* Cannot pipeline while handshaking synchronously. */
result = CURLE_SSL_CONNECT_ERROR;
}
+#endif
else {
/* No more completion port available. Use synchronous IO. */
result = gskit_status(data, gsk_secure_soc_init(BACKEND->handle),
@@ -945,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;
@@ -990,7 +1022,7 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
CURLE_OK) {
int i;
- infof(data, "Server certificate:\n");
+ infof(data, "Server certificate:");
p = cdev;
for(i = 0; i++ < cdec; p++)
switch(p->cert_data_id) {
@@ -999,16 +1031,16 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
certend = cert + cdev->cert_data_l;
break;
case CERT_DN_PRINTABLE:
- infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
+ infof(data, "\t subject: %.*s", p->cert_data_l, p->cert_data_p);
break;
case CERT_ISSUER_DN_PRINTABLE:
- infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
+ infof(data, "\t issuer: %.*s", p->cert_data_l, p->cert_data_p);
break;
case CERT_VALID_FROM:
- infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
+ infof(data, "\t start date: %.*s", p->cert_data_l, p->cert_data_p);
break;
case CERT_VALID_TO:
- infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
+ infof(data, "\t expire date: %.*s", p->cert_data_l, p->cert_data_p);
break;
}
}
@@ -1036,8 +1068,7 @@ static CURLcode gskit_connect_step3(struct Curl_easy *data,
}
/* Check pinned public key. */
- ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ ptr = SSL_PINNED_PUB_KEY();
if(!result && ptr) {
curl_X509certificate x509;
curl_asn1Element *p;
@@ -1159,7 +1190,9 @@ static void gskit_close(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
{
close_one(&conn->ssl[sockindex], data, conn, sockindex);
+#ifndef CURL_DISABLE_PROXY
close_one(&conn->proxy_ssl[sockindex], data, conn, sockindex);
+#endif
}
@@ -1170,6 +1203,7 @@ static int gskit_shutdown(struct Curl_easy *data,
int what;
int rc;
char buf[120];
+ int loop = 10; /* don't get stuck */
if(!BACKEND->handle)
return 0;
@@ -1184,7 +1218,7 @@ static int gskit_shutdown(struct Curl_easy *data,
what = SOCKET_READABLE(conn->sock[sockindex],
SSL_SHUTDOWN_TIMEOUT);
- for(;;) {
+ while(loop--) {
ssize_t nread;
if(what < 0) {
@@ -1206,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;
}
@@ -1282,7 +1317,9 @@ const struct Curl_ssl Curl_ssl_gskit = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- NULL /* sha256sum */
+ NULL, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_GSKIT */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
index 3ddee19..1b145d8 100644
--- a/Utilities/cmcurl/lib/vtls/gtls.c
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -35,14 +35,8 @@
#include <gnutls/abstract.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
-
-#ifdef USE_GNUTLS_NETTLE
#include <gnutls/crypto.h>
-#include <nettle/md5.h>
#include <nettle/sha2.h>
-#else
-#include <gcrypt.h>
-#endif
#include "urldata.h"
#include "sendf.h"
@@ -153,7 +147,7 @@ static void showtime(struct Curl_easy *data,
msnprintf(str,
sizeof(str),
- "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
+ " %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
text,
Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
tm->tm_mday,
@@ -162,7 +156,7 @@ static void showtime(struct Curl_easy *data,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
- infof(data, "%s\n", str);
+ infof(data, "%s", str);
}
#endif
@@ -269,10 +263,10 @@ static CURLcode handshake(struct Curl_easy *data,
strerr = gnutls_alert_get_name(alert);
}
- if(strerr == NULL)
+ if(!strerr)
strerr = gnutls_strerror(rc);
- infof(data, "gnutls_handshake() warning: %s\n", strerr);
+ infof(data, "gnutls_handshake() warning: %s", strerr);
continue;
}
else if(rc < 0) {
@@ -283,7 +277,7 @@ static CURLcode handshake(struct Curl_easy *data,
strerr = gnutls_alert_get_name(alert);
}
- if(strerr == NULL)
+ if(!strerr)
strerr = gnutls_strerror(rc);
failf(data, "gnutls_handshake() failed: %s", strerr);
@@ -314,15 +308,32 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
#define GNUTLS_SRP "+SRP"
static CURLcode
-set_ssl_version_min_max(const char **prioritylist, struct Curl_easy *data)
+set_ssl_version_min_max(struct Curl_easy *data,
+ const char **prioritylist,
+ const char *tls13support)
{
struct connectdata *conn = data->conn;
long ssl_version = SSL_CONN_CONFIG(version);
long ssl_version_max = SSL_CONN_CONFIG(version_max);
- if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
+ if((ssl_version == CURL_SSLVERSION_DEFAULT) ||
+ (ssl_version == CURL_SSLVERSION_TLSv1))
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+ if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
+ if(!tls13support) {
+ /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a
+ prioritylist involving that since it will make GnuTLS return an en
+ error back at us */
+ if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
+ (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) {
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ }
+ }
+ else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) {
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3;
}
+
switch(ssl_version | ssl_version_max) {
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
@@ -330,11 +341,11 @@ set_ssl_version_min_max(const char **prioritylist, struct Curl_easy *data)
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.0:+VERS-TLS1.1";
+ "+VERS-TLS1.1:+VERS-TLS1.0";
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2";
+ "+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0";
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
@@ -342,7 +353,7 @@ set_ssl_version_min_max(const char **prioritylist, struct Curl_easy *data)
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.1:+VERS-TLS1.2";
+ "+VERS-TLS1.2:+VERS-TLS1.1";
return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
@@ -352,25 +363,16 @@ set_ssl_version_min_max(const char **prioritylist, struct Curl_easy *data)
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
"+VERS-TLS1.3";
return CURLE_OK;
- case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
- *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2"
- ":+VERS-TLS1.3";
+ case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_3:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0";
return CURLE_OK;
- case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
+ case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_3:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.1:+VERS-TLS1.2"
- ":+VERS-TLS1.3";
+ "+VERS-TLS1.3:+VERS-TLS1.2:+VERS-TLS1.1";
return CURLE_OK;
- case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
+ case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_3:
*prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.2"
- ":+VERS-TLS1.3";
- return CURLE_OK;
- case CURL_SSLVERSION_TLSv1_3 | CURL_SSLVERSION_MAX_DEFAULT:
- *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
- "+VERS-TLS1.2"
- ":+VERS-TLS1.3";
+ "+VERS-TLS1.3:+VERS-TLS1.2";
return CURLE_OK;
}
@@ -401,6 +403,7 @@ gtls_connect_step1(struct Curl_easy *data,
const char *err = NULL;
const char * const hostname = SSL_HOST_NAME();
long * const certverifyresult = &SSL_SET_OPTION_LVALUE(certverifyresult);
+ const char *tls13support;
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
@@ -429,7 +432,7 @@ gtls_connect_step1(struct Curl_easy *data,
#ifdef HAVE_GNUTLS_SRP
if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
- infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
+ infof(data, "Using TLS-SRP username: %s", SSL_SET_OPTION(username));
rc = gnutls_srp_allocate_client_credentials(
&backend->srp_client_cred);
@@ -459,7 +462,7 @@ gtls_connect_step1(struct Curl_easy *data,
SSL_CONN_CONFIG(CAfile),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
- infof(data, "error reading ca cert file %s (%s)\n",
+ infof(data, "error reading ca cert file %s (%s)",
SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
if(SSL_CONN_CONFIG(verifypeer)) {
*certverifyresult = rc;
@@ -467,7 +470,7 @@ gtls_connect_step1(struct Curl_easy *data,
}
}
else
- infof(data, "found %d certificates in %s\n", rc,
+ infof(data, "found %d certificates in %s", rc,
SSL_CONN_CONFIG(CAfile));
}
@@ -477,7 +480,7 @@ gtls_connect_step1(struct Curl_easy *data,
SSL_CONN_CONFIG(CApath),
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
- infof(data, "error reading ca cert file %s (%s)\n",
+ infof(data, "error reading ca cert file %s (%s)",
SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
if(SSL_CONN_CONFIG(verifypeer)) {
*certverifyresult = rc;
@@ -485,7 +488,7 @@ gtls_connect_step1(struct Curl_easy *data,
}
}
else
- infof(data, "found %d certificates in %s\n",
+ infof(data, "found %d certificates in %s",
rc, SSL_CONN_CONFIG(CApath));
}
@@ -508,7 +511,7 @@ gtls_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CRL_BADFILE;
}
else
- infof(data, "found %d CRL in %s\n",
+ infof(data, "found %d CRL in %s",
rc, SSL_SET_OPTION(CRLfile));
}
@@ -541,43 +544,41 @@ gtls_connect_step1(struct Curl_easy *data,
(gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
strlen(hostname)) < 0))
infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension\n");
+ "TLS extension");
/* Use default priorities */
rc = gnutls_set_default_priority(session);
if(rc != GNUTLS_E_SUCCESS)
return CURLE_SSL_CONNECT_ERROR;
+ /* "In GnuTLS 3.6.5, TLS 1.3 is enabled by default" */
+ tls13support = gnutls_check_version("3.6.5");
+
/* 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_SSLv3:
- prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
- break;
+ 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:
- prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0"
-#ifdef HAS_TLS13
- ":+VERS-TLS1.3"
-#endif
- ;
- break;
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_3:
- {
- CURLcode result = set_ssl_version_min_max(&prioritylist, data);
- if(result != CURLE_OK)
- return result;
- break;
- }
+ case CURL_SSLVERSION_TLSv1_2: {
+ CURLcode result = set_ssl_version_min_max(data, &prioritylist,
+ tls13support);
+ if(result)
+ return result;
+ break;
+ }
case CURL_SSLVERSION_SSLv2:
- failf(data, "GnuTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv3:
default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ failf(data, "GnuTLS does not support SSLv2 or SSLv3");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -592,16 +593,16 @@ gtls_connect_step1(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
strcpy(prioritysrp, prioritylist);
strcpy(prioritysrp + len, ":" GNUTLS_SRP);
-
rc = gnutls_priority_set_direct(session, prioritysrp, &err);
free(prioritysrp);
if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
- infof(data, "This GnuTLS does not support SRP\n");
+ infof(data, "This GnuTLS does not support SRP");
}
}
else {
#endif
+ infof(data, "GnuTLS ciphers: %s", prioritylist);
rc = gnutls_priority_set_direct(session, prioritylist, &err);
#ifdef HAVE_GNUTLS_SRP
}
@@ -617,23 +618,23 @@ gtls_connect_step1(struct Curl_easy *data,
int cur = 0;
gnutls_datum_t protocols[2];
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif
) {
- protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
- protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
+ protocols[cur].data = (unsigned char *)ALPN_H2;
+ protocols[cur].size = ALPN_H2_LENGTH;
cur++;
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ infof(data, "ALPN, offering %.*s", ALPN_H2_LENGTH, ALPN_H2);
}
#endif
protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
cur++;
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
gnutls_alpn_set_protocols(session, protocols, cur, 0);
}
@@ -733,12 +734,13 @@ gtls_connect_step1(struct Curl_easy *data,
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
&ssl_sessionid, &ssl_idsize, sockindex)) {
/* we got a session id, use it! */
gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
/* Informational message */
- infof(data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -841,7 +843,7 @@ gtls_connect_step3(struct Curl_easy *data,
gnutls_cipher_get(session),
gnutls_mac_get(session));
- infof(data, "SSL connection using %s / %s\n",
+ infof(data, "SSL connection using %s / %s",
gnutls_protocol_get_name(version), ptr);
/* This function will return the peer's raw certificate (chain) as sent by
@@ -854,7 +856,7 @@ gtls_connect_step3(struct Curl_easy *data,
if(!chainp) {
if(SSL_CONN_CONFIG(verifypeer) ||
SSL_CONN_CONFIG(verifyhost) ||
- SSL_SET_OPTION(issuercert)) {
+ SSL_CONN_CONFIG(issuercert)) {
#ifdef HAVE_GNUTLS_SRP
if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
&& SSL_SET_OPTION(username) != NULL
@@ -872,7 +874,7 @@ gtls_connect_step3(struct Curl_easy *data,
}
#endif
}
- infof(data, "\t common name: WARNING couldn't obtain\n");
+ infof(data, " common name: WARNING couldn't obtain");
}
if(data->set.ssl.certinfo && chainp) {
@@ -919,13 +921,13 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
else
- infof(data, "\t server certificate verification FAILED\n");
+ infof(data, " server certificate verification FAILED");
}
else
- infof(data, "\t server certificate verification OK\n");
+ infof(data, " server certificate verification OK");
}
else
- infof(data, "\t server certificate verification SKIPPED\n");
+ infof(data, " server certificate verification SKIPPED");
if(SSL_CONN_CONFIG(verifystatus)) {
if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
@@ -937,7 +939,7 @@ gtls_connect_step3(struct Curl_easy *data,
rc = gnutls_ocsp_status_request_get(session, &status_request);
- infof(data, "\t server certificate status verification FAILED\n");
+ infof(data, " server certificate status verification FAILED");
if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
failf(data, "No OCSP response received");
@@ -1025,10 +1027,10 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_SSL_INVALIDCERTSTATUS;
}
else
- infof(data, "\t server certificate status verification OK\n");
+ infof(data, " server certificate status verification OK");
}
else
- infof(data, "\t server certificate status verification SKIPPED\n");
+ infof(data, " server certificate status verification SKIPPED");
/* initialize an X.509 certificate structure. */
gnutls_x509_crt_init(&x509_cert);
@@ -1038,21 +1040,21 @@ gtls_connect_step3(struct Curl_easy *data,
gnutls_x509_crt_t format */
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
- if(SSL_SET_OPTION(issuercert)) {
+ if(SSL_CONN_CONFIG(issuercert)) {
gnutls_x509_crt_init(&x509_issuer);
- issuerp = load_file(SSL_SET_OPTION(issuercert));
+ issuerp = load_file(SSL_CONN_CONFIG(issuercert));
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
gnutls_x509_crt_deinit(x509_issuer);
unload_file(issuerp);
if(rc <= 0) {
failf(data, "server certificate issuer check failed (IssuerCert: %s)",
- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
gnutls_x509_crt_deinit(x509_cert);
return CURLE_SSL_ISSUER_ERROR;
}
- infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
- SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+ infof(data, " server certificate issuer check OK (Issuer Cert: %s)",
+ SSL_CONN_CONFIG(issuercert)?SSL_CONN_CONFIG(issuercert):"none");
}
size = sizeof(certname);
@@ -1062,7 +1064,7 @@ gtls_connect_step3(struct Curl_easy *data,
certname,
&size);
if(rc) {
- infof(data, "error fetching CN from cert:%s\n",
+ infof(data, "error fetching CN from cert:%s",
gnutls_strerror(rc));
}
@@ -1122,11 +1124,11 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
else
- infof(data, "\t common name: %s (does not match '%s')\n",
+ infof(data, " common name: %s (does not match '%s')",
certname, SSL_HOST_DISPNAME());
}
else
- infof(data, "\t common name: %s (matched)\n", certname);
+ infof(data, " common name: %s (matched)", certname);
/* Check for time-based validity */
certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
@@ -1139,7 +1141,7 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
else
- infof(data, "\t server certificate expiration date verify FAILED\n");
+ infof(data, " server certificate expiration date verify FAILED");
}
else {
if(certclock < time(NULL)) {
@@ -1150,10 +1152,10 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
else
- infof(data, "\t server certificate expiration date FAILED\n");
+ infof(data, " server certificate expiration date FAILED");
}
else
- infof(data, "\t server certificate expiration date OK\n");
+ infof(data, " server certificate expiration date OK");
}
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
@@ -1166,7 +1168,7 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
else
- infof(data, "\t server certificate activation date verify FAILED\n");
+ infof(data, " server certificate activation date verify FAILED");
}
else {
if(certclock > time(NULL)) {
@@ -1177,14 +1179,13 @@ gtls_connect_step3(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
else
- infof(data, "\t server certificate activation date FAILED\n");
+ infof(data, " server certificate activation date FAILED");
}
else
- infof(data, "\t server certificate activation date OK\n");
+ infof(data, " server certificate activation date OK");
}
- ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ ptr = SSL_PINNED_PUB_KEY();
if(ptr) {
result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
if(result != CURLE_OK) {
@@ -1207,19 +1208,19 @@ gtls_connect_step3(struct Curl_easy *data,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* public key algorithm's parameters */
algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
- infof(data, "\t certificate public key: %s\n",
+ infof(data, " certificate public key: %s",
gnutls_pk_algorithm_get_name(algo));
/* version of the X.509 certificate. */
- infof(data, "\t certificate version: #%d\n",
+ infof(data, " certificate version: #%d",
gnutls_x509_crt_get_version(x509_cert));
rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
if(rc)
- infof(data, "Failed to get certificate name\n");
+ infof(data, "Failed to get certificate name");
else {
- infof(data, "\t subject: %s\n", certfields.data);
+ infof(data, " subject: %s", certfields.data);
certclock = gnutls_x509_crt_get_activation_time(x509_cert);
showtime(data, "start date", certclock);
@@ -1232,9 +1233,9 @@ gtls_connect_step3(struct Curl_easy *data,
rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
if(rc)
- infof(data, "Failed to get certificate issuer\n");
+ infof(data, "Failed to get certificate issuer");
else {
- infof(data, "\t issuer: %s\n", certfields.data);
+ infof(data, " issuer: %s", certfields.data);
gnutls_free(certfields.data);
}
@@ -1245,13 +1246,13 @@ gtls_connect_step3(struct Curl_easy *data,
if(conn->bits.tls_enable_alpn) {
rc = gnutls_alpn_get_selected_protocol(session, &proto);
if(rc == 0) {
- infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
+ infof(data, "ALPN, server accepted to use %.*s", proto.size,
proto.data);
-#ifdef USE_NGHTTP2
- if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
+#ifdef USE_HTTP2
+ if(proto.size == ALPN_H2_LENGTH &&
+ !memcmp(ALPN_H2, proto.data,
+ ALPN_H2_LENGTH)) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
@@ -1262,7 +1263,7 @@ gtls_connect_step3(struct Curl_easy *data,
}
}
else
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -1292,8 +1293,9 @@ gtls_connect_step3(struct Curl_easy *data,
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL,
- sockindex));
+ incache = !(Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ &ssl_sessionid, NULL, sockindex));
if(incache) {
/* there was one before in the cache, so instead of risking that the
previous one was rejected, we just kill that and store the new */
@@ -1301,8 +1303,10 @@ gtls_connect_step3(struct Curl_easy *data,
}
/* store this session id */
- result = Curl_ssl_addsessionid(data, conn, connect_sessionid,
- connect_idsize, sockindex);
+ result = Curl_ssl_addsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ connect_sessionid, connect_idsize,
+ sockindex);
Curl_ssl_sessionid_unlock(data);
if(result) {
free(connect_sessionid);
@@ -1429,6 +1433,10 @@ static void close_one(struct ssl_connect_data *connssl)
{
struct ssl_backend_data *backend = connssl->backend;
if(backend->session) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)gnutls_record_recv(backend->session, buf, sizeof(buf));
gnutls_bye(backend->session, GNUTLS_SHUT_WR);
gnutls_deinit(backend->session);
backend->session = NULL;
@@ -1497,7 +1505,7 @@ static int gtls_shutdown(struct Curl_easy *data, struct connectdata *conn,
break;
case GNUTLS_E_AGAIN:
case GNUTLS_E_INTERRUPTED:
- infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
+ infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
break;
default:
retval = -1;
@@ -1583,39 +1591,14 @@ static size_t gtls_version(char *buffer, size_t size)
return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
}
-#ifndef USE_GNUTLS_NETTLE
-static int gtls_seed(struct Curl_easy *data)
-{
- /* we have the "SSL is seeded" boolean static to prevent multiple
- time-consuming seedings in vain */
- static bool ssl_seeded = FALSE;
-
- /* Quickly add a bit of entropy */
- gcry_fast_random_poll();
-
- if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
- data->set.str[STRING_SSL_EGDSOCKET]) {
- ssl_seeded = TRUE;
- }
- return 0;
-}
-#endif
-
/* data might be NULL! */
static CURLcode gtls_random(struct Curl_easy *data,
unsigned char *entropy, size_t length)
{
-#if defined(USE_GNUTLS_NETTLE)
int rc;
(void)data;
rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
return rc?CURLE_FAILED_INIT:CURLE_OK;
-#elif defined(USE_GNUTLS)
- if(data)
- gtls_seed(data); /* Initiate the seed if not already done */
- gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
-#endif
- return CURLE_OK;
}
static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
@@ -1623,18 +1606,10 @@ static CURLcode gtls_sha256sum(const unsigned char *tmp, /* input */
unsigned char *sha256sum, /* output */
size_t sha256len)
{
-#if defined(USE_GNUTLS_NETTLE)
struct sha256_ctx SHA256pw;
sha256_init(&SHA256pw);
sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
-#elif defined(USE_GNUTLS)
- gcry_md_hd_t SHA256pw;
- gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
- gcry_md_write(SHA256pw, tmp, tmplen);
- memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
- gcry_md_close(SHA256pw);
-#endif
return CURLE_OK;
}
@@ -1644,7 +1619,7 @@ static bool gtls_cert_status_request(void)
}
static void *gtls_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+ CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
(void)info;
@@ -1671,6 +1646,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_cert_status_request, /* cert_status_request */
gtls_connect, /* connect */
gtls_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1679,7 +1655,9 @@ const struct Curl_ssl Curl_ssl_gnutls = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- gtls_sha256sum /* sha256sum */
+ gtls_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
index fc3a948..780d13e 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls.c
+++ b/Utilities/cmcurl/lib/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>
@@ -89,6 +91,10 @@ struct ssl_backend_data {
#define THREADING_SUPPORT
#endif
+#ifndef MBEDTLS_ERROR_C
+#define mbedtls_strerror(a,b,c) b[0] = 0
+#endif
+
#if defined(THREADING_SUPPORT)
static mbedtls_entropy_context ts_entropy;
@@ -179,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;
@@ -192,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;
}
@@ -201,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;
@@ -250,23 +274,19 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
+ const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
- const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
- const char * const hostname = conn->host.name;
- const long int port = conn->remote_port;
+ 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];
- errorbuf[0] = 0;
- /* mbedTLS only supports SSLv3 and TLSv1 */
- if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
- failf(data, "mbedTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
+ if((SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) ||
+ (SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)) {
+ failf(data, "Not supported SSL version");
+ return CURLE_NOT_BUILT_IN;
}
#ifdef THREADING_SUPPORT
@@ -276,9 +296,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
&ts_entropy, NULL, 0);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
-ret, errorbuf);
}
@@ -289,9 +307,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, mbedtls_entropy_func,
&backend->entropy, NULL, 0);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
-ret, errorbuf);
}
@@ -304,9 +320,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_x509_crt_parse_file(&backend->cacert, ssl_cafile);
if(ret<0) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
ssl_cafile, -ret, errorbuf);
@@ -319,9 +333,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_x509_crt_parse_path(&backend->cacert, ssl_capath);
if(ret<0) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
ssl_capath, -ret, errorbuf);
@@ -337,9 +349,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_x509_crt_parse_file(&backend->clicert, ssl_cert);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
ssl_cert, -ret, errorbuf);
@@ -347,27 +357,72 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
}
- /* Load the client private key */
- mbedtls_pk_init(&backend->pk);
-
- if(SSL_SET_OPTION(key)) {
- ret = mbedtls_pk_parse_keyfile(&backend->pk, SSL_SET_OPTION(key),
- SSL_SET_OPTION(key_passwd));
- if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
- mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
- ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+ if(ssl_cert_blob) {
+ const unsigned char *blob_data =
+ (const unsigned char *)ssl_cert_blob->data;
+ ret = mbedtls_x509_crt_parse(&backend->clicert, blob_data,
+ ssl_cert_blob->len);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
SSL_SET_OPTION(key), -ret, errorbuf);
-
return CURLE_SSL_CERTPROBLEM;
}
}
+ /* Load the client private key */
+ mbedtls_pk_init(&backend->pk);
+
+ 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));
+ failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+ SSL_SET_OPTION(key), -ret, errorbuf);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+ else {
+ const struct curl_blob *ssl_key_blob = SSL_SET_OPTION(key_blob);
+ 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));
+ failf(data, "Error parsing private key - mbedTLS: (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) ||
+ mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY)))
+ ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+ }
+
/* Load the CRL */
mbedtls_x509_crl_init(&backend->crl);
@@ -375,9 +430,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
ret = mbedtls_x509_crl_parse_file(&backend->crl, ssl_crlfile);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
ssl_crlfile, -ret, errorbuf);
@@ -385,7 +438,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
}
- infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port);
+ infof(data, "mbedTLS: Connecting to %s:%ld", hostname, port);
mbedtls_ssl_config_init(&backend->config);
@@ -410,17 +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\n");
- break;
- case CURL_SSLVERSION_SSLv3:
- mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
- MBEDTLS_SSL_MINOR_VERSION_0);
- mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
- MBEDTLS_SSL_MINOR_VERSION_0);
- infof(data, "mbedTLS: Set SSL version to SSLv3\n");
+ 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:
@@ -463,14 +511,16 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, &old_session, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ &old_session, NULL, sockindex)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "mbedTLS re-using session\n");
+ infof(data, "mbedTLS re-using session");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -479,7 +529,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
&backend->cacert,
&backend->crl);
- if(SSL_SET_OPTION(key)) {
+ if(SSL_SET_OPTION(key) || SSL_SET_OPTION(key_blob)) {
mbedtls_ssl_conf_own_cert(&backend->config,
&backend->clicert, &backend->pk);
}
@@ -495,7 +545,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(conn->bits.tls_enable_alpn) {
const char **p = &backend->protocols[0];
#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2)
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2)
*p++ = NGHTTP2_PROTO_VERSION_ID;
#endif
*p++ = ALPN_HTTP_1_1;
@@ -508,7 +558,7 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
for(p = &backend->protocols[0]; *p; ++p)
- infof(data, "ALPN, offering %s\n", *p);
+ infof(data, "ALPN, offering %s", *p);
}
#endif
@@ -547,14 +597,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
const mbedtls_x509_crt *peercert;
-#ifndef CURL_DISABLE_PROXY
- const char * const pinnedpubkey = SSL_IS_PROXY() ?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#else
- const char * const pinnedpubkey =
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#endif
+ const char * const pinnedpubkey = SSL_PINNED_PUB_KEY();
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
@@ -571,18 +614,14 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
else if(ret) {
char errorbuf[128];
- errorbuf[0] = 0;
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
-ret, errorbuf);
return CURLE_SSL_CONNECT_ERROR;
}
- infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
- mbedtls_ssl_get_ciphersuite(&backend->ssl)
- );
+ infof(data, "mbedTLS: Handshake complete, cipher is %s",
+ mbedtls_ssl_get_ciphersuite(&backend->ssl));
ret = mbedtls_ssl_get_verify_result(&backend->ssl);
@@ -619,9 +658,9 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
- infof(data, "Dumping cert info:\n%s\n", buffer);
+ infof(data, "Dumping cert info: %s", buffer);
else
- infof(data, "Unable to dump certificate information.\n");
+ infof(data, "Unable to dump certificate information");
free(buffer);
}
@@ -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
@@ -682,7 +741,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
const char *next_protocol = mbedtls_ssl_get_alpn_protocol(&backend->ssl);
if(next_protocol) {
- infof(data, "ALPN, server accepted to use %s\n", next_protocol);
+ infof(data, "ALPN, server accepted to use %s", next_protocol);
#ifdef USE_NGHTTP2
if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
NGHTTP2_PROTO_VERSION_ID_LEN) &&
@@ -697,7 +756,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
}
}
else {
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
}
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -705,7 +764,7 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#endif
connssl->connecting_state = ssl_connect_3;
- infof(data, "SSL connected\n");
+ infof(data, "SSL connected");
return CURLE_OK;
}
@@ -724,6 +783,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
+ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -742,11 +802,12 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
/* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL, sockindex))
+ if(!Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
+ sockindex))
Curl_ssl_delsessionid(data, old_ssl_sessionid);
- retcode = Curl_ssl_addsessionid(data, conn,
- our_ssl_sessionid, 0, sockindex);
+ retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
+ 0, sockindex);
Curl_ssl_sessionid_unlock(data);
if(retcode) {
mbedtls_ssl_session_free(our_ssl_sessionid);
@@ -791,8 +852,13 @@ static void mbedtls_close(struct Curl_easy *data,
{
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
-
+ char buf[32];
(void) data;
+
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
+
mbedtls_pk_free(&backend->pk);
mbedtls_x509_crt_free(&backend->clicert);
mbedtls_x509_crt_free(&backend->cacert);
@@ -860,15 +926,12 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_entropy_init(&ctr_entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
- errorbuf[0] = 0;
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
&ctr_entropy, NULL, 0);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s",
-ret, errorbuf);
}
@@ -876,9 +939,7 @@ static CURLcode mbedtls_random(struct Curl_easy *data,
ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
if(ret) {
-#ifdef MBEDTLS_ERROR_C
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
-#endif /* MBEDTLS_ERROR_C */
failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s",
-ret, errorbuf);
}
@@ -1062,12 +1123,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;
@@ -1100,6 +1166,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_cert_status_request, /* cert_status_request */
mbedtls_connect, /* connect */
mbedtls_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
@@ -1108,7 +1175,9 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- mbedtls_sha256sum /* sha256sum */
+ mbedtls_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_MBEDTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
index 473f517..751755c 100644
--- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c
+++ b/Utilities/cmcurl/lib/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/Utilities/cmcurl/lib/vtls/mesalink.c b/Utilities/cmcurl/lib/vtls/mesalink.c
index b6d1005..3db9184 100644
--- a/Utilities/cmcurl/lib/vtls/mesalink.c
+++ b/Utilities/cmcurl/lib/vtls/mesalink.c
@@ -98,8 +98,7 @@ mesalink_connect_step1(struct Curl_easy *data,
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
- const char *const hostname =
- SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name;
+ const char * const hostname = SSL_HOST_NAME();
size_t hostname_len = strlen(hostname);
SSL_METHOD *req_method = NULL;
@@ -168,14 +167,14 @@ mesalink_connect_step1(struct Curl_easy *data,
}
infof(data,
"error setting certificate verify locations,"
- " continuing anyway:\n");
+ " continuing anyway:");
}
else {
- infof(data, "successfully set certificate verify locations:\n");
+ infof(data, "successfully set certificate verify locations:");
}
- infof(data, " CAfile: %s\n",
+ infof(data, " CAfile: %s",
SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none");
- infof(data, " CApath: %s\n",
+ infof(data, " CApath: %s",
SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none");
}
@@ -197,7 +196,7 @@ mesalink_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
infof(data,
- "client cert: %s\n",
+ "client cert: %s",
SSL_CONN_CONFIG(clientcert)?
SSL_CONN_CONFIG(clientcert): "none");
}
@@ -210,7 +209,7 @@ mesalink_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CIPHER;
}
#endif
- infof(data, "Cipher selection: %s\n", ciphers);
+ infof(data, "Cipher selection: %s", ciphers);
}
if(BACKEND->handle)
@@ -261,7 +260,9 @@ mesalink_connect_step1(struct Curl_easy *data,
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
if(!SSL_set_session(BACKEND->handle, ssl_sessionid)) {
Curl_ssl_sessionid_unlock(data);
@@ -272,7 +273,7 @@ mesalink_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
- infof(data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -325,7 +326,7 @@ mesalink_connect_step2(struct Curl_easy *data,
connssl->connecting_state = ssl_connect_3;
infof(data,
- "SSL connection using %s / %s\n",
+ "SSL connection using %s / %s",
SSL_get_version(BACKEND->handle),
SSL_get_cipher_name(BACKEND->handle));
@@ -345,24 +346,26 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
bool incache;
SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
+ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
our_ssl_sessionid = SSL_get_session(BACKEND->handle);
Curl_ssl_sessionid_lock(data);
incache =
- !(Curl_ssl_getsessionid(data, conn,
- &old_ssl_sessionid, NULL, sockindex));
+ !(Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
+ sockindex));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing\n");
+ infof(data, "old SSL session ID is stale, removing");
Curl_ssl_delsessionid(data, old_ssl_sessionid);
incache = FALSE;
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(
- data, conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
+ result =
+ Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0,
+ sockindex);
if(result) {
Curl_ssl_sessionid_unlock(data);
failf(data, "failed to store ssl session");
@@ -654,6 +657,7 @@ const struct Curl_ssl Curl_ssl_mesalink = {
Curl_none_cert_status_request, /* cert_status_request */
mesalink_connect, /* connect */
mesalink_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
mesalink_get_internals, /* get_internals */
mesalink_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -662,7 +666,9 @@ const struct Curl_ssl Curl_ssl_mesalink = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- NULL /* sha256sum */
+ NULL, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
index e5ab71c..cf65789 100644
--- a/Utilities/cmcurl/lib/vtls/nss.c
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -139,9 +139,15 @@ static const struct cipher_s cipherlist[] = {
{"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
{"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
{"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
+ {"dhe_rsa_3des_sha", SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"dhe_dss_3des_sha", SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA},
+ {"dhe_rsa_des_sha", SSL_DHE_RSA_WITH_DES_CBC_SHA},
+ {"dhe_dss_des_sha", SSL_DHE_DSS_WITH_DES_CBC_SHA},
/* TLS 1.0: Exportable 56-bit Cipher Suites. */
{"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
{"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
+ /* Ephemeral DH with RC4 bulk encryption */
+ {"dhe_dss_rc4_128_sha", TLS_DHE_DSS_WITH_RC4_128_SHA},
/* AES ciphers. */
{"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
{"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
@@ -219,6 +225,25 @@ static const struct cipher_s cipherlist[] = {
{"aes_256_gcm_sha_384", TLS_AES_256_GCM_SHA384},
{"chacha20_poly1305_sha_256", TLS_CHACHA20_POLY1305_SHA256},
#endif
+#ifdef TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ /* AES CBC cipher suites in RFC 5246. Introduced in NSS release 3.20 */
+ {"dhe_dss_aes_128_sha_256", TLS_DHE_DSS_WITH_AES_128_CBC_SHA256},
+ {"dhe_dss_aes_256_sha_256", TLS_DHE_DSS_WITH_AES_256_CBC_SHA256},
+#endif
+#ifdef TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ /* Camellia cipher suites in RFC 4132/5932.
+ Introduced in NSS release 3.12 */
+ {"dhe_rsa_camellia_128_sha", TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA},
+ {"dhe_dss_camellia_128_sha", TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA},
+ {"dhe_rsa_camellia_256_sha", TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA},
+ {"dhe_dss_camellia_256_sha", TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA},
+ {"rsa_camellia_128_sha", TLS_RSA_WITH_CAMELLIA_128_CBC_SHA},
+ {"rsa_camellia_256_sha", TLS_RSA_WITH_CAMELLIA_256_CBC_SHA},
+#endif
+#ifdef TLS_RSA_WITH_SEED_CBC_SHA
+ /* SEED cipher suite in RFC 4162. Introduced in NSS release 3.12.3 */
+ {"rsa_seed_sha", TLS_RSA_WITH_SEED_CBC_SHA},
+#endif
};
#if defined(WIN32)
@@ -312,7 +337,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
while((*cipher) && (ISSPACE(*cipher)))
++cipher;
- cipher_list = strchr(cipher, ',');
+ cipher_list = strpbrk(cipher, ":, ");
if(cipher_list) {
*cipher_list++ = '\0';
}
@@ -380,7 +405,7 @@ static int is_file(const char *filename)
{
struct_stat st;
- if(filename == NULL)
+ if(!filename)
return 0;
if(stat(filename, &st) == 0)
@@ -408,7 +433,7 @@ static char *dup_nickname(struct Curl_easy *data, const char *str)
n = strchr(str, '/');
if(!n) {
infof(data, "warning: certificate file name \"%s\" handled as nickname; "
- "please use \"./%s\" to force file name\n", str, str);
+ "please use \"./%s\" to force file name", str, str);
return strdup(str);
}
@@ -542,7 +567,6 @@ static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
if(!result && !cacert) {
/* we have successfully loaded a client certificate */
- CERTCertificate *cert;
char *nickname = NULL;
char *n = strrchr(filename, '/');
if(n)
@@ -554,7 +578,7 @@ static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
* <https://bugzilla.redhat.com/733685>. */
nickname = aprintf("PEM Token #1:%s", n);
if(nickname) {
- cert = PK11_FindCertFromNickname(nickname, NULL);
+ CERTCertificate *cert = PK11_FindCertFromNickname(nickname, NULL);
if(cert)
CERT_DestroyCertificate(cert);
@@ -800,7 +824,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
#endif
if(!SSL_CONN_CONFIG(verifypeer)) {
- infof(data, "skipping SSL peer certificate verification\n");
+ infof(data, "skipping SSL peer certificate verification");
return SECSuccess;
}
@@ -833,21 +857,21 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
#endif
case SSL_NEXT_PROTO_NO_SUPPORT:
case SSL_NEXT_PROTO_NO_OVERLAP:
- infof(data, "ALPN/NPN, server did not agree to a protocol\n");
+ infof(data, "ALPN/NPN, server did not agree to a protocol");
return;
#ifdef SSL_ENABLE_ALPN
case SSL_NEXT_PROTO_SELECTED:
- infof(data, "ALPN, server accepted to use %.*s\n", buflen, buf);
+ infof(data, "ALPN, server accepted to use %.*s", buflen, buf);
break;
#endif
case SSL_NEXT_PROTO_NEGOTIATED:
- infof(data, "NPN, server accepted to use %.*s\n", buflen, buf);
+ infof(data, "NPN, server accepted to use %.*s", buflen, buf);
break;
}
#ifdef USE_NGHTTP2
- if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ if(buflen == ALPN_H2_LENGTH &&
+ !memcmp(ALPN_H2, buf, ALPN_H2_LENGTH)) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
@@ -913,7 +937,7 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
*canFalseStart = PR_TRUE;
- infof(data, "Trying TLS False Start\n");
+ infof(data, "Trying TLS False Start");
end:
return SECSuccess;
@@ -931,17 +955,17 @@ 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, "\tsubject: %s\n", subject);
+ infof(data, "subject: %s\n", subject);
CERT_GetCertTimes(cert, &notBefore, &notAfter);
PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
- infof(data, "\tstart date: %s\n", timeString);
+ infof(data, " start date: %s", timeString);
PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
- infof(data, "\texpire date: %s\n", timeString);
- infof(data, "\tcommon name: %s\n", common_name);
- infof(data, "\tissuer: %s\n", issuer);
+ infof(data, " expire date: %s", timeString);
+ infof(data, " common name: %s", common_name);
+ infof(data, " issuer: %s", issuer);
PR_Free(subject);
PR_Free(issuer);
@@ -957,20 +981,19 @@ static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
CERTCertificate *cert2;
CERTCertificate *cert3;
PRTime now;
- int i;
if(SSL_GetChannelInfo(sock, &channel, sizeof(channel)) ==
SECSuccess && channel.length == sizeof(channel) &&
channel.cipherSuite) {
if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
&suite, sizeof(suite)) == SECSuccess) {
- infof(data, "SSL connection using %s\n", suite.cipherSuiteName);
+ infof(data, "SSL connection using %s", suite.cipherSuiteName);
}
}
cert = SSL_PeerCertificate(sock);
if(cert) {
- infof(data, "Server certificate:\n");
+ infof(data, "Server certificate:");
if(!data->set.ssl.certinfo) {
display_cert_info(data, cert);
@@ -978,8 +1001,8 @@ static CURLcode display_conn_info(struct Curl_easy *data, PRFileDesc *sock)
}
else {
/* Count certificates in chain. */
+ int i = 1;
now = PR_Now();
- i = 1;
if(!cert->isRoot) {
cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
while(cert2) {
@@ -1035,7 +1058,7 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
/* print only info about the cert, the error is printed off the callback */
cert = SSL_PeerCertificate(sock);
if(cert) {
- infof(data, "Server certificate:\n");
+ infof(data, "Server certificate:");
display_cert_info(data, cert);
CERT_DestroyCertificate(cert);
}
@@ -1109,7 +1132,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
/* report the resulting status */
switch(result) {
case CURLE_OK:
- infof(data, "pinned public key verified successfully!\n");
+ infof(data, "pinned public key verified successfully!");
break;
case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
failf(data, "failed to verify pinned public key");
@@ -1173,7 +1196,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECFailure;
}
- infof(data, "NSS: client certificate from file\n");
+ infof(data, "NSS: client certificate from file");
display_cert_info(data, cert);
*pRetCert = cert;
@@ -1211,7 +1234,7 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECFailure;
}
- infof(data, "NSS: using client certificate: %s\n", nickname);
+ infof(data, "NSS: using client certificate: %s", nickname);
display_cert_info(data, *pRetCert);
return SECSuccess;
}
@@ -1332,7 +1355,7 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
if(!certpath)
return CURLE_OUT_OF_MEMORY;
- infof(data, "Initializing NSS with certpath: %s\n", certpath);
+ infof(data, "Initializing NSS with certpath: %s", certpath);
nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
free(certpath);
@@ -1342,10 +1365,10 @@ static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
err = PR_GetError();
err_name = nss_error_to_name(err);
- infof(data, "Unable to initialize NSS database: %d (%s)\n", err, err_name);
+ infof(data, "Unable to initialize NSS database: %d (%s)", err, err_name);
}
- infof(data, "Initializing NSS with certpath: none\n");
+ infof(data, "Initializing NSS with certpath: none");
nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
| NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
| NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
@@ -1425,7 +1448,7 @@ static CURLcode nss_setup(struct Curl_easy *data)
static int nss_init(void)
{
/* curl_global_init() is not thread-safe so this test is ok */
- if(nss_initlock == NULL) {
+ if(!nss_initlock) {
PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
nss_initlock = PR_NewLock();
nss_crllock = PR_NewLock();
@@ -1523,6 +1546,14 @@ static void close_one(struct ssl_connect_data *connssl)
const bool client_cert = (backend->client_nickname != NULL)
|| (backend->obj_clicert != NULL);
+ if(backend->handle) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)PR_Recv(backend->handle, buf, (int)sizeof(buf), 0,
+ PR_INTERVAL_NO_WAIT);
+ }
+
free(backend->client_nickname);
backend->client_nickname = NULL;
@@ -1627,8 +1658,8 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
if(capath && !capath[0])
capath = NULL;
- infof(data, " CAfile: %s\n", cafile ? cafile : "none");
- infof(data, " CApath: %s\n", capath ? capath : "none");
+ infof(data, " CAfile: %s", cafile ? cafile : "none");
+ infof(data, " CApath: %s", capath ? capath : "none");
/* load libnssckbi.so if no other trust roots were specified */
use_trust_module = !cafile && !capath;
@@ -1637,7 +1668,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
if(use_trust_module && !trust_module) {
/* libnssckbi.so needed but not yet loaded --> load it! */
result = nss_load_module(&trust_module, trust_library, "trust");
- infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
+ infof(data, "%s %s", (result) ? "failed to load" : "loaded",
trust_library);
if(result == CURLE_FAILED_INIT)
/* If libnssckbi.so is not available (or fails to load), one can still
@@ -1646,7 +1677,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
}
else if(!use_trust_module && trust_module) {
/* libnssckbi.so not needed but already loaded --> unload it! */
- infof(data, "unloading %s\n", trust_library);
+ infof(data, "unloading %s", trust_library);
nss_unload_module(&trust_module);
}
PR_Unlock(nss_trustload_lock);
@@ -1679,7 +1710,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
/* This is purposefully tolerant of errors so non-PEM files can
* be in the same directory */
- infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
+ infof(data, "failed to load '%s' from CURLOPT_CAPATH", fullpath);
free(fullpath);
}
@@ -1687,7 +1718,7 @@ static CURLcode nss_load_ca_certificates(struct Curl_easy *data,
PR_CloseDir(dir);
}
else
- infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
+ infof(data, "warning: CURLOPT_CAPATH not a directory (%s)", capath);
}
return CURLE_OK;
@@ -1701,8 +1732,7 @@ static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
return CURLE_OK;
case CURL_SSLVERSION_SSLv3:
- *nssver = SSL_LIBRARY_VERSION_3_0;
- return CURLE_OK;
+ return CURLE_NOT_BUILT_IN;
case CURL_SSLVERSION_TLSv1_0:
*nssver = SSL_LIBRARY_VERSION_TLS_1_0;
@@ -1782,17 +1812,16 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
struct Curl_easy *data,
CURLcode curlerr)
{
- PRErrorCode err = 0;
struct ssl_backend_data *backend = connssl->backend;
if(is_nss_error(curlerr)) {
/* read NSPR error code */
- err = PR_GetError();
+ PRErrorCode err = PR_GetError();
if(is_cc_error(err))
curlerr = CURLE_SSL_CERTPROBLEM;
/* print the error number and error string */
- infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
+ infof(data, "NSS error %d (%s)", err, nss_error_to_name(err));
/* print a human-readable message describing the error if available */
nss_print_error_message(data, err);
@@ -1809,7 +1838,7 @@ static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
struct Curl_easy *data,
bool blocking)
{
- static PRSocketOptionData sock_opt;
+ PRSocketOptionData sock_opt;
struct ssl_backend_data *backend = connssl->backend;
sock_opt.option = PR_SockOpt_Nonblocking;
sock_opt.value.non_blocking = !blocking;
@@ -1866,7 +1895,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
PR_Unlock(nss_initlock);
if(result == CURLE_FAILED_INIT)
infof(data, "WARNING: failed to load NSS PEM library %s. Using "
- "OpenSSL PEM certificates will not work.\n", pem_library);
+ "OpenSSL PEM certificates will not work.", pem_library);
else if(result)
goto error;
@@ -1901,8 +1930,8 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
sslver_req_str = nss_sslver_to_name(sslver.max);
sslver_supp_str = nss_sslver_to_name(sslver_supported.max);
if(sslver_req_str && sslver_supp_str)
- infof(data, "Falling back from %s to max supported SSL version (%s)\n",
- sslver_req_str, sslver_supp_str);
+ infof(data, "Falling back from %s to max supported SSL version (%s)",
+ sslver_req_str, sslver_supp_str);
free(sslver_req_str);
free(sslver_supp_str);
sslver.max = sslver_supported.max;
@@ -1915,11 +1944,11 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
/* unless the user explicitly asks to allow the protocol vulnerability, we
use the work-around */
if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
- infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
+ infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d",
ssl_cbc_random_iv);
#else
if(ssl_cbc_random_iv)
- infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
+ infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in");
#endif
if(SSL_CONN_CONFIG(cipher_list)) {
@@ -1930,7 +1959,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
}
if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
- infof(data, "warning: ignoring value of ssl.verifyhost\n");
+ infof(data, "warning: ignoring value of ssl.verifyhost");
/* bypass the default SSL_AuthCertificate() hook in case we do not want to
* verify peer */
@@ -1950,7 +1979,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
const CURLcode rv = nss_load_ca_certificates(data, conn, sockindex);
if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
/* not a fatal error because we are not going to verify the peer */
- infof(data, "warning: CA certificates failed to load\n");
+ infof(data, "warning: CA certificates failed to load");
else if(rv) {
result = rv;
goto error;
@@ -1963,7 +1992,7 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
result = rv;
goto error;
}
- infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
+ infof(data, " CRLfile: %s", SSL_SET_OPTION(CRLfile));
}
if(SSL_SET_OPTION(primary.clientcert)) {
@@ -2082,16 +2111,15 @@ static CURLcode nss_setup_connect(struct Curl_easy *data,
int cur = 0;
unsigned char protocols[128];
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif
) {
- protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
- memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN);
- cur += NGHTTP2_PROTO_VERSION_ID_LEN;
+ protocols[cur++] = ALPN_H2_LENGTH;
+ memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH);
+ cur += ALPN_H2_LENGTH;
}
#endif
protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
@@ -2159,9 +2187,9 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
if(result)
goto error;
- if(SSL_SET_OPTION(issuercert)) {
+ if(SSL_CONN_CONFIG(issuercert)) {
SECStatus ret = SECFailure;
- char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
+ char *nickname = dup_nickname(data, SSL_CONN_CONFIG(issuercert));
if(nickname) {
/* we support only nicknames in case of issuercert for now */
ret = check_issuer_cert(backend->handle, nickname);
@@ -2169,12 +2197,12 @@ static CURLcode nss_do_connect(struct Curl_easy *data,
}
if(SECFailure == ret) {
- infof(data, "SSL certificate issuer check failed\n");
+ infof(data, "SSL certificate issuer check failed");
result = CURLE_SSL_ISSUER_ERROR;
goto error;
}
else {
- infof(data, "SSL certificate issuer check ok\n");
+ infof(data, "SSL certificate issuer check ok");
}
}
@@ -2286,7 +2314,7 @@ static ssize_t nss_send(struct Curl_easy *data, /* transfer */
else {
/* print the error number and error string */
const char *err_name = nss_error_to_name(err);
- infof(data, "SSL write: error %d (%s)\n", err, err_name);
+ infof(data, "SSL write: error %d (%s)", err, err_name);
/* print a human-readable message describing the error if available */
nss_print_error_message(data, err);
@@ -2328,7 +2356,7 @@ static ssize_t nss_recv(struct Curl_easy *data, /* transfer */
else {
/* print the error number and error string */
const char *err_name = nss_error_to_name(err);
- infof(data, "SSL read: errno %d (%s)\n", err, err_name);
+ infof(data, "SSL read: errno %d (%s)", err, err_name);
/* print a human-readable message describing the error if available */
nss_print_error_message(data, err);
@@ -2407,7 +2435,7 @@ static bool nss_false_start(void)
}
static void *nss_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+ CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
(void)info;
@@ -2435,6 +2463,7 @@ const struct Curl_ssl Curl_ssl_nss = {
nss_cert_status_request, /* cert_status_request */
nss_connect, /* connect */
nss_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
nss_get_internals, /* get_internals */
nss_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2444,7 +2473,9 @@ const struct Curl_ssl Curl_ssl_nss = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
nss_false_start, /* false_start */
- nss_sha256sum /* sha256sum */
+ nss_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_NSS */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
index 784d9f7..87f4b02 100644
--- a/Utilities/cmcurl/lib/vtls/openssl.c
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -122,12 +122,6 @@
#define HAVE_ERR_REMOVE_THREAD_STATE 1
#endif
-#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \
- OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */
-#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */
-#define OPENSSL_NO_SSL2
-#endif
-
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
!(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)
@@ -200,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
@@ -215,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
@@ -234,6 +228,8 @@
#endif
struct ssl_backend_data {
+ struct Curl_easy *logger; /* transfer handle to pass trace logs to, only
+ using sockindex 0 */
/* these ones requires specific SSL-types */
SSL_CTX* ctx;
SSL* handle;
@@ -244,6 +240,10 @@ struct ssl_backend_data {
#endif
};
+static void ossl_associate_connection(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+
/*
* Number of bytes to read from the random number seed file. This must be
* a finite value (because some entropy "files" like /dev/urandom have
@@ -391,12 +391,23 @@ static int ossl_get_ssl_conn_index(void)
*/
static int ossl_get_ssl_sockindex_index(void)
{
- static int ssl_ex_data_sockindex_index = -1;
- if(ssl_ex_data_sockindex_index < 0) {
- ssl_ex_data_sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL,
- NULL);
+ static int sockindex_index = -1;
+ if(sockindex_index < 0) {
+ sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ }
+ return sockindex_index;
+}
+
+/* Return an extra data index for proxy boolean.
+ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
+ */
+static int ossl_get_proxy_index(void)
+{
+ static int proxy_index = -1;
+ if(proxy_index < 0) {
+ proxy_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
}
- return ssl_ex_data_sockindex_index;
+ return proxy_index;
}
static int passwd_callback(char *buf, int num, int encrypting,
@@ -424,17 +435,16 @@ static bool rand_enough(void)
static CURLcode ossl_seed(struct Curl_easy *data)
{
- /* we have the "SSL is seeded" boolean static to prevent multiple
- time-consuming seedings in vain */
- static bool ssl_seeded = FALSE;
char fname[256];
- if(ssl_seeded)
+ /* 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 */
- ssl_seeded = TRUE;
+ if(data->multi)
+ data->multi->ssl_seeded = TRUE;
return CURLE_OK;
}
@@ -507,7 +517,7 @@ static CURLcode ossl_seed(struct Curl_easy *data)
return CURLE_OK;
}
- infof(data, "libcurl is now using a weak random seed!\n");
+ infof(data, "libcurl is now using a weak random seed!");
return (rand_enough() ? CURLE_OK :
CURLE_SSL_CONNECT_ERROR /* confusing error code */);
}
@@ -587,11 +597,16 @@ static bool is_pkcs11_uri(const char *string)
static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine);
static int
-SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type,
- const char *key_passwd)
+SSL_CTX_use_certificate_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+ int type, const char *key_passwd)
{
int ret = 0;
X509 *x = NULL;
+ /* the typecast of blob->len is fine since it is guaranteed to never be
+ larger than CURL_MAX_INPUT_LENGTH */
+ BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
+ if(!in)
+ return CURLE_OUT_OF_MEMORY;
if(type == SSL_FILETYPE_ASN1) {
/* j = ERR_R_ASN1_LIB; */
@@ -607,7 +622,7 @@ SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type,
goto end;
}
- if(x == NULL) {
+ if(!x) {
ret = 0;
goto end;
}
@@ -615,15 +630,19 @@ SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type,
ret = SSL_CTX_use_certificate(ctx, x);
end:
X509_free(x);
+ BIO_free(in);
return ret;
}
static int
-SSL_CTX_use_PrivateKey_bio(SSL_CTX *ctx, BIO* in, int type,
- const char *key_passwd)
+SSL_CTX_use_PrivateKey_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+ int type, const char *key_passwd)
{
int ret = 0;
EVP_PKEY *pkey = NULL;
+ BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
+ if(!in)
+ return CURLE_OUT_OF_MEMORY;
if(type == SSL_FILETYPE_PEM)
pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback,
@@ -634,19 +653,20 @@ SSL_CTX_use_PrivateKey_bio(SSL_CTX *ctx, BIO* in, int type,
ret = 0;
goto end;
}
- if(pkey == NULL) {
+ if(!pkey) {
ret = 0;
goto end;
}
ret = SSL_CTX_use_PrivateKey(ctx, pkey);
EVP_PKEY_free(pkey);
end:
+ BIO_free(in);
return ret;
}
static int
-SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
- const char *key_passwd)
+SSL_CTX_use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob,
+ const char *key_passwd)
{
/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \
@@ -655,13 +675,16 @@ SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
int ret = 0;
X509 *x = NULL;
void *passwd_callback_userdata = (void *)key_passwd;
+ BIO *in = BIO_new_mem_buf(blob->data, (int)(blob->len));
+ if(!in)
+ return CURLE_OUT_OF_MEMORY;
ERR_clear_error();
x = PEM_read_bio_X509_AUX(in, NULL,
passwd_callback, (void *)key_passwd);
- if(x == NULL) {
+ if(!x) {
ret = 0;
goto end;
}
@@ -669,7 +692,7 @@ SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
ret = SSL_CTX_use_certificate(ctx, x);
if(ERR_peek_error() != 0)
- ret = 0;
+ ret = 0;
if(ret) {
X509 *ca;
@@ -701,10 +724,11 @@ SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
end:
X509_free(x);
+ BIO_free(in);
return ret;
#else
(void)ctx; /* unused */
- (void)in; /* unused */
+ (void)blob; /* unused */
(void)key_passwd; /* unused */
return 0;
#endif
@@ -714,10 +738,10 @@ static
int cert_stuff(struct Curl_easy *data,
SSL_CTX* ctx,
char *cert_file,
- BIO *cert_bio,
+ const struct curl_blob *cert_blob,
const char *cert_type,
char *key_file,
- BIO* key_bio,
+ const struct curl_blob *key_blob,
const char *key_type,
char *key_passwd)
{
@@ -726,7 +750,7 @@ int cert_stuff(struct Curl_easy *data,
int file_type = do_file_type(cert_type);
- if(cert_file || cert_bio || (file_type == SSL_FILETYPE_ENGINE)) {
+ if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE)) {
SSL *ssl;
X509 *x509;
int cert_done = 0;
@@ -743,9 +767,9 @@ int cert_stuff(struct Curl_easy *data,
switch(file_type) {
case SSL_FILETYPE_PEM:
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
- cert_use_result = cert_bio ?
- SSL_CTX_use_certificate_chain_bio(ctx, cert_bio, key_passwd) :
- SSL_CTX_use_certificate_chain_file(ctx, cert_file);
+ cert_use_result = cert_blob ?
+ SSL_CTX_use_certificate_chain_blob(ctx, cert_blob, key_passwd) :
+ SSL_CTX_use_certificate_chain_file(ctx, cert_file);
if(cert_use_result != 1) {
failf(data,
"could not load PEM client certificate, " OSSL_PACKAGE
@@ -762,10 +786,10 @@ int cert_stuff(struct Curl_easy *data,
we use the case above for PEM so this can only be performed with
ASN1 files. */
- cert_use_result = cert_bio ?
- SSL_CTX_use_certificate_bio(ctx, cert_bio,
- file_type, key_passwd) :
- SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
+ cert_use_result = cert_blob ?
+ SSL_CTX_use_certificate_blob(ctx, cert_blob,
+ file_type, key_passwd) :
+ SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
if(cert_use_result != 1) {
failf(data,
"could not load ASN1 client certificate, " OSSL_PACKAGE
@@ -842,13 +866,24 @@ int cert_stuff(struct Curl_easy *data,
case SSL_FILETYPE_PKCS12:
{
- BIO *fp = NULL;
+ BIO *cert_bio = NULL;
PKCS12 *p12 = NULL;
EVP_PKEY *pri;
STACK_OF(X509) *ca = NULL;
- if(!cert_bio) {
- fp = BIO_new(BIO_s_file());
- if(fp == NULL) {
+ if(cert_blob) {
+ cert_bio = BIO_new_mem_buf(cert_blob->data, (int)(cert_blob->len));
+ if(!cert_bio) {
+ failf(data,
+ "BIO_new_mem_buf NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ return 0;
+ }
+ }
+ else {
+ cert_bio = BIO_new(BIO_s_file());
+ if(!cert_bio) {
failf(data,
"BIO_new return NULL, " OSSL_PACKAGE
" error %s",
@@ -857,20 +892,19 @@ int cert_stuff(struct Curl_easy *data,
return 0;
}
- if(BIO_read_filename(fp, cert_file) <= 0) {
+ if(BIO_read_filename(cert_bio, cert_file) <= 0) {
failf(data, "could not open PKCS12 file '%s'", cert_file);
- BIO_free(fp);
+ BIO_free(cert_bio);
return 0;
}
}
- p12 = d2i_PKCS12_bio(cert_bio ? cert_bio : fp, NULL);
- if(fp)
- BIO_free(fp);
+ p12 = d2i_PKCS12_bio(cert_bio, NULL);
+ BIO_free(cert_bio);
if(!p12) {
failf(data, "error reading PKCS12 file '%s'",
- cert_bio ? "(memory blob)" : cert_file);
+ cert_blob ? "(memory blob)" : cert_file);
return 0;
}
@@ -951,9 +985,9 @@ int cert_stuff(struct Curl_easy *data,
return 0;
}
- if((!key_file) && (!key_bio)) {
+ if((!key_file) && (!key_blob)) {
key_file = cert_file;
- key_bio = cert_bio;
+ key_blob = cert_blob;
}
else
file_type = do_file_type(key_type);
@@ -964,8 +998,8 @@ int cert_stuff(struct Curl_easy *data,
break;
/* FALLTHROUGH */
case SSL_FILETYPE_ASN1:
- cert_use_result = key_bio ?
- SSL_CTX_use_PrivateKey_bio(ctx, key_bio, file_type, key_passwd) :
+ cert_use_result = key_blob ?
+ SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) :
SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
if(cert_use_result != 1) {
failf(data, "unable to set private key file: '%s' type %s",
@@ -1158,7 +1192,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 */
@@ -1172,7 +1206,7 @@ static int ossl_init(void)
/* Initialize the extra data indexes */
if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_conn_index() < 0 ||
- ossl_get_ssl_sockindex_index() < 0)
+ ossl_get_ssl_sockindex_index() < 0 || ossl_get_proxy_index() < 0)
return 0;
return 1;
@@ -1319,7 +1353,7 @@ static CURLcode ossl_set_engine_default(struct Curl_easy *data)
#ifdef USE_OPENSSL_ENGINE
if(data->state.engine) {
if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
- infof(data, "set default crypto engine '%s'\n",
+ infof(data, "set default crypto engine '%s'",
ENGINE_get_id(data->state.engine));
}
else {
@@ -1356,10 +1390,22 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
return list;
}
-static void ossl_closeone(struct ssl_connect_data *connssl)
+#define set_logger(conn, data) \
+ conn->ssl[0].backend->logger = data
+
+static void ossl_closeone(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct ssl_connect_data *connssl)
{
struct ssl_backend_data *backend = connssl->backend;
if(backend->handle) {
+ char buf[32];
+ set_logger(conn, data);
+
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
+
(void)SSL_shutdown(backend->handle);
SSL_set_connect_state(backend->handle);
@@ -1378,10 +1424,9 @@ static void ossl_closeone(struct ssl_connect_data *connssl)
static void ossl_close(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
{
- (void) data;
- ossl_closeone(&conn->ssl[sockindex]);
+ ossl_closeone(data, conn, &conn->ssl[sockindex]);
#ifndef CURL_DISABLE_PROXY
- ossl_closeone(&conn->proxy_ssl[sockindex]);
+ ossl_closeone(data, conn, &conn->proxy_ssl[sockindex]);
#endif
}
@@ -1402,6 +1447,7 @@ static int ossl_shutdown(struct Curl_easy *data,
int err;
bool done = FALSE;
struct ssl_backend_data *backend = connssl->backend;
+ int loop = 10;
#ifndef CURL_DISABLE_FTP
/* This has only been tested on the proftpd server, and the mod_tls code
@@ -1415,7 +1461,7 @@ static int ossl_shutdown(struct Curl_easy *data,
if(backend->handle) {
buffsize = (int)sizeof(buf);
- while(!done) {
+ while(!done && loop--) {
int what = SOCKET_READABLE(conn->sock[sockindex],
SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
@@ -1435,11 +1481,11 @@ static int ossl_shutdown(struct Curl_easy *data,
break;
case SSL_ERROR_WANT_READ:
/* there's data pending, re-invoke SSL_read() */
- infof(data, "SSL_ERROR_WANT_READ\n");
+ infof(data, "SSL_ERROR_WANT_READ");
break;
case SSL_ERROR_WANT_WRITE:
/* SSL wants a write. Really odd. Let's bail out. */
- infof(data, "SSL_ERROR_WANT_WRITE\n");
+ infof(data, "SSL_ERROR_WANT_WRITE");
done = TRUE;
break;
default:
@@ -1471,14 +1517,14 @@ static int ossl_shutdown(struct Curl_easy *data,
#ifdef HAVE_SSL_GET_SHUTDOWN
switch(SSL_get_shutdown(backend->handle)) {
case SSL_SENT_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
break;
case SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
+ infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN");
break;
case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
- "SSL_RECEIVED__SHUTDOWN\n");
+ "SSL_RECEIVED__SHUTDOWN");
break;
}
#endif
@@ -1545,7 +1591,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
if(Curl_cert_hostcheck(match_pattern2, hostname)) {
res = TRUE;
infof(data,
- " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+ " subjectAltName: host \"%s\" matched cert's \"%s\"",
dispname, match_pattern2);
}
}
@@ -1564,7 +1610,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
(void)data;
#endif
if(Curl_cert_hostcheck(match_pattern, hostname)) {
- infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+ infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"",
dispname, match_pattern);
return TRUE;
}
@@ -1684,7 +1730,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
ipmatched = TRUE;
infof(data,
- " subjectAltName: host \"%s\" matched cert's IP address!\n",
+ " subjectAltName: host \"%s\" matched cert's IP address!",
dispname);
}
break;
@@ -1701,7 +1747,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
/* an alternative name matched */
;
else if(dNSName || iPAddress) {
- infof(data, " subjectAltName does not match %s\n", dispname);
+ infof(data, " subjectAltName does not match %s", dispname);
failf(data, "SSL: no alternative certificate subject name matches "
"target host name '%s'", dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
@@ -1723,7 +1769,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 =
@@ -1783,7 +1829,7 @@ static CURLcode verifyhost(struct Curl_easy *data, struct connectdata *conn,
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
- infof(data, " common name: %s (matched)\n", peer_CN);
+ infof(data, " common name: %s (matched)", peer_CN);
}
if(peer_CN)
OPENSSL_free(peer_CN);
@@ -1919,7 +1965,7 @@ static CURLcode verifystatus(struct Curl_easy *data,
goto end;
}
- infof(data, "SSL certificate status: %s (%d)\n",
+ infof(data, "SSL certificate status: %s (%d)",
OCSP_cert_status_str(cert_status), cert_status);
switch(cert_status) {
@@ -2014,6 +2060,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";
@@ -2055,25 +2105,24 @@ static const char *tls_rt_type(int type)
}
}
-
/*
* Our callback from the SSL/TLS layers.
*/
-static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
- const void *buf, size_t len, SSL *ssl,
- void *userp)
+static void ossl_trace(int direction, int ssl_ver, int content_type,
+ const void *buf, size_t len, SSL *ssl,
+ void *userp)
{
- struct Curl_easy *data;
char unknown[32];
const char *verstr = NULL;
struct connectdata *conn = userp;
+ struct ssl_connect_data *connssl = &conn->ssl[0];
+ struct ssl_backend_data *backend = connssl->backend;
+ struct Curl_easy *data = backend->logger;
- if(!conn || !conn->data || !conn->data->set.fdebug ||
+ if(!conn || !data || !data->set.fdebug ||
(direction != 0 && direction != 1))
return;
- data = conn->data;
-
switch(ssl_ver) {
#ifdef SSL2_VERSION /* removed in recent versions */
case SSL2_VERSION:
@@ -2113,7 +2162,7 @@ static void ssl_tls_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
@@ -2221,12 +2270,10 @@ select_next_proto_cb(SSL *ssl,
struct connectdata *conn = data->conn;
(void)ssl;
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
- !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
- infof(data, "NPN, negotiated HTTP2 (%s)\n",
- NGHTTP2_PROTO_VERSION_ID);
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
+ !select_next_protocol(out, outlen, in, inlen, ALPN_H2, ALPN_H2_LENGTH)) {
+ infof(data, "NPN, negotiated HTTP2 (%s)", ALPN_H2);
conn->negnpn = CURL_HTTP_VERSION_2;
return SSL_TLSEXT_ERR_OK;
}
@@ -2234,12 +2281,12 @@ select_next_proto_cb(SSL *ssl,
if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1,
ALPN_HTTP_1_1_LENGTH)) {
- infof(data, "NPN, negotiated HTTP1.1\n");
+ infof(data, "NPN, negotiated HTTP1.1");
conn->negnpn = CURL_HTTP_VERSION_1_1;
return SSL_TLSEXT_ERR_OK;
}
- infof(data, "NPN, no overlap, use HTTP1.1\n");
+ infof(data, "NPN, no overlap, use HTTP1.1");
*out = (unsigned char *)ALPN_HTTP_1_1;
*outlen = ALPN_HTTP_1_1_LENGTH;
conn->negnpn = CURL_HTTP_VERSION_1_1;
@@ -2248,35 +2295,6 @@ select_next_proto_cb(SSL *ssl,
}
#endif /* HAS_NPN */
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-static const char *
-get_ssl_version_txt(SSL *ssl)
-{
- if(!ssl)
- return "";
-
- switch(SSL_version(ssl)) {
-#ifdef TLS1_3_VERSION
- case TLS1_3_VERSION:
- return "TLSv1.3";
-#endif
-#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- case TLS1_2_VERSION:
- return "TLSv1.2";
- case TLS1_1_VERSION:
- return "TLSv1.1";
-#endif
- case TLS1_VERSION:
- return "TLSv1.0";
- case SSL3_VERSION:
- return "SSLv3";
- case SSL2_VERSION:
- return "SSLv2";
- }
- return "unknown";
-}
-#endif
-
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
static CURLcode
set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn)
@@ -2285,7 +2303,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;
@@ -2315,7 +2333,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)) {
@@ -2326,7 +2344,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;
@@ -2455,8 +2473,10 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
int data_idx = ossl_get_ssl_data_index();
int connectdata_idx = ossl_get_ssl_conn_index();
int sockindex_idx = ossl_get_ssl_sockindex_index();
+ int proxy_idx = ossl_get_proxy_index();
+ bool isproxy;
- if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0)
+ if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0 || proxy_idx < 0)
return 0;
conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx);
@@ -2469,24 +2489,29 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx);
sockindex = (int)(sockindex_ptr - conn->sock);
+ isproxy = SSL_get_ex_data(ssl, proxy_idx) ? TRUE : FALSE;
+
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
void *old_ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL,
- sockindex));
+ if(isproxy)
+ incache = FALSE;
+ else
+ incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
+ &old_ssl_sessionid, NULL, sockindex));
if(incache) {
if(old_ssl_sessionid != ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing\n");
+ infof(data, "old SSL session ID is stale, removing");
Curl_ssl_delsessionid(data, old_ssl_sessionid);
incache = FALSE;
}
}
if(!incache) {
- if(!Curl_ssl_addsessionid(data, conn, ssl_sessionid,
- 0 /* unknown size */, sockindex)) {
+ if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
+ 0 /* unknown size */, sockindex)) {
/* the session has been put into the session cache */
res = 1;
}
@@ -2499,6 +2524,67 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
return res;
}
+static CURLcode load_cacert_from_memory(SSL_CTX *ctx,
+ const struct curl_blob *ca_info_blob)
+{
+ /* these need to be freed at the end */
+ BIO *cbio = NULL;
+ STACK_OF(X509_INFO) *inf = NULL;
+
+ /* everything else is just a reference */
+ int i, count = 0;
+ X509_STORE *cts = NULL;
+ X509_INFO *itmp = NULL;
+
+ if(ca_info_blob->len > (size_t)INT_MAX)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ cts = SSL_CTX_get_cert_store(ctx);
+ if(!cts)
+ return CURLE_OUT_OF_MEMORY;
+
+ cbio = BIO_new_mem_buf(ca_info_blob->data, (int)ca_info_blob->len);
+ if(!cbio)
+ return CURLE_OUT_OF_MEMORY;
+
+ inf = PEM_X509_INFO_read_bio(cbio, NULL, NULL, NULL);
+ if(!inf) {
+ BIO_free(cbio);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+
+ /* add each entry from PEM file to x509_store */
+ for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
+ itmp = sk_X509_INFO_value(inf, i);
+ if(itmp->x509) {
+ if(X509_STORE_add_cert(cts, itmp->x509)) {
+ ++count;
+ }
+ else {
+ /* set count to 0 to return an error */
+ count = 0;
+ break;
+ }
+ }
+ if(itmp->crl) {
+ if(X509_STORE_add_crl(cts, itmp->crl)) {
+ ++count;
+ }
+ else {
+ /* set count to 0 to return an error */
+ count = 0;
+ break;
+ }
+ }
+ }
+
+ sk_X509_INFO_pop_free(inf, X509_INFO_free);
+ BIO_free(cbio);
+
+ /* if we didn't end up importing anything, treat that as an error */
+ return (count > 0 ? CURLE_OK : CURLE_SSL_CACERT_BADFILE);
+}
+
static CURLcode ossl_connect_step1(struct Curl_easy *data,
struct connectdata *conn, int sockindex)
{
@@ -2509,6 +2595,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
curl_socket_t sockfd = conn->sock[sockindex];
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
ctx_option_t ctx_options = 0;
+ void *ssl_sessionid = NULL;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni;
@@ -2526,8 +2613,11 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#endif
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
+ const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
- const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : SSL_CONN_CONFIG(CAfile));
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
@@ -2562,38 +2652,17 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
use_sni(TRUE);
break;
case CURL_SSLVERSION_SSLv2:
-#ifdef OPENSSL_NO_SSL2
- failf(data, OSSL_PACKAGE " was built without SSLv2 support");
+ failf(data, "No SSLv2 support");
return CURLE_NOT_BUILT_IN;
-#else
-#ifdef USE_OPENSSL_SRP
- if(ssl_authtype == CURL_TLSAUTH_SRP)
- return CURLE_SSL_CONNECT_ERROR;
-#endif
- req_method = SSLv2_client_method();
- use_sni(FALSE);
- break;
-#endif
case CURL_SSLVERSION_SSLv3:
-#ifdef OPENSSL_NO_SSL3_METHOD
- failf(data, OSSL_PACKAGE " was built without SSLv3 support");
+ failf(data, "No SSLv3 support");
return CURLE_NOT_BUILT_IN;
-#else
-#ifdef USE_OPENSSL_SRP
- if(ssl_authtype == CURL_TLSAUTH_SRP)
- return CURLE_SSL_CONNECT_ERROR;
-#endif
- req_method = SSLv3_client_method();
- use_sni(FALSE);
- break;
-#endif
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
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) {
@@ -2609,28 +2678,29 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
- SSL_CTX_set_msg_callback(backend->ctx, ssl_tls_trace);
+ SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
SSL_CTX_set_msg_callback_arg(backend->ctx, conn);
+ set_logger(conn, 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
@@ -2666,48 +2736,16 @@ 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;
#endif
switch(ssl_version) {
- /* "--sslv2" option means SSLv2 only, disable all others */
case CURL_SSLVERSION_SSLv2:
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */
- SSL_CTX_set_min_proto_version(backend->ctx, SSL2_VERSION);
- SSL_CTX_set_max_proto_version(backend->ctx, SSL2_VERSION);
-#else
- ctx_options |= SSL_OP_NO_SSLv3;
- ctx_options |= SSL_OP_NO_TLSv1;
-# if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-# ifdef TLS1_3_VERSION
- ctx_options |= SSL_OP_NO_TLSv1_3;
-# endif
-# endif
-#endif
- break;
-
- /* "--sslv3" option means SSLv3 only, disable all others */
case CURL_SSLVERSION_SSLv3:
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */
- SSL_CTX_set_min_proto_version(backend->ctx, SSL3_VERSION);
- SSL_CTX_set_max_proto_version(backend->ctx, SSL3_VERSION);
-#else
- ctx_options |= SSL_OP_NO_SSLv2;
- ctx_options |= SSL_OP_NO_TLSv1;
-# if OPENSSL_VERSION_NUMBER >= 0x1000100FL
- ctx_options |= SSL_OP_NO_TLSv1_1;
- ctx_options |= SSL_OP_NO_TLSv1_2;
-# ifdef TLS1_3_VERSION
- ctx_options |= SSL_OP_NO_TLSv1_3;
-# endif
-# endif
-#endif
- break;
+ return CURLE_NOT_BUILT_IN;
/* "--tlsv<x.y>" options mean TLS >= version <x.y> */
case CURL_SSLVERSION_DEFAULT:
@@ -2748,60 +2786,42 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
int cur = 0;
unsigned char protocols[128];
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
#endif
) {
- protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
+ protocols[cur++] = ALPN_H2_LENGTH;
- memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN);
- cur += NGHTTP2_PROTO_VERSION_ID_LEN;
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ memcpy(&protocols[cur], ALPN_H2, ALPN_H2_LENGTH);
+ cur += ALPN_H2_LENGTH;
+ infof(data, "ALPN, offering %s", ALPN_H2);
}
#endif
protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
cur += ALPN_HTTP_1_1_LENGTH;
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
/* expects length prefixed preference ordered list of protocols in wire
* format
*/
- SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur);
+ if(SSL_CTX_set_alpn_protos(backend->ctx, protocols, cur)) {
+ failf(data, "Error setting ALPN");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
#endif
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
- BIO *ssl_cert_bio = NULL;
- BIO *ssl_key_bio = NULL;
- if(ssl_cert_blob) {
- /* the typecast of blob->len is fine since it is guaranteed to never be
- larger than CURL_MAX_INPUT_LENGTH */
- ssl_cert_bio = BIO_new_mem_buf(ssl_cert_blob->data,
- (int)ssl_cert_blob->len);
- if(!ssl_cert_bio)
- result = CURLE_OUT_OF_MEMORY;
- }
- if(!result && SSL_SET_OPTION(key_blob)) {
- ssl_key_bio = BIO_new_mem_buf(SSL_SET_OPTION(key_blob)->data,
- (int)SSL_SET_OPTION(key_blob)->len);
- if(!ssl_key_bio)
- result = CURLE_OUT_OF_MEMORY;
- }
if(!result &&
!cert_stuff(data, backend->ctx,
- ssl_cert, ssl_cert_bio, ssl_cert_type,
- SSL_SET_OPTION(key), ssl_key_bio,
+ ssl_cert, ssl_cert_blob, ssl_cert_type,
+ SSL_SET_OPTION(key), SSL_SET_OPTION(key_blob),
SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd)))
result = CURLE_SSL_CERTPROBLEM;
- if(ssl_cert_bio)
- BIO_free(ssl_cert_bio);
- if(ssl_key_bio)
- BIO_free(ssl_key_bio);
if(result)
/* failf() is already done in cert_stuff() */
return result;
@@ -2815,7 +2835,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
- infof(data, "Cipher selection: %s\n", ciphers);
+ infof(data, "Cipher selection: %s", ciphers);
}
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
@@ -2826,7 +2846,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
}
- infof(data, "TLS 1.3 cipher selection: %s\n", ciphers13);
+ infof(data, "TLS 1.3 cipher selection: %s", ciphers13);
}
}
#endif
@@ -2852,7 +2872,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if(ssl_authtype == CURL_TLSAUTH_SRP) {
char * const ssl_username = SSL_SET_OPTION(username);
- infof(data, "Using TLS-SRP username: %s\n", ssl_username);
+ infof(data, "Using TLS-SRP username: %s", ssl_username);
if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
failf(data, "Unable to set SRP user name");
@@ -2863,7 +2883,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!SSL_CONN_CONFIG(cipher_list)) {
- infof(data, "Setting cipher list SRP\n");
+ infof(data, "Setting cipher list SRP");
if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
failf(data, "failed setting SRP cipher list");
@@ -2882,8 +2902,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) &&
(SSL_SET_OPTION(native_ca_store))) {
X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
- HCERTSTORE hStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL,
- TEXT("ROOT"));
+ HCERTSTORE hStore = CertOpenSystemStore(0, TEXT("ROOT"));
if(hStore) {
PCCERT_CONTEXT pContext = NULL;
@@ -2917,7 +2936,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\"\n", cert_name);
#endif
encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
@@ -2999,7 +3018,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
OpenSSL. */
if(X509_STORE_add_cert(store, x509) == 1) {
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- infof(data, "SSL: Imported cert \"%s\"\n", cert_name);
+ infof(data, "SSL: Imported cert \"%s\"", cert_name);
#endif
imported_native_ca = true;
}
@@ -3014,12 +3033,25 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
return result;
}
if(imported_native_ca)
- infof(data, "successfully imported windows ca store\n");
+ infof(data, "successfully imported Windows CA store");
else
- infof(data, "error importing windows ca store, continuing anyway\n");
+ infof(data, "error importing Windows CA store, continuing anyway");
}
#endif
+ if(ca_info_blob) {
+ result = load_cacert_from_memory(backend->ctx, ca_info_blob);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY ||
+ (verifypeer && !imported_native_ca)) {
+ failf(data, "error importing CA certificate blob");
+ return result;
+ }
+ /* Only warn if no certificate verification is required. */
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ }
+
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
{
@@ -3030,10 +3062,10 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
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\n");
+ /* Continue with warning if certificate verification isn't required. */
+ infof(data, "error setting certificate file, continuing anyway");
}
- infof(data, " CAfile: %s\n", ssl_cafile);
+ infof(data, " CAfile: %s", ssl_cafile);
}
if(ssl_capath) {
if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
@@ -3042,16 +3074,16 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
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\n");
+ /* Continue with warning if certificate verification isn't required. */
+ infof(data, "error setting certificate path, continuing anyway");
}
- infof(data, " CApath: %s\n", ssl_capath);
+ infof(data, " CApath: %s", ssl_capath);
}
}
#else
if(ssl_cafile || ssl_capath) {
/* tell SSL where to find CA certificates that are used to verify
- the servers certificate. */
+ 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. */
@@ -3064,27 +3096,28 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
/* Just continue with a warning if no strict certificate verification
is required. */
infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
+ " continuing anyway:");
}
else {
/* Everything is fine. */
- infof(data, "successfully set certificate verify locations:\n");
+ infof(data, "successfully set certificate verify locations:");
}
- infof(data, " CAfile: %s\n", ssl_cafile ? ssl_cafile : "none");
- infof(data, " CApath: %s\n", ssl_capath ? ssl_capath : "none");
+ 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 && !ssl_cafile && !ssl_capath && !imported_native_ca) {
+ 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());
@@ -3094,11 +3127,11 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CRL_BADFILE;
}
/* Everything is fine. */
- infof(data, "successfully load CRL file:\n");
+ 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);
- infof(data, " CRLfile: %s\n", ssl_crlfile);
+ infof(data, " CRLfile: %s", ssl_crlfile);
}
if(verifypeer) {
@@ -3120,7 +3153,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);
@@ -3128,7 +3161,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. */
@@ -3143,7 +3176,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,
@@ -3162,7 +3195,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);
@@ -3202,40 +3235,27 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
data->state.buffer[nlen] = 0;
if(!SSL_set_tlsext_host_name(backend->handle, data->state.buffer))
infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension\n");
+ "TLS extension");
}
#endif
- /* Check if there's a cached ID we can/should use here! */
- if(SSL_SET_OPTION(primary.sessionid)) {
- void *ssl_sessionid = NULL;
- int data_idx = ossl_get_ssl_data_index();
- int connectdata_idx = ossl_get_ssl_conn_index();
- int sockindex_idx = ossl_get_ssl_sockindex_index();
+ ossl_associate_connection(data, conn, sockindex);
- if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0) {
- /* Store the data needed for the "new session" callback.
- * The sockindex is stored as a pointer to an array element. */
- SSL_set_ex_data(backend->handle, data_idx, data);
- SSL_set_ex_data(backend->handle, connectdata_idx, conn);
- SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex);
- }
-
- Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
- /* we got a session id, use it! */
- if(!SSL_set_session(backend->handle, ssl_sessionid)) {
- Curl_ssl_sessionid_unlock(data);
- failf(data, "SSL: SSL_set_session failed: %s",
- ossl_strerror(ERR_get_error(), error_buffer,
- sizeof(error_buffer)));
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* Informational message */
- infof(data, "SSL re-using session ID\n");
+ Curl_ssl_sessionid_lock(data);
+ if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
+ &ssl_sessionid, NULL, sockindex)) {
+ /* we got a session id, use it! */
+ if(!SSL_set_session(backend->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(data);
+ failf(data, "SSL: SSL_set_session failed: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return CURLE_SSL_CONNECT_ERROR;
}
- Curl_ssl_sessionid_unlock(data);
+ /* Informational message */
+ infof(data, "SSL re-using session ID");
}
+ Curl_ssl_sessionid_unlock(data);
#ifndef CURL_DISABLE_PROXY
if(conn->proxy_ssl[sockindex].use) {
@@ -3315,7 +3335,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();
@@ -3340,6 +3360,19 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
error_buffer */
strcpy(error_buffer, "SSL certificate verification failed");
}
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
+ !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 LibreSSL nor BoringSSL */
+ else if((lib == ERR_LIB_SSL) &&
+ (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) {
+ /* If client certificate is required, communicate the
+ error to client */
+ result = CURLE_SSL_CLIENTCERT;
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ }
+#endif
else {
result = CURLE_SSL_CONNECT_ERROR;
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
@@ -3348,16 +3381,12 @@ 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) {
const char * const hostname = SSL_HOST_NAME();
-#ifndef CURL_DISABLE_PROXY
- const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
- const long int port = conn->remote_port;
-#endif
+ const long int port = SSL_HOST_PORT();
char extramsg[80]="";
int sockerr = SOCKERRNO;
if(sockerr && detail == SSL_ERROR_SYSCALL)
@@ -3375,12 +3404,12 @@ 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 */
- infof(data, "SSL connection using %s / %s\n",
- get_ssl_version_txt(backend->handle),
+ infof(data, "SSL connection using %s / %s",
+ SSL_get_version(backend->handle),
SSL_get_cipher(backend->handle));
#ifdef HAS_ALPN
@@ -3391,12 +3420,12 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
const unsigned char *neg_protocol;
unsigned int len;
SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
- if(len != 0) {
- infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
+ if(len) {
+ infof(data, "ALPN, server accepted to use %.*s", len, neg_protocol);
-#ifdef USE_NGHTTP2
- if(len == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) {
+#ifdef USE_HTTP2
+ if(len == ALPN_H2_LENGTH &&
+ !memcmp(ALPN_H2, neg_protocol, len)) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
@@ -3407,7 +3436,7 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data,
}
}
else
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -3515,6 +3544,12 @@ typedef size_t numcert_t;
typedef int numcert_t;
#endif
+#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
+#define OSSL3_CONST const
+#else
+#define OSSL3_CONST
+#endif
+
static CURLcode get_cert_chain(struct Curl_easy *data,
struct ssl_connect_data *connssl)
{
@@ -3611,7 +3646,7 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
pubkey = X509_get_pubkey(x);
if(!pubkey)
- infof(data, " Unable to load public key\n");
+ infof(data, " Unable to load public key");
else {
int pktype;
#ifdef HAVE_OPAQUE_EVP_PKEY
@@ -3622,7 +3657,7 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
switch(pktype) {
case EVP_PKEY_RSA:
{
- RSA *rsa;
+ OSSL3_CONST RSA *rsa;
#ifdef HAVE_OPAQUE_EVP_PKEY
rsa = EVP_PKEY_get0_RSA(pubkey);
#else
@@ -3652,7 +3687,7 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
case EVP_PKEY_DSA:
{
#ifndef OPENSSL_NO_DSA
- DSA *dsa;
+ OSSL3_CONST DSA *dsa;
#ifdef HAVE_OPAQUE_EVP_PKEY
dsa = EVP_PKEY_get0_DSA(pubkey);
#else
@@ -3684,7 +3719,7 @@ static CURLcode get_cert_chain(struct Curl_easy *data,
}
case EVP_PKEY_DH:
{
- DH *dh;
+ OSSL3_CONST DH *dh;
#ifdef HAVE_OPAQUE_EVP_PKEY
dh = EVP_PKEY_get0_DH(pubkey);
#else
@@ -3788,7 +3823,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!
*
@@ -3825,23 +3860,23 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
}
- infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server");
+ infof(data, "%s certificate:", SSL_IS_PROXY() ? "Proxy" : "Server");
rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
buffer, sizeof(buffer));
- infof(data, " subject: %s\n", rc?"[NONE]":buffer);
+ infof(data, " subject: %s", rc?"[NONE]":buffer);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
long len;
ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
- infof(data, " start date: %.*s\n", len, ptr);
+ infof(data, " start date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
- infof(data, " expire date: %.*s\n", len, ptr);
+ infof(data, " expire date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
}
#endif
@@ -3865,19 +3900,19 @@ static CURLcode servercert(struct Curl_easy *data,
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
- infof(data, " issuer: %s\n", buffer);
+ infof(data, " issuer: %s", buffer);
/* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */
/* e.g. match issuer name with provided issuer certificate */
- if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) {
- if(SSL_SET_OPTION(issuercert_blob))
- fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data,
- (int)SSL_SET_OPTION(issuercert_blob)->len);
+ if(SSL_CONN_CONFIG(issuercert) || SSL_CONN_CONFIG(issuercert_blob)) {
+ if(SSL_CONN_CONFIG(issuercert_blob))
+ fp = BIO_new_mem_buf(SSL_CONN_CONFIG(issuercert_blob)->data,
+ (int)SSL_CONN_CONFIG(issuercert_blob)->len);
else {
fp = BIO_new(BIO_s_file());
- if(fp == NULL) {
+ if(!fp) {
failf(data,
"BIO_new return NULL, " OSSL_PACKAGE
" error %s",
@@ -3888,10 +3923,10 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
- if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
+ if(BIO_read_filename(fp, SSL_CONN_CONFIG(issuercert)) <= 0) {
if(strict)
failf(data, "SSL: Unable to open issuer cert (%s)",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(backend->server_cert);
backend->server_cert = NULL;
@@ -3903,7 +3938,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(!issuer) {
if(strict)
failf(data, "SSL: Unable to read issuer cert (%s)",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3914,7 +3949,7 @@ static CURLcode servercert(struct Curl_easy *data,
if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
- SSL_SET_OPTION(issuercert));
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(issuer);
X509_free(backend->server_cert);
@@ -3922,8 +3957,8 @@ static CURLcode servercert(struct Curl_easy *data,
return CURLE_SSL_ISSUER_ERROR;
}
- infof(data, " SSL certificate issuer check ok (%s)\n",
- SSL_SET_OPTION(issuercert));
+ infof(data, " SSL certificate issuer check ok (%s)",
+ SSL_CONN_CONFIG(issuercert));
BIO_free(fp);
X509_free(issuer);
}
@@ -3941,11 +3976,11 @@ static CURLcode servercert(struct Curl_easy *data,
}
else
infof(data, " SSL certificate verify result: %s (%ld),"
- " continuing anyway.\n",
+ " continuing anyway.",
X509_verify_cert_error_string(lerr), lerr);
}
else
- infof(data, " SSL certificate verify ok.\n");
+ infof(data, " SSL certificate verify ok.");
}
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
@@ -3964,8 +3999,7 @@ static CURLcode servercert(struct Curl_easy *data,
/* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
- ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ ptr = SSL_PINNED_PUB_KEY();
if(!result && ptr) {
result = pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
if(result)
@@ -3990,7 +4024,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.
*/
@@ -4028,7 +4062,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;
}
@@ -4176,6 +4210,7 @@ static ssize_t ossl_send(struct Curl_easy *data,
ERR_clear_error();
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+ set_logger(conn, data);
rc = SSL_write(backend->handle, mem, memlen);
if(rc <= 0) {
@@ -4218,7 +4253,7 @@ static ssize_t ossl_send(struct Curl_easy *data,
#endif
) {
char ver[120];
- ossl_version(ver, 120);
+ (void)ossl_version(ver, sizeof(ver));
failf(data, "Error: %s does not support double SSL tunneling.", ver);
}
else
@@ -4254,6 +4289,7 @@ static ssize_t ossl_recv(struct Curl_easy *data, /* transfer */
ERR_clear_error();
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ set_logger(conn, data);
nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
@@ -4453,10 +4489,82 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
(void *)backend->ctx : (void *)backend->handle;
}
+static void ossl_associate_connection(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
+
+ /* If we don't have SSL context, do nothing. */
+ if(!backend->handle)
+ return;
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ int data_idx = ossl_get_ssl_data_index();
+ int connectdata_idx = ossl_get_ssl_conn_index();
+ int sockindex_idx = ossl_get_ssl_sockindex_index();
+ int proxy_idx = ossl_get_proxy_index();
+
+ if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
+ proxy_idx >= 0) {
+ /* Store the data needed for the "new session" callback.
+ * The sockindex is stored as a pointer to an array element. */
+ SSL_set_ex_data(backend->handle, data_idx, data);
+ SSL_set_ex_data(backend->handle, connectdata_idx, conn);
+ SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex);
+#ifndef CURL_DISABLE_PROXY
+ SSL_set_ex_data(backend->handle, proxy_idx, SSL_IS_PROXY() ? (void *) 1:
+ NULL);
+#else
+ SSL_set_ex_data(backend->handle, proxy_idx, NULL);
+#endif
+ }
+ }
+}
+
+/*
+ * Starting with TLS 1.3, the ossl_new_session_cb callback gets called after
+ * the handshake. If the transfer that sets up the callback gets killed before
+ * this callback arrives, we must make sure to properly clear the data to
+ * avoid UAF problems. A future optimization could be to instead store another
+ * transfer that might still be using the same connection.
+ */
+
+static void ossl_disassociate_connection(struct Curl_easy *data,
+ int sockindex)
+{
+ struct connectdata *conn = data->conn;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
+
+ /* If we don't have SSL context, do nothing. */
+ if(!backend->handle)
+ return;
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ int data_idx = ossl_get_ssl_data_index();
+ int connectdata_idx = ossl_get_ssl_conn_index();
+ int sockindex_idx = ossl_get_ssl_sockindex_index();
+ int proxy_idx = ossl_get_proxy_index();
+
+ if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 &&
+ proxy_idx >= 0) {
+ /* Disable references to data in "new session" callback to avoid
+ * accessing a stale pointer. */
+ SSL_set_ex_data(backend->handle, data_idx, NULL);
+ SSL_set_ex_data(backend->handle, connectdata_idx, NULL);
+ SSL_set_ex_data(backend->handle, sockindex_idx, NULL);
+ SSL_set_ex_data(backend->handle, proxy_idx, NULL);
+ }
+ }
+}
+
const struct Curl_ssl Curl_ssl_openssl = {
{ CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */
SSLSUPP_CA_PATH |
+ SSLSUPP_CAINFO_BLOB |
SSLSUPP_CERTINFO |
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_SSL_CTX |
@@ -4477,6 +4585,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_cert_status_request, /* cert_status_request */
ossl_connect, /* connect */
ossl_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
@@ -4486,10 +4595,12 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
- ossl_sha256sum /* sha256sum */
+ ossl_sha256sum, /* sha256sum */
#else
- NULL /* sha256sum */
+ NULL, /* sha256sum */
#endif
+ ossl_associate_connection, /* associate_connection */
+ ossl_disassociate_connection /* disassociate_connection */
};
#endif /* USE_OPENSSL */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c
new file mode 100644
index 0000000..2ac97ce
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/rustls.c
@@ -0,0 +1,575 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020 - 2021, Jacob Hoffman-Andrews,
+ * <github@hoffman-andrews.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_RUSTLS
+
+#include "curl_printf.h"
+
+#include <errno.h>
+#include <crustls.h>
+
+#include "inet_pton.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "vtls.h"
+#include "select.h"
+#include "strerror.h"
+#include "multiif.h"
+
+struct ssl_backend_data
+{
+ const struct rustls_client_config *config;
+ struct rustls_connection *conn;
+ bool data_pending;
+};
+
+/* For a given rustls_result error code, return the best-matching CURLcode. */
+static CURLcode map_error(rustls_result r)
+{
+ if(rustls_result_is_cert_error(r)) {
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ switch(r) {
+ case RUSTLS_RESULT_OK:
+ return CURLE_OK;
+ case RUSTLS_RESULT_NULL_PARAMETER:
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ default:
+ return CURLE_READ_ERROR;
+ }
+}
+
+static bool
+cr_data_pending(const struct connectdata *conn, int sockindex)
+{
+ const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
+ return backend->data_pending;
+}
+
+static CURLcode
+cr_connect(struct Curl_easy *data UNUSED_PARAM,
+ struct connectdata *conn UNUSED_PARAM,
+ int sockindex UNUSED_PARAM)
+{
+ infof(data, "rustls_connect: unimplemented");
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+static int
+read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
+{
+ ssize_t n = sread(*(int *)userdata, buf, len);
+ if(n < 0) {
+ return SOCKERRNO;
+ }
+ *out_n = n;
+ return 0;
+}
+
+static int
+write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
+{
+ ssize_t n = swrite(*(int *)userdata, buf, len);
+ if(n < 0) {
+ return SOCKERRNO;
+ }
+ *out_n = n;
+ return 0;
+}
+
+/*
+ * On each run:
+ * - Read a chunk of bytes from the socket into rustls' TLS input buffer.
+ * - Tell rustls to process any new packets.
+ * - Read out as many plaintext bytes from rustls as possible, until hitting
+ * error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
+ *
+ * It's okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it will copy bytes from the socket into rustls' TLS input
+ * buffer, and process packets, but won't consume bytes from rustls' plaintext
+ * output buffer.
+ */
+static ssize_t
+cr_recv(struct Curl_easy *data, int sockindex,
+ char *plainbuf, size_t plainlen, CURLcode *err)
+{
+ struct connectdata *conn = data->conn;
+ struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *const backend = connssl->backend;
+ struct rustls_connection *const rconn = backend->conn;
+ size_t n = 0;
+ size_t tls_bytes_read = 0;
+ size_t plain_bytes_copied = 0;
+ rustls_result rresult = 0;
+ char errorbuf[255];
+ rustls_io_result io_error;
+
+ io_error = rustls_connection_read_tls(rconn, read_cb,
+ &conn->sock[sockindex], &tls_bytes_read);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ infof(data, "sread: EAGAIN or EWOULDBLOCK");
+ }
+ else if(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;
+ }
+ else if(tls_bytes_read == 0) {
+ failf(data, "connection closed without TLS close_notify alert");
+ *err = CURLE_READ_ERROR;
+ return -1;
+ }
+
+ infof(data, "cr_recv read %ld bytes from the network", tls_bytes_read);
+
+ rresult = rustls_connection_process_new_packets(rconn);
+ if(rresult != RUSTLS_RESULT_OK) {
+ rustls_error(rresult, errorbuf, sizeof(errorbuf), &n);
+ failf(data, "%.*s", n, errorbuf);
+ *err = map_error(rresult);
+ return -1;
+ }
+
+ backend->data_pending = TRUE;
+
+ while(plain_bytes_copied < plainlen) {
+ rresult = rustls_connection_read(rconn,
+ (uint8_t *)plainbuf + plain_bytes_copied,
+ plainlen - plain_bytes_copied,
+ &n);
+ if(rresult == RUSTLS_RESULT_ALERT_CLOSE_NOTIFY) {
+ *err = CURLE_OK;
+ return 0;
+ }
+ else if(rresult != RUSTLS_RESULT_OK) {
+ failf(data, "error in rustls_connection_read");
+ *err = CURLE_READ_ERROR;
+ return -1;
+ }
+ else if(n == 0) {
+ /* rustls returns 0 from connection_read to mean "all currently
+ available data has been read." If we bring in more ciphertext with
+ read_tls, more plaintext will become available. So don't tell curl
+ this is an EOF. Instead, say "come back later." */
+ infof(data, "cr_recv got 0 bytes of plaintext");
+ backend->data_pending = FALSE;
+ break;
+ }
+ else {
+ infof(data, "cr_recv copied out %ld bytes of plaintext", n);
+ plain_bytes_copied += n;
+ }
+ }
+
+ /* If we wrote out 0 plaintext bytes, it might just mean we haven't yet
+ read a full TLS record. Return CURLE_AGAIN so curl doesn't treat this
+ as EOF. */
+ if(plain_bytes_copied == 0) {
+ *err = CURLE_AGAIN;
+ return -1;
+ }
+
+ return plain_bytes_copied;
+}
+
+/*
+ * On each call:
+ * - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
+ * - Fully drain rustls' plaintext output buffer into the socket until
+ * we get either an error or EAGAIN/EWOULDBLOCK.
+ *
+ * It's okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it won't read anything into rustls' plaintext input buffer.
+ * It will only drain rustls' plaintext output buffer into the socket.
+ */
+static ssize_t
+cr_send(struct Curl_easy *data, int sockindex,
+ const void *plainbuf, size_t plainlen, CURLcode *err)
+{
+ struct connectdata *conn = data->conn;
+ struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *const backend = connssl->backend;
+ struct rustls_connection *const rconn = backend->conn;
+ size_t plainwritten = 0;
+ size_t tlswritten = 0;
+ size_t tlswritten_total = 0;
+ rustls_result rresult;
+ rustls_io_result io_error;
+
+ infof(data, "cr_send %ld bytes of plaintext", plainlen);
+
+ if(plainlen > 0) {
+ rresult = rustls_connection_write(rconn, plainbuf, plainlen,
+ &plainwritten);
+ if(rresult != RUSTLS_RESULT_OK) {
+ failf(data, "error in rustls_connection_write");
+ *err = CURLE_WRITE_ERROR;
+ return -1;
+ }
+ else if(plainwritten == 0) {
+ failf(data, "EOF in rustls_connection_write");
+ *err = CURLE_WRITE_ERROR;
+ return -1;
+ }
+ }
+
+ while(rustls_connection_wants_write(rconn)) {
+ io_error = rustls_connection_write_tls(rconn, write_cb,
+ &conn->sock[sockindex], &tlswritten);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ infof(data, "swrite: EAGAIN after %ld bytes", tlswritten_total);
+ *err = CURLE_AGAIN;
+ return -1;
+ }
+ else if(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;
+ }
+ if(tlswritten == 0) {
+ failf(data, "EOF in swrite");
+ *err = CURLE_WRITE_ERROR;
+ return -1;
+ }
+ infof(data, "cr_send wrote %ld bytes to network", tlswritten);
+ tlswritten_total += tlswritten;
+ }
+
+ return plainwritten;
+}
+
+/* A server certificate verify callback for rustls that always returns
+ RUSTLS_RESULT_OK, or in other words disable certificate verification. */
+static enum rustls_result
+cr_verify_none(void *userdata UNUSED_PARAM,
+ const rustls_verify_server_cert_params *params UNUSED_PARAM)
+{
+ return RUSTLS_RESULT_OK;
+}
+
+static bool
+cr_hostname_is_ip(const char *hostname)
+{
+ struct in_addr in;
+#ifdef ENABLE_IPV6
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+ return true;
+ }
+#endif /* ENABLE_IPV6 */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ return true;
+ }
+ return false;
+}
+
+static CURLcode
+cr_init_backend(struct Curl_easy *data, struct connectdata *conn,
+ struct ssl_backend_data *const backend)
+{
+ struct rustls_connection *rconn = backend->conn;
+ struct rustls_client_config_builder *config_builder = NULL;
+ const char *const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char *hostname = conn->host.name;
+ char errorbuf[256];
+ size_t errorlen;
+ int result;
+ rustls_slice_bytes alpn[2] = {
+ { (const uint8_t *)ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH },
+ { (const uint8_t *)ALPN_H2, ALPN_H2_LENGTH },
+ };
+
+ config_builder = rustls_client_config_builder_new();
+#ifdef USE_HTTP2
+ infof(data, "offering ALPN for HTTP/1.1 and HTTP/2");
+ rustls_client_config_builder_set_protocols(config_builder, alpn, 2);
+#else
+ infof(data, "offering ALPN for HTTP/1.1 only");
+ rustls_client_config_builder_set_protocols(config_builder, alpn, 1);
+#endif
+ if(!verifypeer) {
+ rustls_client_config_builder_dangerous_set_certificate_verifier(
+ config_builder, cr_verify_none);
+ /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
+ * connections created with an IP address, even when certificate
+ * verification is turned off. Set a placeholder hostname and disable
+ * SNI. */
+ if(cr_hostname_is_ip(hostname)) {
+ rustls_client_config_builder_set_enable_sni(config_builder, false);
+ hostname = "example.invalid";
+ }
+ }
+ else if(ssl_cafile) {
+ result = rustls_client_config_builder_load_roots_from_file(
+ config_builder, ssl_cafile);
+ if(result != RUSTLS_RESULT_OK) {
+ failf(data, "failed to load trusted certificates");
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ backend->config = rustls_client_config_builder_build(config_builder);
+ DEBUGASSERT(rconn == NULL);
+ result = rustls_client_connection_new(backend->config, hostname, &rconn);
+ if(result != RUSTLS_RESULT_OK) {
+ rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
+ failf(data, "rustls_client_connection_new: %.*s", errorlen, errorbuf);
+ return CURLE_COULDNT_CONNECT;
+ }
+ rustls_connection_set_userdata(rconn, backend);
+ backend->conn = rconn;
+ return CURLE_OK;
+}
+
+static void
+cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn,
+ const struct rustls_connection *rconn)
+{
+ const uint8_t *protocol = NULL;
+ size_t len = 0;
+
+ rustls_connection_get_alpn_protocol(rconn, &protocol, &len);
+ if(NULL == protocol) {
+ infof(data, "ALPN, server did not agree to a protocol");
+ return;
+ }
+
+#ifdef USE_HTTP2
+ if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) {
+ infof(data, "ALPN, negotiated h2");
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(len == ALPN_HTTP_1_1_LENGTH &&
+ 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) {
+ infof(data, "ALPN, negotiated http/1.1");
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ else {
+ infof(data, "ALPN, negotiated an unrecognized protocol");
+ }
+
+ Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+}
+
+static CURLcode
+cr_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
+ int sockindex, bool *done)
+{
+ struct ssl_connect_data *const connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_backend_data *const backend = connssl->backend;
+ struct rustls_connection *rconn = NULL;
+ CURLcode tmperr = CURLE_OK;
+ int result;
+ int what;
+ bool wants_read;
+ bool wants_write;
+ curl_socket_t writefd;
+ curl_socket_t readfd;
+
+ if(ssl_connection_none == connssl->state) {
+ result = cr_init_backend(data, conn, connssl->backend);
+ if(result != CURLE_OK) {
+ return result;
+ }
+ connssl->state = ssl_connection_negotiating;
+ }
+
+ rconn = backend->conn;
+
+ /* Read/write data until the handshake is done or the socket would block. */
+ for(;;) {
+ /*
+ * Connection has been established according to rustls. Set send/recv
+ * handlers, and update the state machine.
+ * This check has to come last because is_handshaking starts out false,
+ * then becomes true when we first write data, then becomes false again
+ * once the handshake is done.
+ */
+ if(!rustls_connection_is_handshaking(rconn)) {
+ infof(data, "Done handshaking");
+ /* Done with the handshake. Set up callbacks to send/receive data. */
+ connssl->state = ssl_connection_complete;
+
+ cr_set_negotiated_alpn(data, conn, rconn);
+
+ conn->recv[sockindex] = cr_recv;
+ conn->send[sockindex] = cr_send;
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ wants_read = rustls_connection_wants_read(rconn);
+ wants_write = rustls_connection_wants_write(rconn);
+ DEBUGASSERT(wants_read || wants_write);
+ writefd = wants_write?sockfd:CURL_SOCKET_BAD;
+ readfd = wants_read?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, 0);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(0 == what) {
+ infof(data, "Curl_socket_check: %s would block",
+ wants_read&&wants_write ? "writing and reading" :
+ wants_write ? "writing" : "reading");
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ /* socket is readable or writable */
+
+ if(wants_write) {
+ infof(data, "rustls_connection wants us to write_tls.");
+ cr_send(data, sockindex, NULL, 0, &tmperr);
+ if(tmperr == CURLE_AGAIN) {
+ infof(data, "writing would block");
+ /* fall through */
+ }
+ else if(tmperr != CURLE_OK) {
+ return tmperr;
+ }
+ }
+
+ if(wants_read) {
+ infof(data, "rustls_connection wants us to read_tls.");
+
+ cr_recv(data, sockindex, NULL, 0, &tmperr);
+ if(tmperr == CURLE_AGAIN) {
+ infof(data, "reading would block");
+ /* fall through */
+ }
+ else if(tmperr != CURLE_OK) {
+ if(tmperr == CURLE_READ_ERROR) {
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ return tmperr;
+ }
+ }
+ }
+ }
+
+ /* We should never fall through the loop. We should return either because
+ the handshake is done or because we can't read/write without blocking. */
+ DEBUGASSERT(false);
+}
+
+/* returns a bitmap of flags for this connection's first socket indicating
+ whether we want to read or write */
+static int
+cr_getsock(struct connectdata *conn, curl_socket_t *socks)
+{
+ struct ssl_connect_data *const connssl = &conn->ssl[FIRSTSOCKET];
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ struct ssl_backend_data *const backend = connssl->backend;
+ struct rustls_connection *rconn = backend->conn;
+
+ if(rustls_connection_wants_write(rconn)) {
+ socks[0] = sockfd;
+ return GETSOCK_WRITESOCK(0);
+ }
+ if(rustls_connection_wants_read(rconn)) {
+ socks[0] = sockfd;
+ return GETSOCK_READSOCK(0);
+ }
+
+ return GETSOCK_BLANK;
+}
+
+static void *
+cr_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
+{
+ struct ssl_backend_data *backend = connssl->backend;
+ return &backend->conn;
+}
+
+static void
+cr_close(struct Curl_easy *data, struct connectdata *conn,
+ int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_backend_data *backend = connssl->backend;
+ CURLcode tmperr = CURLE_OK;
+ ssize_t n = 0;
+
+ if(backend->conn) {
+ rustls_connection_send_close_notify(backend->conn);
+ n = cr_send(data, sockindex, NULL, 0, &tmperr);
+ if(n < 0) {
+ failf(data, "error sending close notify: %d", tmperr);
+ }
+
+ rustls_connection_free(backend->conn);
+ backend->conn = NULL;
+ }
+ if(backend->config) {
+ rustls_client_config_free(backend->config);
+ backend->config = NULL;
+ }
+}
+
+const struct Curl_ssl Curl_ssl_rustls = {
+ { CURLSSLBACKEND_RUSTLS, "rustls" },
+ SSLSUPP_TLS13_CIPHERSUITES, /* supports */
+ sizeof(struct ssl_backend_data),
+
+ Curl_none_init, /* init */
+ Curl_none_cleanup, /* cleanup */
+ rustls_version, /* version */
+ Curl_none_check_cxn, /* check_cxn */
+ Curl_none_shutdown, /* shutdown */
+ cr_data_pending, /* data_pending */
+ Curl_none_random, /* random */
+ Curl_none_cert_status_request, /* cert_status_request */
+ cr_connect, /* connect */
+ cr_connect_nonblocking, /* connect_nonblocking */
+ cr_getsock, /* cr_getsock */
+ cr_get_internals, /* get_internals */
+ cr_close, /* close_one */
+ Curl_none_close_all, /* close_all */
+ Curl_none_session_free, /* session_free */
+ Curl_none_set_engine, /* set_engine */
+ Curl_none_set_engine_default, /* set_engine_default */
+ Curl_none_engines_list, /* engines_list */
+ Curl_none_false_start, /* false_start */
+ NULL, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
+};
+
+#endif /* USE_RUSTLS */
diff --git a/Utilities/cmcurl/lib/vtls/rustls.h b/Utilities/cmcurl/lib/vtls/rustls.h
new file mode 100644
index 0000000..056211d
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/rustls.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020 - 2021, Jacob Hoffman-Andrews,
+ * <github@hoffman-andrews.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifndef HEADER_CURL_RUSTLS_H
+#define HEADER_CURL_RUSTLS_H
+
+#include "curl_setup.h"
+
+#ifdef USE_RUSTLS
+
+extern const struct Curl_ssl Curl_ssl_rustls;
+
+#endif /* USE_RUSTLS */
+#endif /* HEADER_CURL_RUSTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
index 0668f98..722a937 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.c
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -117,6 +117,10 @@
#define SP_PROT_TLS1_2_CLIENT 0x00000800
#endif
+#ifndef SCH_USE_STRONG_CRYPTO
+#define SCH_USE_STRONG_CRYPTO 0x00400000
+#endif
+
#ifndef SECBUFFER_ALERT
#define SECBUFFER_ALERT 17
#endif
@@ -137,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;
@@ -275,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
@@ -324,17 +328,22 @@ get_alg_id_by_name(char *name)
}
static CURLcode
-set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
+set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
+ ALG_ID *algIds)
{
char *startCur = ciphers;
int algCount = 0;
- static ALG_ID algIds[45]; /*There are 45 listed in the MS headers*/
- while(startCur && (0 != *startCur) && (algCount < 45)) {
+ while(startCur && (0 != *startCur) && (algCount < NUMOF_CIPHERS)) {
long alg = strtol(startCur, 0, 0);
if(!alg)
alg = get_alg_id_by_name(startCur);
if(alg)
algIds[algCount++] = alg;
+ else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
+ sizeof("USE_STRONG_CRYPTO") - 1) ||
+ !strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
+ sizeof("SCH_USE_STRONG_CRYPTO") - 1))
+ schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO;
else
return CURLE_SSL_CIPHER;
startCur = strchr(startCur, ':');
@@ -358,28 +367,28 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
size_t store_name_len;
sep = _tcschr(path, TEXT('\\'));
- if(sep == NULL)
+ if(!sep)
return CURLE_SSL_CERTPROBLEM;
store_name_len = sep - path;
- if(_tcsnccmp(path, TEXT("CurrentUser"), store_name_len) == 0)
+ if(_tcsncmp(path, TEXT("CurrentUser"), store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_CURRENT_USER;
- else if(_tcsnccmp(path, TEXT("LocalMachine"), store_name_len) == 0)
+ else if(_tcsncmp(path, TEXT("LocalMachine"), store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE;
- else if(_tcsnccmp(path, TEXT("CurrentService"), store_name_len) == 0)
+ else if(_tcsncmp(path, TEXT("CurrentService"), store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_CURRENT_SERVICE;
- else if(_tcsnccmp(path, TEXT("Services"), store_name_len) == 0)
+ else if(_tcsncmp(path, TEXT("Services"), store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_SERVICES;
- else if(_tcsnccmp(path, TEXT("Users"), store_name_len) == 0)
+ else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_USERS;
- else if(_tcsnccmp(path, TEXT("CurrentUserGroupPolicy"),
+ else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"),
store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY;
- else if(_tcsnccmp(path, TEXT("LocalMachineGroupPolicy"),
+ else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"),
store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY;
- else if(_tcsnccmp(path, TEXT("LocalMachineEnterprise"),
+ else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"),
store_name_len) == 0)
*store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE;
else
@@ -388,7 +397,7 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
store_path_start = sep + 1;
sep = _tcschr(store_path_start, TEXT('\\'));
- if(sep == NULL)
+ if(!sep)
return CURLE_SSL_CERTPROBLEM;
*thumbprint = sep + 1;
@@ -398,12 +407,347 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
*sep = TEXT('\0');
*store_path = _tcsdup(store_path_start);
*sep = TEXT('\\');
- if(*store_path == NULL)
+ if(!*store_path)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
}
#endif
+static CURLcode
+schannel_acquire_credential_handle(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SCHANNEL_CRED schannel_cred;
+ PCCERT_CONTEXT client_certs[1] = { NULL };
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ CURLcode result;
+
+ /* setup Schannel API options */
+ memset(&schannel_cred, 0, sizeof(schannel_cred));
+ schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+
+ if(conn->ssl_config.verifypeer) {
+#ifdef HAS_MANUAL_VERIFY_API
+ if(BACKEND->use_manual_cred_validation)
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
+ else
+#endif
+ schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+
+ if(SSL_SET_OPTION(no_revoke)) {
+ schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+
+ DEBUGF(infof(data, "schannel: disabled server certificate revocation "
+ "checks"));
+ }
+ else if(SSL_SET_OPTION(revoke_best_effort)) {
+ schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+ DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
+ }
+ else {
+ schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
+
+ DEBUGF(infof(data,
+ "schannel: checking server certificate revocation"));
+ }
+ }
+ else {
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+ SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+ DEBUGF(infof(data,
+ "schannel: disabled server cert revocation checks"));
+ }
+
+ if(!conn->ssl_config.verifyhost) {
+ schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+ DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
+ "comparing the supplied target name with the subject "
+ "names in server certificates."));
+ }
+
+ if(!SSL_SET_OPTION(auto_client_cert)) {
+ schannel_cred.dwFlags &= ~SCH_CRED_USE_DEFAULT_CREDS;
+ schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
+ infof(data, "schannel: disabled automatic use of client certificate");
+ }
+ else
+ infof(data, "schannel: enabled automatic use of client certificate");
+
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ result = set_ssl_version_min_max(&schannel_cred, data, conn);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv3:
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(SSL_CONN_CONFIG(cipher_list)) {
+ result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list),
+ BACKEND->algIds);
+ if(CURLE_OK != result) {
+ failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
+ return result;
+ }
+ }
+
+
+#ifdef HAS_CLIENT_CERT_PATH
+ /* client certificate */
+ if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
+ DWORD cert_store_name = 0;
+ TCHAR *cert_store_path = NULL;
+ TCHAR *cert_thumbprint_str = NULL;
+ CRYPT_HASH_BLOB cert_thumbprint;
+ BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
+ HCERTSTORE cert_store = NULL;
+ FILE *fInCert = NULL;
+ void *certdata = NULL;
+ size_t certsize = 0;
+ bool blob = data->set.ssl.primary.cert_blob != NULL;
+ TCHAR *cert_path = NULL;
+ if(blob) {
+ certdata = data->set.ssl.primary.cert_blob->data;
+ certsize = data->set.ssl.primary.cert_blob->len;
+ }
+ else {
+ cert_path = curlx_convert_UTF8_to_tchar(
+ data->set.ssl.primary.clientcert);
+ if(!cert_path)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = get_cert_location(cert_path, &cert_store_name,
+ &cert_store_path, &cert_thumbprint_str);
+
+ if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
+ fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
+
+ if(result && !fInCert) {
+ failf(data, "schannel: Failed to get certificate location"
+ " or file for %s",
+ data->set.ssl.primary.clientcert);
+ curlx_unicodefree(cert_path);
+ return result;
+ }
+ }
+
+ if((fInCert || blob) && (data->set.ssl.cert_type) &&
+ (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
+ failf(data, "schannel: certificate format compatibility error "
+ " for %s",
+ blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
+ curlx_unicodefree(cert_path);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ if(fInCert || blob) {
+ /* Reading a .P12 or .pfx file, like the example at bottom of
+ https://social.msdn.microsoft.com/Forums/windowsdesktop/
+ en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
+ */
+ CRYPT_DATA_BLOB datablob;
+ WCHAR* pszPassword;
+ size_t pwd_len = 0;
+ int str_w_len = 0;
+ const char *cert_showfilename_error = blob ?
+ "(memory blob)" : data->set.ssl.primary.clientcert;
+ curlx_unicodefree(cert_path);
+ if(fInCert) {
+ long cert_tell = 0;
+ bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
+ if(continue_reading)
+ cert_tell = ftell(fInCert);
+ if(cert_tell < 0)
+ continue_reading = FALSE;
+ else
+ certsize = (size_t)cert_tell;
+ if(continue_reading)
+ continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
+ if(continue_reading)
+ certdata = malloc(certsize + 1);
+ if((!certdata) ||
+ ((int) fread(certdata, certsize, 1, fInCert) != 1))
+ continue_reading = FALSE;
+ fclose(fInCert);
+ if(!continue_reading) {
+ failf(data, "schannel: Failed to read cert file %s",
+ data->set.ssl.primary.clientcert);
+ free(certdata);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Convert key-pair data to the in-memory certificate store */
+ datablob.pbData = (BYTE*)certdata;
+ datablob.cbData = (DWORD)certsize;
+
+ if(data->set.ssl.key_passwd != NULL)
+ pwd_len = strlen(data->set.ssl.key_passwd);
+ pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
+ if(pszPassword) {
+ if(pwd_len > 0)
+ str_w_len = MultiByteToWideChar(CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ data->set.ssl.key_passwd, (int)pwd_len,
+ pszPassword, (int)(pwd_len + 1));
+
+ if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
+ pszPassword[str_w_len] = 0;
+ else
+ pszPassword[0] = 0;
+
+ cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
+ free(pszPassword);
+ }
+ if(!blob)
+ free(certdata);
+ if(!cert_store) {
+ DWORD errorcode = GetLastError();
+ if(errorcode == ERROR_INVALID_PASSWORD)
+ failf(data, "schannel: Failed to import cert file %s, "
+ "password is bad",
+ cert_showfilename_error);
+ else
+ failf(data, "schannel: Failed to import cert file %s, "
+ "last error is 0x%x",
+ cert_showfilename_error, errorcode);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ client_certs[0] = CertFindCertificateInStore(
+ cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+ CERT_FIND_ANY, NULL, NULL);
+
+ if(!client_certs[0]) {
+ failf(data, "schannel: Failed to get certificate from file %s"
+ ", last error is 0x%x",
+ cert_showfilename_error, GetLastError());
+ CertCloseStore(cert_store, 0);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ schannel_cred.cCreds = 1;
+ schannel_cred.paCred = client_certs;
+ }
+ else {
+ cert_store =
+ CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
+ (HCRYPTPROV)NULL,
+ CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
+ cert_store_path);
+ if(!cert_store) {
+ failf(data, "schannel: Failed to open cert store %x %s, "
+ "last error is 0x%x",
+ cert_store_name, cert_store_path, GetLastError());
+ free(cert_store_path);
+ curlx_unicodefree(cert_path);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ free(cert_store_path);
+
+ cert_thumbprint.pbData = cert_thumbprint_data;
+ cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
+
+ if(!CryptStringToBinary(cert_thumbprint_str,
+ CERT_THUMBPRINT_STR_LEN,
+ CRYPT_STRING_HEX,
+ cert_thumbprint_data,
+ &cert_thumbprint.cbData,
+ NULL, NULL)) {
+ curlx_unicodefree(cert_path);
+ CertCloseStore(cert_store, 0);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ client_certs[0] = CertFindCertificateInStore(
+ cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+ CERT_FIND_HASH, &cert_thumbprint, NULL);
+
+ curlx_unicodefree(cert_path);
+
+ if(client_certs[0]) {
+ schannel_cred.cCreds = 1;
+ schannel_cred.paCred = client_certs;
+ }
+ else {
+ /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
+ CertCloseStore(cert_store, 0);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+ CertCloseStore(cert_store, 0);
+ }
+#else
+ if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
+ failf(data, "schannel: client cert support not built in");
+ return CURLE_NOT_BUILT_IN;
+ }
+#endif
+
+ /* allocate memory for the re-usable credential handle */
+ BACKEND->cred = (struct Curl_schannel_cred *)
+ calloc(1, sizeof(struct Curl_schannel_cred));
+ if(!BACKEND->cred) {
+ failf(data, "schannel: unable to allocate memory");
+
+ if(client_certs[0])
+ CertFreeCertificateContext(client_certs[0]);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ 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,
+ &schannel_cred, NULL, NULL,
+ &BACKEND->cred->cred_handle,
+ &BACKEND->cred->time_stamp);
+
+ if(client_certs[0])
+ CertFreeCertificateContext(client_certs[0]);
+
+ if(sspi_status != SEC_E_OK) {
+ char buffer[STRERROR_LEN];
+ failf(data, "schannel: AcquireCredentialsHandle failed: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ Curl_safefree(BACKEND->cred);
+ switch(sspi_status) {
+ case SEC_E_INSUFFICIENT_MEMORY:
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_NO_CREDENTIALS:
+ case SEC_E_SECPKG_NOT_FOUND:
+ case SEC_E_NOT_OWNER:
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ case SEC_E_INTERNAL_ERROR:
+ default:
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ return CURLE_OK;
+}
static CURLcode
schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
@@ -418,8 +762,6 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAS_ALPN
unsigned char alpn_buffer[128];
#endif
- SCHANNEL_CRED schannel_cred;
- PCCERT_CONTEXT client_certs[1] = { NULL };
SECURITY_STATUS sspi_status = SEC_E_OK;
struct Curl_schannel_cred *old_cred = NULL;
struct in_addr addr;
@@ -428,15 +770,10 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
TCHAR *host_name;
CURLcode result;
-#ifndef CURL_DISABLE_PROXY
- char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- char * const hostname = conn->host.name;
-#endif
+ char * const hostname = SSL_HOST_NAME();
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
+ "schannel: SSL/TLS connection with %s port %hu (step 1/3)",
hostname, conn->remote_port));
if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
@@ -444,7 +781,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
algorithms that may not be supported by all servers. */
infof(data, "schannel: Windows version is old and may not be able to "
- "connect to some servers due to lack of SNI, algorithms, etc.\n");
+ "connect to some servers due to lack of SNI, algorithms, etc.");
}
#ifdef HAS_ALPN
@@ -469,7 +806,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API
- if(SSL_CONN_CONFIG(CAfile)) {
+ if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
VERSION_GREATER_THAN_EQUAL)) {
BACKEND->use_manual_cred_validation = true;
@@ -483,7 +820,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
else
BACKEND->use_manual_cred_validation = false;
#else
- if(SSL_CONN_CONFIG(CAfile)) {
+ if(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) {
failf(data, "schannel: CA cert support not built in");
return CURLE_NOT_BUILT_IN;
}
@@ -496,333 +833,24 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
if(SSL_SET_OPTION(primary.sessionid)) {
Curl_ssl_sessionid_lock(data);
if(!Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
(void **)&old_cred, NULL, sockindex)) {
BACKEND->cred = old_cred;
- DEBUGF(infof(data, "schannel: re-using existing credential handle\n"));
+ DEBUGF(infof(data, "schannel: re-using existing credential handle"));
/* increment the reference counter of the credential/session handle */
BACKEND->cred->refcount++;
DEBUGF(infof(data,
- "schannel: incremented credential handle refcount = %d\n",
+ "schannel: incremented credential handle refcount = %d",
BACKEND->cred->refcount));
}
Curl_ssl_sessionid_unlock(data);
}
if(!BACKEND->cred) {
- /* setup Schannel API options */
- memset(&schannel_cred, 0, sizeof(schannel_cred));
- schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
-
- if(conn->ssl_config.verifypeer) {
-#ifdef HAS_MANUAL_VERIFY_API
- if(BACKEND->use_manual_cred_validation)
- schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;
- else
-#endif
- schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
-
- if(data->set.ssl.no_revoke) {
- schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE;
-
- DEBUGF(infof(data, "schannel: disabled server certificate revocation "
- "checks\n"));
- }
- else if(data->set.ssl.revoke_best_effort) {
- schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_REVOCATION_CHECK_CHAIN;
-
- DEBUGF(infof(data, "schannel: ignore revocation offline errors"));
- }
- else {
- schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
-
- DEBUGF(infof(data,
- "schannel: checking server certificate revocation\n"));
- }
- }
- else {
- schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
- SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
- SCH_CRED_IGNORE_REVOCATION_OFFLINE;
- DEBUGF(infof(data,
- "schannel: disabled server cert revocation checks\n"));
- }
-
- if(!conn->ssl_config.verifyhost) {
- schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
- DEBUGF(infof(data, "schannel: verifyhost setting prevents Schannel from "
- "comparing the supplied target name with the subject "
- "names in server certificates.\n"));
- }
-
- switch(conn->ssl_config.version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_3:
- {
- result = set_ssl_version_min_max(&schannel_cred, data, conn);
- if(result != CURLE_OK)
- return result;
- break;
- }
- case CURL_SSLVERSION_SSLv3:
- schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
- break;
- case CURL_SSLVERSION_SSLv2:
- schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
- break;
- default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- if(SSL_CONN_CONFIG(cipher_list)) {
- result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list));
- if(CURLE_OK != result) {
- failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG");
- return result;
- }
- }
-
-
-#ifdef HAS_CLIENT_CERT_PATH
- /* client certificate */
- if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
- DWORD cert_store_name = 0;
- TCHAR *cert_store_path = NULL;
- TCHAR *cert_thumbprint_str = NULL;
- CRYPT_HASH_BLOB cert_thumbprint;
- BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
- HCERTSTORE cert_store = NULL;
- FILE *fInCert = NULL;
- void *certdata = NULL;
- size_t certsize = 0;
- bool blob = data->set.ssl.primary.cert_blob != NULL;
- TCHAR *cert_path = NULL;
- if(blob) {
- certdata = data->set.ssl.primary.cert_blob->data;
- certsize = data->set.ssl.primary.cert_blob->len;
- }
- else {
- cert_path = curlx_convert_UTF8_to_tchar(
- data->set.ssl.primary.clientcert);
- if(!cert_path)
- return CURLE_OUT_OF_MEMORY;
-
- result = get_cert_location(cert_path, &cert_store_name,
- &cert_store_path, &cert_thumbprint_str);
-
- if(result && (data->set.ssl.primary.clientcert[0]!='\0'))
- fInCert = fopen(data->set.ssl.primary.clientcert, "rb");
-
- if(result && !fInCert) {
- failf(data, "schannel: Failed to get certificate location"
- " or file for %s",
- data->set.ssl.primary.clientcert);
- curlx_unicodefree(cert_path);
- return result;
- }
- }
-
- if((fInCert || blob) && (data->set.ssl.cert_type) &&
- (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
- failf(data, "schannel: certificate format compatibility error "
- " for %s",
- blob ? "(memory blob)" : data->set.ssl.primary.clientcert);
- curlx_unicodefree(cert_path);
- return CURLE_SSL_CERTPROBLEM;
- }
-
- if(fInCert || blob) {
- /* Reading a .P12 or .pfx file, like the example at bottom of
- https://social.msdn.microsoft.com/Forums/windowsdesktop/
- en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
- */
- CRYPT_DATA_BLOB datablob;
- WCHAR* pszPassword;
- size_t pwd_len = 0;
- int str_w_len = 0;
- const char *cert_showfilename_error = blob ?
- "(memory blob)" : data->set.ssl.primary.clientcert;
- curlx_unicodefree(cert_path);
- if(fInCert) {
- long cert_tell = 0;
- bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
- if(continue_reading)
- cert_tell = ftell(fInCert);
- if(cert_tell < 0)
- continue_reading = FALSE;
- else
- certsize = (size_t)cert_tell;
- if(continue_reading)
- continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
- if(continue_reading)
- certdata = malloc(certsize + 1);
- if((!certdata) ||
- ((int) fread(certdata, certsize, 1, fInCert) != 1))
- continue_reading = FALSE;
- fclose(fInCert);
- if(!continue_reading) {
- failf(data, "schannel: Failed to read cert file %s",
- data->set.ssl.primary.clientcert);
- free(certdata);
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- /* Convert key-pair data to the in-memory certificate store */
- datablob.pbData = (BYTE*)certdata;
- datablob.cbData = (DWORD)certsize;
-
- if(data->set.ssl.key_passwd != NULL)
- pwd_len = strlen(data->set.ssl.key_passwd);
- pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
- if(pszPassword) {
- if(pwd_len > 0)
- str_w_len = MultiByteToWideChar(CP_UTF8,
- MB_ERR_INVALID_CHARS,
- data->set.ssl.key_passwd, (int)pwd_len,
- pszPassword, (int)(pwd_len + 1));
-
- if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
- pszPassword[str_w_len] = 0;
- else
- pszPassword[0] = 0;
-
- cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
- free(pszPassword);
- }
- if(!blob)
- free(certdata);
- if(cert_store == NULL) {
- DWORD errorcode = GetLastError();
- if(errorcode == ERROR_INVALID_PASSWORD)
- failf(data, "schannel: Failed to import cert file %s, "
- "password is bad",
- cert_showfilename_error);
- else
- failf(data, "schannel: Failed to import cert file %s, "
- "last error is 0x%x",
- cert_showfilename_error, errorcode);
- return CURLE_SSL_CERTPROBLEM;
- }
-
- client_certs[0] = CertFindCertificateInStore(
- cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
- CERT_FIND_ANY, NULL, NULL);
-
- if(client_certs[0] == NULL) {
- failf(data, "schannel: Failed to get certificate from file %s"
- ", last error is 0x%x",
- cert_showfilename_error, GetLastError());
- CertCloseStore(cert_store, 0);
- return CURLE_SSL_CERTPROBLEM;
- }
-
- schannel_cred.cCreds = 1;
- schannel_cred.paCred = client_certs;
- }
- else {
- cert_store =
- CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0,
- (HCRYPTPROV)NULL,
- CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
- cert_store_path);
- if(!cert_store) {
- failf(data, "schannel: Failed to open cert store %x %s, "
- "last error is 0x%x",
- cert_store_name, cert_store_path, GetLastError());
- free(cert_store_path);
- curlx_unicodefree(cert_path);
- return CURLE_SSL_CERTPROBLEM;
- }
- free(cert_store_path);
-
- cert_thumbprint.pbData = cert_thumbprint_data;
- cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
-
- if(!CryptStringToBinary(cert_thumbprint_str,
- CERT_THUMBPRINT_STR_LEN,
- CRYPT_STRING_HEX,
- cert_thumbprint_data,
- &cert_thumbprint.cbData,
- NULL, NULL)) {
- curlx_unicodefree(cert_path);
- CertCloseStore(cert_store, 0);
- return CURLE_SSL_CERTPROBLEM;
- }
-
- client_certs[0] = CertFindCertificateInStore(
- cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
- CERT_FIND_HASH, &cert_thumbprint, NULL);
-
- curlx_unicodefree(cert_path);
-
- if(client_certs[0]) {
- schannel_cred.cCreds = 1;
- schannel_cred.paCred = client_certs;
- }
- else {
- /* CRYPT_E_NOT_FOUND / E_INVALIDARG */
- CertCloseStore(cert_store, 0);
- return CURLE_SSL_CERTPROBLEM;
- }
- }
- CertCloseStore(cert_store, 0);
- }
-#else
- if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) {
- failf(data, "schannel: client cert support not built in");
- return CURLE_NOT_BUILT_IN;
- }
-#endif
-
- /* allocate memory for the re-usable credential handle */
- BACKEND->cred = (struct Curl_schannel_cred *)
- calloc(1, sizeof(struct Curl_schannel_cred));
- if(!BACKEND->cred) {
- failf(data, "schannel: unable to allocate memory");
-
- if(client_certs[0])
- CertFreeCertificateContext(client_certs[0]);
-
- return CURLE_OUT_OF_MEMORY;
- }
- 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,
- &schannel_cred, NULL, NULL,
- &BACKEND->cred->cred_handle,
- &BACKEND->cred->time_stamp);
-
- if(client_certs[0])
- CertFreeCertificateContext(client_certs[0]);
-
- if(sspi_status != SEC_E_OK) {
- char buffer[STRERROR_LEN];
- failf(data, "schannel: AcquireCredentialsHandle failed: %s",
- Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- Curl_safefree(BACKEND->cred);
- switch(sspi_status) {
- case SEC_E_INSUFFICIENT_MEMORY:
- return CURLE_OUT_OF_MEMORY;
- case SEC_E_NO_CREDENTIALS:
- case SEC_E_SECPKG_NOT_FOUND:
- case SEC_E_NOT_OWNER:
- case SEC_E_UNKNOWN_CREDENTIALS:
- case SEC_E_INTERNAL_ERROR:
- default:
- return CURLE_SSL_CONNECT_ERROR;
- }
+ result = schannel_acquire_credential_handle(data, conn, sockindex);
+ if(result != CURLE_OK) {
+ return result;
}
}
@@ -832,7 +860,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
|| Curl_inet_pton(AF_INET6, hostname, &addr6)
#endif
) {
- infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
+ infof(data, "schannel: using IP address, SNI is not supported by OS.");
}
#ifdef HAS_ALPN
@@ -860,18 +888,19 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
list_start_index = cur;
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
- memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
- cur += NGHTTP2_PROTO_ALPN_LEN;
- infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
+ alpn_buffer[cur++] = ALPN_H2_LENGTH;
+ memcpy(&alpn_buffer[cur], ALPN_H2, ALPN_H2_LENGTH);
+ cur += ALPN_H2_LENGTH;
+ infof(data, "schannel: ALPN, offering %s", ALPN_H2);
}
#endif
alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
cur += ALPN_HTTP_1_1_LENGTH;
- infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "schannel: ALPN, offering %s", ALPN_HTTP_1_1);
*list_len = curlx_uitous(cur - list_start_index);
*extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
@@ -892,11 +921,15 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
- /* setup request flags */
+ /* security request flags */
BACKEND->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_STREAM;
+ if(!SSL_SET_OPTION(auto_client_cert)) {
+ BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+ }
+
/* allocate memory for the security context handle */
BACKEND->ctxt = (struct Curl_schannel_ctxt *)
calloc(1, sizeof(struct Curl_schannel_ctxt));
@@ -955,7 +988,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
DEBUGF(infof(data, "schannel: sending initial handshake data: "
- "sending %lu bytes...\n", outbuf.cbBuffer));
+ "sending %lu bytes.", outbuf.cbBuffer));
/* send initial handshake data which is now stored in output buffer */
result = Curl_write_plain(data, conn->sock[sockindex], outbuf.pvBuffer,
@@ -968,7 +1001,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
}
DEBUGF(infof(data, "schannel: sent initial handshake data: "
- "sent %zd bytes\n", written));
+ "sent %zd bytes", written));
BACKEND->recv_unrecoverable_err = CURLE_OK;
BACKEND->recv_sspi_close_notify = false;
@@ -996,41 +1029,36 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result;
bool doread;
-#ifndef CURL_DISABLE_PROXY
- char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- char * const hostname = conn->host.name;
-#endif
+ char * const hostname = SSL_HOST_NAME();
const char *pubkey_ptr;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
+ "schannel: SSL/TLS connection with %s port %hu (step 2/3)",
hostname, conn->remote_port));
if(!BACKEND->cred || !BACKEND->ctxt)
return CURLE_SSL_CONNECT_ERROR;
/* buffer to store previously received and decrypted data */
- if(BACKEND->decdata_buffer == NULL) {
+ if(!BACKEND->decdata_buffer) {
BACKEND->decdata_offset = 0;
BACKEND->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
BACKEND->decdata_buffer = malloc(BACKEND->decdata_length);
- if(BACKEND->decdata_buffer == NULL) {
+ if(!BACKEND->decdata_buffer) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
}
/* buffer to store previously received and encrypted data */
- if(BACKEND->encdata_buffer == NULL) {
+ if(!BACKEND->encdata_buffer) {
BACKEND->encdata_is_incomplete = false;
BACKEND->encdata_offset = 0;
BACKEND->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
BACKEND->encdata_buffer = malloc(BACKEND->encdata_length);
- if(BACKEND->encdata_buffer == NULL) {
+ if(!BACKEND->encdata_buffer) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
@@ -1045,7 +1073,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
reallocated_buffer = realloc(BACKEND->encdata_buffer,
reallocated_length);
- if(reallocated_buffer == NULL) {
+ if(!reallocated_buffer) {
failf(data, "schannel: unable to re-allocate memory");
return CURLE_OUT_OF_MEMORY;
}
@@ -1069,7 +1097,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
if(connssl->connecting_state != ssl_connect_2_writing)
connssl->connecting_state = ssl_connect_2_reading;
DEBUGF(infof(data, "schannel: failed to receive handshake, "
- "need more data\n"));
+ "need more data"));
return CURLE_OK;
}
else if((result != CURLE_OK) || (nread == 0)) {
@@ -1081,11 +1109,11 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* increase encrypted data buffer offset */
BACKEND->encdata_offset += nread;
BACKEND->encdata_is_incomplete = false;
- DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
+ DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
}
DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu\n",
+ "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length));
/* setup input buffers */
@@ -1100,7 +1128,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, outbuf, 3);
- if(inbuf[0].pvBuffer == NULL) {
+ if(!inbuf[0].pvBuffer) {
failf(data, "schannel: unable to allocate memory");
return CURLE_OUT_OF_MEMORY;
}
@@ -1130,7 +1158,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
BACKEND->encdata_is_incomplete = true;
connssl->connecting_state = ssl_connect_2_reading;
DEBUGF(infof(data,
- "schannel: received incomplete message, need more data\n"));
+ "schannel: received incomplete message, need more data"));
return CURLE_OK;
}
@@ -1142,7 +1170,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
BACKEND->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
connssl->connecting_state = ssl_connect_2_writing;
DEBUGF(infof(data,
- "schannel: a client certificate has been requested\n"));
+ "schannel: a client certificate has been requested"));
return CURLE_OK;
}
@@ -1152,7 +1180,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* search for handshake tokens that need to be send */
if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
DEBUGF(infof(data, "schannel: sending next handshake data: "
- "sending %lu bytes...\n", outbuf[i].cbBuffer));
+ "sending %lu bytes.", outbuf[i].cbBuffer));
/* send handshake token to server */
result = Curl_write_plain(data, conn->sock[sockindex],
@@ -1207,7 +1235,7 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* check if there was additional remaining encrypted data */
if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
- DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
+ DEBUGF(infof(data, "schannel: encrypted data length: %lu",
inbuf[1].cbBuffer));
/*
There are two cases where we could be getting extra data here:
@@ -1247,12 +1275,10 @@ schannel_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* check if the handshake is complete */
if(sspi_status == SEC_E_OK) {
connssl->connecting_state = ssl_connect_3;
- DEBUGF(infof(data, "schannel: SSL/TLS handshake complete\n"));
+ DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
}
- pubkey_ptr = SSL_IS_PROXY() ?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ pubkey_ptr = SSL_PINNED_PUB_KEY();
if(pubkey_ptr) {
result = pkp_pin_peer_pubkey(data, conn, sockindex, pubkey_ptr);
if(result) {
@@ -1337,9 +1363,9 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
SECURITY_STATUS sspi_status = SEC_E_OK;
CERT_CONTEXT *ccert_context = NULL;
-#ifdef DEBUGBUILD
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
+ bool isproxy = SSL_IS_PROXY();
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ const char * const hostname = SSL_HOST_NAME();
#endif
#ifdef HAS_ALPN
SecPkgContext_ApplicationProtocol alpn_result;
@@ -1348,7 +1374,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGF(infof(data,
- "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
+ "schannel: SSL/TLS connection with %s port %hu (step 3/3)",
hostname, conn->remote_port));
if(!BACKEND->cred)
@@ -1384,13 +1410,12 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
if(alpn_result.ProtoNegoStatus ==
SecApplicationProtocolNegotiationStatus_Success) {
- infof(data, "schannel: ALPN, server accepted to use %.*s\n",
+ infof(data, "schannel: ALPN, server accepted to use %.*s",
alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
-#ifdef USE_NGHTTP2
- if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
+#ifdef USE_HTTP2
+ if(alpn_result.ProtocolIdSize == ALPN_H2_LENGTH &&
+ !memcmp(ALPN_H2, alpn_result.ProtocolId, ALPN_H2_LENGTH)) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
@@ -1402,7 +1427,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
}
}
else
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
@@ -1414,19 +1439,19 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
struct Curl_schannel_cred *old_cred = NULL;
Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, (void **)&old_cred, NULL,
- sockindex));
+ incache = !(Curl_ssl_getsessionid(data, conn, isproxy, (void **)&old_cred,
+ NULL, sockindex));
if(incache) {
if(old_cred != BACKEND->cred) {
DEBUGF(infof(data,
- "schannel: old credential handle is stale, removing\n"));
+ "schannel: old credential handle is stale, removing"));
/* we're not taking old_cred ownership here, no refcount++ is needed */
Curl_ssl_delsessionid(data, (void *)old_cred);
incache = FALSE;
}
}
if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, (void *)BACKEND->cred,
+ result = Curl_ssl_addsessionid(data, conn, isproxy, BACKEND->cred,
sizeof(struct Curl_schannel_cred),
sockindex);
if(result) {
@@ -1438,7 +1463,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
/* this cred session is now also referenced by sessionid cache */
BACKEND->cred->refcount++;
DEBUGF(infof(data,
- "schannel: stored credential handle in session cache\n"));
+ "schannel: stored credential handle in session cache"));
}
}
Curl_ssl_sessionid_unlock(data);
@@ -1451,7 +1476,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&ccert_context);
- if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
+ if((sspi_status != SEC_E_OK) || !ccert_context) {
failf(data, "schannel: failed to retrieve remote cert context");
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -1769,21 +1794,21 @@ schannel_recv(struct Curl_easy *data, int sockindex,
* handled in the cleanup.
*/
- DEBUGF(infof(data, "schannel: client wants to read %zu bytes\n", len));
+ DEBUGF(infof(data, "schannel: client wants to read %zu bytes", len));
*err = CURLE_OK;
if(len && len <= BACKEND->decdata_offset) {
- infof(data, "schannel: enough decrypted data is already available\n");
+ infof(data, "schannel: enough decrypted data is already available");
goto cleanup;
}
else if(BACKEND->recv_unrecoverable_err) {
*err = BACKEND->recv_unrecoverable_err;
- infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
+ infof(data, "schannel: an unrecoverable error occurred in a prior call");
goto cleanup;
}
else if(BACKEND->recv_sspi_close_notify) {
/* once a server has indicated shutdown there is no more encrypted data */
- infof(data, "schannel: server indicated shutdown in a prior call\n");
+ infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup;
}
@@ -1803,7 +1828,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
}
reallocated_buffer = realloc(BACKEND->encdata_buffer,
reallocated_length);
- if(reallocated_buffer == NULL) {
+ if(!reallocated_buffer) {
*err = CURLE_OUT_OF_MEMORY;
failf(data, "schannel: unable to re-allocate memory");
goto cleanup;
@@ -1812,12 +1837,12 @@ schannel_recv(struct Curl_easy *data, int sockindex,
BACKEND->encdata_buffer = reallocated_buffer;
BACKEND->encdata_length = reallocated_length;
size = BACKEND->encdata_length - BACKEND->encdata_offset;
- DEBUGF(infof(data, "schannel: encdata_buffer resized %zu\n",
+ DEBUGF(infof(data, "schannel: encdata_buffer resized %zu",
BACKEND->encdata_length));
}
DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu\n",
+ "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length));
/* read encrypted data from socket */
@@ -1829,25 +1854,25 @@ schannel_recv(struct Curl_easy *data, int sockindex,
nread = -1;
if(*err == CURLE_AGAIN)
DEBUGF(infof(data,
- "schannel: Curl_read_plain returned CURLE_AGAIN\n"));
+ "schannel: Curl_read_plain returned CURLE_AGAIN"));
else if(*err == CURLE_RECV_ERROR)
- infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
+ infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR");
else
- infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
+ infof(data, "schannel: Curl_read_plain returned error %d", *err);
}
else if(nread == 0) {
BACKEND->recv_connection_closed = true;
- DEBUGF(infof(data, "schannel: server closed the connection\n"));
+ DEBUGF(infof(data, "schannel: server closed the connection"));
}
else if(nread > 0) {
BACKEND->encdata_offset += (size_t)nread;
BACKEND->encdata_is_incomplete = false;
- DEBUGF(infof(data, "schannel: encrypted data got %zd\n", nread));
+ DEBUGF(infof(data, "schannel: encrypted data got %zd", nread));
}
}
DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu\n",
+ "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length));
/* decrypt loop */
@@ -1876,7 +1901,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* check for successfully decrypted data, even before actual
renegotiation or shutdown of the connection context */
if(inbuf[1].BufferType == SECBUFFER_DATA) {
- DEBUGF(infof(data, "schannel: decrypted data length: %lu\n",
+ DEBUGF(infof(data, "schannel: decrypted data length: %lu",
inbuf[1].cbBuffer));
/* increase buffer in order to fit the received amount of data */
@@ -1892,7 +1917,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
}
reallocated_buffer = realloc(BACKEND->decdata_buffer,
reallocated_length);
- if(reallocated_buffer == NULL) {
+ if(!reallocated_buffer) {
*err = CURLE_OUT_OF_MEMORY;
failf(data, "schannel: unable to re-allocate memory");
goto cleanup;
@@ -1909,15 +1934,15 @@ schannel_recv(struct Curl_easy *data, int sockindex,
BACKEND->decdata_offset += size;
}
- DEBUGF(infof(data, "schannel: decrypted data added: %zu\n", size));
+ DEBUGF(infof(data, "schannel: decrypted data added: %zu", size));
DEBUGF(infof(data,
- "schannel: decrypted cached: offset %zu length %zu\n",
+ "schannel: decrypted cached: offset %zu length %zu",
BACKEND->decdata_offset, BACKEND->decdata_length));
}
/* check for remaining encrypted data */
if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
- DEBUGF(infof(data, "schannel: encrypted data length: %lu\n",
+ DEBUGF(infof(data, "schannel: encrypted data length: %lu",
inbuf[3].cbBuffer));
/* check if the remaining data is less than the total amount
@@ -1933,7 +1958,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
}
DEBUGF(infof(data,
- "schannel: encrypted cached: offset %zu length %zu\n",
+ "schannel: encrypted cached: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length));
}
else {
@@ -1943,29 +1968,29 @@ schannel_recv(struct Curl_easy *data, int sockindex,
/* check if server wants to renegotiate the connection context */
if(sspi_status == SEC_I_RENEGOTIATE) {
- infof(data, "schannel: remote party requests renegotiation\n");
+ infof(data, "schannel: remote party requests renegotiation");
if(*err && *err != CURLE_AGAIN) {
- infof(data, "schannel: can't renogotiate, an error is pending\n");
+ infof(data, "schannel: can't renogotiate, an error is pending");
goto cleanup;
}
if(BACKEND->encdata_offset) {
*err = CURLE_RECV_ERROR;
infof(data, "schannel: can't renogotiate, "
- "encrypted data available\n");
+ "encrypted data available");
goto cleanup;
}
/* begin renegotiation */
- infof(data, "schannel: renegotiating SSL/TLS connection\n");
+ infof(data, "schannel: renegotiating SSL/TLS connection");
connssl->state = ssl_connection_negotiating;
connssl->connecting_state = ssl_connect_2_writing;
*err = schannel_connect_common(data, conn, sockindex, FALSE, &done);
if(*err) {
- infof(data, "schannel: renegotiation failed\n");
+ infof(data, "schannel: renegotiation failed");
goto cleanup;
}
/* now retry receiving data */
sspi_status = SEC_E_OK;
- infof(data, "schannel: SSL/TLS connection renegotiated\n");
+ infof(data, "schannel: SSL/TLS connection renegotiated");
continue;
}
/* check if the server closed the connection */
@@ -1975,7 +2000,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
BACKEND->recv_sspi_close_notify = true;
if(!BACKEND->recv_connection_closed) {
BACKEND->recv_connection_closed = true;
- infof(data, "schannel: server closed the connection\n");
+ infof(data, "schannel: server closed the connection");
}
goto cleanup;
}
@@ -1984,7 +2009,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
BACKEND->encdata_is_incomplete = true;
if(!*err)
*err = CURLE_AGAIN;
- infof(data, "schannel: failed to decrypt data, need more data\n");
+ infof(data, "schannel: failed to decrypt data, need more data");
goto cleanup;
}
else {
@@ -1992,23 +2017,23 @@ schannel_recv(struct Curl_easy *data, int sockindex,
char buffer[STRERROR_LEN];
#endif
*err = CURLE_RECV_ERROR;
- infof(data, "schannel: failed to read data from server: %s\n",
+ infof(data, "schannel: failed to read data from server: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
goto cleanup;
}
}
DEBUGF(infof(data,
- "schannel: encrypted data buffer: offset %zu length %zu\n",
+ "schannel: encrypted data buffer: offset %zu length %zu",
BACKEND->encdata_offset, BACKEND->encdata_length));
DEBUGF(infof(data,
- "schannel: decrypted data buffer: offset %zu length %zu\n",
+ "schannel: decrypted data buffer: offset %zu length %zu",
BACKEND->decdata_offset, BACKEND->decdata_length));
cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */
- DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
+ DEBUGF(infof(data, "schannel: schannel_recv cleanup"));
/* Error if the connection has closed without a close_notify.
@@ -2030,7 +2055,7 @@ schannel_recv(struct Curl_easy *data, int sockindex,
BACKEND->recv_sspi_close_notify = true;
else {
*err = CURLE_RECV_ERROR;
- infof(data, "schannel: server closed abruptly (missing close_notify)\n");
+ infof(data, "schannel: server closed abruptly (missing close_notify)");
}
}
@@ -2044,9 +2069,9 @@ schannel_recv(struct Curl_easy *data, int sockindex,
memmove(BACKEND->decdata_buffer, BACKEND->decdata_buffer + size,
BACKEND->decdata_offset - size);
BACKEND->decdata_offset -= size;
- DEBUGF(infof(data, "schannel: decrypted data returned %zu\n", size));
+ DEBUGF(infof(data, "schannel: decrypted data returned %zu", size));
DEBUGF(infof(data,
- "schannel: decrypted data buffer: offset %zu length %zu\n",
+ "schannel: decrypted data buffer: offset %zu length %zu",
BACKEND->decdata_offset, BACKEND->decdata_length));
*err = CURLE_OK;
return (ssize_t)size;
@@ -2126,16 +2151,11 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
* Shutting Down an Schannel Connection
*/
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-#ifndef CURL_DISABLE_PROXY
- char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- char * const hostname = conn->host.name;
-#endif
+ char * const hostname = SSL_HOST_NAME();
DEBUGASSERT(data);
- infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu",
hostname, conn->remote_port);
if(BACKEND->cred && BACKEND->ctxt) {
@@ -2193,14 +2213,14 @@ static int schannel_shutdown(struct Curl_easy *data, struct connectdata *conn,
s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
infof(data, "schannel: failed to send close msg: %s"
- " (bytes written: %zd)\n", curl_easy_strerror(result), written);
+ " (bytes written: %zd)", curl_easy_strerror(result), written);
}
}
}
/* free SSPI Schannel API security context handle */
if(BACKEND->ctxt) {
- DEBUGF(infof(data, "schannel: clear security context handle\n"));
+ DEBUGF(infof(data, "schannel: clear security context handle"));
s_pSecFn->DeleteSecurityContext(&BACKEND->ctxt->ctxt_handle);
Curl_safefree(BACKEND->ctxt);
}
@@ -2294,7 +2314,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
- if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ if((sspi_status != SEC_E_OK) || !pCertContextServer) {
char buffer[STRERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
@@ -2404,6 +2424,9 @@ const struct Curl_ssl Curl_ssl_schannel = {
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
SSLSUPP_CERTINFO |
+#ifdef HAS_MANUAL_VERIFY_API
+ SSLSUPP_CAINFO_BLOB |
+#endif
SSLSUPP_PINNEDPUBKEY,
sizeof(struct ssl_backend_data),
@@ -2418,6 +2441,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_cert_status_request, /* cert_status_request */
schannel_connect, /* connect */
schannel_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -2426,7 +2450,9 @@ const struct Curl_ssl Curl_ssl_schannel = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- schannel_sha256sum /* sha256sum */
+ schannel_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif /* USE_SCHANNEL */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h
index 2952caa..77853aa 100644
--- a/Utilities/cmcurl/lib/vtls/schannel.h
+++ b/Utilities/cmcurl/lib/vtls/schannel.h
@@ -71,6 +71,8 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
#endif
#endif
+#define NUMOF_CIPHERS 45 /* There are 45 listed in the MS headers */
+
struct Curl_schannel_cred {
CredHandle cred_handle;
TimeStamp time_stamp;
@@ -102,6 +104,7 @@ struct ssl_backend_data {
#ifdef HAS_MANUAL_VERIFY_API
bool use_manual_cred_validation; /* true if manual cred validation is used */
#endif
+ ALG_ID algIds[NUMOF_CIPHERS];
};
#endif /* EXPOSE_SCHANNEL_INTERNAL_STRUCTS */
diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c
index 2ef39cc..1b283d0 100644
--- a/Utilities/cmcurl/lib/vtls/schannel_verify.c
+++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c
@@ -77,21 +77,156 @@ static int is_cr_or_lf(char c)
return c == '\r' || c == '\n';
}
-static CURLcode add_certs_to_store(HCERTSTORE trust_store,
- const char *ca_file,
- struct Curl_easy *data)
+/* 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 occurrence or NULL if not found
+ */
+static const char *c_memmem(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen)
+{
+ const char *p;
+ char first;
+ const char *str_limit = (const char *)haystack + haystacklen;
+ if(!needlelen || needlelen > haystacklen)
+ return NULL;
+ first = *(const char *)needle;
+ for(p = (const char *)haystack; p <= (str_limit - needlelen); p++)
+ if(((*p) == first) && (memcmp(p, needle, needlelen) == 0))
+ return p;
+
+ return NULL;
+}
+
+static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
+ const char *ca_buffer,
+ size_t ca_buffer_size,
+ const char *ca_file_text,
+ struct Curl_easy *data)
+{
+ const size_t begin_cert_len = strlen(BEGIN_CERT);
+ const size_t end_cert_len = strlen(END_CERT);
+ CURLcode result = CURLE_OK;
+ int num_certs = 0;
+ bool more_certs = 1;
+ const char *current_ca_file_ptr = ca_buffer;
+ const char *ca_buffer_limit = ca_buffer + ca_buffer_size;
+
+ while(more_certs && (current_ca_file_ptr<ca_buffer_limit)) {
+ const char *begin_cert_ptr = c_memmem(current_ca_file_ptr,
+ ca_buffer_limit-current_ca_file_ptr,
+ BEGIN_CERT,
+ begin_cert_len);
+ if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[begin_cert_len])) {
+ more_certs = 0;
+ }
+ else {
+ const char *end_cert_ptr = c_memmem(begin_cert_ptr,
+ ca_buffer_limit-begin_cert_ptr,
+ END_CERT,
+ end_cert_len);
+ if(!end_cert_ptr) {
+ failf(data,
+ "schannel: CA file '%s' is not correctly formatted",
+ ca_file_text);
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ CERT_BLOB cert_blob;
+ CERT_CONTEXT *cert_context = NULL;
+ BOOL add_cert_result = FALSE;
+ DWORD actual_content_type = 0;
+ DWORD cert_size = (DWORD)
+ ((end_cert_ptr + end_cert_len) - begin_cert_ptr);
+
+ cert_blob.pbData = (BYTE *)begin_cert_ptr;
+ cert_blob.cbData = cert_size;
+ if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
+ &cert_blob,
+ CERT_QUERY_CONTENT_FLAG_CERT,
+ CERT_QUERY_FORMAT_FLAG_ALL,
+ 0,
+ NULL,
+ &actual_content_type,
+ NULL,
+ NULL,
+ NULL,
+ (const void **)&cert_context)) {
+ char buffer[STRERROR_LEN];
+ failf(data,
+ "schannel: failed to extract certificate from CA file "
+ "'%s': %s",
+ ca_file_text,
+ Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ current_ca_file_ptr = begin_cert_ptr + cert_size;
+
+ /* Sanity check that the cert_context object is the right type */
+ if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
+ failf(data,
+ "schannel: unexpected content type '%d' when extracting "
+ "certificate from CA file '%s'",
+ actual_content_type, ca_file_text);
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ add_cert_result =
+ CertAddCertificateContextToStore(trust_store,
+ cert_context,
+ CERT_STORE_ADD_ALWAYS,
+ NULL);
+ CertFreeCertificateContext(cert_context);
+ if(!add_cert_result) {
+ char buffer[STRERROR_LEN];
+ failf(data,
+ "schannel: failed to add certificate from CA file '%s' "
+ "to certificate store: %s",
+ ca_file_text,
+ Curl_winapi_strerror(GetLastError(), buffer,
+ sizeof(buffer)));
+ result = CURLE_SSL_CACERT_BADFILE;
+ more_certs = 0;
+ }
+ else {
+ num_certs++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ if(!num_certs) {
+ infof(data,
+ "schannel: did not add any certificates from CA file '%s'",
+ ca_file_text);
+ }
+ else {
+ infof(data,
+ "schannel: added %d certificate(s) from CA file '%s'",
+ num_certs, ca_file_text);
+ }
+ }
+ return result;
+}
+
+static CURLcode add_certs_file_to_store(HCERTSTORE trust_store,
+ const char *ca_file,
+ struct Curl_easy *data)
{
CURLcode result;
HANDLE ca_file_handle = INVALID_HANDLE_VALUE;
LARGE_INTEGER file_size;
char *ca_file_buffer = NULL;
- char *current_ca_file_ptr = NULL;
TCHAR *ca_file_tstr = NULL;
size_t ca_file_bufsize = 0;
DWORD total_bytes_read = 0;
- bool more_certs = 0;
- int num_certs = 0;
- size_t END_CERT_LEN;
ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
if(!ca_file_tstr) {
@@ -181,106 +316,10 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
if(result != CURLE_OK) {
goto cleanup;
}
-
- END_CERT_LEN = strlen(END_CERT);
-
- more_certs = 1;
- current_ca_file_ptr = ca_file_buffer;
- while(more_certs && *current_ca_file_ptr != '\0') {
- char *begin_cert_ptr = strstr(current_ca_file_ptr, BEGIN_CERT);
- if(!begin_cert_ptr || !is_cr_or_lf(begin_cert_ptr[strlen(BEGIN_CERT)])) {
- more_certs = 0;
- }
- else {
- char *end_cert_ptr = strstr(begin_cert_ptr, END_CERT);
- if(!end_cert_ptr) {
- failf(data,
- "schannel: CA file '%s' is not correctly formatted",
- ca_file);
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- CERT_BLOB cert_blob;
- CERT_CONTEXT *cert_context = NULL;
- BOOL add_cert_result = FALSE;
- DWORD actual_content_type = 0;
- DWORD cert_size = (DWORD)
- ((end_cert_ptr + END_CERT_LEN) - begin_cert_ptr);
-
- cert_blob.pbData = (BYTE *)begin_cert_ptr;
- cert_blob.cbData = cert_size;
- if(!CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
- &cert_blob,
- CERT_QUERY_CONTENT_FLAG_CERT,
- CERT_QUERY_FORMAT_FLAG_ALL,
- 0,
- NULL,
- &actual_content_type,
- NULL,
- NULL,
- NULL,
- (const void **)&cert_context)) {
- char buffer[STRERROR_LEN];
- failf(data,
- "schannel: failed to extract certificate from CA file "
- "'%s': %s",
- ca_file,
- Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- current_ca_file_ptr = begin_cert_ptr + cert_size;
-
- /* Sanity check that the cert_context object is the right type */
- if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
- failf(data,
- "schannel: unexpected content type '%d' when extracting "
- "certificate from CA file '%s'",
- actual_content_type, ca_file);
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- add_cert_result =
- CertAddCertificateContextToStore(trust_store,
- cert_context,
- CERT_STORE_ADD_ALWAYS,
- NULL);
- CertFreeCertificateContext(cert_context);
- if(!add_cert_result) {
- char buffer[STRERROR_LEN];
- failf(data,
- "schannel: failed to add certificate from CA file '%s' "
- "to certificate store: %s",
- ca_file,
- Curl_winapi_strerror(GetLastError(), buffer,
- sizeof(buffer)));
- result = CURLE_SSL_CACERT_BADFILE;
- more_certs = 0;
- }
- else {
- num_certs++;
- }
- }
- }
- }
- }
- }
-
- if(result == CURLE_OK) {
- if(!num_certs) {
- infof(data,
- "schannel: did not add any certificates from CA file '%s'\n",
- ca_file);
- }
- else {
- infof(data,
- "schannel: added %d certificate(s) from CA file '%s'\n",
- num_certs, ca_file);
- }
- }
+ result = add_certs_data_to_store(trust_store,
+ ca_file_buffer, ca_file_bufsize,
+ ca_file,
+ data);
cleanup:
if(ca_file_handle != INVALID_HANDLE_VALUE) {
@@ -389,7 +428,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
if(entry->dwAltNameChoice != CERT_ALT_NAME_DNS_NAME) {
continue;
}
- if(entry->pwszDNSName == NULL) {
+ if(!entry->pwszDNSName) {
infof(data, "schannel: Empty DNS name.");
continue;
}
@@ -487,7 +526,7 @@ static CURLcode verify_host(struct Curl_easy *data,
if(match_result == CURL_HOST_MATCH) {
infof(data,
"schannel: connection hostname (%s) validated "
- "against certificate name (%s)\n",
+ "against certificate name (%s)",
conn_hostname, cert_hostname);
result = CURLE_OK;
}
@@ -496,7 +535,7 @@ static CURLcode verify_host(struct Curl_easy *data,
infof(data,
"schannel: connection hostname (%s) did not match "
- "against certificate name (%s)\n",
+ "against certificate name (%s)",
conn_hostname, cert_hostname);
cert_hostname_len =
@@ -536,27 +575,22 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
HCERTSTORE trust_store = NULL;
-#ifndef CURL_DISABLE_PROXY
- const char * const conn_hostname = SSL_IS_PROXY() ?
- conn->http_proxy.host.name :
- conn->host.name;
-#else
- const char * const conn_hostname = conn->host.name;
-#endif
+ const char * const conn_hostname = SSL_HOST_NAME();
sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
- if((sspi_status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ if((sspi_status != SEC_E_OK) || !pCertContextServer) {
char buffer[STRERROR_LEN];
failf(data, "schannel: Failed to read remote certificate context: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
result = CURLE_PEER_FAILED_VERIFICATION;
}
- if(result == CURLE_OK && SSL_CONN_CONFIG(CAfile) &&
+ if(result == CURLE_OK &&
+ (SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
BACKEND->use_manual_cred_validation) {
/*
* Create a chain engine that uses the certificates in the CA file as
@@ -582,8 +616,19 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
result = CURLE_SSL_CACERT_BADFILE;
}
else {
- result = add_certs_to_store(trust_store, SSL_CONN_CONFIG(CAfile),
- data);
+ const struct curl_blob *ca_info_blob = SSL_CONN_CONFIG(ca_info_blob);
+ if(ca_info_blob) {
+ result = add_certs_data_to_store(trust_store,
+ (const char *)ca_info_blob->data,
+ ca_info_blob->len,
+ "(memory blob)",
+ data);
+ }
+ else {
+ result = add_certs_file_to_store(trust_store,
+ SSL_CONN_CONFIG(CAfile),
+ data);
+ }
}
}
@@ -624,7 +669,7 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data,
NULL,
pCertContextServer->hCertStore,
&ChainPara,
- (data->set.ssl.no_revoke ? 0 :
+ (SSL_SET_OPTION(no_revoke) ? 0 :
CERT_CHAIN_REVOCATION_CHECK_CHAIN),
NULL,
&pChainContext)) {
diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c
index 9a8f7de..1e6ed5f 100644
--- a/Utilities/cmcurl/lib/vtls/sectransp.c
+++ b/Utilities/cmcurl/lib/vtls/sectransp.c
@@ -32,6 +32,9 @@
#include "curl_base64.h"
#include "strtok.h"
#include "multiif.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "strerror.h"
#ifdef USE_SECTRANSP
@@ -67,6 +70,7 @@
#define CURL_BUILD_IOS_7 0
#define CURL_BUILD_IOS_9 0
#define CURL_BUILD_IOS_11 0
+#define CURL_BUILD_IOS_13 0
#define CURL_BUILD_MAC 1
/* This is the maximum API level we are allowed to use when building: */
#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
@@ -76,6 +80,7 @@
#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
#define CURL_BUILD_MAC_10_11 MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
#define CURL_BUILD_MAC_10_13 MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
+#define CURL_BUILD_MAC_10_15 MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
/* These macros mean "the following code is present to allow runtime backward
compatibility with at least this cat or earlier":
(You set this at build-time using the compiler command line option
@@ -91,6 +96,7 @@
#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
#define CURL_BUILD_IOS_9 __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
#define CURL_BUILD_IOS_11 __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
+#define CURL_BUILD_IOS_13 __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
#define CURL_BUILD_MAC 0
#define CURL_BUILD_MAC_10_5 0
#define CURL_BUILD_MAC_10_6 0
@@ -99,6 +105,7 @@
#define CURL_BUILD_MAC_10_9 0
#define CURL_BUILD_MAC_10_11 0
#define CURL_BUILD_MAC_10_13 0
+#define CURL_BUILD_MAC_10_15 0
#define CURL_SUPPORT_MAC_10_5 0
#define CURL_SUPPORT_MAC_10_6 0
#define CURL_SUPPORT_MAC_10_7 0
@@ -138,6 +145,636 @@ struct ssl_backend_data {
size_t ssl_write_buffered_length;
};
+struct st_cipher {
+ const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
+ const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
+ SSLCipherSuite num; /* Cipher suite code/number defined in IANA registry */
+ bool weak; /* Flag to mark cipher as weak based on previous implementation
+ of Secure Transport back-end by CURL */
+};
+
+/* Macro to initialize st_cipher data structure: stringify id to name, cipher
+ number/id, 'weak' suite flag
+ */
+#define CIPHER_DEF(num, alias, weak) \
+ { #num, alias, num, weak }
+
+/*
+ Macro to initialize st_cipher data structure with name, code (IANA cipher
+ number/id value), and 'weak' suite flag. The first 28 cipher suite numbers
+ have the same IANA code for both SSL and TLS standards: numbers 0x0000 to
+ 0x001B. They have different names though. The first 4 letters of the cipher
+ suite name are the protocol name: "SSL_" or "TLS_", rest of the IANA name is
+ the same for both SSL and TLS cipher suite name.
+ The second part of the problem is that macOS/iOS SDKs don't define all TLS
+ codes but only 12 of them. The SDK defines all SSL codes though, i.e. SSL_NUM
+ constant is always defined for those 28 ciphers while TLS_NUM is defined only
+ for 12 of the first 28 ciphers. Those 12 TLS cipher codes match to
+ corresponding SSL enum value and represent the same cipher suite. Therefore
+ we'll use the SSL enum value for those cipher suites because it is defined
+ for all 28 of them.
+ We make internal data consistent and based on TLS names, i.e. all st_cipher
+ item names start with the "TLS_" prefix.
+ Summarizing all the above, those 28 first ciphers are presented in our table
+ with both TLS and SSL names. Their cipher numbers are assigned based on the
+ SDK enum value for the SSL cipher, which matches to IANA TLS number.
+ */
+#define CIPHER_DEF_SSLTLS(num_wo_prefix, alias, weak) \
+ { "TLS_" #num_wo_prefix, alias, SSL_##num_wo_prefix, weak }
+
+/*
+ Cipher suites were marked as weak based on the following:
+ RC4 encryption - rfc7465, the document contains a list of deprecated ciphers.
+ Marked in the code below as weak.
+ RC2 encryption - many mentions, was found vulnerable to a relatively easy
+ attack https://link.springer.com/chapter/10.1007%2F3-540-69710-1_14
+ Marked in the code below as weak.
+ DES and IDEA encryption - rfc5469, has a list of deprecated ciphers.
+ Marked in the code below as weak.
+ Anonymous Diffie-Hellman authentication and anonymous elliptic curve
+ Diffie-Hellman - vulnerable to a man-in-the-middle attack. Deprecated by
+ RFC 4346 aka TLS 1.1 (section A.5, page 60)
+ Null bulk encryption suites - not encrypted communication
+ Export ciphers, i.e. ciphers with restrictions to be used outside the US for
+ software exported to some countries, they were excluded from TLS 1.1
+ version. More precisely, they were noted as ciphers which MUST NOT be
+ negotiated in RFC 4346 aka TLS 1.1 (section A.5, pages 60 and 61).
+ All of those filters were considered weak because they contain a weak
+ algorithm like DES, RC2 or RC4, and already considered weak by other
+ criteria.
+ 3DES - NIST deprecated it and is going to retire it by 2023
+ https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
+ OpenSSL https://www.openssl.org/blog/blog/2016/08/24/sweet32/ also
+ deprecated those ciphers. Some other libraries also consider it
+ vulnerable or at least not strong enough.
+
+ CBC ciphers are vulnerable with SSL3.0 and TLS1.0:
+ https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance
+ /118518-technote-esa-00.html
+ We don't take care of this issue because it is resolved by later TLS
+ versions and for us, it requires more complicated checks, we need to
+ check a protocol version also. Vulnerability doesn't look very critical
+ and we do not filter out those cipher suites.
+ */
+
+#define CIPHER_WEAK_NOT_ENCRYPTED TRUE
+#define CIPHER_WEAK_RC_ENCRYPTION TRUE
+#define CIPHER_WEAK_DES_ENCRYPTION TRUE
+#define CIPHER_WEAK_IDEA_ENCRYPTION TRUE
+#define CIPHER_WEAK_ANON_AUTH TRUE
+#define CIPHER_WEAK_3DES_ENCRYPTION TRUE
+#define CIPHER_STRONG_ENOUGH FALSE
+
+/* Please do not change the order of the first ciphers available for SSL.
+ Do not insert and do not delete any of them. Code below
+ depends on their order and continuity.
+ If you add a new cipher, please maintain order by number, i.e.
+ insert in between existing items to appropriate place based on
+ cipher suite IANA number
+*/
+const static struct st_cipher ciphertable[] = {
+ /* SSL version 3.0 and initial TLS 1.0 cipher suites.
+ Defined since SDK 10.2.8 */
+ CIPHER_DEF_SSLTLS(NULL_WITH_NULL_NULL, /* 0x0000 */
+ NULL,
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF_SSLTLS(RSA_WITH_NULL_MD5, /* 0x0001 */
+ "NULL-MD5",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF_SSLTLS(RSA_WITH_NULL_SHA, /* 0x0002 */
+ "NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC4_40_MD5, /* 0x0003 */
+ "EXP-RC4-MD5",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_MD5, /* 0x0004 */
+ "RC4-MD5",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_SHA, /* 0x0005 */
+ "RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* 0x0006 */
+ "EXP-RC2-CBC-MD5",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_IDEA_CBC_SHA, /* 0x0007 */
+ "IDEA-CBC-SHA",
+ CIPHER_WEAK_IDEA_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0008 */
+ "EXP-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_DES_CBC_SHA, /* 0x0009 */
+ "DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
+ "DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x000B */
+ "EXP-DH-DSS-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_DSS_WITH_DES_CBC_SHA, /* 0x000C */
+ "DH-DSS-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x000D */
+ "DH-DSS-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x000E */
+ "EXP-DH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_RSA_WITH_DES_CBC_SHA, /* 0x000F */
+ "DH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0010 */
+ "DH-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x0011 */
+ "EXP-EDH-DSS-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_DSS_WITH_DES_CBC_SHA, /* 0x0012 */
+ "EDH-DSS-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x0013 */
+ "DHE-DSS-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0014 */
+ "EXP-EDH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_RSA_WITH_DES_CBC_SHA, /* 0x0015 */
+ "EDH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0016 */
+ "DHE-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_RC4_40_MD5, /* 0x0017 */
+ "EXP-ADH-RC4-MD5",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_WITH_RC4_128_MD5, /* 0x0018 */
+ "ADH-RC4-MD5",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_DES40_CBC_SHA, /* 0x0019 */
+ "EXP-ADH-DES-CBC-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_WITH_DES_CBC_SHA, /* 0x001A */
+ "ADH-DES-CBC-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_WITH_3DES_EDE_CBC_SHA, /* 0x001B */
+ "ADH-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* 0x001C */
+ NULL,
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* 0x001D */
+ NULL,
+ CIPHER_STRONG_ENOUGH),
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */
+ CIPHER_DEF(TLS_PSK_WITH_NULL_SHA, /* 0x002C */
+ "PSK-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA, /* 0x002D */
+ "DHE-PSK-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA, /* 0x002E */
+ "RSA-PSK-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+ /* TLS addenda using AES, per RFC 3268. Defined since SDK 10.4u */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ "AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA, /* 0x0030 */
+ "DH-DSS-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA, /* 0x0031 */
+ "DH-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* 0x0032 */
+ "DHE-DSS-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* 0x0033 */
+ "DHE-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA, /* 0x0034 */
+ "ADH-AES128-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
+ "AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA, /* 0x0036 */
+ "DH-DSS-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA, /* 0x0037 */
+ "DH-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* 0x0038 */
+ "DHE-DSS-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* 0x0039 */
+ "DHE-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA, /* 0x003A */
+ "ADH-AES256-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ /* TLS 1.2 addenda, RFC 5246 */
+ /* Server provided RSA certificate for key exchange. */
+ CIPHER_DEF(TLS_RSA_WITH_NULL_SHA256, /* 0x003B */
+ "NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ "AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
+ "AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ /* Server-authenticated (and optionally client-authenticated)
+ Diffie-Hellman. */
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA256, /* 0x003E */
+ "DH-DSS-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA256, /* 0x003F */
+ "DH-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, /* 0x0040 */
+ "DHE-DSS-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+
+ /* TLS 1.2 addenda, RFC 5246 */
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */
+ "DHE-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA256, /* 0x0068 */
+ "DH-DSS-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA256, /* 0x0069 */
+ "DH-RSA-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, /* 0x006A */
+ "DHE-DSS-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */
+ "DHE-RSA-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA256, /* 0x006C */
+ "ADH-AES128-SHA256",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA256, /* 0x006D */
+ "ADH-AES256-SHA256",
+ CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* Addendum from RFC 4279, TLS PSK */
+ CIPHER_DEF(TLS_PSK_WITH_RC4_128_SHA, /* 0x008A */
+ "PSK-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008B */
+ "PSK-3DES-EDE-CBC-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA, /* 0x008C */
+ "PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA, /* 0x008D */
+ "PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_RC4_128_SHA, /* 0x008E */
+ "DHE-PSK-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008F */
+ "DHE-PSK-3DES-EDE-CBC-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, /* 0x0090 */
+ "DHE-PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, /* 0x0091 */
+ "DHE-PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_RC4_128_SHA, /* 0x0092 */
+ "RSA-PSK-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x0093 */
+ "RSA-PSK-3DES-EDE-CBC-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, /* 0x0094 */
+ "RSA-PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, /* 0x0095 */
+ "RSA-PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites
+ for TLS. */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ "AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
+ "AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */
+ "DHE-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */
+ "DHE-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_GCM_SHA256, /* 0x00A0 */
+ "DH-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_GCM_SHA384, /* 0x00A1 */
+ "DH-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A2 */
+ "DHE-DSS-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A3 */
+ "DHE-DSS-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A4 */
+ "DH-DSS-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A5 */
+ "DH-DSS-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_128_GCM_SHA256, /* 0x00A6 */
+ "ADH-AES128-GCM-SHA256",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_256_GCM_SHA384, /* 0x00A7 */
+ "ADH-AES256-GCM-SHA384",
+ CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* RFC 5487 - PSK with SHA-256/384 and AES GCM */
+ CIPHER_DEF(TLS_PSK_WITH_AES_128_GCM_SHA256, /* 0x00A8 */
+ "PSK-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_256_GCM_SHA384, /* 0x00A9 */
+ "PSK-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AA */
+ "DHE-PSK-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AB */
+ "DHE-PSK-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AC */
+ "RSA-PSK-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AD */
+ "RSA-PSK-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA256, /* 0x00AE */
+ "PSK-AES128-CBC-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA384, /* 0x00AF */
+ "PSK-AES256-CBC-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_NULL_SHA256, /* 0x00B0 */
+ "PSK-NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_PSK_WITH_NULL_SHA384, /* 0x00B1 */
+ "PSK-NULL-SHA384",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B2 */
+ "DHE-PSK-AES128-CBC-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B3 */
+ "DHE-PSK-AES256-CBC-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA256, /* 0x00B4 */
+ "DHE-PSK-NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA384, /* 0x00B5 */
+ "DHE-PSK-NULL-SHA384",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B6 */
+ "RSA-PSK-AES128-CBC-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B7 */
+ "RSA-PSK-AES256-CBC-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA256, /* 0x00B8 */
+ "RSA-PSK-NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA384, /* 0x00B9 */
+ "RSA-PSK-NULL-SHA384",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+ /* RFC 5746 - Secure Renegotiation. This is not a real suite,
+ it is a response to initiate negotiation again */
+ CIPHER_DEF(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, /* 0x00FF */
+ NULL,
+ CIPHER_STRONG_ENOUGH),
+
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305.
+ Note: TLS 1.3 ciphersuites do not specify the key exchange
+ algorithm -- they only specify the symmetric ciphers.
+ Cipher alias name matches to OpenSSL cipher name, and for
+ TLS 1.3 ciphers */
+ CIPHER_DEF(TLS_AES_128_GCM_SHA256, /* 0x1301 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_AES_256_GCM_SHA384, /* 0x1302 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_AES_128_CCM_SHA256, /* 0x1304 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_AES_128_CCM_8_SHA256, /* 0x1305 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+
+#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
+ /* ECDSA addenda, RFC 4492 */
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_NULL_SHA, /* 0xC001 */
+ "ECDH-ECDSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* 0xC002 */
+ "ECDH-ECDSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
+ "ECDH-ECDSA-DES-CBC3-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
+ "ECDH-ECDSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
+ "ECDH-ECDSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_NULL_SHA, /* 0xC006 */
+ "ECDHE-ECDSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, /* 0xC007 */
+ "ECDHE-ECDSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
+ "ECDHE-ECDSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ "ECDHE-ECDSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ "ECDHE-ECDSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_NULL_SHA, /* 0xC00B */
+ "ECDH-RSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_RC4_128_SHA, /* 0xC00C */
+ "ECDH-RSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
+ "ECDH-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
+ "ECDH-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
+ "ECDH-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_NULL_SHA, /* 0xC010 */
+ "ECDHE-RSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_RC4_128_SHA, /* 0xC011 */
+ "ECDHE-RSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
+ "ECDHE-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ "ECDHE-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
+ "ECDHE-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_NULL_SHA, /* 0xC015 */
+ "AECDH-NULL-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_RC4_128_SHA, /* 0xC016 */
+ "AECDH-RC4-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, /* 0xC017 */
+ "AECDH-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, /* 0xC018 */
+ "AECDH-AES128-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, /* 0xC019 */
+ "AECDH-AES256-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
+ HMAC SHA-256/384. */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ "ECDHE-ECDSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ "ECDHE-ECDSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
+ "ECDH-ECDSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
+ "ECDH-ECDSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ "ECDHE-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ "ECDHE-RSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
+ "ECDH-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
+ "ECDH-RSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
+ SHA-256/384 and AES Galois Counter Mode (GCM) */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ "ECDHE-ECDSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ "ECDHE-ECDSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
+ "ECDH-ECDSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
+ "ECDH-ECDSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ "ECDHE-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
+ "ECDH-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
+ "ECDH-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
+ /* ECDHE_PSK Cipher Suites for Transport Layer Security (TLS), RFC 5489 */
+ CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, /* 0xC035 */
+ "ECDHE-PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, /* 0xC036 */
+ "ECDHE-PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
+
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ /* Addenda from rfc 7905 ChaCha20-Poly1305 Cipher Suites for
+ Transport Layer Security (TLS). */
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ "ECDHE-RSA-CHACHA20-POLY1305",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
+ "ECDHE-ECDSA-CHACHA20-POLY1305",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+
+#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
+ /* ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS),
+ RFC 7905 */
+ CIPHER_DEF(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCAB */
+ "PSK-CHACHA20-POLY1305",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
+
+ /* Tags for SSL 2 cipher kinds which are not specified for SSL 3.
+ Defined since SDK 10.2.8 */
+ CIPHER_DEF(SSL_RSA_WITH_RC2_CBC_MD5, /* 0xFF80 */
+ NULL,
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(SSL_RSA_WITH_IDEA_CBC_MD5, /* 0xFF81 */
+ NULL,
+ CIPHER_WEAK_IDEA_ENCRYPTION),
+ CIPHER_DEF(SSL_RSA_WITH_DES_CBC_MD5, /* 0xFF82 */
+ NULL,
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF(SSL_RSA_WITH_3DES_EDE_CBC_MD5, /* 0xFF83 */
+ NULL,
+ CIPHER_WEAK_3DES_ENCRYPTION),
+};
+
+#define NUM_OF_CIPHERS sizeof(ciphertable)/sizeof(ciphertable[0])
+
+
/* pinned public key support tests */
/* version 1 supports macOS 10.12+ and iOS 10+ */
@@ -295,586 +932,23 @@ static OSStatus SocketWrite(SSLConnectionRef connection,
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
-CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher)
-{
- switch(cipher) {
- /* SSL version 3.0 */
- case SSL_RSA_WITH_NULL_MD5:
- return "SSL_RSA_WITH_NULL_MD5";
- break;
- case SSL_RSA_WITH_NULL_SHA:
- return "SSL_RSA_WITH_NULL_SHA";
- break;
- case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
- return "SSL_RSA_EXPORT_WITH_RC4_40_MD5";
- break;
- case SSL_RSA_WITH_RC4_128_MD5:
- return "SSL_RSA_WITH_RC4_128_MD5";
- break;
- case SSL_RSA_WITH_RC4_128_SHA:
- return "SSL_RSA_WITH_RC4_128_SHA";
- break;
- case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
- return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5";
- break;
- case SSL_RSA_WITH_IDEA_CBC_SHA:
- return "SSL_RSA_WITH_IDEA_CBC_SHA";
- break;
- case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_RSA_WITH_DES_CBC_SHA:
- return "SSL_RSA_WITH_DES_CBC_SHA";
- break;
- case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
- return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DH_DSS_WITH_DES_CBC_SHA:
- return "SSL_DH_DSS_WITH_DES_CBC_SHA";
- break;
- case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DH_RSA_WITH_DES_CBC_SHA:
- return "SSL_DH_RSA_WITH_DES_CBC_SHA";
- break;
- case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DHE_DSS_WITH_DES_CBC_SHA:
- return "SSL_DHE_DSS_WITH_DES_CBC_SHA";
- break;
- case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DHE_RSA_WITH_DES_CBC_SHA:
- return "SSL_DHE_RSA_WITH_DES_CBC_SHA";
- break;
- case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
- return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5";
- break;
- case SSL_DH_anon_WITH_RC4_128_MD5:
- return "SSL_DH_anon_WITH_RC4_128_MD5";
- break;
- case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
- return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA";
- break;
- case SSL_DH_anon_WITH_DES_CBC_SHA:
- return "SSL_DH_anon_WITH_DES_CBC_SHA";
- break;
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
- return "SSL_FORTEZZA_DMS_WITH_NULL_SHA";
- break;
- case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
- return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA";
- break;
- /* TLS 1.0 with AES (RFC 3268)
- (Apparently these are used in SSLv3 implementations as well.) */
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
- break;
- /* SSL version 2.0 */
- case SSL_RSA_WITH_RC2_CBC_MD5:
- return "SSL_RSA_WITH_RC2_CBC_MD5";
- break;
- case SSL_RSA_WITH_IDEA_CBC_MD5:
- return "SSL_RSA_WITH_IDEA_CBC_MD5";
- break;
- case SSL_RSA_WITH_DES_CBC_MD5:
- return "SSL_RSA_WITH_DES_CBC_MD5";
- break;
- case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
- return "SSL_RSA_WITH_3DES_EDE_CBC_MD5";
- break;
- }
- return "SSL_NULL_WITH_NULL_NULL";
-}
-
CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
{
- switch(cipher) {
- /* TLS 1.0 with AES (RFC 3268) */
- case TLS_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
- break;
-#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
- /* TLS 1.0 with ECDSA (RFC 4492) */
- case TLS_ECDH_ECDSA_WITH_NULL_SHA:
- return "TLS_ECDH_ECDSA_WITH_NULL_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
- return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
- return "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
- return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDH_RSA_WITH_NULL_SHA:
- return "TLS_ECDH_RSA_WITH_NULL_SHA";
- break;
- case TLS_ECDH_RSA_WITH_RC4_128_SHA:
- return "TLS_ECDH_RSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_NULL_SHA:
- return "TLS_ECDHE_RSA_WITH_NULL_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
- return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
- return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
- break;
- case TLS_ECDH_anon_WITH_NULL_SHA:
- return "TLS_ECDH_anon_WITH_NULL_SHA";
- break;
- case TLS_ECDH_anon_WITH_RC4_128_SHA:
- return "TLS_ECDH_anon_WITH_RC4_128_SHA";
- break;
- case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
- return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
- return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA";
- break;
- case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
- return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
- break;
-#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
-#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- /* TLS 1.2 (RFC 5246) */
- case TLS_RSA_WITH_NULL_MD5:
- return "TLS_RSA_WITH_NULL_MD5";
- break;
- case TLS_RSA_WITH_NULL_SHA:
- return "TLS_RSA_WITH_NULL_SHA";
- break;
- case TLS_RSA_WITH_RC4_128_MD5:
- return "TLS_RSA_WITH_RC4_128_MD5";
- break;
- case TLS_RSA_WITH_RC4_128_SHA:
- return "TLS_RSA_WITH_RC4_128_SHA";
- break;
- case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_RSA_WITH_NULL_SHA256:
- return "TLS_RSA_WITH_NULL_SHA256";
- break;
- case TLS_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_RSA_WITH_AES_256_CBC_SHA256:
- return "TLS_RSA_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
- return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
- return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
- return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
- return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
- return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
- return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
- break;
- case TLS_DH_anon_WITH_RC4_128_MD5:
- return "TLS_DH_anon_WITH_RC4_128_MD5";
- break;
- case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
- return "TLS_DH_anon_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
- return "TLS_DH_anon_WITH_AES_256_CBC_SHA256";
- break;
- /* TLS 1.2 with AES GCM (RFC 5288) */
- case TLS_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
- return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
- return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
- return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
- return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
- return "TLS_DH_anon_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
- return "TLS_DH_anon_WITH_AES_256_GCM_SHA384";
- break;
- /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */
- case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
- return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
- return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
- return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
- return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
- return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
- break;
-#else
- case SSL_RSA_WITH_NULL_MD5:
- return "TLS_RSA_WITH_NULL_MD5";
- break;
- case SSL_RSA_WITH_NULL_SHA:
- return "TLS_RSA_WITH_NULL_SHA";
- break;
- case SSL_RSA_WITH_RC4_128_MD5:
- return "TLS_RSA_WITH_RC4_128_MD5";
- break;
- case SSL_RSA_WITH_RC4_128_SHA:
- return "TLS_RSA_WITH_RC4_128_SHA";
- break;
- case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
- return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
- break;
- case SSL_DH_anon_WITH_RC4_128_MD5:
- return "TLS_DH_anon_WITH_RC4_128_MD5";
- break;
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
- break;
-#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- /* TLS PSK (RFC 4279): */
- case TLS_PSK_WITH_RC4_128_SHA:
- return "TLS_PSK_WITH_RC4_128_SHA";
- break;
- case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
- return "TLS_PSK_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_PSK_WITH_AES_128_CBC_SHA:
- return "TLS_PSK_WITH_AES_128_CBC_SHA";
- break;
- case TLS_PSK_WITH_AES_256_CBC_SHA:
- return "TLS_PSK_WITH_AES_256_CBC_SHA";
- break;
- case TLS_DHE_PSK_WITH_RC4_128_SHA:
- return "TLS_DHE_PSK_WITH_RC4_128_SHA";
- break;
- case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
- return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
- return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA";
- break;
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
- return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA";
- break;
- case TLS_RSA_PSK_WITH_RC4_128_SHA:
- return "TLS_RSA_PSK_WITH_RC4_128_SHA";
- break;
- case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
- return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA";
- break;
- case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
- return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA";
- break;
- case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
- return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA";
- break;
- /* More TLS PSK (RFC 4785): */
- case TLS_PSK_WITH_NULL_SHA:
- return "TLS_PSK_WITH_NULL_SHA";
- break;
- case TLS_DHE_PSK_WITH_NULL_SHA:
- return "TLS_DHE_PSK_WITH_NULL_SHA";
- break;
- case TLS_RSA_PSK_WITH_NULL_SHA:
- return "TLS_RSA_PSK_WITH_NULL_SHA";
- break;
- /* Even more TLS PSK (RFC 5487): */
- case TLS_PSK_WITH_AES_128_GCM_SHA256:
- return "TLS_PSK_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_PSK_WITH_AES_256_GCM_SHA384:
- return "TLS_PSK_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
- return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
- return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
- return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256";
- break;
- case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
- return "TLS_PSK_WITH_AES_256_GCM_SHA384";
- break;
- case TLS_PSK_WITH_AES_128_CBC_SHA256:
- return "TLS_PSK_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_PSK_WITH_AES_256_CBC_SHA384:
- return "TLS_PSK_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_PSK_WITH_NULL_SHA256:
- return "TLS_PSK_WITH_NULL_SHA256";
- break;
- case TLS_PSK_WITH_NULL_SHA384:
- return "TLS_PSK_WITH_NULL_SHA384";
- break;
- case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
- return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
- return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_DHE_PSK_WITH_NULL_SHA256:
- return "TLS_DHE_PSK_WITH_NULL_SHA256";
- break;
- case TLS_DHE_PSK_WITH_NULL_SHA384:
- return "TLS_RSA_PSK_WITH_NULL_SHA384";
- break;
- case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
- return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256";
- break;
- case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
- return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384";
- break;
- case TLS_RSA_PSK_WITH_NULL_SHA256:
- return "TLS_RSA_PSK_WITH_NULL_SHA256";
- break;
- case TLS_RSA_PSK_WITH_NULL_SHA384:
- return "TLS_RSA_PSK_WITH_NULL_SHA384";
- break;
-#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
-#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
- /* New ChaCha20+Poly1305 cipher-suites used by TLS 1.3: */
- case TLS_AES_128_GCM_SHA256:
- return "TLS_AES_128_GCM_SHA256";
- break;
- case TLS_AES_256_GCM_SHA384:
- return "TLS_AES_256_GCM_SHA384";
- break;
- case TLS_CHACHA20_POLY1305_SHA256:
- return "TLS_CHACHA20_POLY1305_SHA256";
- break;
- case TLS_AES_128_CCM_SHA256:
- return "TLS_AES_128_CCM_SHA256";
- break;
- case TLS_AES_128_CCM_8_SHA256:
- return "TLS_AES_128_CCM_8_SHA256";
- break;
- case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
- return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256";
- break;
- case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
- return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256";
- break;
-#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+ /* The first ciphers in the ciphertable are continuos. Here we do small
+ optimization and instead of loop directly get SSL name by cipher number.
+ */
+ if(cipher <= SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) {
+ return ciphertable[cipher].name;
+ }
+ /* Iterate through the rest of the ciphers */
+ for(size_t i = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA + 1;
+ i < NUM_OF_CIPHERS;
+ ++i) {
+ if(ciphertable[i].num == cipher) {
+ return ciphertable[i].name;
+ }
}
- return "TLS_NULL_WITH_NULL_NULL";
+ return ciphertable[SSL_NULL_WITH_NULL_NULL].name;
}
#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
@@ -1087,12 +1161,14 @@ static OSStatus CopyIdentityWithLabel(char *label,
(SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
err = SecIdentityCopyCertificate(identity, &cert);
if(err == noErr) {
+ OSStatus copy_status = noErr;
#if CURL_BUILD_IOS
common_name = SecCertificateCopySubjectSummary(cert);
#elif CURL_BUILD_MAC_10_7
- SecCertificateCopyCommonName(cert, &common_name);
+ copy_status = SecCertificateCopyCommonName(cert, &common_name);
#endif
- if(CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
+ if(copy_status == noErr &&
+ CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
CFRelease(cert);
CFRelease(common_name);
CFRetain(identity);
@@ -1253,7 +1329,7 @@ CF_INLINE bool is_file(const char *filename)
{
struct_stat st;
- if(filename == NULL)
+ if(!filename)
return false;
if(stat(filename, &st) == 0)
@@ -1386,6 +1462,200 @@ set_ssl_version_min_max(struct Curl_easy *data, struct connectdata *conn,
return CURLE_SSL_CONNECT_ERROR;
}
+static bool is_cipher_suite_strong(SSLCipherSuite suite_num)
+{
+ for(size_t i = 0; i < NUM_OF_CIPHERS; ++i) {
+ if(ciphertable[i].num == suite_num) {
+ return !ciphertable[i].weak;
+ }
+ }
+ /* If the cipher is not in our list, assume it is a new one
+ and therefore strong. Previous implementation was the same,
+ if cipher suite is not in the list, it was considered strong enough */
+ return true;
+}
+
+static bool is_separator(char c)
+{
+ /* Return whether character is a cipher list separator. */
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
+ }
+ return false;
+}
+
+static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
+ SSLContextRef ssl_ctx)
+{
+ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
+ SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+ OSStatus err = noErr;
+
+#if CURL_BUILD_MAC
+ int darwinver_maj = 0, darwinver_min = 0;
+
+ GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif /* CURL_BUILD_MAC */
+
+ /* Disable cipher suites that ST supports but are not safe. These ciphers
+ are unlikely to be used in any case since ST gives other ciphers a much
+ higher priority, but it's probably better that we not connect at all than
+ to give the user a false sense of security if the server only supports
+ insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
+ err = SSLGetNumberSupportedCiphers(ssl_ctx, &all_ciphers_count);
+ if(err != noErr) {
+ failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
+ err);
+ return CURLE_SSL_CIPHER;
+ }
+ all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(!all_ciphers) {
+ failf(data, "SSL: Failed to allocate memory for all ciphers");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(!allowed_ciphers) {
+ Curl_safefree(all_ciphers);
+ failf(data, "SSL: Failed to allocate memory for allowed ciphers");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ err = SSLGetSupportedCiphers(ssl_ctx, all_ciphers,
+ &all_ciphers_count);
+ if(err != noErr) {
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ for(i = 0UL ; i < all_ciphers_count ; i++) {
+#if CURL_BUILD_MAC
+ /* There's a known bug in early versions of Mountain Lion where ST's ECC
+ ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+ Work around the problem here by disabling those ciphers if we are
+ running in an affected version of OS X. */
+ if(darwinver_maj == 12 && darwinver_min <= 3 &&
+ all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
+ continue;
+ }
+#endif /* CURL_BUILD_MAC */
+ if(is_cipher_suite_strong(all_ciphers[i])) {
+ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ }
+ }
+ err = SSLSetEnabledCiphers(ssl_ctx, allowed_ciphers,
+ allowed_ciphers_count);
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+ return CURLE_SSL_CIPHER;
+ }
+ return CURLE_OK;
+}
+
+static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
+ SSLContextRef ssl_ctx,
+ const char *ciphers)
+{
+ size_t ciphers_count = 0;
+ const char *cipher_start = ciphers;
+ OSStatus err = noErr;
+ SSLCipherSuite selected_ciphers[NUM_OF_CIPHERS];
+
+ if(!ciphers)
+ return CURLE_OK;
+
+ while(is_separator(*ciphers)) /* Skip initial separators. */
+ ciphers++;
+ if(!*ciphers)
+ return CURLE_OK;
+
+ cipher_start = ciphers;
+ while(*cipher_start && ciphers_count < NUM_OF_CIPHERS) {
+ bool cipher_found = FALSE;
+ size_t cipher_len = 0;
+ const char *cipher_end = NULL;
+ bool tls_name = FALSE;
+
+ /* Skip separators */
+ while(is_separator(*cipher_start))
+ cipher_start++;
+ if(*cipher_start == '\0') {
+ break;
+ }
+ /* Find last position of a cipher in the ciphers string */
+ cipher_end = cipher_start;
+ while (*cipher_end != '\0' && !is_separator(*cipher_end)) {
+ ++cipher_end;
+ }
+
+ /* IANA cipher names start with the TLS_ or SSL_ prefix.
+ If the 4th symbol of the cipher is '_' we look for a cipher in the
+ table by its (TLS) name.
+ Otherwise, we try to match cipher by an alias. */
+ if(cipher_start[3] == '_') {
+ tls_name = TRUE;
+ }
+ /* Iterate through the cipher table and look for the cipher, starting
+ the cipher number 0x01 because the 0x00 is not the real cipher */
+ cipher_len = cipher_end - cipher_start;
+ for(size_t i = 1; i < NUM_OF_CIPHERS; ++i) {
+ const char *table_cipher_name = NULL;
+ if(tls_name) {
+ table_cipher_name = ciphertable[i].name;
+ }
+ else if(ciphertable[i].alias_name != NULL) {
+ table_cipher_name = ciphertable[i].alias_name;
+ }
+ else {
+ continue;
+ }
+ /* Compare a part of the string between separators with a cipher name
+ in the table and make sure we matched the whole cipher name */
+ if(strncmp(cipher_start, table_cipher_name, cipher_len) == 0
+ && table_cipher_name[cipher_len] == '\0') {
+ selected_ciphers[ciphers_count] = ciphertable[i].num;
+ ++ciphers_count;
+ cipher_found = TRUE;
+ break;
+ }
+ }
+ if(!cipher_found) {
+ /* It would be more human-readable if we print the wrong cipher name
+ but we don't want to allocate any additional memory and copy the name
+ into it, then add it into logs.
+ Also, we do not modify an original cipher list string. We just point
+ to positions where cipher starts and ends in the cipher list string.
+ The message is a bit cryptic and longer than necessary but can be
+ understood by humans. */
+ failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name"
+ " starting position %d and ending position %d",
+ ciphers,
+ cipher_start - ciphers,
+ cipher_end - ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ if(*cipher_end) {
+ cipher_start = cipher_end + 1;
+ }
+ else {
+ break;
+ }
+ }
+ /* All cipher suites in the list are found. Report to logs as-is */
+ infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers);
+
+ err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+ return CURLE_SSL_CIPHER;
+ }
+ return CURLE_OK;
+}
static CURLcode sectransp_connect_step1(struct Curl_easy *data,
struct connectdata *conn,
@@ -1394,26 +1664,22 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
curl_socket_t sockfd = conn->sock[sockindex];
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 *ssl_cablob = NULL;
+ const struct curl_blob *ssl_cablob = SSL_CONN_CONFIG(ca_info_blob);
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ssl_cablob ? NULL : SSL_CONN_CONFIG(CAfile));
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
char * const ssl_cert = SSL_SET_OPTION(primary.clientcert);
const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(primary.cert_blob);
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
- const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
- const char * const hostname = conn->host.name;
- const long int port = conn->remote_port;
-#endif
+ bool isproxy = SSL_IS_PROXY();
+ const char * const hostname = SSL_HOST_NAME();
+ const long int port = SSL_HOST_PORT();
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif /* ENABLE_IPV6 */
- size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
- SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+ char *ciphers;
OSStatus err = noErr;
#if CURL_BUILD_MAC
int darwinver_maj = 0, darwinver_min = 0;
@@ -1484,21 +1750,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
break;
}
case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionMin(backend->ssl_ctx, kSSLProtocol3);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kSSLProtocol3);
- break;
case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionMin(backend->ssl_ctx, kSSLProtocol2);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kSSLProtocol2);
- break;
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
@@ -1533,23 +1787,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
break;
}
case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(backend->ssl_ctx,
- kSSLProtocol3,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(backend->ssl_ctx,
- kSSLProtocol2,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
@@ -1581,23 +1821,9 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
failf(data, "Your version of the OS does not support TLSv1.3");
return CURLE_SSL_CONNECT_ERROR;
case CURL_SSLVERSION_SSLv2:
- err = SSLSetProtocolVersionEnabled(backend->ssl_ctx,
- kSSLProtocol2,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
case CURL_SSLVERSION_SSLv3:
- err = SSLSetProtocolVersionEnabled(backend->ssl_ctx,
- kSSLProtocol3,
- true);
- if(err != noErr) {
- failf(data, "Your version of the OS does not support SSLv3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
@@ -1610,26 +1836,26 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
CFMutableArrayRef alpnArr = CFArrayCreateMutable(NULL, 0,
&kCFTypeArrayCallBacks);
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2
#ifndef CURL_DISABLE_PROXY
- && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+ && (!isproxy || !conn->bits.tunnel_proxy)
#endif
) {
- CFArrayAppendValue(alpnArr, CFSTR(NGHTTP2_PROTO_VERSION_ID));
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ CFArrayAppendValue(alpnArr, CFSTR(ALPN_H2));
+ infof(data, "ALPN, offering %s", ALPN_H2);
}
#endif
CFArrayAppendValue(alpnArr, CFSTR(ALPN_HTTP_1_1));
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
/* expects length prefixed preference ordered list of protocols in wire
* format
*/
err = SSLSetALPNProtocols(backend->ssl_ctx, alpnArr);
if(err != noErr)
- infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d\n",
+ infof(data, "WARNING: failed to set ALPN protocols; OSStatus %d",
err);
CFRelease(alpnArr);
}
@@ -1638,7 +1864,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
if(SSL_SET_OPTION(key)) {
infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
- "Transport. The private key must be in the Keychain.\n");
+ "Transport. The private key must be in the Keychain.");
}
if(ssl_cert || ssl_cert_blob) {
@@ -1646,24 +1872,28 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
SecIdentityRef cert_and_key = NULL;
- /* User wants to authenticate with a client cert. Look for it:
- If we detect that this is a file on disk, then let's load it.
- Otherwise, assume that the user wants to use an identity loaded
- from the Keychain. */
- if(is_cert_file || is_cert_data) {
+ /* User wants to authenticate with a client cert. Look for it. Assume that
+ the user wants to use an identity loaded from the Keychain. If not, try
+ it as a file on disk */
+
+ if(!is_cert_data)
+ err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
+ else
+ err = !noErr;
+ if((err != noErr) && (is_cert_file || is_cert_data)) {
if(!SSL_SET_OPTION(cert_type))
- infof(data, "WARNING: SSL: Certificate type not set, assuming "
- "PKCS#12 format.\n");
- else if(strncmp(SSL_SET_OPTION(cert_type), "P12",
- strlen(SSL_SET_OPTION(cert_type))) != 0)
- infof(data, "WARNING: SSL: The Security framework only supports "
- "loading identities that are in PKCS#12 format.\n");
+ infof(data, "SSL: Certificate type not set, assuming "
+ "PKCS#12 format.");
+ else if(!strcasecompare(SSL_SET_OPTION(cert_type), "P12")) {
+ failf(data, "SSL: The Security framework only supports "
+ "loading identities that are in PKCS#12 format.");
+ return CURLE_SSL_CERTPROBLEM;
+ }
err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
- SSL_SET_OPTION(key_passwd), &cert_and_key);
+ SSL_SET_OPTION(key_passwd),
+ &cert_and_key);
}
- else
- err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
if(err == noErr && cert_and_key) {
SecCertificateRef cert = NULL;
@@ -1676,7 +1906,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
char *certp;
CURLcode result = CopyCertSubject(data, cert, &certp);
if(!result) {
- infof(data, "Client certificate: %s\n", certp);
+ infof(data, "Client certificate: %s", certp);
free(certp);
}
@@ -1788,7 +2018,8 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
if(!(is_cert_file || is_cert_data)) {
- failf(data, "SSL: can't load CA certificate file %s", ssl_cafile);
+ failf(data, "SSL: can't load CA certificate file %s",
+ ssl_cafile ? ssl_cafile : "(blob memory)");
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -1801,7 +2032,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
strlen(hostname));
if(err != noErr) {
- infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
+ infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d",
err);
}
@@ -1811,128 +2042,23 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
#endif
) {
infof(data, "WARNING: using IP address, SNI is being disabled by "
- "the OS.\n");
+ "the OS.");
}
}
else {
- infof(data, "WARNING: disabling hostname validation also disables SNI.\n");
+ infof(data, "WARNING: disabling hostname validation also disables SNI.");
}
- /* Disable cipher suites that ST supports but are not safe. These ciphers
- are unlikely to be used in any case since ST gives other ciphers a much
- higher priority, but it's probably better that we not connect at all than
- to give the user a false sense of security if the server only supports
- insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
- err = SSLGetNumberSupportedCiphers(backend->ssl_ctx, &all_ciphers_count);
- if(err != noErr) {
- failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
- err);
- return CURLE_SSL_CIPHER;
+ ciphers = SSL_CONN_CONFIG(cipher_list);
+ if(ciphers) {
+ err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
}
- all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- if(!all_ciphers) {
- failf(data, "SSL: Failed to allocate memory for all ciphers");
- return CURLE_OUT_OF_MEMORY;
- }
- allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
- if(!allowed_ciphers) {
- Curl_safefree(all_ciphers);
- failf(data, "SSL: Failed to allocate memory for allowed ciphers");
- return CURLE_OUT_OF_MEMORY;
- }
- err = SSLGetSupportedCiphers(backend->ssl_ctx, all_ciphers,
- &all_ciphers_count);
- if(err != noErr) {
- Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
- return CURLE_SSL_CIPHER;
- }
- for(i = 0UL ; i < all_ciphers_count ; i++) {
-#if CURL_BUILD_MAC
- /* There's a known bug in early versions of Mountain Lion where ST's ECC
- ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
- Work around the problem here by disabling those ciphers if we are
- running in an affected version of OS X. */
- if(darwinver_maj == 12 && darwinver_min <= 3 &&
- all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
- continue;
- }
-#endif /* CURL_BUILD_MAC */
- switch(all_ciphers[i]) {
- /* Disable NULL ciphersuites: */
- case SSL_NULL_WITH_NULL_NULL:
- case SSL_RSA_WITH_NULL_MD5:
- case SSL_RSA_WITH_NULL_SHA:
- case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */
- case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
- case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
- case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
- case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */
- case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */
- case 0x002C: /* TLS_PSK_WITH_NULL_SHA */
- case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */
- case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */
- case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */
- case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */
- case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */
- case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */
- case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */
- case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */
- /* Disable anonymous ciphersuites: */
- case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
- case SSL_DH_anon_WITH_RC4_128_MD5:
- case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_anon_WITH_DES_CBC_SHA:
- case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
- case TLS_DH_anon_WITH_AES_128_CBC_SHA:
- case TLS_DH_anon_WITH_AES_256_CBC_SHA:
- case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */
- case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */
- case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
- case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
- case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
- case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
- case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
- case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
- case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
- /* Disable weak key ciphersuites: */
- case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
- case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
- case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
- case SSL_RSA_WITH_DES_CBC_SHA:
- case SSL_DH_DSS_WITH_DES_CBC_SHA:
- case SSL_DH_RSA_WITH_DES_CBC_SHA:
- case SSL_DHE_DSS_WITH_DES_CBC_SHA:
- case SSL_DHE_RSA_WITH_DES_CBC_SHA:
- /* Disable IDEA: */
- case SSL_RSA_WITH_IDEA_CBC_SHA:
- case SSL_RSA_WITH_IDEA_CBC_MD5:
- /* Disable RC4: */
- case SSL_RSA_WITH_RC4_128_MD5:
- case SSL_RSA_WITH_RC4_128_SHA:
- case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */
- case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/
- case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */
- case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */
- case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */
- case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */
- case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */
- break;
- default: /* enable everything else */
- allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
- break;
- }
+ else {
+ err = sectransp_set_default_ciphers(data, backend->ssl_ctx);
}
- err = SSLSetEnabledCiphers(backend->ssl_ctx, allowed_ciphers,
- allowed_ciphers_count);
- Curl_safefree(all_ciphers);
- Curl_safefree(allowed_ciphers);
if(err != noErr) {
- failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+ failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
+ "Error code: %d", err);
return CURLE_SSL_CIPHER;
}
@@ -1941,7 +2067,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
specifically doesn't want us doing that: */
if(SSLSetSessionOption != NULL) {
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
- !data->set.ssl.enable_beast);
+ !SSL_SET_OPTION(enable_beast));
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
data->set.ssl.falsestart); /* false start support */
}
@@ -1953,7 +2079,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, (void **)&ssl_sessionid,
+ if(!Curl_ssl_getsessionid(data, conn, isproxy, (void **)&ssl_sessionid,
&ssl_sessionid_len, sockindex)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -1963,14 +2089,15 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
/* Informational message */
- infof(data, "SSL re-using session ID\n");
+ infof(data, "SSL re-using session ID");
}
/* If there isn't one, then let's make one up! This has to be done prior
to starting the handshake. */
else {
CURLcode result;
ssl_sessionid =
- aprintf("%s:%d:%d:%s:%ld", ssl_cafile,
+ aprintf("%s:%d:%d:%s:%ld",
+ ssl_cafile ? ssl_cafile : "(blob memory)",
verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
ssl_sessionid_len = strlen(ssl_sessionid);
@@ -1981,7 +2108,7 @@ static CURLcode sectransp_connect_step1(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_addsessionid(data, conn, ssl_sessionid,
+ result = Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
ssl_sessionid_len, sockindex);
Curl_ssl_sessionid_unlock(data);
if(result) {
@@ -2021,21 +2148,21 @@ static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
/* Jump through the separators at the beginning of the certificate. */
sep_start = strstr(in, "-----");
- if(sep_start == NULL)
+ if(!sep_start)
return 0;
cert_start = strstr(sep_start + 1, "-----");
- if(cert_start == NULL)
+ if(!cert_start)
return -1;
cert_start += 5;
/* Find separator after the end of the certificate. */
cert_end = strstr(cert_start, "-----");
- if(cert_end == NULL)
+ if(!cert_end)
return -1;
sep_end = strstr(cert_end + 1, "-----");
- if(sep_end == NULL)
+ if(!sep_end)
return -1;
sep_end += 5;
@@ -2110,7 +2237,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
}
static int append_cert_to_array(struct Curl_easy *data,
- unsigned char *buf, size_t buflen,
+ const unsigned char *buf, size_t buflen,
CFMutableArrayRef array)
{
CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
@@ -2148,18 +2275,14 @@ static int append_cert_to_array(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
- SSLContextRef ctx)
+static CURLcode verify_cert_buf(struct Curl_easy *data,
+ const unsigned char *certbuf, size_t buflen,
+ SSLContextRef ctx)
{
int n = 0, rc;
long res;
- unsigned char *certbuf, *der;
- size_t buflen, derlen, offset = 0;
-
- if(read_cert(cafile, &certbuf, &buflen) < 0) {
- failf(data, "SSL: failed to read or invalid CA certificate");
- return CURLE_SSL_CACERT_BADFILE;
- }
+ unsigned char *der;
+ size_t derlen, offset = 0;
/*
* Certbuf now contains the contents of the certificate file, which can be
@@ -2172,8 +2295,7 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
*/
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
- if(array == NULL) {
- free(certbuf);
+ if(!array) {
failf(data, "SSL: out of memory creating CA certificate array");
return CURLE_OUT_OF_MEMORY;
}
@@ -2187,7 +2309,6 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
*/
res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
if(res < 0) {
- free(certbuf);
CFRelease(array);
failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
n, offset);
@@ -2198,7 +2319,6 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
if(res == 0 && offset == 0) {
/* This is not a PEM file, probably a certificate in DER format. */
rc = append_cert_to_array(data, certbuf, buflen, array);
- free(certbuf);
if(rc != CURLE_OK) {
CFRelease(array);
return rc;
@@ -2207,14 +2327,12 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
}
else if(res == 0) {
/* No more certificates in the bundle. */
- free(certbuf);
break;
}
rc = append_cert_to_array(data, der, derlen, array);
free(der);
if(rc != CURLE_OK) {
- free(certbuf);
CFRelease(array);
return rc;
}
@@ -2222,7 +2340,7 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
SecTrustRef trust;
OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
- if(trust == NULL) {
+ if(!trust) {
failf(data, "SSL: error getting certificate chain");
CFRelease(array);
return CURLE_PEER_FAILED_VERIFICATION;
@@ -2271,6 +2389,38 @@ static CURLcode verify_cert(const char *cafile, struct Curl_easy *data,
}
}
+static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
+ const struct curl_blob *ca_info_blob,
+ SSLContextRef ctx)
+{
+ int result;
+ unsigned char *certbuf;
+ size_t buflen;
+
+ if(ca_info_blob) {
+ certbuf = (unsigned char *)malloc(ca_info_blob->len + 1);
+ if(!certbuf) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ buflen = ca_info_blob->len;
+ memcpy(certbuf, ca_info_blob->data, ca_info_blob->len);
+ certbuf[ca_info_blob->len]='\0';
+ }
+ else if(cafile) {
+ if(read_cert(cafile, &certbuf, &buflen) < 0) {
+ failf(data, "SSL: failed to read or invalid CA certificate");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else
+ return CURLE_SSL_CACERT_BADFILE;
+
+ result = verify_cert_buf(data, certbuf, buflen, ctx);
+ free(certbuf);
+ return result;
+}
+
+
#ifdef SECTRANSP_PINNEDPUBKEY
static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
SSLContextRef ctx,
@@ -2295,19 +2445,19 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
do {
SecTrustRef trust;
OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
- if(ret != noErr || trust == NULL)
+ if(ret != noErr || !trust)
break;
SecKeyRef keyRef = SecTrustCopyPublicKey(trust);
CFRelease(trust);
- if(keyRef == NULL)
+ if(!keyRef)
break;
#ifdef SECTRANSP_PINNEDPUBKEY_V1
publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL);
CFRelease(keyRef);
- if(publicKeyBits == NULL)
+ if(!publicKeyBits)
break;
#elif SECTRANSP_PINNEDPUBKEY_V2
@@ -2315,7 +2465,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
&publicKeyBits);
CFRelease(keyRef);
- if(success != errSecSuccess || publicKeyBits == NULL)
+ if(success != errSecSuccess || !publicKeyBits)
break;
#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
@@ -2344,7 +2494,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
spkiHeaderLength = 23;
break;
default:
- infof(data, "SSL: unhandled public key length: %d\n", pubkeylen);
+ infof(data, "SSL: unhandled public key length: %d", pubkeylen);
#elif SECTRANSP_PINNEDPUBKEY_V2
default:
/* ecDSA secp256r1 pubkeylen == 91 header already included?
@@ -2387,12 +2537,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
OSStatus err;
SSLCipherSuite cipher;
SSLProtocol protocol = 0;
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- const char * const hostname = conn->host.name;
-#endif
+ const char * const hostname = SSL_HOST_NAME();
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
@@ -2411,8 +2556,10 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
/* The below is errSSLServerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
- CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data,
+ if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
+ SSL_CONN_CONFIG(verifypeer)) {
+ CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
+ SSL_CONN_CONFIG(ca_info_blob),
backend->ssl_ctx);
if(result)
return result;
@@ -2599,8 +2746,9 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#if CURL_BUILD_MAC_10_6
/* Only returned when kSSLSessionOptionBreakOnCertRequested is set */
case errSSLClientCertRequested:
- failf(data, "The server has requested a client certificate");
- break;
+ failf(data, "Server requested a client certificate during the "
+ "handshake");
+ return CURLE_SSL_CLIENTCERT;
#endif
#if CURL_BUILD_MAC_10_9
/* Alias for errSSLLast, end of error range */
@@ -2621,9 +2769,10 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
connssl->connecting_state = ssl_connect_3;
#ifdef SECTRANSP_PINNEDPUBKEY
- if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) {
- CURLcode result = pkp_pin_peer_pubkey(data, backend->ssl_ctx,
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]);
+ if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) {
+ CURLcode result =
+ pkp_pin_peer_pubkey(data, backend->ssl_ctx,
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
if(result) {
failf(data, "SSL: public key does not match pinned public key!");
return result;
@@ -2636,35 +2785,35 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
(void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
switch(protocol) {
case kSSLProtocol2:
- infof(data, "SSL 2.0 connection using %s\n",
- SSLCipherNameForNumber(cipher));
+ infof(data, "SSL 2.0 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
case kSSLProtocol3:
- infof(data, "SSL 3.0 connection using %s\n",
- SSLCipherNameForNumber(cipher));
+ infof(data, "SSL 3.0 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
case kTLSProtocol1:
- infof(data, "TLS 1.0 connection using %s\n",
+ infof(data, "TLS 1.0 connection using %s",
TLSCipherNameForNumber(cipher));
break;
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
case kTLSProtocol11:
- infof(data, "TLS 1.1 connection using %s\n",
+ infof(data, "TLS 1.1 connection using %s",
TLSCipherNameForNumber(cipher));
break;
case kTLSProtocol12:
- infof(data, "TLS 1.2 connection using %s\n",
+ infof(data, "TLS 1.2 connection using %s",
TLSCipherNameForNumber(cipher));
break;
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
case kTLSProtocol13:
- infof(data, "TLS 1.3 connection using %s\n",
+ infof(data, "TLS 1.3 connection using %s",
TLSCipherNameForNumber(cipher));
break;
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
default:
- infof(data, "Unknown protocol connection\n");
+ infof(data, "Unknown protocol connection");
break;
}
@@ -2678,10 +2827,9 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
if(err == noErr && alpnArr && CFArrayGetCount(alpnArr) >= 1)
chosenProtocol = CFArrayGetValueAtIndex(alpnArr, 0);
-#ifdef USE_NGHTTP2
+#ifdef USE_HTTP2
if(chosenProtocol &&
- !CFStringCompare(chosenProtocol, CFSTR(NGHTTP2_PROTO_VERSION_ID),
- 0)) {
+ !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
@@ -2691,7 +2839,7 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn,
conn->negnpn = CURL_HTTP_VERSION_1_1;
}
else
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
@@ -2708,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;
@@ -2723,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
@@ -2734,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\n", certp);
- free(certp);
- }
+ result = collect_server_cert_single(data, server_cert, i);
}
CFRelease(trust);
}
@@ -2760,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\n", certp);
- free(certp);
- }
+ result = collect_server_cert_single(data, server_cert, i);
}
CFRelease(trust);
}
@@ -2779,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\n", certp);
- free(certp);
- }
+ result = collect_server_cert_single(data, server_cert, i);
}
CFRelease(server_certs);
}
@@ -2800,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\n", 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,
@@ -2823,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;
@@ -3007,6 +3188,7 @@ static int sectransp_shutdown(struct Curl_easy *data,
int what;
int rc;
char buf[120];
+ int loop = 10; /* avoid getting stuck */
if(!backend->ssl_ctx)
return 0;
@@ -3022,7 +3204,7 @@ static int sectransp_shutdown(struct Curl_easy *data,
what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
- for(;;) {
+ while(loop--) {
if(what < 0) {
/* anything that gets here is fatally bad */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -3041,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;
}
@@ -3255,8 +3439,10 @@ static ssize_t sectransp_recv(struct Curl_easy *data,
/* The below is errSSLPeerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
- if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
- CURLcode result = verify_cert(SSL_CONN_CONFIG(CAfile), data,
+ if((SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(ca_info_blob)) &&
+ SSL_CONN_CONFIG(verifypeer)) {
+ CURLcode result = verify_cert(data, SSL_CONN_CONFIG(CAfile),
+ SSL_CONN_CONFIG(ca_info_blob),
backend->ssl_ctx);
if(result)
return result;
@@ -3283,6 +3469,8 @@ static void *sectransp_get_internals(struct ssl_connect_data *connssl,
const struct Curl_ssl Curl_ssl_sectransp = {
{ CURLSSLBACKEND_SECURETRANSPORT, "secure-transport" }, /* info */
+ SSLSUPP_CAINFO_BLOB |
+ SSLSUPP_CERTINFO |
#ifdef SECTRANSP_PINNEDPUBKEY
SSLSUPP_PINNEDPUBKEY,
#else
@@ -3301,6 +3489,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_cert_status_request, /* cert_status_request */
sectransp_connect, /* connect */
sectransp_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -3309,7 +3498,9 @@ const struct Curl_ssl Curl_ssl_sectransp = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
sectransp_false_start, /* false_start */
- sectransp_sha256sum /* sha256sum */
+ sectransp_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#ifdef __clang__
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
index b8ab749..e5bbe1f 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.c
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -125,6 +125,16 @@ static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
return !memcmp(first->data, second->data, first->len); /* same data */
}
+static bool safecmp(char *a, char *b)
+{
+ if(a && b)
+ return !strcmp(a, b);
+ else if(!a && !b)
+ return TRUE; /* match */
+ return FALSE; /* no match */
+}
+
+
bool
Curl_ssl_config_matches(struct ssl_primary_config *data,
struct ssl_primary_config *needle)
@@ -135,11 +145,14 @@ Curl_ssl_config_matches(struct ssl_primary_config *data,
(data->verifyhost == needle->verifyhost) &&
(data->verifystatus == needle->verifystatus) &&
blobcmp(data->cert_blob, needle->cert_blob) &&
- Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
- Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
- Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
- Curl_safe_strcasecompare(data->random_file, needle->random_file) &&
- Curl_safe_strcasecompare(data->egdsocket, needle->egdsocket) &&
+ blobcmp(data->ca_info_blob, needle->ca_info_blob) &&
+ blobcmp(data->issuercert_blob, needle->issuercert_blob) &&
+ safecmp(data->CApath, needle->CApath) &&
+ safecmp(data->CAfile, needle->CAfile) &&
+ safecmp(data->issuercert, needle->issuercert) &&
+ safecmp(data->clientcert, needle->clientcert) &&
+ safecmp(data->random_file, needle->random_file) &&
+ safecmp(data->egdsocket, needle->egdsocket) &&
Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) &&
Curl_safe_strcasecompare(data->cipher_list13, needle->cipher_list13) &&
Curl_safe_strcasecompare(data->curves, needle->curves) &&
@@ -161,8 +174,11 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
dest->sessionid = source->sessionid;
CLONE_BLOB(cert_blob);
+ CLONE_BLOB(ca_info_blob);
+ CLONE_BLOB(issuercert_blob);
CLONE_STRING(CApath);
CLONE_STRING(CAfile);
+ CLONE_STRING(issuercert);
CLONE_STRING(clientcert);
CLONE_STRING(random_file);
CLONE_STRING(egdsocket);
@@ -178,6 +194,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
{
Curl_safefree(sslc->CApath);
Curl_safefree(sslc->CAfile);
+ Curl_safefree(sslc->issuercert);
Curl_safefree(sslc->clientcert);
Curl_safefree(sslc->random_file);
Curl_safefree(sslc->egdsocket);
@@ -185,6 +202,8 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
Curl_safefree(sslc->cipher_list13);
Curl_safefree(sslc->pinned_key);
Curl_safefree(sslc->cert_blob);
+ Curl_safefree(sslc->ca_info_blob);
+ Curl_safefree(sslc->issuercert_blob);
Curl_safefree(sslc->curves);
}
@@ -315,13 +334,15 @@ Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
if(!result)
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
+ else
+ conn->ssl[sockindex].use = FALSE;
return result;
}
CURLcode
Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
- int sockindex, bool *done)
+ bool isproxy, int sockindex, bool *done)
{
CURLcode result;
@@ -338,7 +359,9 @@ Curl_ssl_connect_nonblocking(struct Curl_easy *data, struct connectdata *conn,
/* mark this is being ssl requested from here on. */
conn->ssl[sockindex].use = TRUE;
result = Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
- if(!result && *done)
+ if(result)
+ conn->ssl[sockindex].use = FALSE;
+ else if(*done && !isproxy)
Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSL is connected */
return result;
}
@@ -367,6 +390,7 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
*/
bool Curl_ssl_getsessionid(struct Curl_easy *data,
struct connectdata *conn,
+ const bool isProxy,
void **ssl_sessionid,
size_t *idsize, /* set 0 if unknown */
int sockindex)
@@ -377,7 +401,6 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
bool no_match = TRUE;
#ifndef CURL_DISABLE_PROXY
- const bool isProxy = CONNECT_PROXY_SSL();
struct ssl_primary_config * const ssl_config = isProxy ?
&conn->proxy_ssl_config :
&conn->ssl_config;
@@ -389,14 +412,20 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
struct ssl_primary_config * const ssl_config = &conn->ssl_config;
const char * const name = conn->host.name;
int port = conn->remote_port;
- (void)sockindex;
#endif
+ (void)sockindex;
*ssl_sessionid = NULL;
+#ifdef CURL_DISABLE_PROXY
+ if(isProxy)
+ return TRUE;
+#endif
+
DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
- if(!SSL_SET_OPTION(primary.sessionid))
- /* session ID re-use is disabled */
+ if(!SSL_SET_OPTION(primary.sessionid) || !data->state.session)
+ /* session ID re-use is disabled or the session cache has not been
+ setup */
return TRUE;
/* Lock if shared */
@@ -431,6 +460,10 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
}
}
+ DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
+ no_match? "Didn't find": "Found",
+ isProxy ? "proxy" : "host",
+ conn->handler->scheme, name, port));
return no_match;
}
@@ -480,31 +513,34 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
*/
CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
struct connectdata *conn,
+ const bool isProxy,
void *ssl_sessionid,
size_t idsize,
int sockindex)
{
size_t i;
- struct Curl_ssl_session *store = &data->state.session[0];
- long oldest_age = data->state.session[0].age; /* zero if unused */
+ struct Curl_ssl_session *store;
+ long oldest_age;
char *clone_host;
char *clone_conn_to_host;
int conn_to_port;
long *general_age;
#ifndef CURL_DISABLE_PROXY
- const bool isProxy = CONNECT_PROXY_SSL();
struct ssl_primary_config * const ssl_config = isProxy ?
&conn->proxy_ssl_config :
&conn->ssl_config;
const char *hostname = isProxy ? conn->http_proxy.host.name :
conn->host.name;
#else
- /* proxy support disabled */
- const bool isProxy = FALSE;
struct ssl_primary_config * const ssl_config = &conn->ssl_config;
const char *hostname = conn->host.name;
- (void)sockindex;
#endif
+ (void)sockindex;
+ if(!data->state.session)
+ return CURLE_OK;
+
+ store = &data->state.session[0];
+ oldest_age = data->state.session[0].age; /* zero if unused */
DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
clone_host = strdup(hostname);
@@ -573,9 +609,31 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
+ DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
+ store->scheme, store->name, store->remote_port,
+ isProxy ? "PROXY" : "server"));
return CURLE_OK;
}
+void Curl_ssl_associate_conn(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(Curl_ssl->associate_connection) {
+ Curl_ssl->associate_connection(data, conn, FIRSTSOCKET);
+ if(conn->sock[SECONDARYSOCKET] && conn->bits.sock_accepted)
+ Curl_ssl->associate_connection(data, conn, SECONDARYSOCKET);
+ }
+}
+
+void Curl_ssl_detach_conn(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(Curl_ssl->disassociate_connection) {
+ Curl_ssl->disassociate_connection(data, FIRSTSOCKET);
+ if(conn->sock[SECONDARYSOCKET] && conn->bits.sock_accepted)
+ Curl_ssl->disassociate_connection(data, SECONDARYSOCKET);
+ }
+}
void Curl_ssl_close_all(struct Curl_easy *data)
{
@@ -593,9 +651,6 @@ void Curl_ssl_close_all(struct Curl_easy *data)
Curl_ssl->close_all(data);
}
-#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
- defined(USE_SECTRANSP) || defined(USE_NSS) || \
- defined(USE_MBEDTLS) || defined(USE_WOLFSSL) || defined(USE_BEARSSL)
int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks)
{
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
@@ -613,16 +668,6 @@ int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks)
return GETSOCK_BLANK;
}
-#else
-int Curl_ssl_getsock(struct connectdata *conn,
- curl_socket_t *socks)
-{
- (void)conn;
- (void)socks;
- return GETSOCK_BLANK;
-}
-/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_SECTRANSP || USE_NSS */
-#endif
void Curl_ssl_close(struct Curl_easy *data, struct connectdata *conn,
int sockindex)
@@ -692,12 +737,12 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
static size_t multissl_version(char *buffer, size_t size);
-size_t Curl_ssl_version(char *buffer, size_t size)
+void Curl_ssl_version(char *buffer, size_t size)
{
#ifdef CURL_WITH_MULTI_SSL
- return multissl_version(buffer, size);
+ (void)multissl_version(buffer, size);
#else
- return Curl_ssl->version(buffer, size);
+ (void)Curl_ssl->version(buffer, size);
#endif
}
@@ -924,7 +969,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
if(encode)
return encode;
- infof(data, "\t public key hash: sha256//%s\n", encoded);
+ infof(data, " public key hash: sha256//%s", encoded);
/* it starts with sha256//, copy so we can modify it */
pinkeylen = strlen(pinnedpubkey) + 1;
@@ -1170,6 +1215,13 @@ static CURLcode multissl_connect_nonblocking(struct Curl_easy *data,
return Curl_ssl->connect_nonblocking(data, conn, sockindex, done);
}
+static int multissl_getsock(struct connectdata *conn, curl_socket_t *socks)
+{
+ if(multissl_setup(NULL))
+ return 0;
+ return Curl_ssl->getsock(conn, socks);
+}
+
static void *multissl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info)
{
@@ -1201,6 +1253,7 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_cert_status_request, /* cert_status_request */
multissl_connect, /* connect */
multissl_connect_nonblocking, /* connect_nonblocking */
+ multissl_getsock, /* getsock */
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1209,7 +1262,9 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- NULL /* sha256sum */
+ NULL, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
const struct Curl_ssl *Curl_ssl =
@@ -1227,6 +1282,8 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_mbedtls;
#elif defined(USE_NSS)
&Curl_ssl_nss;
+#elif defined(USE_RUSTLS)
+ &Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
&Curl_ssl_openssl;
#elif defined(USE_SCHANNEL)
@@ -1270,6 +1327,9 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_BEARSSL)
&Curl_ssl_bearssl,
#endif
+#if defined(USE_RUSTLS)
+ &Curl_ssl_rustls,
+#endif
NULL
};
@@ -1343,7 +1403,7 @@ static int multissl_setup(const struct Curl_ssl *backend)
for(i = 0; available_backends[i]; i++) {
if(strcasecompare(env, available_backends[i]->info.name)) {
Curl_ssl = available_backends[i];
- curl_free(env_tmp);
+ free(env_tmp);
return 0;
}
}
@@ -1351,7 +1411,7 @@ static int multissl_setup(const struct Curl_ssl *backend)
/* Fall back to first available backend */
Curl_ssl = available_backends[0];
- curl_free(env_tmp);
+ free(env_tmp);
return 0;
}
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
index 9666682..beaa83d 100644
--- a/Utilities/cmcurl/lib/vtls/vtls.h
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -32,6 +32,7 @@ struct ssl_connect_data;
#define SSLSUPP_SSL_CTX (1<<3) /* supports CURLOPT_SSL_CTX */
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
+#define SSLSUPP_CAINFO_BLOB (1<<6)
struct Curl_ssl {
/*
@@ -62,6 +63,14 @@ struct Curl_ssl {
CURLcode (*connect_nonblocking)(struct Curl_easy *data,
struct connectdata *conn, int sockindex,
bool *done);
+
+ /* If the SSL backend wants to read or write on this connection during a
+ handshake, set socks[0] to the connection's FIRSTSOCKET, and return
+ a bitmap indicating read or write with GETSOCK_WRITESOCK(0) or
+ GETSOCK_READSOCK(0). Otherwise return GETSOCK_BLANK.
+ Mandatory. */
+ int (*getsock)(struct connectdata *conn, curl_socket_t *socks);
+
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
void (*close_one)(struct Curl_easy *data, struct connectdata *conn,
int sockindex);
@@ -75,6 +84,11 @@ struct Curl_ssl {
bool (*false_start)(void);
CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen,
unsigned char *sha256sum, size_t sha256sumlen);
+
+ void (*associate_connection)(struct Curl_easy *data,
+ struct connectdata *conn,
+ int sockindex);
+ void (*disassociate_connection)(struct Curl_easy *data, int sockindex);
};
#ifdef USE_SSL
@@ -108,6 +122,7 @@ bool Curl_ssl_tls13_ciphersuites(void);
#include "mbedtls.h" /* mbedTLS versions */
#include "mesalink.h" /* MesaLink versions */
#include "bearssl.h" /* BearSSL versions */
+#include "rustls.h" /* rustls versions */
#ifndef MAX_PINNED_PUBKEY_SIZE
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
@@ -117,9 +132,11 @@ bool Curl_ssl_tls13_ciphersuites(void);
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
#endif
-/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
+/* see https://www.iana.org/assignments/tls-extensiontype-values/ */
#define ALPN_HTTP_1_1_LENGTH 8
#define ALPN_HTTP_1_1 "http/1.1"
+#define ALPN_H2_LENGTH 2
+#define ALPN_H2 "h2"
/* set of helper macros for the backends to access the correct fields. For the
proxy or for the remote host - to properly support HTTPS proxy */
@@ -139,9 +156,11 @@ bool Curl_ssl_tls13_ciphersuites(void);
(SSL_IS_PROXY() ? conn->http_proxy.host.name : conn->host.name)
#define SSL_HOST_DISPNAME() \
(SSL_IS_PROXY() ? conn->http_proxy.host.dispname : conn->host.dispname)
+#define SSL_HOST_PORT() \
+ (SSL_IS_PROXY() ? conn->port : conn->remote_port)
#define SSL_PINNED_PUB_KEY() (SSL_IS_PROXY() \
? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] \
- : data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG])
+ : data->set.str[STRING_SSL_PINNEDPUBLICKEY])
#else
#define SSL_IS_PROXY() FALSE
#define SSL_SET_OPTION(var) data->set.ssl.var
@@ -149,8 +168,9 @@ bool Curl_ssl_tls13_ciphersuites(void);
#define SSL_CONN_CONFIG(var) conn->ssl_config.var
#define SSL_HOST_NAME() conn->host.name
#define SSL_HOST_DISPNAME() conn->host.dispname
+#define SSL_HOST_PORT() conn->remote_port
#define SSL_PINNED_PUB_KEY() \
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY]
#endif
bool Curl_ssl_config_matches(struct ssl_primary_config *data,
@@ -158,6 +178,10 @@ bool Curl_ssl_config_matches(struct ssl_primary_config *data,
bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
struct ssl_primary_config *dest);
void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc);
+/* An implementation of the getsock field of Curl_ssl that relies
+ on the ssl_connect_state enum. Asks for read or write depending
+ on whether conn->state is ssl_connect_2_reading or
+ ssl_connect_2_writing. */
int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks);
int Curl_ssl_backend(void);
@@ -169,6 +193,7 @@ CURLcode Curl_ssl_connect(struct Curl_easy *data, struct connectdata *conn,
int sockindex);
CURLcode Curl_ssl_connect_nonblocking(struct Curl_easy *data,
struct connectdata *conn,
+ bool isproxy,
int sockindex,
bool *done);
/* tell the SSL stuff to close down all open information regarding
@@ -185,7 +210,7 @@ struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
/* init the SSL session ID cache */
CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
-size_t Curl_ssl_version(char *buffer, size_t size);
+void Curl_ssl_version(char *buffer, size_t size);
bool Curl_ssl_data_pending(const struct connectdata *conn,
int connindex);
int Curl_ssl_check_cxn(struct connectdata *conn);
@@ -222,6 +247,7 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data);
*/
bool Curl_ssl_getsessionid(struct Curl_easy *data,
struct connectdata *conn,
+ const bool isProxy,
void **ssl_sessionid,
size_t *idsize, /* set 0 if unknown */
int sockindex);
@@ -232,6 +258,7 @@ bool Curl_ssl_getsessionid(struct Curl_easy *data,
*/
CURLcode Curl_ssl_addsessionid(struct Curl_easy *data,
struct connectdata *conn,
+ const bool isProxy,
void *ssl_sessionid,
size_t idsize,
int sockindex);
@@ -262,6 +289,11 @@ bool Curl_ssl_cert_status_request(void);
bool Curl_ssl_false_start(void);
+void Curl_ssl_associate_conn(struct Curl_easy *data,
+ struct connectdata *conn);
+void Curl_ssl_detach_conn(struct Curl_easy *data,
+ struct connectdata *conn);
+
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
#else /* if not USE_SSL */
@@ -282,12 +314,14 @@ bool Curl_ssl_false_start(void);
#define Curl_ssl_data_pending(x,y) 0
#define Curl_ssl_check_cxn(x) 0
#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
-#define Curl_ssl_connect_nonblocking(x,y,z,w) CURLE_NOT_BUILT_IN
+#define Curl_ssl_connect_nonblocking(x,y,z,w,a) CURLE_NOT_BUILT_IN
#define Curl_ssl_kill_session(x) Curl_nop_stmt
#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
#define Curl_ssl_cert_status_request() FALSE
#define Curl_ssl_false_start() FALSE
#define Curl_ssl_tls13_ciphersuites() FALSE
+#define Curl_ssl_associate_conn(a,b) Curl_nop_stmt
+#define Curl_ssl_detach_conn(a,b) Curl_nop_stmt
#endif
#endif /* HEADER_CURL_VTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c
index e1fa459..16fbb89 100644
--- a/Utilities/cmcurl/lib/vtls/wolfssl.c
+++ b/Utilities/cmcurl/lib/vtls/wolfssl.c
@@ -47,16 +47,6 @@
#endif
#endif
-/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
- options.h, but is only seen in >= 3.6.6 since that's when they started
- disabling SSLv3 by default. */
-#ifndef WOLFSSL_ALLOW_SSLV3
-#if (LIBWOLFSSL_VERSION_HEX < 0x03006006) || \
- defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
-#define WOLFSSL_ALLOW_SSLV3
-#endif
-#endif
-
#include <limits.h>
#include "urldata.h"
@@ -249,7 +239,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
req_method = SSLv23_client_method();
#else
infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
- "TLS 1.0 is used exclusively\n");
+ "TLS 1.0 is used exclusively");
req_method = TLSv1_client_method();
#endif
use_sni(TRUE);
@@ -285,18 +275,6 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
failf(data, "wolfSSL: TLS 1.3 is not yet supported");
return CURLE_SSL_CONNECT_ERROR;
#endif
- case CURL_SSLVERSION_SSLv3:
-#ifdef WOLFSSL_ALLOW_SSLV3
- req_method = SSLv3_client_method();
- use_sni(FALSE);
-#else
- failf(data, "wolfSSL does not support SSLv3");
- return CURLE_NOT_BUILT_IN;
-#endif
- break;
- case CURL_SSLVERSION_SSLv2:
- failf(data, "wolfSSL does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
default:
failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
@@ -346,7 +324,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
- infof(data, "Cipher selection: %s\n", ciphers);
+ infof(data, "Cipher selection: %s", ciphers);
}
#ifndef NO_FILESYSTEM
@@ -369,16 +347,16 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* Just continue with a warning if no strict certificate
verification is required. */
infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
+ " continuing anyway:");
}
}
else {
/* Everything is fine. */
- infof(data, "successfully set certificate verify locations:\n");
+ infof(data, "successfully set certificate verify locations:");
}
- infof(data, " CAfile: %s\n",
+ infof(data, " CAfile: %s",
SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile) : "none");
- infof(data, " CApath: %s\n",
+ infof(data, " CApath: %s",
SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath) : "none");
}
@@ -418,12 +396,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
-#else
- const char * const hostname = conn->host.name;
-#endif
+ const char * const hostname = SSL_HOST_NAME();
size_t hostname_len = strlen(hostname);
if((hostname_len < USHRT_MAX) &&
(0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
@@ -433,7 +406,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME, hostname,
(unsigned short)hostname_len) != 1)) {
infof(data, "WARNING: failed to configure server name indication (SNI) "
- "TLS extension\n");
+ "TLS extension");
}
}
#endif
@@ -474,15 +447,15 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
/* wolfSSL's ALPN protocol name list format is a comma separated string of
protocols in descending order of preference, eg: "h2,http/1.1" */
-#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
- strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
- infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+#ifdef USE_HTTP2
+ if(data->state.httpwant >= CURL_HTTP_VERSION_2) {
+ strcpy(protocols + strlen(protocols), ALPN_H2 ",");
+ infof(data, "ALPN, offering %s", ALPN_H2);
}
#endif
strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
- infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s", ALPN_HTTP_1_1);
if(wolfSSL_UseALPN(backend->handle, protocols,
(unsigned)strlen(protocols),
@@ -516,18 +489,16 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn,
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
+ if(!Curl_ssl_getsessionid(data, conn,
+ SSL_IS_PROXY() ? TRUE : FALSE,
+ &ssl_sessionid, NULL, sockindex)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
- char error_buffer[WOLFSSL_MAX_ERROR_SZ];
- Curl_ssl_sessionid_unlock(data);
- failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(SSL_get_error(backend->handle, 0),
- error_buffer));
- return CURLE_SSL_CONNECT_ERROR;
+ Curl_ssl_delsessionid(data, ssl_sessionid);
+ infof(data, "Can't use session ID, going on without\n");
}
- /* Informational message */
- infof(data, "SSL re-using session ID\n");
+ else
+ infof(data, "SSL re-using session ID");
}
Curl_ssl_sessionid_unlock(data);
}
@@ -550,20 +521,11 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
int ret = -1;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
-#ifndef CURL_DISABLE_PROXY
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
- const char * const dispname = SSL_IS_PROXY() ?
- conn->http_proxy.host.dispname : conn->host.dispname;
- const char * const pinnedpubkey = SSL_IS_PROXY() ?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#else
- const char * const hostname = conn->host.name;
- const char * const dispname = conn->host.dispname;
- const char * const pinnedpubkey =
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
-#endif
+ const char * const hostname = SSL_HOST_NAME();
+ 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;
@@ -618,7 +580,7 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
* as also mismatching CN fields */
else if(DOMAIN_NAME_MISMATCH == detail) {
#if 1
- failf(data, "\tsubject alt name(s) or common name do not match \"%s\"",
+ failf(data, " subject alt name(s) or common name do not match \"%s\"",
dispname);
return CURLE_PEER_FAILED_VERIFICATION;
#else
@@ -630,13 +592,13 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
* 'conn->ssl_config.verifyhost' value. */
if(SSL_CONN_CONFIG(verifyhost)) {
failf(data,
- "\tsubject alt name(s) or common name do not match \"%s\"\n",
+ " subject alt name(s) or common name do not match \"%s\"\n",
dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
else {
infof(data,
- "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
+ " subject alt name(s) and/or common name do not match \"%s\"",
dispname);
return CURLE_OK;
}
@@ -645,14 +607,14 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
else if(ASN_NO_SIGNER_E == detail) {
if(SSL_CONN_CONFIG(verifypeer)) {
- failf(data, "\tCA signer not available for verification");
+ failf(data, " CA signer not available for verification");
return CURLE_SSL_CACERT_BADFILE;
}
else {
/* Just continue with a warning if no strict certificate
verification is required. */
infof(data, "CA signer not available for verification, "
- "continuing anyway\n");
+ "continuing anyway");
}
}
#endif
@@ -717,27 +679,26 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
if(rc == SSL_SUCCESS) {
- infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
+ infof(data, "ALPN, server accepted to use %.*s", protocol_len,
protocol);
if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
!memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
conn->negnpn = CURL_HTTP_VERSION_1_1;
-#ifdef USE_NGHTTP2
- else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
- protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
- !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
- NGHTTP2_PROTO_VERSION_ID_LEN))
+#ifdef USE_HTTP2
+ else if(data->state.httpwant >= CURL_HTTP_VERSION_2 &&
+ protocol_len == ALPN_H2_LENGTH &&
+ !memcmp(protocol, ALPN_H2, ALPN_H2_LENGTH))
conn->negnpn = CURL_HTTP_VERSION_2;
#endif
else
- infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
+ infof(data, "ALPN, unrecognized protocol %.*s", protocol_len,
protocol);
Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ?
BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
}
else if(rc == SSL_ALPN_NOT_FOUND)
- infof(data, "ALPN, server did not agree to a protocol\n");
+ infof(data, "ALPN, server did not agree to a protocol");
else {
failf(data, "ALPN, failure getting protocol, error %d", rc);
return CURLE_SSL_CONNECT_ERROR;
@@ -747,11 +708,11 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn,
connssl->connecting_state = ssl_connect_3;
#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
- infof(data, "SSL connection using %s / %s\n",
+ infof(data, "SSL connection using %s / %s",
wolfSSL_get_version(backend->handle),
wolfSSL_get_cipher_name(backend->handle));
#else
- infof(data, "SSL connected\n");
+ infof(data, "SSL connected");
#endif
return CURLE_OK;
@@ -770,32 +731,33 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn,
if(SSL_SET_OPTION(primary.sessionid)) {
bool incache;
- SSL_SESSION *our_ssl_sessionid;
void *old_ssl_sessionid = NULL;
-
- our_ssl_sessionid = SSL_get_session(backend->handle);
-
- Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL,
- sockindex));
- if(incache) {
- if(old_ssl_sessionid != our_ssl_sessionid) {
- infof(data, "old SSL session ID is stale, removing\n");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- incache = FALSE;
+ SSL_SESSION *our_ssl_sessionid = SSL_get_session(backend->handle);
+ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+
+ if(our_ssl_sessionid) {
+ Curl_ssl_sessionid_lock(data);
+ incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
+ &old_ssl_sessionid, NULL, sockindex));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing");
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
+ incache = FALSE;
+ }
}
- }
- if(!incache) {
- result = Curl_ssl_addsessionid(data, conn, our_ssl_sessionid,
- 0 /* unknown size */, sockindex);
- if(result) {
- Curl_ssl_sessionid_unlock(data);
- failf(data, "failed to store ssl session");
- return result;
+ if(!incache) {
+ result = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
+ 0, sockindex);
+ if(result) {
+ Curl_ssl_sessionid_unlock(data);
+ failf(data, "failed to store ssl session");
+ return result;
+ }
}
+ Curl_ssl_sessionid_unlock(data);
}
- Curl_ssl_sessionid_unlock(data);
}
connssl->connecting_state = ssl_connect_done;
@@ -815,9 +777,13 @@ 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();
- if(rc < 0) {
+ rc = SSL_write(backend->handle, mem, memlen);
+
+ if(rc <= 0) {
int err = SSL_get_error(backend->handle, rc);
switch(err) {
@@ -846,6 +812,10 @@ static void wolfssl_close(struct Curl_easy *data, struct connectdata *conn,
(void) data;
if(backend->handle) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
(void)SSL_shutdown(backend->handle);
SSL_free(backend->handle);
backend->handle = NULL;
@@ -867,7 +837,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);
@@ -952,6 +926,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;
}
@@ -1125,7 +1100,7 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
}
static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+ CURLINFO info UNUSED_PARAM)
{
struct ssl_backend_data *backend = connssl->backend;
(void)info;
@@ -1152,6 +1127,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_cert_status_request, /* cert_status_request */
wolfssl_connect, /* connect */
wolfssl_connect_nonblocking, /* connect_nonblocking */
+ Curl_ssl_getsock, /* getsock */
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
@@ -1160,7 +1136,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
Curl_none_false_start, /* false_start */
- wolfssl_sha256sum /* sha256sum */
+ wolfssl_sha256sum, /* sha256sum */
+ NULL, /* associate_connection */
+ NULL /* disassociate_connection */
};
#endif
diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c
index c0764c4..15c8156 100644
--- a/Utilities/cmcurl/lib/warnless.c
+++ b/Utilities/cmcurl/lib/warnless.c
@@ -37,85 +37,23 @@
#include "warnless.h"
-#define CURL_MASK_SCHAR 0x7F
-#define CURL_MASK_UCHAR 0xFF
-
-#if (SIZEOF_SHORT == 2)
-# define CURL_MASK_SSHORT 0x7FFF
-# define CURL_MASK_USHORT 0xFFFF
-#elif (SIZEOF_SHORT == 4)
-# define CURL_MASK_SSHORT 0x7FFFFFFF
-# define CURL_MASK_USHORT 0xFFFFFFFF
-#elif (SIZEOF_SHORT == 8)
-# define CURL_MASK_SSHORT 0x7FFFFFFFFFFFFFFF
-# define CURL_MASK_USHORT 0xFFFFFFFFFFFFFFFF
-#else
-# error "SIZEOF_SHORT not defined"
-#endif
-
-#if (SIZEOF_INT == 2)
-# define CURL_MASK_SINT 0x7FFF
-# define CURL_MASK_UINT 0xFFFF
-#elif (SIZEOF_INT == 4)
-# define CURL_MASK_SINT 0x7FFFFFFF
-# define CURL_MASK_UINT 0xFFFFFFFF
-#elif (SIZEOF_INT == 8)
-# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFF
-# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFF
-#elif (SIZEOF_INT == 16)
-# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
-#else
-# error "SIZEOF_INT not defined"
-#endif
-
-#if (SIZEOF_LONG == 2)
-# define CURL_MASK_SLONG 0x7FFFL
-# define CURL_MASK_ULONG 0xFFFFUL
-#elif (SIZEOF_LONG == 4)
-# define CURL_MASK_SLONG 0x7FFFFFFFL
-# define CURL_MASK_ULONG 0xFFFFFFFFUL
-#elif (SIZEOF_LONG == 8)
-# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL
-# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL
-#elif (SIZEOF_LONG == 16)
-# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
-# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL
-#else
-# error "SIZEOF_LONG not defined"
-#endif
-
-#if (SIZEOF_CURL_OFF_T == 2)
-# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF)
-# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF)
-#elif (SIZEOF_CURL_OFF_T == 4)
-# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF)
-# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF)
-#elif (SIZEOF_CURL_OFF_T == 8)
-# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
-# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF)
-#elif (SIZEOF_CURL_OFF_T == 16)
-# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
-# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
-#else
-# error "SIZEOF_CURL_OFF_T not defined"
-#endif
-
-#if (SIZEOF_SIZE_T == SIZEOF_SHORT)
-# define CURL_MASK_SSIZE_T CURL_MASK_SSHORT
-# define CURL_MASK_USIZE_T CURL_MASK_USHORT
-#elif (SIZEOF_SIZE_T == SIZEOF_INT)
-# define CURL_MASK_SSIZE_T CURL_MASK_SINT
-# define CURL_MASK_USIZE_T CURL_MASK_UINT
-#elif (SIZEOF_SIZE_T == SIZEOF_LONG)
-# define CURL_MASK_SSIZE_T CURL_MASK_SLONG
-# define CURL_MASK_USIZE_T CURL_MASK_ULONG
-#elif (SIZEOF_SIZE_T == SIZEOF_CURL_OFF_T)
-# define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT
-# define CURL_MASK_USIZE_T CURL_MASK_UCOFFT
-#else
-# error "SIZEOF_SIZE_T not defined"
-#endif
+#define CURL_MASK_UCHAR ((unsigned char)~0)
+#define CURL_MASK_SCHAR (CURL_MASK_UCHAR >> 1)
+
+#define CURL_MASK_USHORT ((unsigned short)~0)
+#define CURL_MASK_SSHORT (CURL_MASK_USHORT >> 1)
+
+#define CURL_MASK_UINT ((unsigned int)~0)
+#define CURL_MASK_SINT (CURL_MASK_UINT >> 1)
+
+#define CURL_MASK_ULONG ((unsigned long)~0)
+#define CURL_MASK_SLONG (CURL_MASK_ULONG >> 1)
+
+#define CURL_MASK_UCOFFT ((unsigned CURL_TYPEOF_CURL_OFF_T)~0)
+#define CURL_MASK_SCOFFT (CURL_MASK_UCOFFT >> 1)
+
+#define CURL_MASK_USIZE_T ((size_t)~0)
+#define CURL_MASK_SSIZE_T (CURL_MASK_USIZE_T >> 1)
/*
** unsigned long to unsigned short
@@ -207,7 +145,7 @@ unsigned long curlx_uztoul(size_t uznum)
# pragma warning(disable:810) /* conversion may lose significant bits */
#endif
-#if (SIZEOF_LONG < SIZEOF_SIZE_T)
+#if ULONG_MAX < SIZE_T_MAX
DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
#endif
return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
@@ -228,7 +166,7 @@ unsigned int curlx_uztoui(size_t uznum)
# pragma warning(disable:810) /* conversion may lose significant bits */
#endif
-#if (SIZEOF_INT < SIZEOF_SIZE_T)
+#if UINT_MAX < SIZE_T_MAX
DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT);
#endif
return (unsigned int)(uznum & (size_t) CURL_MASK_UINT);
@@ -250,7 +188,7 @@ int curlx_sltosi(long slnum)
#endif
DEBUGASSERT(slnum >= 0);
-#if (SIZEOF_INT < SIZEOF_LONG)
+#if INT_MAX < LONG_MAX
DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
#endif
return (int)(slnum & (long) CURL_MASK_SINT);
@@ -272,7 +210,7 @@ unsigned int curlx_sltoui(long slnum)
#endif
DEBUGASSERT(slnum >= 0);
-#if (SIZEOF_INT < SIZEOF_LONG)
+#if UINT_MAX < LONG_MAX
DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
#endif
return (unsigned int)(slnum & (long) CURL_MASK_UINT);
@@ -352,7 +290,7 @@ int curlx_sztosi(ssize_t sznum)
#endif
DEBUGASSERT(sznum >= 0);
-#if (SIZEOF_INT < SIZEOF_SIZE_T)
+#if INT_MAX < SSIZE_T_MAX
DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT);
#endif
return (int)(sznum & (ssize_t) CURL_MASK_SINT);
diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c
index f29aa05..1bdaead 100644
--- a/Utilities/cmcurl/lib/x509asn1.c
+++ b/Utilities/cmcurl/lib/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)
@@ -517,8 +518,8 @@ static const char *GTime2str(const char *beg, const char *end)
return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
beg, beg + 4, beg + 6,
beg + 8, beg + 10, sec1, sec2,
- fracl? ".": "", fracl, fracp,
- sep, tzl, tzp);
+ fracl? ".": "", (int)fracl, fracp,
+ sep, (int)tzl, tzp);
}
/*
@@ -558,7 +559,7 @@ static const char *UTime2str(const char *beg, const char *end)
return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
20 - (*beg >= '5'), beg, beg + 2, beg + 4,
beg + 6, beg + 8, sec,
- tzl, tzp);
+ (int)tzl, tzp);
}
/*
@@ -866,7 +867,7 @@ static void do_pubkey_field(struct Curl_easy *data, int certnum,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, label, output);
if(!certnum)
- infof(data, " %s: %s\n", label, output);
+ infof(data, " %s: %s", label, output);
free((char *) output);
}
}
@@ -905,7 +906,7 @@ static void do_pubkey(struct Curl_easy *data, int certnum,
if(len > 32)
elem.beg = q; /* Strip leading zero bytes. */
if(!certnum)
- infof(data, " RSA Public Key (%lu bits)\n", len);
+ infof(data, " RSA Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
q = curl_maprintf("%lu", len);
if(q) {
@@ -978,7 +979,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
if(!certnum)
- infof(data, "%2d Subject: %s\n", certnum, ccp);
+ infof(data, "%2d Subject: %s", certnum, ccp);
free((char *) ccp);
/* Issuer. */
@@ -988,7 +989,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
if(!certnum)
- infof(data, " Issuer: %s\n", ccp);
+ infof(data, " Issuer: %s", ccp);
free((char *) ccp);
/* Version (always fits in less than 32 bits). */
@@ -1003,7 +1004,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
free((char *) ccp);
}
if(!certnum)
- infof(data, " Version: %lu (0x%lx)\n", version + 1, version);
+ infof(data, " Version: %lu (0x%lx)", version + 1, version);
/* Serial number. */
ccp = ASN1tostr(&cert.serialNumber, 0);
@@ -1012,7 +1013,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
if(!certnum)
- infof(data, " Serial Number: %s\n", ccp);
+ infof(data, " Serial Number: %s", ccp);
free((char *) ccp);
/* Signature algorithm .*/
@@ -1023,7 +1024,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
if(!certnum)
- infof(data, " Signature Algorithm: %s\n", ccp);
+ infof(data, " Signature Algorithm: %s", ccp);
free((char *) ccp);
/* Start Date. */
@@ -1033,7 +1034,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
if(!certnum)
- infof(data, " Start Date: %s\n", ccp);
+ infof(data, " Start Date: %s", ccp);
free((char *) ccp);
/* Expire Date. */
@@ -1043,7 +1044,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
if(!certnum)
- infof(data, " Expire Date: %s\n", ccp);
+ infof(data, " Expire Date: %s", ccp);
free((char *) ccp);
/* Public Key Algorithm. */
@@ -1054,7 +1055,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
if(!certnum)
- infof(data, " Public Key Algorithm: %s\n", ccp);
+ infof(data, " Public Key Algorithm: %s", ccp);
do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
free((char *) ccp);
@@ -1065,7 +1066,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
if(!certnum)
- infof(data, " Signature: %s\n", ccp);
+ infof(data, " Signature: %s", ccp);
free((char *) ccp);
/* Generate PEM certificate. */
@@ -1098,12 +1099,13 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
if(data->set.ssl.certinfo)
Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
if(!certnum)
- infof(data, "%s\n", cp2);
+ infof(data, "%s", cp2);
free(cp2);
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)
@@ -1145,10 +1147,8 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
int matched = -1;
size_t addrlen = (size_t) -1;
ssize_t len;
- const char *const hostname = SSL_IS_PROXY()?
- conn->http_proxy.host.name : conn->host.name;
- const char *const dispname = SSL_IS_PROXY()?
- conn->http_proxy.host.dispname : conn->host.dispname;
+ const char * const hostname = SSL_HOST_NAME();
+ const char * const dispname = SSL_HOST_DISPNAME();
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
@@ -1222,12 +1222,12 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
switch(matched) {
case 1:
/* an alternative name matched the server hostname */
- infof(data, "\t subjectAltName: %s matched\n", dispname);
+ infof(data, " subjectAltName: %s matched", dispname);
return CURLE_OK;
case 0:
/* an alternative name field existed, but didn't match and then
we MUST fail */
- infof(data, "\t subjectAltName does not match %s\n", dispname);
+ infof(data, " subjectAltName does not match %s", dispname);
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -1264,7 +1264,7 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
failf(data, "SSL: illegal cert name field");
else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
- infof(data, "\t common name: %s (matched)\n", dnsname);
+ infof(data, " common name: %s (matched)", dnsname);
free(dnsname);
return CURLE_OK;
}
diff --git a/Utilities/cmcurl/lib/x509asn1.h b/Utilities/cmcurl/lib/x509asn1.h
index 326e32d..3b51eee 100644
--- a/Utilities/cmcurl/lib/x509asn1.h
+++ b/Utilities/cmcurl/lib/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 */