diff options
author | Brad King <brad.king@kitware.com> | 2022-10-31 20:11:41 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2022-10-31 20:11:41 (GMT) |
commit | 9ffe6b0969fc270cc2a1aac2b2c1bf986af291d5 (patch) | |
tree | 75711965f7fd24679383853a840f42efff676e31 /Utilities/cmcurl/lib | |
parent | fa9bbb8627e8af5153367721eb037b6e094670d1 (diff) | |
parent | ec122fff08ab9a8e56fb90126ecedb99c759011b (diff) | |
download | CMake-9ffe6b0969fc270cc2a1aac2b2c1bf986af291d5.zip CMake-9ffe6b0969fc270cc2a1aac2b2c1bf986af291d5.tar.gz CMake-9ffe6b0969fc270cc2a1aac2b2c1bf986af291d5.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2022-10-26 (cd95ee9f)
Diffstat (limited to 'Utilities/cmcurl/lib')
311 files changed, 7738 insertions, 3883 deletions
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt index 6cf45ad..3138473 100644 --- a/Utilities/cmcurl/lib/CMakeLists.txt +++ b/Utilities/cmcurl/lib/CMakeLists.txt @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2022, 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 @@ -18,9 +18,12 @@ # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # +# SPDX-License-Identifier: curl +# ########################################################################### set(LIB_NAME cmcurl) set(LIBCURL_OUTPUT_NAME cmcurl) +add_definitions(-DBUILDING_LIBCURL) if(BUILD_SHARED_LIBS) set(CURL_STATICLIB NO) @@ -143,7 +146,6 @@ endif() if(WIN32) if(BUILD_SHARED_LIBS) - set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "_USRDLL") if(MSVC) # Add "_imp" as a suffix before the extension to avoid conflicting with # the statically linked "libcurl.lib" @@ -156,16 +158,18 @@ target_include_directories(${LIB_NAME} INTERFACE $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>) -install(TARGETS ${LIB_NAME} - EXPORT ${TARGETS_EXPORT_NAME} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} -) - -export(TARGETS ${LIB_NAME} - APPEND FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake - NAMESPACE ${PROJECT_NAME}:: -) +if(CURL_ENABLE_EXPORT_TARGET) + install(TARGETS ${LIB_NAME} + EXPORT ${TARGETS_EXPORT_NAME} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + + export(TARGETS ${LIB_NAME} + FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake + NAMESPACE ${PROJECT_NAME}:: + ) +endif() endif() diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc index 1ab0078..b2d2e9e 100644 --- a/Utilities/cmcurl/lib/Makefile.inc +++ b/Utilities/cmcurl/lib/Makefile.inc @@ -18,6 +18,8 @@ # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY # KIND, either express or implied. # +# SPDX-License-Identifier: curl +# ########################################################################### LIB_VAUTH_CFILES = \ @@ -108,7 +110,6 @@ LIB_CFILES = \ content_encoding.c \ cookie.c \ curl_addrinfo.c \ - curl_ctype.c \ curl_des.c \ curl_endian.c \ curl_fnmatch.c \ @@ -127,7 +128,6 @@ LIB_CFILES = \ curl_threads.c \ dict.c \ doh.c \ - dotdot.c \ dynbuf.c \ easy.c \ easygetopt.c \ @@ -135,6 +135,7 @@ LIB_CFILES = \ escape.c \ file.c \ fileinfo.c \ + fopen.c \ formdata.c \ ftp.c \ ftplistparser.c \ @@ -176,6 +177,7 @@ LIB_CFILES = \ multi.c \ netrc.c \ nonblock.c \ + noproxy.c \ openldap.c \ parsedate.c \ pingpong.c \ @@ -215,7 +217,8 @@ LIB_CFILES = \ version.c \ version_win32.c \ warnless.c \ - wildcard.c + wildcard.c \ + ws.c LIB_HFILES = \ altsvc.h \ @@ -260,14 +263,16 @@ LIB_HFILES = \ curlx.h \ dict.h \ doh.h \ - dotdot.h \ dynbuf.h \ + easy_lock.h \ easyif.h \ easyoptions.h \ escape.h \ file.h \ fileinfo.h \ + fopen.h \ formdata.h \ + functypes.h \ ftp.h \ ftplistparser.h \ getinfo.h \ @@ -297,6 +302,7 @@ LIB_HFILES = \ multiif.h \ netrc.h \ nonblock.h \ + noproxy.h \ parsedate.h \ pingpong.h \ pop3.h \ @@ -336,7 +342,8 @@ LIB_HFILES = \ urldata.h \ version_win32.h \ warnless.h \ - wildcard.h + wildcard.h \ + ws.h LIB_RCFILES = libcurl.rc diff --git a/Utilities/cmcurl/lib/altsvc.c b/Utilities/cmcurl/lib/altsvc.c index dd2d0eb..7bca840 100644 --- a/Utilities/cmcurl/lib/altsvc.c +++ b/Utilities/cmcurl/lib/altsvc.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* * The Alt-Svc: header is defined in RFC 7838: @@ -34,7 +36,7 @@ #include "parsedate.h" #include "sendf.h" #include "warnless.h" -#include "rand.h" +#include "fopen.h" #include "rename.h" /* The last 3 #include files should be in this order */ @@ -50,15 +52,7 @@ #define MAX_ALTSVC_ALPNLENSTR "10" #define MAX_ALTSVC_ALPNLEN 10 -#if defined(USE_QUICHE) && !defined(UNITTESTS) -#define H3VERSION "h3-29" -#elif defined(USE_NGTCP2) && !defined(UNITTESTS) -#define H3VERSION "h3-29" -#elif defined(USE_MSH3) && !defined(UNITTESTS) -#define H3VERSION "h3-29" -#else #define H3VERSION "h3" -#endif static enum alpnid alpn2alpnid(char *name) { @@ -184,10 +178,9 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line) /* * Load alt-svc entries from the given file. The text based line-oriented file - * format is documented here: - * https://github.com/curl/curl/wiki/QUIC-implementation + * format is documented here: https://curl.se/docs/alt-svc.html * - * This function only returns error on major problems that prevents alt-svc + * This function only returns error on major problems that prevent alt-svc * handling to work completely. It will ignore individual syntactical errors * etc. */ @@ -336,8 +329,7 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, struct Curl_llist_element *n; CURLcode result = CURLE_OK; FILE *out; - char *tempstore; - unsigned char randsuffix[9]; + char *tempstore = NULL; if(!altsvc) /* no cache activated */ @@ -351,17 +343,8 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, /* marked as read-only, no file or zero length file name */ return CURLE_OK; - if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) - return CURLE_FAILED_INIT; - - tempstore = aprintf("%s.%s.tmp", file, randsuffix); - if(!tempstore) - return CURLE_OUT_OF_MEMORY; - - out = fopen(tempstore, FOPEN_WRITETEXT); - if(!out) - result = CURLE_WRITE_ERROR; - else { + result = Curl_fopen(data, file, &out, &tempstore); + if(!result) { fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", out); @@ -373,10 +356,10 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data, break; } fclose(out); - if(!result && Curl_rename(tempstore, file)) + if(!result && tempstore && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; - if(result) + if(result && tempstore) unlink(tempstore); } free(tempstore); @@ -479,6 +462,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, struct altsvc *as; unsigned short dstport = srcport; /* the same by default */ CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf)); + size_t entries = 0; #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif @@ -489,11 +473,10 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, DEBUGASSERT(asi); - /* Flush all cached alternatives for this source origin, if any */ - altsvc_flush(asi, srcalpnid, srchost, srcport); - /* "clear" is a magic keyword */ if(strcasecompare(alpnbuf, "clear")) { + /* Flush cached alternatives for this source origin */ + altsvc_flush(asi, srcalpnid, srchost, srcport); return CURLE_OK; } @@ -511,6 +494,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, bool quoted = FALSE; time_t maxage = 24 * 3600; /* default is 24 hours */ bool persist = FALSE; + bool valid = TRUE; p++; if(*p != ':') { /* host name starts here */ @@ -520,7 +504,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, len = p - hostp; if(!len || (len >= MAX_ALTSVC_HOSTLEN)) { infof(data, "Excessive alt-svc host name, ignoring."); - dstalpnid = ALPN_none; + valid = FALSE; } else { memcpy(namebuf, hostp, len); @@ -537,10 +521,11 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, 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."); - dstalpnid = ALPN_none; + valid = FALSE; } + else + dstport = curlx_ultous(port); p = end_ptr; - dstport = curlx_ultous(port); } if(*p++ != '\"') break; @@ -592,7 +577,12 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, persist = TRUE; } } - if(dstalpnid) { + if(dstalpnid && valid) { + if(!entries++) + /* Flush cached alternatives for this source origin, if any - when + this is the first entry of the line. */ + altsvc_flush(asi, srcalpnid, srchost, srcport); + as = altsvc_createid(srchost, dsthost, srcalpnid, dstalpnid, srcport, dstport); @@ -606,10 +596,6 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data, Curl_alpnid2str(dstalpnid)); } } - else { - infof(data, "Unknown alt-svc protocol \"%s\", skipping.", - alpnbuf); - } } else break; diff --git a/Utilities/cmcurl/lib/altsvc.h b/Utilities/cmcurl/lib/altsvc.h index 2ab89e7..2751d27 100644 --- a/Utilities/cmcurl/lib/altsvc.h +++ b/Utilities/cmcurl/lib/altsvc.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c index 78bb22c..e8c2fc0 100644 --- a/Utilities/cmcurl/lib/amigaos.c +++ b/Utilities/cmcurl/lib/amigaos.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,13 +18,23 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifdef __AMIGA__ -# include "amigaos.h" -# if defined(HAVE_PROTO_BSDSOCKET_H) && !defined(USE_AMISSL) + +#include <curl/curl.h> + +#include "hostip.h" +#include "amigaos.h" + +#ifdef HAVE_PROTO_BSDSOCKET_H +# if defined(__amigaos4__) +# include <bsdsocket/socketbasetags.h> +# elif !defined(USE_AMISSL) # include <amitcp/socketbasetags.h> # endif # ifdef __libnix__ @@ -36,8 +46,154 @@ #include "curl_memory.h" #include "memdebug.h" -#ifdef __AMIGA__ -#if defined(HAVE_PROTO_BSDSOCKET_H) && !defined(USE_AMISSL) +#ifdef HAVE_PROTO_BSDSOCKET_H + +#ifdef __amigaos4__ +/* + * AmigaOS 4.x specific code + */ + +/* + * hostip4.c - Curl_ipv4_resolve_r() replacement code + * + * Logic that needs to be considered are the following build cases: + * - newlib networking + * - clib2 networking + * - direct bsdsocket.library networking (usually AmiSSL builds) + * Each with the threaded resolver enabled or not. + * + * With the threaded resolver enabled, try to use gethostbyname_r() where + * available, otherwise (re)open bsdsocket.library and fallback to + * gethostbyname(). + */ + +#include <proto/bsdsocket.h> + +static struct SocketIFace *__CurlISocket = NULL; +static uint32 SocketFeatures = 0; + +#define HAVE_BSDSOCKET_GETHOSTBYNAME_R 0x01 +#define HAVE_BSDSOCKET_GETADDRINFO 0x02 + +CURLcode Curl_amiga_init(void) +{ + struct SocketIFace *ISocket; + struct Library *base = OpenLibrary("bsdsocket.library", 4); + + if(base) { + ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL); + if(ISocket) { + ULONG enabled = 0; + + SocketBaseTags(SBTM_SETVAL(SBTC_CAN_SHARE_LIBRARY_BASES), TRUE, + SBTM_GETREF(SBTC_HAVE_GETHOSTADDR_R_API), (ULONG)&enabled, + TAG_DONE); + + if(enabled) { + SocketFeatures |= HAVE_BSDSOCKET_GETHOSTBYNAME_R; + } + + __CurlISocket = ISocket; + + atexit(Curl_amiga_cleanup); + + return CURLE_OK; + } + CloseLibrary(base); + } + + return CURLE_FAILED_INIT; +} + +void Curl_amiga_cleanup(void) +{ + if(__CurlISocket) { + struct Library *base = __CurlISocket->Data.LibBase; + DropInterface((struct Interface *)__CurlISocket); + CloseLibrary(base); + __CurlISocket = NULL; + } +} + +#ifdef CURLRES_AMIGA +/* + * Because we need to handle the different cases in hostip4.c at run-time, + * not at compile-time, based on what was detected in Curl_amiga_init(), + * we replace it completely with our own as to not complicate the baseline + * code. Assumes malloc/calloc/free are thread safe because Curl_he2ai() + * allocates memory also. + */ + +struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, + int port) +{ + struct Curl_addrinfo *ai = NULL; + struct hostent *h; + struct SocketIFace *ISocket = __CurlISocket; + + if(SocketFeatures & HAVE_BSDSOCKET_GETHOSTBYNAME_R) { + LONG h_errnop = 0; + struct hostent *buf; + + buf = calloc(1, CURL_HOSTENT_SIZE); + if(buf) { + h = gethostbyname_r((STRPTR)hostname, buf, + (char *)buf + sizeof(struct hostent), + CURL_HOSTENT_SIZE - sizeof(struct hostent), + &h_errnop); + if(h) { + ai = Curl_he2ai(h, port); + } + free(buf); + } + } + else { + #ifdef CURLRES_THREADED + /* gethostbyname() is not thread safe, so we need to reopen bsdsocket + * on the thread's context + */ + struct Library *base = OpenLibrary("bsdsocket.library", 4); + if(base) { + ISocket = (struct SocketIFace *)GetInterface(base, "main", 1, NULL); + if(ISocket) { + h = gethostbyname((STRPTR)hostname); + if(h) { + ai = Curl_he2ai(h, port); + } + DropInterface((struct Interface *)ISocket); + } + CloseLibrary(base); + } + #else + /* not using threaded resolver - safe to use this as-is */ + h = gethostbyname(hostname); + if(h) { + ai = Curl_he2ai(h, port); + } + #endif + } + + return ai; +} +#endif /* CURLRES_AMIGA */ + +#ifdef USE_AMISSL +int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *errorfds, struct timeval *timeout) +{ + int r = WaitSelect(nfds, readfds, writefds, errorfds, timeout, 0); + /* Ensure Ctrl-C signal is actioned */ + if((r == -1) && (SOCKERRNO == EINTR)) + raise(SIGINT); + return r; +} +#endif /* USE_AMISSL */ + +#elif !defined(USE_AMISSL) /* __amigaos4__ */ +/* + * Amiga OS3 specific code + */ + struct Library *SocketBase = NULL; extern int errno, h_errno; @@ -47,7 +203,7 @@ void __request(const char *msg); # define __request(msg) Printf(msg "\n\a") #endif -void Curl_amiga_cleanup() +void Curl_amiga_cleanup(void) { if(SocketBase) { CloseLibrary(SocketBase); @@ -55,68 +211,36 @@ void Curl_amiga_cleanup() } } -bool Curl_amiga_init() +CURLcode Curl_amiga_init(void) { if(!SocketBase) SocketBase = OpenLibrary("bsdsocket.library", 4); if(!SocketBase) { __request("No TCP/IP Stack running!"); - return FALSE; + return CURLE_FAILED_INIT; } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { __request("SocketBaseTags ERROR"); - return FALSE; + return CURLE_FAILED_INIT; } #ifndef __libnix__ atexit(Curl_amiga_cleanup); #endif - return TRUE; + return CURLE_OK; } #ifdef __libnix__ ADD2EXIT(Curl_amiga_cleanup, -50); #endif -#endif /* HAVE_PROTO_BSDSOCKET_H */ +#endif /* !USE_AMISSL */ -#ifdef USE_AMISSL -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 /* HAVE_PROTO_BSDSOCKET_H */ -#endif /* USE_AMISSL */ #endif /* __AMIGA__ */ - diff --git a/Utilities/cmcurl/lib/amigaos.h b/Utilities/cmcurl/lib/amigaos.h index 02e5bb5..9abfb59 100644 --- a/Utilities/cmcurl/lib/amigaos.h +++ b/Utilities/cmcurl/lib/amigaos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,25 +20,23 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" -#if defined(__AMIGA__) && defined(HAVE_BSDSOCKET_H) && !defined(USE_AMISSL) +#if defined(__AMIGA__) && defined(HAVE_PROTO_BSDSOCKET_H) && \ + (!defined(USE_AMISSL) || defined(__amigaos4__)) -bool Curl_amiga_init(); -void Curl_amiga_cleanup(); +CURLcode Curl_amiga_init(void); +void Curl_amiga_cleanup(void); #else -#define Curl_amiga_init() 1 +#define Curl_amiga_init() CURLE_OK #define Curl_amiga_cleanup() Curl_nop_stmt #endif -#ifdef USE_AMISSL -#include <openssl/x509v3.h> -void Curl_amiga_X509_free(X509 *a); -#endif /* USE_AMISSL */ - #endif /* HEADER_CURL_AMIGAOS_H */ diff --git a/Utilities/cmcurl/lib/arpa_telnet.h b/Utilities/cmcurl/lib/arpa_telnet.h index cbe31de..523f7f5 100644 --- a/Utilities/cmcurl/lib/arpa_telnet.h +++ b/Utilities/cmcurl/lib/arpa_telnet.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_TELNET /* diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c index c885ade..33edba1 100644 --- a/Utilities/cmcurl/lib/asyn-ares.c +++ b/Utilities/cmcurl/lib/asyn-ares.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -113,6 +115,7 @@ struct thread_data { #ifndef HAVE_CARES_GETADDRINFO struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ #endif + char hostname[1]; }; /* How long we are willing to wait for additional parallel responses after @@ -250,8 +253,6 @@ void Curl_resolver_kill(struct Curl_easy *data) */ static void destroy_async_data(struct Curl_async *async) { - free(async->hostname); - if(async->tdata) { struct thread_data *res = async->tdata; if(res) { @@ -263,8 +264,6 @@ static void destroy_async_data(struct Curl_async *async) } async->tdata = NULL; } - - async->hostname = NULL; } /* @@ -306,7 +305,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, * 2) wait for the timeout period to check for action on ares' sockets. * 3) tell ares to act on all the sockets marked as "with action" * - * return number of sockets it worked on + * return number of sockets it worked on, or -1 on error */ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) @@ -338,8 +337,11 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms) break; } - if(num) + if(num) { nfds = Curl_poll(pfd, num, timeout_ms); + if(nfds < 0) + return -1; + } else nfds = 0; @@ -376,7 +378,8 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data, DEBUGASSERT(dns); *dns = NULL; - waitperform(data, 0); + if(waitperform(data, 0) < 0) + return CURLE_UNRECOVERABLE_POLL; #ifndef HAVE_CARES_GETADDRINFO /* Now that we've checked for any last minute results above, see if there are @@ -475,7 +478,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, else timeout_ms = 1000; - waitperform(data, timeout_ms); + if(waitperform(data, timeout_ms) < 0) + return CURLE_UNRECOVERABLE_POLL; result = Curl_resolver_is_resolved(data, entry); if(result || data->state.async.done) @@ -742,7 +746,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts, * Curl_resolver_getaddrinfo() - when using ares * * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to + * successful, the 'hostent' is returned and the fourth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ @@ -751,25 +755,18 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, int port, int *waitp) { - char *bufp; - + struct thread_data *res = NULL; + size_t namelen = strlen(hostname); *waitp = 0; /* default to synchronous response */ - bufp = strdup(hostname); - if(bufp) { - struct thread_data *res = NULL; - free(data->state.async.hostname); - data->state.async.hostname = bufp; + res = calloc(sizeof(struct thread_data) + namelen, 1); + if(res) { + strcpy(res->hostname, hostname); + data->state.async.hostname = res->hostname; data->state.async.port = port; data->state.async.done = FALSE; /* not done */ data->state.async.status = 0; /* clear */ data->state.async.dns = NULL; /* clear */ - res = calloc(sizeof(struct thread_data), 1); - if(!res) { - free(data->state.async.hostname); - data->state.async.hostname = NULL; - return NULL; - } data->state.async.tdata = res; /* initial status - failed */ @@ -782,13 +779,17 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, int pf = PF_INET; memset(&hints, 0, sizeof(hints)); #ifdef CURLRES_IPV6 - if(Curl_ipv6works(data)) + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && 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; + /* Since the service is a numerical one, set the hint flags + * accordingly to save a call to getservbyname in inside C-Ares + */ + hints.ai_flags = ARES_AI_NUMERICSERV; msnprintf(service, sizeof(service), "%d", port); res->num_pending = 1; ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname, @@ -797,7 +798,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, #else #ifdef HAVE_CARES_IPV6 - if(Curl_ipv6works(data)) { + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { /* The stack seems to be IPv6-enabled */ res->num_pending = 2; diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c index 149172a..8b375eb 100644 --- a/Utilities/cmcurl/lib/asyn-thread.c +++ b/Utilities/cmcurl/lib/asyn-thread.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -262,23 +264,28 @@ int init_thread_sync_data(struct thread_data *td, return 1; err_exit: - /* Memory allocation failed */ +#ifndef CURL_DISABLE_SOCKETPAIR + if(tsd->sock_pair[0] != CURL_SOCKET_BAD) { + sclose(tsd->sock_pair[0]); + tsd->sock_pair[0] = CURL_SOCKET_BAD; + } +#endif destroy_thread_sync_data(tsd); return 0; } -static int getaddrinfo_complete(struct Curl_easy *data) +static CURLcode getaddrinfo_complete(struct Curl_easy *data) { struct thread_sync_data *tsd = conn_thread_sync_data(data); - int rc; + CURLcode result; - rc = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res); + result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res); /* The tsd->res structure has been copied to async.dns and perhaps the DNS cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it. */ tsd->res = NULL; - return rc; + return result; } @@ -700,7 +707,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data, *waitp = 0; /* default to synchronous response */ #ifdef CURLRES_IPV6 - if(Curl_ipv6works(data)) + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC; #endif /* CURLRES_IPV6 */ diff --git a/Utilities/cmcurl/lib/asyn.h b/Utilities/cmcurl/lib/asyn.h index 3130395..1aab21a 100644 --- a/Utilities/cmcurl/lib/asyn.h +++ b/Utilities/cmcurl/lib/asyn.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -146,7 +148,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data, * Curl_resolver_getaddrinfo() - when using this resolver * * Returns name information about the given hostname and port number. If - * successful, the 'hostent' is returned and the forth argument will point to + * successful, the 'hostent' is returned and the fourth argument will point to * memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. * diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c index 960a1ca..52654c2 100644 --- a/Utilities/cmcurl/lib/base64.c +++ b/Utilities/cmcurl/lib/base64.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* Base64 encoding/decoding */ @@ -41,10 +43,11 @@ #include "memdebug.h" /* ---- Base64 Encoding/Decoding Table --- */ +/* Padding character string starts at offset 64. */ static const char base64[]= - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; -/* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648 +/* The Base 64 encoding with a URL and filename safe alphabet, RFC 4648 section 5 */ static const char base64url[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; @@ -52,25 +55,18 @@ static const char base64url[]= static size_t decodeQuantum(unsigned char *dest, const char *src) { size_t padding = 0; - const char *s, *p; + const char *s; unsigned long i, x = 0; for(i = 0, s = src; i < 4; i++, s++) { if(*s == '=') { - x = (x << 6); + x <<= 6; padding++; } else { - unsigned long v = 0; - p = base64; - - while(*p && (*p != *s)) { - v++; - p++; - } - - if(*p == *s) - x = (x << 6) + v; + const char *p = strchr(base64, *s); + if(p) + x = (x << 6) + curlx_uztoul(p - base64); else return 0; } @@ -107,11 +103,11 @@ CURLcode Curl_base64_decode(const char *src, unsigned char **outptr, size_t *outlen) { size_t srclen = 0; - size_t length = 0; size_t padding = 0; size_t i; size_t numQuantums; size_t rawlen = 0; + const char *padptr; unsigned char *pos; unsigned char *newstr; @@ -124,19 +120,17 @@ CURLcode Curl_base64_decode(const char *src, return CURLE_BAD_CONTENT_ENCODING; /* Find the position of any = padding characters */ - while((src[length] != '=') && src[length]) - length++; - - /* A maximum of two = padding characters is allowed */ - if(src[length] == '=') { + padptr = strchr(src, '='); + if(padptr) { padding++; - if(src[length + 1] == '=') + /* A maximum of two = padding characters is allowed */ + if(padptr[1] == '=') padding++; - } - /* Check the = padding characters weren't part way through the input */ - if(length + padding != srclen) - return CURLE_BAD_CONTENT_ENCODING; + /* Check the = padding characters weren't part way through the input */ + if(padptr + padding != src + srclen) + return CURLE_BAD_CONTENT_ENCODING; + } /* Calculate the number of quantums */ numQuantums = srclen / 4; @@ -144,7 +138,7 @@ CURLcode Curl_base64_decode(const char *src, /* Calculate the size of the decoded string */ rawlen = (numQuantums * 3) - padding; - /* Allocate our buffer including room for a zero terminator */ + /* Allocate our buffer including room for a null-terminator */ newstr = malloc(rawlen + 1); if(!newstr) return CURLE_OUT_OF_MEMORY; @@ -185,6 +179,7 @@ static CURLcode base64_encode(const char *table64, char *output; char *base64data; const char *indata = inputbuff; + const char *padstr = &table64[64]; /* Point to padding string. */ *outptr = NULL; *outlen = 0; @@ -222,27 +217,30 @@ static CURLcode base64_encode(const char *table64, switch(inputparts) { case 1: /* only one byte read */ - msnprintf(output, 5, "%c%c==", - table64[obuf[0]], - table64[obuf[1]]); + i = msnprintf(output, 5, "%c%c%s%s", + table64[obuf[0]], + table64[obuf[1]], + padstr, + padstr); break; case 2: /* two bytes read */ - msnprintf(output, 5, "%c%c%c=", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]]); + i = msnprintf(output, 5, "%c%c%c%s", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + padstr); break; default: - msnprintf(output, 5, "%c%c%c%c", - table64[obuf[0]], - table64[obuf[1]], - table64[obuf[2]], - table64[obuf[3]]); + i = msnprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]]); break; } - output += 4; + output += i; } /* Zero terminate */ @@ -270,8 +268,6 @@ static CURLcode base64_encode(const char *table64, * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * - * When encoded data length is 0, returns NULL in *outptr. - * * @unittest: 1302 */ CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, @@ -293,8 +289,6 @@ CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, * Returns CURLE_OK on success, otherwise specific error code. Function * output shall not be considered valid unless CURLE_OK is returned. * - * When encoded data length is 0, returns NULL in *outptr. - * * @unittest: 1302 */ CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize, diff --git a/Utilities/cmcurl/lib/bufref.c b/Utilities/cmcurl/lib/bufref.c index b84511e..91b0374 100644 --- a/Utilities/cmcurl/lib/bufref.c +++ b/Utilities/cmcurl/lib/bufref.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2021 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/bufref.h b/Utilities/cmcurl/lib/bufref.h index 25f65d8..96b818b 100644 --- a/Utilities/cmcurl/lib/bufref.h +++ b/Utilities/cmcurl/lib/bufref.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2021 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/c-hyper.c b/Utilities/cmcurl/lib/c-hyper.c index 6908298..86abcdb 100644 --- a/Utilities/cmcurl/lib/c-hyper.c +++ b/Utilities/cmcurl/lib/c-hyper.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -52,6 +54,7 @@ #include "multiif.h" #include "progress.h" #include "content_encoding.h" +#include "ws.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -288,7 +291,7 @@ static CURLcode status_line(struct Curl_easy *data, len); if(!data->state.hconnect || !data->set.suppress_connect_headers) { - writetype = CLIENTWRITE_HEADER; + writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS; if(data->set.include_header) writetype |= CLIENTWRITE_BODY; result = Curl_client_write(data, writetype, @@ -469,6 +472,24 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data, if(result) break; + k->deductheadercount = + (100 <= http_status && 199 >= http_status)?k->headerbytecount:0; +#ifdef USE_WEBSOCKETS + if(k->upgr101 == UPGR101_WS) { + if(http_status == 101) { + /* verify the response */ + result = Curl_ws_accept(data); + if(result) + return result; + } + else { + failf(data, "Expected 101, got %u", k->httpcode); + result = CURLE_HTTP_RETURNED_ERROR; + break; + } + } +#endif + /* Curl_http_auth_act() checks what authentication methods that are * available and decides which one (if any) to use. It will set 'newurl' * if an auth method was picked. */ @@ -690,9 +711,18 @@ static int uploadstreamed(void *userdata, hyper_context *ctx, data->state.hresult = result; return HYPER_POLL_ERROR; } - if(!fillcount) - /* done! */ - *chunk = NULL; + if(!fillcount) { + if((data->req.keepon & KEEP_SEND_PAUSE) != KEEP_SEND_PAUSE) + /* done! */ + *chunk = NULL; + else { + /* paused, save a waker */ + if(data->hyp.send_body_waker) + hyper_waker_free(data->hyp.send_body_waker); + data->hyp.send_body_waker = hyper_context_waker(ctx); + return HYPER_POLL_PENDING; + } + } else { hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount); if(copy) @@ -907,12 +937,13 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) result = CURLE_OUT_OF_MEMORY; goto error; } - if(conn->negnpn == CURL_HTTP_VERSION_2) { + if(conn->alpn == CURL_HTTP_VERSION_2) { hyper_clientconn_options_http2(options, 1); h2 = TRUE; } hyper_clientconn_options_set_preserve_header_case(options, 1); hyper_clientconn_options_set_preserve_header_order(options, 1); + hyper_clientconn_options_http1_allow_multiline_headers(options, 1); hyper_clientconn_options_exec(options, h->exec); @@ -1002,10 +1033,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) /* For HTTP/2, we show the Host: header as if we sent it, to make it look like for HTTP/1 but it isn't actually sent since :authority is then used. */ - result = Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host, - strlen(data->state.aptr.host)); - if(result) - goto error; + Curl_debug(data, CURLINFO_HEADER_OUT, data->state.aptr.host, + strlen(data->state.aptr.host)); } if(data->state.aptr.proxyuserpwd) { @@ -1047,6 +1076,21 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) goto error; } +#ifndef CURL_DISABLE_ALTSVC + if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) { + char *altused = aprintf("Alt-Used: %s:%d\r\n", + conn->conn_to_host.name, conn->conn_to_port); + if(!altused) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + result = Curl_hyper_header(data, headers, altused); + if(result) + goto error; + free(altused); + } +#endif + #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy && !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && @@ -1098,6 +1142,9 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(result) goto error; + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, headers); + result = Curl_add_timecondition(data, headers); if(result) goto error; @@ -1110,9 +1157,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(result) goto error; - result = Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2); - if(result) - goto error; + Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2); data->req.upload_chunky = FALSE; sendtask = hyper_clientconn_send(client, req); diff --git a/Utilities/cmcurl/lib/c-hyper.h b/Utilities/cmcurl/lib/c-hyper.h index d63defe..70507ad 100644 --- a/Utilities/cmcurl/lib/c-hyper.h +++ b/Utilities/cmcurl/lib/c-hyper.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -34,6 +36,7 @@ struct hyptransfer { const hyper_executor *exec; hyper_task *endtask; hyper_waker *exp100_waker; + hyper_waker *send_body_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 aa29620..a557ac6 100644 --- a/Utilities/cmcurl/lib/conncache.c +++ b/Utilities/cmcurl/lib/conncache.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -496,7 +498,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data) conn = curr->ptr; if(!CONN_INUSE(conn) && !conn->bits.close && - !conn->bits.connect_only) { + !conn->connect_only) { /* Set higher score for the age passed since the connection was used */ score = Curl_timediff(now, conn->lastused); diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h index ef11dcf..94664bc 100644 --- a/Utilities/cmcurl/lib/conncache.h +++ b/Utilities/cmcurl/lib/conncache.h @@ -21,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -29,6 +31,7 @@ * be shared. */ +#include <curl/curl.h> #include "timeval.h" struct connectdata; diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index 9bcf525..ac007c6 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -470,8 +472,10 @@ static CURLcode bindlocal(struct Curl_easy *data, } if(--portnum > 0) { - infof(data, "Bind to local port %hu failed, trying next", port); port++; /* try next port */ + if(port == 0) + break; + infof(data, "Bind to local port %hu failed, trying next", port - 1); /* We re-use/clobber the port variable here below */ if(sock->sa_family == AF_INET) si4->sin_port = ntohs(port); @@ -621,7 +625,8 @@ void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn, else data->info.conn_local_ip[0] = 0; data->info.conn_scheme = conn->handler->scheme; - data->info.conn_protocol = conn->handler->protocol; + /* conn_protocol can only provide "old" protocols */ + data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK; data->info.conn_primary_port = conn->port; data->info.conn_remote_port = conn->remote_port; data->info.conn_local_port = local_port; @@ -757,11 +762,10 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn, char local_ip[MAX_IPADR_LEN] = ""; int local_port = -1; - if(conn->transport == TRNSPRT_TCP) { - if(!conn->bits.reuse && !conn->bits.tcp_fastopen) - Curl_conninfo_remote(data, conn, sockfd); - Curl_conninfo_local(data, sockfd, local_ip, &local_port); - } /* end of TCP-only section */ + if(!conn->bits.reuse && + (conn->transport != TRNSPRT_TCP || !conn->bits.tcp_fastopen)) + Curl_conninfo_remote(data, conn, sockfd); + Curl_conninfo_local(data, sockfd, local_ip, &local_port); /* persist connection info in session handle */ Curl_persistconninfo(data, conn, local_ip, local_port); @@ -899,6 +903,8 @@ CURLcode Curl_is_connected(struct Curl_easy *data, conn->tempsock[i] = CURL_SOCKET_BAD; post_SOCKS(data, conn, sockindex, connected); connkeep(conn, "HTTP/3 default"); + if(conn->tempsock[other] != CURL_SOCKET_BAD) + Curl_quic_disconnect(data, conn, other); return CURLE_OK; } /* When a QUIC connect attempt fails, the better error explanation is in @@ -1033,7 +1039,6 @@ CURLcode Curl_is_connected(struct Curl_easy *data, (conn->tempsock[1] == CURL_SOCKET_BAD)) { /* no more addresses to try */ const char *hostname; - char buffer[STRERROR_LEN]; CURLcode failreason = result; /* if the first address family runs out of addresses to try before the @@ -1060,11 +1065,7 @@ CURLcode Curl_is_connected(struct Curl_easy *data, "%" CURL_FORMAT_TIMEDIFF_T " ms: %s", hostname, conn->port, Curl_timediff(now, data->progress.t_startsingle), -#ifdef ENABLE_QUIC - (conn->transport == TRNSPRT_QUIC) ? - curl_easy_strerror(result) : -#endif - Curl_strerror(error, buffer, sizeof(buffer))); + curl_easy_strerror(result)); Curl_quic_disconnect(data, conn, 0); Curl_quic_disconnect(data, conn, 1); @@ -1196,6 +1197,7 @@ static CURLcode singleipconnect(struct Curl_easy *data, #ifdef TCP_FASTOPEN_CONNECT int optval = 1; #endif + const char *ipmsg; char buffer[STRERROR_LEN]; curl_socket_t *sockp = &conn->tempsock[tempindex]; *sockp = CURL_SOCKET_BAD; @@ -1213,7 +1215,13 @@ static CURLcode singleipconnect(struct Curl_easy *data, Curl_closesocket(data, conn, sockfd); return CURLE_OK; } - infof(data, " Trying %s:%d...", ipaddress, port); +#ifdef ENABLE_IPV6 + if(addr.family == AF_INET6) + ipmsg = " Trying [%s]:%d..."; + else +#endif + ipmsg = " Trying %s:%d..."; + infof(data, ipmsg, ipaddress, port); #ifdef ENABLE_IPV6 is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) && @@ -1600,9 +1608,20 @@ CURLcode Curl_socket(struct Curl_easy *data, */ addr->family = ai->ai_family; - addr->socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM; - addr->protocol = conn->transport != TRNSPRT_TCP ? IPPROTO_UDP : - ai->ai_protocol; + switch(conn->transport) { + case TRNSPRT_TCP: + addr->socktype = SOCK_STREAM; + addr->protocol = IPPROTO_TCP; + break; + case TRNSPRT_UNIX: + addr->socktype = SOCK_STREAM; + addr->protocol = IPPROTO_IP; + break; + default: /* UDP and QUIC */ + addr->socktype = SOCK_DGRAM; + addr->protocol = IPPROTO_UDP; + break; + } addr->addrlen = ai->ai_addrlen; if(addr->addrlen > sizeof(struct Curl_sockaddr_storage)) @@ -1636,6 +1655,24 @@ CURLcode Curl_socket(struct Curl_easy *data, if(conn->transport == TRNSPRT_QUIC) { /* QUIC sockets need to be nonblocking */ (void)curlx_nonblock(*sockfd, TRUE); + switch(addr->family) { +#if defined(__linux__) && defined(IP_MTU_DISCOVER) + case AF_INET: { + int val = IP_PMTUDISC_DO; + (void)setsockopt(*sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &val, + sizeof(val)); + break; + } +#endif +#if defined(__linux__) && defined(IPV6_MTU_DISCOVER) + case AF_INET6: { + int val = IPV6_PMTUDISC_DO; + (void)setsockopt(*sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, + sizeof(val)); + break; + } +#endif + } } #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) @@ -1645,20 +1682,6 @@ CURLcode Curl_socket(struct Curl_easy *data, } #endif -#if defined(__linux__) && defined(IP_RECVERR) - if(addr->socktype == SOCK_DGRAM) { - int one = 1; - switch(addr->family) { - case AF_INET: - (void)setsockopt(*sockfd, SOL_IP, IP_RECVERR, &one, sizeof(one)); - break; - case AF_INET6: - (void)setsockopt(*sockfd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)); - break; - } - } -#endif - return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h index 1a055f5..582ff08 100644 --- a/Utilities/cmcurl/lib/connect.h +++ b/Utilities/cmcurl/lib/connect.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c index 4c723c3..9e345b1 100644 --- a/Utilities/cmcurl/lib/content_encoding.c +++ b/Utilities/cmcurl/lib/content_encoding.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -26,7 +28,7 @@ #include <curl/curl.h> #include <stddef.h> -#ifdef HAVE_ZLIB_H +#ifdef HAVE_LIBZ #include <cm3p/zlib.h> #endif @@ -80,8 +82,9 @@ typedef enum { ZLIB_INIT_GZIP /* initialized in transparent gzip mode */ } zlibInitState; -/* Writer parameters. */ -struct zlib_params { +/* Deflate and gzip writer. */ +struct zlib_writer { + struct contenc_writer super; zlibInitState zlib_init; /* zlib init state */ uInt trailerlen; /* Remaining trailer byte count. */ z_stream z; /* State structure for zlib. */ @@ -133,7 +136,7 @@ exit_zlib(struct Curl_easy *data, } static CURLcode process_trailer(struct Curl_easy *data, - struct zlib_params *zp) + struct zlib_writer *zp) { z_stream *z = &zp->z; CURLcode result = CURLE_OK; @@ -160,7 +163,7 @@ static CURLcode inflate_stream(struct Curl_easy *data, struct contenc_writer *writer, zlibInitState started) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ uInt nread = z->avail_in; Bytef *orig_in = z->next_in; @@ -263,7 +266,7 @@ static CURLcode inflate_stream(struct Curl_easy *data, static CURLcode deflate_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) @@ -283,7 +286,7 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data, struct contenc_writer *writer, const char *buf, size_t nbytes) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ /* Set the compressed input when this function is called */ @@ -300,7 +303,7 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data, static void deflate_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(data, z, &zp->zlib_init, CURLE_OK); @@ -312,7 +315,7 @@ static const struct content_encoding deflate_encoding = { deflate_init_writer, deflate_unencode_write, deflate_close_writer, - sizeof(struct zlib_params) + sizeof(struct zlib_writer) }; @@ -320,7 +323,7 @@ static const struct content_encoding deflate_encoding = { static CURLcode gzip_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ if(!writer->downstream) @@ -437,7 +440,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data, struct contenc_writer *writer, const char *buf, size_t nbytes) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ if(zp->zlib_init == ZLIB_INIT_GZIP) { @@ -564,7 +567,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data, static void gzip_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zlib_params *zp = (struct zlib_params *) &writer->params; + struct zlib_writer *zp = (struct zlib_writer *) writer; z_stream *z = &zp->z; /* zlib state structure */ exit_zlib(data, z, &zp->zlib_init, CURLE_OK); @@ -576,15 +579,16 @@ static const struct content_encoding gzip_encoding = { gzip_init_writer, gzip_unencode_write, gzip_close_writer, - sizeof(struct zlib_params) + sizeof(struct zlib_writer) }; #endif /* HAVE_LIBZ */ #ifdef HAVE_BROTLI -/* Writer parameters. */ -struct brotli_params { +/* Brotli writer. */ +struct brotli_writer { + struct contenc_writer super; BrotliDecoderState *br; /* State structure for brotli. */ }; @@ -629,7 +633,7 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be) static CURLcode brotli_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct brotli_params *bp = (struct brotli_params *) &writer->params; + struct brotli_writer *bp = (struct brotli_writer *) writer; (void) data; if(!writer->downstream) @@ -643,7 +647,7 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, struct contenc_writer *writer, const char *buf, size_t nbytes) { - struct brotli_params *bp = (struct brotli_params *) &writer->params; + struct brotli_writer *bp = (struct brotli_writer *) writer; const uint8_t *src = (const uint8_t *) buf; char *decomp; uint8_t *dst; @@ -690,7 +694,8 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data, static void brotli_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct brotli_params *bp = (struct brotli_params *) &writer->params; + struct brotli_writer *bp = (struct brotli_writer *) writer; + (void) data; if(bp->br) { @@ -705,14 +710,15 @@ static const struct content_encoding brotli_encoding = { brotli_init_writer, brotli_unencode_write, brotli_close_writer, - sizeof(struct brotli_params) + sizeof(struct brotli_writer) }; #endif #ifdef HAVE_ZSTD -/* Writer parameters. */ -struct zstd_params { +/* Zstd writer. */ +struct zstd_writer { + struct contenc_writer super; ZSTD_DStream *zds; /* State structure for zstd. */ void *decomp; }; @@ -720,7 +726,8 @@ struct zstd_params { static CURLcode zstd_init_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zstd_params *zp = (struct zstd_params *)&writer->params; + struct zstd_writer *zp = (struct zstd_writer *) writer; + (void)data; if(!writer->downstream) @@ -736,7 +743,7 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, const char *buf, size_t nbytes) { CURLcode result = CURLE_OK; - struct zstd_params *zp = (struct zstd_params *)&writer->params; + struct zstd_writer *zp = (struct zstd_writer *) writer; ZSTD_inBuffer in; ZSTD_outBuffer out; size_t errorCode; @@ -775,7 +782,8 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data, static void zstd_close_writer(struct Curl_easy *data, struct contenc_writer *writer) { - struct zstd_params *zp = (struct zstd_params *)&writer->params; + struct zstd_writer *zp = (struct zstd_writer *) writer; + (void)data; if(zp->decomp) { @@ -794,7 +802,7 @@ static const struct content_encoding zstd_encoding = { zstd_init_writer, zstd_unencode_write, zstd_close_writer, - sizeof(struct zstd_params) + sizeof(struct zstd_writer) }; #endif @@ -827,7 +835,7 @@ static const struct content_encoding identity_encoding = { identity_init_writer, identity_unencode_write, identity_close_writer, - 0 + sizeof(struct contenc_writer) }; @@ -919,7 +927,7 @@ static const struct content_encoding client_encoding = { client_init_writer, client_unencode_write, client_close_writer, - 0 + sizeof(struct contenc_writer) }; @@ -962,7 +970,7 @@ static const struct content_encoding error_encoding = { error_init_writer, error_unencode_write, error_close_writer, - 0 + sizeof(struct contenc_writer) }; /* Create an unencoding writer stage using the given handler. */ @@ -971,8 +979,10 @@ new_unencoding_writer(struct Curl_easy *data, const struct content_encoding *handler, struct contenc_writer *downstream) { - size_t sz = offsetof(struct contenc_writer, params) + handler->paramsize; - struct contenc_writer *writer = (struct contenc_writer *)calloc(1, sz); + struct contenc_writer *writer; + + DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer)); + writer = (struct contenc_writer *) calloc(1, handler->writersize); if(writer) { writer->handler = handler; @@ -1026,19 +1036,23 @@ static const struct content_encoding *find_encoding(const char *name, return NULL; } +/* allow no more than 5 "chained" compression steps */ +#define MAX_ENCODE_STACK 5 + /* Set-up the unencoding stack from the Content-Encoding header value. * See RFC 7231 section 3.1.2.2. */ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, const char *enclist, int maybechunked) { struct SingleRequest *k = &data->req; + int counter = 0; do { const char *name; size_t namelen; /* Parse a single encoding name. */ - while(ISSPACE(*enclist) || *enclist == ',') + while(ISBLANK(*enclist) || *enclist == ',') enclist++; name = enclist; @@ -1066,6 +1080,11 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, if(!encoding) encoding = &error_encoding; /* Defer error at stack use. */ + if(++counter >= MAX_ENCODE_STACK) { + failf(data, "Reject response due to %u content encodings", + counter); + return CURLE_BAD_CONTENT_ENCODING; + } /* Stack the unencoding stage. */ writer = new_unencoding_writer(data, encoding, k->writer_stack); if(!writer) diff --git a/Utilities/cmcurl/lib/content_encoding.h b/Utilities/cmcurl/lib/content_encoding.h index acfd0c2..3c278cf 100644 --- a/Utilities/cmcurl/lib/content_encoding.h +++ b/Utilities/cmcurl/lib/content_encoding.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,13 +20,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" struct contenc_writer { const struct content_encoding *handler; /* Encoding handler. */ struct contenc_writer *downstream; /* Downstream writer. */ - void *params; /* Encoding-specific storage (variable length). */ }; /* Content encoding writer. */ @@ -40,7 +41,7 @@ struct content_encoding { const char *buf, size_t nbytes); void (*close_writer)(struct Curl_easy *data, struct contenc_writer *writer); - size_t paramsize; + size_t writersize; }; diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index 0c2d49b..8eaedee 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /*** @@ -33,8 +35,9 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, called before any cookies are set. struct Cookie *Curl_cookie_add(struct Curl_easy *data, - struct CookieInfo *c, bool httpheader, char *lineptr, - const char *domain, const char *path); + struct CookieInfo *c, bool httpheader, bool noexpire, + char *lineptr, const char *domain, const char *path, + bool secure); The 'lineptr' parameter is a full "Set-cookie:" line as received from a server. @@ -96,8 +99,8 @@ Example set of cookies: #include "curl_get_line.h" #include "curl_memrchr.h" #include "parsedate.h" -#include "rand.h" #include "rename.h" +#include "fopen.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -439,6 +442,29 @@ static bool bad_domain(const char *domain) } /* + RFC 6265 section 4.1.1 says a server should accept this range: + + cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E + + But Firefox and Chrome as of June 2022 accept space, comma and double-quotes + fine. The prime reason for filtering out control bytes is that some HTTP + servers return 400 for requests that contain such. +*/ +static int invalid_octets(const char *p) +{ + /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */ + static const char badoctets[] = { + "\x01\x02\x03\x04\x05\x06\x07\x08\x0a" + "\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14" + "\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f" + }; + size_t len; + /* scan for all the octets that are *not* in cookie-octet */ + len = strcspn(p, badoctets); + return (p[len] != '\0'); +} + +/* * Curl_cookie_add * * Add a single cookie line to the cookie keeping object. Be aware that @@ -468,6 +494,8 @@ Curl_cookie_add(struct Curl_easy *data, struct Cookie *clist; struct Cookie *co; struct Cookie *lastc = NULL; + struct Cookie *replace_co = NULL; + struct Cookie *replace_clist = NULL; time_t now = time(NULL); bool replace_old = FALSE; bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */ @@ -477,6 +505,10 @@ Curl_cookie_add(struct Curl_easy *data, (void)data; #endif + DEBUGASSERT(MAX_SET_COOKIE_AMOUNT <= 255); /* counter is an unsigned char */ + if(data->req.setcookies >= MAX_SET_COOKIE_AMOUNT) + return NULL; + /* First, alloc and init a new struct for it */ co = calloc(1, sizeof(struct Cookie)); if(!co) @@ -505,7 +537,7 @@ Curl_cookie_add(struct Curl_easy *data, do { /* we have a <what>=<this> pair or a stand-alone word here */ name[0] = what[0] = 0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%" + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\t\r\n=] =%" MAX_NAME_TXT "[^;\r\n]", name, what)) { /* @@ -559,6 +591,13 @@ Curl_cookie_add(struct Curl_easy *data, while(*whatptr && ISBLANK(*whatptr)) whatptr++; + /* Reject cookies with a TAB inside the content */ + if(strchr(whatptr, '\t')) { + freecookie(co); + infof(data, "cookie contains TAB, dropping"); + return NULL; + } + /* * Check if we have a reserved prefix set before anything else, as we * otherwise have to test for the prefix in both the cookie name and @@ -586,6 +625,11 @@ Curl_cookie_add(struct Curl_easy *data, badcookie = TRUE; break; } + if(invalid_octets(whatptr) || invalid_octets(name)) { + infof(data, "invalid octets in name/value, cookie dropped"); + badcookie = TRUE; + break; + } } else if(!len) { /* @@ -628,7 +672,7 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(strcasecompare("domain", name)) { + else if(strcasecompare("domain", name) && whatptr[0]) { bool is_ip; /* @@ -816,7 +860,7 @@ Curl_cookie_add(struct Curl_easy *data, freecookie(co); return NULL; } - + data->req.setcookies++; } else { /* @@ -1020,12 +1064,53 @@ Curl_cookie_add(struct Curl_easy *data, } #endif + /* A non-secure cookie may not overlay an existing secure cookie. */ myhash = cookiehash(co->domain); clist = c->cookies[myhash]; - replace_old = FALSE; while(clist) { if(strcasecompare(clist->name, co->name)) { /* the names are identical */ + bool matching_domains = FALSE; + + if(clist->domain && co->domain) { + if(strcasecompare(clist->domain, co->domain)) + /* The domains are identical */ + matching_domains = TRUE; + } + else if(!clist->domain && !co->domain) + matching_domains = TRUE; + + if(matching_domains && /* the domains were identical */ + clist->spath && co->spath && /* both have paths */ + clist->secure && !co->secure && !secure) { + size_t cllen; + const char *sep; + + /* + * A non-secure cookie may not overlay an existing secure cookie. + * For an existing cookie "a" with path "/login", refuse a new + * cookie "a" with for example path "/login/en", while the path + * "/loginhelper" is ok. + */ + + sep = strchr(clist->spath + 1, '/'); + + if(sep) + cllen = sep - clist->spath; + else + cllen = strlen(clist->spath); + + if(strncasecompare(clist->spath, co->spath, cllen)) { + infof(data, "cookie '%s' for domain '%s' dropped, would " + "overlay an existing cookie", co->name, co->domain); + freecookie(co); + return NULL; + } + } + } + + if(!replace_co && strcasecompare(clist->name, co->name)) { + /* the names are identical */ if(clist->domain && co->domain) { if(strcasecompare(clist->domain, co->domain) && @@ -1040,30 +1125,7 @@ Curl_cookie_add(struct Curl_easy *data, /* the domains were identical */ if(clist->spath && co->spath) { - if(clist->secure && !co->secure && !secure) { - size_t cllen; - const char *sep; - - /* - * A non-secure cookie may not overlay an existing secure cookie. - * For an existing cookie "a" with path "/login", refuse a new - * cookie "a" with for example path "/login/en", while the path - * "/loginhelper" is ok. - */ - - sep = strchr(clist->spath + 1, '/'); - - if(sep) - cllen = sep - clist->spath; - else - cllen = strlen(clist->spath); - - if(strncasecompare(clist->spath, co->spath, cllen)) { - freecookie(co); - return NULL; - } - } - else if(strcasecompare(clist->spath, co->spath)) + if(strcasecompare(clist->spath, co->spath)) replace_old = TRUE; else replace_old = FALSE; @@ -1085,42 +1147,37 @@ Curl_cookie_add(struct Curl_easy *data, freecookie(co); return NULL; } - if(replace_old) { - co->next = clist->next; /* get the next-pointer first */ - - /* when replacing, creationtime is kept from old */ - co->creationtime = clist->creationtime; - - /* then free all the old pointers */ - free(clist->name); - free(clist->value); - free(clist->domain); - free(clist->path); - free(clist->spath); - free(clist->expirestr); - free(clist->version); - free(clist->maxage); - - *clist = *co; /* then store all the new 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 - */ - do { - lastc = clist; - clist = clist->next; - } while(clist); - break; + replace_co = co; + replace_clist = clist; } } lastc = clist; clist = clist->next; } + if(replace_co) { + co = replace_co; + clist = replace_clist; + co->next = clist->next; /* get the next-pointer first */ + + /* when replacing, creationtime is kept from old */ + co->creationtime = clist->creationtime; + + /* then free all the old pointers */ + free(clist->name); + free(clist->value); + free(clist->domain); + free(clist->path); + free(clist->spath); + free(clist->expirestr); + free(clist->version); + free(clist->maxage); + + *clist = *co; /* then store all the new data */ + + free(co); /* free the newly allocated memory */ + co = clist; + } if(c->running) /* Only show this when NOT reading the cookies from a file */ @@ -1357,7 +1414,8 @@ static struct Cookie *dup_cookie(struct Cookie *src) * * It shall only return cookies that haven't expired. */ -struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, +struct Cookie *Curl_cookie_getlist(struct Curl_easy *data, + struct CookieInfo *c, const char *host, const char *path, bool secure) { @@ -1412,6 +1470,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, mainco = newco; matches++; + if(matches >= MAX_COOKIE_SEND_AMOUNT) { + infof(data, "Included max number of cookies (%zu) in request!", + matches); + break; + } } else goto fail; @@ -1613,20 +1676,9 @@ static CURLcode cookie_output(struct Curl_easy *data, use_stdout = TRUE; } else { - unsigned char randsuffix[9]; - - if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) - return 2; - - tempstore = aprintf("%s.%s.tmp", filename, randsuffix); - if(!tempstore) - return CURLE_OUT_OF_MEMORY; - - out = fopen(tempstore, FOPEN_WRITETEXT); - if(!out) { - error = CURLE_WRITE_ERROR; + error = Curl_fopen(data, filename, &out, &tempstore); + if(error) goto error; - } } fputs("# Netscape HTTP Cookie File\n" @@ -1673,7 +1725,7 @@ static CURLcode cookie_output(struct Curl_easy *data, if(!use_stdout) { fclose(out); out = NULL; - if(Curl_rename(tempstore, filename)) { + if(tempstore && Curl_rename(tempstore, filename)) { unlink(tempstore); error = CURLE_WRITE_ERROR; goto error; diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h index 0ffe08e..abc0a2e 100644 --- a/Utilities/cmcurl/lib/cookie.h +++ b/Utilities/cmcurl/lib/cookie.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -81,10 +83,26 @@ struct CookieInfo { */ #define MAX_COOKIE_LINE 5000 -/* This is the maximum length of a cookie name or content we deal with: */ +/* Maximum length of an incoming cookie name or content we deal with. Longer + cookies are ignored. */ #define MAX_NAME 4096 #define MAX_NAME_TXT "4095" +/* Maximum size for an outgoing cookie line libcurl will use in an http + request. This is the default maximum length used in some versions of Apache + httpd. */ +#define MAX_COOKIE_HEADER_LEN 8190 + +/* Maximum number of cookies libcurl will send in a single request, even if + there might be more cookies that match. One reason to cap the number is to + keep the maximum HTTP request within the maximum allowed size. */ +#define MAX_COOKIE_SEND_AMOUNT 150 + +/* Maximum number of Set-Cookie: lines accepted in a single response. If more + such header lines are received, they are ignored. This value must be less + than 256 since an unsigned char is used to count. */ +#define MAX_SET_COOKIE_AMOUNT 50 + struct Curl_easy; /* * Add a cookie to the internal list of cookies. The domain and path arguments @@ -97,7 +115,8 @@ struct Cookie *Curl_cookie_add(struct Curl_easy *data, const char *domain, const char *path, bool secure); -struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, const char *host, +struct Cookie *Curl_cookie_getlist(struct Curl_easy *data, + 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); diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c index 842fd7f..72e778b 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.c +++ b/Utilities/cmcurl/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -277,7 +279,7 @@ Curl_he2ai(const struct hostent *he, int port) for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { size_t ss_size; - size_t namelen = strlen(he->h_name) + 1; /* include zero termination */ + size_t namelen = strlen(he->h_name) + 1; /* include null-terminatior */ #ifdef ENABLE_IPV6 if(he->h_addrtype == AF_INET6) ss_size = sizeof(struct sockaddr_in6); diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h index 73a8c1b..b778121 100644 --- a/Utilities/cmcurl/lib/curl_addrinfo.h +++ b/Utilities/cmcurl/lib/curl_addrinfo.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_base64.h b/Utilities/cmcurl/lib/curl_base64.h index 4cb9d73..85368a1 100644 --- a/Utilities/cmcurl/lib/curl_base64.h +++ b/Utilities/cmcurl/lib/curl_base64.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ CURLcode Curl_base64_encode(const char *inputbuff, size_t insize, diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake index 4a6f90e..b8a58c8 100644 --- a/Utilities/cmcurl/lib/curl_config.h.cmake +++ b/Utilities/cmcurl/lib/curl_config.h.cmake @@ -18,15 +18,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* lib/curl_config.h.in. Generated somehow by cmake. */ #include <cm3p/kwiml/abi.h> -/* when building libcurl itself */ -#cmakedefine BUILDING_LIBCURL 1 - -/* to disable alt-svc */ +/* disables alt-svc */ #cmakedefine CURL_DISABLE_ALTSVC 1 /* disables cookies support */ @@ -138,9 +137,6 @@ /* Define to 1 if you have the alarm function. */ #cmakedefine HAVE_ALARM 1 -/* Define to 1 if you have the <alloca.h> header file. */ -#cmakedefine HAVE_ALLOCA_H 1 - /* Define to 1 if you have the <arpa/inet.h> header file. */ #cmakedefine HAVE_ARPA_INET_H 1 @@ -150,6 +146,12 @@ /* Define to 1 if you have the <assert.h> header file. */ #cmakedefine HAVE_ASSERT_H 1 +/* Define to 1 if you have _Atomic support. */ +#cmakedefine HAVE_ATOMIC 1 + +/* Define to 1 if you have the `fchmod' function. */ +#cmakedefine HAVE_FCHMOD 1 + /* Define to 1 if you have the `basename' function. */ #cmakedefine HAVE_BASENAME 1 @@ -165,12 +167,6 @@ /* Define to 1 if you have the `closesocket' function. */ #cmakedefine HAVE_CLOSESOCKET 1 -/* 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 <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 @@ -192,15 +188,15 @@ /* Define to 1 if you have a working getaddrinfo function. */ #cmakedefine HAVE_GETADDRINFO 1 +/* Define to 1 if the getaddrinfo function is threadsafe. */ +#cmakedefine HAVE_GETADDRINFO_THREADSAFE 1 + /* Define to 1 if you have the `geteuid' function. */ #cmakedefine HAVE_GETEUID 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 - /* Define to 1 if you have the gethostbyname_r function. */ #cmakedefine HAVE_GETHOSTBYNAME_R 1 @@ -225,9 +221,6 @@ /* Define to 1 if you have the `getppid' function. */ #cmakedefine HAVE_GETPPID 1 -/* Define to 1 if you have the `getprotobyname' function. */ -#cmakedefine HAVE_GETPROTOBYNAME 1 - /* Define to 1 if you have the `getpeername' function. */ #cmakedefine HAVE_GETPEERNAME 1 @@ -279,18 +272,9 @@ /* Define to 1 if you have the `idna_strerror' function. */ #cmakedefine HAVE_IDNA_STRERROR 1 -/* Define to 1 if you have the `idn_free' function. */ -#cmakedefine HAVE_IDN_FREE 1 - -/* Define to 1 if you have the <idn-free.h> header file. */ -#cmakedefine HAVE_IDN_FREE_H 1 - /* Define to 1 if you have the <ifaddrs.h> header file. */ #cmakedefine HAVE_IFADDRS_H 1 -/* Define to 1 if you have the `inet_addr' function. */ -#cmakedefine HAVE_INET_ADDR 1 - /* Define to 1 if you have a IPv6 capable working inet_ntop function. */ #cmakedefine HAVE_INET_NTOP 1 @@ -306,9 +290,6 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #cmakedefine HAVE_INTTYPES_H 1 -/* Define to 1 if you have the ioctl function. */ -#cmakedefine HAVE_IOCTL 1 - /* Define to 1 if you have the ioctlsocket function. */ #cmakedefine HAVE_IOCTLSOCKET 1 @@ -331,21 +312,9 @@ /* Define to 1 if you have the <io.h> header file. */ #cmakedefine HAVE_IO_H 1 -/* if you have the Kerberos4 libraries (including -ldes) */ -#cmakedefine HAVE_KRB4 1 - -/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ -#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM 1 - -/* Define to 1 if you have the <krb.h> header file. */ -#cmakedefine HAVE_KRB_H 1 - /* Define to 1 if you have the lber.h header file. */ #cmakedefine HAVE_LBER_H 1 -/* Define to 1 if you have the ldapssl.h header file. */ -#cmakedefine HAVE_LDAPSSL_H 1 - /* Define to 1 if you have the ldap.h header file. */ #cmakedefine HAVE_LDAP_H 1 @@ -367,24 +336,12 @@ /* Define to 1 if you have the idn2.h header file. */ #cmakedefine HAVE_IDN2_H 1 -/* Define to 1 if you have the `resolv' library (-lresolv). */ -#cmakedefine HAVE_LIBRESOLV 1 - -/* Define to 1 if you have the `resolve' library (-lresolve). */ -#cmakedefine HAVE_LIBRESOLVE 1 - /* Define to 1 if you have the `socket' library (-lsocket). */ #cmakedefine HAVE_LIBSOCKET 1 /* Define to 1 if you have the `ssh2' library (-lssh2). */ #cmakedefine HAVE_LIBSSH2 1 -/* Define to 1 if you have the <libssh2.h> header file. */ -#cmakedefine HAVE_LIBSSH2_H 1 - -/* Define to 1 if you have the <libssh/libssh.h> header file. */ -#cmakedefine HAVE_LIBSSH_LIBSSH_H 1 - /* if zlib is available */ #cmakedefine HAVE_LIBZ 1 @@ -397,20 +354,11 @@ /* Define to 1 if you have the <locale.h> header file. */ #cmakedefine HAVE_LOCALE_H 1 -/* Define to 1 if you have a working localtime_r function. */ -#cmakedefine HAVE_LOCALTIME_R 1 - /* Define to 1 if the compiler supports the 'long long' data type. */ #if KWIML_ABI_SIZEOF_LONG_LONG # define HAVE_LONGLONG 1 #endif -/* Define to 1 if you have the malloc.h header file. */ -#cmakedefine HAVE_MALLOC_H 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#cmakedefine HAVE_MEMORY_H 1 - /* Define to 1 if you have the MSG_NOSIGNAL flag. */ #cmakedefine HAVE_MSG_NOSIGNAL 1 @@ -429,42 +377,12 @@ /* Define to 1 if you have the <net/if.h> header file. */ #cmakedefine HAVE_NET_IF_H 1 -/* Define to 1 if NI_WITHSCOPEID exists and works. */ -#cmakedefine HAVE_NI_WITHSCOPEID 1 - /* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */ #cmakedefine HAVE_OLD_GSSMIT 1 -/* Define to 1 if you have the <openssl/crypto.h> header file. */ -#cmakedefine HAVE_OPENSSL_CRYPTO_H 1 - -/* Define to 1 if you have the <openssl/err.h> header file. */ -#cmakedefine HAVE_OPENSSL_ERR_H 1 - -/* Define to 1 if you have the <openssl/pem.h> header file. */ -#cmakedefine HAVE_OPENSSL_PEM_H 1 - -/* Define to 1 if you have the <openssl/pkcs12.h> header file. */ -#cmakedefine HAVE_OPENSSL_PKCS12_H 1 - -/* Define to 1 if you have the <openssl/rsa.h> header file. */ -#cmakedefine HAVE_OPENSSL_RSA_H 1 - -/* Define to 1 if you have the <openssl/ssl.h> header file. */ -#cmakedefine HAVE_OPENSSL_SSL_H 1 - -/* Define to 1 if you have the <openssl/x509.h> header file. */ -#cmakedefine HAVE_OPENSSL_X509_H 1 - -/* Define to 1 if you have the <pem.h> header file. */ -#cmakedefine HAVE_PEM_H 1 - /* Define to 1 if you have the `pipe' function. */ #cmakedefine HAVE_PIPE 1 -/* Define to 1 if you have a working poll function. */ -#cmakedefine HAVE_POLL 1 - /* If you have a fine poll */ #cmakedefine HAVE_POLL_FINE 1 @@ -483,18 +401,9 @@ /* Define to 1 if you have the `RAND_egd' function. */ #cmakedefine HAVE_RAND_EGD 1 -/* Define to 1 if you have the `RAND_screen' function. */ -#cmakedefine HAVE_RAND_SCREEN 1 - -/* Define to 1 if you have the `RAND_status' function. */ -#cmakedefine HAVE_RAND_STATUS 1 - /* Define to 1 if you have the recv function. */ #cmakedefine HAVE_RECV 1 -/* Define to 1 if you have the recvfrom function. */ -#cmakedefine HAVE_RECVFROM 1 - /* Define to 1 if you have the select function. */ #cmakedefine HAVE_SELECT 1 @@ -522,9 +431,6 @@ /* Define to 1 if you have the `setrlimit' function. */ #cmakedefine HAVE_SETRLIMIT 1 -/* Define to 1 if you have the setsockopt function. */ -#cmakedefine HAVE_SETSOCKOPT 1 - /* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */ #cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1 @@ -549,27 +455,27 @@ /* Define to 1 if you have the `socket' function. */ #cmakedefine HAVE_SOCKET 1 +/* Define to 1 if you have the socketpair function. */ +#cmakedefine HAVE_SOCKETPAIR 1 + /* Define to 1 if you have the <ssl.h> header file. */ #cmakedefine HAVE_SSL_H 1 +/* Define to 1 if you have the <stdatomic.h> header file. */ +#cmakedefine HAVE_STDATOMIC_H 1 + /* Define to 1 if you have the <stdbool.h> header file. */ #cmakedefine HAVE_STDBOOL_H 1 /* Define to 1 if you have the <stdint.h> header file. */ #cmakedefine HAVE_STDINT_H 1 -/* Define to 1 if you have the <stdio.h> header file. */ -#cmakedefine HAVE_STDIO_H 1 - /* Define to 1 if you have the <stdlib.h> header file. */ #cmakedefine HAVE_STDLIB_H 1 /* Define to 1 if you have the strcasecmp function. */ #cmakedefine HAVE_STRCASECMP 1 -/* Define to 1 if you have the strcasestr function. */ -#cmakedefine HAVE_STRCASESTR 1 - /* Define to 1 if you have the strcmpi function. */ #cmakedefine HAVE_STRCMPI 1 @@ -588,18 +494,9 @@ /* Define to 1 if you have the <string.h> header file. */ #cmakedefine HAVE_STRING_H 1 -/* Define to 1 if you have the strncmpi function. */ -#cmakedefine HAVE_STRNCMPI 1 - -/* Define to 1 if you have the strnicmp function. */ -#cmakedefine HAVE_STRNICMP 1 - /* Define to 1 if you have the <stropts.h> header file. */ #cmakedefine HAVE_STROPTS_H 1 -/* Define to 1 if you have the strstr function. */ -#cmakedefine HAVE_STRSTR 1 - /* Define to 1 if you have the strtok_r function. */ #cmakedefine HAVE_STRTOK_R 1 @@ -645,9 +542,6 @@ /* Define to 1 if you have the <sys/types.h> header file. */ #cmakedefine HAVE_SYS_TYPES_H 1 -/* Define to 1 if you have the <sys/uio.h> header file. */ -#cmakedefine HAVE_SYS_UIO_H 1 - /* Define to 1 if you have the <sys/un.h> header file. */ #cmakedefine HAVE_SYS_UN_H 1 @@ -663,15 +557,6 @@ /* Define to 1 if you have the <time.h> header file. */ #cmakedefine HAVE_TIME_H 1 -/* Define to 1 if you have the <tld.h> header file. */ -#cmakedefine HAVE_TLD_H 1 - -/* Define to 1 if you have the `tld_strerror' function. */ -#cmakedefine HAVE_TLD_STRERROR 1 - -/* Define to 1 if you have the `uname' function. */ -#cmakedefine HAVE_UNAME 1 - /* Define to 1 if you have the <unistd.h> header file. */ #cmakedefine HAVE_UNISTD_H 1 @@ -690,9 +575,6 @@ /* Define to 1 if compiler supports old gcc variadic macro style. */ #cmakedefine HAVE_VARIADIC_MACROS_GCC 1 -/* Define to 1 if you have the winber.h header file. */ -#cmakedefine HAVE_WINBER_H 1 - /* Define to 1 if you have the windows.h header file. */ #cmakedefine HAVE_WINDOWS_H 1 @@ -705,28 +587,12 @@ /* Define this symbol if your OS supports changing the contents of argv */ #cmakedefine HAVE_WRITABLE_ARGV 1 -/* Define to 1 if you have the writev function. */ -#cmakedefine HAVE_WRITEV 1 - /* Define to 1 if you have the ws2tcpip.h header file. */ #cmakedefine HAVE_WS2TCPIP_H 1 -/* Define to 1 if you have the <x509.h> header file. */ -#cmakedefine HAVE_X509_H 1 - /* Define if you have the <process.h> header file. */ #cmakedefine HAVE_PROCESS_H 1 -/* if you have the zlib.h header file */ -#cmakedefine HAVE_ZLIB_H 1 - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#cmakedefine LT_OBJDIR ${LT_OBJDIR} - -/* If you lack a fine basename() prototype */ -#cmakedefine NEED_BASENAME_PROTO 1 - /* Define to 1 if you need the lber.h header file even with ldap.h */ #cmakedefine NEED_LBER_H 1 @@ -760,84 +626,6 @@ /* a suitable file to read random data from */ #cmakedefine RANDOM_FILE "${RANDOM_FILE}" -/* Define to the type of arg 1 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1} - -/* Define to the type pointed by arg 2 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2} - -/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ -#cmakedefine RECVFROM_TYPE_ARG2_IS_VOID 1 - -/* Define to the type of arg 3 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3} - -/* Define to the type of arg 4 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4} - -/* Define to the type pointed by arg 5 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5} - -/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ -#cmakedefine RECVFROM_TYPE_ARG5_IS_VOID 1 - -/* Define to the type pointed by arg 6 for recvfrom. */ -#cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6} - -/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ -#cmakedefine RECVFROM_TYPE_ARG6_IS_VOID 1 - -/* Define to the function return type for recvfrom. */ -#cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV} - -/* Define to the type of arg 1 for recv. */ -#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1} - -/* Define to the type of arg 2 for recv. */ -#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2} - -/* Define to the type of arg 3 for recv. */ -#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3} - -/* Define to the type of arg 4 for recv. */ -#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4} - -/* Define to the function return type for recv. */ -#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV} - -/* Define to the type qualifier of arg 5 for select. */ -#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5} - -/* Define to the type of arg 1 for select. */ -#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1} - -/* Define to the type of args 2, 3 and 4 for select. */ -#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234} - -/* Define to the type of arg 5 for select. */ -#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5} - -/* Define to the function return type for select. */ -#cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV} - -/* Define to the type qualifier of arg 2 for send. */ -#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2} - -/* Define to the type of arg 1 for send. */ -#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1} - -/* Define to the type of arg 2 for send. */ -#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2} - -/* Define to the type of arg 3 for send. */ -#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3} - -/* Define to the type of arg 4 for send. */ -#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4} - -/* Define to the function return type for send. */ -#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV} - /* Note: SIZEOF_* variables are fetched with CMake through check_type_size(). As per CMake documentation on CheckTypeSize, C preprocessor code is @@ -882,9 +670,6 @@ ${SIZEOF_TIME_T_CODE} /* Define to 1 if you have the ANSI C header files. */ #cmakedefine STDC_HEADERS 1 -/* Define to the type of arg 3 for strerror_r. */ -#cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3} - /* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ #cmakedefine TIME_WITH_SYS_TIME 1 @@ -918,6 +703,9 @@ ${SIZEOF_TIME_T_CODE} /* if libSSH2 is in use */ #cmakedefine USE_LIBSSH2 1 +/* if libPSL is in use */ +#cmakedefine USE_LIBPSL 1 + /* If you want to build curl with the built-in manual */ #cmakedefine USE_MANUAL 1 @@ -967,9 +755,6 @@ ${SIZEOF_TIME_T_CODE} /* enable multiple SSL backends */ #cmakedefine CURL_WITH_MULTI_SSL 1 -/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ -#cmakedefine USE_YASSLEMUL 1 - /* Version number of package */ #cmakedefine VERSION ${VERSION} @@ -1023,3 +808,6 @@ ${SIZEOF_TIME_T_CODE} /* to make the compiler know the prototypes of Windows IDN APIs */ #cmakedefine WANT_IDN_PROTOTYPES 1 + +/* Define to 1 to enable websocket support. */ +#cmakedefine USE_WEBSOCKETS 1 diff --git a/Utilities/cmcurl/lib/curl_ctype.c b/Utilities/cmcurl/lib/curl_ctype.c deleted file mode 100644 index 233a69e..0000000 --- a/Utilities/cmcurl/lib/curl_ctype.c +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2022, 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" - -#undef _U -#define _U (1<<0) /* upper case */ -#undef _L -#define _L (1<<1) /* lower case */ -#undef _N -#define _N (1<<2) /* decimal numerical digit */ -#undef _S -#define _S (1<<3) /* space */ -#undef _P -#define _P (1<<4) /* punctuation */ -#undef _C -#define _C (1<<5) /* control */ -#undef _X -#define _X (1<<6) /* hexadecimal letter */ -#undef _B -#define _B (1<<7) /* blank */ - -static const unsigned char ascii[128] = { - _C, _C, _C, _C, _C, _C, _C, _C, - _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, - _C, _C, _C, _C, _C, _C, _C, _C, - _C, _C, _C, _C, _C, _C, _C, _C, - _S|_B, _P, _P, _P, _P, _P, _P, _P, - _P, _P, _P, _P, _P, _P, _P, _P, - _N, _N, _N, _N, _N, _N, _N, _N, - _N, _N, _P, _P, _P, _P, _P, _P, - _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, - _U, _U, _U, _U, _U, _U, _U, _U, - _U, _U, _U, _U, _U, _U, _U, _U, - _U, _U, _U, _P, _P, _P, _P, _P, - _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, - _L, _L, _L, _L, _L, _L, _L, _L, - _L, _L, _L, _L, _L, _L, _L, _L, - _L, _L, _L, _P, _P, _P, _P, _C -}; - -int Curl_isspace(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & _S); -} - -int Curl_isdigit(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & _N); -} - -int Curl_isalnum(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_N|_U|_L)); -} - -int Curl_isxdigit(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_N|_X)); -} - -int Curl_isgraph(int c) -{ - if((c < 0) || (c >= 0x80) || (c == ' ')) - return FALSE; - return (ascii[c] & (_N|_X|_U|_L|_P|_S)); -} - -int Curl_isprint(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_N|_X|_U|_L|_P|_S)); -} - -int Curl_isalpha(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_U|_L)); -} - -int Curl_isupper(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_U)); -} - -int Curl_islower(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_L)); -} - -int Curl_iscntrl(int c) -{ - if((c < 0) || (c >= 0x80)) - return FALSE; - return (ascii[c] & (_C)); -} - diff --git a/Utilities/cmcurl/lib/curl_ctype.h b/Utilities/cmcurl/lib/curl_ctype.h index 2fa749d..dc6b8ca 100644 --- a/Utilities/cmcurl/lib/curl_ctype.h +++ b/Utilities/cmcurl/lib/curl_ctype.h @@ -20,34 +20,28 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ -#include "curl_setup.h" +#define ISLOWHEXALHA(x) (((x) >= 'a') && ((x) <= 'f')) +#define ISUPHEXALHA(x) (((x) >= 'A') && ((x) <= 'F')) -int Curl_isspace(int c); -int Curl_isdigit(int c); -int Curl_isalnum(int c); -int Curl_isxdigit(int c); -int Curl_isgraph(int c); -int Curl_isprint(int c); -int Curl_isalpha(int c); -int Curl_isupper(int c); -int Curl_islower(int c); -int Curl_iscntrl(int c); +#define ISLOWCNTRL(x) ((x) >= 0 && ((x) <= 0x1f)) +#define IS7F(x) ((x) == 0x7f) -#define ISSPACE(x) (Curl_isspace((int) ((unsigned char)x))) -#define ISDIGIT(x) (Curl_isdigit((int) ((unsigned char)x))) -#define ISALNUM(x) (Curl_isalnum((int) ((unsigned char)x))) -#define ISXDIGIT(x) (Curl_isxdigit((int) ((unsigned char)x))) -#define ISGRAPH(x) (Curl_isgraph((int) ((unsigned char)x))) -#define ISALPHA(x) (Curl_isalpha((int) ((unsigned char)x))) -#define ISPRINT(x) (Curl_isprint((int) ((unsigned char)x))) -#define ISUPPER(x) (Curl_isupper((int) ((unsigned char)x))) -#define ISLOWER(x) (Curl_islower((int) ((unsigned char)x))) -#define ISCNTRL(x) (Curl_iscntrl((int) ((unsigned char)x))) -#define ISASCII(x) (((x) >= 0) && ((x) <= 0x80)) +#define ISLOWPRINT(x) (((x) >= 9) && ((x) <= 0x0d)) -#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ - (((unsigned char)x) == '\t')) +#define ISPRINT(x) (ISLOWPRINT(x) || (((x) >= ' ') && ((x) <= 0x7e))) +#define ISGRAPH(x) (ISLOWPRINT(x) || (((x) > ' ') && ((x) <= 0x7e))) +#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x)) +#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x)) +#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x)) +#define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x)) +#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z')) +#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z')) +#define ISDIGIT(x) (((x) >= '0') && ((x) <= '9')) +#define ISBLANK(x) (((x) == ' ') || ((x) == '\t')) +#define ISSPACE(x) (ISBLANK(x) || (((x) >= 0xa) && ((x) <= 0x0d))) #endif /* HEADER_CURL_CTYPE_H */ diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c index 5f28ef4..a2bf648 100644 --- a/Utilities/cmcurl/lib/curl_des.c +++ b/Utilities/cmcurl/lib/curl_des.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -39,7 +41,7 @@ * * The function is a port of the Java based oddParity() function over at: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * * Parameters: * diff --git a/Utilities/cmcurl/lib/curl_des.h b/Utilities/cmcurl/lib/curl_des.h index 3d0fd92..c1c1674 100644 --- a/Utilities/cmcurl/lib/curl_des.h +++ b/Utilities/cmcurl/lib/curl_des.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_endian.c b/Utilities/cmcurl/lib/curl_endian.c index ecde74b..3cc7734 100644 --- a/Utilities/cmcurl/lib/curl_endian.c +++ b/Utilities/cmcurl/lib/curl_endian.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_endian.h b/Utilities/cmcurl/lib/curl_endian.h index 4e12d7d..758d55f 100644 --- a/Utilities/cmcurl/lib/curl_endian.h +++ b/Utilities/cmcurl/lib/curl_endian.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* Converts a 16-bit integer from little endian */ diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c index 4bfa585..0dd1eb5 100644 --- a/Utilities/cmcurl/lib/curl_fnmatch.c +++ b/Utilities/cmcurl/lib/curl_fnmatch.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_fnmatch.h b/Utilities/cmcurl/lib/curl_fnmatch.h index 1c80ea7..8324be5 100644 --- a/Utilities/cmcurl/lib/curl_fnmatch.h +++ b/Utilities/cmcurl/lib/curl_fnmatch.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #define CURL_FNMATCH_MATCH 0 diff --git a/Utilities/cmcurl/lib/curl_get_line.c b/Utilities/cmcurl/lib/curl_get_line.c index 8f3b0bd..22e3705 100644 --- a/Utilities/cmcurl/lib/curl_get_line.c +++ b/Utilities/cmcurl/lib/curl_get_line.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,12 +18,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ - !defined(CURL_DISABLE_HSTS) + !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC) #include "curl_get_line.h" #include "curl_memory.h" @@ -31,8 +33,8 @@ #include "memdebug.h" /* - * get_line() makes sure to only return complete whole lines that fit in 'len' - * bytes and end with a newline. + * Curl_get_line() makes sure to only return complete whole lines that fit in + * 'len' bytes and end with a newline. */ char *Curl_get_line(char *buf, int len, FILE *input) { diff --git a/Utilities/cmcurl/lib/curl_get_line.h b/Utilities/cmcurl/lib/curl_get_line.h index 597aa09..b2a534d 100644 --- a/Utilities/cmcurl/lib/curl_get_line.h +++ b/Utilities/cmcurl/lib/curl_get_line.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* get_line() makes sure to only return complete whole lines that fit in 'len' diff --git a/Utilities/cmcurl/lib/curl_gethostname.c b/Utilities/cmcurl/lib/curl_gethostname.c index 2d5ff61..4747e93 100644 --- a/Utilities/cmcurl/lib/curl_gethostname.c +++ b/Utilities/cmcurl/lib/curl_gethostname.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_gethostname.h b/Utilities/cmcurl/lib/curl_gethostname.h index 2161c40..b736096 100644 --- a/Utilities/cmcurl/lib/curl_gethostname.h +++ b/Utilities/cmcurl/lib/curl_gethostname.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* Hostname buffer size */ diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c index 1543a0f..01ab48e 100644 --- a/Utilities/cmcurl/lib/curl_gssapi.c +++ b/Utilities/cmcurl/lib/curl_gssapi.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -89,7 +91,7 @@ static size_t display_gss_error(OM_uint32 status, int type, OM_uint32 maj_stat; OM_uint32 min_stat; OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; + gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER; do { maj_stat = gss_display_status(&min_stat, @@ -98,10 +100,12 @@ static size_t display_gss_error(OM_uint32 status, int type, GSS_C_NO_OID, &msg_ctx, &status_string); - if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { - len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, - "%.*s. ", (int)status_string.length, - (char *)status_string.value); + if(maj_stat == GSS_S_COMPLETE && status_string.length > 0) { + if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { + len += msnprintf(buf + len, GSS_LOG_BUFFER_LEN - len, + "%.*s. ", (int)status_string.length, + (char *)status_string.value); + } } gss_release_buffer(&min_stat, &status_string); } while(!GSS_ERROR(maj_stat) && msg_ctx); diff --git a/Utilities/cmcurl/lib/curl_gssapi.h b/Utilities/cmcurl/lib/curl_gssapi.h index 466d09e..b4ed482 100644 --- a/Utilities/cmcurl/lib/curl_gssapi.h +++ b/Utilities/cmcurl/lib/curl_gssapi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2011 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2011 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h index 5755655..36c0bd6 100644 --- a/Utilities/cmcurl/lib/curl_hmac.h +++ b/Utilities/cmcurl/lib/curl_hmac.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,10 +20,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include <curl/curl.h> + #define HMAC_MD5_LENGTH 16 typedef CURLcode (* HMAC_hinit_func)(void *context); diff --git a/Utilities/cmcurl/lib/curl_krb5.h b/Utilities/cmcurl/lib/curl_krb5.h index ca06840..ccd6f10 100644 --- a/Utilities/cmcurl/lib/curl_krb5.h +++ b/Utilities/cmcurl/lib/curl_krb5.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ struct Curl_sec_client_mech { diff --git a/Utilities/cmcurl/lib/curl_ldap.h b/Utilities/cmcurl/lib/curl_ldap.h index 124e18b..ba3ede4 100644 --- a/Utilities/cmcurl/lib/curl_ldap.h +++ b/Utilities/cmcurl/lib/curl_ldap.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_LDAP extern const struct Curl_handler Curl_handler_ldap; diff --git a/Utilities/cmcurl/lib/curl_md4.h b/Utilities/cmcurl/lib/curl_md4.h index f9dafcb..8049355 100644 --- a/Utilities/cmcurl/lib/curl_md4.h +++ b/Utilities/cmcurl/lib/curl_md4.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h index b7d7c1f..7893296 100644 --- a/Utilities/cmcurl/lib/curl_md5.h +++ b/Utilities/cmcurl/lib/curl_md5.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h index 5806290..092fc9f 100644 --- a/Utilities/cmcurl/lib/curl_memory.h +++ b/Utilities/cmcurl/lib/curl_memory.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/curl_memrchr.c b/Utilities/cmcurl/lib/curl_memrchr.c index 0bd845f..c329a61 100644 --- a/Utilities/cmcurl/lib/curl_memrchr.c +++ b/Utilities/cmcurl/lib/curl_memrchr.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_memrchr.h b/Utilities/cmcurl/lib/curl_memrchr.h index c8394bb..e7654e1 100644 --- a/Utilities/cmcurl/lib/curl_memrchr.h +++ b/Utilities/cmcurl/lib/curl_memrchr.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c index 32c03a5..309dccb 100644 --- a/Utilities/cmcurl/lib/curl_multibyte.c +++ b/Utilities/cmcurl/lib/curl_multibyte.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/curl_multibyte.h b/Utilities/cmcurl/lib/curl_multibyte.h index 491155e..9297148 100644 --- a/Utilities/cmcurl/lib/curl_multibyte.h +++ b/Utilities/cmcurl/lib/curl_multibyte.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c index f3b8b13..38e193c 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.c +++ b/Utilities/cmcurl/lib/curl_ntlm_core.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -27,7 +29,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -58,14 +60,19 @@ #if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL) -#ifdef USE_WOLFSSL -#include <wolfssl/options.h> -#endif - +#if defined(USE_OPENSSL) # include <openssl/des.h> # include <openssl/md5.h> # include <openssl/ssl.h> # include <openssl/rand.h> +#else +# include <wolfssl/options.h> +# include <wolfssl/openssl/des.h> +# include <wolfssl/openssl/md5.h> +# include <wolfssl/openssl/ssl.h> +# include <wolfssl/openssl/rand.h> +#endif + # if (defined(OPENSSL_VERSION_NUMBER) && \ (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL) # define DES_key_schedule des_key_schedule diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h index 5e52bb2..60444c9 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_core.h +++ b/Utilities/cmcurl/lib/curl_ntlm_core.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -35,10 +37,10 @@ #define NTLM_NEEDS_NSS_INIT #endif -#if defined(USE_OPENSSL) || defined(USE_WOLFSSL) #ifdef USE_WOLFSSL # include <wolfssl/options.h> -#endif +# include <wolfssl/openssl/ssl.h> +#elif defined(USE_OPENSSL) # include <openssl/ssl.h> #endif diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c index 5a3bc3c..33dcf0c 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_wb.c +++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -28,7 +30,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.h b/Utilities/cmcurl/lib/curl_ntlm_wb.h index 961b568..1f04db8 100644 --- a/Utilities/cmcurl/lib/curl_ntlm_wb.h +++ b/Utilities/cmcurl/lib/curl_ntlm_wb.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/curl_path.c index a1669d1..b55e830 100644 --- a/Utilities/cmcurl/lib/curl_path.c +++ b/Utilities/cmcurl/lib/curl_path.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl AND ISC + * ***************************************************************************/ #include "curl_setup.h" @@ -120,7 +122,8 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir) bool relativePath = false; static const char WHITESPACE[] = " \t\r\n"; - if(!*cp) { + DEBUGASSERT(homedir); + if(!*cp || !homedir) { *cpp = NULL; *path = NULL; return CURLE_QUOTE_ERROR; diff --git a/Utilities/cmcurl/lib/curl_path.h b/Utilities/cmcurl/lib/curl_path.h index a376bd1..98e56ea 100644 --- a/Utilities/cmcurl/lib/curl_path.h +++ b/Utilities/cmcurl/lib/curl_path.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_printf.h b/Utilities/cmcurl/lib/curl_printf.h index 9fa625f..3823828 100644 --- a/Utilities/cmcurl/lib/curl_printf.h +++ b/Utilities/cmcurl/lib/curl_printf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/curl_range.c b/Utilities/cmcurl/lib/curl_range.c index 24bdb30..dd92d05 100644 --- a/Utilities/cmcurl/lib/curl_range.c +++ b/Utilities/cmcurl/lib/curl_range.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -45,7 +47,7 @@ CURLcode Curl_range(struct Curl_easy *data) from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) diff --git a/Utilities/cmcurl/lib/curl_range.h b/Utilities/cmcurl/lib/curl_range.h index 0a07baf..33570ab 100644 --- a/Utilities/cmcurl/lib/curl_range.h +++ b/Utilities/cmcurl/lib/curl_range.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c index 2fa0267..b0c3710 100644 --- a/Utilities/cmcurl/lib/curl_rtmp.c +++ b/Utilities/cmcurl/lib/curl_rtmp.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com> + * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012, Howard Chu, <hyc@highlandsun.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_rtmp.h b/Utilities/cmcurl/lib/curl_rtmp.h index f45fa71..f856085 100644 --- a/Utilities/cmcurl/lib/curl_rtmp.h +++ b/Utilities/cmcurl/lib/curl_rtmp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010 - 2020, Howard Chu, <hyc@highlandsun.com> + * Copyright (C) 2010 - 2022, Howard Chu, <hyc@highlandsun.com> * * 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifdef USE_LIBRTMP extern const struct Curl_handler Curl_handler_rtmp; diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c index 48d6625..9684ee4 100644 --- a/Utilities/cmcurl/lib/curl_sasl.c +++ b/Utilities/cmcurl/lib/curl_sasl.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC2195 CRAM-MD5 authentication * RFC2617 Basic and Digest Access Authentication * RFC2831 DIGEST-MD5 authentication diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h index d377ae7..c709d56 100644 --- a/Utilities/cmcurl/lib/curl_sasl.h +++ b/Utilities/cmcurl/lib/curl_sasl.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index 3dd5950..c3ad25f 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -20,12 +20,19 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #if defined(BUILDING_LIBCURL) && !defined(CURL_NO_OLDIES) #define CURL_NO_OLDIES #endif +/* define mingw version macros, eg __MINGW{32,64}_{MINOR,MAJOR}_VERSION */ +#ifdef __MINGW32__ +#include <_mingw.h> +#endif + /* * Disable Visual Studio warnings: * 4127 "conditional expression is constant" @@ -155,8 +162,6 @@ /* please, do it beyond the point further indicated in this file. */ /* ================================================================ */ -#include <curl/curl.h> - /* * Disable other protocols when http is the only one desired. */ @@ -216,7 +221,7 @@ /* ================================================================ */ /* No system header file shall be included in this file before this */ -/* point. The only allowed ones are those included from curl/system.h */ +/* point. */ /* ================================================================ */ /* @@ -243,6 +248,8 @@ # include "setup-win32.h" #endif +#include <curl/system.h> + /* * Use getaddrinfo to resolve the IPv4 address literal. If the current network * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64, @@ -271,14 +278,41 @@ #endif #ifdef __AMIGA__ +# ifdef __amigaos4__ +# define __USE_INLINE__ + /* use our own resolver which uses runtime feature detection */ +# define CURLRES_AMIGA + /* getaddrinfo() currently crashes bsdsocket.library, so disable */ +# undef HAVE_GETADDRINFO +# if !(defined(__NEWLIB__) || \ + (defined(__CLIB2__) && defined(__THREAD_SAFE))) + /* disable threaded resolver with clib2 - requires newlib or clib-ts */ +# undef USE_THREADS_POSIX +# endif +# endif # include <exec/types.h> # include <exec/execbase.h> # include <proto/exec.h> # include <proto/dos.h> # include <unistd.h> -# ifdef HAVE_PROTO_BSDSOCKET_H -# include <proto/bsdsocket.h> /* ensure bsdsocket.library use */ -# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +# if defined(HAVE_PROTO_BSDSOCKET_H) && \ + (!defined(__amigaos4__) || defined(USE_AMISSL)) + /* use bsdsocket.library directly, instead of libc networking functions */ +# include <proto/bsdsocket.h> +# ifdef __amigaos4__ + int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *errorfds, struct timeval *timeout); +# define select(a,b,c,d,e) Curl_amiga_select(a,b,c,d,e) +# else +# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0) +# endif + /* must not use libc's fcntl() on bsdsocket.library sockfds! */ +# undef HAVE_FCNTL +# undef HAVE_FCNTL_O_NONBLOCK +# else + /* use libc networking and hence close() and fnctl() */ +# undef HAVE_CLOSESOCKET_CAMEL +# undef HAVE_IOCTLSOCKET_CAMEL # endif /* * In clib2 arpa/inet.h warns that some prototypes may clash @@ -292,8 +326,10 @@ #include <assert.h> #endif -#ifdef __TANDEM /* for nsr-tandem-nsk systems */ -#include <floss.h> +#ifdef __TANDEM /* for ns*-tandem-nsk systems */ +# if ! defined __LP64 +# include <floss.h> /* FLOSS is only used for 32-bit builds. */ +# endif #endif #ifndef STDC_HEADERS /* no standard C headers! */ @@ -571,7 +607,6 @@ /* now undef the stock libc functions just to avoid them being used */ # undef HAVE_GETADDRINFO # undef HAVE_FREEADDRINFO -# undef HAVE_GETHOSTBYNAME #elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) # define CURLRES_ASYNCH # define CURLRES_THREADED @@ -722,12 +757,12 @@ #define SHUT_RDWR 0x02 #endif -/* Define S_ISREG if not defined by system headers, f.e. MSVC */ +/* Define S_ISREG if not defined by system headers, e.g. MSVC */ #if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif -/* Define S_ISDIR if not defined by system headers, f.e. MSVC */ +/* Define S_ISDIR if not defined by system headers, e.g. MSVC */ #if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif @@ -811,6 +846,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #if defined(USE_NGTCP2) || defined(USE_QUICHE) || defined(USE_MSH3) #define ENABLE_QUIC +#define USE_HTTP3 #endif #if defined(USE_UNIX_SOCKETS) && defined(WIN32) diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h index 38018d2..f09b00f 100644 --- a/Utilities/cmcurl/lib/curl_setup_once.h +++ b/Utilities/cmcurl/lib/curl_setup_once.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ @@ -31,7 +33,6 @@ #include <stdlib.h> #include <string.h> #include <stdarg.h> -#include <ctype.h> #include <time.h> #ifdef HAVE_ERRNO_H @@ -86,6 +87,8 @@ #include <sys/socket.h> #endif +#include "functypes.h" + #ifdef __hpux # if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) # ifdef OLD_APP32_64BIT_OFF_T @@ -148,20 +151,10 @@ struct timeval { * SEND_TYPE_RETV must also be defined. */ -#if !defined(RECV_TYPE_ARG1) || \ - !defined(RECV_TYPE_ARG2) || \ - !defined(RECV_TYPE_ARG3) || \ - !defined(RECV_TYPE_ARG4) || \ - !defined(RECV_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recv - /* */ -#else #define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \ (RECV_TYPE_ARG2)(y), \ (RECV_TYPE_ARG3)(z), \ (RECV_TYPE_ARG4)(0)) -#endif #else /* HAVE_RECV */ #ifndef sread /* */ @@ -178,21 +171,10 @@ struct timeval { (SEND_TYPE_ARG3)(z)) #elif defined(HAVE_SEND) -#if !defined(SEND_TYPE_ARG1) || \ - !defined(SEND_QUAL_ARG2) || \ - !defined(SEND_TYPE_ARG2) || \ - !defined(SEND_TYPE_ARG3) || \ - !defined(SEND_TYPE_ARG4) || \ - !defined(SEND_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_send - /* */ -#else #define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \ (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \ (SEND_TYPE_ARG3)(z), \ (SEND_TYPE_ARG4)(SEND_4TH_ARG)) -#endif #else /* HAVE_SEND */ #ifndef swrite /* */ @@ -202,46 +184,6 @@ struct timeval { #endif /* HAVE_SEND */ -#if 0 -#if defined(HAVE_RECVFROM) -/* - * Currently recvfrom is only used on udp sockets. - */ -#if !defined(RECVFROM_TYPE_ARG1) || \ - !defined(RECVFROM_TYPE_ARG2) || \ - !defined(RECVFROM_TYPE_ARG3) || \ - !defined(RECVFROM_TYPE_ARG4) || \ - !defined(RECVFROM_TYPE_ARG5) || \ - !defined(RECVFROM_TYPE_ARG6) || \ - !defined(RECVFROM_TYPE_RETV) - /* */ - Error Missing_definition_of_return_and_arguments_types_of_recvfrom - /* */ -#else -#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \ - (RECVFROM_TYPE_ARG2 *)(b), \ - (RECVFROM_TYPE_ARG3) (bl), \ - (RECVFROM_TYPE_ARG4) (0), \ - (RECVFROM_TYPE_ARG5 *)(f), \ - (RECVFROM_TYPE_ARG6 *)(fl)) -#endif -#else /* HAVE_RECVFROM */ -#ifndef sreadfrom - /* */ - Error Missing_definition_of_macro_sreadfrom - /* */ -#endif -#endif /* HAVE_RECVFROM */ - - -#ifdef RECVFROM_TYPE_ARG6_IS_VOID -# define RECVFROM_ARG6_T int -#else -# define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6 -#endif -#endif /* if 0 */ - - /* * Function-like macro definition used to close a socket. */ @@ -267,9 +209,6 @@ struct timeval { # define sfcntl fcntl #endif -#define TOLOWER(x) (tolower((int) ((unsigned char)x))) - - /* * 'bool' stuff compatible with HP-UX headers. */ @@ -306,6 +245,14 @@ struct timeval { # define HAVE_BOOL_T #endif +/* the type we use for storing a single boolean bit */ +#ifdef _MSC_VER +typedef bool bit; +#define BIT(x) bool x +#else +typedef unsigned int bit; +#define BIT(x) bit x:1 +#endif /* * Redefine TRUE and FALSE too, to catch current use. With this diff --git a/Utilities/cmcurl/lib/curl_sha256.h b/Utilities/cmcurl/lib/curl_sha256.h index 2b7890a..754c761 100644 --- a/Utilities/cmcurl/lib/curl_sha256.h +++ b/Utilities/cmcurl/lib/curl_sha256.h @@ -21,9 +21,12 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include <curl/curl.h> #include "curl_hmac.h" extern const struct HMAC_params Curl_HMAC_SHA256[1]; diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c index 339bf54..33108c4 100644 --- a/Utilities/cmcurl/lib/curl_sspi.c +++ b/Utilities/cmcurl/lib/curl_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_sspi.h b/Utilities/cmcurl/lib/curl_sspi.h index 881384d..ad11130 100644 --- a/Utilities/cmcurl/lib/curl_sspi.h +++ b/Utilities/cmcurl/lib/curl_sspi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_threads.c b/Utilities/cmcurl/lib/curl_threads.c index 4146144..eb8e136 100644 --- a/Utilities/cmcurl/lib/curl_threads.c +++ b/Utilities/cmcurl/lib/curl_threads.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curl_threads.h b/Utilities/cmcurl/lib/curl_threads.h index e10b7a1..63392f6 100644 --- a/Utilities/cmcurl/lib/curl_threads.h +++ b/Utilities/cmcurl/lib/curl_threads.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h index 9f21f60..1796afa 100644 --- a/Utilities/cmcurl/lib/curlx.h +++ b/Utilities/cmcurl/lib/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c index e23e661..6f7678f 100644 --- a/Utilities/cmcurl/lib/dict.c +++ b/Utilities/cmcurl/lib/dict.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/dict.h b/Utilities/cmcurl/lib/dict.h index 6a6c772..b283a0d 100644 --- a/Utilities/cmcurl/lib/dict.h +++ b/Utilities/cmcurl/lib/dict.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_DICT diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c index 4aef8b2..3b1d5d6 100644 --- a/Utilities/cmcurl/lib/doh.c +++ b/Utilities/cmcurl/lib/doh.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -69,12 +71,6 @@ static const char *doh_strerror(DOHcode code) } #endif -#ifdef DEBUGBUILD -#define UNITTEST -#else -#define UNITTEST static -#endif - /* @unittest 1655 */ UNITTEST DOHcode doh_encode(const char *host, @@ -247,6 +243,7 @@ static CURLcode dohprobe(struct Curl_easy *data, the gcc typecheck helpers */ struct dynbuf *resp = &p->serverdoh; ERROR_CHECK_SETOPT(CURLOPT_URL, url); + ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https"); ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb); ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp); ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer); @@ -306,14 +303,6 @@ static CURLcode dohprobe(struct Curl_easy *data, } 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]); - } - if(data->set.str[STRING_SSL_EGDSOCKET]) { - ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET, - data->set.str[STRING_SSL_EGDSOCKET]); - } if(data->set.ssl.fsslctx) ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx); if(data->set.ssl.fsslctxp) @@ -407,7 +396,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, goto error; dohp->pending++; - if(Curl_ipv6works(data)) { + if((conn->ip_version != CURL_IPRESOLVE_V4) && 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], @@ -803,7 +792,7 @@ doh2ai(const struct dohentry *de, const char *hostname, int port) #endif CURLcode result = CURLE_OK; int i; - size_t hostlen = strlen(hostname) + 1; /* include zero terminator */ + size_t hostlen = strlen(hostname) + 1; /* include null-terminator */ if(!de) /* no input == no output! */ diff --git a/Utilities/cmcurl/lib/doh.h b/Utilities/cmcurl/lib/doh.h index 70e96e0..678e807 100644 --- a/Utilities/cmcurl/lib/doh.h +++ b/Utilities/cmcurl/lib/doh.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2018 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "urldata.h" @@ -27,21 +29,6 @@ #ifndef CURL_DISABLE_DOH -/* - * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name - * and returns a 'Curl_addrinfo *' with the address information. - */ - -struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, - const char *hostname, - int port, - int *waitp); - -CURLcode Curl_doh_is_resolved(struct Curl_easy *data, - struct Curl_dns_entry **dns); - -int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks); - typedef enum { DOH_OK, DOH_DNS_BAD_LABEL, /* 1 */ @@ -67,6 +54,38 @@ typedef enum { DNS_TYPE_DNAME = 39 /* RFC6672 */ } DNStype; +/* one of these for each DoH request */ +struct dnsprobe { + CURL *easy; + DNStype dnstype; + unsigned char dohbuffer[512]; + size_t dohlen; + struct dynbuf serverdoh; +}; + +struct dohdata { + struct curl_slist *headers; + struct dnsprobe probe[DOH_PROBE_SLOTS]; + unsigned int pending; /* still outstanding requests */ + int port; + const char *host; +}; + +/* + * Curl_doh() resolve a name using DoH (DNS-over-HTTPS). It resolves a name + * and returns a 'Curl_addrinfo *' with the address information. + */ + +struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, + const char *hostname, + int port, + int *waitp); + +CURLcode Curl_doh_is_resolved(struct Curl_easy *data, + struct Curl_dns_entry **dns); + +int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks); + #define DOH_MAX_ADDR 24 #define DOH_MAX_CNAME 4 diff --git a/Utilities/cmcurl/lib/dotdot.c b/Utilities/cmcurl/lib/dotdot.c deleted file mode 100644 index 73ef2fa..0000000 --- a/Utilities/cmcurl/lib/dotdot.c +++ /dev/null @@ -1,182 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2022, 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 <curl/curl.h> - -#include "dotdot.h" -#include "curl_memory.h" - -/* The last #include file should be: */ -#include "memdebug.h" - -/* - * "Remove Dot Segments" - * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 - */ - -/* - * Curl_dedotdotify() - * @unittest: 1395 - * - * This function gets a null-terminated path with dot and dotdot sequences - * passed in and strips them off according to the rules in RFC 3986 section - * 5.2.4. - * - * The function handles a query part ('?' + stuff) appended but it expects - * that fragments ('#' + stuff) have already been cut off. - * - * RETURNS - * - * an allocated dedotdotified output string - */ -char *Curl_dedotdotify(const char *input) -{ - size_t inlen = strlen(input); - char *clone; - size_t clen = inlen; /* the length of the cloned input */ - char *out = malloc(inlen + 1); - char *outptr; - char *orgclone; - char *queryp; - if(!out) - return NULL; /* out of memory */ - - *out = 0; /* null-terminates, for inputs like "./" */ - - /* get a cloned copy of the input */ - clone = strdup(input); - if(!clone) { - free(out); - return NULL; - } - orgclone = clone; - outptr = out; - - if(!*clone) { - /* zero length string, return that */ - free(out); - return clone; - } - - /* - * To handle query-parts properly, we must find it and remove it during the - * dotdot-operation and then append it again at the end to the output - * string. - */ - queryp = strchr(clone, '?'); - if(queryp) - *queryp = 0; - - do { - - /* A. If the input buffer begins with a prefix of "../" or "./", then - remove that prefix from the input buffer; otherwise, */ - - if(!strncmp("./", clone, 2)) { - clone += 2; - clen -= 2; - } - else if(!strncmp("../", clone, 3)) { - clone += 3; - clen -= 3; - } - - /* B. if the input buffer begins with a prefix of "/./" or "/.", where - "." is a complete path segment, then replace that prefix with "/" in - the input buffer; otherwise, */ - else if(!strncmp("/./", clone, 3)) { - clone += 2; - clen -= 2; - } - else if(!strcmp("/.", clone)) { - clone[1]='/'; - clone++; - clen -= 1; - } - - /* C. if the input buffer begins with a prefix of "/../" or "/..", where - ".." is a complete path segment, then replace that prefix with "/" in - the input buffer and remove the last segment and its preceding "/" (if - any) from the output buffer; otherwise, */ - - else if(!strncmp("/../", clone, 4)) { - clone += 3; - clen -= 3; - /* remove the last segment from the output buffer */ - while(outptr > out) { - outptr--; - if(*outptr == '/') - break; - } - *outptr = 0; /* null-terminate where it stops */ - } - else if(!strcmp("/..", clone)) { - clone[2]='/'; - clone += 2; - clen -= 2; - /* remove the last segment from the output buffer */ - while(outptr > out) { - outptr--; - if(*outptr == '/') - break; - } - *outptr = 0; /* null-terminate where it stops */ - } - - /* D. if the input buffer consists only of "." or "..", then remove - that from the input buffer; otherwise, */ - - else if(!strcmp(".", clone) || !strcmp("..", clone)) { - *clone = 0; - *out = 0; - } - - else { - /* E. move the first path segment in the input buffer to the end of - the output buffer, including the initial "/" character (if any) and - any subsequent characters up to, but not including, the next "/" - character or the end of the input buffer. */ - - do { - *outptr++ = *clone++; - clen--; - } while(*clone && (*clone != '/')); - *outptr = 0; - } - - } while(*clone); - - if(queryp) { - size_t qlen; - /* There was a query part, append that to the output. The 'clone' string - may now have been altered so we copy from the original input string - from the correct index. */ - size_t oindex = queryp - orgclone; - qlen = strlen(&input[oindex]); - memcpy(outptr, &input[oindex], qlen + 1); /* include the end zero byte */ - } - - free(orgclone); - return out; -} diff --git a/Utilities/cmcurl/lib/dynbuf.c b/Utilities/cmcurl/lib/dynbuf.c index ada7e0c..0b1cf9a 100644 --- a/Utilities/cmcurl/lib/dynbuf.c +++ b/Utilities/cmcurl/lib/dynbuf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2020 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -126,7 +128,6 @@ void Curl_dyn_reset(struct dynbuf *s) s->leng = 0; } -#ifdef USE_NGTCP2 /* * Specify the size of the tail to keep (number of bytes from the end of the * buffer). The rest will be dropped. @@ -151,7 +152,6 @@ CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail) return CURLE_OK; } -#endif /* * Appends a buffer with length. @@ -253,3 +253,18 @@ size_t Curl_dyn_len(const struct dynbuf *s) DEBUGASSERT(!s->leng || s->bufr); return s->leng; } + +/* + * Set a new (smaller) length. + */ +CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set) +{ + DEBUGASSERT(s); + DEBUGASSERT(s->init == DYNINIT); + DEBUGASSERT(!s->leng || s->bufr); + if(set > s->leng) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->leng = set; + s->bufr[s->leng] = 0; + return CURLE_OK; +} diff --git a/Utilities/cmcurl/lib/dynbuf.h b/Utilities/cmcurl/lib/dynbuf.h index 252411f..04a728c 100644 --- a/Utilities/cmcurl/lib/dynbuf.h +++ b/Utilities/cmcurl/lib/dynbuf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020, 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2020 - 2022, 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,8 +20,12 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ +#include <curl/curl.h> + #ifndef BUILDING_LIBCURL /* this renames the functions so that the tool code can use the same code without getting symbol collisions */ @@ -36,12 +40,13 @@ #define Curl_dyn_len(a) curlx_dyn_len(a) #define Curl_dyn_reset(a) curlx_dyn_reset(a) #define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b) +#define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b) #define curlx_dynbuf dynbuf /* for the struct name */ #endif struct dynbuf { char *bufr; /* point to a null-terminated allocated buffer */ - size_t leng; /* number of bytes *EXCLUDING* the zero terminator */ + size_t leng; /* number of bytes *EXCLUDING* the null-terminator */ size_t allc; /* size of the current allocation */ size_t toobig; /* size limit for the buffer */ #ifdef DEBUGBUILD @@ -61,6 +66,7 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap) WARN_UNUSED_RESULT; void Curl_dyn_reset(struct dynbuf *s); CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail); +CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set); char *Curl_dyn_ptr(const struct dynbuf *s); unsigned char *Curl_dyn_uptr(const struct dynbuf *s); size_t Curl_dyn_len(const struct dynbuf *s); diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index bd9d695..b8ac1ef 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -80,6 +82,8 @@ #include "altsvc.h" #include "hsts.h" +#include "easy_lock.h" + /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -89,6 +93,19 @@ static unsigned int initialized; static long init_flags; +#ifdef GLOBAL_INIT_IS_THREADSAFE + +static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT; +#define global_init_lock() curl_simple_lock_lock(&s_lock) +#define global_init_unlock() curl_simple_lock_unlock(&s_lock) + +#else + +#define global_init_lock() +#define global_init_unlock() + +#endif + /* * strdup (and other memory functions) is redefined in complicated * ways, but at this point it must be defined as the system-supplied strdup @@ -161,7 +178,7 @@ static CURLcode global_init(long flags, bool memoryfuncs) #endif #ifdef __AMIGA__ - if(!Curl_amiga_init()) { + if(Curl_amiga_init()) { DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n")); goto fail; } @@ -207,7 +224,14 @@ static CURLcode global_init(long flags, bool memoryfuncs) */ CURLcode curl_global_init(long flags) { - return global_init(flags, TRUE); + CURLcode result; + global_init_lock(); + + result = global_init(flags, TRUE); + + global_init_unlock(); + + return result; } /* @@ -218,15 +242,20 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c) { + CURLcode result; + /* Invalid input, return immediately */ if(!m || !f || !r || !s || !c) return CURLE_FAILED_INIT; + global_init_lock(); + if(initialized) { /* Already initialized, don't do it again, but bump the variable anyway to work like curl_global_init() and require the same amount of cleanup calls. */ initialized++; + global_init_unlock(); return CURLE_OK; } @@ -239,7 +268,11 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, Curl_ccalloc = c; /* Call the actual init function, but without setting */ - return global_init(flags, FALSE); + result = global_init(flags, FALSE); + + global_init_unlock(); + + return result; } /** @@ -248,11 +281,17 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, */ void curl_global_cleanup(void) { - if(!initialized) + global_init_lock(); + + if(!initialized) { + global_init_unlock(); return; + } - if(--initialized) + if(--initialized) { + global_init_unlock(); return; + } Curl_ssl_cleanup(); Curl_resolver_global_cleanup(); @@ -273,6 +312,25 @@ void curl_global_cleanup(void) #endif init_flags = 0; + + global_init_unlock(); +} + +/* + * curl_global_sslset() globally initializes the SSL backend to use. + */ +CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) +{ + CURLsslset rc; + + global_init_lock(); + + rc = Curl_init_sslset_nolock(id, name, avail); + + global_init_unlock(); + + return rc; } /* @@ -285,14 +343,18 @@ struct Curl_easy *curl_easy_init(void) struct Curl_easy *data; /* Make sure we inited the global SSL stuff */ + global_init_lock(); + if(!initialized) { - result = curl_global_init(CURL_GLOBAL_DEFAULT); + result = global_init(CURL_GLOBAL_DEFAULT, TRUE); if(result) { /* something in the global init failed, return nothing */ DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n")); + global_init_unlock(); return NULL; } } + global_init_unlock(); /* We use curl_open() with undefined URL so far */ result = Curl_open(&data); @@ -507,19 +569,23 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) /* wait for activity or timeout */ pollrc = Curl_poll(fds, numfds, ev->ms); + if(pollrc < 0) + return CURLE_UNRECOVERABLE_POLL; after = Curl_now(); ev->msbump = FALSE; /* reset here */ - if(0 == pollrc) { + if(!pollrc) { /* timeout! */ ev->ms = 0; /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &ev->running_handles); } - else if(pollrc > 0) { + else { + /* here pollrc is > 0 */ + /* loop over the monitored sockets to see which ones had activity */ for(i = 0; i< numfds; i++) { if(fds[i].revents) { @@ -545,8 +611,6 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) } } } - else - return CURLE_RECV_ERROR; if(mcode) return CURLE_URL_MALFORMAT; @@ -662,7 +726,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) else { /* this multi handle will only ever have a single easy handled attached to it, so make it use minimal hashes */ - multi = Curl_multi_handle(1, 3); + multi = Curl_multi_handle(1, 3, 7); if(!multi) return CURLE_OUT_OF_MEMORY; data->multi_easy = multi; @@ -838,6 +902,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) outcurl->progress.flags = data->progress.flags; outcurl->progress.callback = data->progress.callback; +#ifndef CURL_DISABLE_COOKIES if(data->cookies) { /* If cookies are enabled in the parent handle, we enable them in the clone as well! */ @@ -856,6 +921,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) if(!outcurl->state.cookielist) goto fail; } +#endif if(data->state.url) { outcurl->state.url = strdup(data->state.url); @@ -878,7 +944,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) goto fail; } -#ifdef USE_ALTSVC +#ifndef CURL_DISABLE_ALTSVC if(data->asi) { outcurl->asi = Curl_altsvc_init(); if(!outcurl->asi) @@ -937,8 +1003,10 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) fail: if(outcurl) { +#ifndef CURL_DISABLE_COOKIES curl_slist_free_all(outcurl->state.cookielist); outcurl->state.cookielist = NULL; +#endif Curl_safefree(outcurl->state.buffer); Curl_dyn_free(&outcurl->state.headerb); Curl_safefree(outcurl->state.url); @@ -1065,6 +1133,16 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) } } +#ifdef USE_HYPER + if(!(newstate & KEEP_SEND_PAUSE)) { + /* need to wake the send body waker */ + if(data->hyp.send_body_waker) { + hyper_waker_wake(data->hyp.send_body_waker); + data->hyp.send_body_waker = NULL; + } + } +#endif + /* if there's no error and we're not pausing both directions, we want to have this handle checked soon */ if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != @@ -1093,8 +1171,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) } -static CURLcode easy_connection(struct Curl_easy *data, - curl_socket_t *sfd, +static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, struct connectdata **connp) { if(!data) @@ -1153,11 +1230,12 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, } /* - * Sends data over the connected socket. Use after successful - * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + * Sends data over the connected socket. + * + * This is the private internal version of curl_easy_send() */ -CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, - size_t buflen, size_t *n) +CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, + size_t buflen, ssize_t *n) { curl_socket_t sfd; CURLcode result; @@ -1165,9 +1243,6 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, struct connectdata *c = NULL; SIGPIPE_VARIABLE(pipe_st); - if(Curl_is_in_callback(data)) - return CURLE_RECURSIVE_API_CALL; - result = easy_connection(data, &sfd, &c); if(result) return result; @@ -1189,8 +1264,25 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, if(!result && !n1) return CURLE_AGAIN; - *n = (size_t)n1; + *n = n1; + + return result; +} + +/* + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *n) +{ + ssize_t written = 0; + CURLcode result; + if(Curl_is_in_callback(data)) + return CURLE_RECURSIVE_API_CALL; + result = Curl_senddata(data, buffer, buflen, &written); + *n = (size_t)written; return result; } diff --git a/Utilities/cmcurl/lib/easy_lock.h b/Utilities/cmcurl/lib/easy_lock.h new file mode 100644 index 0000000..d96e56b --- /dev/null +++ b/Utilities/cmcurl/lib/easy_lock.h @@ -0,0 +1,105 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, 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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#define GLOBAL_INIT_IS_THREADSAFE + +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 + +#ifdef __MINGW32__ +#ifndef __MINGW64_VERSION_MAJOR +#if (__MINGW32_MAJOR_VERSION < 5) || \ + (__MINGW32_MAJOR_VERSION == 5 && __MINGW32_MINOR_VERSION == 0) +/* mingw >= 5.0.1 defines SRWLOCK, and slightly different from MS define */ +typedef PVOID SRWLOCK, *PSRWLOCK; +#endif +#endif +#ifndef SRWLOCK_INIT +#define SRWLOCK_INIT NULL +#endif +#endif /* __MINGW32__ */ + +#define curl_simple_lock SRWLOCK +#define CURL_SIMPLE_LOCK_INIT SRWLOCK_INIT + +#define curl_simple_lock_lock(m) AcquireSRWLockExclusive(m) +#define curl_simple_lock_unlock(m) ReleaseSRWLockExclusive(m) + +#elif defined(HAVE_ATOMIC) && defined(HAVE_STDATOMIC_H) +#include <stdatomic.h> +#if defined(HAVE_SCHED_YIELD) +#include <sched.h> +#endif + +#define curl_simple_lock atomic_int +#define CURL_SIMPLE_LOCK_INIT 0 + +/* a clang-thing */ +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __INTEL_COMPILER +/* The Intel compiler tries to look like GCC *and* clang *and* lies in its + __has_builtin() function, so override it. */ + +/* if GCC on i386/x86_64 or if the built-in is present */ +#if ( (defined(__GNUC__) && !defined(__clang__)) && \ + (defined(__i386__) || defined(__x86_64__))) || \ + __has_builtin(__builtin_ia32_pause) +#define HAVE_BUILTIN_IA32_PAUSE +#endif + +#endif + +static inline void curl_simple_lock_lock(curl_simple_lock *lock) +{ + for(;;) { + if(!atomic_exchange_explicit(lock, true, memory_order_acquire)) + break; + /* Reduce cache coherency traffic */ + while(atomic_load_explicit(lock, memory_order_relaxed)) { + /* Reduce load (not mandatory) */ +#ifdef HAVE_BUILTIN_IA32_PAUSE + __builtin_ia32_pause(); +#elif defined(__aarch64__) + __asm__ volatile("yield" ::: "memory"); +#elif defined(HAVE_SCHED_YIELD) + sched_yield(); +#endif + } + } +} + +static inline void curl_simple_lock_unlock(curl_simple_lock *lock) +{ + atomic_store_explicit(lock, false, memory_order_release); +} + +#else + +#undef GLOBAL_INIT_IS_THREADSAFE + +#endif diff --git a/Utilities/cmcurl/lib/easygetopt.c b/Utilities/cmcurl/lib/easygetopt.c index 7b2213f..a639bb3 100644 --- a/Utilities/cmcurl/lib/easygetopt.c +++ b/Utilities/cmcurl/lib/easygetopt.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * ___|___/|_| ______| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel.se>, et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel.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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/easyif.h b/Utilities/cmcurl/lib/easyif.h index 3364418..205382c 100644 --- a/Utilities/cmcurl/lib/easyif.h +++ b/Utilities/cmcurl/lib/easyif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,11 +20,16 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* * Prototypes for library-wide functions provided by easy.c */ +CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer, + size_t buflen, ssize_t *n); + #ifdef CURLDEBUG CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); #endif diff --git a/Utilities/cmcurl/lib/easyoptions.c b/Utilities/cmcurl/lib/easyoptions.c index 04871ad..e59b63a 100644 --- a/Utilities/cmcurl/lib/easyoptions.c +++ b/Utilities/cmcurl/lib/easyoptions.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * ___|___/|_| ______| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel.se>, et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel.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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* This source code is generated by optiontable.pl - DO NOT EDIT BY HAND */ @@ -105,7 +107,8 @@ struct curl_easyoption Curl_easyopts[] = { {"FTP_CREATE_MISSING_DIRS", CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOT_LONG, 0}, {"FTP_FILEMETHOD", CURLOPT_FTP_FILEMETHOD, CURLOT_VALUES, 0}, - {"FTP_RESPONSE_TIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOT_LONG, 0}, + {"FTP_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT, + CURLOT_LONG, CURLOT_FLAG_ALIAS}, {"FTP_SKIP_PASV_IP", CURLOPT_FTP_SKIP_PASV_IP, CURLOT_LONG, 0}, {"FTP_SSL", CURLOPT_USE_SSL, CURLOT_VALUES, CURLOT_FLAG_ALIAS}, {"FTP_SSL_CCC", CURLOPT_FTP_SSL_CCC, CURLOT_LONG, 0}, @@ -201,6 +204,7 @@ struct curl_easyoption Curl_easyopts[] = { {"PROGRESSDATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, {"PROGRESSFUNCTION", CURLOPT_PROGRESSFUNCTION, CURLOT_FUNCTION, 0}, {"PROTOCOLS", CURLOPT_PROTOCOLS, CURLOT_LONG, 0}, + {"PROTOCOLS_STR", CURLOPT_PROTOCOLS_STR, CURLOT_STRING, 0}, {"PROXY", CURLOPT_PROXY, CURLOT_STRING, 0}, {"PROXYAUTH", CURLOPT_PROXYAUTH, CURLOT_VALUES, 0}, {"PROXYHEADER", CURLOPT_PROXYHEADER, CURLOT_SLIST, 0}, @@ -243,6 +247,7 @@ struct curl_easyoption Curl_easyopts[] = { {"READDATA", CURLOPT_READDATA, CURLOT_CBPTR, 0}, {"READFUNCTION", CURLOPT_READFUNCTION, CURLOT_FUNCTION, 0}, {"REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS, CURLOT_LONG, 0}, + {"REDIR_PROTOCOLS_STR", CURLOPT_REDIR_PROTOCOLS_STR, CURLOT_STRING, 0}, {"REFERER", CURLOPT_REFERER, CURLOT_STRING, 0}, {"REQUEST_TARGET", CURLOPT_REQUEST_TARGET, CURLOT_STRING, 0}, {"RESOLVE", CURLOPT_RESOLVE, CURLOT_SLIST, 0}, @@ -262,8 +267,8 @@ struct curl_easyoption Curl_easyopts[] = { {"SASL_IR", CURLOPT_SASL_IR, CURLOT_LONG, 0}, {"SEEKDATA", CURLOPT_SEEKDATA, CURLOT_CBPTR, 0}, {"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0}, - {"SERVER_RESPONSE_TIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT, - CURLOT_LONG, CURLOT_FLAG_ALIAS}, + {"SERVER_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT, + CURLOT_LONG, 0}, {"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0}, {"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0}, {"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0}, @@ -273,6 +278,8 @@ struct curl_easyoption Curl_easyopts[] = { {"SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOT_STRING, 0}, {"SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES, CURLOT_VALUES, 0}, {"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0}, + {"SSH_HOSTKEYDATA", CURLOPT_SSH_HOSTKEYDATA, CURLOT_CBPTR, 0}, + {"SSH_HOSTKEYFUNCTION", CURLOPT_SSH_HOSTKEYFUNCTION, CURLOT_FUNCTION, 0}, {"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOT_STRING, 0}, {"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, @@ -347,10 +354,11 @@ struct curl_easyoption Curl_easyopts[] = { {"WRITEDATA", CURLOPT_WRITEDATA, CURLOT_CBPTR, 0}, {"WRITEFUNCTION", CURLOPT_WRITEFUNCTION, CURLOT_FUNCTION, 0}, {"WRITEHEADER", CURLOPT_HEADERDATA, CURLOT_CBPTR, CURLOT_FLAG_ALIAS}, + {"WS_OPTIONS", CURLOPT_WS_OPTIONS, CURLOT_LONG, 0}, {"XFERINFODATA", CURLOPT_XFERINFODATA, CURLOT_CBPTR, 0}, {"XFERINFOFUNCTION", CURLOPT_XFERINFOFUNCTION, CURLOT_FUNCTION, 0}, {"XOAUTH2_BEARER", CURLOPT_XOAUTH2_BEARER, CURLOT_STRING, 0}, - {NULL, CURLOPT_LASTENTRY, 0, 0} /* end of table */ + {NULL, CURLOPT_LASTENTRY, CURLOT_LONG, 0} /* end of table */ }; #ifdef DEBUGBUILD @@ -360,6 +368,6 @@ struct curl_easyoption Curl_easyopts[] = { */ int Curl_easyopts_check(void) { - return ((CURLOPT_LASTENTRY%10000) != (315 + 1)); + return ((CURLOPT_LASTENTRY%10000) != (320 + 1)); } #endif diff --git a/Utilities/cmcurl/lib/easyoptions.h b/Utilities/cmcurl/lib/easyoptions.h index 91e1190..33f816d 100644 --- a/Utilities/cmcurl/lib/easyoptions.h +++ b/Utilities/cmcurl/lib/easyoptions.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* should probably go into the public header */ diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c index ff58875..da7e552 100644 --- a/Utilities/cmcurl/lib/escape.c +++ b/Utilities/cmcurl/lib/escape.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* Escape and unescape URL encoding in strings. The functions return a new @@ -75,6 +77,9 @@ char *curl_unescape(const char *string, int length) return curl_easy_unescape(NULL, string, length, NULL); } +/* Escapes for URL the given unescaped string of given length. + * 'data' is ignored since 7.82.0. + */ char *curl_easy_escape(struct Curl_easy *data, const char *string, int inlength) { @@ -116,8 +121,6 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string, * Returns a pointer to a malloced string in *ostring with length given in * *olen. If length == 0, the length is assumed to be strlen(string). * - * 'data' can be set to NULL - * * ctrl options: * - REJECT_NADA: accept everything * - REJECT_CTRL: rejects control characters (byte codes lower than 32) in @@ -191,6 +194,7 @@ CURLcode Curl_urldecode(const char *string, size_t length, * pointer to a malloced string with length given in *olen. * If length == 0, the length is assumed to be strlen(string). * If olen == NULL, no output length is stored. + * 'data' is ignored since 7.82.0. */ char *curl_easy_unescape(struct Curl_easy *data, const char *string, int length, int *olen) diff --git a/Utilities/cmcurl/lib/escape.h b/Utilities/cmcurl/lib/escape.h index 0266883..61d4611 100644 --- a/Utilities/cmcurl/lib/escape.h +++ b/Utilities/cmcurl/lib/escape.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c index 3da79a2..d82d57b 100644 --- a/Utilities/cmcurl/lib/file.c +++ b/Utilities/cmcurl/lib/file.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -69,6 +71,8 @@ #if defined(WIN32) || defined(MSDOS) || defined(__EMX__) #define DOS_FILESYSTEM 1 +#elif defined(__amigaos4__) +#define AMIGA_FILESYSTEM 1 #endif #ifdef OPEN_NEEDS_ARG3 @@ -194,8 +198,33 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done) return CURLE_URL_MALFORMAT; } + #ifdef AMIGA_FILESYSTEM + /* + * A leading slash in an AmigaDOS path denotes the parent + * directory, and hence we block this as it is relative. + * Absolute paths start with 'volumename:', so we check for + * this first. Failing that, we treat the path as a real unix + * path, but only if the application was compiled with -lunix. + */ + fd = -1; + file->path = real_path; + + if(real_path[0] == '/') { + extern int __unix_path_semantics; + if(strchr(real_path + 1, ':')) { + /* Amiga absolute path */ + fd = open_readonly(real_path + 1, O_RDONLY); + file->path++; + } + else if(__unix_path_semantics) { + /* -lunix fallback */ + fd = open_readonly(real_path, O_RDONLY); + } + } + #else fd = open_readonly(real_path, O_RDONLY); file->path = real_path; + #endif #endif file->freepath = real_path; /* free this when done */ @@ -234,7 +263,7 @@ static CURLcode file_disconnect(struct Curl_easy *data, { (void)dead_connection; /* not used */ (void)conn; - return file_done(data, 0, 0); + return file_done(data, CURLE_OK, FALSE); } #ifdef DOS_FILESYSTEM diff --git a/Utilities/cmcurl/lib/file.h b/Utilities/cmcurl/lib/file.h index 338f92e..826d453 100644 --- a/Utilities/cmcurl/lib/file.h +++ b/Utilities/cmcurl/lib/file.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/fileinfo.c b/Utilities/cmcurl/lib/fileinfo.c index b7e9f0f..7bbf24b 100644 --- a/Utilities/cmcurl/lib/fileinfo.c +++ b/Utilities/cmcurl/lib/fileinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/fileinfo.h b/Utilities/cmcurl/lib/fileinfo.h index 5ae23ad..5bad718 100644 --- a/Utilities/cmcurl/lib/fileinfo.h +++ b/Utilities/cmcurl/lib/fileinfo.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> diff --git a/Utilities/cmcurl/lib/fopen.c b/Utilities/cmcurl/lib/fopen.c new file mode 100644 index 0000000..ad3691b --- /dev/null +++ b/Utilities/cmcurl/lib/fopen.c @@ -0,0 +1,113 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, 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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) || \ + !defined(CURL_DISABLE_HSTS) + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#include "urldata.h" +#include "rand.h" +#include "fopen.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_fopen() opens a file for writing with a temp name, to be renamed + * to the final name when completed. If there is an existing file using this + * name at the time of the open, this function will clone the mode from that + * file. if 'tempname' is non-NULL, it needs a rename after the file is + * written. + */ +CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, + FILE **fh, char **tempname) +{ + CURLcode result = CURLE_WRITE_ERROR; + unsigned char randsuffix[9]; + char *tempstore = NULL; + struct_stat sb; + int fd = -1; + *tempname = NULL; + + if(stat(filename, &sb) == -1 || !S_ISREG(sb.st_mode)) { + /* a non-regular file, fallback to direct fopen() */ + *fh = fopen(filename, FOPEN_WRITETEXT); + if(*fh) + return CURLE_OK; + goto fail; + } + + result = Curl_rand_hex(data, randsuffix, sizeof(randsuffix)); + if(result) + goto fail; + + tempstore = aprintf("%s.%s.tmp", filename, randsuffix); + if(!tempstore) { + result = CURLE_OUT_OF_MEMORY; + goto fail; + } + + result = CURLE_WRITE_ERROR; + fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600); + if(fd == -1) + goto fail; + +#ifdef HAVE_FCHMOD + { + struct_stat nsb; + if((fstat(fd, &nsb) != -1) && + (nsb.st_uid == sb.st_uid) && (nsb.st_gid == sb.st_gid)) { + /* if the user and group are the same, clone the original mode */ + if(fchmod(fd, sb.st_mode) == -1) + goto fail; + } + } +#endif + + *fh = fdopen(fd, FOPEN_WRITETEXT); + if(!*fh) + goto fail; + + *tempname = tempstore; + return CURLE_OK; + +fail: + if(fd != -1) { + close(fd); + unlink(tempstore); + } + + free(tempstore); + + *tempname = NULL; + return result; +} + +#endif /* ! disabled */ diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.h b/Utilities/cmcurl/lib/fopen.h index 7b6ac48..289e55f 100644 --- a/Utilities/cmcurl/lib/vssh/wolfssh.h +++ b/Utilities/cmcurl/lib/fopen.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_WOLFSSH_H -#define HEADER_CURL_WOLFSSH_H +#ifndef HEADER_CURL_FOPEN_H +#define HEADER_CURL_FOPEN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 +20,11 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ -extern const struct Curl_handler Curl_handler_sftp; +CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, + FILE **fh, char **tempname); -#endif /* HEADER_CURL_WOLFSSH_H */ +#endif diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c index 5fefd7a..46542b4 100644 --- a/Utilities/cmcurl/lib/formdata.c +++ b/Utilities/cmcurl/lib/formdata.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -249,8 +251,10 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } } else { - /* This is not array-state, get next option */ - option = va_arg(params, CURLformoption); + /* This is not array-state, get next option. This gets an 'int' with + va_arg() because CURLformoption might be a smaller type than int and + might cause compiler warnings and wrong behavior. */ + option = (CURLformoption)va_arg(params, int); if(CURLFORM_END == option) break; } diff --git a/Utilities/cmcurl/lib/formdata.h b/Utilities/cmcurl/lib/formdata.h index 09c6e9c..c6c6397 100644 --- a/Utilities/cmcurl/lib/formdata.h +++ b/Utilities/cmcurl/lib/formdata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index 45d9ced..d02ab99 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -514,10 +516,9 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected) } else { /* Add timeout to multi handle and break out of the loop */ - if(*connected == FALSE) { - Curl_expire(data, data->set.accepttimeout > 0 ? - data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0); - } + Curl_expire(data, data->set.accepttimeout ? + data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, + EXPIRE_FTP_ACCEPT); } return result; @@ -783,8 +784,9 @@ static CURLcode ftp_state_user(struct Curl_easy *data, &conn->proto.ftpc.pp, "USER %s", conn->user?conn->user:""); if(!result) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + ftpc->ftp_trying_alternative = FALSE; state(data, FTP_USER); - data->state.ftp_trying_alternative = FALSE; } return result; } @@ -2127,9 +2129,11 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, default: infof(data, "unsupported MDTM reply format"); break; - case 550: /* "No such file or directory" */ - failf(data, "Given file does not exist"); - result = CURLE_REMOTE_FILE_NOT_FOUND; + case 550: /* 550 is used for several different problems, e.g. + "No such file or directory" or "Permission denied". + It does not mean that the file does not exist at all. */ + infof(data, "MDTM failed: file does not exist or permission problem," + " continuing"); break; } @@ -2622,13 +2626,13 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data, (the server denies to log the specified user) */ if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && - !data->state.ftp_trying_alternative) { + !ftpc->ftp_trying_alternative) { /* Ok, USER failed. Let's try the supplied command. */ result = Curl_pp_sendf(data, &ftpc->pp, "%s", data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); if(!result) { - data->state.ftp_trying_alternative = TRUE; + ftpc->ftp_trying_alternative = TRUE; state(data, FTP_USER); } } @@ -2701,10 +2705,11 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, set a valid level */ 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"); - else - infof(data, "Authentication successful"); + if(Curl_sec_login(data, conn)) { + failf(data, "secure login failed"); + return CURLE_WEIRD_SERVER_REPLY; + } + infof(data, "Authentication successful"); } #endif @@ -3561,8 +3566,10 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) bool connected = FALSE; bool complete = FALSE; - /* the ftp struct is inited in ftp_connect() */ - struct FTP *ftp = data->req.p.ftp; + /* the ftp struct is inited in ftp_connect(). If we are connecting to an HTTP + * proxy then the state will not be valid until after that connection is + * complete */ + struct FTP *ftp = NULL; /* if the second connection isn't done yet, wait for it */ if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { @@ -3603,6 +3610,9 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) return result; #endif + /* Curl_proxy_connect might have moved the protocol state */ + ftp = data->req.p.ftp; + if(ftpc->state) { /* already in a state so skip the initial commands. They are only done to kickstart the do_more state */ diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h index 1cfdac0..7f6f432 100644 --- a/Utilities/cmcurl/lib/ftp.h +++ b/Utilities/cmcurl/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 +20,12 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ +#include "curl_setup.h" + #include "pingpong.h" #ifndef CURL_DISABLE_FTP @@ -149,6 +153,7 @@ struct ftp_conn { curl_off_t known_filesize; /* file size is different from -1, if wildcard LIST parsing was done and wc_statemach set it */ + BIT(ftp_trying_alternative); }; #define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */ diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c index 716ff38..40f5f3f 100644 --- a/Utilities/cmcurl/lib/ftplistparser.c +++ b/Utilities/cmcurl/lib/ftplistparser.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /** @@ -420,7 +422,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, char *endptr = finfo->b_data + 6; /* here we can deal with directory size, pass the leading whitespace and then the digits */ - while(ISSPACE(*endptr)) + while(ISBLANK(*endptr)) endptr++; while(ISDIGIT(*endptr)) endptr++; @@ -892,7 +894,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, parser->item_length++; switch(parser->state.NT.sub.time) { case PL_WINNT_TIME_PRESPACE: - if(!ISSPACE(c)) { + if(!ISBLANK(c)) { parser->state.NT.sub.time = PL_WINNT_TIME_TIME; } break; diff --git a/Utilities/cmcurl/lib/ftplistparser.h b/Utilities/cmcurl/lib/ftplistparser.h index e4cd820..0a80543 100644 --- a/Utilities/cmcurl/lib/ftplistparser.h +++ b/Utilities/cmcurl/lib/ftplistparser.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/functypes.h b/Utilities/cmcurl/lib/functypes.h new file mode 100644 index 0000000..8891b1d --- /dev/null +++ b/Utilities/cmcurl/lib/functypes.h @@ -0,0 +1,115 @@ +#ifndef HEADER_CURL_FUNCTYPES_H +#define HEADER_CURL_FUNCTYPES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, 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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +/* defaults: + + ssize_t recv(int, void *, size_t, int); + ssize_t send(int, const void *, size_t, int); + + If other argument or return types are needed: + + 1. For systems that run configure or cmake, the alternatives are provided + here. + 2. For systems with config-*.h files, define them there. +*/ + +#ifdef WIN32 +/* int recv(SOCKET, char *, int, int) */ +#define RECV_TYPE_ARG1 SOCKET +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 int +#define RECV_TYPE_RETV int + +/* int send(SOCKET, const char *, int, int); */ +#define SEND_TYPE_ARG1 SOCKET +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_RETV int + +#elif defined(__AMIGA__) /* Any AmigaOS flavour */ + +/* long recv(long, char *, long, long); */ +#define RECV_TYPE_ARG1 long +#define RECV_TYPE_ARG2 char * +#define RECV_TYPE_ARG3 long +#define RECV_TYPE_ARG4 long +#define RECV_TYPE_RETV long + +/* int send(int, const char *, int, int); */ +#define SEND_TYPE_ARG1 int +#define SEND_TYPE_ARG2 char * +#define SEND_TYPE_ARG3 int +#define SEND_TYPE_RETV int +#endif + + +#ifndef RECV_TYPE_ARG1 +#define RECV_TYPE_ARG1 int +#endif + +#ifndef RECV_TYPE_ARG2 +#define RECV_TYPE_ARG2 void * +#endif + +#ifndef RECV_TYPE_ARG3 +#define RECV_TYPE_ARG3 size_t +#endif + +#ifndef RECV_TYPE_ARG4 +#define RECV_TYPE_ARG4 int +#endif + +#ifndef RECV_TYPE_RETV +#define RECV_TYPE_RETV ssize_t +#endif + +#ifndef SEND_QUAL_ARG2 +#define SEND_QUAL_ARG2 const +#endif + +#ifndef SEND_TYPE_ARG1 +#define SEND_TYPE_ARG1 int +#endif + +#ifndef SEND_TYPE_ARG2 +#define SEND_TYPE_ARG2 void * +#endif + +#ifndef SEND_TYPE_ARG3 +#define SEND_TYPE_ARG3 size_t +#endif + +#ifndef SEND_TYPE_ARG4 +#define SEND_TYPE_ARG4 int +#endif + +#ifndef SEND_TYPE_RETV +#define SEND_TYPE_RETV ssize_t +#endif + +#endif /* HEADER_CURL_FUNCTYPES_H */ diff --git a/Utilities/cmcurl/lib/getenv.c b/Utilities/cmcurl/lib/getenv.c index 92c5350..5f00fd1 100644 --- a/Utilities/cmcurl/lib/getenv.c +++ b/Utilities/cmcurl/lib/getenv.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c index 9091e61..c3556b3 100644 --- a/Utilities/cmcurl/lib/getinfo.c +++ b/Utilities/cmcurl/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -164,6 +166,20 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, case CURLINFO_SCHEME: *param_charp = data->info.conn_scheme; break; + case CURLINFO_CAPATH: +#ifdef CURL_CA_PATH + *param_charp = CURL_CA_PATH; +#else + *param_charp = NULL; +#endif + break; + case CURLINFO_CAINFO: +#ifdef CURL_CA_BUNDLE + *param_charp = CURL_CA_BUNDLE; +#else + *param_charp = NULL; +#endif + break; default: return CURLE_UNKNOWN_OPTION; @@ -285,6 +301,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, /* return if the condition prevented the document to get transferred */ *param_longp = data->info.timecond ? 1L : 0L; break; +#ifndef CURL_DISABLE_RTSP case CURLINFO_RTSP_CLIENT_CSEQ: *param_longp = data->state.rtsp_next_client_CSeq; break; @@ -294,6 +311,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, case CURLINFO_RTSP_CSEQ_RECV: *param_longp = data->state.rtsp_CSeq_recv; break; +#endif case CURLINFO_HTTP_VERSION: switch(data->info.httpversion) { case 10: @@ -560,7 +578,7 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) CURLcode result = CURLE_UNKNOWN_OPTION; if(!data) - return result; + return CURLE_BAD_FUNCTION_ARGUMENT; va_start(arg, info); diff --git a/Utilities/cmcurl/lib/getinfo.h b/Utilities/cmcurl/lib/getinfo.h index f35d1b4..1b5e8c2 100644 --- a/Utilities/cmcurl/lib/getinfo.h +++ b/Utilities/cmcurl/lib/getinfo.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...); CURLcode Curl_initinfo(struct Curl_easy *data); diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c index 0a3ba8f..01f4bde 100644 --- a/Utilities/cmcurl/lib/gopher.c +++ b/Utilities/cmcurl/lib/gopher.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/gopher.h b/Utilities/cmcurl/lib/gopher.h index 6b8bd55..4ea269d 100644 --- a/Utilities/cmcurl/lib/gopher.h +++ b/Utilities/cmcurl/lib/gopher.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_GOPHER diff --git a/Utilities/cmcurl/lib/h2h3.c b/Utilities/cmcurl/lib/h2h3.c index c0ed58d..50254ad 100644 --- a/Utilities/cmcurl/lib/h2h3.c +++ b/Utilities/cmcurl/lib/h2h3.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -189,7 +191,7 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, vptr = Curl_checkheaders(data, STRCONST(H2H3_PSEUDO_SCHEME)); if(vptr) { vptr += sizeof(H2H3_PSEUDO_SCHEME); - while(*vptr && ISSPACE(*vptr)) + while(*vptr && ISBLANK(*vptr)) vptr++; nva[2].value = vptr; infof(data, "set pseudo header %s to %s", H2H3_PSEUDO_SCHEME, vptr); @@ -256,9 +258,6 @@ CURLcode Curl_pseudo_headers(struct Curl_easy *data, nva[i].valuelen = (end - hdbuf); } - nva[i].value = hdbuf; - nva[i].valuelen = (end - hdbuf); - ++i; } diff --git a/Utilities/cmcurl/lib/h2h3.h b/Utilities/cmcurl/lib/h2h3.h index 2225684..84caec5 100644 --- a/Utilities/cmcurl/lib/h2h3.h +++ b/Utilities/cmcurl/lib/h2h3.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c index 8848906..b6a2a33 100644 --- a/Utilities/cmcurl/lib/hash.c +++ b/Utilities/cmcurl/lib/hash.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h index e166916..5b59bf1 100644 --- a/Utilities/cmcurl/lib/hash.h +++ b/Utilities/cmcurl/lib/hash.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/headers.c b/Utilities/cmcurl/lib/headers.c index 226c696..978c918 100644 --- a/Utilities/cmcurl/lib/headers.c +++ b/Utilities/cmcurl/lib/headers.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -32,7 +34,7 @@ #include "curl_memory.h" #include "memdebug.h" -#if !defined(CURL_DISABLE_HTTP) && defined(USE_HEADERS_API) +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) /* Generate the curl_header struct for the user. This function MUST assign all struct fields in the output struct. */ @@ -72,8 +74,8 @@ CURLHcode curl_easy_header(CURL *easy, struct Curl_header_store *hs = NULL; struct Curl_header_store *pick = NULL; if(!name || !hout || !data || - (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX)) || - !type || (request < -1)) + (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX| + CURLH_PSEUDO)) || !type || (request < -1)) return CURLHE_BAD_ARGUMENT; if(!Curl_llist_count(&data->state.httphdrs)) return CURLHE_NOHEADERS; /* no headers available */ @@ -205,7 +207,7 @@ static CURLcode namevalue(char *header, size_t hlen, unsigned int type, return CURLE_BAD_FUNCTION_ARGUMENT; /* skip all leading space letters */ - while(*header && ISSPACE(*header)) + while(*header && ISBLANK(*header)) header++; *value = header; @@ -216,6 +218,57 @@ static CURLcode namevalue(char *header, size_t hlen, unsigned int type, return CURLE_OK; } +static CURLcode unfold_value(struct Curl_easy *data, const char *value, + size_t vlen) /* length of the incoming header */ +{ + struct Curl_header_store *hs; + struct Curl_header_store *newhs; + size_t olen; /* length of the old value */ + size_t oalloc; /* length of the old name + value + separator */ + size_t offset; + DEBUGASSERT(data->state.prevhead); + hs = data->state.prevhead; + olen = strlen(hs->value); + offset = hs->value - hs->buffer; + oalloc = olen + offset + 1; + + /* skip all trailing space letters */ + while(vlen && ISSPACE(value[vlen - 1])) + vlen--; + + /* save only one leading space */ + while((vlen > 1) && ISBLANK(value[0]) && ISBLANK(value[1])) { + vlen--; + value++; + } + + /* since this header block might move in the realloc below, it needs to + first be unlinked from the list and then re-added again after the + realloc */ + Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL); + + /* new size = struct + new value length + old name+value length */ + newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1); + if(!newhs) + return CURLE_OUT_OF_MEMORY; + /* ->name' and ->value point into ->buffer (to keep the header allocation + in a single memory block), which now potentially have moved. Adjust + them. */ + newhs->name = newhs->buffer; + newhs->value = &newhs->buffer[offset]; + + /* put the data at the end of the previous data, not the newline */ + memcpy(&newhs->value[olen], value, vlen); + newhs->value[olen + vlen] = 0; /* null-terminate at newline */ + + /* insert this node into the list of headers */ + Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail, + newhs, &newhs->node); + data->state.prevhead = newhs; + return CURLE_OK; +} + + /* * Curl_headers_push() gets passed a full HTTP header to store. It gets called * immediately before the header callback. The header is CRLF terminated. @@ -242,6 +295,15 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, } hlen = end - header + 1; + if((header[0] == ' ') || (header[0] == '\t')) { + if(data->state.prevhead) + /* line folding, append value to the previous header's value */ + return unfold_value(data, header, hlen); + else + /* can't unfold without a previous header */ + return CURLE_BAD_FUNCTION_ARGUMENT; + } + hs = calloc(1, sizeof(*hs) + hlen); if(!hs) return CURLE_OUT_OF_MEMORY; @@ -260,7 +322,7 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header, /* insert this node into the list of headers */ Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail, hs, &hs->node); - + data->state.prevhead = hs; return CURLE_OK; fail: free(hs); diff --git a/Utilities/cmcurl/lib/headers.h b/Utilities/cmcurl/lib/headers.h index 48c013b..96332db 100644 --- a/Utilities/cmcurl/lib/headers.h +++ b/Utilities/cmcurl/lib/headers.h @@ -20,10 +20,12 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" -#if !defined(CURL_DISABLE_HTTP) && defined(USE_HEADERS_API) +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API) struct Curl_header_store { struct Curl_llist_element node; diff --git a/Utilities/cmcurl/lib/hmac.c b/Utilities/cmcurl/lib/hmac.c index 85b175d..dfb0db5 100644 --- a/Utilities/cmcurl/lib/hmac.c +++ b/Utilities/cmcurl/lib/hmac.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC2104 Keyed-Hashing for Message Authentication * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c index f7d99ce..0bfbe2e 100644 --- a/Utilities/cmcurl/lib/hostasyn.c +++ b/Utilities/cmcurl/lib/hostasyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index 7000b85..941ecac 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -179,7 +181,7 @@ create_hostcache_id(const char *name, int port, char *ptr, size_t buflen) len = buflen - 7; /* store and lower case the name */ while(len--) - *ptr++ = (char)TOLOWER(*name++); + *ptr++ = Curl_raw_tolower(*name++); msnprintf(ptr, 7, ":%u", port); } @@ -295,6 +297,31 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, } } + /* See if the returned entry matches the required resolve mode */ + if(dns && data->conn->ip_version != CURL_IPRESOLVE_WHATEVER) { + int pf = PF_INET; + bool found = false; + struct Curl_addrinfo *addr = dns->addr; + +#ifdef PF_INET6 + if(data->conn->ip_version == CURL_IPRESOLVE_V6) + pf = PF_INET6; +#endif + + while(addr) { + if(addr->ai_family == pf) { + found = true; + break; + } + addr = addr->ai_next; + } + + if(!found) { + infof(data, "Hostname in DNS cache doesn't have needed family, zapped"); + dns = NULL; /* the memory deallocation is being handled by the hash */ + Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1); + } + } return dns; } @@ -461,12 +488,12 @@ Curl_cache_addr(struct Curl_easy *data, } #ifdef ENABLE_IPV6 -/* return a static IPv6 resolve for 'localhost' */ -static struct Curl_addrinfo *get_localhost6(int port) +/* return a static IPv6 ::1 for the name */ +static struct Curl_addrinfo *get_localhost6(int port, const char *name) { struct Curl_addrinfo *ca; const size_t ss_size = sizeof(struct sockaddr_in6); - const size_t hostlen = strlen("localhost"); + const size_t hostlen = strlen(name); struct sockaddr_in6 sa6; unsigned char ipv6[16]; unsigned short port16 = (unsigned short)(port & 0xffff); @@ -491,19 +518,19 @@ static struct Curl_addrinfo *get_localhost6(int port) 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"); + strcpy(ca->ai_canonname, name); return ca; } #else -#define get_localhost6(x) NULL +#define get_localhost6(x,y) NULL #endif -/* return a static IPv4 resolve for 'localhost' */ -static struct Curl_addrinfo *get_localhost(int port) +/* return a static IPv4 127.0.0.1 for the given name */ +static struct Curl_addrinfo *get_localhost(int port, const char *name) { struct Curl_addrinfo *ca; const size_t ss_size = sizeof(struct sockaddr_in); - const size_t hostlen = strlen("localhost"); + const size_t hostlen = strlen(name); struct sockaddr_in sa; unsigned int ipv4; unsigned short port16 = (unsigned short)(port & 0xffff); @@ -527,8 +554,8 @@ static struct Curl_addrinfo *get_localhost(int port) 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); + strcpy(ca->ai_canonname, name); + ca->ai_next = get_localhost6(port, name); return ca; } @@ -544,7 +571,11 @@ bool Curl_ipv6works(struct Curl_easy *data) have the info kept for fast re-use */ DEBUGASSERT(data); DEBUGASSERT(data->multi); - return data->multi->ipv6_works; + if(data->multi->ipv6_up == IPV6_UNKNOWN) { + bool works = Curl_ipv6works(NULL); + data->multi->ipv6_up = works ? IPV6_WORKS : IPV6_DEAD; + } + return data->multi->ipv6_up == IPV6_WORKS; } else { int ipv6_works = -1; @@ -581,6 +612,17 @@ bool Curl_host_is_ipnum(const char *hostname) return FALSE; } + +/* return TRUE if 'part' is a case insensitive tail of 'full' */ +static bool tailmatch(const char *full, const char *part) +{ + size_t plen = strlen(part); + size_t flen = strlen(full); + if(plen > flen) + return FALSE; + return strncasecompare(part, &full[flen - plen], plen); +} + /* * 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 @@ -716,8 +758,9 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, if(conn->ip_version == CURL_IPRESOLVE_V6 && !Curl_ipv6works(data)) return CURLRESOLV_ERROR; - if(strcasecompare(hostname, "localhost")) - addr = get_localhost(port); + if(strcasecompare(hostname, "localhost") || + tailmatch(hostname, ".localhost")) + addr = get_localhost(port, hostname); #ifndef CURL_DISABLE_DOH else if(allowDOH && data->set.doh && !ipnum) addr = Curl_doh(data, hostname, port, &respwait); @@ -991,9 +1034,9 @@ static void freednsentry(void *freethis) /* * Curl_init_dnscache() inits a new DNS cache. */ -void Curl_init_dnscache(struct Curl_hash *hash) +void Curl_init_dnscache(struct Curl_hash *hash, int size) { - Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare, + Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare, freednsentry); } diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h index 1db5981..9d31707 100644 --- a/Utilities/cmcurl/lib/hostip.h +++ b/Utilities/cmcurl/lib/hostip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -130,7 +132,7 @@ void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns); /* init a new dns cache */ -void Curl_init_dnscache(struct Curl_hash *hash); +void Curl_init_dnscache(struct Curl_hash *hash, int hashsize); /* prune old entries from the DNS cache */ void Curl_hostcache_prune(struct Curl_easy *data); diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c index 1fd7910..1dd54e8 100644 --- a/Utilities/cmcurl/lib/hostip4.c +++ b/Utilities/cmcurl/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -110,7 +112,8 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, #endif /* CURLRES_SYNCH */ #endif /* CURLRES_IPV4 */ -#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES) +#if defined(CURLRES_IPV4) && \ + !defined(CURLRES_ARES) && !defined(CURLRES_AMIGA) /* * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function. @@ -295,4 +298,5 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, return ai; } -#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */ +#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) && + !defined(CURLRES_AMIGA) */ diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c index c2d5f08..c62c254 100644 --- a/Utilities/cmcurl/lib/hostip6.c +++ b/Utilities/cmcurl/lib/hostip6.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -94,8 +96,8 @@ static void dump_addrinfo(struct connectdata *conn, * non-ares version). * * Returns name information about the given hostname and port number. If - * successful, the 'addrinfo' is returned and the forth argument will point to - * memory we need to free after use. That memory *MUST* be freed with + * successful, the 'addrinfo' is returned and the fourth argument will point + * to memory we need to free after use. That memory *MUST* be freed with * Curl_freeaddrinfo(), nothing else. */ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, @@ -115,7 +117,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data, *waitp = 0; /* synchronous response only */ - if(Curl_ipv6works(data)) + if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) /* The stack seems to be IPv6-enabled */ pf = PF_UNSPEC; diff --git a/Utilities/cmcurl/lib/hostsyn.c b/Utilities/cmcurl/lib/hostsyn.c index c00c274..ee54363 100644 --- a/Utilities/cmcurl/lib/hostsyn.c +++ b/Utilities/cmcurl/lib/hostsyn.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/hsts.c b/Utilities/cmcurl/lib/hsts.c index b9fa6f7..e3b686e 100644 --- a/Utilities/cmcurl/lib/hsts.c +++ b/Utilities/cmcurl/lib/hsts.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* * The Strict-Transport-Security header is defined in RFC 6797: @@ -35,7 +37,7 @@ #include "sendf.h" #include "strtoofft.h" #include "parsedate.h" -#include "rand.h" +#include "fopen.h" #include "rename.h" #include "strtoofft.h" @@ -154,7 +156,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, return CURLE_OK; do { - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(Curl_strncasecompare("max-age=", p, 8)) { bool quoted = FALSE; @@ -165,7 +167,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, return CURLE_BAD_FUNCTION_ARGUMENT; p += 8; - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(*p == '\"') { p++; @@ -198,7 +200,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, p++; } - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(*p == ';') p++; @@ -354,8 +356,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, struct Curl_llist_element *n; CURLcode result = CURLE_OK; FILE *out; - char *tempstore; - unsigned char randsuffix[9]; + char *tempstore = NULL; if(!h) /* no cache activated */ @@ -369,17 +370,8 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, /* marked as read-only, no file or zero length file name */ goto skipsave; - if(Curl_rand_hex(data, randsuffix, sizeof(randsuffix))) - return CURLE_FAILED_INIT; - - tempstore = aprintf("%s.%s.tmp", file, randsuffix); - if(!tempstore) - return CURLE_OUT_OF_MEMORY; - - out = fopen(tempstore, FOPEN_WRITETEXT); - if(!out) - result = CURLE_WRITE_ERROR; - else { + result = Curl_fopen(data, file, &out, &tempstore); + if(!result) { fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n" "# This file was generated by libcurl! Edit at your own risk.\n", out); @@ -391,10 +383,10 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, break; } fclose(out); - if(!result && Curl_rename(tempstore, file)) + if(!result && tempstore && Curl_rename(tempstore, file)) result = CURLE_WRITE_ERROR; - if(result) + if(result && tempstore) unlink(tempstore); } free(tempstore); @@ -494,8 +486,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h) /* * Load the HSTS cache from the given file. The text based line-oriented file - * format is documented here: - * https://github.com/curl/curl/wiki/HSTS + * format is documented here: https://curl.se/docs/hsts.html * * This function only returns error on major problems that prevent hsts * handling to work completely. It will ignore individual syntactical errors diff --git a/Utilities/cmcurl/lib/hsts.h b/Utilities/cmcurl/lib/hsts.h index 653c053..0e36a77 100644 --- a/Utilities/cmcurl/lib/hsts.h +++ b/Utilities/cmcurl/lib/hsts.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2020 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index b215307..f57859e 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -82,6 +84,7 @@ #include "strdup.h" #include "altsvc.h" #include "hsts.h" +#include "ws.h" #include "c-hyper.h" /* The last 3 #include files should be in this order */ @@ -112,6 +115,10 @@ static int https_getsock(struct Curl_easy *data, #endif static CURLcode http_setup_conn(struct Curl_easy *data, struct connectdata *conn); +#ifdef USE_WEBSOCKETS +static CURLcode ws_setup_conn(struct Curl_easy *data, + struct connectdata *conn); +#endif /* * HTTP handler interface. @@ -140,6 +147,32 @@ const struct Curl_handler Curl_handler_http = { PROTOPT_USERPWDCTRL }; +#ifdef USE_WEBSOCKETS +const struct Curl_handler Curl_handler_ws = { + "WS", /* scheme */ + ws_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTP, /* defport */ + CURLPROTO_WS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_CREDSPERREQUEST | /* flags */ + PROTOPT_USERPWDCTRL +}; +#endif + #ifdef USE_SSL /* * HTTPS handler interface. @@ -164,11 +197,38 @@ const struct Curl_handler Curl_handler_https = { PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ CURLPROTO_HTTP, /* family */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN | /* flags */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN | /* flags */ + PROTOPT_USERPWDCTRL +}; + +#ifdef USE_WEBSOCKETS +const struct Curl_handler Curl_handler_wss = { + "WSS", /* scheme */ + ws_setup_conn, /* setup_connection */ + Curl_http, /* do_it */ + Curl_http_done, /* done */ + ZERO_NULL, /* do_more */ + Curl_http_connect, /* connect_it */ + https_connecting, /* connecting */ + ZERO_NULL, /* doing */ + https_getsock, /* proto_getsock */ + http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ + ZERO_NULL, /* attach connection */ + PORT_HTTPS, /* defport */ + CURLPROTO_WSS, /* protocol */ + CURLPROTO_HTTP, /* family */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */ PROTOPT_USERPWDCTRL }; #endif +#endif + static CURLcode http_setup_conn(struct Curl_easy *data, struct connectdata *conn) { @@ -203,6 +263,16 @@ static CURLcode http_setup_conn(struct Curl_easy *data, return CURLE_OK; } +#ifdef USE_WEBSOCKETS +static CURLcode ws_setup_conn(struct Curl_easy *data, + struct connectdata *conn) +{ + /* websockets is 1.1 only (for now) */ + data->state.httpwant = CURL_HTTP_VERSION_1_1; + return http_setup_conn(data, conn); +} +#endif + #ifndef CURL_DISABLE_PROXY /* * checkProxyHeaders() checks the linked list of custom proxy headers @@ -651,21 +721,6 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data) return result; } -/* - * Curl_allow_auth_to_host() tells if authentication, cookies or other - * "sensitive data" can (still) be sent to this host. - */ -bool Curl_allow_auth_to_host(struct Curl_easy *data) -{ - struct connectdata *conn = data->conn; - return (!data->state.this_is_a_follow || - data->set.allow_auth_to_other_hosts || - (data->state.first_host && - strcasecompare(data->state.first_host, conn->host.name) && - (data->state.first_remote_port == conn->remote_port) && - (data->state.first_remote_protocol == conn->handler->protocol))); -} - #ifndef CURL_DISABLE_HTTP_AUTH /* * Output the correct authentication header depending on the auth type @@ -864,7 +919,7 @@ 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 */ - if(Curl_allow_auth_to_host(data) + if(Curl_auth_allowed_to_host(data) #ifndef CURL_DISABLE_NETRC || conn->bits.netrc #endif @@ -1516,7 +1571,7 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done) } #endif - if(conn->given->protocol & CURLPROTO_HTTPS) { + if(conn->given->flags & PROTOPT_SSL) { /* perform SSL initialization */ result = https_connecting(data, done); if(result) @@ -1641,6 +1696,7 @@ CURLcode Curl_http_done(struct Curl_easy *data, Curl_mime_cleanpart(&http->form); Curl_dyn_reset(&data->state.headerb); Curl_hyper_done(data); + Curl_ws_done(data); if(status) return status; @@ -1917,7 +1973,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, checkprefix("Cookie:", compare)) && /* be careful of sending this potentially sensitive header to other hosts */ - !Curl_allow_auth_to_host(data)) + !Curl_auth_allowed_to_host(data)) ; else { #ifdef USE_HYPER @@ -2030,7 +2086,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data, void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, const char **method, Curl_HttpReq *reqp) { - Curl_HttpReq httpreq = data->state.httpreq; + Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq; const char *request; if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && data->set.upload) @@ -2149,9 +2205,9 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn) [brackets] if the host name is a plain IPv6-address. RFC2732-style. */ const char *host = conn->host.name; - if(((conn->given->protocol&CURLPROTO_HTTPS) && + if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) && (conn->remote_port == PORT_HTTPS)) || - ((conn->given->protocol&CURLPROTO_HTTP) && + ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) && (conn->remote_port == PORT_HTTP)) ) /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include the port number in the host string */ @@ -2700,6 +2756,13 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, FIRSTSOCKET); if(result) failf(data, "Failed sending HTTP request"); +#ifdef USE_WEBSOCKETS + else if((conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) && + !(data->set.connect_only)) + /* Set up the transfer for two-way since without CONNECT_ONLY set, this + request probably wants to send data too post upgrade */ + Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET); +#endif else /* HTTP GET/HEAD download: */ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); @@ -2709,12 +2772,14 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, } #if !defined(CURL_DISABLE_COOKIES) + CURLcode Curl_http_cookies(struct Curl_easy *data, struct connectdata *conn, struct dynbuf *r) { CURLcode result = CURLE_OK; char *addcookies = NULL; + bool linecap = FALSE; if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, STRCONST("Cookie"))) addcookies = data->set.str[STRING_COOKIE]; @@ -2727,12 +2792,12 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, const char *host = data->state.aptr.cookiehost ? data->state.aptr.cookiehost : conn->host.name; const bool secure_context = - conn->handler->protocol&CURLPROTO_HTTPS || + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || 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, host, data->state.up.path, + co = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path, secure_context); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } @@ -2746,6 +2811,13 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, if(result) break; } + if((Curl_dyn_len(r) + strlen(co->name) + strlen(co->value) + 1) >= + MAX_COOKIE_HEADER_LEN) { + infof(data, "Restricted outgoing cookies due to header size, " + "'%s' not sent", co->name); + linecap = TRUE; + break; + } result = Curl_dyn_addf(r, "%s%s=%s", count?"; ":"", co->name, co->value); if(result) @@ -2756,7 +2828,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data, } Curl_cookie_freelist(store); } - if(addcookies && !result) { + if(addcookies && !result && !linecap) { if(!count) result = Curl_dyn_addn(r, STRCONST("Cookie: ")); if(!result) { @@ -3033,7 +3105,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) if(conn->transport != TRNSPRT_QUIC) { if(conn->httpversion < 20) { /* unless the connection is re-used and already http2 */ - switch(conn->negnpn) { + switch(conn->alpn) { case CURL_HTTP_VERSION_2: conn->httpversion = 20; /* we know we're on HTTP/2 now */ @@ -3245,6 +3317,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) } result = Curl_http_cookies(data, conn, &req); + if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, &req); if(!result) result = Curl_add_timecondition(data, &req); if(!result) @@ -3509,15 +3583,15 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, 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 + strlen("Retry-After:")); - if(-1 == date) { - /* not a date, try it as a decimal number */ - (void)curlx_strtoofft(headp + strlen("Retry-After:"), - NULL, 10, &retry_after); + /* Try it as a decimal number, if it works it is not a date */ + (void)curlx_strtoofft(headp + strlen("Retry-After:"), + NULL, 10, &retry_after); + if(!retry_after) { + time_t date = Curl_getdate_capped(headp + strlen("Retry-After:")); + if(-1 != date) + /* convert date to number of seconds into the future */ + retry_after = date - time(NULL); } - else - /* convert date to number of seconds into the future */ - retry_after = date - time(NULL); data->info.retry_after = retry_after; /* store it */ } else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) { @@ -3529,7 +3603,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, The second format was added since Sun's webserver JavaWebServer/1.1.1 obviously sends the header this way! The third added since some servers use that! - The forth means the requested range was unsatisfied. + The fourth means the requested range was unsatisfied. */ char *ptr = headp + strlen("Content-Range:"); @@ -3557,7 +3631,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, const char *host = data->state.aptr.cookiehost? data->state.aptr.cookiehost:conn->host.name; const bool secure_context = - conn->handler->protocol&CURLPROTO_HTTPS || + conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || strcasecompare("localhost", host) || !strcmp(host, "127.0.0.1") || !strcmp(host, "[::1]") ? TRUE : FALSE; @@ -3641,7 +3715,14 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn, #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)) { + ((conn->handler->flags & PROTOPT_SSL) || +#ifdef CURLDEBUG + /* allow debug builds to circumvent the HTTPS restriction */ + getenv("CURL_HSTS_HTTP") +#else + 0 +#endif + )) { CURLcode check = Curl_hsts_parse(data->hsts, data->state.up.hostname, headp + strlen("Strict-Transport-Security:")); @@ -3723,7 +3804,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data, connclose(conn, "HTTP/1.0 close after body"); } else if(conn->httpversion == 20 || - (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) { + (k->upgr101 == UPGR101_H2 && k->httpcode == 101)) { DEBUGF(infof(data, "HTTP/2 found, allow multiplexing")); /* HTTP/2 cannot avoid multiplexing since it is a core functionality of the protocol */ @@ -3799,11 +3880,16 @@ static CURLcode verify_header(struct Curl_easy *data) if(k->headerline < 2) /* the first "header" is the status-line and it has no colon */ return CURLE_OK; - ptr = memchr(header, ':', hlen); - if(!ptr) { - /* this is bad, bail out */ - failf(data, "Header without colon"); - return CURLE_WEIRD_SERVER_REPLY; + if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2) + /* line folding, can't happen on line 2 */ + ; + else { + ptr = memchr(header, ':', hlen); + if(!ptr) { + /* this is bad, bail out */ + failf(data, "Header without colon"); + return CURLE_WEIRD_SERVER_REPLY; + } } return CURLE_OK; } @@ -3944,9 +4030,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, break; case 101: /* Switching Protocols */ - if(k->upgr101 == UPGR101_REQUESTED) { + if(k->upgr101 == UPGR101_H2) { /* Switching to HTTP/2 */ - infof(data, "Received 101"); + infof(data, "Received 101, Switching to HTTP/2"); k->upgr101 = UPGR101_RECEIVED; /* we'll get more headers (HTTP/2 response) */ @@ -3960,8 +4046,21 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return result; *nread = 0; } +#ifdef USE_WEBSOCKETS + else if(k->upgr101 == UPGR101_WS) { + /* verify the response */ + result = Curl_ws_accept(data); + if(result) + return result; + k->header = FALSE; /* no more header to parse! */ + if(data->set.connect_only) { + k->keepon &= ~KEEP_RECV; /* read no more content */ + *nread = 0; + } + } +#endif else { - /* Switching to another protocol (e.g. WebSocket) */ + /* Not switching to another protocol */ k->header = FALSE; /* no more header to parse! */ } break; @@ -4054,6 +4153,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, return CURLE_HTTP_RETURNED_ERROR; } +#ifdef USE_WEBSOCKETS + /* All non-101 HTTP status codes are bad when wanting to upgrade to + websockets */ + if(data->req.upgr101 == UPGR101_WS) { + failf(data, "Refused WebSockets upgrade: %d", k->httpcode); + return CURLE_HTTP_RETURNED_ERROR; + } +#endif + + data->req.deductheadercount = (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h index c4ab3c2..f7cbb34 100644 --- a/Utilities/cmcurl/lib/http.h +++ b/Utilities/cmcurl/lib/http.h @@ -20,8 +20,11 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" +#include "ws.h" typedef enum { HTTPREQ_GET, @@ -48,6 +51,15 @@ extern const struct Curl_handler Curl_handler_http; extern const struct Curl_handler Curl_handler_https; #endif +#ifdef USE_WEBSOCKETS +extern const struct Curl_handler Curl_handler_ws; + +#ifdef USE_SSL +extern const struct Curl_handler Curl_handler_wss; +#endif +#endif /* websockets */ + + /* Header specific functions */ bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ @@ -216,6 +228,10 @@ struct HTTP { HTTPSEND_BODY /* sending body */ } sending; +#ifdef USE_WEBSOCKETS + struct websocket ws; +#endif + #ifndef CURL_DISABLE_HTTP struct dynbuf send_buffer; /* used if the request couldn't be sent in one chunk, points to an allocated send_buffer @@ -225,13 +241,11 @@ struct HTTP { /*********** for HTTP/2 we store stream-local data here *************/ int32_t stream_id; /* stream we are interested in */ - bool bodystarted; /* We store non-final and final response headers here, per-stream */ struct dynbuf header_recvbuf; size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into upper layer */ struct dynbuf trailer_recvbuf; - int status_code; /* HTTP status code */ const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ bool close_handled; /* TRUE if stream closure is handled by libcurl */ @@ -242,6 +256,8 @@ struct HTTP { uint32_t error; /* HTTP/2 stream error code */ #endif #if defined(USE_NGHTTP2) || defined(USE_NGHTTP3) + bool bodystarted; + int status_code; /* HTTP status code */ bool closed; /* TRUE on HTTP2 stream close */ char *mem; /* points to a buffer in memory to store received data */ size_t len; /* size of the buffer 'mem' points to */ @@ -258,6 +274,7 @@ struct HTTP { #ifndef USE_MSH3 /*********** for HTTP/3 we store stream-local data here *************/ int64_t stream3_id; /* stream we are interested in */ + uint64_t error3; /* HTTP/3 stream error code */ bool firstheader; /* FALSE until headers arrive */ bool firstbody; /* FALSE until body arrives */ bool h3req; /* FALSE until request is issued */ @@ -364,10 +381,4 @@ Curl_http_output_auth(struct Curl_easy *data, bool proxytunnel); /* TRUE if this is the request setting up the proxy tunnel */ -/* - * Curl_allow_auth_to_host() tells if authentication, cookies or other - * "sensitive data" can (still) be sent to this host. - */ -bool Curl_allow_auth_to_host(struct Curl_easy *data); - #endif /* HEADER_CURL_HTTP_H */ diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index 0120b86..b7409b0 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -643,7 +645,7 @@ 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", + infof(data, "failed to set user_data for stream %u", frame->promised_stream_id); DEBUGASSERT(0); rv = CURL_PUSH_DENY; @@ -713,19 +715,19 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, data_s = nghttp2_session_get_stream_user_data(session, stream_id); if(!data_s) { H2BUGF(infof(data, - "No Curl_easy associated with stream: %x", + "No Curl_easy associated with stream: %u", stream_id)); return 0; } stream = data_s->req.p.http; if(!stream) { - H2BUGF(infof(data_s, "No proto pointer for stream: %x", + H2BUGF(infof(data_s, "No proto pointer for stream: %u", stream_id)); return NGHTTP2_ERR_CALLBACK_FAILURE; } - H2BUGF(infof(data_s, "on_frame_recv() header %x stream %x", + H2BUGF(infof(data_s, "on_frame_recv() header %x stream %u", frame->hd.type, stream_id)); switch(frame->hd.type) { @@ -913,7 +915,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, /* 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", + infof(data_s, "http/2: failed to clear user_data for stream %u", stream_id); DEBUGASSERT(0); } @@ -1050,6 +1052,12 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, else if(stream->push_headers_used == stream->push_headers_alloc) { char **headp; + if(stream->push_headers_alloc > 1000) { + /* this is beyond crazy many headers, bail out */ + failf(data_s, "Too many PUSH_PROMISE headers"); + Curl_safefree(stream->push_headers); + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; + } stream->push_headers_alloc *= 2; headp = Curl_saferealloc(stream->push_headers, stream->push_headers_alloc * sizeof(char *)); @@ -1240,13 +1248,13 @@ void Curl_http2_done(struct Curl_easy *data, bool premature) /* do this before the reset handling, as that might clear ->stream_id */ if(http->stream_id == httpc->pause_stream_id) { - H2BUGF(infof(data, "DONE the pause stream (%x)", http->stream_id)); + H2BUGF(infof(data, "DONE the pause stream (%u)", http->stream_id)); httpc->pause_stream_id = 0; } if(premature || (!http->closed && http->stream_id)) { /* RST_STREAM */ set_transfer(httpc, data); /* set the transfer */ - H2BUGF(infof(data, "RST stream %x", http->stream_id)); + H2BUGF(infof(data, "RST stream %u", http->stream_id)); if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id, NGHTTP2_STREAM_CLOSED)) (void)nghttp2_session_send(httpc->h2); @@ -1260,7 +1268,7 @@ 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", + infof(data, "http/2: failed to clear user_data for stream %u", http->stream_id); DEBUGASSERT(0); } @@ -1269,6 +1277,27 @@ void Curl_http2_done(struct Curl_easy *data, bool premature) } } +static int client_new(struct connectdata *conn, + nghttp2_session_callbacks *callbacks) +{ +#if NGHTTP2_VERSION_NUM < 0x013200 + /* before 1.50.0 */ + return nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); +#else + nghttp2_option *o; + int rc = nghttp2_option_new(&o); + if(rc) + return rc; + /* turn off RFC 9113 leading and trailing white spaces validation against + HTTP field value. */ + nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(o, 1); + rc = nghttp2_session_client_new2(&conn->proto.httpc.h2, callbacks, conn, + o); + nghttp2_option_del(o); + return rc; +#endif +} + /* * Initialize nghttp2 for a Curl connection */ @@ -1309,7 +1338,7 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn) nghttp2_session_callbacks_set_error_callback(callbacks, error_callback); /* The nghttp2 session is not yet setup, do it */ - rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn); + rc = client_new(conn, callbacks); nghttp2_session_callbacks_del(callbacks); @@ -1363,7 +1392,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); free(base64); - k->upgr101 = UPGR101_REQUESTED; + k->upgr101 = UPGR101_H2; return result; } @@ -1519,7 +1548,7 @@ 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(stream->error == NGHTTP2_REFUSED_STREAM) { - H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection", + H2BUGF(infof(data, "REFUSED_STREAM (%u), try again on a new connection", stream->stream_id)); connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */ data->state.refused_stream = TRUE; @@ -1527,7 +1556,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, return -1; } else if(stream->error != NGHTTP2_NO_ERROR) { - failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)", + failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)", stream->stream_id, nghttp2_http2_strerror(stream->error), stream->error); *err = CURLE_HTTP2_STREAM; @@ -1535,7 +1564,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, } if(!stream->bodystarted) { - failf(data, "HTTP/2 stream %d was closed cleanly, but before getting " + failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " " all response header fields, treated as error", stream->stream_id); *err = CURLE_HTTP2_STREAM; @@ -1740,7 +1769,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", + H2BUGF(infof(data, "stream %u is paused, pause id: %u", stream->stream_id, httpc->pause_stream_id)); *err = CURLE_AGAIN; return -1; @@ -1771,7 +1800,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex, /* 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" + failf(data, "HTTP/2 stream %u was not closed cleanly before" " end of the underlying stream", stream->stream_id); *err = CURLE_HTTP2_STREAM; @@ -1855,7 +1884,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex, if(stream->stream_id != -1) { if(stream->close_handled) { - infof(data, "stream %d closed", stream->stream_id); + infof(data, "stream %u closed", stream->stream_id); *err = CURLE_HTTP2_STREAM; return -1; } @@ -1968,13 +1997,13 @@ 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", + "http2_send() nghttp2_submit_request error (%s)%u", nghttp2_strerror(stream_id), stream_id)); *err = CURLE_SEND_ERROR; return -1; } - infof(data, "Using Stream ID: %x (easy handle %p)", + infof(data, "Using Stream ID: %u (easy handle %p)", stream_id, (void *)data); stream->stream_id = stream_id; @@ -2094,7 +2123,7 @@ 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", + infof(data, "http/2: failed to set user_data for stream %u", stream->stream_id); DEBUGASSERT(0); } diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h index d6986d9..f039059 100644 --- a/Utilities/cmcurl/lib/http2.h +++ b/Utilities/cmcurl/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c index 210c3db..440eb38 100644 --- a/Utilities/cmcurl/lib/http_aws_sigv4.c +++ b/Utilities/cmcurl/lib/http_aws_sigv4.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -27,8 +29,6 @@ #include "urldata.h" #include "strcase.h" #include "strdup.h" -#include "vauth/vauth.h" -#include "vauth/digest.h" #include "http_aws_sigv4.h" #include "curl_sha256.h" #include "transfer.h" @@ -44,6 +44,8 @@ #include "curl_memory.h" #include "memdebug.h" +#include "slist.h" + #define HMAC_SHA256(k, kl, d, dl, o) \ do { \ ret = Curl_hmacit(Curl_HMAC_SHA256, \ @@ -51,19 +53,219 @@ (unsigned int)kl, \ (unsigned char *)d, \ (unsigned int)dl, o); \ - if(ret != CURLE_OK) { \ + if(ret) { \ goto fail; \ } \ } while(0) +#define TIMESTAMP_SIZE 17 + static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l) { int i; DEBUGASSERT(dst_l >= 65); for(i = 0; i < 32; ++i) { - curl_msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]); + msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]); + } +} + +static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr) +{ + char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr)); + + if(tmp) + return tmp; + return Curl_checkheaders(data, STRCONST("Date")); +} + +/* remove whitespace, and lowercase all headers */ +static void trim_headers(struct curl_slist *head) +{ + struct curl_slist *l; + for(l = head; l; l = l->next) { + char *value; /* to read from */ + char *store; + size_t colon = strcspn(l->data, ":"); + Curl_strntolower(l->data, l->data, colon); + + value = &l->data[colon]; + if(!*value) + continue; + ++value; + store = value; + + /* skip leading whitespace */ + while(*value && ISBLANK(*value)) + value++; + + while(*value) { + int space = 0; + while(*value && ISBLANK(*value)) { + value++; + space++; + } + if(space) { + /* replace any number of consecutive whitespace with a single space, + unless at the end of the string, then nothing */ + if(*value) + *store++ = ' '; + } + else + *store++ = *value++; + } + *store = 0; /* null terminate */ + } +} + +/* maximum lenth for the aws sivg4 parts */ +#define MAX_SIGV4_LEN 64 +#define MAX_SIGV4_LEN_TXT "64" + +#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date")) + +#define MAX_HOST_LEN 255 +/* FQDN + host: */ +#define FULL_HOST_LEN (MAX_HOST_LEN + sizeof("host:")) + +/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */ +#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1) + +/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */ +static CURLcode make_headers(struct Curl_easy *data, + const char *hostname, + char *timestamp, + char *provider1, + char **date_header, + struct dynbuf *canonical_headers, + struct dynbuf *signed_headers) +{ + char date_hdr_key[DATE_HDR_KEY_LEN]; + char date_full_hdr[DATE_FULL_HDR_LEN]; + struct curl_slist *head = NULL; + struct curl_slist *tmp_head = NULL; + CURLcode ret = CURLE_OUT_OF_MEMORY; + struct curl_slist *l; + int again = 1; + + /* provider1 mid */ + Curl_strntolower(provider1, provider1, strlen(provider1)); + provider1[0] = Curl_raw_toupper(provider1[0]); + + msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1); + + /* provider1 lowercase */ + Curl_strntolower(provider1, provider1, 1); /* first byte only */ + msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, + "x-%s-date:%s", provider1, timestamp); + + if(Curl_checkheaders(data, STRCONST("Host"))) { + head = NULL; + } + else { + char full_host[FULL_HOST_LEN + 1]; + + if(data->state.aptr.host) { + size_t pos; + + if(strlen(data->state.aptr.host) > FULL_HOST_LEN) { + ret = CURLE_URL_MALFORMAT; + goto fail; + } + strcpy(full_host, data->state.aptr.host); + /* remove /r/n as the separator for canonical request must be '\n' */ + pos = strcspn(full_host, "\n\r"); + full_host[pos] = 0; + } + else { + if(strlen(hostname) > MAX_HOST_LEN) { + ret = CURLE_URL_MALFORMAT; + goto fail; + } + msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname); + } + + head = curl_slist_append(NULL, full_host); + if(!head) + goto fail; + } + + + for(l = data->set.headers; l; l = l->next) { + tmp_head = curl_slist_append(head, l->data); + if(!tmp_head) + goto fail; + head = tmp_head; + } + + trim_headers(head); + + *date_header = find_date_hdr(data, date_hdr_key); + if(!*date_header) { + tmp_head = curl_slist_append(head, date_full_hdr); + if(!tmp_head) + goto fail; + head = tmp_head; + *date_header = curl_maprintf("%s: %s", date_hdr_key, timestamp); + } + else { + char *value; + + *date_header = strdup(*date_header); + if(!*date_header) + goto fail; + + value = strchr(*date_header, ':'); + if(!value) + goto fail; + ++value; + while(ISBLANK(*value)) + ++value; + strncpy(timestamp, value, TIMESTAMP_SIZE - 1); + timestamp[TIMESTAMP_SIZE - 1] = 0; + } + + /* alpha-sort in a case sensitive manner */ + do { + again = 0; + for(l = head; l; l = l->next) { + struct curl_slist *next = l->next; + + if(next && strcmp(l->data, next->data) > 0) { + char *tmp = l->data; + + l->data = next->data; + next->data = tmp; + again = 1; + } + } + } while(again); + + for(l = head; l; l = l->next) { + char *tmp; + + if(Curl_dyn_add(canonical_headers, l->data)) + goto fail; + if(Curl_dyn_add(canonical_headers, "\n")) + goto fail; + + tmp = strchr(l->data, ':'); + if(tmp) + *tmp = 0; + + if(l != head) { + if(Curl_dyn_add(signed_headers, ";")) + goto fail; + } + if(Curl_dyn_add(signed_headers, l->data)) + goto fail; } + + ret = CURLE_OK; +fail: + curl_slist_free_all(head); + + return ret; } CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) @@ -71,29 +273,21 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) CURLcode ret = CURLE_OUT_OF_MEMORY; struct connectdata *conn = data->conn; size_t len; - const char *tmp0; - const char *tmp1; - char *provider0_low = NULL; - char *provider0_up = NULL; - char *provider1_low = NULL; - char *provider1_mid = NULL; - char *region = NULL; - char *service = NULL; + const char *arg; + char provider0[MAX_SIGV4_LEN + 1]=""; + char provider1[MAX_SIGV4_LEN + 1]=""; + char region[MAX_SIGV4_LEN + 1]=""; + char service[MAX_SIGV4_LEN + 1]=""; const char *hostname = conn->host.name; -#ifdef DEBUGBUILD - char *force_timestamp; -#endif time_t clock; struct tm tm; - char timestamp[17]; + char timestamp[TIMESTAMP_SIZE]; char date[9]; - const char *content_type = Curl_checkheaders(data, STRCONST("Content-Type")); - char *canonical_headers = NULL; - char *signed_headers = NULL; - Curl_HttpReq httpreq; - const char *method; - size_t post_data_len; - const char *post_data = data->set.postfields ? data->set.postfields : ""; + struct dynbuf canonical_headers; + struct dynbuf signed_headers; + char *date_header = NULL; + const char *post_data = data->set.postfields; + size_t post_data_len = 0; unsigned char sha_hash[32]; char sha_hex[65]; char *canonical_request = NULL; @@ -101,10 +295,9 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) char *credential_scope = NULL; char *str_to_sign = NULL; 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}; + unsigned char sign0[32] = {0}; + unsigned char sign1[32] = {0}; char *auth_headers = NULL; DEBUGASSERT(!proxy); @@ -115,6 +308,10 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) return CURLE_OK; } + /* we init thoses buffers here, so goto fail will free initialized dynbuf */ + Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER); + Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER); + /* * Parameters parsing * Google and Outscale use the same OSC or GOOG, @@ -122,223 +319,154 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) * AWS is the default because most of non-amazon providers * are still using aws:amz as a prefix. */ - tmp0 = data->set.str[STRING_AWS_SIGV4] ? + arg = data->set.str[STRING_AWS_SIGV4] ? data->set.str[STRING_AWS_SIGV4] : "aws:amz"; - tmp1 = strchr(tmp0, ':'); - len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0); - if(len < 1) { - infof(data, "first provider can't be empty"); + + /* provider1[:provider2[:region[:service]]] + + No string can be longer than N bytes of non-whitespace + */ + (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "[^:]" + ":%" MAX_SIGV4_LEN_TXT "s", + provider0, provider1, region, service); + if(!provider0[0]) { + failf(data, "first provider can't be empty"); ret = CURLE_BAD_FUNCTION_ARGUMENT; goto fail; } - provider0_low = malloc(len + 1); - provider0_up = malloc(len + 1); - if(!provider0_low || !provider0_up) { - goto fail; - } - Curl_strntolower(provider0_low, tmp0, len); - provider0_low[len] = '\0'; - Curl_strntoupper(provider0_up, tmp0, len); - provider0_up[len] = '\0'; - - if(tmp1) { - tmp0 = tmp1 + 1; - tmp1 = strchr(tmp0, ':'); - len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0); - if(len < 1) { - infof(data, "second provider can't be empty"); - ret = CURLE_BAD_FUNCTION_ARGUMENT; - goto fail; - } - provider1_low = malloc(len + 1); - provider1_mid = malloc(len + 1); - if(!provider1_low || !provider1_mid) { - goto fail; - } - Curl_strntolower(provider1_low, tmp0, len); - provider1_low[len] = '\0'; - Curl_strntolower(provider1_mid, tmp0, len); - provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]); - provider1_mid[len] = '\0'; - - if(tmp1) { - tmp0 = tmp1 + 1; - tmp1 = strchr(tmp0, ':'); - len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0); - if(len < 1) { - infof(data, "region can't be empty"); - ret = CURLE_BAD_FUNCTION_ARGUMENT; - goto fail; - } - region = Curl_memdup(tmp0, len + 1); - if(!region) { - goto fail; - } - region[len] = '\0'; + else if(!provider1[0]) + strcpy(provider1, provider0); - if(tmp1) { - tmp0 = tmp1 + 1; - service = strdup(tmp0); - if(!service) { - goto fail; - } - if(strlen(service) < 1) { - infof(data, "service can't be empty"); - ret = CURLE_BAD_FUNCTION_ARGUMENT; - goto fail; - } - } - } - } - else { - provider1_low = Curl_memdup(provider0_low, len + 1); - provider1_mid = Curl_memdup(provider0_low, len + 1); - if(!provider1_low || !provider1_mid) { - goto fail; - } - provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]); - } - - if(!service) { - tmp0 = hostname; - tmp1 = strchr(tmp0, '.'); - len = tmp1 - tmp0; - if(!tmp1 || len < 1) { - infof(data, "service missing in parameters or hostname"); + if(!service[0]) { + char *hostdot = strchr(hostname, '.'); + if(!hostdot) { + failf(data, "service missing in parameters and hostname"); ret = CURLE_URL_MALFORMAT; goto fail; } - service = Curl_memdup(tmp0, len + 1); - if(!service) { + len = hostdot - hostname; + if(len > MAX_SIGV4_LEN) { + failf(data, "service too long in hostname"); + ret = CURLE_URL_MALFORMAT; goto fail; } + strncpy(service, hostname, len); service[len] = '\0'; - if(!region) { - tmp0 = tmp1 + 1; - tmp1 = strchr(tmp0, '.'); - len = tmp1 - tmp0; - if(!tmp1 || len < 1) { - infof(data, "region missing in parameters or hostname"); + if(!region[0]) { + const char *reg = hostdot + 1; + const char *hostreg = strchr(reg, '.'); + if(!hostreg) { + failf(data, "region missing in parameters and hostname"); ret = CURLE_URL_MALFORMAT; goto fail; } - region = Curl_memdup(tmp0, len + 1); - if(!region) { + len = hostreg - reg; + if(len > MAX_SIGV4_LEN) { + failf(data, "region too long in hostname"); + ret = CURLE_URL_MALFORMAT; goto fail; } + strncpy(region, reg, len); region[len] = '\0'; } } #ifdef DEBUGBUILD - force_timestamp = getenv("CURL_FORCETIME"); - if(force_timestamp) - clock = 0; - else - time(&clock); + { + char *force_timestamp = getenv("CURL_FORCETIME"); + if(force_timestamp) + clock = 0; + else + time(&clock); + } #else time(&clock); #endif ret = Curl_gmtime(clock, &tm); - if(ret != CURLE_OK) { + if(ret) { goto fail; } if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) { + ret = CURLE_OUT_OF_MEMORY; goto fail; } + + ret = make_headers(data, hostname, timestamp, provider1, + &date_header, &canonical_headers, &signed_headers); + if(ret) + goto fail; + ret = CURLE_OUT_OF_MEMORY; + memcpy(date, timestamp, sizeof(date)); date[sizeof(date) - 1] = 0; - if(content_type) { - content_type = strchr(content_type, ':'); - if(!content_type) { - ret = CURLE_FAILED_INIT; - goto fail; - } - content_type++; - /* Skip whitespace now */ - while(*content_type == ' ' || *content_type == '\t') - ++content_type; - - canonical_headers = curl_maprintf("content-type:%s\n" - "host:%s\n" - "x-%s-date:%s\n", - content_type, - hostname, - provider1_low, timestamp); - signed_headers = curl_maprintf("content-type;host;x-%s-date", - provider1_low); - } - else { - canonical_headers = curl_maprintf("host:%s\n" - "x-%s-date:%s\n", - hostname, - provider1_low, timestamp); - signed_headers = curl_maprintf("host;x-%s-date", provider1_low); - } - - if(!canonical_headers || !signed_headers) { - goto fail; + if(post_data) { + if(data->set.postfieldsize < 0) + post_data_len = strlen(post_data); + else + post_data_len = (size_t)data->set.postfieldsize; } - - if(data->set.postfieldsize < 0) - post_data_len = strlen(post_data); - else - post_data_len = (size_t)data->set.postfieldsize; if(Curl_sha256it(sha_hash, (const unsigned char *) post_data, - post_data_len)) { + post_data_len)) goto fail; - } sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); - Curl_http_method(data, conn, &method, &httpreq); - - canonical_request = - curl_maprintf("%s\n" /* HTTPRequestMethod */ - "%s\n" /* CanonicalURI */ - "%s\n" /* CanonicalQueryString */ - "%s\n" /* CanonicalHeaders */ - "%s\n" /* SignedHeaders */ - "%s", /* HashedRequestPayload in hex */ - method, - data->state.up.path, - data->state.up.query ? data->state.up.query : "", - canonical_headers, - signed_headers, - sha_hex); - if(!canonical_request) { - goto fail; + { + Curl_HttpReq httpreq; + const char *method; + + Curl_http_method(data, conn, &method, &httpreq); + + canonical_request = + curl_maprintf("%s\n" /* HTTPRequestMethod */ + "%s\n" /* CanonicalURI */ + "%s\n" /* CanonicalQueryString */ + "%s\n" /* CanonicalHeaders */ + "%s\n" /* SignedHeaders */ + "%s", /* HashedRequestPayload in hex */ + method, + data->state.up.path, + data->state.up.query ? data->state.up.query : "", + Curl_dyn_ptr(&canonical_headers), + Curl_dyn_ptr(&signed_headers), + sha_hex); + if(!canonical_request) + goto fail; } - request_type = curl_maprintf("%s4_request", provider0_low); - if(!request_type) { + /* provider 0 lowercase */ + Curl_strntolower(provider0, provider0, strlen(provider0)); + request_type = curl_maprintf("%s4_request", provider0); + if(!request_type) goto fail; - } credential_scope = curl_maprintf("%s/%s/%s/%s", date, region, service, request_type); - if(!credential_scope) { + if(!credential_scope) goto fail; - } if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request, - strlen(canonical_request))) { + strlen(canonical_request))) goto fail; - } sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); + /* provider 0 uppercase */ + Curl_strntoupper(provider0, provider0, strlen(provider0)); + /* - * Google allow to use rsa key instead of HMAC, so this code might change - * In the future, but for now we support only HMAC version + * Google allows using RSA key instead of HMAC, so this code might change + * in the future. For now we ony support HMAC. */ str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */ "%s\n" /* RequestDateTime */ "%s\n" /* CredentialScope */ "%s", /* HashedCanonicalRequest in hex */ - provider0_up, + provider0, timestamp, credential_scope, sha_hex); @@ -346,36 +474,33 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) goto fail; } - secret = curl_maprintf("%s4%s", provider0_up, passwd); - if(!secret) { + /* provider 0 uppercase */ + secret = curl_maprintf("%s4%s", provider0, + data->state.aptr.passwd ? + data->state.aptr.passwd : ""); + if(!secret) goto fail; - } - HMAC_SHA256(secret, strlen(secret), - date, strlen(date), tmp_sign0); - HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0), - region, strlen(region), tmp_sign1); - HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1), - service, strlen(service), tmp_sign0); - HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0), - request_type, strlen(request_type), tmp_sign1); - HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1), - str_to_sign, strlen(str_to_sign), tmp_sign0); + HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0); + HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1); + HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0); + HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1); + HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0); - sha256_to_hex(sha_hex, tmp_sign0, sizeof(sha_hex)); + sha256_to_hex(sha_hex, sign0, sizeof(sha_hex)); + /* provider 0 uppercase */ auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 " "Credential=%s/%s, " "SignedHeaders=%s, " "Signature=%s\r\n" - "X-%s-Date: %s\r\n", - provider0_up, + "%s\r\n", + provider0, user, credential_scope, - signed_headers, + Curl_dyn_ptr(&signed_headers), sha_hex, - provider1_mid, - timestamp); + date_header); if(!auth_headers) { goto fail; } @@ -386,19 +511,14 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) ret = CURLE_OK; fail: - free(provider0_low); - free(provider0_up); - free(provider1_low); - free(provider1_mid); - free(region); - free(service); - free(canonical_headers); - free(signed_headers); + Curl_dyn_free(&canonical_headers); + Curl_dyn_free(&signed_headers); free(canonical_request); free(request_type); free(credential_scope); free(str_to_sign); free(secret); + free(date_header); return ret; } diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.h b/Utilities/cmcurl/lib/http_aws_sigv4.h index 886b314..85755e9 100644 --- a/Utilities/cmcurl/lib/http_aws_sigv4.h +++ b/Utilities/cmcurl/lib/http_aws_sigv4.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c index 6bafcd9..0b83685 100644 --- a/Utilities/cmcurl/lib/http_chunks.c +++ b/Utilities/cmcurl/lib/http_chunks.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -98,7 +100,7 @@ void Curl_httpchunk_init(struct Curl_easy *data) CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *datap, ssize_t datalen, - ssize_t *wrotep, + ssize_t *wrote, CURLcode *extrap) { CURLcode result = CURLE_OK; @@ -107,7 +109,6 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, struct SingleRequest *k = &data->req; size_t piece; curl_off_t length = (curl_off_t)datalen; - size_t *wrote = (size_t *)wrotep; *wrote = 0; /* nothing's written yet */ @@ -124,7 +125,7 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, while(length) { switch(ch->state) { case CHUNK_HEX: - if(isxdigit_ascii(*datap)) { + if(ISXDIGIT(*datap)) { if(ch->hexindex < CHUNK_MAXNUM_LEN) { ch->hexbuffer[ch->hexindex] = *datap; datap++; diff --git a/Utilities/cmcurl/lib/http_chunks.h b/Utilities/cmcurl/lib/http_chunks.h index 741a9a3..2cf5507 100644 --- a/Utilities/cmcurl/lib/http_chunks.h +++ b/Utilities/cmcurl/lib/http_chunks.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ struct connectdata; diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c index 34bb5a8..a71c6b7 100644 --- a/Utilities/cmcurl/lib/http_digest.c +++ b/Utilities/cmcurl/lib/http_digest.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -56,11 +58,11 @@ CURLcode Curl_input_digest(struct Curl_easy *data, digest = &data->state.digest; } - if(!checkprefix("Digest", header) || !ISSPACE(header[6])) + if(!checkprefix("Digest", header) || !ISBLANK(header[6])) return CURLE_BAD_CONTENT_ENCODING; header += strlen("Digest"); - while(*header && ISSPACE(*header)) + while(*header && ISBLANK(*header)) header++; return Curl_auth_decode_digest_http_message(header, digest); diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h index 89438d1..eea90b7 100644 --- a/Utilities/cmcurl/lib/http_digest.h +++ b/Utilities/cmcurl/lib/http_digest.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c index 888d3b2..5909f85 100644 --- a/Utilities/cmcurl/lib/http_negotiate.c +++ b/Utilities/cmcurl/lib/http_negotiate.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -82,7 +84,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, /* Obtain the input token, if any */ header += strlen("Negotiate"); - while(*header && ISSPACE(*header)) + while(*header && ISBLANK(*header)) header++; len = strlen(header); diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h index 2640a3e..6e2096c 100644 --- a/Utilities/cmcurl/lib/http_negotiate.h +++ b/Utilities/cmcurl/lib/http_negotiate.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c index bb7e536..5a6a977 100644 --- a/Utilities/cmcurl/lib/http_ntlm.c +++ b/Utilities/cmcurl/lib/http_ntlm.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -27,7 +29,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ diff --git a/Utilities/cmcurl/lib/http_ntlm.h b/Utilities/cmcurl/lib/http_ntlm.h index 5b4fa00..cec63b8 100644 --- a/Utilities/cmcurl/lib/http_ntlm.h +++ b/Utilities/cmcurl/lib/http_ntlm.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index ed08193..cc20b3a 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -210,10 +212,8 @@ void Curl_connect_done(struct Curl_easy *data) Curl_dyn_free(&s->rcvbuf); Curl_dyn_free(&s->req); - /* restore the protocol pointer, if not already done */ - if(s->prot_save) - data->req.p.http = s->prot_save; - s->prot_save = NULL; + /* restore the protocol pointer */ + data->req.p.http = s->prot_save; data->info.httpcode = 0; /* clear it as it might've been used for the proxy */ data->req.ignorebody = FALSE; @@ -391,8 +391,8 @@ static CURLcode CONNECT(struct Curl_easy *data, if(!result) /* send to debug callback! */ - result = Curl_debug(data, CURLINFO_HEADER_OUT, - k->upload_fromhere, bytes_written); + Curl_debug(data, CURLINFO_HEADER_OUT, + k->upload_fromhere, bytes_written); s->nsend -= bytes_written; k->upload_fromhere += bytes_written; diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h index 67543b5..1e650ee 100644 --- a/Utilities/cmcurl/lib/http_proxy.h +++ b/Utilities/cmcurl/lib/http_proxy.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/idn_win32.c b/Utilities/cmcurl/lib/idn_win32.c index 0914e1f..2433d92 100644 --- a/Utilities/cmcurl/lib/idn_win32.c +++ b/Utilities/cmcurl/lib/idn_win32.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -65,10 +67,10 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags, #define IDN_MAX_LENGTH 255 -bool curl_win32_idn_to_ascii(const char *in, char **out); -bool curl_win32_ascii_to_idn(const char *in, char **out); +bool Curl_win32_idn_to_ascii(const char *in, char **out); +bool Curl_win32_ascii_to_idn(const char *in, char **out); -bool curl_win32_idn_to_ascii(const char *in, char **out) +bool Curl_win32_idn_to_ascii(const char *in, char **out) { bool success = FALSE; @@ -91,7 +93,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out) return success; } -bool curl_win32_ascii_to_idn(const char *in, char **out) +bool Curl_win32_ascii_to_idn(const char *in, char **out) { bool success = FALSE; diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c index 1d34531..c291948 100644 --- a/Utilities/cmcurl/lib/if2ip.c +++ b/Utilities/cmcurl/lib/if2ip.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/if2ip.h b/Utilities/cmcurl/lib/if2ip.h index a360d4a..5d15459 100644 --- a/Utilities/cmcurl/lib/if2ip.h +++ b/Utilities/cmcurl/lib/if2ip.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c index 817513b..ffa08bf 100644 --- a/Utilities/cmcurl/lib/imap.c +++ b/Utilities/cmcurl/lib/imap.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC2195 CRAM-MD5 authentication * RFC2595 Using TLS with IMAP, POP3 and ACAP * RFC2831 DIGEST-MD5 authentication @@ -81,6 +83,7 @@ #include "bufref.h" #include "curl_sasl.h" #include "warnless.h" +#include "curl_ctype.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -1883,22 +1886,17 @@ static char *imap_atom(const char *str, bool escape_only) */ static bool imap_is_bchar(char ch) { + /* Performing the alnum check with this macro is faster because of ASCII + arithmetic */ + if(ISALNUM(ch)) + return true; + switch(ch) { /* bchar */ case ':': case '@': case '/': /* bchar -> achar */ case '&': case '=': - /* bchar -> achar -> uchar -> unreserved */ - case '0': case '1': case '2': case '3': case '4': case '5': case '6': - case '7': case '8': case '9': - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': - case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': - case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': - case 'V': case 'W': case 'X': case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': - case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': - case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': - case 'v': case 'w': case 'x': case 'y': case 'z': + /* bchar -> achar -> uchar -> unreserved (without alphanumeric) */ case '-': case '.': case '_': case '~': /* bchar -> achar -> uchar -> sub-delims-sh */ case '!': case '$': case '\'': case '(': case ')': case '*': diff --git a/Utilities/cmcurl/lib/imap.h b/Utilities/cmcurl/lib/imap.h index ef6515d..43cc1e9 100644 --- a/Utilities/cmcurl/lib/imap.h +++ b/Utilities/cmcurl/lib/imap.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "pingpong.h" diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c index b5f9b80..024f8da 100644 --- a/Utilities/cmcurl/lib/inet_ntop.c +++ b/Utilities/cmcurl/lib/inet_ntop.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1996-2021 Internet Software Consortium. + * Copyright (C) 1996-2022 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 @@ -13,6 +13,8 @@ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * SPDX-License-Identifier: ISC */ /* * Original code by Paul Vixie. "curlified" by Gisle Vanem. diff --git a/Utilities/cmcurl/lib/inet_ntop.h b/Utilities/cmcurl/lib/inet_ntop.h index 067632a..18fbd8b 100644 --- a/Utilities/cmcurl/lib/inet_ntop.h +++ b/Utilities/cmcurl/lib/inet_ntop.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c index ada57af..47fb778 100644 --- a/Utilities/cmcurl/lib/inet_pton.c +++ b/Utilities/cmcurl/lib/inet_pton.c @@ -1,6 +1,6 @@ /* This is from the BIND 4.9.4 release, modified to compile by itself */ -/* Copyright (c) 1996 - 2021 by Internet Software Consortium. +/* Copyright (c) 2003 - 2022 by 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 @@ -14,6 +14,8 @@ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. + * + * SPDX-License-Identifier: ISC */ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/inet_pton.h b/Utilities/cmcurl/lib/inet_pton.h index ec12373..92ae93e 100644 --- a/Utilities/cmcurl/lib/inet_pton.h +++ b/Utilities/cmcurl/lib/inet_pton.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c index dee94c9..1c993c1 100644 --- a/Utilities/cmcurl/lib/krb5.c +++ b/Utilities/cmcurl/lib/krb5.c @@ -5,6 +5,8 @@ * Copyright (c) 2004 - 2022 Daniel Stenberg * All rights reserved. * + * SPDX-License-Identifier: BSD-3-Clause + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -140,11 +142,8 @@ krb5_decode(void *app_data, void *buf, int len, enc.value = buf; enc.length = len; maj = gss_unwrap(&min, *context, &enc, &dec, NULL, NULL); - if(maj != GSS_S_COMPLETE) { - if(len >= 4) - strcpy(buf, "599 "); + if(maj != GSS_S_COMPLETE) return -1; - } memcpy(buf, dec.value, dec.length); len = curlx_uztosi(dec.length); @@ -506,6 +505,7 @@ static CURLcode read_data(struct connectdata *conn, { int len; CURLcode result; + int nread; result = socket_read(fd, &len, sizeof(len)); if(result) @@ -514,7 +514,10 @@ static CURLcode read_data(struct connectdata *conn, if(len) { /* only realloc if there was a length */ len = ntohl(len); - buf->data = Curl_saferealloc(buf->data, len); + if(len > CURL_MAX_INPUT_LENGTH) + len = 0; + else + buf->data = Curl_saferealloc(buf->data, len); } if(!len || !buf->data) return CURLE_OUT_OF_MEMORY; @@ -522,8 +525,11 @@ static CURLcode read_data(struct connectdata *conn, result = socket_read(fd, buf->data, len); if(result) return result; - buf->size = conn->mech->decode(conn->app_data, buf->data, len, - conn->data_prot, conn); + nread = conn->mech->decode(conn->app_data, buf->data, len, + conn->data_prot, conn); + if(nread < 0) + return CURLE_RECV_ERROR; + buf->size = (size_t)nread; buf->index = 0; return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c index 03ea14e..b073349 100644 --- a/Utilities/cmcurl/lib/ldap.c +++ b/Utilities/cmcurl/lib/ldap.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -35,6 +37,18 @@ * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ +/* Wincrypt must be included before anything that could include OpenSSL. */ +#if defined(USE_WIN32_CRYPTO) +#include <wincrypt.h> +/* Undefine wincrypt conflicting symbols for BoringSSL. */ +#undef X509_NAME +#undef X509_EXTENSIONS +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#undef OCSP_REQUEST +#undef OCSP_RESPONSE +#endif + #ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ # include <winldap.h> # ifndef LDAP_VENDOR_NAME @@ -342,7 +356,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #ifdef HAVE_LDAP_SSL #ifdef USE_WIN32_LDAP /* Win32 LDAP SDK doesn't support insecure mode without CA! */ - server = ldap_sslinit(host, (int)conn->port, 1); + server = ldap_sslinit(host, conn->port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; @@ -388,9 +402,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldapssl_init(host, (int)conn->port, 1); + server = ldapssl_init(host, conn->port, 1); if(!server) { - failf(data, "LDAP local: Cannot connect to %s:%ld", + failf(data, "LDAP local: Cannot connect to %s:%u", conn->host.dispname, conn->port); result = CURLE_COULDNT_CONNECT; goto quit; @@ -429,9 +443,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldap_init(host, (int)conn->port); + server = ldap_init(host, conn->port); if(!server) { - failf(data, "LDAP local: Cannot connect to %s:%ld", + failf(data, "LDAP local: Cannot connect to %s:%u", conn->host.dispname, conn->port); result = CURLE_COULDNT_CONNECT; goto quit; @@ -470,9 +484,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } else { - server = ldap_init(host, (int)conn->port); + server = ldap_init(host, conn->port); if(!server) { - failf(data, "LDAP local: Cannot connect to %s:%ld", + failf(data, "LDAP local: Cannot connect to %s:%u", conn->host.dispname, conn->port); result = CURLE_COULDNT_CONNECT; goto quit; diff --git a/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc index fde6c8c..23134a7 100644 --- a/Utilities/cmcurl/lib/libcurl.rc +++ b/Utilities/cmcurl/lib/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <winver.h> #include "../include/curl/curlver.h" diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c index e78da7d..fa2d366 100644 --- a/Utilities/cmcurl/lib/llist.c +++ b/Utilities/cmcurl/lib/llist.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/llist.h b/Utilities/cmcurl/lib/llist.h index ceae2dd..2fcb91c 100644 --- a/Utilities/cmcurl/lib/llist.h +++ b/Utilities/cmcurl/lib/llist.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c index 117cce4..e976fe7 100644 --- a/Utilities/cmcurl/lib/md4.c +++ b/Utilities/cmcurl/lib/md4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -30,7 +32,8 @@ #ifdef USE_OPENSSL #include <openssl/opensslconf.h> -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) && \ + !defined(USE_AMISSL) /* OpenSSL 3.0.0 marks the MD4 functions as deprecated */ #define OPENSSL_NO_MD4 #endif @@ -39,7 +42,7 @@ #ifdef USE_WOLFSSL #include <wolfssl/options.h> #ifdef NO_MD4 -#define OPENSSL_NO_MD4 +#define WOLFSSL_NO_MD4 #endif #endif @@ -82,9 +85,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) md4_digest(ctx, MD4_DIGEST_SIZE, result); } -#elif (defined(USE_OPENSSL) || defined(USE_WOLFSSL)) && \ - !defined(OPENSSL_NO_MD4) /* When OpenSSL or wolfSSL is available, we use their MD4 functions. */ +#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) +#include <wolfssl/openssl/md4.h> + +#elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) #include <openssl/md4.h> #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c index d2ca240..5be6399 100644 --- a/Utilities/cmcurl/lib/md5.c +++ b/Utilities/cmcurl/lib/md5.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -39,7 +41,7 @@ #endif #endif /* USE_MBEDTLS */ -#if defined(USE_OPENSSL) && !defined(USE_AMISSL) +#ifdef USE_OPENSSL #include <openssl/opensslconf.h> #if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_DEPRECATED_3_0) #define USE_OPENSSL_MD5 diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c index 050c5d4..15fb491 100644 --- a/Utilities/cmcurl/lib/memdebug.c +++ b/Utilities/cmcurl/lib/memdebug.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -127,7 +129,8 @@ static bool countcheck(const char *func, int line, const char *source) return FALSE; /* allow this */ } -void *curl_dbg_malloc(size_t wantedsize, int line, const char *source) +ALLOC_FUNC void *curl_dbg_malloc(size_t wantedsize, + int line, const char *source) { struct memdebug *mem; size_t size; @@ -153,8 +156,8 @@ void *curl_dbg_malloc(size_t wantedsize, int line, const char *source) return (mem ? mem->mem : NULL); } -void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size, - int line, const char *source) +ALLOC_FUNC void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size, + int line, const char *source) { struct memdebug *mem; size_t size, user_size; @@ -181,7 +184,8 @@ void *curl_dbg_calloc(size_t wanted_elements, size_t wanted_size, return (mem ? mem->mem : NULL); } -char *curl_dbg_strdup(const char *str, int line, const char *source) +ALLOC_FUNC char *curl_dbg_strdup(const char *str, + int line, const char *source) { char *mem; size_t len; @@ -205,7 +209,8 @@ char *curl_dbg_strdup(const char *str, int line, const char *source) } #if defined(WIN32) && defined(UNICODE) -wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source) +ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str, + int line, const char *source) { wchar_t *mem; size_t wsiz, bsiz; @@ -408,8 +413,8 @@ int curl_dbg_sclose(curl_socket_t sockfd, int line, const char *source) return res; } -FILE *curl_dbg_fopen(const char *file, const char *mode, - int line, const char *source) +ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, + int line, const char *source) { FILE *res = fopen(file, mode); @@ -420,8 +425,8 @@ FILE *curl_dbg_fopen(const char *file, const char *mode, return res; } -FILE *curl_dbg_fdopen(int filedes, const char *mode, - int line, const char *source) +ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, + int line, const char *source) { FILE *res = fdopen(filedes, mode); if(source) diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h index 8e88cea..7fc90e8 100644 --- a/Utilities/cmcurl/lib/memdebug.h +++ b/Utilities/cmcurl/lib/memdebug.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -28,21 +30,44 @@ * as well as the library. Do not mix with library internals! */ +#include <curl/curl.h> +#include "functypes.h" + +#if defined(__GNUC__) && __GNUC__ >= 3 +# define ALLOC_FUNC __attribute__((malloc)) +# define ALLOC_SIZE(s) __attribute__((alloc_size(s))) +# define ALLOC_SIZE2(n, s) __attribute__((alloc_size(n, s))) +#elif defined(_MSC_VER) +# define ALLOC_FUNC __declspec(restrict) +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +#else +# define ALLOC_FUNC +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +#endif + #define CURL_MT_LOGFNAME_BUFSIZE 512 extern FILE *curl_dbg_logfile; /* memory functions */ -CURL_EXTERN void *curl_dbg_malloc(size_t size, int line, const char *source); -CURL_EXTERN void *curl_dbg_calloc(size_t elements, size_t size, int line, - const char *source); -CURL_EXTERN void *curl_dbg_realloc(void *ptr, size_t size, int line, - const char *source); +CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1) void *curl_dbg_malloc(size_t size, + int line, + const char *source); +CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2) void *curl_dbg_calloc(size_t elements, + size_t size, int line, const char *source); +CURL_EXTERN ALLOC_SIZE(2) void *curl_dbg_realloc(void *ptr, + size_t size, + int line, + const char *source); CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source); -CURL_EXTERN char *curl_dbg_strdup(const char *str, int line, const char *src); +CURL_EXTERN ALLOC_FUNC char *curl_dbg_strdup(const char *str, int line, + const char *src); #if defined(WIN32) && defined(UNICODE) -CURL_EXTERN wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, - const char *source); +CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str, + int line, + const char *source); #endif CURL_EXTERN void curl_dbg_memdebug(const char *logname); @@ -77,10 +102,10 @@ CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, const char *source); /* FILE functions */ -CURL_EXTERN FILE *curl_dbg_fopen(const char *file, const char *mode, int line, - const char *source); -CURL_EXTERN FILE *curl_dbg_fdopen(int filedes, const char *mode, +CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fopen(const char *file, const char *mode, int line, const char *source); +CURL_EXTERN ALLOC_FUNC FILE *curl_dbg_fdopen(int filedes, const char *mode, + int line, const char *source); CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source); diff --git a/Utilities/cmcurl/lib/mime.c b/Utilities/cmcurl/lib/mime.c index d6985d3..042141f 100644 --- a/Utilities/cmcurl/lib/mime.c +++ b/Utilities/cmcurl/lib/mime.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -29,8 +31,9 @@ #include "urldata.h" #include "sendf.h" -#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ - !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) +#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include <libgen.h> @@ -1922,8 +1925,8 @@ void Curl_mime_unpause(curl_mimepart *part) } -#else /* !CURL_DISABLE_HTTP && !CURL_DISABLE_MIME || - !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ +#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP || + !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */ /* Mime not compiled in: define stubs for externally-referenced functions. */ curl_mime *curl_mime_init(CURL *easy) diff --git a/Utilities/cmcurl/lib/mime.h b/Utilities/cmcurl/lib/mime.h index f2fc434..bafde29 100644 --- a/Utilities/cmcurl/lib/mime.h +++ b/Utilities/cmcurl/lib/mime.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -132,8 +134,9 @@ struct curl_mimepart { CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); -#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ - !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) +#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) /* Prototypes. */ void Curl_mime_initpart(struct curl_mimepart *part, struct Curl_easy *easy); diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c index 1381201..8a7c17a 100644 --- a/Utilities/cmcurl/lib/mprintf.c +++ b/Utilities/cmcurl/lib/mprintf.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * * Purpose: * A merge of Bjorn Reese's format() function and Daniel's dsprintf() @@ -316,6 +318,11 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto, flags |= FLAGS_PREC; precision = strtol(fmt, &fmt, 10); } + if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) == + (FLAGS_PREC | FLAGS_PRECPARAM)) + /* it is not permitted to use both kinds of precision for the same + argument */ + return 1; break; case 'h': flags |= FLAGS_SHORT; @@ -592,7 +599,7 @@ static int dprintf_formatf( /* Do the actual %-code parsing */ if(dprintf_Pass1(format, vto, endpos, ap_save)) - return -1; + return 0; end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() created for us */ @@ -954,11 +961,22 @@ static int dprintf_formatf( else *fptr++ = 'f'; - *fptr = 0; /* and a final zero termination */ + *fptr = 0; /* and a final null-termination */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#endif /* NOTE NOTE NOTE!! Not all sprintf implementations return number of output characters */ +#ifdef HAVE_SNPRINTF + (snprintf)(work, sizeof(work), formatbuf, p->data.dnum); +#else (sprintf)(work, formatbuf, p->data.dnum); +#endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif DEBUGASSERT(strlen(work) <= sizeof(work)); for(fptr = work; *fptr; fptr++) OUTCHAR(*fptr); @@ -1016,11 +1034,12 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, info.max = maxlength; retcode = dprintf_formatf(&info, addbyter, format, ap_save); - if((retcode != -1) && info.max) { + if(info.max) { /* we terminate this with a zero byte */ if(info.max == info.length) { /* we're at maximum, scrap the last letter */ info.buffer[-1] = 0; + DEBUGASSERT(retcode); retcode--; /* don't count the nul byte */ } else @@ -1058,13 +1077,12 @@ extern int Curl_dyn_vprintf(struct dynbuf *dyn, /* appends the formatted string, returns 0 on success, 1 on error */ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save) { - int retcode; struct asprintf info; info.b = dyn; info.fail = 0; - retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); - if((-1 == retcode) || info.fail) { + (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save); + if(info.fail) { Curl_dyn_free(info.b); return 1; } @@ -1073,15 +1091,14 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save) char *curl_mvaprintf(const char *format, va_list ap_save) { - int retcode; struct asprintf info; struct dynbuf dyn; info.b = &dyn; Curl_dyn_init(info.b, DYN_APRINTF); info.fail = 0; - retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save); - if((-1 == retcode) || info.fail) { + (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save); + if(info.fail) { Curl_dyn_free(info.b); return NULL; } diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c index 9bcbaa1..4f3d143 100644 --- a/Utilities/cmcurl/lib/mqtt.c +++ b/Utilities/cmcurl/lib/mqtt.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -184,7 +186,7 @@ static int add_passwd(const char *passwd, const size_t plen, return 0; } -/* add user to the CONN packet */ +/* add user to the CONNECT packet */ static int add_user(const char *username, const size_t ulen, unsigned char *pkt, const size_t start, int remain_pos) { @@ -202,7 +204,7 @@ static int add_user(const char *username, const size_t ulen, return 0; } -/* add client ID to the CONN packet */ +/* add client ID to the CONNECT packet */ static int add_client_id(const char *client_id, const size_t client_id_len, char *pkt, const size_t start) { @@ -214,7 +216,7 @@ static int add_client_id(const char *client_id, const size_t client_id_len, return 0; } -/* Set initial values of CONN packet */ +/* Set initial values of CONNECT packet */ static int init_connpack(char *packet, char *remain, int remain_pos) { /* Fixed header starts */ @@ -291,7 +293,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data) return CURLE_OUT_OF_MEMORY; memset(packet, 0, packetlen); - /* set initial values for CONN pack */ + /* set initial values for the CONNECT packet */ pos = init_connpack(packet, remain, remain_pos); result = Curl_rand_hex(data, (unsigned char *)&client_id[clen], @@ -387,10 +389,18 @@ static CURLcode mqtt_get_topic(struct Curl_easy *data, char **topic, size_t *topiclen) { char *path = data->state.up.path; - if(strlen(path) > 1) - return Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA); - failf(data, "No MQTT topic found. Forgot to URL encode it?"); - return CURLE_URL_MALFORMAT; + CURLcode result = CURLE_URL_MALFORMAT; + if(strlen(path) > 1) { + result = Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA); + if(!result && (*topiclen > 0xffff)) { + failf(data, "Too long MQTT topic"); + result = CURLE_URL_MALFORMAT; + } + } + else + failf(data, "No MQTT topic found. Forgot to URL encode it?"); + + return result; } static CURLcode mqtt_subscribe(struct Curl_easy *data) @@ -688,7 +698,7 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done) result = mqtt_connect(data); if(result) { - failf(data, "Error %d sending MQTT CONN request", result); + failf(data, "Error %d sending MQTT CONNECT request", result); return result; } mqstate(data, MQTT_FIRST, MQTT_CONNACK); diff --git a/Utilities/cmcurl/lib/mqtt.h b/Utilities/cmcurl/lib/mqtt.h index fb52c72..c400d9b 100644 --- a/Utilities/cmcurl/lib/mqtt.h +++ b/Utilities/cmcurl/lib/mqtt.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2020, Björn Stenberg, <bjorn@haxx.se> + * Copyright (C) 2019 - 2022, Björn Stenberg, <bjorn@haxx.se> * * 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_MQTT diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index 8e58d78..51acba7 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -43,7 +45,6 @@ #include "multihandle.h" #include "sigpipe.h" #include "vtls/vtls.h" -#include "connect.h" #include "http_proxy.h" #include "http2.h" #include "socketpair.h" @@ -53,6 +54,22 @@ #include "curl_memory.h" #include "memdebug.h" +#ifdef __APPLE__ + +#define wakeup_write write +#define wakeup_read read +#define wakeup_close close +#define wakeup_create pipe + +#else /* __APPLE__ */ + +#define wakeup_write swrite +#define wakeup_read sread +#define wakeup_close sclose +#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p) + +#endif /* __APPLE__ */ + /* CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97 to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every @@ -66,6 +83,10 @@ #define CURL_CONNECTION_HASH_SIZE 97 #endif +#ifndef CURL_DNS_HASH_SIZE +#define CURL_DNS_HASH_SIZE 71 +#endif + #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ @@ -370,7 +391,8 @@ static CURLMcode multi_addmsg(struct Curl_multi *multi, } struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ - int chashsize) /* connection hash */ + int chashsize, /* connection hash */ + int dnssize) /* dns hash */ { struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi)); @@ -379,7 +401,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ multi->magic = CURL_MULTI_HANDLE; - Curl_init_dnscache(&multi->hostcache); + Curl_init_dnscache(&multi->hostcache, dnssize); sh_init(&multi->sockhash, hashsize); @@ -394,7 +416,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; multi->max_concurrent_streams = 100; - multi->ipv6_works = Curl_ipv6works(NULL); #ifdef USE_WINSOCK multi->wsa_event = WSACreateEvent(); @@ -402,14 +423,14 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ goto error; #else #ifdef ENABLE_WAKEUP - if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) { + if(wakeup_create(multi->wakeup_pair) < 0) { multi->wakeup_pair[0] = CURL_SOCKET_BAD; multi->wakeup_pair[1] = CURL_SOCKET_BAD; } else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 || curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) { - sclose(multi->wakeup_pair[0]); - sclose(multi->wakeup_pair[1]); + wakeup_close(multi->wakeup_pair[0]); + wakeup_close(multi->wakeup_pair[1]); multi->wakeup_pair[0] = CURL_SOCKET_BAD; multi->wakeup_pair[1] = CURL_SOCKET_BAD; } @@ -433,7 +454,8 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ struct Curl_multi *curl_multi_init(void) { return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, - CURL_CONNECTION_HASH_SIZE); + CURL_CONNECTION_HASH_SIZE, + CURL_DNS_HASH_SIZE); } CURLMcode curl_multi_add_handle(struct Curl_multi *multi, @@ -627,7 +649,7 @@ static CURLcode multi_done(struct Curl_easy *data, if(CURLE_ABORTED_BY_CALLBACK != result) { /* avoid this if we already aborted by callback to avoid this calling another callback */ - CURLcode rc = Curl_pgrsDone(data); + int rc = Curl_pgrsDone(data); if(!result && rc) result = CURLE_ABORTED_BY_CALLBACK; } @@ -729,7 +751,7 @@ static int close_connect_only(struct Curl_easy *data, if(data->state.lastconnect_id != conn->connection_id) return 0; - if(!conn->bits.connect_only) + if(!conn->connect_only) return 1; connclose(conn, "Removing connect-only easy handle"); @@ -826,6 +848,24 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, /* Remove the association between the connection and the handle */ Curl_detach_connection(data); + if(data->set.connect_only && !data->multi_easy) { + /* This removes a handle that was part the multi interface that used + CONNECT_ONLY, that connection is now left alive but since this handle + has bits.close set nothing can use that transfer anymore and it is + forbidden from reuse. And this easy handle cannot find the connection + anymore once removed from the multi handle + + Better close the connection here, at once. + */ + struct connectdata *c; + curl_socket_t s; + s = Curl_getconnectinfo(data, &c); + if((s != CURL_SOCKET_BAD) && c) { + Curl_conncache_remove_conn(data, c, TRUE); + Curl_disconnect(data, c, TRUE); + } + } + if(data->state.lastconnect_id != -1) { /* Mark any connect-only connection for closure */ Curl_conncache_foreach(data, data->state.conn_cache, @@ -1307,16 +1347,19 @@ static CURLMcode multi_wait(struct Curl_multi *multi, 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) + return CURLM_UNRECOVERABLE_POLL; if(pollrc > 0) { retcode = pollrc; #ifdef USE_WINSOCK } + else { /* now wait... if not ready during the pre-check (pollrc == 0) */ + WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE); + } /* With WinSock, we have to run the following section unconditionally to call WSAEventSelect(fd, event, 0) on all the sockets */ { @@ -1328,20 +1371,23 @@ static CURLMcode multi_wait(struct Curl_multi *multi, unsigned r = ufds[curlfds + i].revents; unsigned short mask = 0; #ifdef USE_WINSOCK + curl_socket_t s = extra_fds[i].fd; wsa_events.lNetworkEvents = 0; - if(WSAEnumNetworkEvents(extra_fds[i].fd, NULL, &wsa_events) == 0) { + if(WSAEnumNetworkEvents(s, 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) + if(ret && !pollrc && wsa_events.lNetworkEvents) retcode++; } - WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0); - if(pollrc <= 0) + WSAEventSelect(s, multi->wsa_event, 0); + if(!pollrc) { + extra_fds[i].revents = mask; continue; + } #endif if(r & POLLIN) mask |= CURL_WAIT_POLLIN; @@ -1364,7 +1410,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, 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) + if(ret && !pollrc && wsa_events.lNetworkEvents) retcode++; } WSAEventSelect(sockbunch[i], multi->wsa_event, 0); @@ -1391,7 +1437,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, data from it until it receives an error (except EINTR). In normal cases it will get EAGAIN or EWOULDBLOCK when there is no more data, breaking the loop. */ - nread = sread(multi->wakeup_pair[0], buf, sizeof(buf)); + nread = wakeup_read(multi->wakeup_pair[0], buf, sizeof(buf)); if(nread <= 0) { if(nread < 0 && EINTR == SOCKERRNO) continue; @@ -1484,7 +1530,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi) that will call curl_multi_wait(). If swrite() returns that it would block, it's considered successful because it means that previous calls to this function will wake up the poll(). */ - if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) { + if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) { int err = SOCKERRNO; int return_success; #ifdef USE_WINSOCK @@ -2096,7 +2142,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } } - if(data->set.connect_only) { + if(data->set.connect_only == 1) { /* keep connection open for application to use the socket */ connkeep(data->conn, "CONNECT_ONLY"); multistate(data, MSTATE_DONE); @@ -2720,8 +2766,8 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) WSACloseEvent(multi->wsa_event); #else #ifdef ENABLE_WAKEUP - sclose(multi->wakeup_pair[0]); - sclose(multi->wakeup_pair[1]); + wakeup_close(multi->wakeup_pair[0]); + wakeup_close(multi->wakeup_pair[1]); #endif #endif free(multi); diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h index db7f130..a997784 100644 --- a/Utilities/cmcurl/lib/multihandle.h +++ b/Utilities/cmcurl/lib/multihandle.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "llist.h" @@ -148,11 +150,13 @@ struct Curl_multi { 0 is used for read, 1 is used for write */ #endif #endif - /* multiplexing wanted */ - bool multiplexing; - bool recheckstate; /* see Curl_multi_connchanged */ +#define IPV6_UNKNOWN 0 +#define IPV6_DEAD 1 +#define IPV6_WORKS 2 + unsigned char ipv6_up; /* IPV6_* defined */ + bool multiplexing; /* multiplexing wanted */ + bool recheckstate; /* see Curl_multi_connchanged */ bool in_callback; /* true while executing a callback */ - bool ipv6_works; #ifdef USE_OPENSSL bool ssl_seeded; #endif diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h index 5a8c358..0cb9d4f 100644 --- a/Utilities/cmcurl/lib/multiif.h +++ b/Utilities/cmcurl/lib/multiif.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -40,8 +42,9 @@ bool Curl_is_in_callback(struct Curl_easy *easy); CURLcode Curl_preconnect(struct Curl_easy *data); /* Internal version of curl_multi_init() accepts size parameters for the - socket and connection hashes */ -struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); + socket, connection and dns hashes */ +struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize, + int dnssize); /* the write bits start at bit 16 for the *getsock() bitmap */ #define GETSOCK_WRITEBITSTART 16 diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c index 0a4ae2c..4461b84 100644 --- a/Utilities/cmcurl/lib/netrc.c +++ b/Utilities/cmcurl/lib/netrc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -31,6 +33,7 @@ #include "netrc.h" #include "strtok.h" #include "strcase.h" +#include "curl_get_line.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -56,8 +59,6 @@ enum host_lookup_state { static int parsenetrc(const char *host, char **loginp, char **passwordp, - bool *login_changed, - bool *password_changed, char *netrcfile) { FILE *file; @@ -71,31 +72,87 @@ static int parsenetrc(const char *host, char state_login = 0; /* Found a login keyword */ char state_password = 0; /* Found a password keyword */ - int state_our_login = FALSE; /* With specific_login, found *our* login - name */ + int state_our_login = TRUE; /* With specific_login, found *our* login + name (or login-less line) */ DEBUGASSERT(netrcfile); file = fopen(netrcfile, FOPEN_READTEXT); if(file) { - char *tok; - char *tok_buf; bool done = FALSE; char netrcbuffer[4096]; int netrcbuffsize = (int)sizeof(netrcbuffer); - while(!done && fgets(netrcbuffer, netrcbuffsize, file)) { + while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) { + char *tok; + char *tok_end; + bool quoted; 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; + tok = netrcbuffer; while(tok) { + while(ISBLANK(*tok)) + tok++; + /* tok is first non-space letter */ + if(!*tok || (*tok == '#')) + /* end of line or the rest is a comment */ + break; + + /* leading double-quote means quoted string */ + quoted = (*tok == '\"'); + + tok_end = tok; + if(!quoted) { + while(!ISSPACE(*tok_end)) + tok_end++; + *tok_end = 0; + } + else { + bool escape = FALSE; + bool endquote = FALSE; + char *store = tok; + tok_end++; /* pass the leading quote */ + while(*tok_end) { + char s = *tok_end; + if(escape) { + escape = FALSE; + switch(s) { + case 'n': + s = '\n'; + break; + case 'r': + s = '\r'; + break; + case 't': + s = '\t'; + break; + } + } + else if(s == '\\') { + escape = TRUE; + tok_end++; + continue; + } + else if(s == '\"') { + tok_end++; /* pass the ending quote */ + endquote = TRUE; + break; + } + *store++ = s; + tok_end++; + } + *store = 0; + if(escape || !endquote) { + /* bad syntax, get out */ + retcode = NETRC_FAILED; + goto out; + } + } + if((login && *login) && (password && *password)) { done = TRUE; break; @@ -140,9 +197,9 @@ static int parsenetrc(const char *host, /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { - state_our_login = strcasecompare(login, tok); + state_our_login = !Curl_timestrcmp(login, tok); } - else if(!login || strcmp(login, tok)) { + else if(!login || Curl_timestrcmp(login, tok)) { if(login_alloc) { free(login); login_alloc = FALSE; @@ -158,7 +215,7 @@ static int parsenetrc(const char *host, } else if(state_password) { if((state_our_login || !specific_login) - && (!password || strcmp(password, tok))) { + && (!password || Curl_timestrcmp(password, tok))) { if(password_alloc) { free(password); password_alloc = FALSE; @@ -183,27 +240,22 @@ static int parsenetrc(const char *host, } break; } /* switch (state) */ - - tok = strtok_r(NULL, " \t\n", &tok_buf); - } /* while(tok) */ - } /* while fgets() */ + tok = ++tok_end; + } + } /* while Curl_get_line() */ out: if(!retcode) { /* success */ - *login_changed = FALSE; - *password_changed = FALSE; if(login_alloc) { if(*loginp) free(*loginp); *loginp = login; - *login_changed = TRUE; } if(password_alloc) { if(*passwordp) free(*passwordp); *passwordp = password; - *password_changed = TRUE; } } else { @@ -224,17 +276,16 @@ static int parsenetrc(const char *host, * *loginp and *passwordp MUST be allocated if they aren't NULL when passed * in. */ -int Curl_parsenetrc(const char *host, - char **loginp, - char **passwordp, - bool *login_changed, - bool *password_changed, +int Curl_parsenetrc(const char *host, char **loginp, char **passwordp, char *netrcfile) { int retcode = 1; char *filealloc = NULL; if(!netrcfile) { +#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) + char pwbuf[1024]; +#endif char *home = NULL; char *homea = curl_getenv("HOME"); /* portable environment reader */ if(homea) { @@ -243,7 +294,6 @@ int Curl_parsenetrc(const char *host, } else { struct passwd pw, *pw_res; - char pwbuf[1024]; if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) && pw_res) { home = pw.pw_dir; @@ -256,6 +306,13 @@ int Curl_parsenetrc(const char *host, if(pw) { home = pw->pw_dir; } +#elif defined(_WIN32) + } + else { + homea = curl_getenv("USERPROFILE"); + if(homea) { + home = homea; + } #endif } @@ -268,8 +325,7 @@ int Curl_parsenetrc(const char *host, free(homea); return -1; } - retcode = parsenetrc(host, loginp, passwordp, login_changed, - password_changed, filealloc); + retcode = parsenetrc(host, loginp, passwordp, filealloc); free(filealloc); #ifdef WIN32 if(retcode == NETRC_FILE_MISSING) { @@ -279,16 +335,14 @@ int Curl_parsenetrc(const char *host, free(homea); return -1; } - retcode = parsenetrc(host, loginp, passwordp, login_changed, - password_changed, filealloc); + retcode = parsenetrc(host, loginp, passwordp, filealloc); free(filealloc); } #endif free(homea); } else - retcode = parsenetrc(host, loginp, passwordp, login_changed, - password_changed, netrcfile); + retcode = parsenetrc(host, loginp, passwordp, netrcfile); return retcode; } diff --git a/Utilities/cmcurl/lib/netrc.h b/Utilities/cmcurl/lib/netrc.h index 4938a59..53d0056 100644 --- a/Utilities/cmcurl/lib/netrc.h +++ b/Utilities/cmcurl/lib/netrc.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,18 +20,16 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_NETRC /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ -int Curl_parsenetrc(const char *host, - char **loginp, - char **passwordp, - bool *login_changed, - bool *password_changed, - char *filename); +int Curl_parsenetrc(const char *host, char **loginp, + char **passwordp, char *filename); /* Assume: (*passwordp)[0]=0, host[0] != 0. * If (*loginp)[0] = 0, search for login and password within a machine * section in the netrc. diff --git a/Utilities/cmcurl/lib/nonblock.c b/Utilities/cmcurl/lib/nonblock.c index 28f6e75..ce73af3 100644 --- a/Utilities/cmcurl/lib/nonblock.c +++ b/Utilities/cmcurl/lib/nonblock.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/nonblock.h b/Utilities/cmcurl/lib/nonblock.h index 761dab4..a42f443 100644 --- a/Utilities/cmcurl/lib/nonblock.h +++ b/Utilities/cmcurl/lib/nonblock.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> /* for curl_socket_t */ diff --git a/Utilities/cmcurl/lib/noproxy.c b/Utilities/cmcurl/lib/noproxy.c new file mode 100644 index 0000000..81f1e09 --- /dev/null +++ b/Utilities/cmcurl/lib/noproxy.c @@ -0,0 +1,222 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, 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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifndef CURL_DISABLE_PROXY + +#include "inet_pton.h" +#include "strcase.h" +#include "noproxy.h" + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +/* + * Curl_cidr4_match() returns TRUE if the given IPv4 address is within the + * specified CIDR address range. + */ +UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ + const char *network, /* 1.2.3.4 address */ + unsigned int bits) +{ + unsigned int address = 0; + unsigned int check = 0; + + if(bits > 32) + /* strange input */ + return FALSE; + + if(1 != Curl_inet_pton(AF_INET, ipv4, &address)) + return FALSE; + if(1 != Curl_inet_pton(AF_INET, network, &check)) + return FALSE; + + if(bits && (bits != 32)) { + unsigned int mask = 0xffffffff << (32 - bits); + unsigned int haddr = htonl(address); + unsigned int hcheck = htonl(check); +#if 0 + fprintf(stderr, "Host %s (%x) network %s (%x) bits %u mask %x => %x\n", + ipv4, haddr, network, hcheck, bits, mask, + (haddr ^ hcheck) & mask); +#endif + if((haddr ^ hcheck) & mask) + return FALSE; + return TRUE; + } + return (address == check); +} + +UNITTEST bool Curl_cidr6_match(const char *ipv6, + const char *network, + unsigned int bits) +{ +#ifdef ENABLE_IPV6 + int bytes; + int rest; + unsigned char address[16]; + unsigned char check[16]; + + if(!bits) + bits = 128; + + bytes = bits/8; + rest = bits & 0x07; + if(1 != Curl_inet_pton(AF_INET6, ipv6, address)) + return FALSE; + if(1 != Curl_inet_pton(AF_INET6, network, check)) + return FALSE; + if((bytes > 16) || ((bytes == 16) && rest)) + return FALSE; + if(bytes && memcmp(address, check, bytes)) + return FALSE; + if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest)))) + return FALSE; + + return TRUE; +#else + (void)ipv6; + (void)network; + (void)bits; + return FALSE; +#endif +} + +enum nametype { + TYPE_HOST, + TYPE_IPV4, + TYPE_IPV6 +}; + +/**************************************************************** +* Checks if the host is in the noproxy list. returns TRUE if it matches and +* therefore the proxy should NOT be used. +****************************************************************/ +bool Curl_check_noproxy(const char *name, const char *no_proxy) +{ + /* no_proxy=domain1.dom,host.domain2.dom + * (a comma-separated list of hosts which should + * not be proxied, or an asterisk to override + * all proxy variables) + */ + if(no_proxy && no_proxy[0]) { + const char *p = no_proxy; + size_t namelen; + enum nametype type = TYPE_HOST; + char hostip[128]; + if(!strcmp("*", no_proxy)) + return TRUE; + + /* NO_PROXY was specified and it wasn't just an asterisk */ + + if(name[0] == '[') { + char *endptr; + /* IPv6 numerical address */ + endptr = strchr(name, ']'); + if(!endptr) + return FALSE; + name++; + namelen = endptr - name; + if(namelen >= sizeof(hostip)) + return FALSE; + memcpy(hostip, name, namelen); + hostip[namelen] = 0; + name = hostip; + type = TYPE_IPV6; + } + else { + unsigned int address; + if(1 == Curl_inet_pton(AF_INET, name, &address)) + type = TYPE_IPV4; + namelen = strlen(name); + } + + while(*p) { + const char *token; + size_t tokenlen = 0; + bool match = FALSE; + + /* pass blanks */ + while(*p && ISBLANK(*p)) + p++; + + token = p; + /* pass over the pattern */ + while(*p && !ISBLANK(*p) && (*p != ',')) { + p++; + tokenlen++; + } + + if(tokenlen) { + switch(type) { + case TYPE_HOST: + if(*token == '.') { + ++token; + --tokenlen; + /* tailmatch */ + match = (tokenlen <= namelen) && + strncasecompare(token, name + (namelen - tokenlen), namelen); + } + else + match = (tokenlen == namelen) && + strncasecompare(token, name, namelen); + break; + case TYPE_IPV4: + /* FALLTHROUGH */ + case TYPE_IPV6: { + const char *check = token; + char *slash = strchr(check, '/'); + unsigned int bits = 0; + char checkip[128]; + /* if the slash is part of this token, use it */ + if(slash && (slash < &check[tokenlen])) { + bits = atoi(slash + 1); + /* copy the check name to a temp buffer */ + if(tokenlen >= sizeof(checkip)) + break; + memcpy(checkip, check, tokenlen); + checkip[ slash - check ] = 0; + check = checkip; + } + if(type == TYPE_IPV6) + match = Curl_cidr6_match(name, check, bits); + else + match = Curl_cidr4_match(name, check, bits); + break; + } + } + if(match) + return TRUE; + } /* if(tokenlen) */ + while(*p == ',') + p++; + } /* while(*p) */ + } /* NO_PROXY was specified and it wasn't just an asterisk */ + + return FALSE; +} + +#endif /* CURL_DISABLE_PROXY */ diff --git a/Utilities/cmcurl/lib/dotdot.h b/Utilities/cmcurl/lib/noproxy.h index ac1ea36..8800a21 100644 --- a/Utilities/cmcurl/lib/dotdot.h +++ b/Utilities/cmcurl/lib/noproxy.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_DOTDOT_H -#define HEADER_CURL_DOTDOT_H +#ifndef HEADER_CURL_NOPROXY_H +#define HEADER_CURL_NOPROXY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,25 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ -char *Curl_dedotdotify(const char *input); -#endif /* HEADER_CURL_DOTDOT_H */ +#include "curl_setup.h" + +#ifndef CURL_DISABLE_PROXY + +#ifdef DEBUGBUILD + +UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ + const char *network, /* 1.2.3.4 address */ + unsigned int bits); +UNITTEST bool Curl_cidr6_match(const char *ipv6, + const char *network, + unsigned int bits); +#endif + +bool Curl_check_noproxy(const char *name, const char *no_proxy); + +#endif + +#endif /* HEADER_CURL_NOPROXY_H */ diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c index 4e92567..3a93b67 100644 --- a/Utilities/cmcurl/lib/openldap.c +++ b/Utilities/cmcurl/lib/openldap.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -1066,8 +1068,8 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf, if(!binary) { /* check for leading or trailing whitespace */ - if(ISSPACE(bvals[i].bv_val[0]) || - ISSPACE(bvals[i].bv_val[bvals[i].bv_len - 1])) + if(ISBLANK(bvals[i].bv_val[0]) || + ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1])) binval = 1; else { /* check for unprintable characters */ diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c index 3c38f2c..5ed8819 100644 --- a/Utilities/cmcurl/lib/parsedate.c +++ b/Utilities/cmcurl/lib/parsedate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* A brief summary of the date string formats this parser groks: diff --git a/Utilities/cmcurl/lib/parsedate.h b/Utilities/cmcurl/lib/parsedate.h index a99faf9..4e43477 100644 --- a/Utilities/cmcurl/lib/parsedate.h +++ b/Utilities/cmcurl/lib/parsedate.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ extern const char * const Curl_wkday[7]; diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c index e08c1d8..d4e6be9 100644 --- a/Utilities/cmcurl/lib/pingpong.c +++ b/Utilities/cmcurl/lib/pingpong.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * 'pingpong' is for generic back-and-forth support functions used by FTP, * IMAP, POP3, SMTP and whatever more that likes them. * @@ -328,7 +330,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, else if(gotbytes <= 0) { keepon = FALSE; result = CURLE_RECV_ERROR; - failf(data, "response reading failed"); + failf(data, "response reading failed (errno: %d)", SOCKERRNO); } else { /* we got a whole chunk of data, which can be anything from one @@ -396,7 +398,8 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data, } else if(keepon) { - if((perline == gotbytes) && (gotbytes > data->set.buffer_size/2)) { + if((perline == gotbytes) && + (gotbytes > (ssize_t)data->set.buffer_size/2)) { /* We got an excessive line without newlines and we need to deal with it. We keep the first bytes of the line then we throw away the rest. */ diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h index 8f56f3f..cefae07 100644 --- a/Utilities/cmcurl/lib/pingpong.h +++ b/Utilities/cmcurl/lib/pingpong.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c index 2c1b06c..3151a3f 100644 --- a/Utilities/cmcurl/lib/pop3.c +++ b/Utilities/cmcurl/lib/pop3.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC1734 POP3 Authentication * RFC1939 POP3 protocol * RFC2195 CRAM-MD5 authentication diff --git a/Utilities/cmcurl/lib/pop3.h b/Utilities/cmcurl/lib/pop3.h index 17629ee..bb0645f 100644 --- a/Utilities/cmcurl/lib/pop3.h +++ b/Utilities/cmcurl/lib/pop3.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "pingpong.h" diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c index f5ef6bd..4a1e1da 100644 --- a/Utilities/cmcurl/lib/progress.c +++ b/Utilities/cmcurl/lib/progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/progress.h b/Utilities/cmcurl/lib/progress.h index ac4ebc0..a129315 100644 --- a/Utilities/cmcurl/lib/progress.h +++ b/Utilities/cmcurl/lib/progress.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "timeval.h" diff --git a/Utilities/cmcurl/lib/psl.c b/Utilities/cmcurl/lib/psl.c index e460918..60c98a4 100644 --- a/Utilities/cmcurl/lib/psl.c +++ b/Utilities/cmcurl/lib/psl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/psl.h b/Utilities/cmcurl/lib/psl.h index c103674..34f0a5c 100644 --- a/Utilities/cmcurl/lib/psl.h +++ b/Utilities/cmcurl/lib/psl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifdef USE_LIBPSL diff --git a/Utilities/cmcurl/lib/quic.h b/Utilities/cmcurl/lib/quic.h index f92720f..b357747 100644 --- a/Utilities/cmcurl/lib/quic.h +++ b/Utilities/cmcurl/lib/quic.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -54,6 +56,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature); bool Curl_quic_data_pending(const struct Curl_easy *data); void Curl_quic_disconnect(struct Curl_easy *data, struct connectdata *conn, int tempindex); +CURLcode Curl_quic_idle(struct Curl_easy *data); #else /* ENABLE_QUIC */ #define Curl_quic_done_sending(x) diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c index 8da1e8d..2e7e7e8 100644 --- a/Utilities/cmcurl/lib/rand.c +++ b/Utilities/cmcurl/lib/rand.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -36,6 +38,64 @@ #include "curl_memory.h" #include "memdebug.h" +#ifdef WIN32 + +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +# define HAVE_MINGW_ORIGINAL +#endif + +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \ + !defined(HAVE_MINGW_ORIGINAL) +# define HAVE_WIN_BCRYPTGENRANDOM +# include <bcrypt.h> +# ifdef _MSC_VER +# pragma comment(lib, "bcrypt.lib") +# endif +# ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG +# define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 +# endif +# ifndef STATUS_SUCCESS +# define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +# endif +#elif defined(USE_WIN32_CRYPTO) +# include <wincrypt.h> +# ifdef _MSC_VER +# pragma comment(lib, "advapi32.lib") +# endif +#endif + +CURLcode Curl_win32_random(unsigned char *entropy, size_t length) +{ + memset(entropy, 0, length); + +#if defined(HAVE_WIN_BCRYPTGENRANDOM) + if(BCryptGenRandom(NULL, entropy, (ULONG)length, + BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS) + return CURLE_FAILED_INIT; + + return CURLE_OK; +#elif defined(USE_WIN32_CRYPTO) + { + HCRYPTPROV hCryptProv = 0; + + if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + return CURLE_FAILED_INIT; + + if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { + CryptReleaseContext(hCryptProv, 0UL); + return CURLE_FAILED_INIT; + } + + CryptReleaseContext(hCryptProv, 0UL); + } + return CURLE_OK; +#else + return CURLE_NOT_BUILT_IN; +#endif +} +#endif + static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) { unsigned int r; @@ -71,7 +131,15 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) /* ---- non-cryptographic version following ---- */ -#ifdef RANDOM_FILE +#ifdef WIN32 + if(!seeded) { + result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd)); + if(result != CURLE_NOT_BUILT_IN) + return result; + } +#endif + +#if defined(RANDOM_FILE) && !defined(WIN32) if(!seeded) { /* if there's a random file to read a seed from, use it */ int fd = open(RANDOM_FILE, O_RDONLY); @@ -106,7 +174,8 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) * 'rndptr' points to. * * If libcurl is built without TLS support or with a TLS backend that lacks a - * proper random API (Gskit or mbedTLS), this function will use "weak" random. + * proper random API (rustls, Gskit or mbedTLS), this function will use "weak" + * random. * * When built *with* TLS support and a backend that offers strong random, it * will return error if it cannot provide strong random values. @@ -143,7 +212,7 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num) /* * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random - * hexadecimal digits PLUS a zero terminating byte. It must be an odd number + * hexadecimal digits PLUS a null-terminating byte. It must be an odd number * size. */ @@ -166,7 +235,7 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, /* make sure it fits in the local buffer and that it is an odd number! */ return CURLE_BAD_FUNCTION_ARGUMENT; - num--; /* save one for zero termination */ + num--; /* save one for null-termination */ result = Curl_rand(data, buffer, num/2); if(result) diff --git a/Utilities/cmcurl/lib/rand.h b/Utilities/cmcurl/lib/rand.h index 02d95d8..30fc296 100644 --- a/Utilities/cmcurl/lib/rand.h +++ b/Utilities/cmcurl/lib/rand.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -40,10 +42,16 @@ CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num); /* * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random - * hexadecimal digits PLUS a zero terminating byte. It must be an odd number + * hexadecimal digits PLUS a null-terminating byte. It must be an odd number * size. */ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd, size_t num); +#ifdef WIN32 +/* Random generator shared between the Schannel vtls and Curl_rand*() + functions */ +CURLcode Curl_win32_random(unsigned char *entropy, size_t length); +#endif + #endif /* HEADER_CURL_RAND_H */ diff --git a/Utilities/cmcurl/lib/rename.c b/Utilities/cmcurl/lib/rename.c index f858d43..cfb3699 100644 --- a/Utilities/cmcurl/lib/rename.c +++ b/Utilities/cmcurl/lib/rename.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2020 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "rename.h" diff --git a/Utilities/cmcurl/lib/rename.h b/Utilities/cmcurl/lib/rename.h index 534f747..9958e2c 100644 --- a/Utilities/cmcurl/lib/rename.h +++ b/Utilities/cmcurl/lib/rename.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2020 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ int Curl_rename(const char *oldpath, const char *newpath); diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index 726bfb9..6d3bf97 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -792,7 +794,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) /* Find the first non-space letter */ start = header + 8; - while(*start && ISSPACE(*start)) + while(*start && ISBLANK(*start)) start++; if(!*start) { diff --git a/Utilities/cmcurl/lib/rtsp.h b/Utilities/cmcurl/lib/rtsp.h index da11ade..377c828 100644 --- a/Utilities/cmcurl/lib/rtsp.h +++ b/Utilities/cmcurl/lib/rtsp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifdef USE_HYPER #define CURL_DISABLE_RTSP 1 diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c index a48da82..2ac0746 100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -308,8 +310,12 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms) else pending_ms = 0; r = poll(ufds, nfds, pending_ms); - if(r <= 0) + if(r <= 0) { + if((r == -1) && (SOCKERRNO == EINTR)) + /* make EINTR from select or poll not a "lethal" error */ + r = 0; return r; + } for(i = 0; i < nfds; i++) { if(ufds[i].fd == CURL_SOCKET_BAD) @@ -352,8 +358,12 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms) value). */ r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms); - if(r <= 0) + if(r <= 0) { + if((r == -1) && (SOCKERRNO == EINTR)) + /* make EINTR from select or poll not a "lethal" error */ + r = 0; return r; + } r = 0; for(i = 0; i < nfds; i++) { diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h index f4bcba3..f2cf8bb 100644 --- a/Utilities/cmcurl/lib/select.h +++ b/Utilities/cmcurl/lib/select.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -34,8 +36,7 @@ * Definition of pollfd struct and constants for platforms lacking them. */ -#if !defined(HAVE_STRUCT_POLLFD) && \ - !defined(HAVE_SYS_POLL_H) && \ +#if !defined(HAVE_SYS_POLL_H) && \ !defined(HAVE_POLL_H) && \ !defined(POLLIN) diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c index d7d4d8a..d26b7e7 100644 --- a/Utilities/cmcurl/lib/sendf.c +++ b/Utilities/cmcurl/lib/sendf.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -46,13 +48,14 @@ #include "strdup.h" #include "http2.h" #include "headers.h" +#include "ws.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -#ifdef CURL_DO_LINEEND_CONV +#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP) /* * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF * (\n), with special processing for CRLF sequences that are split between two @@ -132,7 +135,7 @@ static size_t convert_lineends(struct Curl_easy *data, } return size; } -#endif /* CURL_DO_LINEEND_CONV */ +#endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */ #ifdef USE_RECV_BEFORE_SEND_WORKAROUND bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) @@ -243,7 +246,7 @@ 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; + int len; char buffer[MAXINFO + 2]; va_start(ap, fmt); len = mvsnprintf(buffer, MAXINFO, fmt, ap); @@ -263,7 +266,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) DEBUGASSERT(!strchr(fmt, '\n')); if(data->set.verbose || data->set.errorbuffer) { va_list ap; - size_t len; + int len; char error[CURL_ERROR_SIZE + 2]; va_start(ap, fmt); len = mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap); @@ -494,6 +497,9 @@ static CURLcode pausewrite(struct Curl_easy *data, } } DEBUGASSERT(i < 3); + if(i >= 3) + /* There are more types to store than what fits: very bad */ + return CURLE_OUT_OF_MEMORY; } else i = 0; @@ -529,6 +535,7 @@ static CURLcode chop_write(struct Curl_easy *data, curl_write_callback writebody = NULL; char *ptr = optr; size_t len = olen; + void *writebody_ptr = data->set.out; if(!len) return CURLE_OK; @@ -539,8 +546,18 @@ static CURLcode chop_write(struct Curl_easy *data, return pausewrite(data, type, ptr, len); /* Determine the callback(s) to use. */ - if(type & CLIENTWRITE_BODY) + if(type & CLIENTWRITE_BODY) { +#ifdef USE_WEBSOCKETS + if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) { + struct HTTP *ws = data->req.p.http; + writebody = Curl_ws_writecb; + ws->ws.data = data; + writebody_ptr = ws; + } + else +#endif writebody = data->set.fwrite_func; + } if((type & CLIENTWRITE_HEADER) && (data->set.fwrite_header || data->set.writeheader)) { /* @@ -558,7 +575,7 @@ static CURLcode chop_write(struct Curl_easy *data, if(writebody) { size_t wrote; Curl_set_in_callback(data, true); - wrote = writebody(ptr, 1, chunklen, data->set.out); + wrote = writebody(ptr, 1, chunklen, writebody_ptr); Curl_set_in_callback(data, false); if(CURL_WRITEFUNC_PAUSE == wrote) { @@ -581,18 +598,20 @@ static CURLcode chop_write(struct Curl_easy *data, len -= chunklen; } +#ifndef CURL_DISABLE_HTTP /* HTTP header, but not status-line */ if((conn->handler->protocol & PROTO_FAMILY_HTTP) && (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) { - CURLcode result = - Curl_headers_push(data, optr, - type & CLIENTWRITE_CONNECT ? CURLH_CONNECT : - (type & CLIENTWRITE_1XX ? CURLH_1XX : - (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER : - CURLH_HEADER))); + unsigned char htype = (unsigned char) + (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT : + (type & CLIENTWRITE_1XX ? CURLH_1XX : + (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER : + CURLH_HEADER))); + CURLcode result = Curl_headers_push(data, optr, htype); if(result) return result; } +#endif if(writeheader) { size_t wrote; @@ -605,8 +624,10 @@ static CURLcode chop_write(struct Curl_easy *data, /* here we pass in the HEADER bit only since if this was body as well then it was passed already and clearly that didn't trigger the pause, so this is saved for later with the HEADER bit only */ - return pausewrite(data, CLIENTWRITE_HEADER, optr, olen); - + return pausewrite(data, CLIENTWRITE_HEADER | + (type & (CLIENTWRITE_STATUS|CLIENTWRITE_CONNECT| + CLIENTWRITE_1XX|CLIENTWRITE_TRAILER)), + optr, olen); if(wrote != olen) { failf(data, "Failed writing header"); return CURLE_WRITE_ERROR; @@ -631,22 +652,15 @@ CURLcode Curl_client_write(struct Curl_easy *data, char *ptr, size_t len) { - struct connectdata *conn = data->conn; - - if(!len) - return CURLE_OK; - +#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV) /* FTP data may need conversion. */ if((type & CLIENTWRITE_BODY) && - (conn->handler->protocol & PROTO_FAMILY_FTP) && - conn->proto.ftpc.transfertype == 'A') { - -#ifdef CURL_DO_LINEEND_CONV + (data->conn->handler->protocol & PROTO_FAMILY_FTP) && + data->conn->proto.ftpc.transfertype == 'A') { /* convert end-of-line markers */ len = convert_lineends(data, ptr, len); -#endif /* CURL_DO_LINEEND_CONV */ } - +#endif return chop_write(data, type, ptr, len); } @@ -714,17 +728,17 @@ CURLcode Curl_read(struct Curl_easy *data, /* transfer */ } /* return 0 on success */ -int Curl_debug(struct Curl_easy *data, curl_infotype type, - char *ptr, size_t size) +void Curl_debug(struct Curl_easy *data, curl_infotype type, + char *ptr, size_t size) { - int rc = 0; if(data->set.verbose) { static const char s_infotype[CURLINFO_END][3] = { "* ", "< ", "> ", "{ ", "} ", "{ ", "} " }; if(data->set.fdebug) { + bool inCallback = Curl_is_in_callback(data); Curl_set_in_callback(data, true); - rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata); - Curl_set_in_callback(data, false); + (void)(*data->set.fdebug)(data, type, ptr, size, data->set.debugdata); + Curl_set_in_callback(data, inCallback); } else { switch(type) { @@ -739,5 +753,4 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type, } } } - return rc; } diff --git a/Utilities/cmcurl/lib/sendf.h b/Utilities/cmcurl/lib/sendf.h index 6676003..7c4c128 100644 --- a/Utilities/cmcurl/lib/sendf.h +++ b/Utilities/cmcurl/lib/sendf.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -87,8 +89,8 @@ CURLcode Curl_write_plain(struct Curl_easy *data, ssize_t *written); /* the function used to output verbose information */ -int Curl_debug(struct Curl_easy *data, curl_infotype type, - char *ptr, size_t size); +void Curl_debug(struct Curl_easy *data, curl_infotype type, + char *ptr, size_t size); #endif /* HEADER_CURL_SENDF_H */ diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c index 05e1a54..5b59754 100644 --- a/Utilities/cmcurl/lib/setopt.c +++ b/Utilities/cmcurl/lib/setopt.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -146,6 +148,40 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) #define C_SSLVERSION_VALUE(x) (x & 0xffff) #define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000) +static CURLcode protocol2num(const char *str, curl_prot_t *val) +{ + if(!str) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(curl_strequal(str, "all")) { + *val = ~(curl_prot_t) 0; + return CURLE_OK; + } + + *val = 0; + + do { + const char *token = str; + size_t tlen; + + str = strchr(str, ','); + tlen = str? (size_t) (str - token): strlen(token); + if(tlen) { + const struct Curl_handler *h = Curl_builtin_scheme(token, tlen); + + if(!h) + return CURLE_UNSUPPORTED_PROTOCOL; + + *val |= h->protocol; + } + } while(str++); + + if(!*val) + /* no protocol listed */ + return CURLE_BAD_FUNCTION_ARGUMENT; + return CURLE_OK; +} + /* * Do not make Curl_vsetopt() static: it is called from * packages/OS400/ccsidcurl.c. @@ -155,9 +191,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) char *argptr; CURLcode result = CURLE_OK; long arg; -#ifdef ENABLE_IPV6 unsigned long uarg; -#endif curl_off_t bigsize; switch(option) { @@ -165,7 +199,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = va_arg(param, long); if(arg < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.dns_cache_timeout = arg; + else if(arg > INT_MAX) + arg = INT_MAX; + + data->set.dns_cache_timeout = (int)arg; break; case CURLOPT_DNS_USE_GLOBAL_CACHE: /* deprecated */ @@ -203,19 +240,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; #endif case CURLOPT_RANDOM_FILE: - /* - * This is the path name to a file that contains random data to seed - * the random SSL stuff with. The file is only used for reading. - */ - result = Curl_setstropt(&data->set.str[STRING_SSL_RANDOM_FILE], - va_arg(param, char *)); break; case CURLOPT_EGDSOCKET: - /* - * The Entropy Gathering Daemon socket pathname - */ - result = Curl_setstropt(&data->set.str[STRING_SSL_EGDSOCKET], - va_arg(param, char *)); break; case CURLOPT_MAXCONNECTS: /* @@ -318,12 +344,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_SERVER_RESPONSE_TIMEOUT: /* - * Option that specifies how quickly an server response must be obtained + * Option that specifies how quickly a server response must be obtained * before it is considered failure. For pingpong protocols. */ arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) - data->set.server_response_timeout = arg * 1000; + data->set.server_response_timeout = (unsigned int)arg * 1000; else return CURLE_BAD_FUNCTION_ARGUMENT; break; @@ -353,7 +379,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = va_arg(param, long); if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_netrc = (enum CURL_NETRC_OPTION)arg; + data->set.use_netrc = (unsigned char)arg; break; case CURLOPT_NETRC_FILE: /* @@ -625,8 +651,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) } else data->set.method = HTTPREQ_GET; + data->set.upload = FALSE; break; +#ifndef CURL_DISABLE_MIME case CURLOPT_HTTPPOST: /* * Set to make us do HTTP POST @@ -635,6 +663,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.method = HTTPREQ_POST_FORM; data->set.opt_no_body = FALSE; /* this is implied */ break; +#endif case CURLOPT_AWS_SIGV4: /* @@ -650,18 +679,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.httpauth = CURLAUTH_AWS_SIGV4; break; - case CURLOPT_MIMEPOST: - /* - * Set to make us do MIME/form POST - */ - result = Curl_mime_set_subparts(&data->set.mimepost, - va_arg(param, curl_mime *), FALSE); - if(!result) { - data->set.method = HTTPREQ_POST_MIME; - data->set.opt_no_body = FALSE; /* this is implied */ - } - break; - case CURLOPT_REFERER: /* * String to set in the HTTP Referer: field. @@ -683,13 +700,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) va_arg(param, char *)); break; - case CURLOPT_HTTPHEADER: - /* - * Set a list with HTTP headers to use (or replace internals with) - */ - data->set.headers = va_arg(param, struct curl_slist *); - break; - #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYHEADER: /* @@ -927,6 +937,36 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; #endif /* CURL_DISABLE_HTTP */ +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP) +# if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) + case CURLOPT_HTTPHEADER: + /* + * Set a list with HTTP headers to use (or replace internals with) + */ + data->set.headers = va_arg(param, struct curl_slist *); + break; +# endif + +# ifndef CURL_DISABLE_MIME + case CURLOPT_MIMEPOST: + /* + * Set to make us do MIME POST + */ + result = Curl_mime_set_subparts(&data->set.mimepost, + va_arg(param, curl_mime *), FALSE); + if(!result) { + data->set.method = HTTPREQ_POST_MIME; + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; + + case CURLOPT_MIME_OPTIONS: + data->set.mime_options = (unsigned int)va_arg(param, long); + break; +# endif +#endif + case CURLOPT_HTTPAUTH: /* * Set HTTP Authentication type BITMASK. @@ -1115,13 +1155,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; } break; -#endif /* CURL_DISABLE_PROXY */ case CURLOPT_SOCKS5_AUTH: data->set.socks5auth = va_arg(param, unsigned long); if(data->set.socks5auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) result = CURLE_NOT_BUILT_IN; break; +#endif /* CURL_DISABLE_PROXY */ + #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CURLOPT_SOCKS5_GSSAPI_NEC: /* @@ -1270,7 +1311,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) (arg > CURLFTP_CREATE_DIR_RETRY)) result = CURLE_BAD_FUNCTION_ARGUMENT; else - data->set.ftp_create_missing_dirs = (int)arg; + data->set.ftp_create_missing_dirs = (unsigned char)arg; break; case CURLOPT_READDATA: /* @@ -1360,12 +1401,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; case CURLOPT_PORT: /* - * The port number to use when getting the URL + * The port number to use when getting the URL. 0 disables it. */ arg = va_arg(param, long); if((arg < 0) || (arg > 65535)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_port = arg; + data->set.use_port = (unsigned short)arg; break; case CURLOPT_TIMEOUT: /* @@ -1374,16 +1415,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) */ arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) - data->set.timeout = arg * 1000; + data->set.timeout = (unsigned int)arg * 1000; else return CURLE_BAD_FUNCTION_ARGUMENT; break; case CURLOPT_TIMEOUT_MS: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.timeout = arg; + uarg = va_arg(param, unsigned long); + if(uarg >= UINT_MAX) + uarg = UINT_MAX; + data->set.timeout = (unsigned int)uarg; break; case CURLOPT_CONNECTTIMEOUT: @@ -1392,27 +1433,29 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) */ arg = va_arg(param, long); if((arg >= 0) && (arg <= (INT_MAX/1000))) - data->set.connecttimeout = arg * 1000; + data->set.connecttimeout = (unsigned int)arg * 1000; else return CURLE_BAD_FUNCTION_ARGUMENT; break; case CURLOPT_CONNECTTIMEOUT_MS: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.connecttimeout = arg; + uarg = va_arg(param, unsigned long); + if(uarg >= UINT_MAX) + uarg = UINT_MAX; + data->set.connecttimeout = (unsigned int)uarg; break; +#ifndef CURL_DISABLE_FTP case CURLOPT_ACCEPTTIMEOUT_MS: /* - * The maximum time you allow curl to wait for server connect + * The maximum time for curl to wait for FTP server connect */ - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.accepttimeout = arg; + uarg = va_arg(param, unsigned long); + if(uarg >= UINT_MAX) + uarg = UINT_MAX; + data->set.accepttimeout = (unsigned int)uarg; break; +#endif case CURLOPT_USERPWD: /* @@ -1612,13 +1655,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) * Set data write callback */ data->set.fwrite_func = va_arg(param, curl_write_callback); - if(!data->set.fwrite_func) { - data->set.is_fwrite_set = 0; + if(!data->set.fwrite_func) /* When set to NULL, reset to our internal default function */ data->set.fwrite_func = (curl_write_callback)fwrite; - } - else - data->set.is_fwrite_set = 1; break; case CURLOPT_READFUNCTION: /* @@ -2166,7 +2205,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) else if(arg < READBUFFER_MIN) arg = READBUFFER_MIN; - data->set.buffer_size = arg; + data->set.buffer_size = (int)arg; break; case CURLOPT_UPLOAD_BUFFERSIZE: @@ -2360,9 +2399,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_CONNECT_ONLY: /* - * No data transfer, set up connection and let application use the socket + * No data transfer. + * (1) - only do connection + * (2) - do first get request but get no content */ - data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE; + arg = va_arg(param, long); + if(arg > 2) + return CURLE_BAD_FUNCTION_ARGUMENT; + data->set.connect_only = (unsigned char)arg; break; case CURLOPT_SOCKOPTFUNCTION: @@ -2435,7 +2479,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #ifdef USE_SSH /* we only include SSH options if explicitly built to support SSH */ case CURLOPT_SSH_AUTH_TYPES: - data->set.ssh_auth_types = va_arg(param, long); + data->set.ssh_auth_types = (unsigned int)va_arg(param, long); break; case CURLOPT_SSH_PUBLIC_KEYFILE: @@ -2478,7 +2522,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], va_arg(param, char *)); break; +#ifdef USE_LIBSSH2 + case CURLOPT_SSH_HOSTKEYFUNCTION: + /* the callback to check the hostkey without the knownhost file */ + data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback); + break; + case CURLOPT_SSH_HOSTKEYDATA: + /* + * Custom client data to pass to the SSH keyfunc callback + */ + data->set.ssh_hostkeyfunc_userp = va_arg(param, void *); + break; +#endif case CURLOPT_SSH_KEYFUNCTION: /* setting to NULL is fine since the ssh.c functions themselves will then revert to use the internal default */ @@ -2523,7 +2579,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = va_arg(param, long); if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.new_file_perms = arg; + data->set.new_file_perms = (unsigned int)arg; break; case CURLOPT_NEW_DIRECTORY_PERMS: @@ -2533,7 +2589,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = va_arg(param, long); if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.new_directory_perms = arg; + data->set.new_directory_perms = (unsigned int)arg; break; #endif @@ -2558,16 +2614,36 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ - data->set.allowed_protocols = va_arg(param, long); + data->set.allowed_protocols = (curl_prot_t)va_arg(param, long); break; case CURLOPT_REDIR_PROTOCOLS: /* set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. */ - data->set.redir_protocols = va_arg(param, long); + data->set.redir_protocols = (curl_prot_t)va_arg(param, long); break; + case CURLOPT_PROTOCOLS_STR: { + curl_prot_t prot; + argptr = va_arg(param, char *); + result = protocol2num(argptr, &prot); + if(result) + return result; + data->set.allowed_protocols = prot; + break; + } + + case CURLOPT_REDIR_PROTOCOLS_STR: { + curl_prot_t prot; + argptr = va_arg(param, char *); + result = protocol2num(argptr, &prot); + if(result) + return result; + data->set.redir_protocols = prot; + break; + } + case CURLOPT_DEFAULT_PROTOCOL: /* Set the protocol to use when the URL doesn't include any protocol */ result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], @@ -2596,13 +2672,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) break; #endif -#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \ - !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP) - case CURLOPT_MIME_OPTIONS: - data->set.mime_options = va_arg(param, long); - break; -#endif - case CURLOPT_SASL_AUTHZID: /* Authorization identity (identity to act as) */ result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], @@ -2833,13 +2902,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.tcp_keepidle = arg; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepidle = (int)arg; break; case CURLOPT_TCP_KEEPINTVL: arg = va_arg(param, long); if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.tcp_keepintvl = arg; + else if(arg > INT_MAX) + arg = INT_MAX; + data->set.tcp_keepintvl = (int)arg; break; case CURLOPT_TCP_FASTOPEN: #if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ @@ -2850,7 +2923,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) #endif break; case CURLOPT_SSL_ENABLE_NPN: - data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_ENABLE_ALPN: data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; @@ -2906,10 +2978,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: - arg = va_arg(param, long); - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.happy_eyeballs_timeout = arg; + uarg = va_arg(param, unsigned long); + if(uarg >= UINT_MAX) + uarg = UINT_MAX; + data->set.happy_eyeballs_timeout = (unsigned int)uarg; break; #ifndef CURL_DISABLE_SHUFFLE_DNS case CURLOPT_DNS_SHUFFLE_ADDRESSES: @@ -3026,6 +3098,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURLOPT_PREREQDATA: data->set.prereq_userp = va_arg(param, void *); break; +#ifdef USE_WEBSOCKETS + case CURLOPT_WS_OPTIONS: { + bool raw; + arg = va_arg(param, long); + raw = (arg & CURLWS_RAW_MODE); + data->set.ws_raw_mode = raw; + break; + } +#endif default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/Utilities/cmcurl/lib/setopt.h b/Utilities/cmcurl/lib/setopt.h index affbfd9..ffc77a7 100644 --- a/Utilities/cmcurl/lib/setopt.h +++ b/Utilities/cmcurl/lib/setopt.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ CURLcode Curl_setstropt(char **charp, const char *s); diff --git a/Utilities/cmcurl/lib/setup-os400.h b/Utilities/cmcurl/lib/setup-os400.h index 8c97371..6023ca2 100644 --- a/Utilities/cmcurl/lib/setup-os400.h +++ b/Utilities/cmcurl/lib/setup-os400.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/setup-vms.h b/Utilities/cmcurl/lib/setup-vms.h index a6710d9..b570683 100644 --- a/Utilities/cmcurl/lib/setup-vms.h +++ b/Utilities/cmcurl/lib/setup-vms.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* */ diff --git a/Utilities/cmcurl/lib/setup-win32.h b/Utilities/cmcurl/lib/setup-win32.h index fa8742f..bc5f8ef 100644 --- a/Utilities/cmcurl/lib/setup-win32.h +++ b/Utilities/cmcurl/lib/setup-win32.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -35,10 +37,21 @@ #ifdef HAVE_WINDOWS_H # if defined(UNICODE) && !defined(_UNICODE) -# define _UNICODE +# error "UNICODE is defined but _UNICODE is not defined" # endif # if defined(_UNICODE) && !defined(UNICODE) -# define UNICODE +# error "_UNICODE is defined but UNICODE is not defined" +# endif +/* + * Don't include unneeded stuff in Windows headers to avoid compiler + * warnings and macro clashes. + * Make sure to define this macro before including any Windows headers. + */ +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOGDI +# define NOGDI # endif # include <winerror.h> # include <windows.h> diff --git a/Utilities/cmcurl/lib/sha256.c b/Utilities/cmcurl/lib/sha256.c index 1e879f6..60720f5 100644 --- a/Utilities/cmcurl/lib/sha256.c +++ b/Utilities/cmcurl/lib/sha256.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c index 403563f..1a083e7 100644 --- a/Utilities/cmcurl/lib/share.c +++ b/Utilities/cmcurl/lib/share.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -39,7 +41,7 @@ curl_share_init(void) if(share) { share->magic = CURL_GOOD_SHARE; share->specifier |= (1<<CURL_LOCK_DATA_SHARE); - Curl_init_dnscache(&share->hostcache); + Curl_init_dnscache(&share->hostcache, 23); } return share; diff --git a/Utilities/cmcurl/lib/share.h b/Utilities/cmcurl/lib/share.h index 222e34b..32be416 100644 --- a/Utilities/cmcurl/lib/share.h +++ b/Utilities/cmcurl/lib/share.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/sigpipe.h b/Utilities/cmcurl/lib/sigpipe.h index d6ec5fc..d12b317 100644 --- a/Utilities/cmcurl/lib/sigpipe.h +++ b/Utilities/cmcurl/lib/sigpipe.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/slist.c b/Utilities/cmcurl/lib/slist.c index 907c203..6c80722 100644 --- a/Utilities/cmcurl/lib/slist.c +++ b/Utilities/cmcurl/lib/slist.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/slist.h b/Utilities/cmcurl/lib/slist.h index 3114259..4e5834c 100644 --- a/Utilities/cmcurl/lib/slist.h +++ b/Utilities/cmcurl/lib/slist.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c index 8f44704..a62e858 100644 --- a/Utilities/cmcurl/lib/smb.c +++ b/Utilities/cmcurl/lib/smb.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -32,7 +34,7 @@ #include <process.h> #ifdef CURL_WINDOWS_APP #define getpid GetCurrentProcessId -#elif !defined(MSDOS) +#elif defined(WIN32) #define getpid _getpid #endif #endif diff --git a/Utilities/cmcurl/lib/smb.h b/Utilities/cmcurl/lib/smb.h index 0e3c2ec..919f3ac 100644 --- a/Utilities/cmcurl/lib/smb.h +++ b/Utilities/cmcurl/lib/smb.h @@ -7,8 +7,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies - * Copyright (C) 2018 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2018, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies + * Copyright (C) 2018 - 2022, 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,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ enum smb_conn_state { diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c index c736cfa..6ebb41a 100644 --- a/Utilities/cmcurl/lib/smtp.c +++ b/Utilities/cmcurl/lib/smtp.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC1870 SMTP Service Extension for Message Size * RFC2195 CRAM-MD5 authentication * RFC2831 DIGEST-MD5 authentication @@ -1818,7 +1820,9 @@ static CURLcode smtp_parse_address(struct Curl_easy *data, const char *fqma, return result; } -CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread) +CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, + const ssize_t nread, + const ssize_t offset) { /* When sending a SMTP payload we must detect CRLF. sequences making sure they are sent as CRLF.. instead, as a . on the beginning of a line will @@ -1852,7 +1856,9 @@ CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread) /* This loop can be improved by some kind of Boyer-Moore style of approach but that is saved for later... */ - for(i = 0, si = 0; i < nread; i++) { + if(offset) + memcpy(scratch, data->req.upload_fromhere, offset); + for(i = offset, si = offset; i < nread; i++) { if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) { smtp->eob++; diff --git a/Utilities/cmcurl/lib/smtp.h b/Utilities/cmcurl/lib/smtp.h index 1fe4534..24c5589 100644 --- a/Utilities/cmcurl/lib/smtp.h +++ b/Utilities/cmcurl/lib/smtp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2009 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2009 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "pingpong.h" @@ -91,6 +93,8 @@ extern const struct Curl_handler Curl_handler_smtps; #define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e" #define SMTP_EOB_REPL_LEN 4 -CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread); +CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, + const ssize_t nread, + const ssize_t offset); #endif /* HEADER_CURL_SMTP_H */ diff --git a/Utilities/cmcurl/lib/sockaddr.h b/Utilities/cmcurl/lib/sockaddr.h index 84c08d9..77ec833 100644 --- a/Utilities/cmcurl/lib/sockaddr.h +++ b/Utilities/cmcurl/lib/sockaddr.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/socketpair.c b/Utilities/cmcurl/lib/socketpair.c index 409d2ad..0f8798f 100644 --- a/Utilities/cmcurl/lib/socketpair.c +++ b/Utilities/cmcurl/lib/socketpair.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/socketpair.h b/Utilities/cmcurl/lib/socketpair.h index cdcc0b9..de70df6 100644 --- a/Utilities/cmcurl/lib/socketpair.h +++ b/Utilities/cmcurl/lib/socketpair.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2019 - 2022, 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,10 +20,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifndef HAVE_SOCKETPAIR +#include <curl/curl.h> + int Curl_socketpair(int domain, int type, int protocol, curl_socket_t socks[2]); #else diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c index d614ae5..52c2988 100644 --- a/Utilities/cmcurl/lib/socks.c +++ b/Utilities/cmcurl/lib/socks.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/socks.h b/Utilities/cmcurl/lib/socks.h index f30c610..ff83aa5 100644 --- a/Utilities/cmcurl/lib/socks.h +++ b/Utilities/cmcurl/lib/socks.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c index 8ef2f8f..f14099f 100644 --- a/Utilities/cmcurl/lib/socks_gssapi.c +++ b/Utilities/cmcurl/lib/socks_gssapi.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com> + * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012, Markus Moeller, <markus_moeller@compuserve.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -51,7 +53,7 @@ static int check_gss_err(struct Curl_easy *data, if(GSS_ERROR(major_status)) { OM_uint32 maj_stat, min_stat; OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; + gss_buffer_desc status_string = GSS_C_EMPTY_BUFFER; char buf[1024]; size_t len; diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c index ffc8703..210a0df 100644 --- a/Utilities/cmcurl/lib/socks_sspi.c +++ b/Utilities/cmcurl/lib/socks_sspi.c @@ -5,8 +5,8 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. - * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com> + * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012, 2011, Markus Moeller, <markus_moeller@compuserve.com> * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/speedcheck.c b/Utilities/cmcurl/lib/speedcheck.c index 841d256..3ddc43d 100644 --- a/Utilities/cmcurl/lib/speedcheck.c +++ b/Utilities/cmcurl/lib/speedcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/speedcheck.h b/Utilities/cmcurl/lib/speedcheck.h index 1d4c7bf..cb44eb0 100644 --- a/Utilities/cmcurl/lib/speedcheck.h +++ b/Utilities/cmcurl/lib/speedcheck.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c index bcc0795..33b44aa 100644 --- a/Utilities/cmcurl/lib/splay.c +++ b/Utilities/cmcurl/lib/splay.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1997 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -101,7 +103,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, struct Curl_tree *node) { static const struct curltime KEY_NOTUSED = { - (time_t)-1, (unsigned int)-1 + ~0, -1 }; /* will *NEVER* appear */ if(!node) @@ -211,7 +213,7 @@ int Curl_splayremove(struct Curl_tree *t, struct Curl_tree **newroot) { static const struct curltime KEY_NOTUSED = { - (time_t)-1, (unsigned int)-1 + ~0, -1 }; /* will *NEVER* appear */ struct Curl_tree *x; diff --git a/Utilities/cmcurl/lib/splay.h b/Utilities/cmcurl/lib/splay.h index eb9f65f..015e2ca 100644 --- a/Utilities/cmcurl/lib/splay.h +++ b/Utilities/cmcurl/lib/splay.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1997 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #include "timeval.h" diff --git a/Utilities/cmcurl/lib/strcase.c b/Utilities/cmcurl/lib/strcase.c index 692a3f1..09d2a8a 100644 --- a/Utilities/cmcurl/lib/strcase.c +++ b/Utilities/cmcurl/lib/strcase.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -26,25 +28,58 @@ #include "strcase.h" -static char raw_tolower(char in); +/* Mapping table to go from lowercase to uppercase for plain ASCII.*/ +static const unsigned char touppermap[256] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, +41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, +60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, +79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, +66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, +85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, +134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, +150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, +166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, +182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, +198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, +214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, +230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, +246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + +/* Mapping table to go from uppercase to lowercase for plain ASCII.*/ +static const unsigned char tolowermap[256] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, +22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, +42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, +62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, +111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, +96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, +112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, +128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, +144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, +160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, +176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, +192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, +208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, +224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, +240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 +}; + /* Portable, consistent toupper. Do not use toupper() because its behavior is altered by the current locale. */ char Curl_raw_toupper(char in) { - if(in >= 'a' && in <= 'z') - return (char)('A' + in - 'a'); - return in; + return touppermap[(unsigned char) in]; } /* Portable, consistent tolower. Do not use tolower() because its behavior is altered by the current locale. */ -static char raw_tolower(char in) +char Curl_raw_tolower(char in) { - if(in >= 'A' && in <= 'Z') - return (char)('a' + in - 'A'); - return in; + return tolowermap[(unsigned char) in]; } /* @@ -62,14 +97,15 @@ int Curl_strcasecompare(const char *first, const char *second) while(*first && *second) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) /* get out of the loop as soon as they don't match */ - break; + return 0; first++; second++; } - /* we do the comparison here (possibly again), just to make sure that if the - loop above is skipped because one of the strings reached zero, we must not - return this as a successful match */ - return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); + /* If we're here either the strings are the same or the length is different. + We can just test if the "current" character is non-zero for one and zero + for the other. Note that the characters may not be exactly the same even + if they match, we only want to compare zero-ness. */ + return !*first == !*second; } int Curl_safe_strcasecompare(const char *first, const char *second) @@ -127,7 +163,7 @@ void Curl_strntolower(char *dest, const char *src, size_t n) return; do { - *dest++ = raw_tolower(*src); + *dest++ = Curl_raw_tolower(*src); } while(*src++ && --n); } @@ -141,6 +177,28 @@ bool Curl_safecmp(char *a, char *b) return !a && !b; } +/* + * Curl_timestrcmp() returns 0 if the two strings are identical. The time this + * function spends is a function of the shortest string, not of the contents. + */ +int Curl_timestrcmp(const char *a, const char *b) +{ + int match = 0; + int i = 0; + + if(a && b) { + while(1) { + match |= a[i]^b[i]; + if(!a[i] || !b[i]) + break; + i++; + } + } + else + return a || b; + return match; +} + /* --- public functions --- */ int curl_strequal(const char *first, const char *second) diff --git a/Utilities/cmcurl/lib/strcase.h b/Utilities/cmcurl/lib/strcase.h index 2635f51..65a5753 100644 --- a/Utilities/cmcurl/lib/strcase.h +++ b/Utilities/cmcurl/lib/strcase.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> @@ -41,6 +43,7 @@ int Curl_safe_strcasecompare(const char *first, const char *second); int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); +char Curl_raw_tolower(char in); /* checkprefix() is a shorter version of the above, used when the first argument is the string literal */ @@ -50,5 +53,6 @@ void Curl_strntoupper(char *dest, const char *src, size_t n); void Curl_strntolower(char *dest, const char *src, size_t n); bool Curl_safecmp(char *a, char *b); +int Curl_timestrcmp(const char *first, const char *second); #endif /* HEADER_CURL_STRCASE_H */ diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c index 85cf33b..ac22b6d 100644 --- a/Utilities/cmcurl/lib/strdup.c +++ b/Utilities/cmcurl/lib/strdup.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h index 8c8a6f2..fb46808 100644 --- a/Utilities/cmcurl/lib/strdup.h +++ b/Utilities/cmcurl/lib/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c index 781e26b..b9a51e2 100644 --- a/Utilities/cmcurl/lib/strerror.c +++ b/Utilities/cmcurl/lib/strerror.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -263,9 +265,6 @@ curl_easy_strerror(CURLcode error) case CURLE_TFTP_NOSUCHUSER: return "TFTP: No such user"; - case CURLE_CONV_FAILED: - return "Conversion failed"; - case CURLE_REMOTE_FILE_NOT_FOUND: return "Remote file not found"; @@ -317,6 +316,9 @@ curl_easy_strerror(CURLcode error) case CURLE_SSL_CLIENTCERT: return "SSL Client Certificate required"; + case CURLE_UNRECOVERABLE_POLL: + return "Unrecoverable error in select/poll"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: @@ -329,6 +331,7 @@ curl_easy_strerror(CURLcode error) case CURLE_OBSOLETE51: case CURLE_OBSOLETE57: case CURLE_OBSOLETE62: + case CURLE_OBSOLETE75: case CURLE_OBSOLETE76: case CURL_LAST: break; @@ -400,6 +403,9 @@ curl_multi_strerror(CURLMcode error) case CURLM_ABORTED_BY_CALLBACK: return "Operation was aborted by an application callback"; + case CURLM_UNRECOVERABLE_POLL: + return "Unrecoverable error in select/poll"; + case CURLM_LAST: break; } @@ -470,7 +476,7 @@ curl_url_strerror(CURLUcode error) return "Port number was not a decimal number between 0 and 65535"; case CURLUE_UNSUPPORTED_SCHEME: - return "This libcurl build doesn't support the given URL scheme"; + return "Unsupported URL scheme"; case CURLUE_URLDECODE: return "URL decode error, most likely because of rubbish in the input"; @@ -524,7 +530,7 @@ curl_url_strerror(CURLUcode error) return "Bad file:// URL"; case CURLUE_BAD_SLASHES: - return "Unsupported number of slashes"; + return "Unsupported number of slashes following scheme"; case CURLUE_BAD_SCHEME: return "Bad scheme"; diff --git a/Utilities/cmcurl/lib/strerror.h b/Utilities/cmcurl/lib/strerror.h index 96a7e27..658f16c 100644 --- a/Utilities/cmcurl/lib/strerror.h +++ b/Utilities/cmcurl/lib/strerror.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "urldata.h" diff --git a/Utilities/cmcurl/lib/strtok.c b/Utilities/cmcurl/lib/strtok.c index d53e587..6120bcc 100644 --- a/Utilities/cmcurl/lib/strtok.c +++ b/Utilities/cmcurl/lib/strtok.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/strtok.h b/Utilities/cmcurl/lib/strtok.h index 831ef0c..641a3da 100644 --- a/Utilities/cmcurl/lib/strtok.h +++ b/Utilities/cmcurl/lib/strtok.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #include <stddef.h> diff --git a/Utilities/cmcurl/lib/strtoofft.c b/Utilities/cmcurl/lib/strtoofft.c index ac87cfc..30deb8c 100644 --- a/Utilities/cmcurl/lib/strtoofft.c +++ b/Utilities/cmcurl/lib/strtoofft.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <errno.h> @@ -85,7 +87,7 @@ static curl_off_t strtooff(const char *nptr, char **endptr, int base) /* Skip leading whitespace. */ end = (char *)nptr; - while(ISSPACE(end[0])) { + while(ISBLANK(end[0])) { end++; } @@ -220,9 +222,9 @@ CURLofft curlx_strtoofft(const char *str, char **endp, int base, errno = 0; *num = 0; /* clear by default */ - while(*str && ISSPACE(*str)) + while(*str && ISBLANK(*str)) str++; - if('-' == *str) { + if(('-' == *str) || (ISSPACE(*str))) { if(endp) *endp = (char *)str; /* didn't actually move */ return CURL_OFFT_INVAL; /* nothing parsed */ diff --git a/Utilities/cmcurl/lib/strtoofft.h b/Utilities/cmcurl/lib/strtoofft.h index 4d22ba3..311dae4 100644 --- a/Utilities/cmcurl/lib/strtoofft.h +++ b/Utilities/cmcurl/lib/strtoofft.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c index 9a6dd9c..bede9c7 100644 --- a/Utilities/cmcurl/lib/system_win32.c +++ b/Utilities/cmcurl/lib/system_win32.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016 - 2021, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2016 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/system_win32.h b/Utilities/cmcurl/lib/system_win32.h index 69e0c81..167804e 100644 --- a/Utilities/cmcurl/lib/system_win32.h +++ b/Utilities/cmcurl/lib/system_win32.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016 - 2020, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2016 - 2022, 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 @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index 2abfcd9..923c7f8 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/telnet.h b/Utilities/cmcurl/lib/telnet.h index 1427473..6dd99b4 100644 --- a/Utilities/cmcurl/lib/telnet.h +++ b/Utilities/cmcurl/lib/telnet.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_TELNET extern const struct Curl_handler Curl_handler_telnet; diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c index 7f2c88b..9e6d949 100644 --- a/Utilities/cmcurl/lib/tftp.c +++ b/Utilities/cmcurl/lib/tftp.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/tftp.h b/Utilities/cmcurl/lib/tftp.h index 4b5bea2..3f1fda6 100644 --- a/Utilities/cmcurl/lib/tftp.h +++ b/Utilities/cmcurl/lib/tftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef CURL_DISABLE_TFTP extern const struct Curl_handler Curl_handler_tftp; diff --git a/Utilities/cmcurl/lib/timediff.c b/Utilities/cmcurl/lib/timediff.c index 003477c..c589318 100644 --- a/Utilities/cmcurl/lib/timediff.c +++ b/Utilities/cmcurl/lib/timediff.c @@ -18,10 +18,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "timediff.h" +#include <limits.h> + /* * Converts number of milliseconds into a timeval structure. * diff --git a/Utilities/cmcurl/lib/timediff.h b/Utilities/cmcurl/lib/timediff.h index fcd5f05..90e5474 100644 --- a/Utilities/cmcurl/lib/timediff.h +++ b/Utilities/cmcurl/lib/timediff.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c index ca98fe5..647d7b0 100644 --- a/Utilities/cmcurl/lib/timeval.c +++ b/Utilities/cmcurl/lib/timeval.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "timeval.h" diff --git a/Utilities/cmcurl/lib/timeval.h b/Utilities/cmcurl/lib/timeval.h index dce32f4..8d4fef4 100644 --- a/Utilities/cmcurl/lib/timeval.h +++ b/Utilities/cmcurl/lib/timeval.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index 315da87..441da73 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -202,6 +204,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, } #endif +#ifndef CURL_DISABLE_HTTP /* if we are transmitting trailing data, we don't need to write a chunk size so we skip this */ if(data->req.upload_chunky && @@ -211,7 +214,6 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */ } -#ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_SENDING) { /* if we're here then that means that we already sent the last empty chunk but we didn't send a final CR LF, so we sent 0 CR LF. We then start @@ -267,6 +269,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, return CURLE_READ_ERROR; } +#ifndef CURL_DISABLE_HTTP if(!data->req.forbidchunk && data->req.upload_chunky) { /* if chunked Transfer-Encoding * build chunk: @@ -317,15 +320,12 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, /* always append ASCII CRLF to the data unless we have a valid trailer callback */ -#ifndef CURL_DISABLE_HTTP if((nread-hexlen) == 0 && data->set.trailer_callback != NULL && data->state.trailers_state == TRAILERS_NONE) { data->state.trailers_state = TRAILERS_INITIALIZED; } - else -#endif - { + else { memcpy(data->req.upload_fromhere + nread, endofline_network, strlen(endofline_network)); @@ -333,7 +333,6 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, } } -#ifndef CURL_DISABLE_HTTP if(data->state.trailers_state == TRAILERS_SENDING && !trailers_left(data)) { Curl_dyn_free(&data->state.trailers_buf); @@ -345,7 +344,6 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, infof(data, "Signaling end of chunked upload after trailers."); } else -#endif if((nread - hexlen) == 0 && data->state.trailers_state != TRAILERS_INITIALIZED) { /* mark this as done once this chunk is transferred */ @@ -357,6 +355,7 @@ CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes, if(added_crlf) nread += strlen(endofline_network); /* for the added end of line */ } +#endif *nreadp = nread; @@ -540,6 +539,13 @@ static CURLcode readwrite_data(struct Curl_easy *data, bool is_http2 = ((conn->handler->protocol & PROTO_FAMILY_HTTP) && (conn->httpversion == 20)); #endif + bool is_http3 = +#ifdef ENABLE_QUIC + ((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (conn->httpversion == 30)); +#else + FALSE; +#endif if( #ifdef USE_NGHTTP2 @@ -550,6 +556,7 @@ static CURLcode readwrite_data(struct Curl_easy *data, for a particular stream. */ !is_http2 && #endif + !is_http3 && /* Same reason mentioned above. */ k->size != -1 && !k->header) { /* make sure we don't read too much */ curl_off_t totalleft = k->size - k->bytecount; @@ -597,6 +604,9 @@ static CURLcode readwrite_data(struct Curl_easy *data, DEBUGF(infof(data, "nread == 0, stream closed, bailing")); else #endif + if(is_http3 && !nread) + DEBUGF(infof(data, "nread == 0, stream closed, bailing")); + else DEBUGF(infof(data, "nread <= 0, server closed connection, bailing")); k->keepon &= ~KEEP_RECV; break; @@ -754,7 +764,13 @@ static CURLcode readwrite_data(struct Curl_easy *data, if(nread < 0) /* this should be unusual */ nread = 0; - k->keepon &= ~KEEP_RECV; /* we're done reading */ + /* HTTP/3 over QUIC should keep reading until QUIC connection + is closed. In contrast to HTTP/2 which can stop reading + from TCP connection, HTTP/3 over QUIC needs ACK from server + to ensure stream closure. It should keep reading. */ + if(!is_http3) { + k->keepon &= ~KEEP_RECV; /* we're done reading */ + } } k->bytecount += nread; @@ -900,6 +916,9 @@ static void win_update_buffer_size(curl_socket_t sockfd) #define win_update_buffer_size(x) #endif +#define curl_upload_refill_watermark(data) \ + ((ssize_t)((data)->set.upload_buffer_size >> 5)) + /* * Send data to upload to the server, when the socket is writable. */ @@ -921,13 +940,25 @@ static CURLcode readwrite_upload(struct Curl_easy *data, do { curl_off_t nbody; + ssize_t offset = 0; + + if(0 != k->upload_present && + k->upload_present < curl_upload_refill_watermark(data) && + !k->upload_chunky &&/*(variable sized chunked header; append not safe)*/ + !k->upload_done && /*!(k->upload_done once k->upload_present sent)*/ + !(k->writebytecount + k->upload_present - k->pendingheader == + data->state.infilesize)) { + offset = k->upload_present; + } /* only read more data if there's no upload data already - present in the upload buffer */ - if(0 == k->upload_present) { + present in the upload buffer, or if appending to upload buffer */ + if(0 == k->upload_present || offset) { result = Curl_get_upload_buffer(data); if(result) return result; + if(offset && k->upload_fromhere != data->state.ulbuf) + memmove(data->state.ulbuf, k->upload_fromhere, offset); /* init the "upload from here" pointer */ k->upload_fromhere = data->state.ulbuf; @@ -960,12 +991,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data, sending_http_headers = FALSE; } - result = Curl_fillreadbuffer(data, data->set.upload_buffer_size, + k->upload_fromhere += offset; + result = Curl_fillreadbuffer(data, data->set.upload_buffer_size-offset, &fillcount); + k->upload_fromhere -= offset; if(result) return result; - nread = fillcount; + nread = offset + fillcount; } else nread = 0; /* we're done uploading/reading */ @@ -1007,7 +1040,9 @@ static CURLcode readwrite_upload(struct Curl_easy *data, * That means the hex values for ASCII CR (0x0d) & LF (0x0a) * must be used instead of the escape sequences \r & \n. */ - for(i = 0, si = 0; i < nread; i++, si++) { + if(offset) + memcpy(data->state.scratch, k->upload_fromhere, offset); + for(i = offset, si = offset; i < nread; i++, si++) { if(k->upload_fromhere[i] == 0x0a) { data->state.scratch[si++] = 0x0d; data->state.scratch[si] = 0x0a; @@ -1037,12 +1072,12 @@ static CURLcode readwrite_upload(struct Curl_easy *data, #ifndef CURL_DISABLE_SMTP if(conn->handler->protocol & PROTO_FAMILY_SMTP) { - result = Curl_smtp_escape_eob(data, nread); + result = Curl_smtp_escape_eob(data, nread, offset); if(result) return result; } #endif /* CURL_DISABLE_SMTP */ - } /* if 0 == k->upload_present */ + } /* if 0 == k->upload_present or appended to upload buffer */ else { /* We have a partial buffer left from a previous "round". Use that instead of reading more data */ @@ -1153,10 +1188,12 @@ CURLcode Curl_readwrite(struct connectdata *conn, else fd_write = CURL_SOCKET_BAD; +#if defined(USE_HTTP2) || defined(USE_HTTP3) if(data->state.drain) { select_res |= CURL_CSELECT_IN; DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data")); } +#endif if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ @@ -1222,6 +1259,14 @@ CURLcode Curl_readwrite(struct connectdata *conn, infof(data, "Done waiting for 100-continue"); } } + +#ifdef ENABLE_QUIC + if(conn->transport == TRNSPRT_QUIC) { + result = Curl_quic_idle(data); + if(result) + return result; + } +#endif } if(Curl_pgrsUpdate(data)) @@ -1394,7 +1439,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) if(result) return result; - data->state.wildcardmatch = data->set.wildcard_enabled; + data->state.requests = 0; 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 */ @@ -1416,10 +1461,11 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) else data->state.infilesize = 0; +#ifndef CURL_DISABLE_COOKIES /* If there is a list of cookie files to read, do it now! */ if(data->state.cookielist) Curl_cookie_loadfiles(data); - +#endif /* If there is a list of host pairs to deal with */ if(data->state.resolve) result = Curl_loadhostpairs(data); @@ -1449,6 +1495,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) data->state.authproxy.picked &= data->state.authproxy.want; #ifndef CURL_DISABLE_FTP + data->state.wildcardmatch = data->set.wildcard_enabled; if(data->state.wildcardmatch) { struct WildcardData *wc = &data->wildcard; if(wc->state < CURLWC_INIT) { @@ -1562,7 +1609,7 @@ CURLcode Curl_follow(struct Curl_easy *data, data->state.referer_alloc = FALSE; } - /* Make a copy of the URL without crenditals and fragment */ + /* Make a copy of the URL without credentials and fragment */ u = curl_url(); if(!u) return CURLE_OUT_OF_MEMORY; @@ -1590,7 +1637,7 @@ CURLcode Curl_follow(struct Curl_easy *data, if((type != FOLLOW_RETRY) && (data->req.httpcode != 401) && (data->req.httpcode != 407) && - Curl_is_absolute_url(newurl, NULL, 0)) + Curl_is_absolute_url(newurl, NULL, 0, FALSE)) /* If this is not redirect due to a 401 or 407 response and an absolute URL: don't allow a custom port number */ disallowport = TRUE; @@ -1599,10 +1646,14 @@ CURLcode Curl_follow(struct Curl_easy *data, uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME : ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) | - CURLU_ALLOW_SPACE); + CURLU_ALLOW_SPACE | + (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); if(uc) { - if(type != FOLLOW_FAKE) + if(type != FOLLOW_FAKE) { + failf(data, "The redirect target URL could not be parsed: %s", + curl_url_strerror(uc)); return Curl_uc_to_curlcode(uc); + } /* the URL could not be parsed for some reason, but since this is FAKE mode, just duplicate the field as-is */ @@ -1649,7 +1700,7 @@ CURLcode Curl_follow(struct Curl_easy *data, return Curl_uc_to_curlcode(uc); } - p = Curl_builtin_scheme(scheme); + p = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED); if(p && (p->protocol != data->info.conn_protocol)) { infof(data, "Clear auth, redirects scheme from %s to %s", data->info.conn_scheme, scheme); @@ -1813,10 +1864,12 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url) return CURLE_OK; if((data->req.bytecount + data->req.headerbytecount == 0) && - conn->bits.reuse && - (!data->set.opt_no_body - || (conn->handler->protocol & PROTO_FAMILY_HTTP)) && - (data->set.rtspreq != RTSPREQ_RECEIVE)) + conn->bits.reuse && + (!data->set.opt_no_body || (conn->handler->protocol & PROTO_FAMILY_HTTP)) +#ifndef CURL_DISABLE_RTSP + && (data->set.rtspreq != RTSPREQ_RECEIVE) +#endif + ) /* We got no data, we attempted to re-use a connection. For HTTP this can be a retry so we try again regardless if we expected a body. For other protocols we only try again only if we expected a body. @@ -1888,11 +1941,14 @@ Curl_setup_transfer( struct SingleRequest *k = &data->req; struct connectdata *conn = data->conn; struct HTTP *http = data->req.p.http; - bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && - (http->sending == HTTPSEND_REQUEST)); + bool httpsending; + DEBUGASSERT(conn != NULL); DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); + httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_REQUEST)); + if(conn->bits.multiplex || conn->httpversion == 20 || httpsending) { /* when multiplexing, the read/write sockets need to be the same! */ conn->sockfd = sockindex == -1 ? diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h index 56d2fd1..65fe68e 100644 --- a/Utilities/cmcurl/lib/transfer.h +++ b/Utilities/cmcurl/lib/transfer.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #define Curl_headersep(x) ((((x)==':') || ((x)==';'))) diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index 6b31d4b..be5ffca 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -71,10 +73,11 @@ #endif #elif defined(USE_WIN32_IDN) -/* prototype for curl_win32_idn_to_ascii() */ -bool curl_win32_idn_to_ascii(const char *in, char **out); +/* prototype for Curl_win32_idn_to_ascii() */ +bool Curl_win32_idn_to_ascii(const char *in, char **out); #endif /* USE_LIBIDN2 */ +#include "doh.h" #include "urldata.h" #include "netrc.h" @@ -103,6 +106,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "urlapi-int.h" #include "system_win32.h" #include "hsts.h" +#include "noproxy.h" /* And now for the protocols */ #include "ftp.h" @@ -125,7 +129,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "http_proxy.h" #include "conncache.h" #include "multihandle.h" -#include "dotdot.h" #include "strdup.h" #include "setopt.h" #include "altsvc.h" @@ -147,6 +150,13 @@ static void conn_free(struct connectdata *conn); # error READBUFFER_SIZE is too small #endif +#ifdef USE_UNIX_SOCKETS +#define UNIX_SOCKET_PREFIX "localhost" +#endif + +/* Reject URLs exceeding this length */ +#define MAX_URL_LEN 0xffff + /* * get_protocol_family() * @@ -158,7 +168,7 @@ static void conn_free(struct connectdata *conn); * * Returns the family as a single bit protocol identifier. */ -static unsigned int get_protocol_family(const struct Curl_handler *h) +static curl_prot_t get_protocol_family(const struct Curl_handler *h) { DEBUGASSERT(h); DEBUGASSERT(h->family); @@ -182,6 +192,16 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_http, #endif +#ifdef USE_WEBSOCKETS +#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP) + &Curl_handler_wss, +#endif + +#ifndef CURL_DISABLE_HTTP + &Curl_handler_ws, +#endif +#endif + #ifndef CURL_DISABLE_FTP &Curl_handler_ftp, #endif @@ -433,6 +453,7 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->info.wouldredirect); /* this destroys the channel and we cannot use it anymore after this */ + Curl_resolver_cancel(data); Curl_resolver_cleanup(data->state.async.resolver); Curl_http2_cleanup_dependencies(data); @@ -495,7 +516,6 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) /* use fread as default function to read input */ set->fread_func_set = (curl_read_callback)fread; set->is_fread_set = 0; - set->is_fwrite_set = 0; set->seek_func = ZERO_NULL; set->seek_client = ZERO_NULL; @@ -505,7 +525,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->maxredirs = -1; /* allow any amount by default */ set->method = HTTPREQ_GET; /* Default HTTP request */ +#ifndef CURL_DISABLE_RTSP set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */ +#endif #ifndef CURL_DISABLE_FTP set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */ set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */ @@ -521,10 +543,12 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->proxyport = 0; set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ - set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ +#ifndef CURL_DISABLE_PROXY + set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ /* SOCKS5 proxy auth defaults to username/password + GSS-API */ set->socks5auth = CURLAUTH_BASIC | CURLAUTH_GSSAPI; +#endif /* make libcurl quiet by default: */ set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */ @@ -544,8 +568,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) #ifdef USE_TLS_SRP set->ssl.primary.authtype = CURL_TLSAUTH_NONE; #endif - set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth - type */ + /* defaults to any auth type */ + set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by default */ #ifndef CURL_DISABLE_PROXY @@ -554,11 +578,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ - - /* for the *protocols fields we don't use the CURLPROTO_ALL convenience - define since we internally only use the lower 16 bits for the passed - in bitmask to not conflict with the private bits */ - set->allowed_protocols = CURLPROTO_ALL; + set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL; set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | CURLPROTO_FTPS; @@ -598,22 +618,23 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) #endif } +#ifndef CURL_DISABLE_FTP set->wildcard_enabled = FALSE; set->chunk_bgn = ZERO_NULL; set->chunk_end = ZERO_NULL; + set->fnmatch = ZERO_NULL; +#endif set->tcp_keepalive = FALSE; set->tcp_keepintvl = 60; set->tcp_keepidle = 60; set->tcp_fastopen = FALSE; set->tcp_nodelay = TRUE; - set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; set->expect_100_timeout = 1000L; /* Wait for a second by default. */ set->sep_headers = TRUE; /* separated header lists by default */ set->buffer_size = READBUFFER_SIZE; set->upload_buffer_size = UPLOADBUFFER_DEFAULT; set->happy_eyeballs_timeout = CURL_HET_DEFAULT; - set->fnmatch = ZERO_NULL; set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ set->maxage_conn = 118; @@ -730,15 +751,6 @@ static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn) DEBUGASSERT(data); 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); @@ -853,7 +865,7 @@ void Curl_disconnect(struct Curl_easy *data, /* Cleanup NEGOTIATE connection-related data */ Curl_http_auth_cleanup_negotiate(conn); - if(conn->bits.connect_only) + if(conn->connect_only) /* treat the connection as dead in CONNECT_ONLY situations */ dead_connection = TRUE; @@ -937,19 +949,11 @@ 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://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */ - 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 != !needle->passwd) - return FALSE; - /* curl_strequal does a case insentive comparison, so do not use it here! */ - if(data->passwd && - needle->passwd && - strcmp(data->passwd, needle->passwd) != 0) + + /* curl_strequal does a case insensitive comparison, + so do not use it here! */ + if(Curl_timestrcmp(data->user, needle->user) || + Curl_timestrcmp(data->passwd, needle->passwd)) return FALSE; return TRUE; } @@ -1100,12 +1104,17 @@ static void prune_dead_connections(struct Curl_easy *data) } } +#ifdef USE_SSH static bool ssh_config_matches(struct connectdata *one, struct connectdata *two) { return (Curl_safecmp(one->proto.sshc.rsa, two->proto.sshc.rsa) && Curl_safecmp(one->proto.sshc.rsa_pub, two->proto.sshc.rsa_pub)); } +#else +#define ssh_config_matches(x,y) FALSE +#endif + /* * Given one filled in connection struct (named needle), this function should * detect if there already is one that has all the significant details @@ -1194,7 +1203,7 @@ ConnectionExists(struct Curl_easy *data, check = curr->ptr; curr = curr->next; - if(check->bits.connect_only || check->bits.close) + if(check->connect_only || check->bits.close) /* connect-only or to-be-closed connections will not be reused */ continue; @@ -1346,10 +1355,10 @@ ConnectionExists(struct Curl_easy *data, if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ - if(strcmp(needle->user, check->user) || - strcmp(needle->passwd, check->passwd) || - !Curl_safecmp(needle->sasl_authzid, check->sasl_authzid) || - !Curl_safecmp(needle->oauth_bearer, check->oauth_bearer)) { + if(Curl_timestrcmp(needle->user, check->user) || + Curl_timestrcmp(needle->passwd, check->passwd) || + Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) || + Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) { /* one of them was different */ continue; } @@ -1425,8 +1434,8 @@ ConnectionExists(struct Curl_easy *data, possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { - if(strcmp(needle->user, check->user) || - strcmp(needle->passwd, check->passwd)) { + if(Curl_timestrcmp(needle->user, check->user) || + Curl_timestrcmp(needle->passwd, check->passwd)) { /* we prefer a credential match, but this is at least a connection that can be reused and "upgraded" to NTLM */ @@ -1448,8 +1457,10 @@ ConnectionExists(struct Curl_easy *data, if(!check->http_proxy.user || !check->http_proxy.passwd) continue; - if(strcmp(needle->http_proxy.user, check->http_proxy.user) || - strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) + if(Curl_timestrcmp(needle->http_proxy.user, + check->http_proxy.user) || + Curl_timestrcmp(needle->http_proxy.passwd, + check->http_proxy.passwd)) continue; } else if(check->proxy_ntlm_state != NTLMSTATE_NONE) { @@ -1621,7 +1632,7 @@ CURLcode Curl_idnconvert_hostname(struct Curl_easy *data, #elif defined(USE_WIN32_IDN) char *ace_hostname = NULL; - if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) { + if(Curl_win32_idn_to_ascii(host->name, &ace_hostname)) { host->encalloc = ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; @@ -1652,7 +1663,7 @@ void Curl_free_idnconverted_hostname(struct hostname *host) } #elif defined(USE_WIN32_IDN) free(host->encalloc); /* must be freed with free() since this was - allocated by curl_win32_idn_to_ascii */ + allocated by Curl_win32_idn_to_ascii */ host->encalloc = NULL; #else (void)host; @@ -1770,19 +1781,15 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; conn->ssl_config.ssl_options = data->set.ssl.primary.ssl_options; -#ifdef USE_TLS_SRP -#endif #ifndef CURL_DISABLE_PROXY conn->proxy_ssl_config.verifystatus = data->set.proxy_ssl.primary.verifystatus; conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; conn->proxy_ssl_config.ssl_options = data->set.proxy_ssl.primary.ssl_options; -#ifdef USE_TLS_SRP -#endif #endif conn->ip_version = data->set.ipver; - conn->bits.connect_only = data->set.connect_only; + conn->connect_only = data->set.connect_only; conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */ #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \ @@ -1826,15 +1833,18 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) } /* returns the handler if the given scheme is built-in */ -const struct Curl_handler *Curl_builtin_scheme(const char *scheme) +const struct Curl_handler *Curl_builtin_scheme(const char *scheme, + size_t schemelen) { const struct Curl_handler * const *pp; const struct Curl_handler *p; /* Scan protocol handler table and match against 'scheme'. The handler may be changed later when the protocol specific setup function is called. */ + if(schemelen == CURL_ZERO_TERMINATED) + schemelen = strlen(scheme); for(pp = protocols; (p = *pp) != NULL; pp++) - if(strcasecompare(p->scheme, scheme)) - /* Protocol found in table. Check if allowed */ + if(strncasecompare(p->scheme, scheme, schemelen) && !p->scheme[schemelen]) + /* Protocol found in table. */ return p; return NULL; /* not found */ } @@ -1844,7 +1854,8 @@ static CURLcode findprotocol(struct Curl_easy *data, struct connectdata *conn, const char *protostr) { - const struct Curl_handler *p = Curl_builtin_scheme(protostr); + const struct Curl_handler *p = Curl_builtin_scheme(protostr, + CURL_ZERO_TERMINATED); if(p && /* Protocol found in table. Check if allowed */ (data->set.allowed_protocols & p->protocol)) { @@ -1968,7 +1979,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; if(data->set.str[STRING_DEFAULT_PROTOCOL] && - !Curl_is_absolute_url(data->state.url, NULL, 0)) { + !Curl_is_absolute_url(data->state.url, NULL, 0, TRUE)) { char *url = aprintf("%s://%s", data->set.str[STRING_DEFAULT_PROTOCOL], data->state.url); if(!url) @@ -2012,10 +2023,60 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, if(!strcasecompare("file", data->state.up.scheme)) return CURLE_OUT_OF_MEMORY; } + else if(strlen(data->state.up.hostname) > MAX_URL_LEN) { + failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN); + return CURLE_URL_MALFORMAT; + } + hostname = data->state.up.hostname; + + if(hostname && hostname[0] == '[') { + /* This looks like an IPv6 address literal. See if there is an address + scope. */ + size_t hlen; + conn->bits.ipv6_ip = TRUE; + /* cut off the brackets! */ + hostname++; + hlen = strlen(hostname); + hostname[hlen - 1] = 0; + + zonefrom_url(uh, data, conn); + } + + /* make sure the connect struct gets its own copy of the host name */ + conn->host.rawalloc = strdup(hostname ? hostname : ""); + if(!conn->host.rawalloc) + return CURLE_OUT_OF_MEMORY; + conn->host.name = conn->host.rawalloc; + + /************************************************************* + * IDN-convert the hostnames + *************************************************************/ + result = Curl_idnconvert_hostname(data, &conn->host); + if(result) + return result; + if(conn->bits.conn_to_host) { + result = Curl_idnconvert_hostname(data, &conn->conn_to_host); + if(result) + return result; + } +#ifndef CURL_DISABLE_PROXY + if(conn->bits.httpproxy) { + result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); + if(result) + return result; + } + if(conn->bits.socksproxy) { + result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); + if(result) + return result; + } +#endif #ifndef CURL_DISABLE_HSTS + /* HSTS upgrade */ if(data->hsts && strcasecompare("http", data->state.up.scheme)) { - if(Curl_hsts(data->hsts, data->state.up.hostname, TRUE)) { + /* This MUST use the IDN decoded name */ + if(Curl_hsts(data->hsts, conn->host.name, TRUE)) { char *url; Curl_safefree(data->state.up.scheme); uc = curl_url_set(uh, CURLUPART_SCHEME, "https", 0); @@ -2066,7 +2127,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, return Curl_uc_to_curlcode(uc); } - if(!data->state.aptr.user) { + if(!data->set.str[STRING_USERNAME]) { /* 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 */ @@ -2101,7 +2162,8 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, else if(uc != CURLUE_NO_OPTIONS) return Curl_uc_to_curlcode(uc); - uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, 0); + uc = curl_url_get(uh, CURLUPART_PATH, &data->state.up.path, + CURLU_URLENCODE); if(uc) return Curl_uc_to_curlcode(uc); @@ -2115,31 +2177,11 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, unsigned long port = strtoul(data->state.up.port, NULL, 10); conn->port = conn->remote_port = (data->set.use_port && data->state.allow_port) ? - (int)data->set.use_port : curlx_ultous(port); + data->set.use_port : curlx_ultous(port); } (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0); - hostname = data->state.up.hostname; - if(hostname && hostname[0] == '[') { - /* This looks like an IPv6 address literal. See if there is an address - scope. */ - size_t hlen; - conn->bits.ipv6_ip = TRUE; - /* cut off the brackets! */ - hostname++; - hlen = strlen(hostname); - hostname[hlen - 1] = 0; - - zonefrom_url(uh, data, conn); - } - - /* make sure the connect struct gets its own copy of the host name */ - conn->host.rawalloc = strdup(hostname ? hostname : ""); - if(!conn->host.rawalloc) - return CURLE_OUT_OF_MEMORY; - conn->host.name = conn->host.rawalloc; - #ifdef ENABLE_IPV6 if(data->set.scope_id) /* Override any scope that was set above. */ @@ -2237,83 +2279,6 @@ void Curl_free_request_state(struct Curl_easy *data) #ifndef CURL_DISABLE_PROXY -/**************************************************************** -* Checks if the host is in the noproxy list. returns true if it matches -* and therefore the proxy should NOT be used. -****************************************************************/ -static bool check_noproxy(const char *name, const char *no_proxy) -{ - /* no_proxy=domain1.dom,host.domain2.dom - * (a comma-separated list of hosts which should - * not be proxied, or an asterisk to override - * all proxy variables) - */ - if(no_proxy && no_proxy[0]) { - size_t tok_start; - size_t tok_end; - const char *separator = ", "; - size_t no_proxy_len; - size_t namelen; - char *endptr; - if(strcasecompare("*", no_proxy)) { - return TRUE; - } - - /* NO_PROXY was specified and it wasn't just an asterisk */ - - no_proxy_len = strlen(no_proxy); - if(name[0] == '[') { - /* IPv6 numerical address */ - endptr = strchr(name, ']'); - if(!endptr) - return FALSE; - name++; - namelen = endptr - name; - } - else - namelen = strlen(name); - - for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) { - while(tok_start < no_proxy_len && - strchr(separator, no_proxy[tok_start]) != NULL) { - /* Look for the beginning of the token. */ - ++tok_start; - } - - if(tok_start == no_proxy_len) - break; /* It was all trailing separator chars, no more tokens. */ - - for(tok_end = tok_start; tok_end < no_proxy_len && - strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) - /* Look for the end of the token. */ - ; - - /* To match previous behavior, where it was necessary to specify - * ".local.com" to prevent matching "notlocal.com", we will leave - * the '.' off. - */ - if(no_proxy[tok_start] == '.') - ++tok_start; - - if((tok_end - tok_start) <= namelen) { - /* Match the last part of the name to the domain we are checking. */ - const char *checkn = name + namelen - (tok_end - tok_start); - if(strncasecompare(no_proxy + tok_start, checkn, - tok_end - tok_start)) { - if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { - /* We either have an exact match, or the previous character is a . - * so it is within the same domain, so no proxy for this host. - */ - return TRUE; - } - } - } /* if((tok_end - tok_start) <= namelen) */ - } /* for(tok_start = 0; tok_start < no_proxy_len; - tok_start = tok_end + 1) */ - } /* NO_PROXY was specified and it wasn't just an asterisk */ - - return FALSE; -} #ifndef CURL_DISABLE_HTTP /**************************************************************** @@ -2353,7 +2318,7 @@ static char *detect_proxy(struct Curl_easy *data, /* Now, build <protocol>_proxy and check for such a one to use */ while(*protop) - *envp++ = (char)tolower((int)*protop++); + *envp++ = Curl_raw_tolower(*protop++); /* append _proxy */ strcpy(envp, "_proxy"); @@ -2411,13 +2376,18 @@ static CURLcode parse_proxy(struct Curl_easy *data, int port = -1; char *proxyuser = NULL; char *proxypasswd = NULL; - char *host; + char *host = NULL; bool sockstype; CURLUcode uc; struct proxy_info *proxyinfo; CURLU *uhp = curl_url(); CURLcode result = CURLE_OK; char *scheme = NULL; +#ifdef USE_UNIX_SOCKETS + char *path = NULL; + bool is_unix_proxy = FALSE; +#endif + if(!uhp) { result = CURLE_OUT_OF_MEMORY; @@ -2542,21 +2512,54 @@ static CURLcode parse_proxy(struct Curl_easy *data, result = CURLE_OUT_OF_MEMORY; goto error; } - Curl_safefree(proxyinfo->host.rawalloc); - proxyinfo->host.rawalloc = host; - if(host[0] == '[') { - /* this is a numerical IPv6, strip off the brackets */ - size_t len = strlen(host); - host[len-1] = 0; /* clear the trailing bracket */ - host++; - zonefrom_url(uhp, data, conn); +#ifdef USE_UNIX_SOCKETS + if(sockstype && strcasecompare(UNIX_SOCKET_PREFIX, host)) { + uc = curl_url_get(uhp, CURLUPART_PATH, &path, CURLU_URLDECODE); + if(uc) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + /* path will be "/", if no path was was found */ + if(strcmp("/", path)) { + is_unix_proxy = TRUE; + free(host); + host = aprintf(UNIX_SOCKET_PREFIX"%s", path); + if(!host) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + Curl_safefree(proxyinfo->host.rawalloc); + proxyinfo->host.rawalloc = host; + proxyinfo->host.name = host; + host = NULL; + } + } + + if(!is_unix_proxy) { +#endif + Curl_safefree(proxyinfo->host.rawalloc); + proxyinfo->host.rawalloc = host; + if(host[0] == '[') { + /* this is a numerical IPv6, strip off the brackets */ + size_t len = strlen(host); + host[len-1] = 0; /* clear the trailing bracket */ + host++; + zonefrom_url(uhp, data, conn); + } + proxyinfo->host.name = host; + host = NULL; +#ifdef USE_UNIX_SOCKETS } - proxyinfo->host.name = host; +#endif error: free(proxyuser); free(proxypasswd); + free(host); free(scheme); +#ifdef USE_UNIX_SOCKETS + free(path); +#endif curl_url_cleanup(uhp); return result; } @@ -2644,8 +2647,8 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, } } - if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? - data->set.str[STRING_NOPROXY] : no_proxy)) { + if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ? + data->set.str[STRING_NOPROXY] : no_proxy)) { Curl_safefree(proxy); Curl_safefree(socksproxy); } @@ -2683,16 +2686,16 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, * connection that may exist registered to the same proxy host. ***********************************************************************/ if(proxy || socksproxy) { + curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype; if(proxy) { - result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); + result = parse_proxy(data, conn, proxy, ptype); Curl_safefree(proxy); /* parse_proxy copies the proxy string */ if(result) goto out; } if(socksproxy) { - result = parse_proxy(data, conn, socksproxy, - conn->socks_proxy.proxytype); + result = parse_proxy(data, conn, socksproxy, ptype); /* parse_proxy copies the socks proxy string */ Curl_safefree(socksproxy); if(result) @@ -2842,15 +2845,15 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, (psep && psep > osep ? (size_t)(psep - osep) : (size_t)(login + len - osep)) - 1 : 0); - /* Allocate the user portion buffer */ - if(userp && ulen) { + /* Allocate the user portion buffer, which can be zero length */ + if(userp) { ubuf = malloc(ulen + 1); if(!ubuf) result = CURLE_OUT_OF_MEMORY; } /* Allocate the password portion buffer */ - if(!result && passwdp && plen) { + if(!result && passwdp && psep) { pbuf = malloc(plen + 1); if(!pbuf) { free(ubuf); @@ -2913,7 +2916,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data, /* if set, we use this instead of the port possibly given in the URL */ char portbuf[16]; CURLUcode uc; - conn->remote_port = (unsigned short)data->set.use_port; + conn->remote_port = data->set.use_port; msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port); uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0); if(uc) @@ -2935,14 +2938,6 @@ static CURLcode override_login(struct Curl_easy *data, char **passwdp = &conn->passwd; char **optionsp = &conn->options; -#ifndef CURL_DISABLE_NETRC - if(data->set.use_netrc == CURL_NETRC_REQUIRED && data->state.aptr.user) { - Curl_safefree(*userp); - Curl_safefree(*passwdp); - Curl_safefree(data->state.aptr.user); /* disable user+password */ - } -#endif - if(data->set.str[STRING_OPTIONS]) { free(*optionsp); *optionsp = strdup(data->set.str[STRING_OPTIONS]); @@ -2951,29 +2946,31 @@ static CURLcode override_login(struct Curl_easy *data, } #ifndef CURL_DISABLE_NETRC + if(data->set.use_netrc == CURL_NETRC_REQUIRED) { + Curl_safefree(*userp); + Curl_safefree(*passwdp); + } conn->bits.netrc = FALSE; if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { - bool netrc_user_changed = FALSE; - bool netrc_passwd_changed = FALSE; int ret; bool url_provided = FALSE; - if(data->state.up.user) { - /* there was a user name in the URL */ - userp = &data->state.up.user; + if(data->state.aptr.user) { + /* there was a user name in the URL. Use the URL decoded version */ + userp = &data->state.aptr.user; url_provided = TRUE; } ret = Curl_parsenetrc(conn->host.name, userp, passwdp, - &netrc_user_changed, &netrc_passwd_changed, data->set.str[STRING_NETRC_FILE]); if(ret > 0) { 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; + failf(data, ".netrc parser error"); + return CURLE_READ_ERROR; } else { /* set bits.netrc TRUE to remember that we got the name from a .netrc @@ -2986,29 +2983,35 @@ static CURLcode override_login(struct Curl_easy *data, conn->user = strdup(*userp); if(!conn->user) return CURLE_OUT_OF_MEMORY; - /* don't update the user name below */ - userp = NULL; + } + /* no user was set but a password, set a blank user */ + if(userp && !*userp && *passwdp) { + *userp = strdup(""); + if(!*userp) + return CURLE_OUT_OF_MEMORY; } } #endif /* for updated strings, we update them in the URL */ - if(userp) { - if(*userp) { - CURLcode result = Curl_setstropt(&data->state.aptr.user, *userp); + if(*userp) { + CURLcode result; + if(data->state.aptr.user != *userp) { + /* nothing to do then */ + 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(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(*passwdp) { @@ -3361,131 +3364,166 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, return result; } -/************************************************************* - * Resolve the address of the server or proxy - *************************************************************/ -static CURLcode resolve_server(struct Curl_easy *data, - struct connectdata *conn, - bool *async) +#ifdef USE_UNIX_SOCKETS +static CURLcode resolve_unix(struct Curl_easy *data, + struct connectdata *conn, + char *unix_path) { - CURLcode result = CURLE_OK; + struct Curl_dns_entry *hostaddr = NULL; + bool longpath = FALSE; + + DEBUGASSERT(unix_path); + DEBUGASSERT(conn->dns_entry == NULL); + + /* Unix domain sockets are local. The host gets ignored, just use the + * specified domain socket address. Do not cache "DNS entries". There is + * no DNS involved and we already have the filesystem path available. */ + hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); + if(!hostaddr) + return CURLE_OUT_OF_MEMORY; + + hostaddr->addr = Curl_unix2addr(unix_path, &longpath, + conn->bits.abstract_unix_socket); + if(!hostaddr->addr) { + if(longpath) + /* Long paths are not supported for now */ + failf(data, "Unix socket path too long: '%s'", unix_path); + free(hostaddr); + return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY; + } + + hostaddr->inuse++; + conn->dns_entry = hostaddr; + return CURLE_OK; +} +#endif + +#ifndef CURL_DISABLE_PROXY +static CURLcode resolve_proxy(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + struct Curl_dns_entry *hostaddr = NULL; + struct hostname *host; timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + int rc; - DEBUGASSERT(conn); - DEBUGASSERT(data); - /************************************************************* - * Resolve the name of the server or proxy - *************************************************************/ - if(conn->bits.reuse) - /* We're reusing the connection - no need to resolve anything, and - idnconvert_hostname() was called already in create_conn() for the re-use - case. */ - *async = FALSE; + DEBUGASSERT(conn->dns_entry == NULL); - else { - /* this is a fresh connect */ - int rc; - struct Curl_dns_entry *hostaddr = NULL; + host = conn->bits.socksproxy ? &conn->socks_proxy.host : + &conn->http_proxy.host; -#ifdef USE_UNIX_SOCKETS - if(conn->unix_domain_socket) { - /* Unix domain sockets are local. The host gets ignored, just use the - * specified domain socket address. Do not cache "DNS entries". There is - * no DNS involved and we already have the filesystem path available */ - const char *path = conn->unix_domain_socket; - - hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); - if(!hostaddr) - result = CURLE_OUT_OF_MEMORY; - else { - bool longpath = FALSE; - hostaddr->addr = Curl_unix2addr(path, &longpath, - conn->bits.abstract_unix_socket); - if(hostaddr->addr) - hostaddr->inuse++; - else { - /* Long paths are not supported for now */ - if(longpath) { - failf(data, "Unix socket path too long: '%s'", path); - result = CURLE_COULDNT_RESOLVE_HOST; - } - else - result = CURLE_OUT_OF_MEMORY; - free(hostaddr); - hostaddr = NULL; - } - } - } - else + conn->hostname_resolve = strdup(host->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; + + rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, + &hostaddr, timeout_ms); + conn->dns_entry = hostaddr; + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + else if(rc == CURLRESOLV_TIMEDOUT) + return CURLE_OPERATION_TIMEDOUT; + else if(!hostaddr) { + failf(data, "Couldn't resolve proxy '%s'", host->dispname); + return CURLE_COULDNT_RESOLVE_PROXY; + } + + return CURLE_OK; +} #endif - if(!CONN_IS_PROXIED(conn)) { - struct hostname *connhost; - if(conn->bits.conn_to_host) - connhost = &conn->conn_to_host; - else - connhost = &conn->host; +static CURLcode resolve_host(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + struct Curl_dns_entry *hostaddr = NULL; + struct hostname *connhost; + timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + int rc; - /* If not connecting via a proxy, extract the port from the URL, if it is - * there, thus overriding any defaults that might have been set above. */ - if(conn->bits.conn_to_port) - conn->port = conn->conn_to_port; - else - conn->port = conn->remote_port; + DEBUGASSERT(conn->dns_entry == NULL); - /* Resolve target host right on */ - conn->hostname_resolve = strdup(connhost->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; - rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, - &hostaddr, timeout_ms); - if(rc == CURLRESOLV_PENDING) - *async = TRUE; - - 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, "Could not resolve host: %s", connhost->dispname); - result = CURLE_COULDNT_RESOLVE_HOST; - /* don't return yet, we need to clean up the timeout first */ - } - } -#ifndef CURL_DISABLE_PROXY - else { - /* This is a proxy that hasn't been resolved yet. */ + connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; - struct hostname * const host = conn->bits.socksproxy ? - &conn->socks_proxy.host : &conn->http_proxy.host; + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ + conn->port = conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; - /* resolve proxy */ - conn->hostname_resolve = strdup(host->name); - if(!conn->hostname_resolve) - return CURLE_OUT_OF_MEMORY; - rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, - &hostaddr, timeout_ms); + /* Resolve target host right on */ + conn->hostname_resolve = strdup(connhost->name); + if(!conn->hostname_resolve) + return CURLE_OUT_OF_MEMORY; - if(rc == CURLRESOLV_PENDING) - *async = TRUE; + rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port, + &hostaddr, timeout_ms); + conn->dns_entry = hostaddr; + if(rc == CURLRESOLV_PENDING) + *async = TRUE; + 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)); + return CURLE_OPERATION_TIMEDOUT; + } + else if(!hostaddr) { + failf(data, "Could not resolve host: %s", connhost->dispname); + return CURLE_COULDNT_RESOLVE_HOST; + } - else if(rc == CURLRESOLV_TIMEDOUT) - result = CURLE_OPERATION_TIMEDOUT; + return CURLE_OK; +} - else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", host->dispname); - result = CURLE_COULDNT_RESOLVE_PROXY; - /* don't return yet, we need to clean up the timeout first */ - } - } +/* Perform a fresh resolve */ +static CURLcode resolve_fresh(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ +#ifdef USE_UNIX_SOCKETS + char *unix_path = conn->unix_domain_socket; + +#ifndef CURL_DISABLE_PROXY + if(!unix_path && conn->socks_proxy.host.name && + !strncmp(UNIX_SOCKET_PREFIX"/", + conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX))) + unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1; #endif - DEBUGASSERT(conn->dns_entry == NULL); - conn->dns_entry = hostaddr; + + if(unix_path) { + conn->transport = TRNSPRT_UNIX; + return resolve_unix(data, conn, unix_path); } +#endif - return result; +#ifndef CURL_DISABLE_PROXY + if(CONN_IS_PROXIED(conn)) + return resolve_proxy(data, conn, async); +#endif + + return resolve_host(data, conn, async); +} + +/************************************************************* + * Resolve the address of the server or proxy + *************************************************************/ +static CURLcode resolve_server(struct Curl_easy *data, + struct connectdata *conn, + bool *async) +{ + DEBUGASSERT(conn); + DEBUGASSERT(data); + + /* Resolve the name of the server or proxy */ + if(conn->bits.reuse) { + /* We're reusing the connection - no need to resolve anything, and + idnconvert_hostname() was called already in create_conn() for the re-use + case. */ + *async = FALSE; + return CURLE_OK; + } + + return resolve_fresh(data, conn, async); } /* @@ -3502,17 +3540,6 @@ static void reuse_conn(struct Curl_easy *data, **established** from the primary socket to a remote address. */ char local_ip[MAX_IPADR_LEN] = ""; 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); - - free(old_conn->http_proxy.host.rawalloc); - free(old_conn->socks_proxy.host.rawalloc); - Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); -#endif - /* free the SSL config struct from this connection struct as this was - allocated in vain and is targeted for destruction */ - Curl_free_primary_ssl_config(&old_conn->ssl_config); /* 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 */ @@ -3543,20 +3570,17 @@ static void reuse_conn(struct Curl_easy *data, old_conn->http_proxy.passwd = NULL; old_conn->socks_proxy.passwd = NULL; } - Curl_safefree(old_conn->http_proxy.user); - Curl_safefree(old_conn->socks_proxy.user); - Curl_safefree(old_conn->http_proxy.passwd); - Curl_safefree(old_conn->socks_proxy.passwd); #endif - /* host can change, when doing keepalive with a proxy or if the case is - different this time etc */ Curl_free_idnconverted_hostname(&conn->host); Curl_free_idnconverted_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); Curl_safefree(conn->conn_to_host.rawalloc); conn->host = old_conn->host; + old_conn->host.rawalloc = NULL; + old_conn->host.encalloc = NULL; conn->conn_to_host = old_conn->conn_to_host; + old_conn->conn_to_host.rawalloc = NULL; conn->conn_to_port = old_conn->conn_to_port; conn->remote_port = old_conn->remote_port; Curl_safefree(conn->hostname_resolve); @@ -3576,15 +3600,7 @@ static void reuse_conn(struct Curl_easy *data, /* re-use init */ conn->bits.reuse = TRUE; /* yes, we're re-using here */ - Curl_safefree(old_conn->user); - Curl_safefree(old_conn->passwd); - Curl_safefree(old_conn->options); - Curl_safefree(old_conn->localdev); - Curl_llist_destroy(&old_conn->easyq, NULL); - -#ifdef USE_UNIX_SOCKETS - Curl_safefree(old_conn->unix_domain_socket); -#endif + conn_free(old_conn); } /** @@ -3714,29 +3730,6 @@ static CURLcode create_conn(struct Curl_easy *data, if(result) goto out; - /************************************************************* - * IDN-convert the hostnames - *************************************************************/ - result = Curl_idnconvert_hostname(data, &conn->host); - if(result) - goto out; - if(conn->bits.conn_to_host) { - result = Curl_idnconvert_hostname(data, &conn->conn_to_host); - if(result) - goto out; - } -#ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy) { - result = Curl_idnconvert_hostname(data, &conn->http_proxy.host); - if(result) - goto out; - } - if(conn->bits.socksproxy) { - result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host); - if(result) - goto out; - } -#endif /************************************************************* * Check whether the host and the "connect to host" are equal. @@ -3834,8 +3827,6 @@ static CURLcode create_conn(struct Curl_easy *data, 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]; data->set.ssl.primary.cipher_list13 = @@ -3849,9 +3840,6 @@ static CURLcode create_conn(struct Curl_easy *data, #ifndef CURL_DISABLE_PROXY data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; - data->set.proxy_ssl.primary.random_file = - data->set.str[STRING_SSL_RANDOM_FILE]; - data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; data->set.proxy_ssl.primary.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; data->set.proxy_ssl.primary.cipher_list13 = @@ -3934,10 +3922,6 @@ static CURLcode create_conn(struct Curl_easy *data, * allocated before we can move along and use the previously existing one. */ reuse_conn(data, conn, conn_temp); -#ifdef USE_SSL - free(conn->ssl_extra); -#endif - free(conn); /* we don't need this anymore */ conn = conn_temp; *in_connect = conn; @@ -3958,13 +3942,11 @@ static CURLcode create_conn(struct Curl_easy *data, be able to do that if we have reached the limit of how many connections we are allowed to open. */ - if(conn->handler->flags & PROTOPT_ALPN_NPN) { + if(conn->handler->flags & PROTOPT_ALPN) { /* The protocol wants it, so set the bits if enabled in the easy handle (default) */ if(data->set.ssl_enable_alpn) conn->bits.tls_enable_alpn = TRUE; - if(data->set.ssl_enable_npn) - conn->bits.tls_enable_npn = TRUE; } if(waitpipe) diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h index 59a1c24..ba4270d 100644 --- a/Utilities/cmcurl/lib/url.h +++ b/Utilities/cmcurl/lib/url.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -44,7 +46,8 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len, char **userptr, char **passwdptr, char **optionsptr); -const struct Curl_handler *Curl_builtin_scheme(const char *scheme); +const struct Curl_handler *Curl_builtin_scheme(const char *scheme, + size_t schemelen); bool Curl_is_ASCII_name(const char *hostname); CURLcode Curl_idnconvert_hostname(struct Curl_easy *data, diff --git a/Utilities/cmcurl/lib/urlapi-int.h b/Utilities/cmcurl/lib/urlapi-int.h index bd6b601..43a83ef 100644 --- a/Utilities/cmcurl/lib/urlapi-int.h +++ b/Utilities/cmcurl/lib/urlapi-int.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,13 +20,17 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" -bool Curl_is_absolute_url(const char *url, char *scheme, size_t buflen); +size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, + bool guess_scheme); #ifdef DEBUGBUILD -CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, bool); +CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, + bool has_scheme); #endif #endif /* HEADER_CURL_URLAPI_INT_H */ diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c index 2a36de6..7dac81c 100644 --- a/Utilities/cmcurl/lib/urlapi.c +++ b/Utilities/cmcurl/lib/urlapi.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -25,12 +27,12 @@ #include "urldata.h" #include "urlapi-int.h" #include "strcase.h" -#include "dotdot.h" #include "url.h" #include "escape.h" #include "curl_ctype.h" #include "inet_pton.h" #include "inet_ntop.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -66,9 +68,6 @@ struct Curl_URL { char *path; char *query; char *fragment; - - char *scratch; /* temporary scratch area */ - char *temppath; /* temporary path pointer */ long portnum; /* the numerical version */ }; @@ -86,8 +85,6 @@ static void free_urlhandle(struct Curl_URL *u) free(u->path); free(u->query); free(u->fragment); - free(u->scratch); - free(u->temppath); } /* @@ -119,91 +116,50 @@ static const char *find_host_sep(const char *url) } /* - * Decide in an encoding-independent manner whether a character in an - * URL must be escaped. The same criterion must be used in strlen_url() - * and strcpy_url(). + * Decide in an encoding-independent manner whether a character in a URL must + * be escaped. This is used in urlencode_str(). */ static bool urlchar_needs_escaping(int c) { return !(ISCNTRL(c) || ISSPACE(c) || ISGRAPH(c)); } -/* - * strlen_url() returns the length of the given URL if the spaces within the - * URL were properly URL encoded. - * URL encoding should be skipped for host names, otherwise IDN resolution - * will fail. - */ -static size_t strlen_url(const char *url, bool relative) -{ - const unsigned char *ptr; - size_t newlen = 0; - bool left = TRUE; /* left side of the ? */ - const unsigned char *host_sep = (const unsigned char *) url; - - if(!relative) - host_sep = (const unsigned char *) find_host_sep(url); - - for(ptr = (unsigned char *)url; *ptr; ptr++) { - - if(ptr < host_sep) { - ++newlen; - continue; - } - - if(*ptr == ' ') { - if(left) - newlen += 3; - else - newlen++; - continue; - } - - if (*ptr == '?') - left = FALSE; - - if(urlchar_needs_escaping(*ptr)) - newlen += 2; - - newlen++; - } - - return newlen; -} - -/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in - * the source URL accordingly. +/* urlencode_str() writes data into an output dynbuf and URL-encodes the + * spaces in the source URL accordingly. + * * URL encoding should be skipped for host names, otherwise IDN resolution * will fail. */ -static void strcpy_url(char *output, const char *url, bool relative) +static CURLUcode urlencode_str(struct dynbuf *o, const char *url, + size_t len, bool relative, + bool query) { /* we must add this with whitespace-replacing */ - bool left = TRUE; + bool left = !query; const unsigned char *iptr; - char *optr = output; const unsigned char *host_sep = (const unsigned char *) url; if(!relative) host_sep = (const unsigned char *) find_host_sep(url); for(iptr = (unsigned char *)url; /* read from here */ - *iptr; /* until zero byte */ - iptr++) { + len; iptr++, len--) { if(iptr < host_sep) { - *optr++ = *iptr; + if(Curl_dyn_addn(o, iptr, 1)) + return CURLUE_OUT_OF_MEMORY; continue; } if(*iptr == ' ') { if(left) { - *optr++='%'; /* add a '%' */ - *optr++='2'; /* add a '2' */ - *optr++='0'; /* add a '0' */ + if(Curl_dyn_addn(o, "%20", 3)) + return CURLUE_OUT_OF_MEMORY; + } + else { + if(Curl_dyn_addn(o, "+", 1)) + return CURLUE_OUT_OF_MEMORY; } - else - *optr++='+'; /* add a '+' here */ continue; } @@ -211,22 +167,28 @@ static void strcpy_url(char *output, const char *url, bool relative) left = FALSE; if(urlchar_needs_escaping(*iptr)) { - msnprintf(optr, 4, "%%%02x", *iptr); - optr += 3; + if(Curl_dyn_addf(o, "%%%02x", *iptr)) + return CURLUE_OUT_OF_MEMORY; + } + else { + if(Curl_dyn_addn(o, iptr, 1)) + return CURLUE_OUT_OF_MEMORY; } - else - *optr++ = *iptr; } - *optr = 0; /* null-terminate output buffer */ + return CURLUE_OK; } /* - * Returns true if the given URL is absolute (as opposed to relative). Returns - * the scheme in the buffer if TRUE and 'buf' is non-NULL. The buflen must - * be larger than MAX_SCHEME_LEN if buf is set. + * Returns the length of the scheme if the given URL is absolute (as opposed + * to relative). Stores the scheme in the buffer if TRUE and 'buf' is + * non-NULL. The buflen must be larger than MAX_SCHEME_LEN if buf is set. + * + * If 'guess_scheme' is TRUE, it means the URL might be provided without + * scheme. */ -bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) +size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen, + bool guess_scheme) { int i; DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN)); @@ -234,8 +196,8 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) if(buf) buf[0] = 0; /* always leave a defined value in buf */ #ifdef WIN32 - if(STARTS_WITH_DRIVE_PREFIX(url)) - return FALSE; + if(guess_scheme && STARTS_WITH_DRIVE_PREFIX(url)) + return 0; #endif for(i = 0; i < MAX_SCHEME_LEN; ++i) { char s = url[i]; @@ -248,16 +210,22 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) break; } } - if(i && (url[i] == ':') && (url[i + 1] == '/')) { + if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) { + /* If this does not guess scheme, the scheme always ends with the colon so + that this also detects data: URLs etc. In guessing mode, data: could + be the host name "data" with a specified port number. */ + + /* the length of the scheme is the name part only */ + size_t len = i; if(buf) { buf[i] = 0; while(i--) { - buf[i] = (char)TOLOWER(url[i]); + buf[i] = Curl_raw_tolower(url[i]); } } - return TRUE; + return len; } - return FALSE; + return 0; } /* @@ -265,34 +233,26 @@ bool Curl_is_absolute_url(const char *url, char *buf, size_t buflen) * URL-encodes any spaces. * The returned pointer must be freed by the caller unless NULL * (returns NULL on out of memory). + * + * Note that this function destroys the 'base' string. */ -static char *concat_url(const char *base, const char *relurl) +static char *concat_url(char *base, const char *relurl) { /*** TRY to append this new path to the old URL to the right of the host part. Oh crap, this is doomed to cause problems in the future... */ - char *newest; + struct dynbuf newest; char *protsep; char *pathsep; - size_t newlen; bool host_changed = FALSE; - const char *useurl = relurl; - size_t urllen; - - /* we must make our own copy of the URL to play with, as it may - point to read-only data */ - char *url_clone = strdup(base); - - if(!url_clone) - return NULL; /* skip out of this NOW */ /* protsep points to the start of the host name */ - protsep = strstr(url_clone, "//"); + protsep = strstr(base, "//"); if(!protsep) - protsep = url_clone; + protsep = base; else protsep += 2; /* pass the slashes */ @@ -385,38 +345,24 @@ static char *concat_url(const char *base, const char *relurl) } } - /* If the new part contains a space, this is a mighty stupid redirect - but we still make an effort to do "right". To the left of a '?' - letter we replace each space with %20 while it is replaced with '+' - on the right side of the '?' letter. - */ - newlen = strlen_url(useurl, !host_changed); - - urllen = strlen(url_clone); - - newest = malloc(urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); - - if(!newest) { - free(url_clone); /* don't leak this */ - return NULL; - } + Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH); /* copy over the root url part */ - memcpy(newest, url_clone, urllen); + if(Curl_dyn_add(&newest, base)) + return NULL; /* check if we need to append a slash */ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0])) ; - else - newest[urllen++]='/'; + else { + if(Curl_dyn_addn(&newest, "/", 1)) + return NULL; + } /* then append the new piece on the right side */ - strcpy_url(&newest[urllen], useurl, !host_changed); - - free(url_clone); + urlencode_str(&newest, useurl, strlen(useurl), !host_changed, FALSE); - return newest; + return Curl_dyn_ptr(&newest); } /* scan for byte values < 31 or 127 */ @@ -450,7 +396,7 @@ static bool junkscan(const char *part, unsigned int flags) * */ static CURLUcode parse_hostname_login(struct Curl_URL *u, - char **hostname, + struct dynbuf *host, unsigned int flags) { CURLUcode result = CURLUE_OK; @@ -460,27 +406,31 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, char *optionsp = NULL; const struct Curl_handler *h = NULL; - /* At this point, we're hoping all the other special cases have - * been taken care of, so conn->host.name is at most - * [user[:password][;options]]@]hostname + /* At this point, we assume all the other special cases have been taken + * care of, so the host is at most + * + * [user[:password][;options]]@]hostname * * We need somewhere to put the embedded details, so do that first. */ - char *ptr = strchr(*hostname, '@'); - char *login = *hostname; + char *login = Curl_dyn_ptr(host); + char *ptr; + DEBUGASSERT(login); + + ptr = strchr(login, '@'); if(!ptr) goto out; /* We will now try to extract the * possible login information in a string like: * ftp://user:password@ftp.my.site:8021/README */ - *hostname = ++ptr; + ptr++; /* if this is a known scheme, get some details */ if(u->scheme) - h = Curl_builtin_scheme(u->scheme); + h = Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED); /* We could use the login information in the URL so extract it. Only parse options if the handler says we should. Note that 'h' might be NULL! */ @@ -522,6 +472,10 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, u->options = optionsp; } + /* move the name to the start of the host buffer */ + if(Curl_dyn_tail(host, strlen(ptr))) + return CURLUE_OUT_OF_MEMORY; + return CURLUE_OK; out: @@ -535,13 +489,13 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u, return result; } -UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, +UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host, bool has_scheme) { char *portptr = NULL; char endbracket; int len; - + char *hostname = Curl_dyn_ptr(host); /* * Find the end of an IPv6 address, either on the ']' ending bracket or * a percent-encoded zone index. @@ -578,6 +532,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, char *rest; long port; char portbuf[7]; + size_t keep = portptr - hostname; /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just @@ -586,15 +541,15 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, Don't do it if the URL has no scheme, to make something that looks like a scheme not work! */ - if(!portptr[1]) { - *portptr = '\0'; + Curl_dyn_setlen(host, keep); + portptr++; + if(!*portptr) return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER; - } - if(!ISDIGIT(portptr[1])) + if(!ISDIGIT(*portptr)) return CURLUE_BAD_PORT_NUMBER; - port = strtol(portptr + 1, &rest, 10); /* Port number must be decimal */ + port = strtol(portptr, &rest, 10); /* Port number must be decimal */ if(port > 0xffff) return CURLUE_BAD_PORT_NUMBER; @@ -602,7 +557,6 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, if(rest[0]) return CURLUE_BAD_PORT_NUMBER; - *portptr++ = '\0'; /* cut off the name there */ *rest = 0; /* generate a new port number string to get rid of leading zeroes etc */ msnprintf(portbuf, sizeof(portbuf), "%ld", port); @@ -615,12 +569,15 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname, return CURLUE_OK; } -static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) +static CURLUcode hostname_check(struct Curl_URL *u, char *hostname, + size_t hlen) /* length of hostname */ { size_t len; - size_t hlen = strlen(hostname); + DEBUGASSERT(hostname); - if(hostname[0] == '[') { + if(!hostname[0]) + return CURLUE_NO_HOST; + else if(hostname[0] == '[') { const char *l = "0123456789abcdefABCDEF:."; if(hlen < 4) /* '[::]' is the shortest possible valid string */ return CURLUE_BAD_IPV6; @@ -679,13 +636,11 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname) } else { /* letters from the second string are not ok */ - len = strcspn(hostname, " \r\n\t/:#?!@"); + len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,"); if(hlen != len) /* hostname with bad content */ return CURLUE_BAD_HOSTNAME; } - if(!hostname[0]) - return CURLUE_NO_HOST; return CURLUE_OK; } @@ -779,79 +734,230 @@ static bool ipv4_normalize(const char *hostname, char *outp, size_t olen) return TRUE; } -/* return strdup'ed version in 'outp', possibly percent decoded */ -static CURLUcode decode_host(char *hostname, char **outp) +/* if necessary, replace the host content with a URL decoded version */ +static CURLUcode decode_host(struct dynbuf *host) { char *per = NULL; - if(hostname[0] != '[') + const char *hostname = Curl_dyn_ptr(host); + if(hostname[0] == '[') /* only decode if not an ipv6 numerical */ - per = strchr(hostname, '%'); - if(!per) { - *outp = strdup(hostname); - if(!*outp) - return CURLUE_OUT_OF_MEMORY; - } + return CURLUE_OK; + per = strchr(hostname, '%'); + if(!per) + /* nothing to decode */ + return CURLUE_OK; else { - /* might be encoded */ + /* encoded */ size_t dlen; - CURLcode result = Curl_urldecode(hostname, 0, outp, &dlen, REJECT_CTRL); + char *decoded; + CURLcode result = Curl_urldecode(hostname, 0, &decoded, &dlen, + REJECT_CTRL); if(result) return CURLUE_BAD_HOSTNAME; + Curl_dyn_reset(host); + result = Curl_dyn_addn(host, decoded, dlen); + free(decoded); + if(result) + return CURLUE_OUT_OF_MEMORY; } return CURLUE_OK; } -static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) +/* + * "Remove Dot Segments" + * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 + */ + +/* + * dedotdotify() + * @unittest: 1395 + * + * This function gets a null-terminated path with dot and dotdot sequences + * passed in and strips them off according to the rules in RFC 3986 section + * 5.2.4. + * + * The function handles a query part ('?' + stuff) appended but it expects + * that fragments ('#' + stuff) have already been cut off. + * + * RETURNS + * + * an allocated dedotdotified output string + */ +UNITTEST char *dedotdotify(const char *input, size_t clen); +UNITTEST char *dedotdotify(const char *input, size_t clen) { - char *path; - bool path_alloced = FALSE; + char *out = malloc(clen + 1); + char *outptr; + const char *orginput = input; + char *queryp; + if(!out) + return NULL; /* out of memory */ + + *out = 0; /* null-terminates, for inputs like "./" */ + outptr = out; + + if(!*input) + /* zero length input string, return that */ + return out; + + /* + * To handle query-parts properly, we must find it and remove it during the + * dotdot-operation and then append it again at the end to the output + * string. + */ + queryp = strchr(input, '?'); + + do { + bool dotdot = TRUE; + if(*input == '.') { + /* A. If the input buffer begins with a prefix of "../" or "./", then + remove that prefix from the input buffer; otherwise, */ + + if(!strncmp("./", input, 2)) { + input += 2; + clen -= 2; + } + else if(!strncmp("../", input, 3)) { + input += 3; + clen -= 3; + } + /* D. if the input buffer consists only of "." or "..", then remove + that from the input buffer; otherwise, */ + + else if(!strcmp(".", input) || !strcmp("..", input) || + !strncmp(".?", input, 2) || !strncmp("..?", input, 3)) { + *out = 0; + break; + } + else + dotdot = FALSE; + } + else if(*input == '/') { + /* B. if the input buffer begins with a prefix of "/./" or "/.", where + "." is a complete path segment, then replace that prefix with "/" in + the input buffer; otherwise, */ + if(!strncmp("/./", input, 3)) { + input += 2; + clen -= 2; + } + else if(!strcmp("/.", input) || !strncmp("/.?", input, 3)) { + *outptr++ = '/'; + *outptr = 0; + break; + } + + /* C. if the input buffer begins with a prefix of "/../" or "/..", + where ".." is a complete path segment, then replace that prefix with + "/" in the input buffer and remove the last segment and its + preceding "/" (if any) from the output buffer; otherwise, */ + + else if(!strncmp("/../", input, 4)) { + input += 3; + clen -= 3; + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr = 0; /* null-terminate where it stops */ + } + else if(!strcmp("/..", input) || !strncmp("/..?", input, 4)) { + /* remove the last segment from the output buffer */ + while(outptr > out) { + outptr--; + if(*outptr == '/') + break; + } + *outptr++ = '/'; + *outptr = 0; /* null-terminate where it stops */ + break; + } + else + dotdot = FALSE; + } + else + dotdot = FALSE; + + if(!dotdot) { + /* E. move the first path segment in the input buffer to the end of + the output buffer, including the initial "/" character (if any) and + any subsequent characters up to, but not including, the next "/" + character or the end of the input buffer. */ + + do { + *outptr++ = *input++; + clen--; + } while(*input && (*input != '/') && (*input != '?')); + *outptr = 0; + } + + /* continue until end of input string OR, if there is a terminating + query part, stop there */ + } while(*input && (!queryp || (input < queryp))); + + if(queryp) { + size_t qlen; + /* There was a query part, append that to the output. */ + size_t oindex = queryp - orginput; + qlen = strlen(&orginput[oindex]); + memcpy(outptr, &orginput[oindex], qlen + 1); /* include zero byte */ + } + + return out; +} + +static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) +{ + const char *path; + size_t pathlen; bool uncpath = FALSE; - char *hostname; char *query = NULL; char *fragment = NULL; - CURLUcode result; - bool url_has_scheme = FALSE; char schemebuf[MAX_SCHEME_LEN + 1]; const char *schemep = NULL; size_t schemelen = 0; size_t urllen; + CURLUcode result = CURLUE_OK; + size_t fraglen = 0; + struct dynbuf host; DEBUGASSERT(url); + Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH); + /************************************************************* * Parse the URL. ************************************************************/ /* allocate scratch area */ urllen = strlen(url); - if(urllen > CURL_MAX_INPUT_LENGTH) + if(urllen > CURL_MAX_INPUT_LENGTH) { /* excessive input length */ - return CURLUE_MALFORMED_INPUT; - - path = u->scratch = malloc(urllen * 2 + 2); - if(!path) - return CURLUE_OUT_OF_MEMORY; - - hostname = &path[urllen + 1]; - hostname[0] = 0; - - if(Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf))) { - url_has_scheme = TRUE; - schemelen = strlen(schemebuf); + result = CURLUE_MALFORMED_INPUT; + goto fail; } + schemelen = Curl_is_absolute_url(url, schemebuf, sizeof(schemebuf), + flags & (CURLU_GUESS_SCHEME| + CURLU_DEFAULT_SCHEME)); + /* handle the file: scheme */ - if(url_has_scheme && !strcmp(schemebuf, "file")) { - if(urllen <= 6) + if(schemelen && !strcmp(schemebuf, "file")) { + if(urllen <= 6) { /* file:/ is not enough to actually be a complete file: URL */ - return CURLUE_BAD_FILE_URL; + result = CURLUE_BAD_FILE_URL; + goto fail; + } /* path has been allocated large enough to hold this */ - strcpy(path, &url[5]); + path = (char *)&url[5]; - u->scheme = strdup("file"); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + schemep = u->scheme = strdup("file"); + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } /* Extra handling URLs with an authority component (i.e. that start with * "file://") @@ -861,7 +967,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) */ if(path[0] == '/' && path[1] == '/') { /* swallow the two slashes */ - char *ptr = &path[2]; + const char *ptr = &path[2]; /* * According to RFC 8089, a file: URL can be reliably dereferenced if: @@ -897,13 +1003,17 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) chars, and the delimiting slash character must be appended to the host name */ path = strpbrk(ptr, "/\\:*?\"<>|"); - if(!path || *path != '/') - return CURLUE_BAD_FILE_URL; + if(!path || *path != '/') { + result = CURLUE_BAD_FILE_URL; + goto fail; + } len = path - ptr; if(len) { - memcpy(hostname, ptr, len); - hostname[len] = 0; + if(Curl_dyn_addn(&host, ptr, len)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } uncpath = TRUE; } @@ -911,7 +1021,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) #else /* Invalid file://hostname/, expected localhost or 127.0.0.1 or none */ - return CURLUE_BAD_FILE_URL; + result = CURLUE_BAD_FILE_URL; + goto fail; #endif } } @@ -920,7 +1031,8 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) } if(!uncpath) - hostname = NULL; /* no host for file: URLs by default */ + /* no host for file: URLs by default */ + Curl_dyn_reset(&host); #if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) /* Don't allow Windows drive letters when not in Windows. @@ -928,13 +1040,14 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) || STARTS_WITH_URL_DRIVE_PREFIX(path)) { /* File drive letters are only accepted in MSDOS/Windows */ - return CURLUE_BAD_FILE_URL; + result = CURLUE_BAD_FILE_URL; + goto fail; } #else /* If the path starts with a slash and a drive letter, ditch the slash */ if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) { /* This cannot be done with strcpy, as the memory chunks overlap! */ - memmove(path, &path[1], strlen(&path[1]) + 1); + path++; } #endif @@ -944,32 +1057,39 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) const char *p; const char *hostp; size_t len; - path[0] = 0; - if(url_has_scheme) { + if(schemelen) { int i = 0; p = &url[schemelen + 1]; while(p && (*p == '/') && (i < 4)) { p++; i++; } - if((i < 1) || (i>3)) - /* less than one or more than three slashes */ - return CURLUE_BAD_SLASHES; schemep = schemebuf; - if(!Curl_builtin_scheme(schemep) && - !(flags & CURLU_NON_SUPPORT_SCHEME)) - return CURLUE_UNSUPPORTED_SCHEME; + if(!Curl_builtin_scheme(schemep, CURL_ZERO_TERMINATED) && + !(flags & CURLU_NON_SUPPORT_SCHEME)) { + result = CURLUE_UNSUPPORTED_SCHEME; + goto fail; + } - if(junkscan(schemep, flags)) - return CURLUE_BAD_SCHEME; + if((i < 1) || (i>3)) { + /* less than one or more than three slashes */ + result = CURLUE_BAD_SLASHES; + goto fail; + } + if(junkscan(schemep, flags)) { + result = CURLUE_BAD_SCHEME; + goto fail; + } } else { /* no scheme! */ - if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) - return CURLUE_BAD_SCHEME; + if(!(flags & (CURLU_DEFAULT_SCHEME|CURLU_GUESS_SCHEME))) { + result = CURLUE_BAD_SCHEME; + goto fail; + } if(flags & CURLU_DEFAULT_SCHEME) schemep = DEFAULT_SCHEME; @@ -986,122 +1106,169 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) len = p - hostp; if(len) { - memcpy(hostname, hostp, len); - hostname[len] = 0; + if(Curl_dyn_addn(&host, hostp, len)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } } else { - if(!(flags & CURLU_NO_AUTHORITY)) - return CURLUE_NO_HOST; + if(!(flags & CURLU_NO_AUTHORITY)) { + result = CURLUE_NO_HOST; + goto fail; + } } - strcpy(path, p); + path = (char *)p; if(schemep) { u->scheme = strdup(schemep); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } } } - if((flags & CURLU_URLENCODE) && path[0]) { - /* worst case output length is 3x the original! */ - char *newp = malloc(strlen(path) * 3); - if(!newp) - return CURLUE_OUT_OF_MEMORY; - path_alloced = TRUE; - strcpy_url(newp, path, TRUE); /* consider it relative */ - u->temppath = path = newp; - } - fragment = strchr(path, '#'); if(fragment) { - *fragment++ = 0; - if(junkscan(fragment, flags)) - return CURLUE_BAD_FRAGMENT; - if(fragment[0]) { - u->fragment = strdup(fragment); - if(!u->fragment) - return CURLUE_OUT_OF_MEMORY; + fraglen = strlen(fragment); + if(fraglen > 1) { + /* skip the leading '#' in the copy but include the terminating null */ + u->fragment = Curl_memdup(fragment + 1, fraglen); + if(!u->fragment) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + + if(junkscan(u->fragment, flags)) { + result = CURLUE_BAD_FRAGMENT; + goto fail; + } } } query = strchr(path, '?'); - if(query) { - *query++ = 0; - if(junkscan(query, flags)) - return CURLUE_BAD_QUERY; - /* done even if the query part is a blank string */ - u->query = strdup(query); - if(!u->query) - return CURLUE_OUT_OF_MEMORY; - } + if(query && (!fragment || (query < fragment))) { + size_t qlen = strlen(query) - fraglen; /* includes '?' */ + pathlen = strlen(path) - qlen - fraglen; + if(qlen > 1) { + if(qlen && (flags & CURLU_URLENCODE)) { + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + /* skip the leading question mark */ + if(urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + u->query = Curl_dyn_ptr(&enc); + } + else { + u->query = Curl_memdup(query + 1, qlen); + if(!u->query) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + u->query[qlen - 1] = 0; + } - if(junkscan(path, flags)) - return CURLUE_BAD_PATH; + if(junkscan(u->query, flags)) { + result = CURLUE_BAD_QUERY; + goto fail; + } + } + else { + /* single byte query */ + u->query = strdup(""); + if(!u->query) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + else + pathlen = strlen(path) - fraglen; + + if(pathlen && (flags & CURLU_URLENCODE)) { + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(urlencode_str(&enc, path, pathlen, TRUE, FALSE)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + pathlen = Curl_dyn_len(&enc); + path = u->path = Curl_dyn_ptr(&enc); + } - if(!path[0]) - /* if there's no path left set, unset */ + if(!pathlen) { + /* there is no path left, unset */ path = NULL; + } else { + if(!u->path) { + u->path = Curl_memdup(path, pathlen + 1); + if(!u->path) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + u->path[pathlen] = 0; + path = u->path; + } + else if(flags & CURLU_URLENCODE) + /* it might have encoded more than just the path so cut it */ + u->path[pathlen] = 0; + + if(junkscan(u->path, flags)) { + result = CURLUE_BAD_PATH; + goto fail; + } + if(!(flags & CURLU_PATH_AS_IS)) { /* remove ../ and ./ sequences according to RFC3986 */ - char *newp = Curl_dedotdotify(path); - if(!newp) - return CURLUE_OUT_OF_MEMORY; - - if(strcmp(newp, path)) { - /* if we got a new version */ - if(path_alloced) - Curl_safefree(u->temppath); - u->temppath = path = newp; - path_alloced = TRUE; + char *newp = dedotdotify((char *)path, pathlen); + if(!newp) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; } - else - free(newp); + free(u->path); + u->path = newp; } - - u->path = path_alloced?path:strdup(path); - if(!u->path) - return CURLUE_OUT_OF_MEMORY; - u->temppath = NULL; /* used now */ } - if(hostname) { + if(Curl_dyn_len(&host)) { char normalized_ipv4[sizeof("255.255.255.255") + 1]; /* * Parse the login details and strip them out of the host name. */ - result = parse_hostname_login(u, &hostname, flags); + result = parse_hostname_login(u, &host, flags); + if(!result) + result = Curl_parse_port(u, &host, schemelen); if(result) - return result; + goto fail; - result = Curl_parse_port(u, hostname, url_has_scheme); - if(result) - return result; - - if(junkscan(hostname, flags)) - return CURLUE_BAD_HOSTNAME; + if(junkscan(Curl_dyn_ptr(&host), flags)) { + result = CURLUE_BAD_HOSTNAME; + goto fail; + } - if(0 == strlen(hostname) && (flags & CURLU_NO_AUTHORITY)) { - /* Skip hostname check, it's allowed to be empty. */ - u->host = strdup(""); + if(ipv4_normalize(Curl_dyn_ptr(&host), + normalized_ipv4, sizeof(normalized_ipv4))) { + Curl_dyn_reset(&host); + if(Curl_dyn_add(&host, normalized_ipv4)) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } } else { - if(ipv4_normalize(hostname, normalized_ipv4, sizeof(normalized_ipv4))) - u->host = strdup(normalized_ipv4); - else { - result = decode_host(hostname, &u->host); - if(result) - return result; - result = hostname_check(u, u->host); - if(result) - return result; - } + result = decode_host(&host); + if(!result) + result = hostname_check(u, Curl_dyn_ptr(&host), Curl_dyn_len(&host)); + if(result) + goto fail; } - if(!u->host) - return CURLUE_OUT_OF_MEMORY; + if((flags & CURLU_GUESS_SCHEME) && !schemep) { + const char *hostname = Curl_dyn_ptr(&host); /* legacy curl-style guess based on host name */ if(checkprefix("ftp.", hostname)) schemep = "ftp"; @@ -1119,27 +1286,26 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags) schemep = "http"; u->scheme = strdup(schemep); - if(!u->scheme) - return CURLUE_OUT_OF_MEMORY; + if(!u->scheme) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; + } + } + } + else if(flags & CURLU_NO_AUTHORITY) { + /* allowed to be empty. */ + if(Curl_dyn_add(&host, "")) { + result = CURLUE_OUT_OF_MEMORY; + goto fail; } } - Curl_safefree(u->scratch); - Curl_safefree(u->temppath); - - return CURLUE_OK; -} + u->host = Curl_dyn_ptr(&host); -/* - * Parse the URL and set the relevant members of the Curl_URL struct. - */ -static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags) -{ - CURLUcode result = seturl(url, u, flags); - if(result) { - free_urlhandle(u); - memset(u, 0, sizeof(struct Curl_URL)); - } + return result; + fail: + Curl_dyn_free(&host); + free_urlhandle(u); return result; } @@ -1157,8 +1323,6 @@ static CURLUcode parseurl_and_replace(const char *url, CURLU *u, free_urlhandle(u); *u = tmpurl; } - else - free_urlhandle(&tmpurl); return result; } @@ -1257,7 +1421,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 */ const struct Curl_handler *h = - Curl_builtin_scheme(u->scheme); + Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED); if(h) { msnprintf(portbuf, sizeof(portbuf), "%u", h->defport); ptr = portbuf; @@ -1267,7 +1431,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, /* there is a stored port number, but ask to inhibit if it matches the default one for the scheme */ const struct Curl_handler *h = - Curl_builtin_scheme(u->scheme); + Curl_builtin_scheme(u->scheme, CURL_ZERO_TERMINATED); if(h && (h->defport == u->portnum) && (flags & CURLU_NO_DEFAULT_PORT)) ptr = NULL; @@ -1313,7 +1477,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, else return CURLUE_NO_SCHEME; - h = Curl_builtin_scheme(scheme); + h = Curl_builtin_scheme(scheme, CURL_ZERO_TERMINATED); if(!port && (flags & CURLU_DEFAULT_PORT)) { /* there's no stored port number, but asked to deliver a default one for the scheme */ @@ -1336,14 +1500,13 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, if(u->host[0] == '[') { if(u->zoneid) { /* make it '[ host %25 zoneid ]' */ + struct dynbuf enc; size_t hostlen = strlen(u->host); - size_t alen = hostlen + 3 + strlen(u->zoneid) + 1; - allochost = malloc(alen); - if(!allochost) + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(Curl_dyn_addf(&enc, "%.*s%%25%s]", (int)hostlen - 1, u->host, + u->zoneid)) return CURLUE_OUT_OF_MEMORY; - memcpy(allochost, u->host, hostlen - 1); - msnprintf(&allochost[hostlen - 1], alen - hostlen + 1, - "%%25%s]", u->zoneid); + allochost = Curl_dyn_ptr(&enc); } } else if(urlencode) { @@ -1354,32 +1517,32 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, else { /* only encode '%' in output host name */ char *host = u->host; - size_t pcount = 0; + bool percent = FALSE; /* first, count number of percents present in the name */ while(*host) { - if(*host == '%') - pcount++; + if(*host == '%') { + percent = TRUE; + break; + } host++; } - /* if there were percents, encode the host name */ - if(pcount) { - size_t hostlen = strlen(u->host); - size_t alen = hostlen + 2 * pcount + 1; - char *o = allochost = malloc(alen); - if(!allochost) - return CURLUE_OUT_OF_MEMORY; - + /* if there were percent(s), encode the host name */ + if(percent) { + struct dynbuf enc; + CURLcode result; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); host = u->host; while(*host) { - if(*host == '%') { - memcpy(o, "%25", 3); - o += 3; - host++; - continue; - } - *o++ = *host++; + if(*host == '%') + result = Curl_dyn_addn(&enc, "%25", 3); + else + result = Curl_dyn_addn(&enc, host, 1); + if(result) + return CURLUE_OUT_OF_MEMORY; + host++; } - *o = '\0'; + free(u->host); + u->host = Curl_dyn_ptr(&enc); } } @@ -1412,13 +1575,15 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, break; } if(ptr) { - *part = strdup(ptr); + size_t partlen = strlen(ptr); + size_t i = 0; + *part = Curl_memdup(ptr, partlen + 1); if(!*part) return CURLUE_OUT_OF_MEMORY; if(plusdecode) { /* convert + to space */ - char *plus; - for(plus = *part; *plus; ++plus) { + char *plus = *part; + for(i = 0; i < partlen; ++plus, i++) { if(*plus == '+') *plus = ' '; } @@ -1435,7 +1600,18 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, return CURLUE_URLDECODE; } *part = decoded; + partlen = dlen; } + if(urlencode) { + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + if(urlencode_str(&enc, *part, partlen, TRUE, + what == CURLUPART_QUERY)) + return CURLUE_OUT_OF_MEMORY; + free(*part); + *part = Curl_dyn_ptr(&enc); + } + return CURLUE_OK; } else @@ -1497,6 +1673,10 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if(storep && *storep) { Curl_safefree(*storep); } + else if(!storep) { + free_urlhandle(u); + memset(u, 0, sizeof(struct Curl_URL)); + } return CURLUE_OK; } @@ -1507,7 +1687,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_BAD_SCHEME; if(!(flags & CURLU_NON_SUPPORT_SCHEME) && /* verify that it is a fine scheme */ - !Curl_builtin_scheme(part)) + !Curl_builtin_scheme(part, CURL_ZERO_TERMINATED)) return CURLUE_UNSUPPORTED_SCHEME; storep = &u->scheme; urlencode = FALSE; /* never */ @@ -1573,7 +1753,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, /* if the new thing is absolute or the old one is not * (we could not get an absolute url in 'oldurl'), * then replace the existing with the new. */ - if(Curl_is_absolute_url(part, NULL, 0) + if(Curl_is_absolute_url(part, NULL, 0, + flags & (CURLU_GUESS_SCHEME| + CURLU_DEFAULT_SCHEME)) || curl_url_get(u, CURLUPART_URL, &oldurl, flags)) { return parseurl_and_replace(part, u, flags); } @@ -1603,14 +1785,16 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if(urlencode) { const unsigned char *i; - char *o; - char *enc = malloc(nalloc * 3 + 1); /* for worst case! */ - if(!enc) - return CURLUE_OUT_OF_MEMORY; - for(i = (const unsigned char *)part, o = enc; *i; i++) { + struct dynbuf enc; + + Curl_dyn_init(&enc, nalloc * 3 + 1); + + for(i = (const unsigned char *)part; *i; i++) { + CURLcode result; if((*i == ' ') && plusencode) { - *o = '+'; - o++; + result = Curl_dyn_addn(&enc, "+", 1); + if(result) + return CURLUE_OUT_OF_MEMORY; } else if(Curl_isunreserved(*i) || ((*i == '/') && urlskipslash) || @@ -1618,16 +1802,17 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, if((*i == '=') && equalsencode) /* only skip the first equals sign */ equalsencode = FALSE; - *o = *i; - o++; + result = Curl_dyn_addn(&enc, i, 1); + if(result) + return CURLUE_OUT_OF_MEMORY; } else { - msnprintf(o, 4, "%%%02x", *i); - o += 3; + result = Curl_dyn_addf(&enc, "%%%02x", *i); + if(result) + return CURLUE_OUT_OF_MEMORY; } } - *o = 0; /* null-terminate */ - newp = enc; + newp = Curl_dyn_ptr(&enc); } else { char *p; @@ -1639,8 +1824,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, /* make sure percent encoded are lower case */ if((*p == '%') && ISXDIGIT(p[1]) && ISXDIGIT(p[2]) && (ISUPPER(p[1]) || ISUPPER(p[2]))) { - p[1] = (char)TOLOWER(p[1]); - p[2] = (char)TOLOWER(p[2]); + p[1] = Curl_raw_tolower(p[1]); + p[2] = Curl_raw_tolower(p[2]); p += 3; } else @@ -1649,34 +1834,41 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, } if(appendquery) { - /* Append the string onto the old query. Add a '&' separator if none is - present at the end of the exsting query already */ + /* Append the 'newp' string onto the old query. Add a '&' separator if + none is present at the end of the existing query already */ + size_t querylen = u->query ? strlen(u->query) : 0; bool addamperand = querylen && (u->query[querylen -1] != '&'); if(querylen) { - size_t newplen = strlen(newp); - char *p = malloc(querylen + addamperand + newplen + 1); - if(!p) { - free((char *)newp); - return CURLUE_OUT_OF_MEMORY; + struct dynbuf enc; + Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH); + + if(Curl_dyn_addn(&enc, u->query, querylen)) /* add original query */ + goto nomem; + + if(addamperand) { + if(Curl_dyn_addn(&enc, "&", 1)) + goto nomem; } - strcpy(p, u->query); /* original query */ - if(addamperand) - p[querylen] = '&'; /* ampersand */ - strcpy(&p[querylen + addamperand], newp); /* new suffix */ + if(Curl_dyn_add(&enc, newp)) + goto nomem; free((char *)newp); free(*storep); - *storep = p; + *storep = Curl_dyn_ptr(&enc); return CURLUE_OK; + nomem: + free((char *)newp); + return CURLUE_OUT_OF_MEMORY; } } if(what == CURLUPART_HOST) { - if(0 == strlen(newp) && (flags & CURLU_NO_AUTHORITY)) { + size_t n = strlen(newp); + if(!n && (flags & CURLU_NO_AUTHORITY)) { /* Skip hostname check, it's allowed to be empty. */ } else { - if(hostname_check(u, (char *)newp)) { + if(hostname_check(u, (char *)newp, n)) { free((char *)newp); return CURLUE_BAD_HOSTNAME; } diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index 584434d..1d430b5 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* This file is for lib internal stuff */ @@ -51,6 +53,33 @@ #define PORT_GOPHER 70 #define PORT_MQTT 1883 +#ifdef USE_WEBSOCKETS +/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number, + * the rest are internal information. If we use higher bits we only do this on + * platforms that have a >= 64 bit type and then we use such a type for the + * protocol fields in the protocol handler. + */ +#define CURLPROTO_WS (1<<30) +#define CURLPROTO_WSS ((curl_prot_t)1<<31) +#else +#define CURLPROTO_WS 0 +#define CURLPROTO_WSS 0 +#endif + +/* This should be undefined once we need bit 32 or higher */ +#define PROTO_TYPE_SMALL + +#ifndef PROTO_TYPE_SMALL +typedef curl_off_t curl_prot_t; +#else +typedef unsigned int curl_prot_t; +#endif + +/* This mask is for all the old protocols that are provided and defined in the + public header and shall exclude protocols added since which are not exposed + in the API */ +#define CURLPROTO_MASK (0x3ffffff) + #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" #define DICT_MATCH3 "/FIND:" @@ -64,7 +93,8 @@ /* Convenience defines for checking protocols or their SSL based version. Each protocol handler should only ever have a single CURLPROTO_ in its protocol field. */ -#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS) +#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS|CURLPROTO_WS| \ + CURLPROTO_WSS) #define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS) #define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S) #define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS) @@ -155,10 +185,10 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data, # endif #endif -#ifdef HAVE_LIBSSH2_H +#ifdef USE_LIBSSH2 #include <libssh2.h> #include <libssh2_sftp.h> -#endif /* HAVE_LIBSSH2_H */ +#endif /* USE_LIBSSH2 */ #define READBUFFER_SIZE CURL_MAX_WRITE_SIZE #define READBUFFER_MAX CURL_MAX_READ_SIZE @@ -180,15 +210,6 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data, #define GOOD_EASY_HANDLE(x) \ ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) -/* the type we use for storing a single boolean bit */ -#ifdef _MSC_VER -typedef bool bit; -#define BIT(x) bool x -#else -typedef unsigned int bit; -#define BIT(x) bit x:1 -#endif - #ifdef HAVE_GSSAPI /* Types needed for krb5-ftp connections */ struct krb5buffer { @@ -248,8 +269,6 @@ struct ssl_primary_config { 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 */ char *cipher_list; /* list of ciphers to use */ char *cipher_list13; /* list of TLS 1.3 cipher suites to use */ char *pinned_key; @@ -327,11 +346,11 @@ struct digestdata { char *nonce; char *cnonce; char *realm; - int algo; char *opaque; char *qop; char *algorithm; int nc; /* nonce count */ + unsigned char algo; BIT(stale); /* set true for re-negotiation */ BIT(userhash); #endif @@ -516,9 +535,7 @@ struct ConnectBits { connection */ BIT(multiplex); /* connection is multiplexed */ BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(tls_enable_npn); /* TLS NPN extension? */ BIT(tls_enable_alpn); /* TLS ALPN extension? */ - BIT(connect_only); #ifndef CURL_DISABLE_DOH BIT(doh); #endif @@ -563,7 +580,7 @@ struct Curl_async { struct Curl_dns_entry *dns; struct thread_data *tdata; void *resolver; /* resolver state, if it is used in the URL state - - ares_channel f.e. */ + ares_channel e.g. */ int port; int status; /* if done is TRUE, this is the status from the callback */ BIT(done); /* set TRUE when the lookup is complete */ @@ -584,8 +601,9 @@ enum expect100 { enum upgrade101 { UPGR101_INIT, /* default state */ - UPGR101_REQUESTED, /* upgrade requested */ - UPGR101_RECEIVED, /* response received */ + UPGR101_WS, /* upgrade to WebSockets requested */ + UPGR101_H2, /* upgrade to HTTP/2 requested */ + UPGR101_RECEIVED, /* 101 response received */ UPGR101_WORKING /* talking upgraded protocol */ }; @@ -607,23 +625,6 @@ enum doh_slots { DOH_PROBE_SLOTS }; -/* one of these for each DoH request */ -struct dnsprobe { - CURL *easy; - int dnstype; - unsigned char dohbuffer[512]; - size_t dohlen; - struct dynbuf serverdoh; -}; - -struct dohdata { - struct curl_slist *headers; - struct dnsprobe probe[DOH_PROBE_SLOTS]; - unsigned int pending; /* still outstanding requests */ - int port; - const char *host; -}; - /* * Request specific data in the easy handle (Curl_easy). Previously, * these members were on the connectdata struct but since a conn struct may @@ -707,6 +708,7 @@ struct SingleRequest { #ifndef CURL_DISABLE_DOH struct dohdata *doh; /* DoH specific data for this request */ #endif + unsigned char setcookies; 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 @@ -804,10 +806,10 @@ struct Curl_handler { 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 */ + curl_prot_t protocol; /* See CURLPROTO_* - this needs to be the single + specific protocol bit */ + curl_prot_t family; /* single bit for protocol family; basically the + non-TLS name of the protocol this is */ unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */ }; @@ -828,7 +830,7 @@ struct Curl_handler { url query strings (?foo=bar) ! */ #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ -#define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ +#define PROTOPT_ALPN (1<<8) /* set ALPN for this */ #define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ #define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field of the URL */ @@ -864,7 +866,8 @@ struct postponed_data { struct proxy_info { struct hostname host; long port; - curl_proxytype proxytype; /* what kind of proxy that is in use */ + unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in + use */ char *user; /* proxy user name string, allocated */ char *passwd; /* proxy password string, allocated */ }; @@ -903,6 +906,11 @@ struct connstate { unsigned char *outp; /* send from this pointer */ }; +#define TRNSPRT_TCP 3 +#define TRNSPRT_UDP 4 +#define TRNSPRT_QUIC 5 +#define TRNSPRT_UNIX 6 + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -940,15 +948,6 @@ struct connectdata { cache entry remains locked. It gets unlocked in multi_done() */ struct Curl_addrinfo *ip_addr; struct Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */ -#ifdef ENABLE_IPV6 - unsigned int scope_id; /* Scope id for IPv6 */ -#endif - - enum { - TRNSPRT_TCP = 3, - TRNSPRT_UDP = 4, - TRNSPRT_QUIC = 5 - } transport; #ifdef ENABLE_QUIC struct quicsocket hequic[2]; /* two, for happy eyeballs! */ @@ -964,13 +963,6 @@ struct connectdata { struct proxy_info socks_proxy; struct proxy_info http_proxy; #endif - int port; /* which port to use locally - to connect to */ - int remote_port; /* the remote port, not the proxy port! */ - int conn_to_port; /* the remote port to connect to. valid only if - bits.conn_to_port is set */ - unsigned short secondary_port; /* secondary socket remote port to connect to - (ftp) */ - /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is *attempted* from the primary socket to a remote address. When more @@ -979,14 +971,11 @@ struct connectdata { these are updated with data which comes directly from the socket. */ char primary_ip[MAX_IPADR_LEN]; - unsigned char ip_version; /* copied from the Curl_easy at creation time */ - char *user; /* user name string, allocated */ char *passwd; /* password string, allocated */ char *options; /* options string, allocated */ char *sasl_authzid; /* authorization identity string, allocated */ char *oauth_bearer; /* OAUTH2 bearer, allocated */ - 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 */ @@ -1013,8 +1002,6 @@ struct connectdata { #endif struct ConnectBits bits; /* various state-flags for this connection */ - /* The field below gets set in Curl_connecthost */ - int num_addr; /* number of addresses to try to connect to */ /* connecttime: when connect() is called on the current IP address. Used to be able to track when to move on to try next IP - but only when the multi interface is used. */ @@ -1042,9 +1029,9 @@ struct connectdata { #ifdef HAVE_GSSAPI BIT(sec_complete); /* if Kerberos is enabled for this connection */ - enum protection_level command_prot; - enum protection_level data_prot; - enum protection_level request_data_prot; + unsigned char command_prot; /* enum protection_level */ + unsigned char data_prot; /* enum protection_level */ + unsigned char request_data_prot; /* enum protection_level */ size_t buffer_size; struct krb5buffer in_buffer; void *app_data; @@ -1091,18 +1078,38 @@ struct connectdata { struct dynbuf trailer; union { +#ifndef CURL_DISABLE_FTP struct ftp_conn ftpc; +#endif +#ifndef CURL_DISABLE_HTTP struct http_conn httpc; +#endif +#ifdef USE_SSH struct ssh_conn sshc; +#endif +#ifndef CURL_DISABLE_TFTP struct tftp_state_data *tftpc; +#endif +#ifndef CURL_DISABLE_IMAP struct imap_conn imapc; +#endif +#ifndef CURL_DISABLE_POP3 struct pop3_conn pop3c; +#endif +#ifndef CURL_DISABLE_SMTP struct smtp_conn smtpc; +#endif +#ifndef CURL_DISABLE_RTSP struct rtsp_conn rtspc; +#endif +#ifndef CURL_DISABLE_SMB struct smb_conn smbc; +#endif void *rtmp; struct ldapconninfo *ldapc; +#ifndef CURL_DISABLE_MQTT struct mqtt_conn mqtt; +#endif } proto; struct http_connect_state *connect_state; /* for HTTP CONNECT */ @@ -1123,12 +1130,27 @@ struct connectdata { int localportrange; int cselect_bits; /* bitmask of socket events */ int waitfor; /* current READ/WRITE bits to wait for */ - int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ - #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) int socks5_gssapi_enctype; #endif + /* The field below gets set in Curl_connecthost */ + int num_addr; /* number of addresses to try to connect to */ + int port; /* which port to use locally - to connect to */ + int remote_port; /* the remote port, not the proxy port! */ + int conn_to_port; /* the remote port to connect to. valid only if + bits.conn_to_port is set */ +#ifdef ENABLE_IPV6 + unsigned int scope_id; /* Scope id for IPv6 */ +#endif unsigned short localport; + unsigned short secondary_port; /* secondary socket remote port to connect to + (ftp) */ + unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION* + value */ + unsigned char transport; /* one of the TRNSPRT_* defines */ + unsigned char ip_version; /* copied from the Curl_easy at creation time */ + unsigned char httpversion; /* the HTTP version*10 reported by the server */ + unsigned char connect_only; }; /* The end of connectdata. */ @@ -1288,6 +1310,7 @@ typedef enum { EXPIRE_TIMEOUT, EXPIRE_TOOFAST, EXPIRE_QUIC, + EXPIRE_FTP_ACCEPT, EXPIRE_LAST /* not an actual timer, used as a marker only */ } expire_id; @@ -1341,7 +1364,7 @@ struct UrlState { This is strdup()ed data. */ char *first_host; int first_remote_port; - unsigned int first_remote_protocol; + curl_prot_t first_remote_protocol; int retrycount; /* number of retries on a new connection */ struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ @@ -1356,9 +1379,10 @@ struct UrlState { /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */ void (*prev_signal)(int sig); #endif +#ifndef CURL_DISABLE_CRYPTO_AUTH struct digestdata digest; /* state data for host Digest auth */ struct digestdata proxydigest; /* state data for proxy Digest auth */ - +#endif struct auth authhost; /* auth details for host */ struct auth authproxy; /* auth details for proxy */ #ifdef USE_CURL_ASYNC @@ -1374,7 +1398,7 @@ struct UrlState { struct Curl_llist timeoutlist; /* list of pending timeouts */ struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */ - /* a place to store the most recently set FTP entrypath */ + /* a place to store the most recently set (S)FTP entrypath */ char *most_recent_ftp_entrypath; unsigned char httpwant; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ @@ -1393,30 +1417,37 @@ struct UrlState { this syntax. */ curl_off_t resume_from; /* continue [ftp] transfer from here */ +#ifndef CURL_DISABLE_RTSP /* This RTSP state information survives requests and connections */ long rtsp_next_client_CSeq; /* the session's next client CSeq */ long rtsp_next_server_CSeq; /* the session's next server CSeq */ long rtsp_CSeq_recv; /* most recent CSeq received */ +#endif curl_off_t infilesize; /* size of file to upload, -1 means unknown. Copied from set.filesize at start of operation */ - +#if defined(USE_HTTP2) || defined(USE_HTTP3) size_t drain; /* Increased when this stream has data to read, even if its socket is not necessarily is readable. Decreased when checked. */ +#endif curl_read_callback fread_func; /* read callback/function */ void *in; /* CURLOPT_READDATA */ - +#ifdef USE_HTTP2 struct Curl_easy *stream_depends_on; int stream_weight; +#endif CURLU *uh; /* URL handle for the current parsed URL */ struct urlpieces up; - Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ + unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any) + is this */ char *url; /* work URL, copied from UserDefined */ char *referer; /* referer string */ +#ifndef CURL_DISABLE_COOKIES struct curl_slist *cookielist; /* list of cookie files set by curl_easy_setopt(COOKIEFILE) calls */ +#endif struct curl_slist *resolve; /* set to point to the set.resolve list when this should be dealt with in pretransfer */ #ifndef CURL_DISABLE_HTTP @@ -1425,9 +1456,10 @@ struct UrlState { headers */ struct Curl_llist httphdrs; /* received headers */ struct curl_header headerout; /* for external purposes */ -#endif + struct Curl_header_store *prevhead; /* the latest added header */ trailers_state trailers_state; /* whether we are sending trailers - and what stage are we at */ + and what stage are we at */ +#endif #ifdef USE_HYPER bool hconnect; /* set if a CONNECT request */ CURLcode hresult; /* used to pass return codes back from hyper callbacks */ @@ -1471,7 +1503,6 @@ struct UrlState { is always set TRUE when curl_easy_perform() is called. */ BIT(authproblem); /* TRUE if there's some problem authenticating */ /* set after initial USER failure, to prevent an authentication loop */ - BIT(ftp_trying_alternative); BIT(wildcardmatch); /* enable wildcard matching */ BIT(expect100header); /* TRUE if we added Expect: 100-continue */ BIT(disableexpect); /* TRUE if Expect: is disabled due to a previous @@ -1548,8 +1579,6 @@ enum dupstring { STRING_SSL_CIPHER_LIST_PROXY, /* list of 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, /* crl file to check certificate */ STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */ @@ -1632,16 +1661,15 @@ struct UserDefined { void *out; /* CURLOPT_WRITEDATA */ void *in_set; /* CURLOPT_READDATA */ void *writeheader; /* write the header to this if non-NULL */ - void *rtp_out; /* write RTP to this if non-NULL */ - long use_port; /* which port to use (when not using default) */ + unsigned short use_port; /* which port to use (when not using default) */ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ +#ifndef CURL_DISABLE_PROXY unsigned long socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ +#endif long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ - int keep_post; /* keep POSTs as POSTs after a 30x request; each - bit represents a request, from 301 to 303 */ void *postfields; /* if POST, set the fields' values here */ curl_seek_callback seek_func; /* function that seeks the input */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead @@ -1679,16 +1707,17 @@ struct UserDefined { #endif void *progress_client; /* pointer to pass to the progress callback */ void *ioctl_client; /* pointer to pass to the ioctl callback */ - long timeout; /* in milliseconds, 0 means no timeout */ - long connecttimeout; /* in milliseconds, 0 means no timeout */ - long accepttimeout; /* in milliseconds, 0 means no timeout */ - long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */ - long server_response_timeout; /* in milliseconds, 0 means no timeout */ + unsigned int timeout; /* ms, 0 means no timeout */ + unsigned int connecttimeout; /* ms, 0 means no timeout */ + unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */ + unsigned int server_response_timeout; /* ms, 0 means no timeout */ long maxage_conn; /* in seconds, max idle time to allow a connection that is to be reused */ long maxlifetime_conn; /* in seconds, max time since creation to allow a connection that is to be reused */ +#ifndef CURL_DISABLE_TFTP long tftp_blksize; /* in bytes, 0 means use default */ +#endif curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ @@ -1708,15 +1737,17 @@ struct UserDefined { the transfer on source host */ struct curl_slist *source_postquote; /* in 3rd party transfer mode - after the transfer on source host */ +#ifndef CURL_DISABLE_TELNET struct curl_slist *telnet_options; /* linked list of telnet options */ +#endif struct curl_slist *resolve; /* list of names to add/remove from DNS cache */ struct curl_slist *connect_to; /* list of host:port mappings to override the hostname and port to connect to */ - 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 */ - Curl_HttpReq method; /* what kind of HTTP request (if any) is this */ + unsigned char timecondition; /* kind of time comparison: curl_TimeCond */ + unsigned char proxytype; /* what kind of proxy: curl_proxytype */ + unsigned char method; /* what kind of HTTP request: Curl_HttpReq */ 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 */ @@ -1724,8 +1755,8 @@ struct UserDefined { struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ #endif 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 */ + int dns_cache_timeout; /* DNS cache timeout (seconds) */ + unsigned int buffer_size; /* size of receive buffer to use */ unsigned int upload_buffer_size; /* size of upload buffer to use, keep it >= CURL_MAX_WRITE_SIZE */ void *private_data; /* application-private data */ @@ -1734,36 +1765,46 @@ struct UserDefined { file 0 - whatever, 1 - v2, 2 - v6 */ curl_off_t max_filesize; /* Maximum file size to download */ #ifndef CURL_DISABLE_FTP - curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ - curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ - curl_ftpccc ftp_ccc; /* FTP CCC options */ + unsigned char ftp_filemethod; /* how to get to a file: curl_ftpfile */ + unsigned char ftpsslauth; /* what AUTH XXX to try: curl_ftpauth */ + unsigned char ftp_ccc; /* FTP CCC options: curl_ftpccc */ + unsigned int accepttimeout; /* in milliseconds, 0 means no timeout */ +#endif + /* Desppie the name ftp_create_missing_dirs is for FTP(S) and SFTP + 1 - create directories that don't exist + 2 - the same but also allow MKD to fail once + */ + unsigned char ftp_create_missing_dirs; +#ifdef USE_LIBSSH2 + curl_sshhostkeycallback ssh_hostkeyfunc; /* hostkey check callback */ + void *ssh_hostkeyfunc_userp; /* custom pointer to callback */ #endif - int ftp_create_missing_dirs; /* 1 - create directories that don't exist - 2 - the same but also allow MKD to fail once - */ + 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 */ + unsigned char use_netrc; /* enum CURL_NETRC_OPTION values */ #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 */ - long new_directory_perms; /* Permissions to use when creating remote dirs */ - long ssh_auth_types; /* allowed SSH auth types */ + unsigned int new_file_perms; /* when creating remote files */ + unsigned int new_directory_perms; /* when creating remote dirs */ + int ssh_auth_types; /* allowed SSH auth types */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ struct curl_blob *blobs[BLOB_LAST]; #ifdef ENABLE_IPV6 unsigned int scope_id; /* Scope id for IPv6 */ #endif - long allowed_protocols; - long redir_protocols; - long mime_options; /* Mime option flags. */ - struct curl_slist *mail_rcpt; /* linked list of mail recipients */ + curl_prot_t allowed_protocols; + curl_prot_t redir_protocols; + unsigned int mime_options; /* Mime option flags. */ + +#ifndef CURL_DISABLE_RTSP + void *rtp_out; /* write RTP to this if non-NULL */ /* Common RTSP header options */ Curl_RtspReq rtspreq; /* RTSP request type */ - long rtspversion; /* like httpversion, for RTSP */ +#endif +#ifndef CURL_DISABLE_FTP curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer starts */ curl_chunk_end_callback chunk_end; /* called after part transferring @@ -1771,38 +1812,48 @@ struct UserDefined { curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds to pattern (e.g. if WILDCARDMATCH is on) */ void *fnmatch_data; - +#endif long gssapi_delegation; /* GSS-API credential delegation, see the documentation of CURLOPT_GSSAPI_DELEGATION */ - long tcp_keepidle; /* seconds in idle before sending keepalive probe */ - long tcp_keepintvl; /* seconds between TCP keepalive probes */ + int tcp_keepidle; /* seconds in idle before sending keepalive probe */ + int tcp_keepintvl; /* seconds between TCP keepalive probes */ size_t maxconnects; /* Max idle connections in the connection cache */ long expect_100_timeout; /* in milliseconds */ +#ifdef USE_HTTP2 struct Curl_easy *stream_depends_on; int stream_weight; struct Curl_http2_dep *stream_dependents; - +#endif curl_resolver_start_callback resolver_start; /* optional callback called before resolver start */ void *resolver_start_client; /* pointer to pass to resolver start callback */ long upkeep_interval_ms; /* Time between calls for connection upkeep. */ multidone_func fmultidone; +#ifndef CURL_DISABLE_DOH struct Curl_easy *dohfor; /* this is a DoH request for that transfer */ +#endif CURLU *uh; /* URL handle for the current parsed URL */ void *trailer_data; /* pointer to pass to trailer data callback */ curl_trailer_callback trailer_callback; /* trailing data callback */ + char keep_post; /* keep POSTs as POSTs after a 30x request; each + bit represents a request, from 301 to 303 */ +#ifndef CURL_DISABLE_SMTP + struct curl_slist *mail_rcpt; /* linked list of mail recipients */ + BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some + recipients */ +#endif + unsigned char connect_only; /* make connection/request, then let + application use the socket */ BIT(is_fread_set); /* has read callback been set to non-NULL? */ - BIT(is_fwrite_set); /* has write callback been set to non-NULL? */ - BIT(free_referer); /* set TRUE if 'referer' points to a string we - allocated */ +#ifndef CURL_DISABLE_TFTP BIT(tftp_no_options); /* do not send TFTP options requests */ +#endif BIT(sep_headers); /* handle host and proxy headers separately */ BIT(cookiesession); /* new cookie session? */ BIT(crlf); /* convert crlf on ftp upload(?) */ - BIT(strip_path_slash); /* strip off initial slash from path */ BIT(ssh_compression); /* enable SSH compression */ /* Here follows boolean settings that define how to behave during @@ -1820,6 +1871,7 @@ struct UserDefined { BIT(ftp_use_pret); /* if PRET is to be used before PASV or not */ BIT(ftp_skip_ip); /* skip the IP address the FTP server passes on to us */ + BIT(wildcard_enabled); /* enable wildcard matching */ #endif BIT(hide_progress); /* don't use the progress meter */ BIT(http_fail_on_error); /* fail on HTTP error codes >= 400 */ @@ -1840,7 +1892,6 @@ struct UserDefined { BIT(no_signal); /* do not use any signal/alarm handler */ BIT(tcp_nodelay); /* whether to enable TCP_NODELAY or not */ BIT(ignorecl); /* ignore content length */ - BIT(connect_only); /* make connection, let application use the socket */ BIT(http_te_skip); /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ BIT(http_ce_skip); /* pass the raw body data to the user, even when @@ -1851,10 +1902,8 @@ struct UserDefined { BIT(socks5_gssapi_nec); /* Flag to support NEC SOCKS5 server */ #endif BIT(sasl_ir); /* Enable/disable SASL initial response */ - BIT(wildcard_enabled); /* enable wildcard matching */ BIT(tcp_keepalive); /* use TCP keepalives */ BIT(tcp_fastopen); /* use TCP Fast Open */ - BIT(ssl_enable_npn); /* TLS NPN extension? */ BIT(ssl_enable_alpn);/* TLS ALPN extension? */ BIT(path_as_is); /* allow dotdots? */ BIT(pipewait); /* wait for multiplex status before starting a new @@ -1874,8 +1923,9 @@ struct UserDefined { BIT(doh_verifystatus); /* DoH certificate status verification */ #endif BIT(http09_allowed); /* allow HTTP/0.9 responses */ - BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some - recipients */ +#ifdef USE_WEBSOCKETS + BIT(ws_raw_mode); +#endif }; struct Names { @@ -1937,10 +1987,12 @@ struct Curl_easy { #endif struct SingleRequest req; /* Request-specific data */ struct UserDefined set; /* values set by the libcurl user */ +#ifndef CURL_DISABLE_COOKIES 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. */ +#endif #ifndef CURL_DISABLE_HSTS struct hsts *hsts; #endif diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c index d17e16f..b82b171 100644 --- a/Utilities/cmcurl/lib/vauth/cleartext.c +++ b/Utilities/cmcurl/lib/vauth/cleartext.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC4616 PLAIN authentication * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt> * diff --git a/Utilities/cmcurl/lib/vauth/cram.c b/Utilities/cmcurl/lib/vauth/cram.c index 9ddb0ac..475d31b 100644 --- a/Utilities/cmcurl/lib/vauth/cram.c +++ b/Utilities/cmcurl/lib/vauth/cram.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC2195 CRAM-MD5 authentication * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c index d461609..f945e8b 100644 --- a/Utilities/cmcurl/lib/vauth/digest.c +++ b/Utilities/cmcurl/lib/vauth/digest.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC2831 DIGEST-MD5 authentication * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication * @@ -47,6 +49,15 @@ #include "curl_memory.h" #include "memdebug.h" +#define SESSION_ALGO 1 /* for algos with this bit set */ + +#define ALGO_MD5 0 +#define ALGO_MD5SESS (ALGO_MD5 | SESSION_ALGO) +#define ALGO_SHA256 2 +#define ALGO_SHA256SESS (ALGO_SHA256 | SESSION_ALGO) +#define ALGO_SHA512_256 4 +#define ALGO_SHA512_256SESS (ALGO_SHA512_256 | SESSION_ALGO) + #if !defined(USE_WINDOWS_SSPI) #define DIGEST_QOP_VALUE_AUTH (1 << 0) #define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) @@ -79,44 +90,50 @@ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, } for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) { - switch(*str) { - case '\\': - if(!escape) { - /* possibly the start of an escaped quote */ - escape = TRUE; - *content++ = '\\'; /* Even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - - case ',': - if(!starts_with_quote) { - /* This signals the end of the content if we didn't get a starting - quote and then we do "sloppy" parsing */ - c = 0; /* the end */ - continue; - } - break; - - case '\r': - case '\n': - /* end of string */ - c = 0; - continue; + if(!escape) { + switch(*str) { + case '\\': + if(starts_with_quote) { + /* the start of an escaped quote */ + escape = TRUE; + continue; + } + break; + + case ',': + if(!starts_with_quote) { + /* This signals the end of the content if we didn't get a starting + quote and then we do "sloppy" parsing */ + c = 0; /* the end */ + continue; + } + break; - case '\"': - if(!escape && starts_with_quote) { + case '\r': + case '\n': /* end of string */ + if(starts_with_quote) + return FALSE; /* No closing quote */ c = 0; continue; + + case '\"': + if(starts_with_quote) { + /* end of string */ + c = 0; + continue; + } + else + return FALSE; + break; } - break; } escape = FALSE; *content++ = *str; } + if(escape) + return FALSE; /* No character after backslash */ *content = 0; *endptr = str; @@ -365,7 +382,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) return CURLE_BAD_CONTENT_ENCODING; - /* Generate 32 random hex chars, 32 bytes + 1 zero termination */ + /* Generate 32 random hex chars, 32 bytes + 1 null-termination */ result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce)); if(result) return result; @@ -504,7 +521,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, char content[DIGEST_MAX_CONTENT_LENGTH]; /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Extract a value=content pair */ @@ -543,6 +560,9 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, token = strtok_r(tmp, ",", &tok_buf); while(token) { + /* Pass additional spaces here */ + while(*token && ISBLANK(*token)) + token++; if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; } @@ -575,17 +595,17 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, return CURLE_OUT_OF_MEMORY; if(strcasecompare(content, "MD5-sess")) - digest->algo = CURLDIGESTALGO_MD5SESS; + digest->algo = ALGO_MD5SESS; else if(strcasecompare(content, "MD5")) - digest->algo = CURLDIGESTALGO_MD5; + digest->algo = ALGO_MD5; else if(strcasecompare(content, "SHA-256")) - digest->algo = CURLDIGESTALGO_SHA256; + digest->algo = ALGO_SHA256; else if(strcasecompare(content, "SHA-256-SESS")) - digest->algo = CURLDIGESTALGO_SHA256SESS; + digest->algo = ALGO_SHA256SESS; else if(strcasecompare(content, "SHA-512-256")) - digest->algo = CURLDIGESTALGO_SHA512_256; + digest->algo = ALGO_SHA512_256; else if(strcasecompare(content, "SHA-512-256-SESS")) - digest->algo = CURLDIGESTALGO_SHA512_256SESS; + digest->algo = ALGO_SHA512_256SESS; else return CURLE_BAD_CONTENT_ENCODING; } @@ -602,7 +622,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, break; /* We're done here */ /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Allow the list to be comma-separated */ @@ -620,6 +640,10 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, if(!digest->nonce) return CURLE_BAD_CONTENT_ENCODING; + /* "<algo>-sess" protocol versions require "auth" or "auth-int" qop */ + if(!digest->qop && (digest->algo & SESSION_ALGO)) + return CURLE_BAD_CONTENT_ENCODING; + return CURLE_OK; } @@ -664,6 +688,8 @@ static CURLcode auth_create_digest_http_message( char *cnonce = NULL; size_t cnonce_sz = 0; char *userp_quoted; + char *realm_quoted; + char *nonce_quoted; char *response = NULL; char *hashthis = NULL; char *tmp = NULL; @@ -687,7 +713,7 @@ static CURLcode auth_create_digest_http_message( } if(digest->userhash) { - hashthis = aprintf("%s:%s", userp, digest->realm); + hashthis = aprintf("%s:%s", userp, digest->realm ? digest->realm : ""); if(!hashthis) return CURLE_OUT_OF_MEMORY; @@ -707,7 +733,8 @@ static CURLcode auth_create_digest_http_message( unq(nonce-value) ":" unq(cnonce-value) */ - hashthis = aprintf("%s:%s:%s", userp, digest->realm, passwdp); + hashthis = aprintf("%s:%s:%s", userp, digest->realm ? digest->realm : "", + passwdp); if(!hashthis) return CURLE_OUT_OF_MEMORY; @@ -715,9 +742,7 @@ static CURLcode auth_create_digest_http_message( free(hashthis); convert_to_ascii(hashbuf, ha1); - if(digest->algo == CURLDIGESTALGO_MD5SESS || - digest->algo == CURLDIGESTALGO_SHA256SESS || - digest->algo == CURLDIGESTALGO_SHA512_256SESS) { + if(digest->algo & SESSION_ALGO) { /* nonce and cnonce are OUTSIDE the hash */ tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); if(!tmp) @@ -786,16 +811,33 @@ static CURLcode auth_create_digest_http_message( nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" Digest parameters are all quoted strings. Username which is provided by - the user will need double quotes and backslashes within it escaped. For - the other fields, this shouldn't be an issue. realm, nonce, and opaque - are copied as is from the server, escapes and all. cnonce is generated - with web-safe characters. uri is already percent encoded. nc is 8 hex + the user will need double quotes and backslashes within it escaped. + realm, nonce, and opaque will need backslashes as well as they were + de-escaped when copied from request header. cnonce is generated with + web-safe characters. uri is already percent encoded. nc is 8 hex characters. algorithm and qop with standard values only contain web-safe characters. */ userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp); if(!userp_quoted) return CURLE_OUT_OF_MEMORY; + if(digest->realm) + realm_quoted = auth_digest_string_quoted(digest->realm); + else { + realm_quoted = malloc(1); + if(realm_quoted) + realm_quoted[0] = 0; + } + if(!realm_quoted) { + free(userp_quoted); + return CURLE_OUT_OF_MEMORY; + } + nonce_quoted = auth_digest_string_quoted(digest->nonce); + if(!nonce_quoted) { + free(realm_quoted); + free(userp_quoted); + return CURLE_OUT_OF_MEMORY; + } if(digest->qop) { response = aprintf("username=\"%s\", " @@ -807,18 +849,16 @@ static CURLcode auth_create_digest_http_message( "qop=%s, " "response=\"%s\"", userp_quoted, - digest->realm, - digest->nonce, + realm_quoted, + nonce_quoted, uripath, digest->cnonce, digest->nc, digest->qop, request_digest); - if(strcasecompare(digest->qop, "auth")) - digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 - padded which tells to the server how many times you are - using the same nonce in the qop=auth mode */ + /* Increment nonce-count to use another nc value for the next request */ + digest->nc++; } else { response = aprintf("username=\"%s\", " @@ -827,20 +867,29 @@ static CURLcode auth_create_digest_http_message( "uri=\"%s\", " "response=\"%s\"", userp_quoted, - digest->realm, - digest->nonce, + realm_quoted, + nonce_quoted, uripath, request_digest); } + free(nonce_quoted); + free(realm_quoted); free(userp_quoted); if(!response) return CURLE_OUT_OF_MEMORY; /* Add the optional fields */ if(digest->opaque) { + char *opaque_quoted; /* Append the opaque */ - tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); + opaque_quoted = auth_digest_string_quoted(digest->opaque); + if(!opaque_quoted) { + free(response); + return CURLE_OUT_OF_MEMORY; + } + tmp = aprintf("%s, opaque=\"%s\"", response, opaque_quoted); free(response); + free(opaque_quoted); if(!tmp) return CURLE_OUT_OF_MEMORY; @@ -902,28 +951,18 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, struct digestdata *digest, char **outptr, size_t *outlen) { - switch(digest->algo) { - case CURLDIGESTALGO_MD5: - case CURLDIGESTALGO_MD5SESS: + if(digest->algo <= ALGO_MD5SESS) return auth_create_digest_http_message(data, userp, passwdp, request, uripath, digest, outptr, outlen, auth_digest_md5_to_ascii, Curl_md5it); - - case CURLDIGESTALGO_SHA256: - case CURLDIGESTALGO_SHA256SESS: - case CURLDIGESTALGO_SHA512_256: - case CURLDIGESTALGO_SHA512_256SESS: - return auth_create_digest_http_message(data, userp, passwdp, - request, uripath, digest, - outptr, outlen, - auth_digest_sha256_to_ascii, - Curl_sha256it); - - default: - return CURLE_UNSUPPORTED_PROTOCOL; - } + DEBUGASSERT(digest->algo <= ALGO_SHA512_256SESS); + return auth_create_digest_http_message(data, userp, passwdp, + request, uripath, digest, + outptr, outlen, + auth_digest_sha256_to_ascii, + Curl_sha256it); } /* @@ -946,7 +985,7 @@ void Curl_auth_digest_cleanup(struct digestdata *digest) Curl_safefree(digest->algorithm); digest->nc = 0; - digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ + digest->algo = ALGO_MD5; /* default algorithm */ digest->stale = FALSE; /* default means normal, not stale */ digest->userhash = FALSE; } diff --git a/Utilities/cmcurl/lib/vauth/digest.h b/Utilities/cmcurl/lib/vauth/digest.h index ee373cd..d785bdd 100644 --- a/Utilities/cmcurl/lib/vauth/digest.h +++ b/Utilities/cmcurl/lib/vauth/digest.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> @@ -29,15 +31,6 @@ #define DIGEST_MAX_VALUE_LENGTH 256 #define DIGEST_MAX_CONTENT_LENGTH 1024 -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS, - CURLDIGESTALGO_SHA256, - CURLDIGESTALGO_SHA256SESS, - CURLDIGESTALGO_SHA512_256, - CURLDIGESTALGO_SHA512_256SESS -}; - /* This is used to extract the realm from a challenge message */ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, const char **endptr); diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c index 94f8f8c..89a9db5 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 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2015 - 2022, 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 @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC2831 DIGEST-MD5 authentication * ***************************************************************************/ @@ -257,7 +259,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, char content[DIGEST_MAX_CONTENT_LENGTH]; /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Extract a value=content pair */ @@ -290,7 +292,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, break; /* We're done here */ /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) + while(*chlg && ISBLANK(*chlg)) chlg++; /* Allow the list to be comma-separated */ @@ -331,7 +333,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, char value[DIGEST_MAX_VALUE_LENGTH]; char content[DIGEST_MAX_CONTENT_LENGTH]; - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(!Curl_auth_digest_get_pair(p, value, content, &p)) @@ -343,7 +345,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, break; } - while(*p && ISSPACE(*p)) + while(*p && ISBLANK(*p)) p++; if(',' == *p) @@ -429,8 +431,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, has changed then delete that context. */ if((userp && !digest->user) || (!userp && digest->user) || (passwdp && !digest->passwd) || (!passwdp && digest->passwd) || - (userp && digest->user && strcmp(userp, digest->user)) || - (passwdp && digest->passwd && strcmp(passwdp, digest->passwd))) { + (userp && digest->user && Curl_timestrcmp(userp, digest->user)) || + (passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) { if(digest->http_context) { s_pSecFn->DeleteSecurityContext(digest->http_context); Curl_safefree(digest->http_context); diff --git a/Utilities/cmcurl/lib/vauth/gsasl.c b/Utilities/cmcurl/lib/vauth/gsasl.c index 40fef53..a73c644 100644 --- a/Utilities/cmcurl/lib/vauth/gsasl.c +++ b/Utilities/cmcurl/lib/vauth/gsasl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020 - 2021, Simon Josefsson, <simon@josefsson.org>, et al. + * Copyright (C) 2020 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC5802 SCRAM-SHA-1 authentication * ***************************************************************************/ @@ -34,7 +36,8 @@ #include <gsasl.h> -/* The last #include files should be: */ +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c index 67d43bd..bac7804 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 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2015 - 2022, 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 @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c index c652fd7..895b4a1 100644 --- a/Utilities/cmcurl/lib/vauth/krb5_sspi.c +++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2021, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2014 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c index 115f70b..c10fa6c 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm.c +++ b/Utilities/cmcurl/lib/vauth/ntlm.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -27,7 +29,7 @@ /* * NTLM details: * - * https://davenport.sourceforge.io/ntlm.html + * https://davenport.sourceforge.net/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -62,6 +64,10 @@ /* "NTLMSSP" signature is always in ASCII regardless of the platform */ #define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" +/* The fixed host name we provide, in order to not leak our real local host + name. Copy the name used by Firefox. */ +#define NTLM_HOSTNAME "WORKSTATION" + #if DEBUG_ME # define DEBUG_OUT(x) x static void ntlm_print_flags(FILE *handle, unsigned long flags) @@ -521,6 +527,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, userlen = strlen(user); +#ifndef NTLM_HOSTNAME /* Get the machine's un-qualified host name as NTLM doesn't like the fully qualified domain name */ if(Curl_gethostname(host, sizeof(host))) { @@ -530,6 +537,10 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, else { hostlen = strlen(host); } +#else + (void)msnprintf(host, sizeof(host), "%s", NTLM_HOSTNAME); + hostlen = sizeof(NTLM_HOSTNAME)-1; +#endif if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { unsigned char ntbuffer[0x18]; @@ -589,7 +600,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* A safer but less compatible alternative is: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */ + * See https://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ } if(unicode) { @@ -647,7 +658,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, /* LanManager response */ /* NT response */ - 0, /* zero termination */ + 0, /* null-termination */ 0, 0, 0, /* type-3 long, the 24 upper bits */ SHORTPAIR(0x18), /* LanManager response length, twice */ diff --git a/Utilities/cmcurl/lib/vauth/ntlm.h b/Utilities/cmcurl/lib/vauth/ntlm.h index 8ec23ad..4dfda55 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm.h +++ b/Utilities/cmcurl/lib/vauth/ntlm.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -32,7 +34,8 @@ /* Stuff only required for curl_ntlm_msgs.c */ #ifdef BUILDING_CURL_NTLM_MSGS_C -/* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */ +/* Flag bits definitions based on + https://davenport.sourceforge.net/ntlm.html */ #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) /* Indicates that Unicode strings are supported for use in security buffer diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c index 3e39dad..193576a 100644 --- a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c +++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vauth/oauth2.c b/Utilities/cmcurl/lib/vauth/oauth2.c index a5f16a0..1604b30 100644 --- a/Utilities/cmcurl/lib/vauth/oauth2.c +++ b/Utilities/cmcurl/lib/vauth/oauth2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC6749 OAuth 2.0 Authorization Framework * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c index 8c1a3ed..25dff96 100644 --- a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC4178 Simple and Protected GSS-API Negotiation Mechanism * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c index d219d8b..d845cac 100644 --- a/Utilities/cmcurl/lib/vauth/spnego_sspi.c +++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * * RFC4178 Simple and Protected GSS-API Negotiation Mechanism * ***************************************************************************/ diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c index 3624fb0..58fe051 100644 --- a/Utilities/cmcurl/lib/vauth/vauth.c +++ b/Utilities/cmcurl/lib/vauth/vauth.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2014 - 2021, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2014 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -25,6 +27,8 @@ #include <curl/curl.h> #include "vauth.h" +#include "urldata.h" +#include "strcase.h" #include "curl_multibyte.h" #include "curl_printf.h" @@ -142,3 +146,18 @@ bool Curl_auth_user_contains_domain(const char *user) return valid; } + +/* + * Curl_auth_ollowed_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_auth_allowed_to_host(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + return (!data->state.this_is_a_follow || + data->set.allow_auth_to_other_hosts || + (data->state.first_host && + strcasecompare(data->state.first_host, conn->host.name) && + (data->state.first_remote_port == conn->remote_port) && + (data->state.first_remote_protocol == conn->handler->protocol))); +} diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h index 6e12378..af27f01 100644 --- a/Utilities/cmcurl/lib/vauth/vauth.h +++ b/Utilities/cmcurl/lib/vauth/vauth.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> @@ -52,6 +54,12 @@ struct gsasldata; #define GSS_ERROR(status) ((status) & 0x80000000) #endif +/* + * Curl_auth_allowed_to_host() tells if authentication, cookies or other + * "sensitive data" can (still) be sent to this host. + */ +bool Curl_auth_allowed_to_host(struct Curl_easy *data); + /* This is used to build a SPN string */ #if !defined(USE_WINDOWS_SSPI) char *Curl_auth_build_spn(const char *service, const char *host, @@ -222,7 +230,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, CURLcode Curl_auth_create_spnego_message(struct negotiatedata *nego, char **outptr, size_t *outlen); -/* This is used to clean up the SPNEGO specifiec data */ +/* This is used to clean up the SPNEGO specific data */ void Curl_auth_cleanup_spnego(struct negotiatedata *nego); #endif /* USE_SPNEGO */ diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c index 5e3e428..cb44eb4 100644 --- a/Utilities/cmcurl/lib/version.c +++ b/Utilities/cmcurl/lib/version.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -29,6 +31,7 @@ #include "vssh/ssh.h" #include "quic.h" #include "curl_printf.h" +#include "easy_lock.h" #ifdef USE_ARES # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ @@ -50,7 +53,7 @@ #include <librtmp/rtmp.h> #endif -#ifdef HAVE_ZLIB_H +#ifdef HAVE_LIBZ #include <cm3p/zlib.h> #endif @@ -335,6 +338,11 @@ static const char * const protocols[] = { #endif #ifdef USE_LIBRTMP "rtmp", + "rtmpe", + "rtmps", + "rtmpt", + "rtmpte", + "rtmpts", #endif #ifndef CURL_DISABLE_RTSP "rtsp", @@ -364,6 +372,12 @@ static const char * const protocols[] = { #ifndef CURL_DISABLE_TFTP "tftp", #endif +#ifdef USE_WEBSOCKETS + "ws", +#endif +#if defined(USE_SSL) && defined(USE_WEBSOCKETS) + "wss", +#endif NULL }; @@ -451,6 +465,9 @@ static curl_version_info_data version_info = { #if defined(USE_GSASL) | CURL_VERSION_GSASL #endif +#if defined(GLOBAL_INIT_IS_THREADSAFE) + | CURL_VERSION_THREADSAFE +#endif , NULL, /* ssl_version */ 0, /* ssl_version_num, this is kept at zero */ diff --git a/Utilities/cmcurl/lib/version_win32.c b/Utilities/cmcurl/lib/version_win32.c index afdb1d6..e8f14f9 100644 --- a/Utilities/cmcurl/lib/version_win32.c +++ b/Utilities/cmcurl/lib/version_win32.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/version_win32.h b/Utilities/cmcurl/lib/version_win32.h index 38af87f..7a9a6a1 100644 --- a/Utilities/cmcurl/lib/version_win32.h +++ b/Utilities/cmcurl/lib/version_win32.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2016 - 2021, Steve Holme, <steve_holme@hotmail.com>. + * Copyright (C) 2016 - 2022, 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 @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vquic/msh3.c b/Utilities/cmcurl/lib/vquic/msh3.c index f7bd315..c3e58e7 100644 --- a/Utilities/cmcurl/lib/vquic/msh3.c +++ b/Utilities/cmcurl/lib/vquic/msh3.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -25,7 +27,6 @@ #ifdef USE_MSH3 #include "urldata.h" -#include "curl_printf.h" #include "timeval.h" #include "multiif.h" #include "sendf.h" @@ -33,6 +34,11 @@ #include "h2h3.h" #include "msh3.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + /* #define DEBUG_HTTP3 1 */ #ifdef DEBUG_HTTP3 #define H3BUGF(x) x @@ -108,7 +114,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, socklen_t addrlen) { struct quicsocket *qs = &conn->hequic[sockindex]; - bool unsecure = !conn->ssl_config.verifypeer; + bool insecure = !conn->ssl_config.verifypeer; memset(qs, 0, sizeof(*qs)); (void)sockfd; @@ -126,7 +132,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, qs->conn = MsH3ConnectionOpen(qs->api, conn->host.name, (uint16_t)conn->remote_port, - unsecure); + insecure); if(!qs->conn) { failf(data, "can't create msh3 connection"); if(qs->api) { @@ -220,13 +226,8 @@ static unsigned int msh3_conncheck(struct Curl_easy *data, return CONNRESULT_NONE; } -static void msh3_cleanup(struct quicsocket *qs, struct HTTP *stream) +static void disconnect(struct quicsocket *qs) { - if(stream && stream->recv_buf) { - free(stream->recv_buf); - stream->recv_buf = ZERO_NULL; - msh3_lock_uninitialize(&stream->recv_lock); - } if(qs->conn) { MsH3ConnectionClose(qs->conn); qs->conn = ZERO_NULL; @@ -240,18 +241,20 @@ static void msh3_cleanup(struct quicsocket *qs, struct HTTP *stream) static CURLcode msh3_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { + (void)data; (void)dead_connection; H3BUGF(infof(data, "disconnecting (msh3)")); - msh3_cleanup(conn->quic, data->req.p.http); + disconnect(conn->quic); return CURLE_OK; } void Curl_quic_disconnect(struct Curl_easy *data, struct connectdata *conn, int tempindex) { + (void)data; if(conn->transport == TRNSPRT_QUIC) { - H3BUGF(infof(data, "disconnecting (curl)")); - msh3_cleanup(&conn->hequic[tempindex], data->req.p.http); + H3BUGF(infof(data, "disconnecting QUIC index %u", tempindex)); + disconnect(&conn->hequic[tempindex]); } } @@ -286,7 +289,6 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request, struct HTTP *stream = IfContext; size_t total_len; (void)Request; - H3BUGF(printf("* msh3_header_received\n")); if(stream->recv_header_complete) { H3BUGF(printf("* ignoring header after data\n")); @@ -379,9 +381,6 @@ static void MSH3_CALL msh3_shutdown(MSH3_REQUEST *Request, void *IfContext) (void)stream; } -static_assert(sizeof(MSH3_HEADER) == sizeof(struct h2h3pseudo), - "Sizes must match for cast below to work"); - static ssize_t msh3_stream_send(struct Curl_easy *data, int sockindex, const void *mem, @@ -394,6 +393,9 @@ static ssize_t msh3_stream_send(struct Curl_easy *data, struct h2h3req *hreq; (void)sockindex; + /* Sizes must match for cast below to work" */ + DEBUGASSERT(sizeof(MSH3_HEADER) == sizeof(struct h2h3pseudo)); + H3BUGF(infof(data, "msh3_stream_send %zu", len)); if(!stream->req) { @@ -488,9 +490,19 @@ CURLcode Curl_quic_done_sending(struct Curl_easy *data) void Curl_quic_done(struct Curl_easy *data, bool premature) { - (void)data; + struct HTTP *stream = data->req.p.http; (void)premature; H3BUGF(infof(data, "Curl_quic_done")); + if(stream) { + if(stream->recv_buf) { + Curl_safefree(stream->recv_buf); + msh3_lock_uninitialize(&stream->recv_lock); + } + if(stream->req) { + MsH3RequestClose(stream->req); + stream->req = ZERO_NULL; + } + } } bool Curl_quic_data_pending(const struct Curl_easy *data) @@ -500,4 +512,16 @@ bool Curl_quic_data_pending(const struct Curl_easy *data) return stream->recv_header_len || stream->recv_data_len; } +/* + * Called from transfer.c:Curl_readwrite when neither HTTP level read + * nor write is performed. It is a good place to handle timer expiry + * for QUIC transport. + */ +CURLcode Curl_quic_idle(struct Curl_easy *data) +{ + (void)data; + H3BUGF(infof(data, "Curl_quic_idle")); + return CURLE_OK; +} + #endif /* USE_MSH3 */ diff --git a/Utilities/cmcurl/lib/vquic/msh3.h b/Utilities/cmcurl/lib/vquic/msh3.h index bacdcb1..ce884d9 100644 --- a/Utilities/cmcurl/lib/vquic/msh3.h +++ b/Utilities/cmcurl/lib/vquic/msh3.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.c b/Utilities/cmcurl/lib/vquic/ngtcp2.c index f1a64ee..097cca4 100644 --- a/Utilities/cmcurl/lib/vquic/ngtcp2.c +++ b/Utilities/cmcurl/lib/vquic/ngtcp2.c @@ -18,21 +18,29 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NGTCP2 #include <ngtcp2/ngtcp2.h> -#include <ngtcp2/ngtcp2_crypto.h> #include <nghttp3/nghttp3.h> #ifdef USE_OPENSSL #include <openssl/err.h> +#ifdef OPENSSL_IS_BORINGSSL +#include <ngtcp2/ngtcp2_crypto_boringssl.h> +#else #include <ngtcp2/ngtcp2_crypto_openssl.h> +#endif #include "vtls/openssl.h" #elif defined(USE_GNUTLS) #include <ngtcp2/ngtcp2_crypto_gnutls.h> #include "vtls/gtls.h" +#elif defined(USE_WOLFSSL) +#include <ngtcp2/ngtcp2_crypto_wolfssl.h> +#include "vtls/wolfssl.h" #endif #include "urldata.h" #include "sendf.h" @@ -96,17 +104,32 @@ struct h3out { "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \ "%DISABLE_TLS13_COMPAT_MODE" +#elif defined(USE_WOLFSSL) +#define QUIC_CIPHERS \ + "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ + "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" +#define QUIC_GROUPS "P-256:P-384:P-521" #endif +/* ngtcp2 default congestion controller does not perform pacing. Limit + the maximum packet burst to MAX_PKT_BURST packets. */ +#define MAX_PKT_BURST 10 + static CURLcode ng_process_ingress(struct Curl_easy *data, curl_socket_t sockfd, struct quicsocket *qs); static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd, struct quicsocket *qs); static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, - size_t datalen, void *user_data, + uint64_t datalen, void *user_data, void *stream_user_data); +static ngtcp2_conn *get_conn(ngtcp2_crypto_conn_ref *conn_ref) +{ + struct quicsocket *qs = conn_ref->user_data; + return qs->qconn; +} + static ngtcp2_tstamp timestamp(void) { struct curltime ct = Curl_now(); @@ -187,91 +210,44 @@ static int keylog_callback(gnutls_session_t session, const char *label, Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size); return 0; } -#endif - -static int init_ngh3_conn(struct quicsocket *qs); - -static int write_client_handshake(struct quicsocket *qs, - ngtcp2_crypto_level level, - const uint8_t *data, size_t len) -{ - int rv; - - rv = ngtcp2_conn_submit_crypto_data(qs->qconn, level, data, len); - if(rv) { - H3BUGF(fprintf(stderr, "write_client_handshake failed\n")); - } - assert(0 == rv); - - return 1; -} - -#ifdef USE_OPENSSL -static int quic_set_encryption_secrets(SSL *ssl, - OSSL_ENCRYPTION_LEVEL ossl_level, - const uint8_t *rx_secret, - const uint8_t *tx_secret, - size_t secretlen) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - 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) - return 0; - - if(ngtcp2_crypto_derive_and_install_tx_key( - qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) - return 0; - - if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) { - if(init_ngh3_conn(qs) != CURLE_OK) - return 0; - } - - return 1; -} - -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 = - ngtcp2_crypto_openssl_from_ossl_encryption_level(ossl_level); - - return write_client_handshake(qs, level, data, len); -} - -static int quic_flush_flight(SSL *ssl) +#elif defined(USE_WOLFSSL) +#if defined(HAVE_SECRET_CALLBACK) +static void keylog_callback(const WOLFSSL *ssl, const char *line) { (void)ssl; - return 1; -} - -static int quic_send_alert(SSL *ssl, enum ssl_encryption_level_t level, - uint8_t alert) -{ - struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl); - (void)level; - - qs->tls_alert = alert; - return 1; + Curl_tls_keylog_write_line(line); } +#endif +#endif -static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets, - quic_add_handshake_data, - quic_flush_flight, quic_send_alert}; +static int init_ngh3_conn(struct quicsocket *qs); +#ifdef USE_OPENSSL static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) { struct connectdata *conn = data->conn; SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION); - SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION); +#ifdef OPENSSL_IS_BORINGSSL + if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed"); + return NULL; + } +#else + if(ngtcp2_crypto_openssl_configure_client_context(ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_openssl_configure_client_context failed"); + return NULL; + } +#endif SSL_CTX_set_default_verify_paths(ssl_ctx); +#ifdef OPENSSL_IS_BORINGSSL + if(SSL_CTX_set1_curves_list(ssl_ctx, QUIC_GROUPS) != 1) { + failf(data, "SSL_CTX_set1_curves_list failed"); + return NULL; + } +#else if(SSL_CTX_set_ciphersuites(ssl_ctx, QUIC_CIPHERS) != 1) { char error_buffer[256]; ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); @@ -283,8 +259,7 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) failf(data, "SSL_CTX_set1_groups_list failed"); return NULL; } - - SSL_CTX_set_quic_method(ssl_ctx, &quic_method); +#endif /* Open the file if a TLS or QUIC backend has not done this before. */ Curl_tls_keylog_open(); @@ -353,7 +328,7 @@ static int quic_init_ssl(struct quicsocket *qs) DEBUGASSERT(!qs->ssl); qs->ssl = SSL_new(qs->sslctx); - SSL_set_app_data(qs->ssl, qs); + SSL_set_app_data(qs->ssl, &qs->conn_ref); SSL_set_connect_state(qs->ssl); SSL_set_quic_use_legacy_codepoint(qs->ssl, 0); @@ -367,107 +342,6 @@ static int quic_init_ssl(struct quicsocket *qs) return 0; } #elif defined(USE_GNUTLS) -static int secret_func(gnutls_session_t ssl, - gnutls_record_encryption_level_t gtls_level, - const void *rx_secret, - const void *tx_secret, size_t secretlen) -{ - struct quicsocket *qs = gnutls_session_get_ptr(ssl); - 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( - qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0) - return 0; - - if(ngtcp2_crypto_derive_and_install_tx_key( - qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0) - return 0; - - if(level == NGTCP2_CRYPTO_LEVEL_APPLICATION) { - if(init_ngh3_conn(qs) != CURLE_OK) - return -1; - } - - return 0; -} - -static int read_func(gnutls_session_t ssl, - gnutls_record_encryption_level_t gtls_level, - gnutls_handshake_description_t htype, const void *data, - size_t len) -{ - struct quicsocket *qs = gnutls_session_get_ptr(ssl); - ngtcp2_crypto_level level = - ngtcp2_crypto_gnutls_from_gnutls_record_encryption_level(gtls_level); - int rv; - - if(htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC) - return 0; - - rv = write_client_handshake(qs, level, data, len); - if(rv == 0) - return -1; - - return 0; -} - -static int alert_read_func(gnutls_session_t ssl, - gnutls_record_encryption_level_t gtls_level, - gnutls_alert_level_t alert_level, - gnutls_alert_description_t alert_desc) -{ - struct quicsocket *qs = gnutls_session_get_ptr(ssl); - (void)gtls_level; - (void)alert_level; - - qs->tls_alert = alert_desc; - return 1; -} - -static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data, - size_t data_size) -{ - struct quicsocket *qs = gnutls_session_get_ptr(ssl); - ngtcp2_transport_params params; - - if(ngtcp2_decode_transport_params( - ¶ms, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS, - data, data_size) != 0) - return -1; - - if(ngtcp2_conn_set_remote_transport_params(qs->qconn, ¶ms) != 0) - return -1; - - return 0; -} - -static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata) -{ - struct quicsocket *qs = gnutls_session_get_ptr(ssl); - uint8_t paramsbuf[64]; - ngtcp2_transport_params params; - ssize_t nwrite; - int rc; - - ngtcp2_conn_get_local_transport_params(qs->qconn, ¶ms); - nwrite = ngtcp2_encode_transport_params( - paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO, - ¶ms); - if(nwrite < 0) { - H3BUGF(fprintf(stderr, "ngtcp2_encode_transport_params: %s\n", - ngtcp2_strerror((int)nwrite))); - return -1; - } - - rc = gnutls_buffer_append_data(extdata, paramsbuf, nwrite); - if(rc < 0) - return rc; - - return (int)nwrite; -} - static int quic_init_ssl(struct quicsocket *qs) { gnutls_datum_t alpn[2]; @@ -478,26 +352,17 @@ static int quic_init_ssl(struct quicsocket *qs) DEBUGASSERT(!qs->ssl); gnutls_init(&qs->ssl, GNUTLS_CLIENT); - gnutls_session_set_ptr(qs->ssl, qs); + gnutls_session_set_ptr(qs->ssl, &qs->conn_ref); - rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL); - if(rc < 0) { - H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n", - gnutls_strerror(rc))); + if(ngtcp2_crypto_gnutls_configure_client_session(qs->ssl) != 0) { + H3BUGF(fprintf(stderr, + "ngtcp2_crypto_gnutls_configure_client_session failed\n")); return 1; } - gnutls_handshake_set_secret_function(qs->ssl, secret_func); - gnutls_handshake_set_read_function(qs->ssl, read_func); - gnutls_alert_set_read_function(qs->ssl, alert_read_func); - - rc = gnutls_session_ext_register(qs->ssl, "QUIC Transport Parameters", - NGTCP2_TLSEXT_QUIC_TRANSPORT_PARAMETERS_V1, GNUTLS_EXT_TLS, - tp_recv_func, tp_send_func, NULL, NULL, NULL, - GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | - GNUTLS_EXT_FLAG_EE); + rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL); if(rc < 0) { - H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n", + H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n", gnutls_strerror(rc))); return 1; } @@ -546,7 +411,105 @@ static int quic_init_ssl(struct quicsocket *qs) gnutls_server_name_set(qs->ssl, GNUTLS_NAME_DNS, hostname, strlen(hostname)); return 0; } +#elif defined(USE_WOLFSSL) + +static WOLFSSL_CTX *quic_ssl_ctx(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + WOLFSSL_CTX *ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()); + + if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) { + failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed"); + return NULL; + } + + wolfSSL_CTX_set_default_verify_paths(ssl_ctx); + + if(wolfSSL_CTX_set_cipher_list(ssl_ctx, QUIC_CIPHERS) != 1) { + char error_buffer[256]; + ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer)); + failf(data, "SSL_CTX_set_ciphersuites: %s", error_buffer); + return NULL; + } + + if(wolfSSL_CTX_set1_groups_list(ssl_ctx, (char *)QUIC_GROUPS) != 1) { + failf(data, "SSL_CTX_set1_groups_list failed"); + return NULL; + } + + /* Open the file if a TLS or QUIC backend has not done this before. */ + Curl_tls_keylog_open(); + if(Curl_tls_keylog_enabled()) { +#if defined(HAVE_SECRET_CALLBACK) + wolfSSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback); +#else + failf(data, "wolfSSL was built without keylog callback"); + return NULL; +#endif + } + + if(conn->ssl_config.verifypeer) { + const char * const ssl_cafile = conn->ssl_config.CAfile; + const char * const ssl_capath = conn->ssl_config.CApath; + + if(ssl_cafile || ssl_capath) { + wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + /* tell wolfSSL where to find CA certificates that are used to verify + the server's certificate. */ + if(!wolfSSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return NULL; + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } +#ifdef CURL_CA_FALLBACK + else { + /* verifying the peer without any CA certificates won't work so + use wolfssl's built-in default as fallback */ + wolfSSL_CTX_set_default_verify_paths(ssl_ctx); + } #endif + } + else { + wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL); + } + + return ssl_ctx; +} + +/** SSL callbacks ***/ + +static int quic_init_ssl(struct quicsocket *qs) +{ + const uint8_t *alpn = NULL; + size_t alpnlen = 0; + /* this will need some attention when HTTPS proxy over QUIC get fixed */ + const char * const hostname = qs->conn->host.name; + + DEBUGASSERT(!qs->ssl); + qs->ssl = SSL_new(qs->sslctx); + + wolfSSL_set_app_data(qs->ssl, &qs->conn_ref); + wolfSSL_set_connect_state(qs->ssl); + wolfSSL_set_quic_use_legacy_codepoint(qs->ssl, 0); + + alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3; + alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1; + if(alpn) + wolfSSL_set_alpn_protos(qs->ssl, alpn, (int)alpnlen); + + /* set SNI */ + wolfSSL_UseSNI(qs->ssl, WOLFSSL_SNI_HOST_NAME, + hostname, (unsigned short)strlen(hostname)); + + return 0; +} +#endif /* defined(USE_WOLFSSL) */ static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data) { @@ -571,7 +534,7 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags, void *user_data, void *stream_user_data) { struct quicsocket *qs = (struct quicsocket *)user_data; - ssize_t nconsumed; + nghttp3_ssize nconsumed; int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0; (void)offset; (void)stream_user_data; @@ -579,6 +542,9 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags, nconsumed = nghttp3_conn_read_stream(qs->h3conn, stream_id, buf, buflen, fin); if(nconsumed < 0) { + ngtcp2_connection_close_error_set_application_error( + &qs->last_error, nghttp3_err_infer_quic_app_error_code((int)nconsumed), + NULL, 0); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -629,6 +595,8 @@ static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags, rv = nghttp3_conn_close_stream(qs->h3conn, stream_id, app_error_code); if(rv) { + ngtcp2_connection_close_error_set_application_error( + &qs->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0); return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -735,6 +703,23 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid, return 0; } +static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_crypto_level level, + void *user_data) +{ + struct quicsocket *qs = (struct quicsocket *)user_data; + (void)tconn; + + if(level != NGTCP2_CRYPTO_LEVEL_APPLICATION) { + return 0; + } + + if(init_ngh3_conn(qs) != CURLE_OK) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_client_initial_cb, NULL, /* recv_client_initial */ @@ -773,6 +758,9 @@ static ngtcp2_callbacks ng_callbacks = { ngtcp2_crypto_get_path_challenge_data_cb, cb_stream_stop_sending, NULL, /* version_negotiation */ + cb_recv_rx_key, + NULL, /* recv_tx_key */ + NULL, /* early_data_rejected */ }; /* @@ -818,6 +806,10 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, result = quic_set_client_cert(data, qs); if(result) return result; +#elif defined(USE_WOLFSSL) + qs->sslctx = quic_ssl_ctx(data); + if(!qs->sslctx) + return CURLE_QUIC_CONNECT_ERROR; #endif if(quic_init_ssl(qs)) @@ -855,6 +847,29 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl); + ngtcp2_connection_close_error_default(&qs->last_error); + +#if defined(__linux__) && defined(UDP_SEGMENT) && defined(HAVE_SENDMSG) + qs->no_gso = FALSE; +#else + qs->no_gso = TRUE; +#endif + + qs->num_blocked_pkt = 0; + qs->num_blocked_pkt_sent = 0; + memset(&qs->blocked_pkt, 0, sizeof(qs->blocked_pkt)); + + qs->pktbuflen = NGTCP2_MAX_PMTUD_UDP_PAYLOAD_SIZE * MAX_PKT_BURST; + qs->pktbuf = malloc(qs->pktbuflen); + if(!qs->pktbuf) { + ngtcp2_conn_del(qs->qconn); + qs->qconn = NULL; + return CURLE_OUT_OF_MEMORY; + } + + qs->conn_ref.get_conn = get_conn; + qs->conn_ref.user_data = qs; + return CURLE_OK; } @@ -899,18 +914,14 @@ static void qs_disconnect(struct quicsocket *qs) char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE]; ngtcp2_tstamp ts; ngtcp2_ssize rc; - ngtcp2_connection_close_error errorcode; if(!qs->conn) /* already closed */ return; - ngtcp2_connection_close_error_set_application_error(&errorcode, - NGHTTP3_H3_NO_ERROR, - NULL, 0); ts = timestamp(); rc = ngtcp2_conn_write_connection_close(qs->qconn, NULL, /* path */ NULL, /* pkt_info */ (uint8_t *)buffer, sizeof(buffer), - &errorcode, ts); + &qs->last_error, ts); if(rc > 0) { while((send(qs->conn->sock[FIRSTSOCKET], buffer, rc, 0) == -1) && SOCKERRNO == EINTR); @@ -926,6 +937,8 @@ static void qs_disconnect(struct quicsocket *qs) SSL_free(qs->ssl); #elif defined(USE_GNUTLS) gnutls_deinit(qs->ssl); +#elif defined(USE_WOLFSSL) + wolfSSL_free(qs->ssl); #endif qs->ssl = NULL; #ifdef USE_GNUTLS @@ -934,10 +947,13 @@ static void qs_disconnect(struct quicsocket *qs) qs->cred = NULL; } #endif + free(qs->pktbuf); nghttp3_conn_del(qs->h3conn); ngtcp2_conn_del(qs->qconn); #ifdef USE_OPENSSL SSL_CTX_free(qs->sslctx); +#elif defined(USE_WOLFSSL) + wolfSSL_CTX_free(qs->sslctx); #endif } @@ -1006,6 +1022,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, H3BUGF(infof(data, "cb_h3_stream_close CALLED")); stream->closed = TRUE; + stream->error3 = app_error_code; Curl_expire(data, 0, EXPIRE_QUIC); /* make sure that ngh3_stream_recv is called again to complete the transfer even if there are no more packets to be received from the server. */ @@ -1117,6 +1134,10 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id, return -1; } } + + if(stream->status_code / 100 != 1) { + stream->bodystarted = TRUE; + } return 0; } @@ -1139,9 +1160,10 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, if(token == NGHTTP3_QPACK_TOKEN__STATUS) { char line[14]; /* status line is always 13 characters long */ size_t ncopy; - int status = decode_status_code(h3val.base, h3val.len); - DEBUGASSERT(status != -1); - ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status); + stream->status_code = decode_status_code(h3val.base, h3val.len); + DEBUGASSERT(stream->status_code != -1); + ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", + stream->status_code); result = write_data(stream, line, ncopy); if(result) { return -1; @@ -1171,16 +1193,36 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id, return 0; } -static int cb_h3_send_stop_sending(nghttp3_conn *conn, int64_t stream_id, - uint64_t app_error_code, - void *user_data, - void *stream_user_data) +static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + struct quicsocket *qs = user_data; + int rv; + (void)conn; + (void)stream_user_data; + + rv = ngtcp2_conn_shutdown_stream_read(qs->qconn, stream_id, app_error_code); + if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id, + uint64_t app_error_code, void *user_data, + void *stream_user_data) { + struct quicsocket *qs = user_data; + int rv; (void)conn; - (void)stream_id; - (void)app_error_code; - (void)user_data; (void)stream_user_data; + + rv = ngtcp2_conn_shutdown_stream_write(qs->qconn, stream_id, app_error_code); + if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) { + return NGTCP2_ERR_CALLBACK_FAILURE; + } + return 0; } @@ -1195,9 +1237,9 @@ static nghttp3_callbacks ngh3_callbacks = { NULL, /* begin_trailers */ cb_h3_recv_header, NULL, /* end_trailers */ - cb_h3_send_stop_sending, + cb_h3_stop_sending, NULL, /* end_stream */ - NULL, /* reset_stream */ + cb_h3_reset_stream, NULL /* shutdown */ }; @@ -1333,6 +1375,24 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data, } if(stream->closed) { + if(stream->error3 != NGHTTP3_H3_NO_ERROR) { + failf(data, + "HTTP/3 stream %" PRId64 " was not closed cleanly: (err %" PRIu64 + ")", + stream->stream3_id, stream->error3); + *curlcode = CURLE_HTTP3; + return -1; + } + + if(!stream->bodystarted) { + failf(data, + "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting" + " all response header fields, treated as error", + stream->stream3_id); + *curlcode = CURLE_HTTP3; + return -1; + } + *curlcode = CURLE_OK; return 0; } @@ -1344,7 +1404,7 @@ static ssize_t ngh3_stream_recv(struct Curl_easy *data, /* this amount of data has now been acked on this stream */ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, - size_t datalen, void *user_data, + uint64_t datalen, void *user_data, void *stream_user_data) { struct Curl_easy *data = stream_user_data; @@ -1368,10 +1428,10 @@ static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id, return 0; } -static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id, - nghttp3_vec *vec, size_t veccnt, - uint32_t *pflags, void *user_data, - void *stream_user_data) +static nghttp3_ssize cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id, + nghttp3_vec *vec, size_t veccnt, + uint32_t *pflags, void *user_data, + void *stream_user_data) { struct Curl_easy *data = stream_user_data; size_t nread; @@ -1482,6 +1542,7 @@ static CURLcode http_request(struct Curl_easy *data, const void *mem, nva[i].namelen = hreq->header[i].namelen; nva[i].value = (unsigned char *)hreq->header[i].value; nva[i].valuelen = hreq->header[i].valuelen; + nva[i].flags = NGHTTP3_NV_FLAG_NONE; } } @@ -1550,6 +1611,11 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data, curl_socket_t sockfd = conn->sock[sockindex]; struct HTTP *stream = data->req.p.http; + if(stream->closed) { + *curlcode = CURLE_HTTP3; + return -1; + } + if(!stream->h3req) { CURLcode result = http_request(data, mem, len); if(result) { @@ -1626,12 +1692,23 @@ static CURLcode ng_has_connected(struct Curl_easy *data, if(result) return result; infof(data, "Verified certificate just fine"); -#else +#elif defined(USE_GNUTLS) result = Curl_gtls_verifyserver(data, conn, conn->quic->ssl, FIRSTSOCKET); +#elif defined(USE_WOLFSSL) + char *snihost = Curl_ssl_snihost(data, SSL_HOST_NAME(), NULL); + if(!snihost || + (wolfSSL_check_domain_name(conn->quic->ssl, snihost) == SSL_FAILURE)) + return CURLE_PEER_FAILED_VERIFICATION; + infof(data, "Verified certificate just fine"); #endif } else infof(data, "Skipped certificate verification"); +#ifdef USE_OPENSSL + if(data->set.ssl.certinfo) + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, conn->quic->ssl); +#endif return result; } @@ -1704,7 +1781,17 @@ static CURLcode ng_process_ingress(struct Curl_easy *data, rv = ngtcp2_conn_read_pkt(qs->qconn, &path, &pi, buf, recvd, ts); if(rv) { - /* TODO Send CONNECTION_CLOSE if possible */ + if(!qs->last_error.error_code) { + if(rv == NGTCP2_ERR_CRYPTO) { + ngtcp2_connection_close_error_set_transport_error_tls_alert( + &qs->last_error, ngtcp2_conn_get_tls_alert(qs->qconn), NULL, 0); + } + else { + ngtcp2_connection_close_error_set_transport_error_liberr( + &qs->last_error, rv, NULL, 0); + } + } + if(rv == NGTCP2_ERR_CRYPTO) /* this is a "TLS problem", but a failed certificate verification is a common reason for this */ @@ -1716,32 +1803,231 @@ static CURLcode ng_process_ingress(struct Curl_easy *data, return CURLE_OK; } +static CURLcode do_sendmsg(size_t *sent, struct Curl_easy *data, int sockfd, + struct quicsocket *qs, const uint8_t *pkt, + size_t pktlen, size_t gsolen); + +static CURLcode send_packet_no_gso(size_t *psent, struct Curl_easy *data, + int sockfd, struct quicsocket *qs, + const uint8_t *pkt, size_t pktlen, + size_t gsolen) +{ + const uint8_t *p, *end = pkt + pktlen; + size_t sent; + + *psent = 0; + + for(p = pkt; p < end; p += gsolen) { + size_t len = CURLMIN(gsolen, (size_t)(end - p)); + CURLcode curlcode = do_sendmsg(&sent, data, sockfd, qs, p, len, len); + if(curlcode != CURLE_OK) { + return curlcode; + } + *psent += sent; + } + + return CURLE_OK; +} + +static CURLcode do_sendmsg(size_t *psent, struct Curl_easy *data, int sockfd, + struct quicsocket *qs, const uint8_t *pkt, + size_t pktlen, size_t gsolen) +{ +#ifdef HAVE_SENDMSG + struct iovec msg_iov; + struct msghdr msg = {0}; + ssize_t sent; +#if defined(__linux__) && defined(UDP_SEGMENT) + uint8_t msg_ctrl[32]; + struct cmsghdr *cm; +#endif + + *psent = 0; + msg_iov.iov_base = (uint8_t *)pkt; + msg_iov.iov_len = pktlen; + msg.msg_iov = &msg_iov; + msg.msg_iovlen = 1; + +#if defined(__linux__) && defined(UDP_SEGMENT) + if(pktlen > gsolen) { + /* Only set this, when we need it. macOS, for example, + * does not seem to like a msg_control of length 0. */ + msg.msg_control = msg_ctrl; + assert(sizeof(msg_ctrl) >= CMSG_SPACE(sizeof(uint16_t))); + msg.msg_controllen = CMSG_SPACE(sizeof(uint16_t)); + cm = CMSG_FIRSTHDR(&msg); + cm->cmsg_level = SOL_UDP; + cm->cmsg_type = UDP_SEGMENT; + cm->cmsg_len = CMSG_LEN(sizeof(uint16_t)); + *(uint16_t *)(void *)CMSG_DATA(cm) = gsolen & 0xffff; + } +#endif + + + while((sent = sendmsg(sockfd, &msg, 0)) == -1 && SOCKERRNO == EINTR) + ; + + if(sent == -1) { + switch(SOCKERRNO) { + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + return CURLE_AGAIN; + case EMSGSIZE: + /* UDP datagram is too large; caused by PMTUD. Just let it be lost. */ + break; + case EIO: + if(pktlen > gsolen) { + /* GSO failure */ + failf(data, "sendmsg() returned %zd (errno %d); disable GSO", sent, + SOCKERRNO); + qs->no_gso = TRUE; + return send_packet_no_gso(psent, data, sockfd, qs, pkt, pktlen, + gsolen); + } + /* FALLTHROUGH */ + default: + failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO); + return CURLE_SEND_ERROR; + } + } + else { + assert(pktlen == (size_t)sent); + } +#else + ssize_t sent; + (void)qs; + (void)gsolen; + + *psent = 0; + + while((sent = send(sockfd, (const char *)pkt, pktlen, 0)) == -1 && + SOCKERRNO == EINTR) + ; + + if(sent == -1) { + if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { + return CURLE_AGAIN; + } + else { + failf(data, "send() returned %zd (errno %d)", sent, SOCKERRNO); + if(SOCKERRNO != EMSGSIZE) { + return CURLE_SEND_ERROR; + } + /* UDP datagram is too large; caused by PMTUD. Just let it be + lost. */ + } + } +#endif + + *psent = pktlen; + + return CURLE_OK; +} + +static CURLcode send_packet(size_t *psent, struct Curl_easy *data, int sockfd, + struct quicsocket *qs, const uint8_t *pkt, + size_t pktlen, size_t gsolen) +{ + if(qs->no_gso && pktlen > gsolen) { + return send_packet_no_gso(psent, data, sockfd, qs, pkt, pktlen, gsolen); + } + + return do_sendmsg(psent, data, sockfd, qs, pkt, pktlen, gsolen); +} + +static void push_blocked_pkt(struct quicsocket *qs, const uint8_t *pkt, + size_t pktlen, size_t gsolen) +{ + struct blocked_pkt *blkpkt; + + assert(qs->num_blocked_pkt < + sizeof(qs->blocked_pkt) / sizeof(qs->blocked_pkt[0])); + + blkpkt = &qs->blocked_pkt[qs->num_blocked_pkt++]; + + blkpkt->pkt = pkt; + blkpkt->pktlen = pktlen; + blkpkt->gsolen = gsolen; +} + +static CURLcode send_blocked_pkt(struct Curl_easy *data, int sockfd, + struct quicsocket *qs) +{ + size_t sent; + CURLcode curlcode; + struct blocked_pkt *blkpkt; + + for(; qs->num_blocked_pkt_sent < qs->num_blocked_pkt; + ++qs->num_blocked_pkt_sent) { + blkpkt = &qs->blocked_pkt[qs->num_blocked_pkt_sent]; + curlcode = send_packet(&sent, data, sockfd, qs, blkpkt->pkt, + blkpkt->pktlen, blkpkt->gsolen); + + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + blkpkt->pkt += sent; + blkpkt->pktlen -= sent; + } + return curlcode; + } + } + + qs->num_blocked_pkt = 0; + qs->num_blocked_pkt_sent = 0; + + return CURLE_OK; +} + static CURLcode ng_flush_egress(struct Curl_easy *data, int sockfd, struct quicsocket *qs) { int rv; - ssize_t sent; - ssize_t outlen; - uint8_t out[NGTCP2_MAX_UDP_PAYLOAD_SIZE]; + size_t sent; + ngtcp2_ssize outlen; + uint8_t *outpos = qs->pktbuf; + size_t max_udp_payload_size = + ngtcp2_conn_get_max_tx_udp_payload_size(qs->qconn); + size_t path_max_udp_payload_size = + ngtcp2_conn_get_path_max_tx_udp_payload_size(qs->qconn); + size_t max_pktcnt = + CURLMIN(MAX_PKT_BURST, qs->pktbuflen / max_udp_payload_size); + size_t pktcnt = 0; + size_t gsolen; ngtcp2_path_storage ps; ngtcp2_tstamp ts = timestamp(); ngtcp2_tstamp expiry; ngtcp2_duration timeout; int64_t stream_id; - ssize_t veccnt; + nghttp3_ssize veccnt; int fin; nghttp3_vec vec[16]; - ssize_t ndatalen; + ngtcp2_ssize ndatalen; uint32_t flags; + CURLcode curlcode; rv = ngtcp2_conn_handle_expiry(qs->qconn, ts); if(rv) { failf(data, "ngtcp2_conn_handle_expiry returned error: %s", ngtcp2_strerror(rv)); + ngtcp2_connection_close_error_set_transport_error_liberr(&qs->last_error, + rv, NULL, 0); return CURLE_SEND_ERROR; } + if(qs->num_blocked_pkt) { + curlcode = send_blocked_pkt(data, sockfd, qs); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + } + ngtcp2_path_storage_zero(&ps); for(;;) { @@ -1755,39 +2041,45 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, if(veccnt < 0) { failf(data, "nghttp3_conn_writev_stream returned error: %s", nghttp3_strerror((int)veccnt)); + ngtcp2_connection_close_error_set_application_error( + &qs->last_error, + nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0); return CURLE_SEND_ERROR; } } flags = NGTCP2_WRITE_STREAM_FLAG_MORE | (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0); - outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, out, - sizeof(out), + outlen = ngtcp2_conn_writev_stream(qs->qconn, &ps.path, NULL, outpos, + max_udp_payload_size, &ndatalen, flags, stream_id, (const ngtcp2_vec *)vec, veccnt, ts); if(outlen == 0) { + if(outpos != qs->pktbuf) { + curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf, + outpos - qs->pktbuf, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + push_blocked_pkt(qs, qs->pktbuf + sent, outpos - qs->pktbuf - sent, + gsolen); + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + } + break; } if(outlen < 0) { switch(outlen) { case NGTCP2_ERR_STREAM_DATA_BLOCKED: assert(ndatalen == -1); - rv = nghttp3_conn_block_stream(qs->h3conn, stream_id); - if(rv) { - failf(data, "nghttp3_conn_block_stream returned error: %s\n", - nghttp3_strerror(rv)); - return CURLE_SEND_ERROR; - } + nghttp3_conn_block_stream(qs->h3conn, stream_id); continue; 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; - } + nghttp3_conn_shutdown_stream_write(qs->h3conn, stream_id); continue; case NGTCP2_ERR_WRITE_MORE: assert(ndatalen >= 0); @@ -1802,6 +2094,8 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, assert(ndatalen == -1); failf(data, "ngtcp2_conn_writev_stream returned error: %s", ngtcp2_strerror((int)outlen)); + ngtcp2_connection_close_error_set_transport_error_liberr( + &qs->last_error, (int)outlen, NULL, 0); return CURLE_SEND_ERROR; } } @@ -1814,20 +2108,61 @@ static CURLcode ng_flush_egress(struct Curl_easy *data, } } - while((sent = send(sockfd, (const char *)out, outlen, 0)) == -1 && - SOCKERRNO == EINTR) - ; + outpos += outlen; - if(sent == -1) { - if(SOCKERRNO == EAGAIN || SOCKERRNO == EWOULDBLOCK) { - /* TODO Cache packet */ - break; + if(pktcnt == 0) { + gsolen = outlen; + } + else if((size_t)outlen > gsolen || + (gsolen > path_max_udp_payload_size && + (size_t)outlen != gsolen)) { + /* Packet larger than path_max_udp_payload_size is PMTUD probe + packet and it might not be sent because of EMSGSIZE. Send + them separately to minimize the loss. */ + curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf, + outpos - outlen - qs->pktbuf, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + push_blocked_pkt(qs, qs->pktbuf + sent, + outpos - outlen - qs->pktbuf - sent, gsolen); + push_blocked_pkt(qs, outpos - outlen, outlen, outlen); + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; } - else { - failf(data, "send() returned %zd (errno %d)", sent, - SOCKERRNO); - return CURLE_SEND_ERROR; + curlcode = send_packet(&sent, data, sockfd, qs, outpos - outlen, outlen, + outlen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + assert(0 == sent); + push_blocked_pkt(qs, outpos - outlen, outlen, outlen); + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; + } + + pktcnt = 0; + outpos = qs->pktbuf; + continue; + } + + if(++pktcnt >= max_pktcnt || (size_t)outlen < gsolen) { + curlcode = send_packet(&sent, data, sockfd, qs, qs->pktbuf, + outpos - qs->pktbuf, gsolen); + if(curlcode) { + if(curlcode == CURLE_AGAIN) { + push_blocked_pkt(qs, qs->pktbuf + sent, outpos - qs->pktbuf - sent, + gsolen); + Curl_expire(data, 1, EXPIRE_QUIC); + return CURLE_OK; + } + return curlcode; } + + pktcnt = 0; + outpos = qs->pktbuf; } } @@ -1894,4 +2229,26 @@ bool Curl_quic_data_pending(const struct Curl_easy *data) return Curl_dyn_len(&stream->overflow) > 0; } +/* + * Called from transfer.c:Curl_readwrite when neither HTTP level read + * nor write is performed. It is a good place to handle timer expiry + * for QUIC transport. + */ +CURLcode Curl_quic_idle(struct Curl_easy *data) +{ + struct connectdata *conn = data->conn; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + struct quicsocket *qs = conn->quic; + + if(ngtcp2_conn_get_expiry(qs->qconn) > timestamp()) { + return CURLE_OK; + } + + if(ng_flush_egress(data, sockfd, qs)) { + return CURLE_SEND_ERROR; + } + + return CURLE_OK; +} + #endif diff --git a/Utilities/cmcurl/lib/vquic/ngtcp2.h b/Utilities/cmcurl/lib/vquic/ngtcp2.h index 5014530..6539f5f 100644 --- a/Utilities/cmcurl/lib/vquic/ngtcp2.h +++ b/Utilities/cmcurl/lib/vquic/ngtcp2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,20 +20,36 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_NGTCP2 -#include <ngtcp2/ngtcp2.h> +#ifdef HAVE_NETINET_UDP_H +#include <netinet/udp.h> +#endif + +#include <ngtcp2/ngtcp2_crypto.h> #include <nghttp3/nghttp3.h> #ifdef USE_OPENSSL #include <openssl/ssl.h> #elif defined(USE_GNUTLS) #include <gnutls/gnutls.h> +#elif defined(USE_WOLFSSL) +#include <wolfssl/options.h> +#include <wolfssl/ssl.h> +#include <wolfssl/quic.h> #endif +struct blocked_pkt { + const uint8_t *pkt; + size_t pktlen; + size_t gsolen; +}; + struct quicsocket { struct connectdata *conn; /* point back to the connection */ ngtcp2_conn *qconn; @@ -42,17 +58,29 @@ struct quicsocket { uint32_t version; ngtcp2_settings settings; ngtcp2_transport_params transport_params; + ngtcp2_connection_close_error last_error; + ngtcp2_crypto_conn_ref conn_ref; #ifdef USE_OPENSSL SSL_CTX *sslctx; SSL *ssl; #elif defined(USE_GNUTLS) gnutls_certificate_credentials_t cred; gnutls_session_t ssl; +#elif defined(USE_WOLFSSL) + WOLFSSL_CTX *sslctx; + WOLFSSL *ssl; #endif - /* the last TLS alert description generated by the local endpoint */ - uint8_t tls_alert; struct sockaddr_storage local_addr; socklen_t local_addrlen; + bool no_gso; + uint8_t *pktbuf; + size_t pktbuflen; + /* the number of entries in blocked_pkt */ + size_t num_blocked_pkt; + /* the number of processed entries in blocked_pkt */ + size_t num_blocked_pkt_sent; + /* the packets blocked by sendmsg (EAGAIN or EWOULDBLOCK) */ + struct blocked_pkt blocked_pkt[2]; nghttp3_conn *h3conn; nghttp3_settings h3settings; diff --git a/Utilities/cmcurl/lib/vquic/quiche.c b/Utilities/cmcurl/lib/vquic/quiche.c index bfdc966..a52a7e8 100644 --- a/Utilities/cmcurl/lib/vquic/quiche.c +++ b/Utilities/cmcurl/lib/vquic/quiche.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -201,23 +203,31 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data) { struct connectdata *conn = data->conn; - const char * const ssl_cafile = conn->ssl_config.CAfile; - const char * const ssl_capath = conn->ssl_config.CApath; - if(conn->ssl_config.verifypeer) { - SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); - /* tell OpenSSL where to find CA certificates that are used to verify - the server's certificate. */ - if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) { - /* Fail if we insist on successfully verifying the server. */ - failf(data, "error setting certificate verify locations:" - " CAfile: %s CApath: %s", - ssl_cafile ? ssl_cafile : "none", - ssl_capath ? ssl_capath : "none"); - return NULL; + const char * const ssl_cafile = conn->ssl_config.CAfile; + const char * const ssl_capath = conn->ssl_config.CApath; + if(ssl_cafile || ssl_capath) { + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL); + /* tell OpenSSL where to find CA certificates that are used to verify + the server's certificate. */ + if(!SSL_CTX_load_verify_locations(ssl_ctx, ssl_cafile, ssl_capath)) { + /* Fail if we insist on successfully verifying the server. */ + failf(data, "error setting certificate verify locations:" + " CAfile: %s CApath: %s", + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); + return NULL; + } + infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); + infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); + } +#ifdef CURL_CA_FALLBACK + else { + /* verifying the peer without any CA certificates won't work so + use openssl's built-in default as fallback */ + SSL_CTX_set_default_verify_paths(ssl_ctx); } - infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none"); - infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none"); +#endif } } return ssl_ctx; @@ -248,6 +258,7 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, struct quicsocket *qs = &conn->hequic[sockindex]; char ipbuf[40]; int port; + int rv; #ifdef DEBUG_QUICHE /* initialize debug log callback only once */ @@ -293,8 +304,16 @@ CURLcode Curl_quic_connect(struct Curl_easy *data, if(result) return result; + qs->local_addrlen = sizeof(qs->local_addr); + rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr, + &qs->local_addrlen); + if(rv == -1) + return CURLE_QUIC_CONNECT_ERROR; + qs->conn = quiche_conn_new_with_tls((const uint8_t *) qs->scid, - sizeof(qs->scid), NULL, 0, addr, addrlen, + sizeof(qs->scid), NULL, 0, + (struct sockaddr *)&qs->local_addr, + qs->local_addrlen, addr, addrlen, qs->cfg, qs->ssl, false); if(!qs->conn) { failf(data, "can't create quiche connection"); @@ -397,6 +416,10 @@ static CURLcode quiche_has_connected(struct Curl_easy *data, qs->cfg = NULL; qs->conn = NULL; } + if(data->set.ssl.certinfo) + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, qs->ssl); + return CURLE_OK; fail: quiche_h3_config_free(qs->h3config); @@ -468,6 +491,8 @@ static CURLcode process_ingress(struct Curl_easy *data, int sockfd, recv_info.from = (struct sockaddr *) &from; recv_info.from_len = from_len; + recv_info.to = (struct sockaddr *) &qs->local_addr; + recv_info.to_len = qs->local_addrlen; recvd = quiche_conn_recv(qs->conn, buf, recvd, &recv_info); if(recvd == QUICHE_ERR_DONE) @@ -856,4 +881,15 @@ bool Curl_quic_data_pending(const struct Curl_easy *data) return FALSE; } +/* + * Called from transfer.c:Curl_readwrite when neither HTTP level read + * nor write is performed. It is a good place to handle timer expiry + * for QUIC transport. + */ +CURLcode Curl_quic_idle(struct Curl_easy *data) +{ + (void)data; + return CURLE_OK; +} + #endif diff --git a/Utilities/cmcurl/lib/vquic/quiche.h b/Utilities/cmcurl/lib/vquic/quiche.h index 759a20b..2da65f5 100644 --- a/Utilities/cmcurl/lib/vquic/quiche.h +++ b/Utilities/cmcurl/lib/vquic/quiche.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -47,6 +49,8 @@ struct quicsocket { SSL_CTX *sslctx; SSL *ssl; bool h3_recving; /* TRUE when in h3-body-reading state */ + struct sockaddr_storage local_addr; + socklen_t local_addrlen; }; #endif diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c index be2a65f..e52a4f3 100644 --- a/Utilities/cmcurl/lib/vquic/vquic.c +++ b/Utilities/cmcurl/lib/vquic/vquic.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vquic/vquic.h b/Utilities/cmcurl/lib/vquic/vquic.h index 3df138f..8f599a8 100644 --- a/Utilities/cmcurl/lib/vquic/vquic.h +++ b/Utilities/cmcurl/lib/vquic/vquic.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c index 7bf2b04..0105e40 100644 --- a/Utilities/cmcurl/lib/vssh/libssh.c +++ b/Utilities/cmcurl/lib/vssh/libssh.c @@ -21,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -94,6 +96,13 @@ #include "curl_memory.h" #include "memdebug.h" +/* in 0.10.0 or later, ignore deprecated warnings */ +#if defined(__GNUC__) && \ + (LIBSSH_VERSION_MINOR >= 10) || \ + (LIBSSH_VERSION_MAJOR > 0) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + /* A recent macro provided by libssh. Or make our own. */ #ifndef SSH_STRING_FREE_CHAR #define SSH_STRING_FREE_CHAR(x) \ @@ -954,10 +963,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) rc = sftp_init(sshc->sftp_session); if(rc != SSH_OK) { - rc = sftp_get_error(sshc->sftp_session); failf(data, "Failure initializing sftp session: %s", ssh_get_error(sshc->ssh_session)); - MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(rc)); + MOVE_TO_ERROR_STATE(sftp_error_to_CURLE(SSH_FX_FAILURE)); break; } state(data, SSH_SFTP_REALPATH); @@ -1658,7 +1666,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) if(from_t == CURL_OFFT_FLOW) { return CURLE_RANGE_ERROR; } - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) { @@ -1970,10 +1978,13 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) } ssh_disconnect(sshc->ssh_session); - /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back, - explicitly mark it as closed with the memdebug macro: */ - fake_sclose(conn->sock[FIRSTSOCKET]); - conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; + if(!ssh_version(SSH_VERSION_INT(0, 10, 0))) { + /* conn->sock[FIRSTSOCKET] is closed by ssh_disconnect behind our back, + explicitly mark it as closed with the memdebug macro. This libssh + bug is fixed in 0.10.0. */ + fake_sclose(conn->sock[FIRSTSOCKET]); + conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; + } SSH_STRING_FREE_CHAR(sshc->homedir); data->state.most_recent_ftp_entrypath = NULL; @@ -2906,32 +2917,33 @@ static void sftp_quote_stat(struct Curl_easy *data) } sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_UIDGID; } - else if(strncasecompare(cmd, "atime", 5)) { + else if(strncasecompare(cmd, "atime", 5) || + strncasecompare(cmd, "mtime", 5)) { time_t date = Curl_getdate_capped(sshc->quote_path1); + bool fail = FALSE; if(date == -1) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: incorrect access date format"); - state(data, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - return; + failf(data, "incorrect date format for %.*s", 5, cmd); + fail = TRUE; } - sshc->quote_attrs->atime = (uint32_t)date; - sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME; - } - else if(strncasecompare(cmd, "mtime", 5)) { - time_t date = Curl_getdate_capped(sshc->quote_path1); - if(date == -1) { +#if SIZEOF_TIME_T > 4 + else if(date > 0xffffffff) { + failf(data, "date overflow"); + fail = TRUE; /* avoid setting a capped time */ + } +#endif + if(fail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: incorrect modification date format"); state(data, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; return; } - sshc->quote_attrs->mtime = (uint32_t)date; + if(strncasecompare(cmd, "atime", 5)) + sshc->quote_attrs->atime = (uint32_t)date; + else /* mtime */ + sshc->quote_attrs->mtime = (uint32_t)date; + sshc->quote_attrs->flags |= SSH_FILEXFER_ATTR_ACMODTIME; } @@ -2956,7 +2968,7 @@ void Curl_ssh_cleanup(void) void Curl_ssh_version(char *buffer, size_t buflen) { - (void)msnprintf(buffer, buflen, "libssh/%s", CURL_LIBSSH_VERSION); + (void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0)); } #endif /* USE_LIBSSH */ diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c index d269263..5a2c0f8 100644 --- a/Utilities/cmcurl/lib/vssh/libssh2.c +++ b/Utilities/cmcurl/lib/vssh/libssh2.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* #define CURL_LIBSSH2_DEBUG */ @@ -437,9 +439,45 @@ static int sshkeycallback(struct Curl_easy *easy, #else #define session_startup(x,y) libssh2_session_startup(x, (int)y) #endif +static int convert_ssh2_keytype(int sshkeytype) +{ + int keytype = CURLKHTYPE_UNKNOWN; + switch(sshkeytype) { + case LIBSSH2_HOSTKEY_TYPE_RSA: + keytype = CURLKHTYPE_RSA; + break; + case LIBSSH2_HOSTKEY_TYPE_DSS: + keytype = CURLKHTYPE_DSS; + break; +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_256: + keytype = CURLKHTYPE_ECDSA; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_384: + keytype = CURLKHTYPE_ECDSA; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521 + case LIBSSH2_HOSTKEY_TYPE_ECDSA_521: + keytype = CURLKHTYPE_ECDSA; + break; +#endif +#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519 + case LIBSSH2_HOSTKEY_TYPE_ED25519: + keytype = CURLKHTYPE_ED25519; + break; +#endif + } + return keytype; +} static CURLcode ssh_knownhost(struct Curl_easy *data) { + int sshkeytype = 0; + size_t keylen = 0; + int rc = 0; CURLcode result = CURLE_OK; #ifdef HAVE_LIBSSH2_KNOWNHOST_API @@ -448,11 +486,8 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) struct connectdata *conn = data->conn; struct ssh_conn *sshc = &conn->proto.sshc; struct libssh2_knownhost *host = NULL; - int rc; - int keytype; - size_t keylen; const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, - &keylen, &keytype); + &keylen, &sshkeytype); int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE; int keybit = 0; @@ -464,12 +499,12 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) */ enum curl_khmatch keymatch; curl_sshkeycallback func = - data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback; + data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback; struct curl_khkey knownkey; struct curl_khkey *knownkeyp = NULL; struct curl_khkey foundkey; - switch(keytype) { + switch(sshkeytype) { case LIBSSH2_HOSTKEY_TYPE_RSA: keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA; break; @@ -533,16 +568,14 @@ static CURLcode ssh_knownhost(struct Curl_easy *data) if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) { knownkey.key = host->key; knownkey.len = 0; - knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - CURLKHTYPE_RSA : CURLKHTYPE_DSS; + knownkey.keytype = convert_ssh2_keytype(sshkeytype); knownkeyp = &knownkey; } /* setup 'foundkey' */ foundkey.key = remotekey; foundkey.len = keylen; - foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)? - CURLKHTYPE_RSA : CURLKHTYPE_DSS; + foundkey.keytype = convert_ssh2_keytype(sshkeytype); /* * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the @@ -639,7 +672,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) #ifdef LIBSSH2_HOSTKEY_HASH_SHA256 /* The fingerprint points to static storage (!), don't free() it. */ fingerprint = libssh2_hostkey_hash(sshc->ssh_session, - LIBSSH2_HOSTKEY_HASH_SHA256); + LIBSSH2_HOSTKEY_HASH_SHA256); #else const char *hostkey; size_t len = 0; @@ -654,8 +687,8 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) if(!fingerprint) { failf(data, - "Denied establishing ssh session: sha256 fingerprint " - "not available"); + "Denied establishing ssh session: sha256 fingerprint " + "not available"); state(data, SSH_SESSION_FREE); sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION; return sshc->actualcode; @@ -715,7 +748,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) const char *fingerprint = NULL; fingerprint = libssh2_hostkey_hash(sshc->ssh_session, - LIBSSH2_HOSTKEY_HASH_MD5); + LIBSSH2_HOSTKEY_HASH_MD5); if(fingerprint) { /* The fingerprint points to static storage (!), don't free() it. */ @@ -748,7 +781,31 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data) } if(!pubkey_md5 && !pubkey_sha256) { - return ssh_knownhost(data); + if(data->set.ssh_hostkeyfunc) { + size_t keylen = 0; + int sshkeytype = 0; + int rc = 0; + /* we handle the process to the callback*/ + const char *remotekey = libssh2_session_hostkey(sshc->ssh_session, + &keylen, &sshkeytype); + if(remotekey) { + int keytype = convert_ssh2_keytype(sshkeytype); + Curl_set_in_callback(data, true); + rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp, + keytype, remotekey, keylen); + Curl_set_in_callback(data, false); + if(rc!= CURLKHMATCH_OK) { + state(data, SSH_SESSION_FREE); + } + } + else { + state(data, SSH_SESSION_FREE); + } + return CURLE_OK; + } + else { + return ssh_knownhost(data); + } } else { /* as we already matched, we skip the check for known hosts */ @@ -1698,32 +1755,35 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) break; } } - else if(strncasecompare(cmd, "atime", 5)) { + else if(strncasecompare(cmd, "atime", 5) || + strncasecompare(cmd, "mtime", 5)) { time_t date = Curl_getdate_capped(sshc->quote_path1); + bool fail = FALSE; + if(date == -1) { - Curl_safefree(sshc->quote_path1); - Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: incorrect access date format"); - state(data, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - sshc->actualcode = CURLE_QUOTE_ERROR; - break; + failf(data, "incorrect date format for %.*s", 5, cmd); + fail = TRUE; } - sshp->quote_attrs.atime = (unsigned long)date; - sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; - } - else if(strncasecompare(cmd, "mtime", 5)) { - time_t date = Curl_getdate_capped(sshc->quote_path1); - if(date == -1) { +#if SIZEOF_TIME_T > SIZEOF_LONG + if(date > 0xffffffff) { + /* if 'long' can't old >32bit, this date cannot be sent */ + failf(data, "date overflow"); + fail = TRUE; + } +#endif + if(fail) { Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - failf(data, "Syntax error: incorrect modification date format"); state(data, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; sshc->actualcode = CURLE_QUOTE_ERROR; break; } - sshp->quote_attrs.mtime = (unsigned long)date; + if(strncasecompare(cmd, "atime", 5)) + sshp->quote_attrs.atime = (unsigned long)date; + else /* mtime */ + sshp->quote_attrs.mtime = (unsigned long)date; + sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; } @@ -2278,7 +2338,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)) { Curl_dyn_init(&sshp->readdir_link, PATH_MAX); - result = Curl_dyn_add(&sshp->readdir_link, sshp->path); + result = Curl_dyn_addf(&sshp->readdir_link, "%s%s", sshp->path, + sshp->readdir_filename); state(data, SSH_SFTP_READDIR_LINK); if(!result) break; @@ -2445,7 +2506,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) from_t = curlx_strtoofft(data->state.range, &ptr, 0, &from); if(from_t == CURL_OFFT_FLOW) return CURLE_RANGE_ERROR; - while(*ptr && (ISSPACE(*ptr) || (*ptr == '-'))) + while(*ptr && (ISBLANK(*ptr) || (*ptr == '-'))) ptr++; to_t = curlx_strtoofft(ptr, &ptr2, 0, &to); if(to_t == CURL_OFFT_FLOW) diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h index 30d82e5..13bb8aa 100644 --- a/Utilities/cmcurl/lib/vssh/ssh.h +++ b/Utilities/cmcurl/lib/vssh/ssh.h @@ -20,14 +20,16 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" -#if defined(HAVE_LIBSSH2_H) +#if defined(USE_LIBSSH2) #include <libssh2.h> #include <libssh2_sftp.h> -#elif defined(HAVE_LIBSSH_LIBSSH_H) +#elif defined(USE_LIBSSH) #include <libssh/libssh.h> #include <libssh/sftp.h> #elif defined(USE_WOLFSSH) @@ -209,11 +211,7 @@ struct ssh_conn { #endif /* USE_LIBSSH */ }; -#if defined(USE_LIBSSH) - -#define CURL_LIBSSH_VERSION ssh_version(0) - -#elif defined(USE_LIBSSH2) +#if defined(USE_LIBSSH2) /* Feature detection based on version numbers to better work with non-configure platforms */ diff --git a/Utilities/cmcurl/lib/vssh/wolfssh.c b/Utilities/cmcurl/lib/vssh/wolfssh.c index 85f2941..c2f85f3 100644 --- a/Utilities/cmcurl/lib/vssh/wolfssh.c +++ b/Utilities/cmcurl/lib/vssh/wolfssh.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/bearssl.c b/Utilities/cmcurl/lib/vtls/bearssl.c index 91f4416..1221ce8 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.c +++ b/Utilities/cmcurl/lib/vtls/bearssl.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -74,9 +76,9 @@ struct cafile_parser { #define CAFILE_SOURCE_PATH 1 #define CAFILE_SOURCE_BLOB 2 struct cafile_source { - const int type; - const char * const data; - const size_t len; + int type; + const char *data; + size_t len; }; static void append_dn(void *ctx, const void *buf, size_t len) @@ -616,11 +618,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, } if(ca_info_blob) { - struct cafile_source source = { - CAFILE_SOURCE_BLOB, - ca_info_blob->data, - ca_info_blob->len, - }; + struct cafile_source source; + source.type = CAFILE_SOURCE_BLOB; + source.data = ca_info_blob->data; + source.len = ca_info_blob->len; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { @@ -633,11 +635,11 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data, } if(ssl_cafile) { - struct cafile_source source = { - CAFILE_SOURCE_PATH, - ssl_cafile, - 0, - }; + struct cafile_source source; + source.type = CAFILE_SOURCE_PATH; + source.data = ssl_cafile; + source.len = 0; + ret = load_cafile(&source, &backend->anchors, &backend->anchors_len); if(ret != CURLE_OK) { if(verifypeer) { @@ -873,14 +875,14 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data, #ifdef USE_HTTP2 if(!strcmp(protocol, ALPN_H2)) - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; else #endif if(!strcmp(protocol, ALPN_HTTP_1_1)) - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; else infof(data, "ALPN, unrecognized protocol %s", protocol); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else diff --git a/Utilities/cmcurl/lib/vtls/bearssl.h b/Utilities/cmcurl/lib/vtls/bearssl.h index d72b7d0..5125359 100644 --- a/Utilities/cmcurl/lib/vtls/bearssl.h +++ b/Utilities/cmcurl/lib/vtls/bearssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2019 - 2020, Michael Forney, <mforney@mforney.org> + * Copyright (C) 2019 - 2022, Michael Forney, <mforney@mforney.org> * * 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c index 7a65f92..4ee4ede 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.c +++ b/Utilities/cmcurl/lib/vtls/gskit.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/gskit.h b/Utilities/cmcurl/lib/vtls/gskit.h index 202df7e..cf923f6 100644 --- a/Utilities/cmcurl/lib/vtls/gskit.h +++ b/Utilities/cmcurl/lib/vtls/gskit.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c index dd82755..cf3dbc5 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.c +++ b/Utilities/cmcurl/lib/vtls/gtls.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -43,6 +45,7 @@ #include "inet_pton.h" #include "gtls.h" #include "vtls.h" +#include "vauth/vauth.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" @@ -446,7 +449,7 @@ gtls_connect_step1(struct Curl_easy *data, #ifdef USE_GNUTLS_SRP if((SSL_SET_OPTION(primary.authtype) == CURL_TLSAUTH_SRP) && - Curl_allow_auth_to_host(data)) { + Curl_auth_allowed_to_host(data)) { infof(data, "Using TLS-SRP username: %s", SSL_SET_OPTION(primary.username)); @@ -1272,19 +1275,19 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(proto.size == ALPN_H2_LENGTH && !memcmp(ALPN_H2, proto.data, ALPN_H2_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(proto.size == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } } else infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h index 642d5f0..abade73 100644 --- a/Utilities/cmcurl/lib/vtls/gtls.h +++ b/Utilities/cmcurl/lib/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/hostcheck.c b/Utilities/cmcurl/lib/vtls/hostcheck.c index 8dc97a2..2a648f2 100644 --- a/Utilities/cmcurl/lib/vtls/hostcheck.c +++ b/Utilities/cmcurl/lib/vtls/hostcheck.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/hostcheck.h b/Utilities/cmcurl/lib/vtls/hostcheck.h index aa96640..d3c4eab 100644 --- a/Utilities/cmcurl/lib/vtls/hostcheck.h +++ b/Utilities/cmcurl/lib/vtls/hostcheck.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include <curl/curl.h> diff --git a/Utilities/cmcurl/lib/vtls/keylog.c b/Utilities/cmcurl/lib/vtls/keylog.c index a45945f..1952a69 100644 --- a/Utilities/cmcurl/lib/vtls/keylog.c +++ b/Utilities/cmcurl/lib/vtls/keylog.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,10 +18,13 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #include "keylog.h" +#include <curl/curl.h> /* The last #include files should be: */ #include "curl_memory.h" diff --git a/Utilities/cmcurl/lib/vtls/keylog.h b/Utilities/cmcurl/lib/vtls/keylog.h index 63626da..5d3c675 100644 --- a/Utilities/cmcurl/lib/vtls/keylog.h +++ b/Utilities/cmcurl/lib/vtls/keylog.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c index b60b9ca..fbde897 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -819,19 +821,19 @@ mbed_connect_step2(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(!strncmp(next_protocol, ALPN_H2, ALPN_H2_LENGTH) && !next_protocol[ALPN_H2_LENGTH]) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) && !next_protocol[ALPN_HTTP_1_1_LENGTH]) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } } else { infof(data, VTLS_INFOF_NO_ALPN); } - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.h b/Utilities/cmcurl/lib/vtls/mbedtls.h index 1abd331..ec3b43b 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls.h +++ b/Utilities/cmcurl/lib/vtls/mbedtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -21,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c index 751755c..3971e69 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c +++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013 - 2022, 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 @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h index e40dfc8..3a50d03 100644 --- a/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h +++ b/Utilities/cmcurl/lib/vtls/mbedtls_threadlock.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2013 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com> * * This software is licensed as described in the file COPYING, which @@ -21,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index cb0509f..12cf618 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -334,7 +336,7 @@ static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc *model, char name[MAX_CIPHER_LENGTH + 1]; size_t len; bool found = FALSE; - while((*cipher) && (ISSPACE(*cipher))) + while((*cipher) && (ISBLANK(*cipher))) ++cipher; end = strpbrk(cipher, ":, "); @@ -848,7 +850,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) unsigned int buflen; SSLNextProtoState state; - if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) { + if(!conn->bits.tls_enable_alpn) { return; } @@ -869,21 +871,21 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, buflen, buf); break; #endif - case SSL_NEXT_PROTO_NEGOTIATED: - infof(data, "NPN, server accepted to use %.*s", buflen, buf); + default: + /* ignore SSL_NEXT_PROTO_NEGOTIATED */ break; } #ifdef USE_HTTP2 if(buflen == ALPN_H2_LENGTH && !memcmp(ALPN_H2, buf, ALPN_H2_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(buflen == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } /* This callback might get called when PR_Recv() is used within @@ -891,7 +893,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) * be any "bundle" associated with the connection anymore. */ if(conn->bundle) - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } } @@ -934,8 +936,8 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, if(cipherInfo.symCipher != ssl_calg_aes_gcm) goto end; - /* Enforce ALPN or NPN to do False Start, as an indicator of server - * compatibility. */ + /* Enforce ALPN to do False Start, as an indicator of server + compatibility. */ rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn, &negotiatedExtension); if(rv != SECSuccess || !negotiatedExtension) { @@ -2134,12 +2136,6 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, } #endif -#ifdef SSL_ENABLE_NPN - if(SSL_OptionSet(backend->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn - ? PR_TRUE : PR_FALSE) != SECSuccess) - goto error; -#endif - #ifdef SSL_ENABLE_ALPN if(SSL_OptionSet(backend->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn ? PR_TRUE : PR_FALSE) != SECSuccess) @@ -2158,15 +2154,15 @@ static CURLcode nss_setup_connect(struct Curl_easy *data, } #endif -#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { +#if defined(SSL_ENABLE_ALPN) + if(conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; #ifdef USE_HTTP2 if(data->state.httpwant >= CURL_HTTP_VERSION_2 #ifndef CURL_DISABLE_PROXY - && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) + && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy) #endif ) { protocols[cur++] = ALPN_H2_LENGTH; diff --git a/Utilities/cmcurl/lib/vtls/nssg.h b/Utilities/cmcurl/lib/vtls/nssg.h index 37b3646..454a38f 100644 --- a/Utilities/cmcurl/lib/vtls/nssg.h +++ b/Utilities/cmcurl/lib/vtls/nssg.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index 5d1203b..0dc695d 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -27,7 +29,7 @@ #include "curl_setup.h" -#ifdef USE_OPENSSL +#if defined(USE_QUICHE) || defined(USE_OPENSSL) #include <limits.h> @@ -53,6 +55,7 @@ #include "slist.h" #include "select.h" #include "vtls.h" +#include "vauth/vauth.h" #include "keylog.h" #include "strcase.h" #include "hostcheck.h" @@ -76,10 +79,6 @@ #include <openssl/buffer.h> #include <openssl/pkcs12.h> -#ifdef USE_AMISSL -#include "amigaos.h" -#endif - #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP) #include <openssl/ocsp.h> #endif @@ -275,6 +274,344 @@ struct ssl_backend_data { #endif }; +#define push_certinfo(_label, _num) \ +do { \ + long info_len = BIO_get_mem_data(mem, &ptr); \ + Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ + if(1 != BIO_reset(mem)) \ + break; \ +} while(0) + +static void pubkey_show(struct Curl_easy *data, + BIO *mem, + int num, + const char *type, + const char *name, + const BIGNUM *bn) +{ + char *ptr; + char namebuf[32]; + + msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); + + if(bn) + BN_print(mem, bn); + push_certinfo(namebuf, num); +} + +#ifdef HAVE_OPAQUE_RSA_DSA_DH +#define print_pubkey_BN(_type, _name, _num) \ + pubkey_show(data, mem, _num, #_type, #_name, _name) + +#else +#define print_pubkey_BN(_type, _name, _num) \ +do { \ + if(_type->_name) { \ + pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ + } \ +} while(0) +#endif + +static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) +{ + int i, ilen; + + ilen = (int)len; + if(ilen < 0) + return 1; /* buffer too big */ + + i = i2t_ASN1_OBJECT(buf, ilen, a); + + if(i >= ilen) + return 1; /* buffer too small */ + + return 0; +} + +static void X509V3_ext(struct Curl_easy *data, + int certnum, + CONST_EXTS STACK_OF(X509_EXTENSION) *exts) +{ + int i; + + if((int)sk_X509_EXTENSION_num(exts) <= 0) + /* no extensions, bail out */ + return; + + for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { + ASN1_OBJECT *obj; + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + BUF_MEM *biomem; + char namebuf[128]; + BIO *bio_out = BIO_new(BIO_s_mem()); + + if(!bio_out) + return; + + obj = X509_EXTENSION_get_object(ext); + + asn1_object_dump(obj, namebuf, sizeof(namebuf)); + + if(!X509V3_EXT_print(bio_out, ext, 0, 0)) + ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); + + BIO_get_mem_ptr(bio_out, &biomem); + Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, + biomem->length); + BIO_free(bio_out); + } +} + +#ifdef OPENSSL_IS_BORINGSSL +typedef size_t numcert_t; +#else +typedef int numcert_t; +#endif + +CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl) +{ + CURLcode result; + STACK_OF(X509) *sk; + int i; + numcert_t numcerts; + BIO *mem; + + DEBUGASSERT(ssl); + + sk = SSL_get_peer_cert_chain(ssl); + if(!sk) { + return CURLE_OUT_OF_MEMORY; + } + + numcerts = sk_X509_num(sk); + + result = Curl_ssl_init_certinfo(data, (int)numcerts); + if(result) { + return result; + } + + mem = BIO_new(BIO_s_mem()); + if(!mem) { + return CURLE_OUT_OF_MEMORY; + } + + for(i = 0; i < (int)numcerts; i++) { + ASN1_INTEGER *num; + X509 *x = sk_X509_value(sk, i); + EVP_PKEY *pubkey = NULL; + int j; + char *ptr; + const ASN1_BIT_STRING *psig = NULL; + + X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Subject", i); + + X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); + push_certinfo("Issuer", i); + + BIO_printf(mem, "%lx", X509_get_version(x)); + push_certinfo("Version", i); + + num = X509_get_serialNumber(x); + if(num->type == V_ASN1_NEG_INTEGER) + BIO_puts(mem, "-"); + for(j = 0; j < num->length; j++) + BIO_printf(mem, "%02x", num->data[j]); + push_certinfo("Serial Number", i); + +#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) + { + const X509_ALGOR *sigalg = NULL; + X509_PUBKEY *xpubkey = NULL; + ASN1_OBJECT *pubkeyoid = NULL; + + X509_get0_signature(&psig, &sigalg, x); + if(sigalg) { + i2a_ASN1_OBJECT(mem, sigalg->algorithm); + push_certinfo("Signature Algorithm", i); + } + + xpubkey = X509_get_X509_PUBKEY(x); + if(xpubkey) { + X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey); + if(pubkeyoid) { + i2a_ASN1_OBJECT(mem, pubkeyoid); + push_certinfo("Public Key Algorithm", i); + } + } + + X509V3_ext(data, i, X509_get0_extensions(x)); + } +#else + { + /* before OpenSSL 1.0.2 */ + X509_CINF *cinf = x->cert_info; + + i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); + push_certinfo("Signature Algorithm", i); + + i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); + push_certinfo("Public Key Algorithm", i); + + X509V3_ext(data, i, cinf->extensions); + + psig = x->signature; + } +#endif + + ASN1_TIME_print(mem, X509_get0_notBefore(x)); + push_certinfo("Start date", i); + + ASN1_TIME_print(mem, X509_get0_notAfter(x)); + push_certinfo("Expire date", i); + + pubkey = X509_get_pubkey(x); + if(!pubkey) + infof(data, " Unable to load public key"); + else { + int pktype; +#ifdef HAVE_OPAQUE_EVP_PKEY + pktype = EVP_PKEY_id(pubkey); +#else + pktype = pubkey->type; +#endif + switch(pktype) { + case EVP_PKEY_RSA: + { +#ifndef HAVE_EVP_PKEY_GET_PARAMS + RSA *rsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + rsa = EVP_PKEY_get0_RSA(pubkey); +#else + rsa = pubkey->pkey.rsa; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(n); + DECLARE_PKEY_PARAM_BIGNUM(e); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); +#else + RSA_get0_key(rsa, &n, &e, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ + BIO_printf(mem, "%d", BN_num_bits(n)); +#else + BIO_printf(mem, "%d", BN_num_bits(rsa->n)); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + push_certinfo("RSA Public Key", i); + print_pubkey_BN(rsa, n, i); + print_pubkey_BN(rsa, e, i); + FREE_PKEY_PARAM_BIGNUM(n); + FREE_PKEY_PARAM_BIGNUM(e); + } + + break; + } + case EVP_PKEY_DSA: + { +#ifndef OPENSSL_NO_DSA +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DSA *dsa; +#ifdef HAVE_OPAQUE_EVP_PKEY + dsa = EVP_PKEY_get0_DSA(pubkey); +#else + dsa = pubkey->pkey.dsa; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + print_pubkey_BN(dsa, p, i); + print_pubkey_BN(dsa, q, i); + print_pubkey_BN(dsa, g, i); + print_pubkey_BN(dsa, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); + } +#endif /* !OPENSSL_NO_DSA */ + break; + } + case EVP_PKEY_DH: + { +#ifndef HAVE_EVP_PKEY_GET_PARAMS + DH *dh; +#ifdef HAVE_OPAQUE_EVP_PKEY + dh = EVP_PKEY_get0_DH(pubkey); +#else + dh = pubkey->pkey.dh; +#endif /* HAVE_OPAQUE_EVP_PKEY */ +#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ + { +#ifdef HAVE_OPAQUE_RSA_DSA_DH + DECLARE_PKEY_PARAM_BIGNUM(p); + DECLARE_PKEY_PARAM_BIGNUM(q); + DECLARE_PKEY_PARAM_BIGNUM(g); + DECLARE_PKEY_PARAM_BIGNUM(pub_key); +#ifdef HAVE_EVP_PKEY_GET_PARAMS + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); + EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); +#else + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, NULL); +#endif /* HAVE_EVP_PKEY_GET_PARAMS */ + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, q, i); + print_pubkey_BN(dh, g, i); +#else + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, g, i); +#endif /* HAVE_OPAQUE_RSA_DSA_DH */ + print_pubkey_BN(dh, pub_key, i); + FREE_PKEY_PARAM_BIGNUM(p); + FREE_PKEY_PARAM_BIGNUM(q); + FREE_PKEY_PARAM_BIGNUM(g); + FREE_PKEY_PARAM_BIGNUM(pub_key); + } + break; + } + } + EVP_PKEY_free(pubkey); + } + + if(psig) { + for(j = 0; j < psig->length; j++) + BIO_printf(mem, "%02x:", psig->data[j]); + push_certinfo("Signature", i); + } + + PEM_write_bio_X509(mem, x); + push_certinfo("Cert", i); + } + + BIO_free(mem); + + return CURLE_OK; +} + +#endif /* quiche or OpenSSL */ + +#ifdef USE_OPENSSL + static bool ossl_associate_connection(struct Curl_easy *data, struct connectdata *conn, int sockindex); @@ -486,36 +823,19 @@ static CURLcode ossl_seed(struct Curl_easy *data) return CURLE_SSL_CONNECT_ERROR; #else -#ifndef RANDOM_FILE - /* if RANDOM_FILE isn't defined, we only perform this if an option tells - us to! */ - if(data->set.str[STRING_SSL_RANDOM_FILE]) -#define RANDOM_FILE "" /* doesn't matter won't be used */ +#ifdef RANDOM_FILE + RAND_load_file(RANDOM_FILE, RAND_LOAD_LENGTH); + if(rand_enough()) + return CURLE_OK; #endif - { - /* let the option override the define */ - RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? - data->set.str[STRING_SSL_RANDOM_FILE]: - RANDOM_FILE), - RAND_LOAD_LENGTH); - if(rand_enough()) - return CURLE_OK; - } -#if defined(HAVE_RAND_EGD) - /* only available in OpenSSL 0.9.5 and later */ +#if defined(HAVE_RAND_EGD) && defined(EGD_SOCKET) + /* available in OpenSSL 0.9.5 and later */ /* EGD_SOCKET is set at configure time or not at all */ -#ifndef EGD_SOCKET - /* If we don't have the define set, we only do this if the egd-option - is set */ - if(data->set.str[STRING_SSL_EGDSOCKET]) -#define EGD_SOCKET "" /* doesn't matter won't be used */ -#endif { /* If there's an option and a define, the option overrides the define */ - int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? - data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); + int ret = RAND_egd(EGD_SOCKET); if(-1 != ret) { if(rand_enough()) return CURLE_OK; @@ -814,9 +1134,10 @@ int cert_stuff(struct Curl_easy *data, SSL_CTX_use_certificate_chain_file(ctx, cert_file); if(cert_use_result != 1) { failf(data, - "could not load PEM client certificate, " OSSL_PACKAGE + "could not load PEM client certificate from %s, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", + (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file), ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return 0; @@ -834,9 +1155,10 @@ int cert_stuff(struct Curl_easy *data, 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 + "could not load ASN1 client certificate from %s, " OSSL_PACKAGE " error %s, " "(no key found, wrong pass phrase, or wrong file format?)", + (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file), ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return 0; @@ -889,8 +1211,9 @@ int cert_stuff(struct Curl_easy *data, } if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { - failf(data, "unable to set client certificate"); - X509_free(params.cert); + failf(data, "unable to set client certificate [%s]", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); return 0; } X509_free(params.cert); /* we don't need the handle any more... */ @@ -1013,11 +1336,7 @@ int cert_stuff(struct Curl_easy *data, fail: EVP_PKEY_free(pri); X509_free(x509); -#ifdef USE_AMISSL - sk_X509_pop_free(ca, Curl_amiga_X509_free); -#else sk_X509_pop_free(ca, X509_free); -#endif if(!cert_done) return 0; /* failure! */ break; @@ -2276,14 +2595,6 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, # define HAS_ALPN 1 #endif -/* Check for OpenSSL 1.0.1 which has NPN support. */ -#undef HAS_NPN -#if OPENSSL_VERSION_NUMBER >= 0x10001000L \ - && !defined(OPENSSL_NO_TLSEXT) \ - && !defined(OPENSSL_NO_NEXTPROTONEG) -# define HAS_NPN 1 -#endif - /* Check for OpenSSL 1.1.0 which has set_{min,max}_proto_version(). */ #undef HAS_MODERN_SET_PROTO_VER #if OPENSSL_VERSION_NUMBER >= 0x10100000L \ @@ -2292,64 +2603,6 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, # define HAS_MODERN_SET_PROTO_VER 1 #endif -#ifdef HAS_NPN - -/* - * in is a list of length prefixed strings. this function has to select - * the protocol we want to use from the list and write its string into out. - */ - -static int -select_next_protocol(unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - const char *key, unsigned int keylen) -{ - unsigned int i; - for(i = 0; i + keylen <= inlen; i += in[i] + 1) { - if(memcmp(&in[i + 1], key, keylen) == 0) { - *out = (unsigned char *) &in[i + 1]; - *outlen = in[i]; - return 0; - } - } - return -1; -} - -static int -select_next_proto_cb(SSL *ssl, - unsigned char **out, unsigned char *outlen, - const unsigned char *in, unsigned int inlen, - void *arg) -{ - struct Curl_easy *data = (struct Curl_easy *)arg; - struct connectdata *conn = data->conn; - (void)ssl; - -#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; - } -#endif - - if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1, - ALPN_HTTP_1_1_LENGTH)) { - 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"); - *out = (unsigned char *)ALPN_HTTP_1_1; - *outlen = ALPN_HTTP_1_1_LENGTH; - conn->negnpn = CURL_HTTP_VERSION_1_1; - - return SSL_TLSEXT_ERR_OK; -} -#endif /* HAS_NPN */ - #ifdef HAS_MODERN_SET_PROTO_VER static CURLcode set_ssl_version_min_max(SSL_CTX *ctx, struct connectdata *conn) @@ -2840,11 +3093,6 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, SSL_CTX_set_options(backend->ctx, ctx_options); -#ifdef HAS_NPN - if(conn->bits.tls_enable_npn) - SSL_CTX_set_next_proto_select_cb(backend->ctx, select_next_proto_cb, data); -#endif - #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { int cur = 0; @@ -2934,7 +3182,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, #ifdef USE_OPENSSL_SRP if((ssl_authtype == CURL_TLSAUTH_SRP) && - Curl_allow_auth_to_host(data)) { + Curl_auth_allowed_to_host(data)) { char * const ssl_username = SSL_SET_OPTION(primary.username); char * const ssl_password = SSL_SET_OPTION(primary.password); infof(data, "Using TLS-SRP username: %s", ssl_username); @@ -3472,19 +3720,19 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, #ifdef USE_HTTP2 if(len == ALPN_H2_LENGTH && !memcmp(ALPN_H2, neg_protocol, len)) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(len == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } } else infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif @@ -3493,342 +3741,6 @@ static CURLcode ossl_connect_step2(struct Curl_easy *data, } } -static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) -{ - int i, ilen; - - ilen = (int)len; - if(ilen < 0) - return 1; /* buffer too big */ - - i = i2t_ASN1_OBJECT(buf, ilen, a); - - if(i >= ilen) - return 1; /* buffer too small */ - - return 0; -} - -#define push_certinfo(_label, _num) \ -do { \ - long info_len = BIO_get_mem_data(mem, &ptr); \ - Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \ - if(1 != BIO_reset(mem)) \ - break; \ -} while(0) - -static void pubkey_show(struct Curl_easy *data, - BIO *mem, - int num, - const char *type, - const char *name, - const BIGNUM *bn) -{ - char *ptr; - char namebuf[32]; - - msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - - if(bn) - BN_print(mem, bn); - push_certinfo(namebuf, num); -} - -#ifdef HAVE_OPAQUE_RSA_DSA_DH -#define print_pubkey_BN(_type, _name, _num) \ - pubkey_show(data, mem, _num, #_type, #_name, _name) - -#else -#define print_pubkey_BN(_type, _name, _num) \ -do { \ - if(_type->_name) { \ - pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \ - } \ -} while(0) -#endif - -static void X509V3_ext(struct Curl_easy *data, - int certnum, - CONST_EXTS STACK_OF(X509_EXTENSION) *exts) -{ - int i; - - if((int)sk_X509_EXTENSION_num(exts) <= 0) - /* no extensions, bail out */ - return; - - for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) { - ASN1_OBJECT *obj; - X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); - BUF_MEM *biomem; - char namebuf[128]; - BIO *bio_out = BIO_new(BIO_s_mem()); - - if(!bio_out) - return; - - obj = X509_EXTENSION_get_object(ext); - - asn1_object_dump(obj, namebuf, sizeof(namebuf)); - - if(!X509V3_EXT_print(bio_out, ext, 0, 0)) - ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext)); - - BIO_get_mem_ptr(bio_out, &biomem); - Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data, - biomem->length); - BIO_free(bio_out); - } -} - -#ifdef OPENSSL_IS_BORINGSSL -typedef size_t numcert_t; -#else -typedef int numcert_t; -#endif - -static CURLcode get_cert_chain(struct Curl_easy *data, - struct ssl_connect_data *connssl) -{ - CURLcode result; - STACK_OF(X509) *sk; - int i; - numcert_t numcerts; - BIO *mem; - struct ssl_backend_data *backend = connssl->backend; - - DEBUGASSERT(backend); - - sk = SSL_get_peer_cert_chain(backend->handle); - if(!sk) { - return CURLE_OUT_OF_MEMORY; - } - - numcerts = sk_X509_num(sk); - - result = Curl_ssl_init_certinfo(data, (int)numcerts); - if(result) { - return result; - } - - mem = BIO_new(BIO_s_mem()); - if(!mem) { - return CURLE_OUT_OF_MEMORY; - } - - for(i = 0; i < (int)numcerts; i++) { - ASN1_INTEGER *num; - X509 *x = sk_X509_value(sk, i); - EVP_PKEY *pubkey = NULL; - int j; - char *ptr; - const ASN1_BIT_STRING *psig = NULL; - - X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Subject", i); - - X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE); - push_certinfo("Issuer", i); - - BIO_printf(mem, "%lx", X509_get_version(x)); - push_certinfo("Version", i); - - num = X509_get_serialNumber(x); - if(num->type == V_ASN1_NEG_INTEGER) - BIO_puts(mem, "-"); - for(j = 0; j < num->length; j++) - BIO_printf(mem, "%02x", num->data[j]); - push_certinfo("Serial Number", i); - -#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) - { - const X509_ALGOR *sigalg = NULL; - X509_PUBKEY *xpubkey = NULL; - ASN1_OBJECT *pubkeyoid = NULL; - - X509_get0_signature(&psig, &sigalg, x); - if(sigalg) { - i2a_ASN1_OBJECT(mem, sigalg->algorithm); - push_certinfo("Signature Algorithm", i); - } - - xpubkey = X509_get_X509_PUBKEY(x); - if(xpubkey) { - X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey); - if(pubkeyoid) { - i2a_ASN1_OBJECT(mem, pubkeyoid); - push_certinfo("Public Key Algorithm", i); - } - } - - X509V3_ext(data, i, X509_get0_extensions(x)); - } -#else - { - /* before OpenSSL 1.0.2 */ - X509_CINF *cinf = x->cert_info; - - i2a_ASN1_OBJECT(mem, cinf->signature->algorithm); - push_certinfo("Signature Algorithm", i); - - i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm); - push_certinfo("Public Key Algorithm", i); - - X509V3_ext(data, i, cinf->extensions); - - psig = x->signature; - } -#endif - - ASN1_TIME_print(mem, X509_get0_notBefore(x)); - push_certinfo("Start date", i); - - ASN1_TIME_print(mem, X509_get0_notAfter(x)); - push_certinfo("Expire date", i); - - pubkey = X509_get_pubkey(x); - if(!pubkey) - infof(data, " Unable to load public key"); - else { - int pktype; -#ifdef HAVE_OPAQUE_EVP_PKEY - pktype = EVP_PKEY_id(pubkey); -#else - pktype = pubkey->type; -#endif - switch(pktype) { - case EVP_PKEY_RSA: - { -#ifndef HAVE_EVP_PKEY_GET_PARAMS - RSA *rsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - rsa = EVP_PKEY_get0_RSA(pubkey); -#else - rsa = pubkey->pkey.rsa; -#endif /* HAVE_OPAQUE_EVP_PKEY */ -#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ - - { -#ifdef HAVE_OPAQUE_RSA_DSA_DH - DECLARE_PKEY_PARAM_BIGNUM(n); - DECLARE_PKEY_PARAM_BIGNUM(e); -#ifdef HAVE_EVP_PKEY_GET_PARAMS - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &n); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &e); -#else - RSA_get0_key(rsa, &n, &e, NULL); -#endif /* HAVE_EVP_PKEY_GET_PARAMS */ - BIO_printf(mem, "%d", BN_num_bits(n)); -#else - BIO_printf(mem, "%d", BN_num_bits(rsa->n)); -#endif /* HAVE_OPAQUE_RSA_DSA_DH */ - push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); - print_pubkey_BN(rsa, e, i); - FREE_PKEY_PARAM_BIGNUM(n); - FREE_PKEY_PARAM_BIGNUM(e); - } - - break; - } - case EVP_PKEY_DSA: - { -#ifndef OPENSSL_NO_DSA -#ifndef HAVE_EVP_PKEY_GET_PARAMS - DSA *dsa; -#ifdef HAVE_OPAQUE_EVP_PKEY - dsa = EVP_PKEY_get0_DSA(pubkey); -#else - dsa = pubkey->pkey.dsa; -#endif /* HAVE_OPAQUE_EVP_PKEY */ -#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ - { -#ifdef HAVE_OPAQUE_RSA_DSA_DH - DECLARE_PKEY_PARAM_BIGNUM(p); - DECLARE_PKEY_PARAM_BIGNUM(q); - DECLARE_PKEY_PARAM_BIGNUM(g); - DECLARE_PKEY_PARAM_BIGNUM(pub_key); -#ifdef HAVE_EVP_PKEY_GET_PARAMS - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); -#else - DSA_get0_pqg(dsa, &p, &q, &g); - DSA_get0_key(dsa, &pub_key, NULL); -#endif /* HAVE_EVP_PKEY_GET_PARAMS */ -#endif /* HAVE_OPAQUE_RSA_DSA_DH */ - print_pubkey_BN(dsa, p, i); - print_pubkey_BN(dsa, q, i); - print_pubkey_BN(dsa, g, i); - print_pubkey_BN(dsa, pub_key, i); - FREE_PKEY_PARAM_BIGNUM(p); - FREE_PKEY_PARAM_BIGNUM(q); - FREE_PKEY_PARAM_BIGNUM(g); - FREE_PKEY_PARAM_BIGNUM(pub_key); - } -#endif /* !OPENSSL_NO_DSA */ - break; - } - case EVP_PKEY_DH: - { -#ifndef HAVE_EVP_PKEY_GET_PARAMS - DH *dh; -#ifdef HAVE_OPAQUE_EVP_PKEY - dh = EVP_PKEY_get0_DH(pubkey); -#else - dh = pubkey->pkey.dh; -#endif /* HAVE_OPAQUE_EVP_PKEY */ -#endif /* !HAVE_EVP_PKEY_GET_PARAMS */ - { -#ifdef HAVE_OPAQUE_RSA_DSA_DH - DECLARE_PKEY_PARAM_BIGNUM(p); - DECLARE_PKEY_PARAM_BIGNUM(q); - DECLARE_PKEY_PARAM_BIGNUM(g); - DECLARE_PKEY_PARAM_BIGNUM(pub_key); -#ifdef HAVE_EVP_PKEY_GET_PARAMS - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_P, &p); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_Q, &q); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_FFC_G, &g); - EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, &pub_key); -#else - DH_get0_pqg(dh, &p, &q, &g); - DH_get0_key(dh, &pub_key, NULL); -#endif /* HAVE_EVP_PKEY_GET_PARAMS */ - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, q, i); - print_pubkey_BN(dh, g, i); -#else - print_pubkey_BN(dh, p, i); - print_pubkey_BN(dh, g, i); -#endif /* HAVE_OPAQUE_RSA_DSA_DH */ - print_pubkey_BN(dh, pub_key, i); - FREE_PKEY_PARAM_BIGNUM(p); - FREE_PKEY_PARAM_BIGNUM(q); - FREE_PKEY_PARAM_BIGNUM(g); - FREE_PKEY_PARAM_BIGNUM(pub_key); - } - break; - } - } - EVP_PKEY_free(pubkey); - } - - if(psig) { - for(j = 0; j < psig->length; j++) - BIO_printf(mem, "%02x:", psig->data[j]); - push_certinfo("Signature", i); - } - - PEM_write_bio_X509(mem, x); - push_certinfo("Cert", i); - } - - BIO_free(mem); - - return CURLE_OK; -} - /* * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL @@ -3923,8 +3835,8 @@ static CURLcode servercert(struct Curl_easy *data, } if(data->set.ssl.certinfo) - /* we've been asked to gather certificate info! */ - (void)get_cert_chain(data, connssl); + /* asked to gather certificate info */ + (void)Curl_ossl_certchain(data, connssl->backend->handle); backend->server_cert = SSL_get1_peer_certificate(backend->handle); if(!backend->server_cert) { @@ -4467,7 +4379,7 @@ static size_t ossl_version(char *buffer, size_t size) } count = msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); for(p = buffer; *p; ++p) { - if(ISSPACE(*p)) + if(ISBLANK(*p)) *p = '_'; } return count; @@ -4479,7 +4391,13 @@ static size_t ossl_version(char *buffer, size_t size) (LIBRESSL_VERSION_NUMBER>>12)&0xff); #endif #elif defined(OPENSSL_IS_BORINGSSL) +#ifdef CURL_BORINGSSL_VERSION + return msnprintf(buffer, size, "%s/%s", + OSSL_PACKAGE, + CURL_BORINGSSL_VERSION); +#else return msnprintf(buffer, size, OSSL_PACKAGE); +#endif #elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING) return msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING)); diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h index 0a7536e..9df4ecd 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.h +++ b/Utilities/cmcurl/lib/vtls/openssl.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -29,6 +31,7 @@ * This header should only be needed to get included by vtls.c, openssl.c * and ngtcp2.c */ +#include <openssl/ssl.h> #include "urldata.h" @@ -51,5 +54,7 @@ CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, const struct curl_blob *key_blob, const char *key_type, char *key_passwd); +CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl); + #endif /* USE_OPENSSL */ #endif /* HEADER_CURL_SSLUSE_H */ diff --git a/Utilities/cmcurl/lib/vtls/rustls.c b/Utilities/cmcurl/lib/vtls/rustls.c index 16970b7..77a49f1 100644 --- a/Utilities/cmcurl/lib/vtls/rustls.c +++ b/Utilities/cmcurl/lib/vtls/rustls.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -413,20 +415,20 @@ cr_set_negotiated_alpn(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(len == ALPN_H2_LENGTH && 0 == memcmp(ALPN_H2, protocol, len)) { infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_H2); - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(len == ALPN_HTTP_1_1_LENGTH && 0 == memcmp(ALPN_HTTP_1_1, protocol, len)) { infof(data, VTLS_INFOF_ALPN_ACCEPTED_1STR, ALPN_HTTP_1_1); - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } else { infof(data, "ALPN, negotiated an unrecognized protocol"); } - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } diff --git a/Utilities/cmcurl/lib/vtls/rustls.h b/Utilities/cmcurl/lib/vtls/rustls.h index 056211d..6b393dd 100644 --- a/Utilities/cmcurl/lib/vtls/rustls.h +++ b/Utilities/cmcurl/lib/vtls/rustls.h @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2020 - 2021, Jacob Hoffman-Andrews, + * Copyright (C) 2020 - 2022, Jacob Hoffman-Andrews, * <github@hoffman-andrews.com> * * This software is licensed as described in the file COPYING, which @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #ifndef HEADER_CURL_RUSTLS_H #define HEADER_CURL_RUSTLS_H diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index dfec66d..454eb79 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -51,6 +53,7 @@ #include "curl_printf.h" #include "multiif.h" #include "version_win32.h" +#include "rand.h" /* The last #include file should be: */ #include "curl_memory.h" @@ -81,8 +84,35 @@ #endif #endif -#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) -#define HAS_CLIENT_CERT_PATH +#ifndef BCRYPT_CHACHA20_POLY1305_ALGORITHM +#define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305" +#endif + +#ifndef BCRYPT_CHAIN_MODE_CCM +#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM" +#endif + +#ifndef BCRYPT_CHAIN_MODE_GCM +#define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM" +#endif + +#ifndef BCRYPT_AES_ALGORITHM +#define BCRYPT_AES_ALGORITHM L"AES" +#endif + +#ifndef BCRYPT_SHA256_ALGORITHM +#define BCRYPT_SHA256_ALGORITHM L"SHA256" +#endif + +#ifndef BCRYPT_SHA384_ALGORITHM +#define BCRYPT_SHA384_ALGORITHM L"SHA384" +#endif + +/* Workaround broken compilers like MinGW. + Return the number of elements in a statically sized array. +*/ +#ifndef ARRAYSIZE +#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) #endif #ifdef HAS_CLIENT_CERT_PATH @@ -117,6 +147,10 @@ #define SP_PROT_TLS1_2_CLIENT 0x00000800 #endif +#ifndef SP_PROT_TLS1_3_CLIENT +#define SP_PROT_TLS1_3_CLIENT 0x00002000 +#endif + #ifndef SCH_USE_STRONG_CRYPTO #define SCH_USE_STRONG_CRYPTO 0x00400000 #endif @@ -147,6 +181,10 @@ #define ALG_CLASS_DHASH ALG_CLASS_HASH #endif +#ifndef PKCS12_NO_PERSIST_KEY +#define PKCS12_NO_PERSIST_KEY 0x00008000 +#endif + static Curl_recv schannel_recv; static Curl_send schannel_send; @@ -171,7 +209,7 @@ static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr, } static CURLcode -set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct Curl_easy *data, +set_ssl_version_min_max(DWORD *enabled_protocols, struct Curl_easy *data, struct connectdata *conn) { long ssl_version = SSL_CONN_CONFIG(version); @@ -181,23 +219,44 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct Curl_easy *data, switch(ssl_version_max) { case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_DEFAULT: - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + + /* Windows Server 2022 and newer (including Windows 11) support TLS 1.3 + built-in. Previous builds of Windows 10 had broken TLS 1.3 + implementations that could be enabled via registry. + */ + if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; + } + else /* Windows 10 and older */ + ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; + break; } + for(; i <= (ssl_version_max >> 16); ++i) { switch(i) { case CURL_SSLVERSION_TLSv1_0: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT; + (*enabled_protocols) |= SP_PROT_TLS1_0_CLIENT; break; case CURL_SSLVERSION_TLSv1_1: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT; + (*enabled_protocols) |= SP_PROT_TLS1_1_CLIENT; break; case CURL_SSLVERSION_TLSv1_2: - schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT; + (*enabled_protocols) |= SP_PROT_TLS1_2_CLIENT; break; case CURL_SSLVERSION_TLSv1_3: - failf(data, "schannel: TLS 1.3 is not yet supported"); - return CURLE_SSL_CONNECT_ERROR; + + /* Windows Server 2022 and newer */ + if(curlx_verify_windows_version(10, 0, 20348, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + (*enabled_protocols) |= SP_PROT_TLS1_3_CLIENT; + break; + } + else { /* Windows 10 and older */ + failf(data, "schannel: TLS 1.3 not supported on Windows prior to 11"); + return CURLE_SSL_CONNECT_ERROR; + } } } return CURLE_OK; @@ -214,8 +273,12 @@ get_alg_id_by_name(char *name) { char tmp[LONGEST_ALG_ID] = { 0 }; char *nameEnd = strchr(name, ':'); - size_t n = nameEnd ? min((size_t)(nameEnd - name), LONGEST_ALG_ID - 1) : \ - min(strlen(name), LONGEST_ALG_ID - 1); + size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name); + + /* reject too-long alg names */ + if(n > (LONGEST_ALG_ID - 1)) + return 0; + strncpy(tmp, name, n); tmp[n] = 0; CIPHEROPTION(CALG_MD2); @@ -383,13 +446,13 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, else if(_tcsncmp(path, TEXT("Users"), store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_USERS; else if(_tcsncmp(path, TEXT("CurrentUserGroupPolicy"), - store_name_len) == 0) + store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY; else if(_tcsncmp(path, TEXT("LocalMachineGroupPolicy"), - store_name_len) == 0) + store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY; else if(_tcsncmp(path, TEXT("LocalMachineEnterprise"), - store_name_len) == 0) + store_name_len) == 0) *store_name = CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE; else return CURLE_SSL_CERTPROBLEM; @@ -419,49 +482,52 @@ schannel_acquire_credential_handle(struct Curl_easy *data, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - SCHANNEL_CRED schannel_cred; - ALG_ID algIds[NUM_CIPHERS]; + +#ifdef HAS_CLIENT_CERT_PATH PCCERT_CONTEXT client_certs[1] = { NULL }; + HCERTSTORE client_cert_store = NULL; +#endif SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; + + /* setup Schannel API options */ + DWORD flags = 0; + DWORD enabled_protocols = 0; + struct ssl_backend_data *backend = connssl->backend; DEBUGASSERT(backend); - /* 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; + flags = SCH_CRED_MANUAL_CRED_VALIDATION; else #endif - schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; + flags = SCH_CRED_AUTO_CRED_VALIDATION; if(SSL_SET_OPTION(no_revoke)) { - schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | + flags |= 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 | + flags |= 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; + flags |= SCH_CRED_REVOCATION_CHECK_CHAIN; DEBUGF(infof(data, "schannel: checking server certificate revocation")); } } else { - schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION | + flags = SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; DEBUGF(infof(data, @@ -469,15 +535,15 @@ schannel_acquire_credential_handle(struct Curl_easy *data, } if(!conn->ssl_config.verifyhost) { - schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; + flags |= 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; + flags &= ~SCH_CRED_USE_DEFAULT_CREDS; + flags |= SCH_CRED_NO_DEFAULT_CREDS; infof(data, "schannel: disabled automatic use of client certificate"); } else @@ -491,7 +557,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: { - result = set_ssl_version_min_max(&schannel_cred, data, conn); + result = set_ssl_version_min_max(&enabled_protocols, data, conn); if(result != CURLE_OK) return result; break; @@ -505,16 +571,6 @@ schannel_acquire_credential_handle(struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; } - if(SSL_CONN_CONFIG(cipher_list)) { - result = set_ssl_ciphers(&schannel_cred, SSL_CONN_CONFIG(cipher_list), - 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) { @@ -540,7 +596,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; result = get_cert_location(cert_path, &cert_store_name, - &cert_store_path, &cert_thumbprint_str); + &cert_store_path, &cert_thumbprint_str); if(result && (data->set.ssl.primary.clientcert[0]!='\0')) fInCert = fopen(data->set.ssl.primary.clientcert, "rb"); @@ -555,18 +611,18 @@ schannel_acquire_credential_handle(struct Curl_easy *data, } if((fInCert || blob) && (data->set.ssl.cert_type) && - (!strcasecompare(data->set.ssl.cert_type, "P12"))) { + (!strcasecompare(data->set.ssl.cert_type, "P12"))) { failf(data, "schannel: certificate format compatibility error " - " for %s", - blob ? "(memory blob)" : data->set.ssl.primary.clientcert); + " 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 + https://social.msdn.microsoft.com/Forums/windowsdesktop/ + en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5 */ CRYPT_DATA_BLOB datablob; WCHAR* pszPassword; @@ -594,7 +650,7 @@ schannel_acquire_credential_handle(struct Curl_easy *data, fclose(fInCert); if(!continue_reading) { failf(data, "schannel: Failed to read cert file %s", - data->set.ssl.primary.clientcert); + data->set.ssl.primary.clientcert); free(certdata); return CURLE_SSL_CERTPROBLEM; } @@ -610,16 +666,23 @@ schannel_acquire_credential_handle(struct Curl_easy *data, 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)); + 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); + if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) + cert_store = PFXImportCertStore(&datablob, pszPassword, + PKCS12_NO_PERSIST_KEY); + else + cert_store = PFXImportCertStore(&datablob, pszPassword, 0); + free(pszPassword); } if(!blob) @@ -648,9 +711,6 @@ schannel_acquire_credential_handle(struct Curl_easy *data, CertCloseStore(cert_store, 0); return CURLE_SSL_CERTPROBLEM; } - - schannel_cred.cCreds = 1; - schannel_cred.paCred = client_certs; } else { cert_store = @@ -688,17 +748,13 @@ schannel_acquire_credential_handle(struct Curl_easy *data, curlx_unicodefree(cert_path); - if(client_certs[0]) { - schannel_cred.cCreds = 1; - schannel_cred.paCred = client_certs; - } - else { + if(!client_certs[0]) { /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ CertCloseStore(cert_store, 0); return CURLE_SSL_CERTPROBLEM; } } - CertCloseStore(cert_store, 0); + client_cert_store = cert_store; } #else if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { @@ -713,22 +769,279 @@ schannel_acquire_credential_handle(struct Curl_easy *data, if(!backend->cred) { failf(data, "schannel: unable to allocate memory"); +#ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); + if(client_cert_store) + CertCloseStore(client_cert_store, 0); +#endif return CURLE_OUT_OF_MEMORY; } backend->cred->refcount = 1; - 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); +#ifdef HAS_CLIENT_CERT_PATH + /* Since we did not persist the key, we need to extend the store's + * lifetime until the end of the connection + */ + backend->cred->client_cert_store = client_cert_store; +#endif + /* Windows 10, 1809 (a.k.a. Windows 10 build 17763) */ + if(curlx_verify_windows_version(10, 0, 17763, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) { + + char *ciphers13 = 0; + + bool disable_aes_gcm_sha384 = FALSE; + bool disable_aes_gcm_sha256 = FALSE; + bool disable_chacha_poly = FALSE; + bool disable_aes_ccm_8_sha256 = FALSE; + bool disable_aes_ccm_sha256 = FALSE; + + SCH_CREDENTIALS credentials = { 0 }; + TLS_PARAMETERS tls_parameters = { 0 }; + CRYPTO_SETTINGS crypto_settings[4] = { 0 }; + UNICODE_STRING blocked_ccm_modes[1] = { 0 }; + UNICODE_STRING blocked_gcm_modes[1] = { 0 }; + + int crypto_settings_idx = 0; + + + /* If TLS 1.3 ciphers are explicitly listed, then + * disable all the ciphers and re-enable which + * ciphers the user has provided. + */ + ciphers13 = SSL_CONN_CONFIG(cipher_list13); + if(ciphers13) { + const int remaining_ciphers = 5; + + /* detect which remaining ciphers to enable + and then disable everything else. + */ + + char *startCur = ciphers13; + int algCount = 0; + char tmp[LONGEST_ALG_ID] = { 0 }; + char *nameEnd; + size_t n; + + disable_aes_gcm_sha384 = TRUE; + disable_aes_gcm_sha256 = TRUE; + disable_chacha_poly = TRUE; + disable_aes_ccm_8_sha256 = TRUE; + disable_aes_ccm_sha256 = TRUE; + + while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) { + nameEnd = strchr(startCur, ':'); + n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur); + + /* reject too-long cipher names */ + if(n > (LONGEST_ALG_ID - 1)) { + failf(data, "Cipher name too long, not checked."); + return CURLE_SSL_CIPHER; + } + + strncpy(tmp, startCur, n); + tmp[n] = 0; + + if(disable_aes_gcm_sha384 + && !strcmp("TLS_AES_256_GCM_SHA384", tmp)) { + disable_aes_gcm_sha384 = FALSE; + } + else if(disable_aes_gcm_sha256 + && !strcmp("TLS_AES_128_GCM_SHA256", tmp)) { + disable_aes_gcm_sha256 = FALSE; + } + else if(disable_chacha_poly + && !strcmp("TLS_CHACHA20_POLY1305_SHA256", tmp)) { + disable_chacha_poly = FALSE; + } + else if(disable_aes_ccm_8_sha256 + && !strcmp("TLS_AES_128_CCM_8_SHA256", tmp)) { + disable_aes_ccm_8_sha256 = FALSE; + } + else if(disable_aes_ccm_sha256 + && !strcmp("TLS_AES_128_CCM_SHA256", tmp)) { + disable_aes_ccm_sha256 = FALSE; + } + else { + failf(data, "Passed in an unknown TLS 1.3 cipher."); + return CURLE_SSL_CIPHER; + } + + startCur = nameEnd; + if(startCur) + startCur++; + + algCount++; + } + } + + if(disable_aes_gcm_sha384 && disable_aes_gcm_sha256 + && disable_chacha_poly && disable_aes_ccm_8_sha256 + && disable_aes_ccm_sha256) { + failf(data, "All available TLS 1.3 ciphers were disabled."); + return CURLE_SSL_CIPHER; + } + + /* Disable TLS_AES_128_CCM_8_SHA256 and/or TLS_AES_128_CCM_SHA256 */ + if(disable_aes_ccm_8_sha256 || disable_aes_ccm_sha256) { + /* + Disallow AES_CCM algorithm. + */ + blocked_ccm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_CCM); + blocked_ccm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_CCM); + blocked_ccm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_CCM; + + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageCipher; + crypto_settings[crypto_settings_idx].rgstrChainingModes = + blocked_ccm_modes; + crypto_settings[crypto_settings_idx].cChainingModes = + ARRAYSIZE(blocked_ccm_modes); + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)BCRYPT_AES_ALGORITHM; + + /* only disabling one of the CCM modes */ + if(disable_aes_ccm_8_sha256 != disable_aes_ccm_sha256) { + if(disable_aes_ccm_8_sha256) + crypto_settings[crypto_settings_idx].dwMinBitLength = 128; + else /* disable_aes_ccm_sha256 */ + crypto_settings[crypto_settings_idx].dwMaxBitLength = 64; + } + + crypto_settings_idx++; + } + + /* Disable TLS_AES_256_GCM_SHA384 and/or TLS_AES_128_GCM_SHA256 */ + if(disable_aes_gcm_sha384 || disable_aes_gcm_sha256) { + + /* + Disallow AES_GCM algorithm + */ + blocked_gcm_modes[0].Length = sizeof(BCRYPT_CHAIN_MODE_GCM); + blocked_gcm_modes[0].MaximumLength = sizeof(BCRYPT_CHAIN_MODE_GCM); + blocked_gcm_modes[0].Buffer = (PWSTR)BCRYPT_CHAIN_MODE_GCM; + + /* if only one is disabled, then explicitly disable the + digest cipher suite (sha384 or sha256) */ + if(disable_aes_gcm_sha384 != disable_aes_gcm_sha256) { + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageDigest; + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(disable_aes_gcm_sha384 ? + BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(disable_aes_gcm_sha384 ? + BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)(disable_aes_gcm_sha384 ? + BCRYPT_SHA384_ALGORITHM : BCRYPT_SHA256_ALGORITHM); + } + else { /* Disable both AES_GCM ciphers */ + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageCipher; + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(BCRYPT_AES_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)BCRYPT_AES_ALGORITHM; + } + + crypto_settings[crypto_settings_idx].rgstrChainingModes = + blocked_gcm_modes; + crypto_settings[crypto_settings_idx].cChainingModes = 1; + + crypto_settings_idx++; + } + + /* + Disable ChaCha20-Poly1305. + */ + if(disable_chacha_poly) { + crypto_settings[crypto_settings_idx].eAlgorithmUsage = + TlsParametersCngAlgUsageCipher; + crypto_settings[crypto_settings_idx].strCngAlgId.Length = + sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.MaximumLength = + sizeof(BCRYPT_CHACHA20_POLY1305_ALGORITHM); + crypto_settings[crypto_settings_idx].strCngAlgId.Buffer = + (PWSTR)BCRYPT_CHACHA20_POLY1305_ALGORITHM; + crypto_settings_idx++; + } + + tls_parameters.pDisabledCrypto = crypto_settings; + + /* The number of blocked suites */ + tls_parameters.cDisabledCrypto = crypto_settings_idx; + credentials.pTlsParameters = &tls_parameters; + credentials.cTlsParameters = 1; + + credentials.dwVersion = SCH_CREDENTIALS_VERSION; + credentials.dwFlags = flags | SCH_USE_STRONG_CRYPTO; + + credentials.pTlsParameters->grbitDisabledProtocols = + (DWORD)~enabled_protocols; + +#ifdef HAS_CLIENT_CERT_PATH + if(client_certs[0]) { + credentials.cCreds = 1; + credentials.paCred = client_certs; + } +#endif + + sspi_status = + s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME, + SECPKG_CRED_OUTBOUND, NULL, + &credentials, NULL, NULL, + &backend->cred->cred_handle, + &backend->cred->time_stamp); + } + else { + /* Pre-Windows 10 1809 */ + ALG_ID algIds[NUM_CIPHERS]; + char *ciphers = SSL_CONN_CONFIG(cipher_list); + SCHANNEL_CRED schannel_cred = { 0 }; + schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; + schannel_cred.dwFlags = flags; + schannel_cred.grbitEnabledProtocols = enabled_protocols; + + if(ciphers) { + result = set_ssl_ciphers(&schannel_cred, ciphers, algIds); + if(CURLE_OK != result) { + failf(data, "Unable to set ciphers to passed via SSL_CONN_CONFIG"); + return result; + } + } + else { + schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO; + } + +#ifdef HAS_CLIENT_CERT_PATH + if(client_certs[0]) { + schannel_cred.cCreds = 1; + schannel_cred.paCred = client_certs; + } +#endif + + 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); + } + +#ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); +#endif if(sspi_status != SEC_E_OK) { char buffer[STRERROR_LEN]; @@ -1016,6 +1329,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn, backend->recv_unrecoverable_err = CURLE_OK; backend->recv_sspi_close_notify = false; backend->recv_connection_closed = false; + backend->recv_renegotiating = false; backend->encdata_is_incomplete = false; /* continue to second handshake step */ @@ -1415,6 +1729,7 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { + unsigned char alpn = 0; infof(data, VTLS_INFOF_ALPN_ACCEPTED_LEN_1STR, alpn_result.ProtocolIdSize, alpn_result.ProtocolId); @@ -1422,20 +1737,33 @@ schannel_connect_step3(struct Curl_easy *data, struct connectdata *conn, #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; + alpn = CURL_HTTP_VERSION_2; } else #endif if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH && !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + alpn = CURL_HTTP_VERSION_1_1; } + if(backend->recv_renegotiating) { + if(alpn != conn->alpn) { + failf(data, "schannel: server selected an ALPN protocol too late"); + return CURLE_SSL_CONNECT_ERROR; + } + } + else + conn->alpn = alpn; + } + else { + if(!backend->recv_renegotiating) + infof(data, VTLS_INFOF_NO_ALPN); + } + + if(!backend->recv_renegotiating) { + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? + BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } - else - infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? - BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } #endif @@ -1607,8 +1935,15 @@ schannel_connect_common(struct Curl_easy *data, struct connectdata *conn, if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; - conn->recv[sockindex] = schannel_recv; - conn->send[sockindex] = schannel_send; + if(!connssl->backend->recv_renegotiating) { + /* On renegotiation, we don't want to reset the existing recv/send + * function pointers. They will have been set after the initial TLS + * handshake was completed. If they were subsequently modified, as + * is the case with HTTP/2, we don't want to override that change. + */ + conn->recv[sockindex] = schannel_recv; + conn->send[sockindex] = schannel_send; + } #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS /* When SSPI is used in combination with Schannel @@ -1990,17 +2325,14 @@ schannel_recv(struct Curl_easy *data, int sockindex, infof(data, "schannel: can't renegotiate, an error is pending"); goto cleanup; } - if(backend->encdata_offset) { - *err = CURLE_RECV_ERROR; - infof(data, "schannel: can't renegotiate, " - "encrypted data available"); - goto cleanup; - } + /* begin renegotiation */ infof(data, "schannel: renegotiating SSL/TLS connection"); connssl->state = ssl_connection_negotiating; connssl->connecting_state = ssl_connect_2_writing; + backend->recv_renegotiating = true; *err = schannel_connect_common(data, conn, sockindex, FALSE, &done); + backend->recv_renegotiating = false; if(*err) { infof(data, "schannel: renegotiation failed"); goto cleanup; @@ -2154,6 +2486,12 @@ static void schannel_session_free(void *ptr) if(cred->refcount == 0) { s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); curlx_unicodefree(cred->sni_hostname); +#ifdef HAS_CLIENT_CERT_PATH + if(cred->client_cert_store) { + CertCloseStore(cred->client_cert_store, 0); + cred->client_cert_store = NULL; + } +#endif Curl_safefree(cred); } } @@ -2296,21 +2634,9 @@ static size_t schannel_version(char *buffer, size_t size) static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM, unsigned char *entropy, size_t length) { - HCRYPTPROV hCryptProv = 0; - (void)data; - if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return CURLE_FAILED_INIT; - - if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { - CryptReleaseContext(hCryptProv, 0UL); - return CURLE_FAILED_INIT; - } - - CryptReleaseContext(hCryptProv, 0UL); - return CURLE_OK; + return Curl_win32_random(entropy, length); } static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, @@ -2457,7 +2783,8 @@ const struct Curl_ssl Curl_ssl_schannel = { #ifdef HAS_MANUAL_VERIFY_API SSLSUPP_CAINFO_BLOB | #endif - SSLSUPP_PINNEDPUBKEY, + SSLSUPP_PINNEDPUBKEY | + SSLSUPP_TLS13_CIPHERSUITES, sizeof(struct ssl_backend_data), diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h index da60702..24d7eff 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.h +++ b/Utilities/cmcurl/lib/vtls/schannel.h @@ -21,11 +21,35 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifdef USE_SCHANNEL +#define SCHANNEL_USE_BLACKLISTS 1 + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4201) +#endif +#include <subauth.h> +#ifdef _MSC_VER +#pragma warning(pop) +#endif +/* Wincrypt must be included before anything that could include OpenSSL. */ +#if defined(USE_WIN32_CRYPTO) +#include <wincrypt.h> +/* Undefine wincrypt conflicting symbols for BoringSSL. */ +#undef X509_NAME +#undef X509_EXTENSIONS +#undef PKCS7_ISSUER_AND_SERIAL +#undef PKCS7_SIGNER_INFO +#undef OCSP_REQUEST +#undef OCSP_RESPONSE +#endif + #include <schnlsp.h> #include <schannel.h> #include "curl_sspi.h" @@ -59,22 +83,87 @@ CURLcode Curl_verify_certificate(struct Curl_easy *data, /* structs to expose only in schannel.c and schannel_verify.c */ #ifdef EXPOSE_SCHANNEL_INTERNAL_STRUCTS +#include <wincrypt.h> + #ifdef __MINGW32__ -#include <_mingw.h> #ifdef __MINGW64_VERSION_MAJOR #define HAS_MANUAL_VERIFY_API #endif #else -#include <wincrypt.h> #ifdef CERT_CHAIN_REVOCATION_CHECK_CHAIN #define HAS_MANUAL_VERIFY_API #endif #endif +#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ + && !defined(DISABLE_SCHANNEL_CLIENT_CERT) +#define HAS_CLIENT_CERT_PATH +#endif + +#ifndef SCH_CREDENTIALS_VERSION + +#define SCH_CREDENTIALS_VERSION 0x00000005 + +typedef enum _eTlsAlgorithmUsage +{ + TlsParametersCngAlgUsageKeyExchange, + TlsParametersCngAlgUsageSignature, + TlsParametersCngAlgUsageCipher, + TlsParametersCngAlgUsageDigest, + TlsParametersCngAlgUsageCertSig +} eTlsAlgorithmUsage; + +typedef struct _CRYPTO_SETTINGS +{ + eTlsAlgorithmUsage eAlgorithmUsage; + UNICODE_STRING strCngAlgId; + DWORD cChainingModes; + PUNICODE_STRING rgstrChainingModes; + DWORD dwMinBitLength; + DWORD dwMaxBitLength; +} CRYPTO_SETTINGS, * PCRYPTO_SETTINGS; + +typedef struct _TLS_PARAMETERS +{ + DWORD cAlpnIds; + PUNICODE_STRING rgstrAlpnIds; + DWORD grbitDisabledProtocols; + DWORD cDisabledCrypto; + PCRYPTO_SETTINGS pDisabledCrypto; + DWORD dwFlags; +} TLS_PARAMETERS, * PTLS_PARAMETERS; + +typedef struct _SCH_CREDENTIALS +{ + DWORD dwVersion; + DWORD dwCredFormat; + DWORD cCreds; + PCCERT_CONTEXT* paCred; + HCERTSTORE hRootStore; + + DWORD cMappers; + struct _HMAPPER **aphMappers; + + DWORD dwSessionLifespan; + DWORD dwFlags; + DWORD cTlsParameters; + PTLS_PARAMETERS pTlsParameters; +} SCH_CREDENTIALS, * PSCH_CREDENTIALS; + +#define SCH_CRED_MAX_SUPPORTED_PARAMETERS 16 +#define SCH_CRED_MAX_SUPPORTED_ALPN_IDS 16 +#define SCH_CRED_MAX_SUPPORTED_CRYPTO_SETTINGS 16 +#define SCH_CRED_MAX_SUPPORTED_CHAINING_MODES 16 + +#endif + struct Curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; TCHAR *sni_hostname; +#ifdef HAS_CLIENT_CERT_PATH + HCERTSTORE client_cert_store; +#endif int refcount; }; @@ -99,6 +188,7 @@ struct ssl_backend_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ + bool recv_renegotiating; /* true if recv is doing renegotiation */ bool use_alpn; /* true if ALPN is used for this connection */ #ifdef HAS_MANUAL_VERIFY_API bool use_manual_cred_validation; /* true if manual cred validation is used */ diff --git a/Utilities/cmcurl/lib/vtls/schannel_verify.c b/Utilities/cmcurl/lib/vtls/schannel_verify.c index 4dc2d14..1ac1d3e 100644 --- a/Utilities/cmcurl/lib/vtls/schannel_verify.c +++ b/Utilities/cmcurl/lib/vtls/schannel_verify.c @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c index 2e57d83..c764e36 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.c +++ b/Utilities/cmcurl/lib/vtls/sectransp.c @@ -19,6 +19,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -2845,18 +2847,18 @@ sectransp_connect_step2(struct Curl_easy *data, struct connectdata *conn, #ifdef USE_HTTP2 if(chosenProtocol && !CFStringCompare(chosenProtocol, CFSTR(ALPN_H2), 0)) { - conn->negnpn = CURL_HTTP_VERSION_2; + conn->alpn = CURL_HTTP_VERSION_2; } else #endif if(chosenProtocol && !CFStringCompare(chosenProtocol, CFSTR(ALPN_HTTP_1_1), 0)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; + conn->alpn = CURL_HTTP_VERSION_1_1; } else infof(data, VTLS_INFOF_NO_ALPN); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); /* chosenProtocol is a reference to the string within alpnArr @@ -2964,7 +2966,7 @@ collect_server_cert(struct Curl_easy *data, private API and doesn't work as expected. So we have to look for a different symbol to make sure this code is only executed under Lion or later. */ - if(SecTrustEvaluateAsync) { + if(SecTrustCopyPublicKey) { #pragma unused(server_certs) err = SSLCopyPeerTrust(backend->ssl_ctx, &trust); /* For some reason, SSLCopyPeerTrust() can return noErr and yet return diff --git a/Utilities/cmcurl/lib/vtls/sectransp.h b/Utilities/cmcurl/lib/vtls/sectransp.h index 0febd66..2d53b7c 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.h +++ b/Utilities/cmcurl/lib/vtls/sectransp.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>. - * Copyright (C) 2012 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2012 - 2022, 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,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index e2d3438..9dee5aa 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* This file is for implementing all "generic" SSL functions that all libcurl @@ -143,11 +145,9 @@ Curl_ssl_config_matches(struct ssl_primary_config *data, Curl_safecmp(data->CAfile, needle->CAfile) && Curl_safecmp(data->issuercert, needle->issuercert) && Curl_safecmp(data->clientcert, needle->clientcert) && - Curl_safecmp(data->random_file, needle->random_file) && - Curl_safecmp(data->egdsocket, needle->egdsocket) && #ifdef USE_TLS_SRP - Curl_safecmp(data->username, needle->username) && - Curl_safecmp(data->password, needle->password) && + !Curl_timestrcmp(data->username, needle->username) && + !Curl_timestrcmp(data->password, needle->password) && (data->authtype == needle->authtype) && #endif Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list) && @@ -182,8 +182,6 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source, CLONE_STRING(CAfile); CLONE_STRING(issuercert); CLONE_STRING(clientcert); - CLONE_STRING(random_file); - CLONE_STRING(egdsocket); CLONE_STRING(cipher_list); CLONE_STRING(cipher_list13); CLONE_STRING(pinned_key); @@ -203,8 +201,6 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) Curl_safefree(sslc->CAfile); Curl_safefree(sslc->issuercert); Curl_safefree(sslc->clientcert); - Curl_safefree(sslc->random_file); - Curl_safefree(sslc->egdsocket); Curl_safefree(sslc->cipher_list); Curl_safefree(sslc->cipher_list13); Curl_safefree(sslc->pinned_key); @@ -223,13 +219,13 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc) static int multissl_setup(const struct Curl_ssl *backend); #endif -int Curl_ssl_backend(void) +curl_sslbackend Curl_ssl_backend(void) { #ifdef USE_SSL multissl_setup(NULL); return Curl_ssl->info.id; #else - return (int)CURLSSLBACKEND_NONE; + return CURLSSLBACKEND_NONE; #endif } @@ -903,7 +899,7 @@ char *Curl_ssl_snihost(struct Curl_easy *data, const char *host, size_t *olen) size_t len = strlen(host); if(len && (host[len-1] == '.')) len--; - if((long)len >= data->set.buffer_size) + if(len >= data->set.buffer_size) return NULL; Curl_strntolower(data->state.buffer, host, len); @@ -1460,8 +1456,10 @@ static int multissl_setup(const struct Curl_ssl *backend) return 0; } -CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail) +/* This function is used to select the SSL backend to use. It is called by + curl_global_sslset (easy.c) which uses the global init lock. */ +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) { int i; @@ -1490,8 +1488,8 @@ CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, } #else /* USE_SSL */ -CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, - const curl_ssl_backend ***avail) +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail) { (void)id; (void)name; diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h index 6bd1e0d..50c53b3 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.h +++ b/Utilities/cmcurl/lib/vtls/vtls.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -123,6 +125,9 @@ struct curl_slist *Curl_none_engines_list(struct Curl_easy *data); bool Curl_none_false_start(void); bool Curl_ssl_tls13_ciphersuites(void); +CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + #include "openssl.h" /* OpenSSL versions */ #include "gtls.h" /* GnuTLS versions */ #include "nssg.h" /* NSS versions */ @@ -195,7 +200,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc); ssl_connect_2_writing. */ int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks); -int Curl_ssl_backend(void); +curl_sslbackend Curl_ssl_backend(void); #ifdef USE_SSL int Curl_ssl_init(void); diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c index da8cb82..594c39a 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.c +++ b/Utilities/cmcurl/lib/vtls/wolfssl.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ /* @@ -503,7 +505,7 @@ wolfssl_connect_step1(struct Curl_easy *data, struct connectdata *conn, SSL_free(backend->handle); backend->handle = SSL_new(backend->ctx); if(!backend->handle) { - failf(data, "SSL: couldn't create a context"); + failf(data, "SSL: couldn't create a handle"); return CURLE_OUT_OF_MEMORY; } @@ -761,17 +763,17 @@ wolfssl_connect_step2(struct Curl_easy *data, struct connectdata *conn, 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; + conn->alpn = CURL_HTTP_VERSION_1_1; #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; + conn->alpn = CURL_HTTP_VERSION_2; #endif else infof(data, "ALPN, unrecognized protocol %.*s", protocol_len, protocol); - Curl_multiuse_state(data, conn->negnpn == CURL_HTTP_VERSION_2 ? + Curl_multiuse_state(data, conn->alpn == CURL_HTTP_VERSION_2 ? BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE); } else if(rc == SSL_ALPN_NOT_FOUND) @@ -809,8 +811,10 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, if(SSL_SET_OPTION(primary.sessionid)) { bool incache; + bool added = FALSE; void *old_ssl_sessionid = NULL; - SSL_SESSION *our_ssl_sessionid = SSL_get_session(backend->handle); + /* SSL_get1_session allocates memory that has to be freed. */ + SSL_SESSION *our_ssl_sessionid = SSL_get1_session(backend->handle); bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE; if(our_ssl_sessionid) { @@ -830,11 +834,20 @@ wolfssl_connect_step3(struct Curl_easy *data, struct connectdata *conn, 0, sockindex, NULL); if(result) { Curl_ssl_sessionid_unlock(data); + SSL_SESSION_free(our_ssl_sessionid); failf(data, "failed to store ssl session"); return result; } + else { + added = TRUE; + } } Curl_ssl_sessionid_unlock(data); + + if(!added) { + /* If the session info wasn't added to the cache, free our copy. */ + SSL_SESSION_free(our_ssl_sessionid); + } } } @@ -954,8 +967,7 @@ static ssize_t wolfssl_recv(struct Curl_easy *data, static void wolfssl_session_free(void *ptr) { - (void)ptr; - /* wolfSSL reuses sessions on own, no free */ + SSL_SESSION_free(ptr); } diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.h b/Utilities/cmcurl/lib/vtls/wolfssl.h index d411e69..b2e7c3f 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.h +++ b/Utilities/cmcurl/lib/vtls/wolfssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c index dfb9386..0cfcbe8 100644 --- a/Utilities/cmcurl/lib/vtls/x509asn1.c +++ b/Utilities/cmcurl/lib/vtls/x509asn1.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -43,6 +45,7 @@ #include <curl/curl.h> #include "urldata.h" #include "strcase.h" +#include "curl_ctype.h" #include "hostcheck.h" #include "vtls/vtls.h" #include "sendf.h" @@ -714,7 +717,7 @@ static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn) /* Encode delimiter. If attribute has a short uppercase name, delimiter is ", ". */ if(l) { - for(p3 = str; isupper(*p3); p3++) + for(p3 = str; ISUPPER(*p3); p3++) ; for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) { if(l < buflen) @@ -956,7 +959,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, infof(data, " ECC Public Key (%lu bits)", len); if(data->set.ssl.certinfo) { char q[sizeof(len) * 8 / 3 + 1]; - msnprintf(q, sizeof(q), "%lu", len); + (void)msnprintf(q, sizeof(q), "%lu", len); if(Curl_ssl_push_certinfo(data, certnum, "ECC Public Key", q)) return 1; } diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.h b/Utilities/cmcurl/lib/vtls/x509asn1.h index db7df0e..a18fa11 100644 --- a/Utilities/cmcurl/lib/vtls/x509asn1.h +++ b/Utilities/cmcurl/lib/vtls/x509asn1.h @@ -21,6 +21,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c index 0336a41..b00d7a5 100644 --- a/Utilities/cmcurl/lib/warnless.c +++ b/Utilities/cmcurl/lib/warnless.c @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" @@ -37,6 +39,8 @@ #include "warnless.h" +#include <limits.h> + #define CURL_MASK_UCHAR ((unsigned char)~0) #define CURL_MASK_SCHAR (CURL_MASK_UCHAR >> 1) diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h index 37ac5ba..4367099 100644 --- a/Utilities/cmcurl/lib/warnless.h +++ b/Utilities/cmcurl/lib/warnless.h @@ -20,6 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c index 105bcce..a3e24b6 100644 --- a/Utilities/cmcurl/lib/wildcard.c +++ b/Utilities/cmcurl/lib/wildcard.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2022, 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 @@ -18,6 +18,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" diff --git a/Utilities/cmcurl/lib/wildcard.h b/Utilities/cmcurl/lib/wildcard.h index 081be9e..21e933b 100644 --- a/Utilities/cmcurl/lib/wildcard.h +++ b/Utilities/cmcurl/lib/wildcard.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 2010 - 2022, 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,11 +20,14 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * + * SPDX-License-Identifier: curl + * ***************************************************************************/ #include "curl_setup.h" #ifndef CURL_DISABLE_FTP +#include <curl/curl.h> #include "llist.h" /* list of wildcard process states */ diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c new file mode 100644 index 0000000..a673446 --- /dev/null +++ b/Utilities/cmcurl/lib/ws.c @@ -0,0 +1,757 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, 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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" +#include <curl/curl.h> + +#ifdef USE_WEBSOCKETS + +#include "urldata.h" +#include "dynbuf.h" +#include "rand.h" +#include "curl_base64.h" +#include "sendf.h" +#include "multiif.h" +#include "ws.h" +#include "easyif.h" +#include "transfer.h" +#include "nonblock.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +struct wsfield { + const char *name; + const char *val; +}; + +CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req) +{ + unsigned int i; + CURLcode result = CURLE_OK; + unsigned char rand[16]; + char *randstr; + size_t randlen; + char keyval[40]; + struct SingleRequest *k = &data->req; + struct wsfield heads[]= { + { + /* The request MUST contain an |Upgrade| header field whose value + MUST include the "websocket" keyword. */ + "Upgrade:", "websocket" + }, + { + /* The request MUST contain a |Connection| header field whose value + MUST include the "Upgrade" token. */ + "Connection:", "Upgrade", + }, + { + /* The request MUST include a header field with the name + |Sec-WebSocket-Version|. The value of this header field MUST be + 13. */ + "Sec-WebSocket-Version:", "13", + }, + { + /* The request MUST include a header field with the name + |Sec-WebSocket-Key|. The value of this header field MUST be a nonce + consisting of a randomly selected 16-byte value that has been + base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be + selected randomly for each connection. */ + "Sec-WebSocket-Key:", NULL, + } + }; + heads[3].val = &keyval[0]; + + /* 16 bytes random */ + result = Curl_rand(data, (unsigned char *)rand, sizeof(rand)); + if(result) + return result; + result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen); + if(result) + return result; + DEBUGASSERT(randlen < sizeof(keyval)); + if(randlen >= sizeof(keyval)) + return CURLE_FAILED_INIT; + strcpy(keyval, randstr); + free(randstr); + for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) { + if(!Curl_checkheaders(data, STRCONST(heads[i].name))) { +#ifdef USE_HYPER + char field[128]; + msnprintf(field, sizeof(field), "%s %s", heads[i].name, + heads[i].val); + result = Curl_hyper_header(data, req, field); +#else + (void)data; + result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name, + heads[i].val); +#endif + } + } + k->upgr101 = UPGR101_WS; + Curl_dyn_init(&data->req.p.http->ws.buf, MAX_WS_SIZE * 2); + return result; +} + +CURLcode Curl_ws_accept(struct Curl_easy *data) +{ + struct SingleRequest *k = &data->req; + struct HTTP *ws = data->req.p.http; + struct connectdata *conn = data->conn; + struct websocket *wsp = &data->req.p.http->ws; + CURLcode result; + + /* Verify the Sec-WebSocket-Accept response. + + The sent value is the base64 encoded version of a SHA-1 hash done on the + |Sec-WebSocket-Key| header field concatenated with + the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11". + */ + + /* If the response includes a |Sec-WebSocket-Extensions| header field and + this header field indicates the use of an extension that was not present + in the client's handshake (the server has indicated an extension not + requested by the client), the client MUST Fail the WebSocket Connection. + */ + + /* If the response includes a |Sec-WebSocket-Protocol| header field + and this header field indicates the use of a subprotocol that was + not present in the client's handshake (the server has indicated a + subprotocol not requested by the client), the client MUST Fail + the WebSocket Connection. */ + + /* 4 bytes random */ + result = Curl_rand(data, (unsigned char *)&ws->ws.mask, sizeof(ws->ws.mask)); + if(result) + return result; + + infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x", + ws->ws.mask[0], ws->ws.mask[1], ws->ws.mask[2], ws->ws.mask[3]); + k->upgr101 = UPGR101_RECEIVED; + + if(data->set.connect_only) + /* switch off non-blocking sockets */ + (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE); + + wsp->oleft = 0; + return result; +} + +#define WSBIT_FIN 0x80 +#define WSBIT_OPCODE_CONT 0 +#define WSBIT_OPCODE_TEXT (1) +#define WSBIT_OPCODE_BIN (2) +#define WSBIT_OPCODE_CLOSE (8) +#define WSBIT_OPCODE_PING (9) +#define WSBIT_OPCODE_PONG (0xa) +#define WSBIT_OPCODE_MASK (0xf) + +#define WSBIT_MASK 0x80 + +/* remove the spent bytes from the beginning of the buffer as that part has + now been delivered to the application */ +static void ws_decode_clear(struct Curl_easy *data) +{ + struct websocket *wsp = &data->req.p.http->ws; + size_t spent = wsp->usedbuf; + size_t len = Curl_dyn_len(&wsp->buf); + size_t keep = len - spent; + DEBUGASSERT(len >= spent); + Curl_dyn_tail(&wsp->buf, keep); +} + +/* ws_decode() decodes a binary frame into structured WebSocket data, + + wpkt - the incoming raw data. If NULL, work on the already buffered data. + ilen - the size of the provided data, perhaps too little, perhaps too much + out - stored pointed to extracted data + olen - stored length of the extracted data + oleft - number of unread bytes pending to that belongs to this frame + more - if there is more data in there + flags - stored bitmask about the frame + + Returns CURLE_AGAIN if there is only a partial frame in the buffer. Then it + stores the first part in the ->extra buffer to be used in the next call + when more data is provided. +*/ + +static CURLcode ws_decode(struct Curl_easy *data, + unsigned char *wpkt, size_t ilen, + unsigned char **out, size_t *olen, + curl_off_t *oleft, + bool *more, + unsigned int *flags) +{ + bool fin; + unsigned char opcode; + curl_off_t total; + size_t dataindex = 2; + curl_off_t plen; /* size of data in the buffer */ + curl_off_t payloadsize; + struct websocket *wsp = &data->req.p.http->ws; + unsigned char *p; + CURLcode result; + + *olen = 0; + + /* add the incoming bytes, if any */ + if(wpkt) { + result = Curl_dyn_addn(&wsp->buf, wpkt, ilen); + if(result) + return result; + } + + plen = Curl_dyn_len(&wsp->buf); + if(plen < 2) { + /* the smallest possible frame is two bytes */ + infof(data, "WS: plen == %u, EAGAIN", (int)plen); + return CURLE_AGAIN; + } + + p = Curl_dyn_uptr(&wsp->buf); + + fin = p[0] & WSBIT_FIN; + opcode = p[0] & WSBIT_OPCODE_MASK; + infof(data, "WS:%d received FIN bit %u", __LINE__, (int)fin); + *flags = 0; + switch(opcode) { + case WSBIT_OPCODE_CONT: + if(!fin) + *flags |= CURLWS_CONT; + infof(data, "WS: received OPCODE CONT"); + break; + case WSBIT_OPCODE_TEXT: + infof(data, "WS: received OPCODE TEXT"); + *flags |= CURLWS_TEXT; + break; + case WSBIT_OPCODE_BIN: + infof(data, "WS: received OPCODE BINARY"); + *flags |= CURLWS_BINARY; + break; + case WSBIT_OPCODE_CLOSE: + infof(data, "WS: received OPCODE CLOSE"); + *flags |= CURLWS_CLOSE; + break; + case WSBIT_OPCODE_PING: + infof(data, "WS: received OPCODE PING"); + *flags |= CURLWS_PING; + break; + case WSBIT_OPCODE_PONG: + infof(data, "WS: received OPCODE PONG"); + *flags |= CURLWS_PONG; + break; + } + + if(p[1] & WSBIT_MASK) { + /* A client MUST close a connection if it detects a masked frame. */ + failf(data, "WS: masked input frame"); + return CURLE_RECV_ERROR; + } + payloadsize = p[1]; + if(payloadsize == 126) { + if(plen < 4) { + infof(data, "WS:%d plen == %u, EAGAIN", __LINE__, (int)plen); + return CURLE_AGAIN; /* not enough data available */ + } + payloadsize = (p[2] << 8) | p[3]; + dataindex += 2; + } + else if(payloadsize == 127) { + /* 64 bit payload size */ + if(plen < 10) + return CURLE_AGAIN; + if(p[2] & 80) { + failf(data, "WS: too large frame"); + return CURLE_RECV_ERROR; + } + dataindex += 8; + payloadsize = ((curl_off_t)p[2] << 56) | + (curl_off_t)p[3] << 48 | + (curl_off_t)p[4] << 40 | + (curl_off_t)p[5] << 32 | + (curl_off_t)p[6] << 24 | + (curl_off_t)p[7] << 16 | + (curl_off_t)p[8] << 8 | + p[9]; + } + + total = dataindex + payloadsize; + if(total > plen) { + /* deliver a partial frame */ + *oleft = total - dataindex; + payloadsize = total - dataindex; + } + else { + *oleft = 0; + if(plen > total) + /* there is another fragment after */ + *more = TRUE; + } + + /* point to the payload */ + *out = &p[dataindex]; + + /* return the payload length */ + *olen = payloadsize; + + /* number of bytes "used" from the buffer */ + wsp->usedbuf = dataindex + payloadsize; + infof(data, "WS: received %zu bytes payload (%zu left)", + payloadsize, *oleft); + return CURLE_OK; +} + +/* Curl_ws_writecb() is the write callback for websocket traffic. The + websocket data is provided to this raw, in chunks. This function should + handle/decode the data and call the "real" underlying callback accordingly. +*/ +size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */, + size_t nitems, void *userp) +{ + struct HTTP *ws = (struct HTTP *)userp; + struct Curl_easy *data = ws->ws.data; + void *writebody_ptr = data->set.out; + if(data->set.ws_raw_mode) + return data->set.fwrite_func(buffer, size, nitems, writebody_ptr); + else if(nitems) { + unsigned char *frame = NULL; + size_t flen = 0; + size_t wrote = 0; + CURLcode result; + bool more; /* there's is more to parse in the buffer */ + curl_off_t oleft; + + decode: + more = FALSE; + oleft = ws->ws.frame.bytesleft; + if(!oleft) { + unsigned int recvflags; + result = ws_decode(data, (unsigned char *)buffer, nitems, + &frame, &flen, &oleft, &more, &recvflags); + if(result == CURLE_AGAIN) + /* insufficient amount of data, keep it for later */ + return nitems; + else if(result) { + infof(data, "WS: decode error %d", (int)result); + return nitems - 1; + } + /* Store details about the frame to be reachable with curl_ws_meta() + from within the write callback */ + ws->ws.frame.age = 0; + ws->ws.frame.offset = 0; + ws->ws.frame.flags = recvflags; + ws->ws.frame.bytesleft = oleft; + } + else { + if(nitems > (size_t)ws->ws.frame.bytesleft) { + nitems = ws->ws.frame.bytesleft; + more = TRUE; + } + else + more = FALSE; + ws->ws.frame.offset += nitems; + ws->ws.frame.bytesleft -= nitems; + frame = (unsigned char *)buffer; + flen = nitems; + } + if((ws->ws.frame.flags & CURLWS_PING) && !oleft) { + /* auto-respond to PINGs, only works for single-frame payloads atm */ + size_t bytes; + infof(data, "WS: auto-respond to PING with a PONG"); + DEBUGASSERT(frame); + /* send back the exact same content as a PONG */ + result = curl_ws_send(data, frame, flen, &bytes, 0, CURLWS_PONG); + if(result) + return result; + } + else { + /* deliver the decoded frame to the user callback */ + Curl_set_in_callback(data, true); + wrote = data->set.fwrite_func((char *)frame, 1, flen, writebody_ptr); + Curl_set_in_callback(data, false); + if(wrote != flen) + return 0; + } + if(oleft) + ws->ws.frame.offset += flen; + /* the websocket frame has been delivered */ + ws_decode_clear(data); + if(more) { + /* there's more websocket data to deal with in the buffer */ + buffer = NULL; /* the buffer as been drained already */ + goto decode; + } + } + return nitems; +} + + +CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer, + size_t buflen, size_t *nread, + struct curl_ws_frame **metap) +{ + size_t bytes; + CURLcode result; + struct websocket *wsp = &data->req.p.http->ws; + + *nread = 0; + *metap = NULL; + /* get a download buffer */ + result = Curl_preconnect(data); + if(result) + return result; + + do { + bool drain = FALSE; /* if there is pending buffered data to drain */ + char *inbuf = data->state.buffer; + bytes = wsp->stillbuffer; + if(!bytes) { + result = curl_easy_recv(data, data->state.buffer, + data->set.buffer_size, &bytes); + if(result) + return result; + } + else { + /* the pending bytes can be found here */ + inbuf = wsp->stillb; + drain = TRUE; + } + if(bytes) { + unsigned char *out; + size_t olen; + bool more; + unsigned int recvflags; + curl_off_t oleft = wsp->frame.bytesleft; + + infof(data, "WS: got %u websocket bytes to decode", (int)bytes); + if(!oleft && !drain) { + result = ws_decode(data, (unsigned char *)inbuf, bytes, + &out, &olen, &oleft, &more, &recvflags); + if(result == CURLE_AGAIN) + /* a packet fragment only */ + break; + else if(result) + return result; + wsp->frame.offset = 0; + wsp->frame.bytesleft = oleft; + wsp->frame.flags = recvflags; + } + else { + olen = oleft; + out = (unsigned char *)wsp->stillb; + recvflags = wsp->frame.flags; + if((curl_off_t)buflen < oleft) + /* there is still data left after this */ + wsp->frame.bytesleft -= buflen; + else + wsp->frame.bytesleft = 0; + } + + /* auto-respond to PINGs */ + if((recvflags & CURLWS_PING) && !oleft) { + infof(data, "WS: auto-respond to PING with a PONG"); + /* send back the exact same content as a PONG */ + result = curl_ws_send(data, out, olen, &bytes, 0, CURLWS_PONG); + if(result) + return result; + } + else { + if(olen < buflen) { + /* copy the payload to the user buffer */ + memcpy(buffer, out, olen); + *nread = olen; + if(!oleft) + /* websocket frame has been delivered */ + ws_decode_clear(data); + } + else { + /* copy a partial payload */ + memcpy(buffer, out, buflen); + *nread = buflen; + /* remember what is left and where */ + wsp->stillbuffer = olen - buflen; + wsp->stillb = (char *)buffer + buflen; + } + wsp->frame.offset += *nread; + } + } + else + *nread = bytes; + break; + } while(1); + *metap = &wsp->frame; + return CURLE_OK; +} + +static void ws_xor(struct Curl_easy *data, + const unsigned char *source, + unsigned char *dest, + size_t len) +{ + struct websocket *wsp = &data->req.p.http->ws; + size_t i; + /* append payload after the mask, XOR appropriately */ + for(i = 0; i < len; i++) { + dest[i] = source[i] ^ wsp->mask[wsp->xori]; + wsp->xori++; + wsp->xori &= 3; + } +} + +/*** + RFC 6455 Section 5.2 + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ +*/ + +static size_t ws_packethead(struct Curl_easy *data, + size_t len, unsigned int flags) +{ + struct HTTP *ws = data->req.p.http; + unsigned char *out = (unsigned char *)data->state.ulbuf; + unsigned char firstbyte = 0; + int outi; + unsigned char opcode; + if(flags & CURLWS_TEXT) { + opcode = WSBIT_OPCODE_TEXT; + infof(data, "WS: send OPCODE TEXT"); + } + else if(flags & CURLWS_CLOSE) { + opcode = WSBIT_OPCODE_CLOSE; + infof(data, "WS: send OPCODE CLOSE"); + } + else if(flags & CURLWS_PING) { + opcode = WSBIT_OPCODE_PING; + infof(data, "WS: send OPCODE PING"); + } + else if(flags & CURLWS_PONG) { + opcode = WSBIT_OPCODE_PONG; + infof(data, "WS: send OPCODE PONG"); + } + else { + opcode = WSBIT_OPCODE_BIN; + infof(data, "WS: send OPCODE BINARY"); + } + + if(!(flags & CURLWS_CONT)) { + /* if not marked as continuing, assume this is the final fragment */ + firstbyte |= WSBIT_FIN | opcode; + ws->ws.contfragment = FALSE; + } + else if(ws->ws.contfragment) { + /* the previous fragment was not a final one and this isn't either, keep a + CONT opcode and no FIN bit */ + firstbyte |= WSBIT_OPCODE_CONT; + } + else { + ws->ws.contfragment = TRUE; + } + out[0] = firstbyte; + if(len > 65535) { + out[1] = 127 | WSBIT_MASK; + out[2] = (len >> 8) & 0xff; + out[3] = len & 0xff; + outi = 10; + } + else if(len > 126) { + out[1] = 126 | WSBIT_MASK; + out[2] = (len >> 8) & 0xff; + out[3] = len & 0xff; + outi = 4; + } + else { + out[1] = (unsigned char)len | WSBIT_MASK; + outi = 2; + } + + infof(data, "WS: send FIN bit %u (byte %02x)", + firstbyte & WSBIT_FIN ? 1 : 0, + firstbyte); + infof(data, "WS: send payload len %u", (int)len); + + /* 4 bytes mask */ + memcpy(&out[outi], &ws->ws.mask, 4); + + if(data->set.upload_buffer_size < (len + 10)) + return 0; + + /* pass over the mask */ + outi += 4; + + ws->ws.xori = 0; + /* return packet size */ + return outi; +} + +CURL_EXTERN CURLcode curl_ws_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t totalsize, + unsigned int sendflags) +{ + CURLcode result; + size_t headlen; + char *out; + ssize_t written; + struct websocket *wsp = &data->req.p.http->ws; + + if(!data->set.ws_raw_mode) { + result = Curl_get_upload_buffer(data); + if(result) + return result; + } + else { + if(totalsize || sendflags) + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + if(data->set.ws_raw_mode) { + if(!buflen) + /* nothing to do */ + return CURLE_OK; + /* raw mode sends exactly what was requested, and this is from within + the write callback */ + if(Curl_is_in_callback(data)) + result = Curl_write(data, data->conn->writesockfd, buffer, buflen, + &written); + else + result = Curl_senddata(data, buffer, buflen, &written); + + infof(data, "WS: wanted to send %zu bytes, sent %zu bytes", + buflen, written); + *sent = written; + return result; + } + + if(buflen > (data->set.upload_buffer_size - 10)) + /* don't do more than this in one go */ + buflen = data->set.upload_buffer_size - 10; + + if(sendflags & CURLWS_OFFSET) { + if(totalsize) { + /* a frame series 'totalsize' bytes big, this is the first */ + headlen = ws_packethead(data, totalsize, sendflags); + wsp->sleft = totalsize - buflen; + } + else { + headlen = 0; + if((curl_off_t)buflen > wsp->sleft) { + infof(data, "WS: unaligned frame size (sending %zu instead of %zu)", + buflen, wsp->sleft); + wsp->sleft = 0; + } + else + wsp->sleft -= buflen; + } + } + else + headlen = ws_packethead(data, buflen, sendflags); + + /* headlen is the size of the frame header */ + out = data->state.ulbuf; + if(buflen) + /* for PING and PONG etc there might not be a payload */ + ws_xor(data, buffer, (unsigned char *)out + headlen, buflen); + + if(data->set.connect_only) + result = Curl_senddata(data, out, buflen + headlen, &written); + else + result = Curl_write(data, data->conn->writesockfd, out, + buflen + headlen, &written); + + infof(data, "WS: wanted to send %zu bytes, sent %zu bytes", + headlen + buflen, written); + *sent = written; + + return result; +} + +void Curl_ws_done(struct Curl_easy *data) +{ + struct websocket *wsp = &data->req.p.http->ws; + DEBUGASSERT(wsp); + Curl_dyn_free(&wsp->buf); +} + +CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +{ + /* we only return something for websocket, called from within the callback + when not using raw mode */ + if(GOOD_EASY_HANDLE(data) && Curl_is_in_callback(data) && data->req.p.http && + !data->set.ws_raw_mode) + return &data->req.p.http->ws.frame; + return NULL; +} + +#else + +CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, + size_t *nread, + struct curl_ws_frame **metap) +{ + (void)curl; + (void)buffer; + (void)buflen; + (void)nread; + (void)metap; + return CURLE_OK; +} + +CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, + size_t buflen, size_t *sent, + curl_off_t framesize, + unsigned int sendflags) +{ + (void)curl; + (void)buffer; + (void)buflen; + (void)sent; + (void)framesize; + (void)sendflags; + return CURLE_OK; +} + +CURL_EXTERN struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data) +{ + (void)data; + return NULL; +} +#endif /* USE_WEBSOCKETS */ diff --git a/Utilities/cmcurl/lib/ws.h b/Utilities/cmcurl/lib/ws.h new file mode 100644 index 0000000..341242e --- /dev/null +++ b/Utilities/cmcurl/lib/ws.h @@ -0,0 +1,69 @@ +#ifndef HEADER_CURL_WS_H +#define HEADER_CURL_WS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2022, 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. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#ifdef USE_WEBSOCKETS + +#ifdef USE_HYPER +#define REQTYPE void +#else +#define REQTYPE struct dynbuf +#endif + +/* this is the largest single fragment size we support */ +#define MAX_WS_SIZE 65535 + +/* part of 'struct HTTP', when used in the 'struct SingleRequest' in the + Curl_easy struct */ +struct websocket { + bool contfragment; /* set TRUE if the previous fragment sent was not final */ + unsigned char mask[4]; /* 32 bit mask for this connection */ + struct Curl_easy *data; /* used for write callback handling */ + struct dynbuf buf; + size_t usedbuf; /* number of leading bytes in 'buf' the most recent complete + websocket frame uses */ + struct curl_ws_frame frame; /* the struct used for frame state */ + curl_off_t oleft; /* outstanding number of payload bytes left from the + server */ + curl_off_t stillbuffer; /* number of bytes left in the buffer to deliver in + the next curl_ws_recv() call */ + char *stillb; /* the stillbuffer pending bytes are here */ + curl_off_t sleft; /* outstanding number of payload bytes left to send */ + unsigned int xori; /* xor index */ +}; + +CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req); +CURLcode Curl_ws_accept(struct Curl_easy *data); + +size_t Curl_ws_writecb(char *buffer, size_t size, size_t nitems, void *userp); +void Curl_ws_done(struct Curl_easy *data); + +#else +#define Curl_ws_request(x,y) CURLE_OK +#define Curl_ws_done(x) Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_WS_H */ |