diff --git a/project/jni/curl/Android.mk b/project/jni/curl/Android.mk index 1fe42b5a5..308fde0db 100644 --- a/project/jni/curl/Android.mk +++ b/project/jni/curl/Android.mk @@ -69,14 +69,14 @@ CURL_HEADERS := \ typecheck-gcc.h LOCAL_SRC_FILES := $(addprefix lib/,$(CSOURCES)) -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/include/curl $(LOCAL_PATH)/lib $(LOCAL_PATH)/../boringssl/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/include/curl $(LOCAL_PATH)/lib $(LOCAL_PATH)/../openssl/include LOCAL_CFLAGS += $(common_CFLAGS) LOCAL_MODULE:= libcurl -LOCAL_SHARED_LIBRARIES := +LOCAL_SHARED_LIBRARIES := ssl crypto -LOCAL_STATIC_LIBRARIES := ssl crypto +#LOCAL_STATIC_LIBRARIES := ssl crypto LOCAL_LDLIBS := -lz diff --git a/project/jni/curl/include/README b/project/jni/curl/include/README index 3e52a1d0a..f0b3b9393 100644 --- a/project/jni/curl/include/README +++ b/project/jni/curl/include/README @@ -4,52 +4,46 @@ | (__| |_| | _ <| |___ \___|\___/|_| \_\_____| -Include files for libcurl, external users. +README -They're all placed in the curl subdirectory here for better fit in any kind -of environment. You must include files from here using... + Curl is a command line tool for transferring data specified with URL + syntax. Find out how to use curl by reading the curl.1 man page or the + MANUAL document. Find out how to install Curl by reading the INSTALL + document. - #include + libcurl is the library curl is using to do its job. It is readily + available to be used by your software. Read the libcurl.3 man page to + learn how! -... style and point the compiler's include path to the directory holding the -curl subdirectory. It makes it more likely to survive future modifications. + You find answers to the most frequent questions we get in the FAQ document. -NOTE FOR LIBCURL HACKERS + Study the COPYING file for distribution terms and similar. If you distribute + curl binaries or other binaries that involve libcurl, you might enjoy the + LICENSE-MIXING document. -The following notes apply to libcurl version 7.19.0 and later. +CONTACT -* The distributed curl/curlbuild.h file is only intended to be used on systems - which can not run the also distributed configure script. + If you have problems, questions, ideas or suggestions, please contact us + by posting to a suitable mailing list. See https://curl.haxx.se/mail/ -* The distributed curlbuild.h file is generated as a copy of curlbuild.h.dist - when the libcurl source code distribution archive file is originally created. + All contributors to the project are listed in the THANKS document. -* If you check out from git on a non-configure platform, you must run the - appropriate buildconf* script to set up curlbuild.h and other local files - before being able of compiling the library. +WEB SITE -* On systems capable of running the configure script, the configure process - will overwrite the distributed include/curl/curlbuild.h file with one that - is suitable and specific to the library being configured and built, which - is generated from the include/curl/curlbuild.h.in template file. + Visit the curl web site for the latest news and downloads: -* If you intend to distribute an already compiled libcurl library you _MUST_ - also distribute along with it the generated curl/curlbuild.h which has been - used to compile it. Otherwise the library will be of no use for the users of - the library that you have built. It is _your_ responsibility to provide this - file. No one at the cURL project can know how you have built the library. + https://curl.haxx.se/ -* File curl/curlbuild.h includes platform and configuration dependent info, - and must not be modified by anyone. Configure script generates it for you. +GIT -* We cannot assume anything else but very basic compiler features being - present. While libcurl requires an ANSI C compiler to build, some of the - earlier ANSI compilers clearly can't deal with some preprocessor operators. + To download the very latest source off the GIT server do this: -* Newlines must remain unix-style for older compilers' sake. + git clone https://github.com/curl/curl.git -* Comments must be written in the old-style /* unnested C-fashion */ + (you'll get a directory named curl created, filled with the source code) -To figure out how to do good and portable checks for features, operating -systems or specific hardwarare, a very good resource is Bjorn Reese's -collection at http://predef.sf.net/ +NOTICE + + Curl contains pieces of source code that is Copyright (c) 1998, 1999 + Kungliga Tekniska Högskolan. This notice is included here to comply with the + distribution terms. diff --git a/project/jni/curl/include/curl/curl.h b/project/jni/curl/include/curl/curl.h index e0d5c0f4e..57e716b3e 100644 --- a/project/jni/curl/include/curl/curl.h +++ b/project/jni/curl/include/curl/curl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -373,6 +373,7 @@ typedef curlioerr (*curl_ioctl_callback)(CURL *handle, int cmd, void *clientp); +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* * The following typedef's are signatures of malloc, free, realloc, strdup and * calloc respectively. Function pointers of these types can be passed to the @@ -385,6 +386,9 @@ typedef void *(*curl_realloc_callback)(void *ptr, size_t size); typedef char *(*curl_strdup_callback)(const char *str); typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + /* the kind of data that is passed to information_callback*/ typedef enum { CURLINFO_TEXT = 0, @@ -471,9 +475,9 @@ typedef enum { CURLE_OBSOLETE44, /* 44 - NOT USED */ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ CURLE_OBSOLETE46, /* 46 - NOT USED */ - CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ - CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ CURLE_OBSOLETE50, /* 50 - NOT USED */ CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint wasn't verified fine */ @@ -535,6 +539,8 @@ typedef enum { CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not match */ CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ CURL_LAST /* never use! */ } CURLcode; @@ -1460,7 +1466,7 @@ typedef enum { CINIT(TFTP_BLKSIZE, LONG, 178), /* Socks Service */ - CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ /* Socks Service */ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), @@ -1676,6 +1682,13 @@ typedef enum { /* Do not send any tftp option requests to the server */ CINIT(TFTP_NO_OPTIONS, LONG, 242), + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1727,6 +1740,8 @@ enum { CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ }; @@ -2110,6 +2125,11 @@ typedef enum { CURLSSLBACKEND_MBEDTLS = 11 } curl_sslbackend; +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL 1 +#define CURLSSLBACKEND_BORINGSSL 1 +#define CURLSSLBACKEND_WOLFSSL 6 + /* Information about the SSL library used and the respective internal SSL handle, which can be used to obtain further information regarding the connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ diff --git a/project/jni/curl/include/curl/curlbuild.h b/project/jni/curl/include/curl/curlbuild.h index d7ab0be3e..d36ca98d7 100644 --- a/project/jni/curl/include/curl/curlbuild.h +++ b/project/jni/curl/include/curl/curlbuild.h @@ -8,11 +8,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.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 @@ -36,7 +36,7 @@ * * If you think that something actually needs to be changed, adjusted * or fixed in this file, then, report it on the libcurl development - * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ + * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/ * * This header file shall only export symbols which are 'curl' or 'CURL' * prefixed, otherwise public name space would be polluted. @@ -59,52 +59,52 @@ /* ================================================================ */ #ifdef CURL_SIZEOF_LONG -# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" +#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined #endif #ifdef CURL_TYPEOF_CURL_SOCKLEN_T -# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" +#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined #endif #ifdef CURL_SIZEOF_CURL_SOCKLEN_T -# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" +#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined #endif #ifdef CURL_TYPEOF_CURL_OFF_T -# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" +#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined #endif #ifdef CURL_FORMAT_CURL_OFF_T -# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" +#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined #endif #ifdef CURL_FORMAT_CURL_OFF_TU -# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" +#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined #endif #ifdef CURL_FORMAT_OFF_T -# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" +#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined #endif #ifdef CURL_SIZEOF_CURL_OFF_T -# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" +#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined #endif #ifdef CURL_SUFFIX_CURL_OFF_T -# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" +#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined #endif #ifdef CURL_SUFFIX_CURL_OFF_TU -# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" +#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined #endif @@ -133,14 +133,14 @@ /* Configure process defines this to 1 when it finds out that system */ /* header file stdint.h must be included by the external interface. */ -#define CURL_PULL_STDINT_H 1 +/* #undef CURL_PULL_STDINT_H */ #ifdef CURL_PULL_STDINT_H # include #endif /* Configure process defines this to 1 when it finds out that system */ /* header file inttypes.h must be included by the external interface. */ -#define CURL_PULL_INTTYPES_H 1 +/* #undef CURL_PULL_INTTYPES_H */ #ifdef CURL_PULL_INTTYPES_H # include #endif @@ -152,6 +152,13 @@ # include #endif +/* Configure process defines this to 1 when it finds out that system */ +/* header file sys/poll.h must be included by the external interface. */ +/* #undef CURL_PULL_SYS_POLL_H */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + /* The size of `long', as computed by sizeof. */ #ifdef __LP64__ #define CURL_SIZEOF_LONG 8 @@ -169,27 +176,27 @@ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; /* Signed integral data type used for curl_off_t. */ -#define CURL_TYPEOF_CURL_OFF_T int64_t +#define CURL_TYPEOF_CURL_OFF_T long /* Data type definition of curl_off_t. */ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; /* curl_off_t formatting string directive without "%" conversion specifier. */ -#define CURL_FORMAT_CURL_OFF_T "lld" +#define CURL_FORMAT_CURL_OFF_T "ld" /* unsigned curl_off_t formatting string without "%" conversion specifier. */ -#define CURL_FORMAT_CURL_OFF_TU "llu" +#define CURL_FORMAT_CURL_OFF_TU "lu" /* curl_off_t formatting string directive with "%" conversion specifier. */ -#define CURL_FORMAT_OFF_T "%lld" +#define CURL_FORMAT_OFF_T "%ld" /* The size of `curl_off_t', as computed by sizeof. */ -#define CURL_SIZEOF_CURL_OFF_T 8 +#define CURL_SIZEOF_CURL_OFF_T CURL_SIZEOF_LONG /* curl_off_t constant suffix. */ -#define CURL_SUFFIX_CURL_OFF_T LL +#define CURL_SUFFIX_CURL_OFF_T L /* unsigned curl_off_t constant suffix. */ -#define CURL_SUFFIX_CURL_OFF_TU ULL +#define CURL_SUFFIX_CURL_OFF_TU UL #endif /* __CURL_CURLBUILD_H */ diff --git a/project/jni/curl/include/curl/curlver.h b/project/jni/curl/include/curl/curlver.h index 18c10fe1e..03cdf7ddd 100644 --- a/project/jni/curl/include/curl/curlver.h +++ b/project/jni/curl/include/curl/curlver.h @@ -30,12 +30,12 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.48.0" +#define LIBCURL_VERSION "7.49.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 48 +#define LIBCURL_VERSION_MINOR 49 #define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier @@ -57,7 +57,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x073000 +#define LIBCURL_VERSION_NUM 0x073100 /* * This is the date and time when the full source package was created. The @@ -68,7 +68,7 @@ * * "Mon Feb 12 11:35:33 UTC 2007" */ -#define LIBCURL_TIMESTAMP "Wed Mar 23 06:57:50 UTC 2016" +#define LIBCURL_TIMESTAMP "Wed May 18 05:59:55 UTC 2016" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) #define CURL_AT_LEAST_VERSION(x,y,z) \ diff --git a/project/jni/curl/include/curl/mprintf.h b/project/jni/curl/include/curl/mprintf.h index de8c96248..e20f546e1 100644 --- a/project/jni/curl/include/curl/mprintf.h +++ b/project/jni/curl/include/curl/mprintf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,8 +24,7 @@ #include #include /* needed for FILE */ - -#include "curl.h" +#include "curl.h" /* for CURL_EXTERN */ #ifdef __cplusplus extern "C" { @@ -44,29 +43,6 @@ CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, CURL_EXTERN char *curl_maprintf(const char *format, ...); CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); -#ifdef _MPRINTF_REPLACE -# undef printf -# undef fprintf -# undef sprintf -# undef vsprintf -# undef snprintf -# undef vprintf -# undef vfprintf -# undef vsnprintf -# undef aprintf -# undef vaprintf -# define printf curl_mprintf -# define fprintf curl_mfprintf -# define sprintf curl_msprintf -# define vsprintf curl_mvsprintf -# define snprintf curl_msnprintf -# define vprintf curl_mvprintf -# define vfprintf curl_mvfprintf -# define vsnprintf curl_mvsnprintf -# define aprintf curl_maprintf -# define vaprintf curl_mvaprintf -#endif - #ifdef __cplusplus } #endif diff --git a/project/jni/curl/lib/Makefile.inc b/project/jni/curl/lib/Makefile.inc index 39884d0b1..b573e932e 100644 --- a/project/jni/curl/lib/Makefile.inc +++ b/project/jni/curl/lib/Makefile.inc @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -20,6 +20,13 @@ # ########################################################################### +LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \ + vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \ + vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \ + vauth/spnego_gssapi.c vauth/spnego_sspi.c + +LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h + LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \ vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \ vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c \ @@ -43,12 +50,10 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ - http_negotiate_sspi.c http_proxy.c non-ascii.c asyn-ares.c \ - asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ - curl_ntlm_core.c curl_ntlm_msgs.c curl_sasl.c curl_multibyte.c \ - hostcheck.c conncache.c pipeline.c dotdot.c x509asn1.c \ - http2.c curl_sasl_sspi.c smb.c curl_sasl_gssapi.c curl_endian.c \ - curl_des.c + http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ + http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c \ + curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ + x509asn1.c http2.c smb.c curl_endian.c curl_des.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -63,13 +68,13 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ - curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ - curl_ntlm_msgs.h curl_sasl.h curl_multibyte.h hostcheck.h \ - conncache.h curl_setup_once.h multihandle.h setup-vms.h pipeline.h \ - dotdot.h x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ + http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \ + curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ + curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ + x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ curl_printf.h LIB_RCFILES = libcurl.rc -CSOURCES = $(LIB_CFILES) $(LIB_VTLS_CFILES) -HHEADERS = $(LIB_HFILES) $(LIB_VTLS_HFILES) +CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES) +HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES) diff --git a/project/jni/curl/lib/amigaos.c b/project/jni/curl/lib/amigaos.c index e2fe35d1f..5591d2220 100644 --- a/project/jni/curl/lib/amigaos.c +++ b/project/jni/curl/lib/amigaos.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,7 +35,7 @@ extern int errno, h_errno; #include void __request(const char *msg); #else -# define __request( msg ) Printf( msg "\n\a") +# define __request(msg) Printf(msg "\n\a") #endif void Curl_amiga_cleanup() diff --git a/project/jni/curl/lib/asyn-ares.c b/project/jni/curl/lib/asyn-ares.c index adb1a238a..51f61dee1 100644 --- a/project/jni/curl/lib/asyn-ares.c +++ b/project/jni/curl/lib/asyn-ares.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -68,7 +68,6 @@ #include "connect.h" #include "select.h" #include "progress.h" -#include "curl_printf.h" # if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) @@ -83,8 +82,9 @@ #define HAVE_CARES_CALLBACK_TIMEOUTS 1 #endif +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" struct ResolverResults { diff --git a/project/jni/curl/lib/asyn-thread.c b/project/jni/curl/lib/asyn-thread.c index 83ce0ce4e..81caedb09 100644 --- a/project/jni/curl/lib/asyn-thread.c +++ b/project/jni/curl/lib/asyn-thread.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,10 +69,9 @@ #include "inet_ntop.h" #include "curl_threads.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" - -/* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** diff --git a/project/jni/curl/lib/base64.c b/project/jni/curl/lib/base64.c index 9bb7de495..0ef24d51f 100644 --- a/project/jni/curl/lib/base64.c +++ b/project/jni/curl/lib/base64.c @@ -23,13 +23,13 @@ /* Base64 encoding/decoding */ #include "curl_setup.h" -#include "curl_printf.h" #include "urldata.h" /* for the SessionHandle definition */ #include "warnless.h" #include "curl_base64.h" #include "non-ascii.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" @@ -246,7 +246,7 @@ static CURLcode base64_encode(const char *table64, table64[obuf[0]], table64[obuf[1]], table64[obuf[2]], - table64[obuf[3]] ); + table64[obuf[3]]); break; } output += 4; diff --git a/project/jni/curl/lib/conncache.c b/project/jni/curl/lib/conncache.c index 6e03caf3c..d0c09c826 100644 --- a/project/jni/curl/lib/conncache.c +++ b/project/jni/curl/lib/conncache.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012, Linus Nielsen Feltzing, + * Copyright (C) 2012, 2016, Linus Nielsen Feltzing, * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which @@ -32,10 +32,9 @@ #include "sendf.h" #include "rawstr.h" #include "conncache.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" static void conn_llist_dtor(void *user, void *element) @@ -132,9 +131,16 @@ void Curl_conncache_destroy(struct conncache *connc) /* returns an allocated key to find a bundle for this connection */ static char *hashkey(struct connectdata *conn) { - return aprintf("%s:%d", - conn->bits.proxy?conn->proxy.name:conn->host.name, - conn->localport); + const char *hostname; + + if(conn->bits.proxy) + hostname = conn->proxy.name; + else if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + + return aprintf("%s:%d", hostname, conn->port); } /* Look up the bundle with all the connections to the same host this diff --git a/project/jni/curl/lib/connect.c b/project/jni/curl/lib/connect.c index 567186a69..ac2f26833 100644 --- a/project/jni/curl/lib/connect.c +++ b/project/jni/curl/lib/connect.c @@ -56,7 +56,6 @@ #include #endif -#include "curl_printf.h" #include "urldata.h" #include "sendf.h" #include "if2ip.h" @@ -74,7 +73,8 @@ #include "conncache.h" #include "multihandle.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" @@ -668,7 +668,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) /* there's no connection! */ return; - if(!conn->bits.reuse) { + if(!conn->bits.reuse && !conn->bits.tcp_fastopen) { int error; len = sizeof(struct Curl_sockaddr_storage); @@ -764,6 +764,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); if(rc == 0) { /* no connection yet */ + error = 0; if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) { infof(data, "After %ldms connect time, move on!\n", conn->timeoutms_per_addr); @@ -776,7 +777,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, trynextip(conn, sockindex, 1); } } - else if(rc == CURL_CSELECT_OUT) { + else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) { if(verifyconnect(conn->tempsock[i], &error)) { /* we are connected with TCP, awesome! */ @@ -841,6 +842,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, if(result) { /* no more addresses to try */ + const char* hostname; + /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ if(conn->tempaddr[1] == NULL) { @@ -849,9 +852,15 @@ CURLcode Curl_is_connected(struct connectdata *conn, return result; } + if(conn->bits.proxy) + hostname = conn->proxy.name; + else if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + failf(data, "Failed to connect to %s port %ld: %s", - conn->bits.proxy?conn->proxy.name:conn->host.name, - conn->port, Curl_strerror(conn, error)); + hostname, conn->port, Curl_strerror(conn, error)); } return result; @@ -1000,7 +1009,7 @@ static CURLcode singleipconnect(struct connectdata *conn, curl_socket_t *sockp) { struct Curl_sockaddr_ex addr; - int rc; + int rc = -1; int error = 0; bool isconnected = FALSE; struct SessionHandle *data = conn->data; @@ -1089,7 +1098,26 @@ static CURLcode singleipconnect(struct connectdata *conn, /* Connect TCP sockets, bind UDP */ if(!isconnected && (conn->socktype == SOCK_STREAM)) { - rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + if(conn->bits.tcp_fastopen) { +#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */ + sa_endpoints_t endpoints; + endpoints.sae_srcif = 0; + endpoints.sae_srcaddr = NULL; + endpoints.sae_srcaddrlen = 0; + endpoints.sae_dstaddr = &addr.sa_addr; + endpoints.sae_dstaddrlen = addr.addrlen; + + rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, + CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, + NULL, 0, NULL, NULL); +#elif defined(MSG_FASTOPEN) /* Linux */ + rc = 0; /* Do nothing */ +#endif + } + else { + rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + } + if(-1 == rc) error = SOCKERRNO; } diff --git a/project/jni/curl/lib/cookie.c b/project/jni/curl/lib/cookie.c index 1f2239242..01ce270bb 100644 --- a/project/jni/curl/lib/cookie.c +++ b/project/jni/curl/lib/cookie.c @@ -88,7 +88,6 @@ Example set of cookies: # include #endif -#include "curl_printf.h" #include "urldata.h" #include "cookie.h" #include "strequal.h" @@ -101,7 +100,8 @@ Example set of cookies: #include "curl_memrchr.h" #include "inet_pton.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/project/jni/curl/lib/curl_addrinfo.c b/project/jni/curl/lib/curl_addrinfo.c index cc60ddb66..8fa0c84cc 100644 --- a/project/jni/curl/lib/curl_addrinfo.c +++ b/project/jni/curl/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -50,10 +50,9 @@ #include "curl_addrinfo.h" #include "inet_pton.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" - -/* The last #include file should be: */ #include "memdebug.h" /* diff --git a/project/jni/curl/lib/curl_config.h b/project/jni/curl/lib/curl_config.h index 20282d649..af67786ed 100644 --- a/project/jni/curl/lib/curl_config.h +++ b/project/jni/curl/lib/curl_config.h @@ -1,9 +1,6 @@ /* lib/curl_config.h. Generated from curl_config.h.in by configure. */ /* lib/curl_config.h.in. Generated from configure.ac by autoheader. */ -/* when building libcurl itself */ -/* #undef BUILDING_LIBCURL */ - /* Location of default ca bundle */ #define CURL_CA_BUNDLE "ca-certificates.crt" @@ -52,6 +49,9 @@ /* to disable RTSP */ #define CURL_DISABLE_RTSP 1 +/* to disable SMB/CIFS */ +#define CURL_DISABLE_SMB 1 + /* to disable SMTP */ #define CURL_DISABLE_SMTP 1 @@ -61,27 +61,24 @@ /* to disable TFTP */ #define CURL_DISABLE_TFTP 1 +/* to disable TLS-SRP authentication */ +#define CURL_DISABLE_TLS_SRP 1 + /* to disable verbose strings */ /* #undef CURL_DISABLE_VERBOSE_STRINGS */ -/* to make a symbol visible */ +/* Definition to make a library symbol externally visible. */ #define CURL_EXTERN_SYMBOL __attribute__ ((__visibility__ ("default"))) -/* to enable hidden symbols */ -/* #undef CURL_HIDDEN_SYMBOLS */ - -/* Use Windows LDAP implementation */ -/* #undef CURL_LDAP_WIN */ - -/* when not building a shared library */ -/* #undef CURL_STATICLIB */ - /* your Entropy Gathering Daemon socket pathname */ /* #undef EGD_SOCKET */ /* Define if you want to enable IPv6 support */ #define ENABLE_IPV6 1 +/* Define to the type of arg 2 for gethostname. */ +#define GETHOSTNAME_TYPE_ARG2 size_t + /* Define to the type qualifier of arg 1 for getnameinfo. */ #define GETNAMEINFO_QUAL_ARG1 const @@ -125,7 +122,7 @@ #define HAVE_BOOL_T 1 /* Define to 1 if using BoringSSL. */ -#define HAVE_BORINGSSL 1 +/* #undef HAVE_BORINGSSL */ /* Define to 1 if you have the clock_gettime function and monotonic timer. */ #define HAVE_CLOCK_GETTIME_MONOTONIC 1 @@ -145,14 +142,23 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_CRYPTO_H */ -/* Define to 1 if you have the header file. */ -/* #undef HAVE_DES_H */ +/* Define to 1 if you have the `CyaSSL_CTX_UseSupportedCurve' function. */ +/* #undef HAVE_CYASSL_CTX_USESUPPORTEDCURVE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CYASSL_ERROR_SSL_H */ + +/* Define to 1 if you have the `CyaSSL_get_peer_certificate' function. */ +/* #undef HAVE_CYASSL_GET_PEER_CERTIFICATE */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_CYASSL_OPTIONS_H */ /* Define to 1 if you have the header file. */ #define HAVE_DLFCN_H 1 /* Define to 1 if you have the `ENGINE_cleanup' function. */ -/* #undef HAVE_ENGINE_CLEANUP */ +#define HAVE_ENGINE_CLEANUP 1 /* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */ #define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1 @@ -262,6 +268,9 @@ /* Define to 1 if you have the `getpwuid' function. */ #define HAVE_GETPWUID 1 +/* Define to 1 if you have the `getpwuid_r' function. */ +/* #undef HAVE_GETPWUID_R */ + /* Define to 1 if you have the `getrlimit' function. */ #define HAVE_GETRLIMIT 1 @@ -277,7 +286,14 @@ /* Define to 1 if you have a working gmtime_r function. */ #define HAVE_GMTIME_R 1 -/* if you have the gssapi libraries */ +/* Define to 1 if you have the `gnutls_certificate_set_x509_key_file2' + function. */ +/* #undef HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 */ + +/* if you have the function gnutls_srp_verifier */ +/* #undef HAVE_GNUTLS_SRP */ + +/* if you have GSS-API libraries */ /* #undef HAVE_GSSAPI */ /* Define to 1 if you have the header file. */ @@ -310,6 +326,9 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_IFADDRS_H */ +/* Define to 1 if you have the `if_nametoindex' function. */ +/* #undef HAVE_IF_NAMETOINDEX */ + /* Define to 1 if you have the `inet_addr' function. */ #define HAVE_INET_ADDR 1 @@ -365,6 +384,15 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_KRB_H */ +/* if you have the Kerberos4 libraries (including -ldes) */ +/* #undef HAVE_KRB4 */ + +/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */ +/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_KRB_H */ + /* Define to 1 if you have the lber.h header file. */ /* #undef HAVE_LBER_H */ @@ -386,20 +414,14 @@ /* Define to 1 if you have the `ldap_url_parse' function. */ /* #undef HAVE_LDAP_URL_PARSE */ -/* Define to 1 if you have the `gcrypt' library (-lgcrypt). */ -/* #undef HAVE_LIBGCRYPT */ - /* Define to 1 if you have the header file. */ #define HAVE_LIBGEN_H 1 /* Define to 1 if you have the `idn' library (-lidn). */ /* #undef HAVE_LIBIDN */ -/* Define to 1 if you have the `resolv' library (-lresolv). */ -/* #undef HAVE_LIBRESOLV */ - -/* Define to 1 if you have the `resolve' library (-lresolve). */ -/* #undef HAVE_LIBRESOLVE */ +/* Define to 1 if using libressl. */ +/* #undef HAVE_LIBRESSL */ /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBRTMP_RTMP_H */ @@ -407,26 +429,11 @@ /* Define to 1 if you have the `ssh2' library (-lssh2). */ /* #undef HAVE_LIBSSH2 */ -/* Define to 1 if you have the `libssh2_exit' function. */ -/* #undef HAVE_LIBSSH2_EXIT */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_LIBSSH2_H */ -/* Define to 1 if you have the `libssh2_init' function. */ -/* #undef HAVE_LIBSSH2_INIT */ - -/* Define to 1 if you have the `libssh2_scp_send64' function. */ -/* #undef HAVE_LIBSSH2_SCP_SEND64 */ - -/* Define to 1 if you have the `libssh2_session_handshake' function. */ -/* #undef HAVE_LIBSSH2_SESSION_HANDSHAKE */ - -/* Define to 1 if you have the `libssh2_version' function. */ -/* #undef HAVE_LIBSSH2_VERSION */ - /* Define to 1 if you have the `ssl' library (-lssl). */ -/* #undef HAVE_LIBSSL */ +#define HAVE_LIBSSL 1 /* if zlib is available */ #define HAVE_LIBZ 1 @@ -470,10 +477,13 @@ /* Define to 1 if you have the header file. */ #define HAVE_NET_IF_H 1 +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NGHTTP2_NGHTTP2_H */ + /* Define to 1 if NI_WITHSCOPEID exists and works. */ /* #undef HAVE_NI_WITHSCOPEID */ -/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE +/* if you have an old MIT Kerberos version, lacking GSS_C_NT_HOSTBASED_SERVICE */ /* #undef HAVE_OLD_GSSMIT */ @@ -496,7 +506,7 @@ #define HAVE_OPENSSL_RSA_H 1 /* if you have the function SRP_Calc_client_key */ -/* #define HAVE_OPENSSL_SRP 1 */ +#define HAVE_OPENSSL_SRP 1 /* Define to 1 if you have the header file. */ #define HAVE_OPENSSL_SSL_H 1 @@ -512,9 +522,6 @@ /* Define to 1 if you have the `pipe' function. */ #define HAVE_PIPE 1 -/* if you have the function PK11_CreateGenericObject */ -/* #undef HAVE_PK11_CREATEGENERICOBJECT */ - /* Define to 1 if you have a working poll function. */ #define HAVE_POLL 1 @@ -534,20 +541,17 @@ #define HAVE_PWD_H 1 /* Define to 1 if you have the `RAND_egd' function. */ -/* #undef HAVE_RAND_EGD */ +#define HAVE_RAND_EGD 1 /* Define to 1 if you have the `RAND_screen' function. */ /* #undef HAVE_RAND_SCREEN */ /* Define to 1 if you have the `RAND_status' function. */ -/* #undef HAVE_RAND_STATUS */ +#define HAVE_RAND_STATUS 1 /* Define to 1 if you have the recv function. */ #define HAVE_RECV 1 -/* Define to 1 if you have the recvfrom function. */ -#define HAVE_RECVFROM 1 - /* Define to 1 if you have the header file. */ /* #undef HAVE_RSA_H */ @@ -611,8 +615,8 @@ /* Define to 1 if you have the header file. */ /* #undef HAVE_SOCKET_H */ -/* Define this if you have the SPNEGO library fbopenssl */ -/* #undef HAVE_SPNEGO */ +/* Define to 1 if you have the `SSLv2_client_method' function. */ +/* #undef HAVE_SSLV2_CLIENT_METHOD */ /* Define to 1 if you have the `SSL_get_shutdown' function. */ #define HAVE_SSL_GET_SHUTDOWN 1 @@ -635,12 +639,6 @@ /* Define to 1 if you have the strcasecmp function. */ #define HAVE_STRCASECMP 1 -/* Define to 1 if you have the strcasestr function. */ -#define HAVE_STRCASESTR 1 - -/* Define to 1 if you have the strcasestr function. */ -#define HAVE_STRCASESTR 1 - /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ @@ -659,12 +657,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 -/* Define to 1 if you have the strlcat function. */ -#define HAVE_STRLCAT 1 - -/* Define to 1 if you have the `strlcpy' function. */ -#define HAVE_STRLCPY 1 - /* Define to 1 if you have the strncasecmp function. */ #define HAVE_STRNCASECMP 1 @@ -788,6 +780,18 @@ /* Define to 1 if you have the winsock.h header file. */ /* #undef HAVE_WINSOCK_H */ +/* Define to 1 if you have the `wolfSSLv3_client_method' function. */ +/* #undef HAVE_WOLFSSLV3_CLIENT_METHOD */ + +/* Define to 1 if you have the `wolfSSL_CTX_UseSupportedCurve' function. */ +/* #undef HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE */ + +/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */ +/* #undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE */ + +/* Define to 1 if you have the `wolfSSL_UseALPN' function. */ +/* #undef HAVE_WOLFSSL_USEALPN */ + /* Define this symbol if your OS supports changing the contents of argv */ /* #undef HAVE_WRITABLE_ARGV */ @@ -803,13 +807,9 @@ /* if you have the zlib.h header file */ #define HAVE_ZLIB_H 1 -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ +/* Define to the sub-directory where libtool stores uninstalled libraries. */ #define LT_OBJDIR ".libs/" -/* Define to 1 if you are building a native Windows target. */ -/* #undef NATIVE_WINDOWS */ - /* Define to 1 if you need the lber.h header file even with ldap.h */ /* #undef NEED_LBER_H */ @@ -825,6 +825,12 @@ /* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */ /* #undef NEED_THREAD_SAFE */ +/* Define to enable NTLM delegation to winbind's ntlm_auth helper. */ +#define NTLM_WB_ENABLED 1 + +/* Define absolute filename for winbind's ntlm_auth helper. */ +#define NTLM_WB_FILE "/usr/bin/ntlm_auth" + /* cpu-machine-OS */ #define OS "arm-linux-eabi" @@ -832,7 +838,7 @@ #define PACKAGE "curl" /* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "a suitable curl mailing list: http://curl.haxx.se/mail/" +#define PACKAGE_BUGREPORT "a suitable curl mailing list: https://curl.haxx.se/mail/" /* Define to the full name of this package. */ #define PACKAGE_NAME "curl" @@ -850,37 +856,7 @@ #define PACKAGE_VERSION "-" /* a suitable file to read random data from */ -/* #undef RANDOM_FILE */ - -/* Define to the type of arg 1 for recvfrom. */ -/* #undef RECVFROM_TYPE_ARG1 */ - -/* Define to the type pointed by arg 2 for recvfrom. */ -/* #undef RECVFROM_TYPE_ARG2 */ - -/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */ -/* #undef RECVFROM_TYPE_ARG2_IS_VOID */ - -/* Define to the type of arg 3 for recvfrom. */ -/* #undef RECVFROM_TYPE_ARG3 */ - -/* Define to the type of arg 4 for recvfrom. */ -/* #undef RECVFROM_TYPE_ARG4 */ - -/* Define to the type pointed by arg 5 for recvfrom. */ -/* #undef RECVFROM_TYPE_ARG5 */ - -/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */ -/* #undef RECVFROM_TYPE_ARG5_IS_VOID */ - -/* Define to the type pointed by arg 6 for recvfrom. */ -/* #undef RECVFROM_TYPE_ARG6 */ - -/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */ -/* #undef RECVFROM_TYPE_ARG6_IS_VOID */ - -/* Define to the function return type for recvfrom. */ -/* #undef RECVFROM_TYPE_RETV */ +#define RANDOM_FILE "/dev/urandom" /* Define to the type of arg 1 for recv. */ #define RECV_TYPE_ARG1 int @@ -982,8 +958,14 @@ /* Define to enable c-ares support */ /* #undef USE_ARES */ -/* Define to disable non-blocking sockets. */ -/* #undef USE_BLOCKING_SOCKETS */ +/* if axTLS is enabled */ +/* #undef USE_AXTLS */ + +/* if CyaSSL/WolfSSL is enabled */ +/* #undef USE_CYASSL */ + +/* to enable iOS/Mac OS X native SSL/TLS support */ +/* #undef USE_DARWINSSL */ /* if GnuTLS is enabled */ /* #undef USE_GNUTLS */ @@ -997,6 +979,15 @@ /* If you want to build curl with the built-in manual */ #define USE_MANUAL 1 +/* if mbedTLS is enabled */ +/* #undef USE_MBEDTLS */ + +/* Define to enable metalink support */ +/* #undef USE_METALINK */ + +/* if nghttp2 is in use */ +/* #undef USE_NGHTTP2 */ + /* if NSS is enabled */ /* #undef USE_NSS */ @@ -1004,14 +995,33 @@ /* #undef USE_OPENLDAP */ /* if OpenSSL is in use */ -/* #define USE_OPENSSL 1 */ +#define USE_OPENSSL 1 /* if PolarSSL is enabled */ /* #undef USE_POLARSSL */ +/* to enable Windows native SSL/TLS support */ +/* #undef USE_SCHANNEL */ + /* if you want POSIX threaded DNS lookup */ /* #undef USE_THREADS_POSIX */ +/* Use TLS-SRP authentication */ +#define USE_TLS_SRP 1 + +/* Use Unix domain sockets */ +#define USE_UNIX_SOCKETS 1 + +/* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */ +/* #undef USE_WIN32_IDN */ + +/* Define to 1 if you are building a Windows target with large file support. + */ +/* #undef USE_WIN32_SMALL_FILES */ + +/* Use Windows LDAP implementation */ +/* #undef USE_WIN32_LDAP */ + /* Define to 1 if you are building a Windows target without large file support. */ /* #undef USE_WIN32_LARGE_FILES */ @@ -1019,8 +1029,11 @@ /* to enable SSPI support */ /* #undef USE_WINDOWS_SSPI */ -/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */ -/* #undef USE_YASSLEMUL */ +/* Version number of package */ +#define VERSION "-" + +/* Define to 1 to provide own prototypes. */ +/* #undef WANT_IDN_PROTOTYPES */ /* Define to avoid automatic inclusion of winsock.h */ /* #undef WIN32_LEAN_AND_MEAN */ @@ -1030,6 +1043,11 @@ /* # undef _ALL_SOURCE */ #endif +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + /* Number of bits in a file offset, on hosts where this is settable. */ /* #undef _FILE_OFFSET_BITS */ diff --git a/project/jni/curl/lib/curl_fnmatch.c b/project/jni/curl/lib/curl_fnmatch.c index 53240078a..e8108bb10 100644 --- a/project/jni/curl/lib/curl_fnmatch.c +++ b/project/jni/curl/lib/curl_fnmatch.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #include "curl_fnmatch.h" #include "curl_memory.h" diff --git a/project/jni/curl/lib/curl_gssapi.c b/project/jni/curl/lib/curl_gssapi.c index 75af67036..6f9121e4e 100644 --- a/project/jni/curl/lib/curl_gssapi.c +++ b/project/jni/curl/lib/curl_gssapi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -76,6 +76,32 @@ OM_uint32 Curl_gss_init_sec_context( NULL /* time_rec */); } +#define GSS_LOG_BUFFER_LEN 1024 +static size_t display_gss_error(OM_uint32 status, int type, + char *buf, size_t len) { + OM_uint32 maj_stat; + OM_uint32 min_stat; + OM_uint32 msg_ctx = 0; + gss_buffer_desc status_string; + + do { + maj_stat = gss_display_status(&min_stat, + status, + type, + GSS_C_NO_OID, + &msg_ctx, + &status_string); + if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { + len += snprintf(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 != 0); + + return len; +} + /* * Curl_gss_log_error() * @@ -84,37 +110,22 @@ OM_uint32 Curl_gss_init_sec_context( * Parameters: * * data [in] - The session handle. - * status [in] - The status code. * prefix [in] - The prefix of the log message. + * major [in] - The major status code. + * minor [in] - The minor status code. */ -void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, - const char *prefix) +void Curl_gss_log_error(struct SessionHandle *data, const char *prefix, + OM_uint32 major, OM_uint32 minor) { - OM_uint32 maj_stat; - OM_uint32 min_stat; - OM_uint32 msg_ctx = 0; - gss_buffer_desc status_string; - char buf[1024]; - size_t len; + char buf[GSS_LOG_BUFFER_LEN]; + size_t len = 0; - snprintf(buf, sizeof(buf), "%s", prefix); - len = strlen(buf); - do { - maj_stat = gss_display_status(&min_stat, - status, - GSS_C_MECH_CODE, - GSS_C_NO_OID, - &msg_ctx, - &status_string); - if(sizeof(buf) > len + status_string.length + 1) { - snprintf(buf + len, sizeof(buf) - len, - ": %s", (char*)status_string.value); - len += status_string.length; - } - gss_release_buffer(&min_stat, &status_string); - } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); + if(major != GSS_S_FAILURE) + len = display_gss_error(major, GSS_C_GSS_CODE, buf, len); - infof(data, "%s\n", buf); + display_gss_error(minor, GSS_C_MECH_CODE, buf, len); + + infof(data, "%s%s\n", prefix, buf); } #endif /* HAVE_GSSAPI */ diff --git a/project/jni/curl/lib/curl_gssapi.h b/project/jni/curl/lib/curl_gssapi.h index c1642a8b6..42fd1e41d 100644 --- a/project/jni/curl/lib/curl_gssapi.h +++ b/project/jni/curl/lib/curl_gssapi.h @@ -56,8 +56,8 @@ OM_uint32 Curl_gss_init_sec_context( OM_uint32 *ret_flags); /* Helper to log a GSS-API error status */ -void Curl_gss_log_error(struct SessionHandle *data, OM_uint32 status, - const char *prefix); +void Curl_gss_log_error(struct SessionHandle *data, const char *prefix, + OM_uint32 major, OM_uint32 minor); /* Provide some definitions missing in old headers */ #ifdef HAVE_OLD_GSSMIT diff --git a/project/jni/curl/lib/curl_memory.h b/project/jni/curl/lib/curl_memory.h index fcd177cd5..6f792fffd 100644 --- a/project/jni/curl/lib/curl_memory.h +++ b/project/jni/curl/lib/curl_memory.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -83,7 +83,20 @@ #ifndef CURLX_NO_MEMORY_CALLBACKS -#include /* for the callback typedefs */ +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ +/* + * The following memory function replacement typedef's are COPIED from + * curl/curl.h and MUST match the originals. We copy them to avoid having to + * include curl/curl.h here. We avoid that include since it includes stdio.h + * and other headers that may get messed up with defines done here. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif extern curl_malloc_callback Curl_cmalloc; extern curl_free_callback Curl_cfree; diff --git a/project/jni/curl/lib/curl_memrchr.c b/project/jni/curl/lib/curl_memrchr.c index 1be27e5c8..c521497b2 100644 --- a/project/jni/curl/lib/curl_memrchr.c +++ b/project/jni/curl/lib/curl_memrchr.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,6 +21,9 @@ ***************************************************************************/ #include "curl_setup.h" + +#include + #include "curl_memrchr.h" #include "curl_memory.h" diff --git a/project/jni/curl/lib/curl_ntlm_core.c b/project/jni/curl/lib/curl_ntlm_core.c index e79d1f64f..ea7548dd1 100644 --- a/project/jni/curl/lib/curl_ntlm_core.c +++ b/project/jni/curl/lib/curl_ntlm_core.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,7 +28,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) @@ -107,9 +107,8 @@ #include "warnless.h" #include "curl_endian.h" #include "curl_des.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" diff --git a/project/jni/curl/lib/curl_ntlm_wb.c b/project/jni/curl/lib/curl_ntlm_wb.c index 06f66702d..afdea16c0 100644 --- a/project/jni/curl/lib/curl_ntlm_wb.c +++ b/project/jni/curl/lib/curl_ntlm_wb.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,7 +29,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 @@ -47,13 +47,12 @@ #include "urldata.h" #include "sendf.h" #include "select.h" -#include "curl_ntlm_msgs.h" +#include "vauth/ntlm.h" #include "curl_ntlm_wb.h" #include "url.h" #include "strerror.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" diff --git a/project/jni/curl/lib/curl_sasl.c b/project/jni/curl/lib/curl_sasl.c index 945d75232..94b39e4a6 100644 --- a/project/jni/curl/lib/curl_sasl.c +++ b/project/jni/curl/lib/curl_sasl.c @@ -36,6 +36,7 @@ #include "curl_base64.h" #include "curl_md5.h" +#include "vauth/vauth.h" #include "vtls/vtls.h" #include "curl_hmac.h" #include "curl_sasl.h" @@ -45,9 +46,8 @@ #include "rawstr.h" #include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -69,1145 +69,6 @@ const struct { { ZERO_NULL, 0, 0 } }; -#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) -#define DIGEST_QOP_VALUE_AUTH (1 << 0) -#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) -#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) - -#define DIGEST_QOP_VALUE_STRING_AUTH "auth" -#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" -#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" - -/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. - It converts digest text to ASCII so the MD5 will be correct for - what ultimately goes over the network. -*/ -#define CURL_OUTPUT_DIGEST_CONV(a, b) \ - result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ - if(result) { \ - free(b); \ - return result; \ - } - -#endif - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -bool Curl_sasl_digest_get_pair(const char *str, char *value, char *content, - const char **endptr) -{ - int c; - bool starts_with_quote = FALSE; - bool escape = FALSE; - - for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--); ) - *value++ = *str++; - *value = 0; - - if('=' != *str++) - /* eek, no match */ - return FALSE; - - if('\"' == *str) { - /* this starts with a quote so it must end with one as well! */ - str++; - starts_with_quote = TRUE; - } - - 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; - - case '\"': - if(!escape && starts_with_quote) { - /* end of string */ - c = 0; - continue; - } - break; - } - - escape = FALSE; - *content++ = *str; - } - - *content = 0; - *endptr = str; - - return TRUE; -} -#endif - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(USE_WINDOWS_SSPI) -/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ -static void sasl_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ - unsigned char *dest) /* 33 bytes */ -{ - int i; - for(i = 0; i < 16; i++) - snprintf((char *)&dest[i*2], 3, "%02x", source[i]); -} - -/* Perform quoted-string escaping as described in RFC2616 and its errata */ -static char *sasl_digest_string_quoted(const char *source) -{ - char *dest, *d; - const char *s = source; - size_t n = 1; /* null terminator */ - - /* Calculate size needed */ - while(*s) { - ++n; - if(*s == '"' || *s == '\\') { - ++n; - } - ++s; - } - - dest = malloc(n); - if(dest) { - s = source; - d = dest; - while(*s) { - if(*s == '"' || *s == '\\') { - *d++ = '\\'; - } - *d++ = *s++; - } - *d = 0; - } - - return dest; -} - -/* Retrieves the value for a corresponding key from the challenge string - * returns TRUE if the key could be found, FALSE if it does not exists - */ -static bool sasl_digest_get_key_value(const char *chlg, - const char *key, - char *value, - size_t max_val_len, - char end_char) -{ - char *find_pos; - size_t i; - - find_pos = strstr(chlg, key); - if(!find_pos) - return FALSE; - - find_pos += strlen(key); - - for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) - value[i] = *find_pos++; - value[i] = '\0'; - - return TRUE; -} - -static CURLcode sasl_digest_get_qop_values(const char *options, int *value) -{ - char *tmp; - char *token; - char *tok_buf; - - /* Initialise the output */ - *value = 0; - - /* Tokenise the list of qop values. Use a temporary clone of the buffer since - strtok_r() ruins it. */ - tmp = strdup(options); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) - *value |= DIGEST_QOP_VALUE_AUTH; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) - *value |= DIGEST_QOP_VALUE_AUTH_INT; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) - *value |= DIGEST_QOP_VALUE_AUTH_CONF; - - token = strtok_r(NULL, ",", &tok_buf); - } - - free(tmp); - - return CURLE_OK; -} -#endif /* !CURL_DISABLE_CRYPTO_AUTH && !USE_WINDOWS_SSPI */ - -#if !defined(USE_WINDOWS_SSPI) -/* - * Curl_sasl_build_spn() - * - * This is used to build a SPN string in the format service/instance. - * - * Parameters: - * - * service [in] - The service type such as www, smtp, pop or imap. - * instance [in] - The host name or realm. - * - * Returns a pointer to the newly allocated SPN. - */ -char *Curl_sasl_build_spn(const char *service, const char *instance) -{ - /* Generate and return our SPN */ - return aprintf("%s/%s", service, instance); -} -#endif - -/* - * sasl_create_plain_message() - * - * This is used to generate an already encoded PLAIN message ready - * for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_plain_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) -{ - CURLcode result; - char *plainauth; - size_t ulen; - size_t plen; - - ulen = strlen(userp); - plen = strlen(passwdp); - - plainauth = malloc(2 * ulen + plen + 2); - if(!plainauth) { - *outlen = 0; - *outptr = NULL; - return CURLE_OUT_OF_MEMORY; - } - - /* Calculate the reply */ - memcpy(plainauth, userp, ulen); - plainauth[ulen] = '\0'; - memcpy(plainauth + ulen + 1, userp, ulen); - plainauth[2 * ulen + 1] = '\0'; - memcpy(plainauth + 2 * ulen + 2, passwdp, plen); - - /* Base64 encode the reply */ - result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, - outlen); - free(plainauth); - return result; -} - -/* - * sasl_create_login_message() - * - * This is used to generate an already encoded LOGIN message containing the - * user name or password ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * valuep [in] - The user name or user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_login_message(struct SessionHandle *data, - const char *valuep, char **outptr, - size_t *outlen) -{ - size_t vlen = strlen(valuep); - - if(!vlen) { - /* Calculate an empty reply */ - *outptr = strdup("="); - if(*outptr) { - *outlen = (size_t) 1; - return CURLE_OK; - } - - *outlen = 0; - return CURLE_OUT_OF_MEMORY; - } - - /* Base64 encode the value */ - return Curl_base64_encode(data, valuep, vlen, outptr, outlen); -} - -/* - * sasl_create_external_message() - * - * This is used to generate an already encoded EXTERNAL message containing - * the user name ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * user [in] - The user name. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_external_message(struct SessionHandle *data, - const char *user, char **outptr, - size_t *outlen) -{ - /* This is the same formatting as the login message. */ - return sasl_create_login_message(data, user, outptr, outlen); -} - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* - * sasl_decode_cram_md5_message() - * - * This is used to decode an already encoded CRAM-MD5 challenge message. - * - * Parameters: - * - * chlg64 [in] - The base64 encoded challenge message. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_decode_cram_md5_message(const char *chlg64, char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlg64len = strlen(chlg64); - - *outptr = NULL; - *outlen = 0; - - /* Decode the challenge if necessary */ - if(chlg64len && *chlg64 != '=') - result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); - - return result; -} - -/* - * sasl_create_cram_md5_message() - * - * This is used to generate an already encoded CRAM-MD5 response message ready - * for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg [in] - The challenge. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_cram_md5_message(struct SessionHandle *data, - const char *chlg, - const char *userp, - const char *passwdp, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - HMAC_context *ctxt; - unsigned char digest[MD5_DIGEST_LEN]; - char *response; - - if(chlg) - chlglen = strlen(chlg); - - /* Compute the digest using the password as the key */ - ctxt = Curl_HMAC_init(Curl_HMAC_MD5, - (const unsigned char *) passwdp, - curlx_uztoui(strlen(passwdp))); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - /* Update the digest with the given challenge */ - if(chlglen > 0) - Curl_HMAC_update(ctxt, (const unsigned char *) chlg, - curlx_uztoui(chlglen)); - - /* Finalise the digest */ - Curl_HMAC_final(ctxt, digest); - - /* Generate the response */ - response = aprintf( - "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - userp, digest[0], digest[1], digest[2], digest[3], digest[4], - digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], - digest[11], digest[12], digest[13], digest[14], digest[15]); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the response */ - result = Curl_base64_encode(data, response, 0, outptr, outlen); - - free(response); - - return result; -} - -#ifndef USE_WINDOWS_SSPI -/* - * sasl_decode_digest_md5_message() - * - * This is used internally to decode an already encoded DIGEST-MD5 challenge - * message into the seperate attributes. - * - * Parameters: - * - * chlg64 [in] - The base64 encoded challenge message. - * nonce [in/out] - The buffer where the nonce will be stored. - * nlen [in] - The length of the nonce buffer. - * realm [in/out] - The buffer where the realm will be stored. - * rlen [in] - The length of the realm buffer. - * alg [in/out] - The buffer where the algorithm will be stored. - * alen [in] - The length of the algorithm buffer. - * qop [in/out] - The buffer where the qop-options will be stored. - * qlen [in] - The length of the qop buffer. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_decode_digest_md5_message(const char *chlg64, - char *nonce, size_t nlen, - char *realm, size_t rlen, - char *alg, size_t alen, - char *qop, size_t qlen) -{ - CURLcode result = CURLE_OK; - unsigned char *chlg = NULL; - size_t chlglen = 0; - size_t chlg64len = strlen(chlg64); - - /* Decode the base-64 encoded challenge message */ - if(chlg64len && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) - return CURLE_BAD_CONTENT_ENCODING; - - /* Retrieve nonce string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "nonce=\"", nonce, nlen, '\"')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Retrieve realm string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "realm=\"", realm, rlen, '\"')) { - /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ - strcpy(realm, ""); - } - - /* Retrieve algorithm string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "algorithm=", alg, alen, ',')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Retrieve qop-options string from the challenge */ - if(!sasl_digest_get_key_value((char *)chlg, "qop=\"", qop, qlen, '\"')) { - free(chlg); - return CURLE_BAD_CONTENT_ENCODING; - } - - free(chlg); - - return CURLE_OK; -} - -/* - * Curl_sasl_create_digest_md5_message() - * - * This is used to generate an already encoded DIGEST-MD5 response message - * ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The base64 encoded challenge message. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t i; - MD5_context *ctxt; - char *response = NULL; - unsigned char digest[MD5_DIGEST_LEN]; - char HA1_hex[2 * MD5_DIGEST_LEN + 1]; - char HA2_hex[2 * MD5_DIGEST_LEN + 1]; - char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; - char nonce[64]; - char realm[128]; - char algorithm[64]; - char qop_options[64]; - int qop_values; - char cnonce[33]; - unsigned int entropy[4]; - char nonceCount[] = "00000001"; - char method[] = "AUTHENTICATE"; - char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; - char *spn = NULL; - - /* Decode the challange message */ - result = sasl_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), - realm, sizeof(realm), - algorithm, sizeof(algorithm), - qop_options, sizeof(qop_options)); - if(result) - return result; - - /* We only support md5 sessions */ - if(strcmp(algorithm, "md5-sess") != 0) - return CURLE_BAD_CONTENT_ENCODING; - - /* Get the qop-values from the qop-options */ - result = sasl_digest_get_qop_values(qop_options, &qop_values); - if(result) - return result; - - /* We only support auth quality-of-protection */ - if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) - return CURLE_BAD_CONTENT_ENCODING; - - /* Generate 16 bytes of random data */ - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); - entropy[2] = Curl_rand(data); - entropy[3] = Curl_rand(data); - - /* Convert the random data into a 32 byte hex string */ - snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", - entropy[0], entropy[1], entropy[2], entropy[3]); - - /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) userp, - curlx_uztoui(strlen(userp))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) realm, - curlx_uztoui(strlen(realm))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) passwdp, - curlx_uztoui(strlen(passwdp))); - Curl_MD5_final(ctxt, digest); - - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) - return CURLE_OUT_OF_MEMORY; - - Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) nonce, - curlx_uztoui(strlen(nonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) cnonce, - curlx_uztoui(strlen(cnonce))); - Curl_MD5_final(ctxt, digest); - - /* Convert calculated 16 octet hex into 32 bytes string */ - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); - - /* Generate our SPN */ - spn = Curl_sasl_build_spn(service, realm); - if(!spn) - return CURLE_OUT_OF_MEMORY; - - /* Calculate H(A2) */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) { - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - Curl_MD5_update(ctxt, (const unsigned char *) method, - curlx_uztoui(strlen(method))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) spn, - curlx_uztoui(strlen(spn))); - Curl_MD5_final(ctxt, digest); - - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); - - /* Now calculate the response hash */ - ctxt = Curl_MD5_init(Curl_DIGEST_MD5); - if(!ctxt) { - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) nonce, - curlx_uztoui(strlen(nonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - - Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, - curlx_uztoui(strlen(nonceCount))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) cnonce, - curlx_uztoui(strlen(cnonce))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - Curl_MD5_update(ctxt, (const unsigned char *) qop, - curlx_uztoui(strlen(qop))); - Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); - - Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); - Curl_MD5_final(ctxt, digest); - - for(i = 0; i < MD5_DIGEST_LEN; i++) - snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); - - /* Generate the response */ - response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," - "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," - "qop=%s", - userp, realm, nonce, - cnonce, nonceCount, spn, resp_hash_hex, qop); - free(spn); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the response */ - result = Curl_base64_encode(data, response, 0, outptr, outlen); - - free(response); - - return result; -} - -/* - * Curl_sasl_decode_digest_http_message() - * - * This is used to decode a HTTP DIGEST challenge message into the seperate - * attributes. - * - * Parameters: - * - * chlg [in] - The challenge message. - * digest [in/out] - The digest data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, - struct digestdata *digest) -{ - bool before = FALSE; /* got a nonce before */ - bool foundAuth = FALSE; - bool foundAuthInt = FALSE; - char *token = NULL; - char *tmp = NULL; - - /* If we already have received a nonce, keep that in mind */ - if(digest->nonce) - before = TRUE; - - /* Clean up any former leftovers and initialise to defaults */ - Curl_sasl_digest_cleanup(digest); - - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Extract a value=content pair */ - if(Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "nonce")) { - free(digest->nonce); - digest->nonce = strdup(content); - if(!digest->nonce) - return CURLE_OUT_OF_MEMORY; - } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { - digest->stale = TRUE; - digest->nc = 1; /* we make a new nonce now */ - } - } - else if(Curl_raw_equal(value, "realm")) { - free(digest->realm); - digest->realm = strdup(content); - if(!digest->realm) - return CURLE_OUT_OF_MEMORY; - } - else if(Curl_raw_equal(value, "opaque")) { - free(digest->opaque); - digest->opaque = strdup(content); - if(!digest->opaque) - return CURLE_OUT_OF_MEMORY; - } - else if(Curl_raw_equal(value, "qop")) { - char *tok_buf; - /* Tokenize the list and choose auth if possible, use a temporary - clone of the buffer since strtok_r() ruins it */ - tmp = strdup(content); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - token = strtok_r(tmp, ",", &tok_buf); - while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { - foundAuth = TRUE; - } - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { - foundAuthInt = TRUE; - } - token = strtok_r(NULL, ",", &tok_buf); - } - - free(tmp); - - /* Select only auth or auth-int. Otherwise, ignore */ - if(foundAuth) { - free(digest->qop); - digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); - if(!digest->qop) - return CURLE_OUT_OF_MEMORY; - } - else if(foundAuthInt) { - free(digest->qop); - digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); - if(!digest->qop) - return CURLE_OUT_OF_MEMORY; - } - } - else if(Curl_raw_equal(value, "algorithm")) { - free(digest->algorithm); - digest->algorithm = strdup(content); - if(!digest->algorithm) - return CURLE_OUT_OF_MEMORY; - - if(Curl_raw_equal(content, "MD5-sess")) - digest->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) - digest->algo = CURLDIGESTALGO_MD5; - else - return CURLE_BAD_CONTENT_ENCODING; - } - else { - /* unknown specifier, ignore it! */ - } - } - else - break; /* we're done here */ - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Allow the list to be comma-separated */ - if(',' == *chlg) - chlg++; - } - - /* We had a nonce since before, and we got another one now without - 'stale=true'. This means we provided bad credentials in the previous - request */ - if(before && !digest->stale) - return CURLE_BAD_CONTENT_ENCODING; - - /* We got this header without a nonce, that's a bad Digest line! */ - if(!digest->nonce) - return CURLE_BAD_CONTENT_ENCODING; - - return CURLE_OK; -} - -/* - * Curl_sasl_create_digest_http_message() - * - * This is used to generate a HTTP DIGEST response message ready for sending - * to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name. - * passdwp [in] - The user's password. - * request [in] - The HTTP request. - * uripath [in] - The path of the HTTP uri. - * digest [in/out] - The digest data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uripath, - struct digestdata *digest, - char **outptr, size_t *outlen) -{ - CURLcode result; - unsigned char md5buf[16]; /* 16 bytes/128 bits */ - unsigned char request_digest[33]; - unsigned char *md5this; - unsigned char ha1[33];/* 32 digits and 1 zero byte */ - unsigned char ha2[33];/* 32 digits and 1 zero byte */ - char cnoncebuf[33]; - char *cnonce = NULL; - size_t cnonce_sz = 0; - char *userp_quoted; - char *response = NULL; - char *tmp = NULL; - - if(!digest->nc) - digest->nc = 1; - - if(!digest->cnonce) { - snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", - Curl_rand(data), Curl_rand(data), - Curl_rand(data), Curl_rand(data)); - - result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), - &cnonce, &cnonce_sz); - if(result) - return result; - - digest->cnonce = cnonce; - } - - /* - If the algorithm is "MD5" or unspecified (which then defaults to MD5): - - A1 = unq(username-value) ":" unq(realm-value) ":" passwd - - If the algorithm is "MD5-sess" then: - - A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) ":" - unq(nonce-value) ":" unq(cnonce-value) - */ - - md5this = (unsigned char *) - aprintf("%s:%s:%s", userp, digest->realm, passwdp); - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - sasl_digest_md5_to_ascii(md5buf, ha1); - - if(digest->algo == CURLDIGESTALGO_MD5SESS) { - /* nonce and cnonce are OUTSIDE the hash */ - tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, (unsigned char *)tmp); - free(tmp); - sasl_digest_md5_to_ascii(md5buf, ha1); - } - - /* - If the "qop" directive's value is "auth" or is unspecified, then A2 is: - - A2 = Method ":" digest-uri-value - - If the "qop" value is "auth-int", then A2 is: - - A2 = Method ":" digest-uri-value ":" H(entity-body) - - (The "Method" value is the HTTP request method as specified in section - 5.1.1 of RFC 2616) - */ - - md5this = (unsigned char *)aprintf("%s:%s", request, uripath); - - if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { - /* We don't support auth-int for PUT or POST at the moment. - TODO: replace md5 of empty string with entity-body for PUT/POST */ - unsigned char *md5this2 = (unsigned char *) - aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); - free(md5this); - md5this = md5this2; - } - - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - sasl_digest_md5_to_ascii(md5buf, ha2); - - if(digest->qop) { - md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s", - ha1, - digest->nonce, - digest->nc, - digest->cnonce, - digest->qop, - ha2); - } - else { - md5this = (unsigned char *)aprintf("%s:%s:%s", - ha1, - digest->nonce, - ha2); - } - - if(!md5this) - return CURLE_OUT_OF_MEMORY; - - CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ - Curl_md5it(md5buf, md5this); - free(md5this); - sasl_digest_md5_to_ascii(md5buf, request_digest); - - /* for test case 64 (snooped from a Mozilla 1.3a request) - - Authorization: Digest username="testuser", realm="testrealm", \ - 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 - characters. algorithm and qop with standard values only contain web-safe - characters. - */ - userp_quoted = sasl_digest_string_quoted(userp); - if(!userp_quoted) - return CURLE_OUT_OF_MEMORY; - - if(digest->qop) { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "cnonce=\"%s\", " - "nc=%08x, " - "qop=%s, " - "response=\"%s\"", - userp_quoted, - digest->realm, - digest->nonce, - uripath, - digest->cnonce, - digest->nc, - digest->qop, - request_digest); - - if(Curl_raw_equal(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 */ - } - else { - response = aprintf("username=\"%s\", " - "realm=\"%s\", " - "nonce=\"%s\", " - "uri=\"%s\", " - "response=\"%s\"", - userp_quoted, - digest->realm, - digest->nonce, - uripath, - request_digest); - } - free(userp_quoted); - if(!response) - return CURLE_OUT_OF_MEMORY; - - /* Add the optional fields */ - if(digest->opaque) { - /* Append the opaque */ - tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); - free(response); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - response = tmp; - } - - if(digest->algorithm) { - /* Append the algorithm */ - tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); - free(response); - if(!tmp) - return CURLE_OUT_OF_MEMORY; - - response = tmp; - } - - /* Return the output */ - *outptr = response; - *outlen = strlen(response); - - return CURLE_OK; -} - -/* - * Curl_sasl_digest_cleanup() - * - * This is used to clean up the digest specific data. - * - * Parameters: - * - * digest [in/out] - The digest data struct being cleaned up. - * - */ -void Curl_sasl_digest_cleanup(struct digestdata *digest) -{ - Curl_safefree(digest->nonce); - Curl_safefree(digest->cnonce); - Curl_safefree(digest->realm); - Curl_safefree(digest->opaque); - Curl_safefree(digest->qop); - Curl_safefree(digest->algorithm); - - digest->nc = 0; - digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ - digest->stale = FALSE; /* default means normal, not stale */ -} -#endif /* !USE_WINDOWS_SSPI */ - -#endif /* CURL_DISABLE_CRYPTO_AUTH */ - -#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) -/* - * Curl_sasl_ntlm_cleanup() - * - * This is used to clean up the NTLM specific data. - * - * Parameters: - * - * ntlm [in/out] - The NTLM data struct being cleaned up. - * - */ -void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) -{ - /* Free the target info */ - Curl_safefree(ntlm->target_info); - - /* Reset any variables */ - ntlm->target_info_len = 0; -} -#endif /* USE_NTLM && !USE_WINDOWS_SSPI*/ - -/* - * sasl_create_oauth_bearer_message() - * - * This is used to generate an already encoded OAuth 2.0 message ready for - * sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * user [in] - The user name. - * host [in] - The host name (for OAUTHBEARER). - * port [in] - The port (for OAUTHBEARER when not Port 80). - * bearer [in] - The bearer token. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -static CURLcode sasl_create_oauth_bearer_message(struct SessionHandle *data, - const char *user, - const char *host, - const long port, - const char *bearer, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - char *oauth = NULL; - - /* Generate the message */ - if(host == NULL && (port == 0 || port == 80)) - oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); - else if(port == 0 || port == 80) - oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host, - bearer); - else - oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, - host, port, bearer); - if(!oauth) - return CURLE_OUT_OF_MEMORY; - - /* Base64 encode the reply */ - result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen); - - free(oauth); - - return result; -} - /* * Curl_sasl_cleanup() * @@ -1224,14 +85,14 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused) #if defined(USE_KERBEROS5) /* Cleanup the gssapi structure */ if(authused == SASL_MECH_GSSAPI) { - Curl_sasl_gssapi_cleanup(&conn->krb5); + Curl_auth_gssapi_cleanup(&conn->krb5); } #endif #if defined(USE_NTLM) /* Cleanup the NTLM structure */ if(authused == SASL_MECH_NTLM) { - Curl_sasl_ntlm_cleanup(&conn->ntlm); + Curl_auth_ntlm_cleanup(&conn->ntlm); } #endif @@ -1403,6 +264,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, size_t len = 0; saslstate state1 = SASL_STOP; saslstate state2 = SASL_FINAL; +#if defined(USE_KERBEROS5) + const char* service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; +#endif sasl->force_ir = force_ir; /* Latch for future use */ sasl->authused = 0; /* No mechanism used yet */ @@ -1417,7 +283,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_EXTERNAL; if(force_ir || data->set.sasl_ir) - result = sasl_create_external_message(data, conn->user, &resp, &len); + result = Curl_auth_create_external_message(data, conn->user, &resp, + &len); } else if(conn->bits.user_passwd) { #if defined(USE_KERBEROS5) @@ -1429,9 +296,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_GSSAPI; if(force_ir || data->set.sasl_ir) - result = Curl_sasl_create_gssapi_user_message(data, conn->user, + result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, - sasl->params->service, + service, + data->easy_conn-> + host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); @@ -1459,7 +328,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_NTLM; if(force_ir || data->set.sasl_ir) - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, &conn->ntlm, &resp, &len); } else @@ -1471,11 +340,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_OAUTHBEARER; if(force_ir || data->set.sasl_ir) - result = sasl_create_oauth_bearer_message(data, conn->user, - conn->host.name, - conn->port, - conn->oauth_bearer, - &resp, &len); + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + conn->host.name, + conn->port, + conn->oauth_bearer, + &resp, &len); } else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) { mech = SASL_MECH_STRING_XOAUTH2; @@ -1483,10 +352,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_XOAUTH2; if(force_ir || data->set.sasl_ir) - result = sasl_create_oauth_bearer_message(data, conn->user, - NULL, 0, - conn->oauth_bearer, - &resp, &len); + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + NULL, 0, + conn->oauth_bearer, + &resp, &len); } else if(enabledmechs & SASL_MECH_LOGIN) { mech = SASL_MECH_STRING_LOGIN; @@ -1495,7 +364,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_LOGIN; if(force_ir || data->set.sasl_ir) - result = sasl_create_login_message(data, conn->user, &resp, &len); + result = Curl_auth_create_login_message(data, conn->user, &resp, &len); } else if(enabledmechs & SASL_MECH_PLAIN) { mech = SASL_MECH_STRING_PLAIN; @@ -1503,24 +372,22 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, sasl->authused = SASL_MECH_PLAIN; if(force_ir || data->set.sasl_ir) - result = sasl_create_plain_message(data, conn->user, conn->passwd, - &resp, &len); + result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, + &resp, &len); } } - if(!result) { + if(!result && mech) { if(resp && sasl->params->maxirlen && strlen(mech) + len > sasl->params->maxirlen) { free(resp); resp = NULL; } - if(mech) { - result = sasl->params->sendauth(conn, mech, resp); - if(!result) { - *progress = SASL_INPROGRESS; - state(sasl, conn, resp? state2: state1); - } + result = sasl->params->sendauth(conn, mech, resp); + if(!result) { + *progress = SASL_INPROGRESS; + state(sasl, conn, resp ? state2 : state1); } } @@ -1545,6 +412,11 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, char *serverdata; char *chlg = NULL; size_t chlglen = 0; +#endif +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; #endif size_t len = 0; @@ -1570,34 +442,35 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, *progress = SASL_DONE; return result; case SASL_PLAIN: - result = sasl_create_plain_message(data, conn->user, conn->passwd, &resp, - &len); + result = Curl_auth_create_plain_message(data, conn->user, conn->passwd, + &resp, + &len); break; case SASL_LOGIN: - result = sasl_create_login_message(data, conn->user, &resp, &len); + result = Curl_auth_create_login_message(data, conn->user, &resp, &len); newstate = SASL_LOGIN_PASSWD; break; case SASL_LOGIN_PASSWD: - result = sasl_create_login_message(data, conn->passwd, &resp, &len); + result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len); break; case SASL_EXTERNAL: - result = sasl_create_external_message(data, conn->user, &resp, &len); + result = Curl_auth_create_external_message(data, conn->user, &resp, &len); break; #ifndef CURL_DISABLE_CRYPTO_AUTH case SASL_CRAMMD5: sasl->params->getmessage(data->state.buffer, &serverdata); - result = sasl_decode_cram_md5_message(serverdata, &chlg, &chlglen); + result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen); if(!result) - result = sasl_create_cram_md5_message(data, chlg, conn->user, - conn->passwd, &resp, &len); + result = Curl_auth_create_cram_md5_message(data, chlg, conn->user, + conn->passwd, &resp, &len); free(chlg); break; case SASL_DIGESTMD5: sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_sasl_create_digest_md5_message(data, serverdata, + result = Curl_auth_create_digest_md5_message(data, serverdata, conn->user, conn->passwd, - sasl->params->service, + service, &resp, &len); newstate = SASL_DIGESTMD5_RESP; break; @@ -1611,17 +484,17 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, #ifdef USE_NTLM case SASL_NTLM: /* Create the type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, + result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd, &conn->ntlm, &resp, &len); newstate = SASL_NTLM_TYPE2MSG; break; case SASL_NTLM_TYPE2MSG: /* Decode the type-2 message */ sasl->params->getmessage(data->state.buffer, &serverdata); - result = Curl_sasl_decode_ntlm_type2_message(data, serverdata, + result = Curl_auth_decode_ntlm_type2_message(data, serverdata, &conn->ntlm); if(!result) - result = Curl_sasl_create_ntlm_type3_message(data, conn->user, + result = Curl_auth_create_ntlm_type3_message(data, conn->user, conn->passwd, &conn->ntlm, &resp, &len); break; @@ -1629,9 +502,10 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, #if defined(USE_KERBEROS5) case SASL_GSSAPI: - result = Curl_sasl_create_gssapi_user_message(data, conn->user, + result = Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd, - sasl->params->service, + service, + data->easy_conn->host.name, sasl->mutual_auth, NULL, &conn->krb5, &resp, &len); @@ -1642,7 +516,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, if(sasl->mutual_auth) { /* Decode the user token challenge and create the optional response message */ - result = Curl_sasl_create_gssapi_user_message(data, NULL, NULL, NULL, + result = Curl_auth_create_gssapi_user_message(data, NULL, NULL, + NULL, NULL, sasl->mutual_auth, serverdata, &conn->krb5, &resp, &len); @@ -1650,14 +525,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, } else /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, serverdata, + result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; case SASL_GSSAPI_NO_DATA: sasl->params->getmessage(data->state.buffer, &serverdata); /* Decode the security challenge and create the response message */ - result = Curl_sasl_create_gssapi_security_message(data, serverdata, + result = Curl_auth_create_gssapi_security_message(data, serverdata, &conn->krb5, &resp, &len); break; @@ -1666,20 +541,20 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, case SASL_OAUTH2: /* Create the authorisation message */ if(sasl->authused == SASL_MECH_OAUTHBEARER) { - result = sasl_create_oauth_bearer_message(data, conn->user, - conn->host.name, - conn->port, - conn->oauth_bearer, - &resp, &len); + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + conn->host.name, + conn->port, + conn->oauth_bearer, + &resp, &len); /* Failures maybe sent by the server as continuations for OAUTHBEARER */ newstate = SASL_OAUTH2_RESP; } else - result = sasl_create_oauth_bearer_message(data, conn->user, - NULL, 0, - conn->oauth_bearer, - &resp, &len); + result = Curl_auth_create_oauth_bearer_message(data, conn->user, + NULL, 0, + conn->oauth_bearer, + &resp, &len); break; case SASL_OAUTH2_RESP: diff --git a/project/jni/curl/lib/curl_sasl.h b/project/jni/curl/lib/curl_sasl.h index 2175e03d4..6535fedbc 100644 --- a/project/jni/curl/lib/curl_sasl.h +++ b/project/jni/curl/lib/curl_sasl.h @@ -27,18 +27,6 @@ struct SessionHandle; struct connectdata; -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -struct digestdata; -#endif - -#if defined(USE_NTLM) -struct ntlmdata; -#endif - -#if defined(USE_KERBEROS5) -struct kerberos5data; -#endif - /* Authentication mechanism flags */ #define SASL_MECH_LOGIN (1 << 0) #define SASL_MECH_PLAIN (1 << 1) @@ -66,16 +54,6 @@ struct kerberos5data; #define SASL_MECH_STRING_XOAUTH2 "XOAUTH2" #define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER" -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -#define DIGEST_MAX_VALUE_LENGTH 256 -#define DIGEST_MAX_CONTENT_LENGTH 1024 -#endif - -enum { - CURLDIGESTALGO_MD5, - CURLDIGESTALGO_MD5SESS -}; - /* SASL machine states */ typedef enum { SASL_STOP, @@ -136,96 +114,6 @@ struct SASL { (wordlen == (sizeof(mech) - 1) / sizeof(char) && \ !memcmp(line, mech, wordlen)) -/* This is used to build a SPN string */ -#if !defined(USE_WINDOWS_SSPI) -char *Curl_sasl_build_spn(const char *service, const char *instance); -#else -TCHAR *Curl_sasl_build_spn(const char *service, const char *instance); -#endif - -#if defined(HAVE_GSSAPI) -char *Curl_sasl_build_gssapi_spn(const char *service, const char *instance); -#endif - -#ifndef CURL_DISABLE_CRYPTO_AUTH -/* This is used to extract the realm from a challenge message */ -bool Curl_sasl_digest_get_pair(const char *str, char *value, char *content, - const char **endptr); - -/* This is used to generate a base64 encoded DIGEST-MD5 response message */ -CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen); - -/* This is used to decode a HTTP DIGEST challenge message */ -CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, - struct digestdata *digest); - -/* This is used to generate a HTTP DIGEST response message */ -CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uri, - struct digestdata *digest, - char **outptr, size_t *outlen); - -/* This is used to clean up the digest specific data */ -void Curl_sasl_digest_cleanup(struct digestdata *digest); -#endif - -#ifdef USE_NTLM -/* This is used to generate a base64 encoded NTLM type-1 message */ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, - size_t *outlen); - -/* This is used to decode a base64 encoded NTLM type-2 message */ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, - const char *type2msg, - struct ntlmdata *ntlm); - -/* This is used to generate a base64 encoded NTLM type-3 message */ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen); - -/* This is used to clean up the ntlm specific data */ -void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm); - -#endif /* USE_NTLM */ - -#if defined(USE_KERBEROS5) -/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token - message */ -CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const char *service, - const bool mutual, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen); - -/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security - token message */ -CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, - const char *input, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen); - -/* This is used to clean up the gssapi specific data */ -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5); -#endif /* USE_KERBEROS5 */ - /* This is used to cleanup any libraries or curl modules used by the sasl functions */ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused); diff --git a/project/jni/curl/lib/curl_sasl_sspi.c b/project/jni/curl/lib/curl_sasl_sspi.c deleted file mode 100644 index f46376cc4..000000000 --- a/project/jni/curl/lib/curl_sasl_sspi.c +++ /dev/null @@ -1,1295 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 2014 - 2016 Daniel Stenberg, , et al. - * Copyright (C) 2014 - 2016, Steve Holme, . - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * 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. - * - * RFC2617 Basic and Digest Access Authentication - * RFC2831 DIGEST-MD5 authentication - * RFC4422 Simple Authentication and Security Layer (SASL) - * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism - * - ***************************************************************************/ - -#include "curl_setup.h" - -#if defined(USE_WINDOWS_SSPI) - -#include - -#include "curl_sasl.h" -#include "urldata.h" -#include "curl_base64.h" -#include "warnless.h" -#include "curl_multibyte.h" -#include "sendf.h" -#include "strdup.h" -#include "curl_printf.h" -#include "rawstr.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -/* - * Curl_sasl_build_spn() - * - * This is used to build a SPN string in the format service/instance. - * - * Parameters: - * - * serivce [in] - The service type such as www, smtp, pop or imap. - * instance [in] - The host name or realm. - * - * Returns a pointer to the newly allocated SPN. - */ -TCHAR *Curl_sasl_build_spn(const char *service, const char *instance) -{ - char *utf8_spn = NULL; - TCHAR *tchar_spn = NULL; - - /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather - than doing this ourselves but the first is only available in Windows XP - and Windows Server 2003 and the latter is only available in Windows 2000 - but not Windows95/98/ME or Windows NT4.0 unless the Active Directory - Client Extensions are installed. As such it is far simpler for us to - formulate the SPN instead. */ - - /* Allocate our UTF8 based SPN */ - utf8_spn = aprintf("%s/%s", service, instance); - if(!utf8_spn) { - return NULL; - } - - /* Allocate our TCHAR based SPN */ - tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); - if(!tchar_spn) { - free(utf8_spn); - - return NULL; - } - - /* Release the UTF8 variant when operating with Unicode */ - Curl_unicodefree(utf8_spn); - - /* Return our newly allocated SPN */ - return tchar_spn; -} - -#if !defined(CURL_DISABLE_CRYPTO_AUTH) -/* - * Curl_sasl_create_digest_md5_message() - * - * This is used to generate an already encoded DIGEST-MD5 response message - * ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The base64 encoded challenge message. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, - const char *chlg64, - const char *userp, - const char *passwdp, - const char *service, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - TCHAR *spn = NULL; - size_t chlglen = 0; - size_t token_max = 0; - unsigned char *input_token = NULL; - unsigned char *output_token = NULL; - CredHandle credentials; - CtxtHandle context; - PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &input_token, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!input_token) { - infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - if(status != SEC_E_OK) { - free(input_token); - - return CURLE_NOT_BUILT_IN; - } - - token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our response buffer */ - output_token = malloc(token_max); - if(!output_token) { - free(input_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Generate our SPN */ - spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); - if(!spn) { - free(output_token); - free(input_token); - - return CURLE_OUT_OF_MEMORY; - } - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &identity); - if(result) { - free(spn); - free(output_token); - free(input_token); - - return result; - } - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); - free(spn); - free(output_token); - free(input_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = input_token; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - /* Generate our response message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, - 0, 0, 0, &chlg_desc, 0, - &context, &resp_desc, &attrs, - &expiry); - - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - s_pSecFn->FreeCredentialsHandle(&credentials); - Curl_sspi_free_identity(p_identity); - free(spn); - free(output_token); - free(input_token); - - return CURLE_RECV_ERROR; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, - outptr, outlen); - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); - - /* Free the SPN */ - free(spn); - - /* Free the response buffer */ - free(output_token); - - /* Free the decoded challenge message */ - free(input_token); - - return result; -} - -/* - * Curl_override_sspi_http_realm() - * - * This is used to populate the domain in a SSPI identity structure - * The realm is extracted from the challenge message and used as the - * domain if it is not already explicitly set. - * - * Parameters: - * - * chlg [in] - The challenge message. - * identity [in/out] - The identity structure. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity) -{ - xcharp_u domain, dup_domain; - - /* If domain is blank or unset, check challenge message for realm */ - if(!identity->Domain || !identity->DomainLength) { - for(;;) { - char value[DIGEST_MAX_VALUE_LENGTH]; - char content[DIGEST_MAX_CONTENT_LENGTH]; - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Extract a value=content pair */ - if(Curl_sasl_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "realm")) { - - /* Setup identity's domain and length */ - domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)content); - if(!domain.tchar_ptr) - return CURLE_OUT_OF_MEMORY; - dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); - if(!dup_domain.tchar_ptr) { - Curl_unicodefree(domain.tchar_ptr); - return CURLE_OUT_OF_MEMORY; - } - free(identity->Domain); - identity->Domain = dup_domain.tbyte_ptr; - identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); - dup_domain.tchar_ptr = NULL; - - Curl_unicodefree(domain.tchar_ptr); - } - else { - /* unknown specifier, ignore it! */ - } - } - else - break; /* we're done here */ - - /* Pass all additional spaces here */ - while(*chlg && ISSPACE(*chlg)) - chlg++; - - /* Allow the list to be comma-separated */ - if(',' == *chlg) - chlg++; - } - } - - return CURLE_OK; -} - -/* - * Curl_sasl_decode_digest_http_message() - * - * This is used to decode a HTTP DIGEST challenge message into the seperate - * attributes. - * - * Parameters: - * - * chlg [in] - The challenge message. - * digest [in/out] - The digest data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_decode_digest_http_message(const char *chlg, - struct digestdata *digest) -{ - size_t chlglen = strlen(chlg); - - /* We had an input token before and we got another one now. This means we - provided bad credentials in the previous request. */ - if(digest->input_token) - return CURLE_BAD_CONTENT_ENCODING; - - /* Simply store the challenge for use later */ - digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); - if(!digest->input_token) - return CURLE_OUT_OF_MEMORY; - - digest->input_token_len = chlglen; - - return CURLE_OK; -} - -/* - * Curl_sasl_create_digest_http_message() - * - * This is used to generate a HTTP DIGEST response message ready for sending - * to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * request [in] - The HTTP request. - * uripath [in] - The path of the HTTP uri. - * digest [in/out] - The digest data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_digest_http_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const unsigned char *request, - const unsigned char *uripath, - struct digestdata *digest, - char **outptr, size_t *outlen) -{ - size_t token_max; - CredHandle credentials; - CtxtHandle context; - char *resp; - BYTE *output_token; - PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf[3]; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - TCHAR *spn; - - (void) data; - - /* Query the security package for DigestSSP */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate the output buffer according to the max token size as indicated - by the security package */ - output_token = malloc(token_max); - if(!output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - if(Curl_create_sspi_identity(userp, passwdp, &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Populate our identity domain */ - if(Curl_override_sspi_http_realm((const char*)digest->input_token, - &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer if present */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 3; - chlg_desc.pBuffers = chlg_buf; - chlg_buf[0].BufferType = SECBUFFER_TOKEN; - chlg_buf[0].pvBuffer = digest->input_token; - chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); - chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[1].pvBuffer = (void *)request; - chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); - chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[2].pvBuffer = NULL; - chlg_buf[2].cbBuffer = 0; - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - spn = Curl_convert_UTF8_to_tchar((char *) uripath); - if(!spn) { - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Generate our reponse message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, - spn, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, &context, - &resp_desc, &attrs, &expiry); - Curl_unicodefree(spn); - - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - s_pSecFn->FreeCredentialsHandle(&credentials); - - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - resp = malloc(resp_buf.cbBuffer + 1); - if(!resp) { - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_OUT_OF_MEMORY; - } - - /* Copy the generated reponse */ - memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); - resp[resp_buf.cbBuffer] = 0x00; - - /* Return the response */ - *outptr = resp; - *outlen = resp_buf.cbBuffer; - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); - - /* Free the response buffer */ - free(output_token); - - return CURLE_OK; -} - -/* - * Curl_sasl_digest_cleanup() - * - * This is used to clean up the digest specific data. - * - * Parameters: - * - * digest [in/out] - The digest data struct being cleaned up. - * - */ -void Curl_sasl_digest_cleanup(struct digestdata *digest) -{ - /* Free the input token */ - Curl_safefree(digest->input_token); - - /* Reset any variables */ - digest->input_token_len = 0; -} -#endif /* !CURL_DISABLE_CRYPTO_AUTH */ - -#if defined USE_NTLM -/* - * Curl_sasl_create_ntlm_type1_message() - * - * This is used to generate an already encoded NTLM type-1 message ready for - * sending to the recipient. - * - * Parameters: - * - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * ntlm [in/out] - The NTLM data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - PSecPkgInfo SecurityPackage; - SecBuffer type_1_buf; - SecBufferDesc type_1_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - /* Clean up any former leftovers and initialise to defaults */ - Curl_sasl_ntlm_cleanup(ntlm); - - /* Query the security package for NTLM */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - ntlm->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our output buffer */ - ntlm->output_token = malloc(ntlm->token_max); - if(!ntlm->output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - CURLcode result; - - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - ntlm->p_identity = &ntlm->identity; - } - else - /* Use the current Windows user */ - ntlm->p_identity = NULL; - - /* Allocate our credentials handle */ - ntlm->credentials = malloc(sizeof(CredHandle)); - if(!ntlm->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(ntlm->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_NTLM), - SECPKG_CRED_OUTBOUND, NULL, - ntlm->p_identity, NULL, NULL, - ntlm->credentials, &expiry); - if(status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - ntlm->context = malloc(sizeof(CtxtHandle)); - if(!ntlm->context) - return CURLE_OUT_OF_MEMORY; - - memset(ntlm->context, 0, sizeof(CtxtHandle)); - - /* Setup the type-1 "output" security buffer */ - type_1_desc.ulVersion = SECBUFFER_VERSION; - type_1_desc.cBuffers = 1; - type_1_desc.pBuffers = &type_1_buf; - type_1_buf.BufferType = SECBUFFER_TOKEN; - type_1_buf.pvBuffer = ntlm->output_token; - type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); - - /* Generate our type-1 message */ - status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, - (TCHAR *) TEXT(""), - 0, 0, SECURITY_NETWORK_DREP, - NULL, 0, - ntlm->context, &type_1_desc, - &attrs, &expiry); - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) - return CURLE_RECV_ERROR; - - /* Base64 encode the response */ - return Curl_base64_encode(NULL, (char *) ntlm->output_token, - type_1_buf.cbBuffer, outptr, outlen); -} - -/* - * Curl_sasl_decode_ntlm_type2_message() - * - * This is used to decode an already encoded NTLM type-2 message. - * - * Parameters: - * - * data [in] - The session handle. - * type2msg [in] - The base64 encoded type-2 message. - * ntlm [in/out] - The NTLM data struct being used and modified. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, - const char *type2msg, - struct ntlmdata *ntlm) -{ - CURLcode result = CURLE_OK; - unsigned char *type2 = NULL; - size_t type2_len = 0; - -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; -#endif - - /* Decode the base-64 encoded type-2 message */ - if(strlen(type2msg) && *type2msg != '=') { - result = Curl_base64_decode(type2msg, &type2, &type2_len); - if(result) - return result; - } - - /* Ensure we have a valid type-2 message */ - if(!type2) { - infof(data, "NTLM handshake failure (empty type-2 message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Simply store the challenge for use later */ - ntlm->input_token = type2; - ntlm->input_token_len = type2_len; - - return result; -} - -/* - * Curl_sasl_create_ntlm_type3_message() - * - * This is used to generate an already encoded NTLM type-3 message ready for - * sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * ntlm [in/out] - The NTLM data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - struct ntlmdata *ntlm, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - SecBuffer type_2_buf; - SecBuffer type_3_buf; - SecBufferDesc type_2_desc; - SecBufferDesc type_3_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - (void) passwdp; - (void) userp; - - /* Setup the type-2 "input" security buffer */ - type_2_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2_buf; - type_2_buf.BufferType = SECBUFFER_TOKEN; - type_2_buf.pvBuffer = ntlm->input_token; - type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); - - /* Setup the type-3 "output" security buffer */ - type_3_desc.ulVersion = SECBUFFER_VERSION; - type_3_desc.cBuffers = 1; - type_3_desc.pBuffers = &type_3_buf; - type_3_buf.BufferType = SECBUFFER_TOKEN; - type_3_buf.pvBuffer = ntlm->output_token; - type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); - - /* Generate our type-3 message */ - status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, - ntlm->context, - (TCHAR *) TEXT(""), - 0, 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, ntlm->context, - &type_3_desc, - &attrs, &expiry); - if(status != SEC_E_OK) { - infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", - status); - - return CURLE_RECV_ERROR; - } - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *) ntlm->output_token, - type_3_buf.cbBuffer, outptr, outlen); - - Curl_sasl_ntlm_cleanup(ntlm); - - return result; -} - -/* - * Curl_sasl_ntlm_cleanup() - * - * This is used to clean up the NTLM specific data. - * - * Parameters: - * - * ntlm [in/out] - The NTLM data struct being cleaned up. - * - */ -void Curl_sasl_ntlm_cleanup(struct ntlmdata *ntlm) -{ - /* Free our security context */ - if(ntlm->context) { - s_pSecFn->DeleteSecurityContext(ntlm->context); - free(ntlm->context); - ntlm->context = NULL; - } - - /* Free our credentials handle */ - if(ntlm->credentials) { - s_pSecFn->FreeCredentialsHandle(ntlm->credentials); - free(ntlm->credentials); - ntlm->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(ntlm->p_identity); - ntlm->p_identity = NULL; - - /* Free the input and output tokens */ - Curl_safefree(ntlm->input_token); - Curl_safefree(ntlm->output_token); - - /* Reset any variables */ - ntlm->token_max = 0; -} -#endif /* USE_NTLM */ - -#if defined(USE_KERBEROS5) -/* - * Curl_sasl_create_gssapi_user_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) user token - * message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * userp [in] - The user name in the format User or Domain\User. - * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. - * mutual_auth [in] - Flag specifing whether or not mutual authentication - * is enabled. - * chlg64 [in] - The optional base64 encoded challenge message. - * krb5 [in/out] - The Kerberos 5 data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, - const char *userp, - const char *passwdp, - const char *service, - const bool mutual_auth, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t chlglen = 0; - unsigned char *chlg = NULL; - CtxtHandle context; - PSecPkgInfo SecurityPackage; - SecBuffer chlg_buf; - SecBuffer resp_buf; - SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - - if(!krb5->credentials) { - /* Query the security package for Kerberos */ - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_KERBEROS), - &SecurityPackage); - if(status != SEC_E_OK) { - return CURLE_NOT_BUILT_IN; - } - - krb5->token_max = SecurityPackage->cbMaxToken; - - /* Release the package buffer as it is not required anymore */ - s_pSecFn->FreeContextBuffer(SecurityPackage); - - /* Allocate our response buffer */ - krb5->output_token = malloc(krb5->token_max); - if(!krb5->output_token) - return CURLE_OUT_OF_MEMORY; - - /* Generate our SPN */ - krb5->spn = Curl_sasl_build_spn(service, data->easy_conn->host.name); - if(!krb5->spn) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - krb5->p_identity = &krb5->identity; - } - else - /* Use the current Windows user */ - krb5->p_identity = NULL; - - /* Allocate our credentials handle */ - krb5->credentials = malloc(sizeof(CredHandle)); - if(!krb5->credentials) - return CURLE_OUT_OF_MEMORY; - - memset(krb5->credentials, 0, sizeof(CredHandle)); - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) - TEXT(SP_NAME_KERBEROS), - SECPKG_CRED_OUTBOUND, NULL, - krb5->p_identity, NULL, NULL, - krb5->credentials, &expiry); - if(status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - - /* Allocate our new context handle */ - krb5->context = malloc(sizeof(CtxtHandle)); - if(!krb5->context) - return CURLE_OUT_OF_MEMORY; - - memset(krb5->context, 0, sizeof(CtxtHandle)); - } - else { - /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Setup the challenge "input" security buffer */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 1; - chlg_desc.pBuffers = &chlg_buf; - chlg_buf.BufferType = SECBUFFER_TOKEN; - chlg_buf.pvBuffer = chlg; - chlg_buf.cbBuffer = curlx_uztoul(chlglen); - } - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = krb5->output_token; - resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); - - /* Generate our challenge-response message */ - status = s_pSecFn->InitializeSecurityContext(krb5->credentials, - chlg ? krb5->context : NULL, - krb5->spn, - (mutual_auth ? - ISC_REQ_MUTUAL_AUTH : 0), - 0, SECURITY_NATIVE_DREP, - chlg ? &chlg_desc : NULL, 0, - &context, - &resp_desc, &attrs, - &expiry); - - if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { - free(chlg); - - return CURLE_RECV_ERROR; - } - - if(memcmp(&context, krb5->context, sizeof(context))) { - s_pSecFn->DeleteSecurityContext(krb5->context); - - memcpy(krb5->context, &context, sizeof(context)); - } - - if(resp_buf.cbBuffer) { - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *)resp_buf.pvBuffer, - resp_buf.cbBuffer, outptr, outlen); - } - - /* Free the decoded challenge */ - free(chlg); - - return result; -} - -/* - * Curl_sasl_create_gssapi_security_message() - * - * This is used to generate an already encoded GSSAPI (Kerberos V5) security - * token message ready for sending to the recipient. - * - * Parameters: - * - * data [in] - The session handle. - * chlg64 [in] - The optional base64 encoded challenge message. - * krb5 [in/out] - The Kerberos 5 data struct being used and modified. - * outptr [in/out] - The address where a pointer to newly allocated memory - * holding the result will be stored upon completion. - * outlen [out] - The length of the output message. - * - * Returns CURLE_OK on success. - */ -CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, - const char *chlg64, - struct kerberos5data *krb5, - char **outptr, - size_t *outlen) -{ - CURLcode result = CURLE_OK; - size_t offset = 0; - size_t chlglen = 0; - size_t messagelen = 0; - size_t appdatalen = 0; - unsigned char *chlg = NULL; - unsigned char *trailer = NULL; - unsigned char *message = NULL; - unsigned char *padding = NULL; - unsigned char *appdata = NULL; - SecBuffer input_buf[2]; - SecBuffer wrap_buf[3]; - SecBufferDesc input_desc; - SecBufferDesc wrap_desc; - unsigned long indata = 0; - unsigned long outdata = 0; - unsigned long qop = 0; - unsigned long sec_layer = 0; - unsigned long max_size = 0; - SecPkgContext_Sizes sizes; - SecPkgCredentials_Names names; - SECURITY_STATUS status; - char *user_name; - - /* Decode the base-64 encoded input message */ - if(strlen(chlg64) && *chlg64 != '=') { - result = Curl_base64_decode(chlg64, &chlg, &chlglen); - if(result) - return result; - } - - /* Ensure we have a valid challenge message */ - if(!chlg) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Get our response size information */ - status = s_pSecFn->QueryContextAttributes(krb5->context, - SECPKG_ATTR_SIZES, - &sizes); - if(status != SEC_E_OK) { - free(chlg); - - return CURLE_OUT_OF_MEMORY; - } - - /* Get the fully qualified username back from the context */ - status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, - SECPKG_CRED_ATTR_NAMES, - &names); - if(status != SEC_E_OK) { - free(chlg); - - return CURLE_RECV_ERROR; - } - - /* Setup the "input" security buffer */ - input_desc.ulVersion = SECBUFFER_VERSION; - input_desc.cBuffers = 2; - input_desc.pBuffers = input_buf; - input_buf[0].BufferType = SECBUFFER_STREAM; - input_buf[0].pvBuffer = chlg; - input_buf[0].cbBuffer = curlx_uztoul(chlglen); - input_buf[1].BufferType = SECBUFFER_DATA; - input_buf[1].pvBuffer = NULL; - input_buf[1].cbBuffer = 0; - - /* Decrypt the inbound challenge and obtain the qop */ - status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); - if(status != SEC_E_OK) { - infof(data, "GSSAPI handshake failure (empty security message)\n"); - - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ - if(input_buf[1].cbBuffer != 4) { - infof(data, "GSSAPI handshake failure (invalid security data)\n"); - - free(chlg); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Copy the data out and free the challenge as it is not required anymore */ - memcpy(&indata, input_buf[1].pvBuffer, 4); - s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); - free(chlg); - - /* Extract the security layer */ - sec_layer = indata & 0x000000FF; - if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { - infof(data, "GSSAPI handshake failure (invalid security layer)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - - /* Extract the maximum message size the server can receive */ - max_size = ntohl(indata & 0xFFFFFF00); - if(max_size > 0) { - /* The server has told us it supports a maximum receive buffer, however, as - we don't require one unless we are encrypting data, we tell the server - our receive buffer is zero. */ - max_size = 0; - } - - /* Allocate the trailer */ - trailer = malloc(sizes.cbSecurityTrailer); - if(!trailer) - return CURLE_OUT_OF_MEMORY; - - /* Convert the user name to UTF8 when operating with Unicode */ - user_name = Curl_convert_tchar_to_UTF8(names.sUserName); - if(!user_name) { - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate our message */ - messagelen = sizeof(outdata) + strlen(user_name) + 1; - message = malloc(messagelen); - if(!message) { - free(trailer); - Curl_unicodefree(user_name); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the message with the security layer, client supported receive - message size and authorization identity including the 0x00 based - terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization - identity is not terminated with the zero-valued (%x00) octet." it seems - necessary to include it. */ - outdata = htonl(max_size) | sec_layer; - memcpy(message, &outdata, sizeof(outdata)); - strcpy((char *) message + sizeof(outdata), user_name); - Curl_unicodefree(user_name); - - /* Allocate the padding */ - padding = malloc(sizes.cbBlockSize); - if(!padding) { - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Setup the "authentication data" security buffer */ - wrap_desc.ulVersion = SECBUFFER_VERSION; - wrap_desc.cBuffers = 3; - wrap_desc.pBuffers = wrap_buf; - wrap_buf[0].BufferType = SECBUFFER_TOKEN; - wrap_buf[0].pvBuffer = trailer; - wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; - wrap_buf[1].BufferType = SECBUFFER_DATA; - wrap_buf[1].pvBuffer = message; - wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); - wrap_buf[2].BufferType = SECBUFFER_PADDING; - wrap_buf[2].pvBuffer = padding; - wrap_buf[2].cbBuffer = sizes.cbBlockSize; - - /* Encrypt the data */ - status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, - &wrap_desc, 0); - if(status != SEC_E_OK) { - free(padding); - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Allocate the encryption (wrap) buffer */ - appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + - wrap_buf[2].cbBuffer; - appdata = malloc(appdatalen); - if(!appdata) { - free(padding); - free(message); - free(trailer); - - return CURLE_OUT_OF_MEMORY; - } - - /* Populate the encryption buffer */ - memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); - offset += wrap_buf[0].cbBuffer; - memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); - offset += wrap_buf[1].cbBuffer; - memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); - - /* Base64 encode the response */ - result = Curl_base64_encode(data, (char *)appdata, appdatalen, outptr, - outlen); - - /* Free all of our local buffers */ - free(appdata); - free(padding); - free(message); - free(trailer); - - return result; -} - -/* - * Curl_sasl_gssapi_cleanup() - * - * This is used to clean up the GSSAPI (Kerberos V5) specific data. - * - * Parameters: - * - * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. - * - */ -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) -{ - /* Free our security context */ - if(krb5->context) { - s_pSecFn->DeleteSecurityContext(krb5->context); - free(krb5->context); - krb5->context = NULL; - } - - /* Free our credentials handle */ - if(krb5->credentials) { - s_pSecFn->FreeCredentialsHandle(krb5->credentials); - free(krb5->credentials); - krb5->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(krb5->p_identity); - krb5->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(krb5->spn); - Curl_safefree(krb5->output_token); - - /* Reset any variables */ - krb5->token_max = 0; -} -#endif /* USE_KERBEROS5 */ - -#endif /* USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/curl_setup.h b/project/jni/curl/lib/curl_setup.h index 516327345..d78873fe5 100644 --- a/project/jni/curl/lib/curl_setup.h +++ b/project/jni/curl/lib/curl_setup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -473,7 +473,7 @@ # endif # ifndef fileno /* sunos 4 have this as a macro! */ - int fileno( FILE *stream); + int fileno(FILE *stream); # endif #endif /* WIN32 */ @@ -722,4 +722,19 @@ endings either CRLF or LF so 't' is appropriate. #define FOPEN_WRITETEXT "w" #endif +/* WinSock destroys recv() buffer when send() failed. + * Enabled automatically for Windows and for Cygwin as Cygwin sockets are + * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657 + * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround. + */ +#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND) +# if defined(WIN32) || defined(__CYGWIN__) +# define USE_RECV_BEFORE_SEND_WORKAROUND +# endif +#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ +# ifdef USE_RECV_BEFORE_SEND_WORKAROUND +# undef USE_RECV_BEFORE_SEND_WORKAROUND +# endif +#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ + #endif /* HEADER_CURL_SETUP_H */ diff --git a/project/jni/curl/lib/curl_threads.c b/project/jni/curl/lib/curl_threads.c index 59d881143..c98d8bbad 100644 --- a/project/jni/curl/lib/curl_threads.c +++ b/project/jni/curl/lib/curl_threads.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #if defined(USE_THREADS_POSIX) # ifdef HAVE_PTHREAD_H # include diff --git a/project/jni/curl/lib/dotdot.c b/project/jni/curl/lib/dotdot.c index 99fac7f98..ea7c8a04f 100644 --- a/project/jni/curl/lib/dotdot.c +++ b/project/jni/curl/lib/dotdot.c @@ -22,9 +22,11 @@ #include "curl_setup.h" -#include "dotdot.h" +#include +#include "dotdot.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" diff --git a/project/jni/curl/lib/easy.c b/project/jni/curl/lib/easy.c index 2bddbb22f..ea7af5e52 100644 --- a/project/jni/curl/lib/easy.c +++ b/project/jni/curl/lib/easy.c @@ -73,9 +73,8 @@ #include "multiif.h" #include "sigpipe.h" #include "ssh.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -121,8 +120,8 @@ static CURLcode win32_init(void) /* wVersionRequested in wVersion. wHighVersion contains the */ /* highest supported version. */ - if(LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) || - HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) { + if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) || + HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) { /* Tell the user that we couldn't find a useable */ /* winsock.dll. */ @@ -625,7 +624,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(0 == pollrc) { /* timeout! */ ev->ms = 0; - /* fprintf(stderr, "call curl_multi_socket_action( TIMEOUT )\n"); */ + /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */ mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &ev->running_handles); } @@ -635,7 +634,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) if(fds[i].revents) { /* socket activity, tell libcurl */ int act = poll2cselect(fds[i].revents); /* convert */ - infof(multi->easyp, "call curl_multi_socket_action( socket %d )\n", + infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n", fds[i].fd); mcode = curl_multi_socket_action(multi, fds[i].fd, act, &ev->running_handles); diff --git a/project/jni/curl/lib/escape.c b/project/jni/curl/lib/escape.c index 40338a904..2c6a7f655 100644 --- a/project/jni/curl/lib/escape.c +++ b/project/jni/curl/lib/escape.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,9 +31,8 @@ #include "warnless.h" #include "non-ascii.h" #include "escape.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -105,7 +104,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) alloc *= 2; testing_ptr = realloc(ns, alloc); if(!testing_ptr) { - free( ns ); + free(ns); return NULL; } else { diff --git a/project/jni/curl/lib/file.c b/project/jni/curl/lib/file.c index 5c31fc4f7..1eeb84d5a 100644 --- a/project/jni/curl/lib/file.c +++ b/project/jni/curl/lib/file.c @@ -61,9 +61,8 @@ #include "url.h" #include "parsedate.h" /* for the week day and month names */ #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -368,7 +367,7 @@ static CURLcode file_upload(struct connectdata *conn) /*skip bytes before resume point*/ if(data->state.resume_from) { - if((curl_off_t)nread <= data->state.resume_from ) { + if((curl_off_t)nread <= data->state.resume_from) { data->state.resume_from -= nread; nread = 0; buf2 = buf; @@ -469,6 +468,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done) information. Which for FILE can't be much more than the file size and date. */ if(data->set.opt_no_body && data->set.include_header && fstated) { + time_t filetime; + struct tm buffer; + const struct tm *tm = &buffer; snprintf(buf, sizeof(data->state.buffer), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); @@ -480,29 +482,24 @@ static CURLcode file_do(struct connectdata *conn, bool *done) if(result) return result; - if(fstated) { - time_t filetime = (time_t)statbuf.st_mtime; - struct tm buffer; - const struct tm *tm = &buffer; - result = Curl_gmtime(filetime, &buffer); - if(result) - return result; + filetime = (time_t)statbuf.st_mtime; + result = Curl_gmtime(filetime, &buffer); + if(result) + return result; - /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ - snprintf(buf, BUFSIZE-1, - "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", - Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], - tm->tm_mday, - Curl_month[tm->tm_mon], - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); - result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); - } - /* if we fstat()ed the file, set the file size to make it available post- - transfer */ - if(fstated) + /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ + snprintf(buf, BUFSIZE-1, + "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n", + Curl_wkday[tm->tm_wday?tm->tm_wday-1:6], + tm->tm_mday, + Curl_month[tm->tm_mon], + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); + result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); + if(!result) + /* set the file size to make it available post transfer */ Curl_pgrsSetDownloadSize(data, expected_size); return result; } diff --git a/project/jni/curl/lib/formdata.c b/project/jni/curl/lib/formdata.c index c241e6e9b..a71f099c8 100644 --- a/project/jni/curl/lib/formdata.c +++ b/project/jni/curl/lib/formdata.c @@ -36,9 +36,8 @@ #include "strequal.h" #include "sendf.h" #include "strdup.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -632,7 +631,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, else { if(((form->flags & HTTPPOST_FILENAME) || (form->flags & HTTPPOST_BUFFER)) && - !form->contenttype ) { + !form->contenttype) { char *f = form->flags & HTTPPOST_BUFFER? form->showfilename : form->value; @@ -770,7 +769,7 @@ curl_off_t VmsRealFileSize(const char * name, int ret_stat; FILE * file; - file = fopen(name, "r"); /* VMS */ + file = fopen(name, FOPEN_READTEXT); /* VMS */ if(file == NULL) return 0; @@ -1273,7 +1272,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, curList = file->contentheader; while(curList) { /* Process the additional headers specified for this form */ - result = AddFormDataf( &form, &size, "\r\n%s", curList->data ); + result = AddFormDataf(&form, &size, "\r\n%s", curList->data); if(result) break; curList = curList->next; @@ -1386,7 +1385,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, * Curl_FormInit() inits the struct 'form' points to with the 'formdata' * and resets the 'sent' counter. */ -int Curl_FormInit(struct Form *form, struct FormData *formdata ) +int Curl_FormInit(struct Form *form, struct FormData *formdata) { if(!formdata) return 1; /* error */ @@ -1421,10 +1420,10 @@ static FILE * vmsfopenread(const char *file, const char *mode) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: - return fopen(file, "r"); /* VMS */ + return fopen(file, FOPEN_READTEXT); /* VMS */ break; default: - return fopen(file, "r", "rfm=stmlf", "ctx=stm"); + return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm"); } } #endif @@ -1499,9 +1498,9 @@ size_t Curl_FormReader(char *buffer, } do { - if((form->data->length - form->sent ) > wantedsize - gotsize) { + if((form->data->length - form->sent) > wantedsize - gotsize) { - memcpy(buffer + gotsize , form->data->line + form->sent, + memcpy(buffer + gotsize, form->data->line + form->sent, wantedsize - gotsize); form->sent += wantedsize-gotsize; diff --git a/project/jni/curl/lib/formdata.h b/project/jni/curl/lib/formdata.h index 3fe1e83bd..a5ebc1d45 100644 --- a/project/jni/curl/lib/formdata.h +++ b/project/jni/curl/lib/formdata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -68,7 +68,7 @@ typedef struct FormInfo { struct FormInfo *more; } FormInfo; -int Curl_FormInit(struct Form *form, struct FormData *formdata ); +int Curl_FormInit(struct Form *form, struct FormData *formdata); CURLcode Curl_getformdata(struct SessionHandle *data, struct FormData **, diff --git a/project/jni/curl/lib/ftp.c b/project/jni/curl/lib/ftp.c index 9b728cc98..cfa1bbb80 100644 --- a/project/jni/curl/lib/ftp.c +++ b/project/jni/curl/lib/ftp.c @@ -77,10 +77,9 @@ #include "warnless.h" #include "http_proxy.h" #include "non-ascii.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #ifndef NI_MAXHOST @@ -710,7 +709,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ /* check and reset timeout value every lap */ timeout = Curl_pp_state_timeout(pp); - if(timeout <=0 ) { + if(timeout <=0) { failf(data, "FTP response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } @@ -1036,7 +1035,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(*string_ftpport == '[') { /* [ipv6]:port(-range) */ ip_start = string_ftpport + 1; - if((ip_end = strchr(string_ftpport, ']')) != NULL ) + if((ip_end = strchr(string_ftpport, ']')) != NULL) strncpy(addr, ip_start, ip_end - ip_start); } else @@ -1057,7 +1056,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, else #endif /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start ); + strncpy(addr, string_ftpport, ip_end - ip_start); } else /* ipv4|interface */ @@ -1077,11 +1076,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* correct errors like: * :1234-1230 - * :-4711 , in this case port_min is (unsigned)-1, + * :-4711, in this case port_min is (unsigned)-1, * therefore port_min > port_max for all cases * but port_max = (unsigned)-1 */ - if(port_min > port_max ) + if(port_min > port_max) port_min = port_max = 0; @@ -1525,12 +1524,12 @@ static CURLcode ftp_state_list(struct connectdata *conn) } } - cmd = aprintf( "%s%s%s", - data->set.str[STRING_CUSTOMREQUEST]? - data->set.str[STRING_CUSTOMREQUEST]: - (data->set.ftp_list_only?"NLST":"LIST"), - lstArg? " ": "", - lstArg? lstArg: "" ); + cmd = aprintf("%s%s%s", + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: + (data->set.ftp_list_only?"NLST":"LIST"), + lstArg? " ": "", + lstArg? lstArg: ""); if(!cmd) { free(lstArg); @@ -1652,7 +1651,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, /* 4. lower the infilesize counter */ /* => transfer as usual */ - if(data->state.resume_from < 0 ) { + if(data->state.resume_from < 0) { /* Got no given size to start from, figure it out */ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_STOR_SIZE); @@ -3242,7 +3241,7 @@ static CURLcode ftp_connect(struct connectdata *conn, * Input argument is already checked for validity. */ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, - bool premature) + bool premature) { struct SessionHandle *data = conn->data; struct FTP *ftp = data->req.protop; @@ -3256,11 +3255,6 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, const char *path_to_use = data->state.path; if(!ftp) - /* When the easy handle is removed from the multi while libcurl is still - * trying to resolve the host name, it seems that the ftp struct is not - * yet initialized, but the removal action calls Curl_done() which calls - * this function. So we simply return success if no ftp pointer is set. - */ return CURLE_OK; switch(status) { diff --git a/project/jni/curl/lib/getinfo.c b/project/jni/curl/lib/getinfo.c index 39189cb60..d4b01bf29 100644 --- a/project/jni/curl/lib/getinfo.c +++ b/project/jni/curl/lib/getinfo.c @@ -307,7 +307,7 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, #elif defined(USE_GSKIT) tsi->internals = (void *)conn->ssl[i].handle; #elif defined(USE_MBEDTLS) - tsi->internals = (void *)&conn->ssl[i].ssn; + tsi->internals = (void *)&conn->ssl[i].ssl; #elif defined(USE_NSS) tsi->internals = (void *)conn->ssl[i].handle; #elif defined(USE_OPENSSL) @@ -316,7 +316,7 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, (void *)conn->ssl[i].ctx : (void *)conn->ssl[i].handle); #elif defined(USE_POLARSSL) - tsi->internals = (void *)&conn->ssl[i].ssn; + tsi->internals = (void *)&conn->ssl[i].ssl; #elif defined(USE_SCHANNEL) tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle; #elif defined(USE_SSL) diff --git a/project/jni/curl/lib/hash.c b/project/jni/curl/lib/hash.c index a0889783d..937381b65 100644 --- a/project/jni/curl/lib/hash.c +++ b/project/jni/curl/lib/hash.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,9 +22,12 @@ #include "curl_setup.h" +#include + #include "hash.h" #include "llist.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" diff --git a/project/jni/curl/lib/hmac.c b/project/jni/curl/lib/hmac.c index 664c77418..3df471585 100644 --- a/project/jni/curl/lib/hmac.c +++ b/project/jni/curl/lib/hmac.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,8 +26,11 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include + #include "curl_hmac.h" #include "curl_memory.h" + /* The last #include file should be: */ #include "memdebug.h" diff --git a/project/jni/curl/lib/hostip.c b/project/jni/curl/lib/hostip.c index a4bde568f..ead78de72 100644 --- a/project/jni/curl/lib/hostip.c +++ b/project/jni/curl/lib/hostip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,9 +56,9 @@ #include "url.h" #include "inet_ntop.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #if defined(CURLRES_SYNCH) && \ @@ -353,7 +353,8 @@ Curl_fetch_addr(struct connectdata *conn, dns = fetch_addr(conn, hostname, port); - if(dns) dns->inuse++; /* we use it! */ + if(dns) + dns->inuse++; /* we use it! */ if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -777,7 +778,7 @@ CURLcode Curl_loadhostpairs(struct SessionHandle *data) char address[256]; int port; - for(hostp = data->change.resolve; hostp; hostp = hostp->next ) { + for(hostp = data->change.resolve; hostp; hostp = hostp->next) { if(!hostp->data) continue; if(hostp->data[0] == '-') { diff --git a/project/jni/curl/lib/hostip4.c b/project/jni/curl/lib/hostip4.c index 25c452965..15895d7ce 100644 --- a/project/jni/curl/lib/hostip4.c +++ b/project/jni/curl/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -48,9 +48,9 @@ #include "strerror.h" #include "url.h" #include "inet_pton.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** diff --git a/project/jni/curl/lib/hostip6.c b/project/jni/curl/lib/hostip6.c index 2f58376d2..59bc4e4ac 100644 --- a/project/jni/curl/lib/hostip6.c +++ b/project/jni/curl/lib/hostip6.c @@ -49,10 +49,9 @@ #include "url.h" #include "inet_pton.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" - -/* The last #include file should be: */ #include "memdebug.h" /*********************************************************************** diff --git a/project/jni/curl/lib/http.c b/project/jni/curl/lib/http.c index b85ff0d5a..6a76b88ed 100644 --- a/project/jni/curl/lib/http.c +++ b/project/jni/curl/lib/http.c @@ -54,9 +54,10 @@ #include "curl_base64.h" #include "cookie.h" #include "strequal.h" +#include "vauth/vauth.h" #include "vtls/vtls.h" #include "http_digest.h" -#include "curl_ntlm.h" +#include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "http_negotiate.h" #include "url.h" @@ -76,9 +77,9 @@ #include "pipeline.h" #include "http2.h" #include "connect.h" -#include "curl_printf.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" @@ -144,11 +145,10 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* readwrite */ PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL | PROTOPT_CREDSPERREQUEST /* flags */ + PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ }; #endif - CURLcode Curl_http_setup_conn(struct connectdata *conn) { /* allocate the HTTP-specific struct for the SessionHandle, only to survive @@ -185,6 +185,7 @@ char *Curl_checkheaders(const struct connectdata *conn, if(Curl_raw_nequal(head->data, thisheader, thislen)) return head->data; } + return NULL; } @@ -196,7 +197,6 @@ char *Curl_checkheaders(const struct connectdata *conn, * It takes a connectdata struct as input instead of the SessionHandle simply * to know if this is a proxy request or not, as it then might check a * different header list. - * */ char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader) @@ -205,12 +205,13 @@ char *Curl_checkProxyheaders(const struct connectdata *conn, size_t thislen = strlen(thisheader); struct SessionHandle *data = conn->data; - for(head = (conn->bits.proxy && data->set.sep_headers)? - data->set.proxyheaders:data->set.headers; + for(head = (conn->bits.proxy && data->set.sep_headers) ? + data->set.proxyheaders : data->set.headers; head; head=head->next) { if(Curl_raw_nequal(head->data, thisheader, thislen)) return head->data; } + return NULL; } @@ -309,7 +310,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) free(*userp); *userp = aprintf("%sAuthorization: Basic %s\r\n", - proxy?"Proxy-":"", + proxy ? "Proxy-" : "", authorization); free(authorization); if(!*userp) @@ -528,7 +529,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) return result; } } - else if((data->req.httpcode < 300) && (!data->state.authhost.done) && conn->bits.authneg) { @@ -553,7 +553,6 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) return result; } - /* * Output the correct authentication header depending on the auth type * and whether or not it is to a proxy. @@ -584,7 +583,7 @@ output_auth_headers(struct connectdata *conn, negdata->state = GSS_AUTHNONE; if((authstatus->picked == CURLAUTH_NEGOTIATE) && negdata->context && !GSS_ERROR(negdata->status)) { - auth="Negotiate"; + auth = "Negotiate"; result = Curl_output_negotiate(conn, proxy); if(result) return result; @@ -595,7 +594,7 @@ output_auth_headers(struct connectdata *conn, #endif #ifdef USE_NTLM if(authstatus->picked == CURLAUTH_NTLM) { - auth="NTLM"; + auth = "NTLM"; result = Curl_output_ntlm(conn, proxy); if(result) return result; @@ -613,7 +612,7 @@ output_auth_headers(struct connectdata *conn, #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(authstatus->picked == CURLAUTH_DIGEST) { - auth="Digest"; + auth = "Digest"; result = Curl_output_digest(conn, proxy, (const unsigned char *)request, @@ -629,11 +628,12 @@ output_auth_headers(struct connectdata *conn, !Curl_checkProxyheaders(conn, "Proxy-authorization:")) || (!proxy && conn->bits.user_passwd && !Curl_checkheaders(conn, "Authorization:"))) { - auth="Basic"; + auth = "Basic"; result = http_output_basic(conn, proxy); if(result) return result; } + /* NOTE: this function should set 'done' TRUE, as the other auth functions work that way */ authstatus->done = TRUE; @@ -641,9 +641,9 @@ output_auth_headers(struct connectdata *conn, if(auth) { infof(data, "%s auth using %s with user '%s'\n", - proxy?"Proxy":"Server", auth, - proxy?(conn->proxyuser?conn->proxyuser:""): - (conn->user?conn->user:"")); + proxy ? "Proxy" : "Server", auth, + proxy ? (conn->proxyuser ? conn->proxyuser : "") : + (conn->user ? conn->user : "")); authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } else @@ -735,7 +735,6 @@ Curl_http_output_auth(struct connectdata *conn, return result; } - /* * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate: * headers. They are dealt with both in the transfer.c main loop and in the @@ -780,7 +779,6 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, * request is sent, and then it is again set _after_ all response 401/407 * headers have been received but then only to a single preferred method * (bit). - * */ while(*auth) { @@ -893,6 +891,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, while(*auth && ISSPACE(*auth)) auth++; } + return CURLE_OK; } @@ -934,8 +933,7 @@ static int http_should_fail(struct connectdata *conn) ** Any code >= 400 that's not 401 or 407 is always ** a terminal error */ - if((httpcode != 401) && - (httpcode != 407)) + if((httpcode != 401) && (httpcode != 407)) return 1; /* @@ -986,7 +984,7 @@ static size_t readmoredata(char *buffer, struct HTTP *http = conn->data->req.protop; size_t fullsize = size * nitems; - if(0 == http->postsize) + if(!http->postsize) /* nothing to return */ return 0; @@ -1092,7 +1090,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, return result; } - if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data @@ -1100,7 +1097,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, buffer is using this size. */ - sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size; + sendsize = (size > CURL_MAX_WRITE_SIZE) ? CURL_MAX_WRITE_SIZE : size; /* OpenSSL is very picky and we must send the SAME buffer pointer to the library when we attempt to re-send this buffer. Sending the same data @@ -1123,7 +1120,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, * only send away a part). */ /* how much of the header that was sent */ - size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount; + size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount; size_t bodylen = amount - headlen; if(conn->data->set.verbose) { @@ -1136,10 +1133,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, ptr+headlen, bodylen, conn); } } - if(bodylen) - /* since we sent a piece of the body here, up the byte counter for it - accordingly */ - http->writebytecount += bodylen; /* 'amount' can never be a very large value here so typecasting it so a signed 31 bit value should not cause problems even if ssize_t is @@ -1147,6 +1140,10 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, *bytes_written += (long)amount; if(http) { + /* if we sent a piece of the body here, up the byte counter for it + accordingly */ + http->writebytecount += bodylen; + if((size_t)amount != size) { /* The whole request could not be sent in one system call. We must queue it up and send it later when we get the chance. We must not @@ -1242,11 +1239,11 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size) buffer size that doubles the required size. If this new size would wrap size_t, then just use the largest possible one */ - if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) || - (~(size*2) < (in->size_used*2))) + if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) || + (~(size * 2) < (in->size_used * 2))) new_size = (size_t)-1; else - new_size = (in->size_used+size)*2; + new_size = (in->size_used+size) * 2; if(in->buffer) /* we have a buffer, enlarge the existing one */ @@ -1419,6 +1416,7 @@ static int https_getsock(struct connectdata *conn, return GETSOCK_READSOCK(0); } } + return CURLE_OK; } #else @@ -1436,8 +1434,8 @@ static int https_getsock(struct connectdata *conn, #endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */ /* - * Curl_http_done() gets called from Curl_done() after a single HTTP request - * has been performed. + * Curl_http_done() gets called after a single HTTP request has been + * performed. */ CURLcode Curl_http_done(struct connectdata *conn, @@ -1456,8 +1454,10 @@ CURLcode Curl_http_done(struct connectdata *conn, data->state.negotiate.state == GSS_AUTHSENT) { /* add forbid re-use if http-code != 401/407 as a WA only needed for * 401/407 that signal auth failure (empty) otherwise state will be RECV - * with current code */ - if((data->req.httpcode != 401) && (data->req.httpcode != 407)) + * with current code. + * Do not close CONNECT_ONLY connections. */ + if((data->req.httpcode != 401) && (data->req.httpcode != 407) && + !data->set.connect_only) connclose(conn, "Negotiate transfer completed"); Curl_cleanup_negotiate(data); } @@ -1467,7 +1467,7 @@ CURLcode Curl_http_done(struct connectdata *conn, conn->seek_func = data->set.seek_func; /* restore */ conn->seek_client = data->set.seek_client; /* restore */ - if(http == NULL) + if(!http) return CURLE_OK; if(http->send_buffer) { @@ -1517,9 +1517,9 @@ CURLcode Curl_http_done(struct connectdata *conn, entire operation is complete */ !conn->bits.retry && !data->set.connect_only && - ((http->readbytecount + - data->req.headerbytecount - - data->req.deductheadercount)) <= 0) { + (http->readbytecount + + data->req.headerbytecount - + data->req.deductheadercount) <= 0) { /* If this connection isn't simply closed to be retried, AND nothing was read from the HTTP server (that counts), this can't be right so we return an error here */ @@ -1530,7 +1530,6 @@ CURLcode Curl_http_done(struct connectdata *conn, return CURLE_OK; } - /* * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons * to avoid it include: @@ -1578,6 +1577,7 @@ static CURLcode expect100(struct SessionHandle *data, data->state.expect100header = TRUE; } } + return result; } @@ -1696,6 +1696,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, headers = headers->next; } } + return CURLE_OK; } @@ -1793,13 +1794,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) switch(conn->negnpn) { case CURL_HTTP_VERSION_2: conn->httpversion = 20; /* we know we're on HTTP/2 now */ - result = Curl_http2_init(conn); - if(result) - return result; - - result = Curl_http2_setup(conn); - if(result) - return result; result = Curl_http2_switched(conn, NULL, 0); if(result) @@ -1809,7 +1803,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* continue with HTTP/1.1 when explicitly requested */ break; default: - /* and as fallback */ + /* Check if user wants to use HTTP/2 with clear TCP*/ +#ifdef USE_NGHTTP2 + if(conn->data->set.httpversion == + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { + DEBUGF(infof(data, "HTTP/2 over clean TCP\n")); + conn->httpversion = 20; + + result = Curl_http2_switched(conn, NULL, 0); + if(result) + return result; + } +#endif break; } } @@ -1829,6 +1834,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.first_host = strdup(conn->host.name); if(!data->state.first_host) return CURLE_OUT_OF_MEMORY; + + data->state.first_remote_port = conn->remote_port; } http->writebytecount = http->readbytecount = 0; @@ -1910,6 +1917,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!conn->allocptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } + else { + Curl_safefree(conn->allocptr.accept_encoding); + conn->allocptr.accept_encoding = NULL; + } #ifdef HAVE_LIBZ /* we only consider transfer-encoding magic if libz support is built-in */ @@ -2145,7 +2156,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * file size before we continue this venture in the dark lands of HTTP. *********************************************************************/ - if(data->state.resume_from < 0 ) { + if(data->state.resume_from < 0) { /* * This is meant to get the size of the present remote-file by itself. * We don't support this now. Bail out! diff --git a/project/jni/curl/lib/http.h b/project/jni/curl/lib/http.h index 5000df448..981472e07 100644 --- a/project/jni/curl/lib/http.h +++ b/project/jni/curl/lib/http.h @@ -214,6 +214,7 @@ struct http_conn { them for both cases. */ int32_t pause_stream_id; /* stream ID which paused nghttp2_session_mem_recv */ + size_t drain_total; /* sum of all stream's UrlState.drain */ /* this is a hash of all individual streams (SessionHandle structs) */ struct h2settings settings; diff --git a/project/jni/curl/lib/http2.c b/project/jni/curl/lib/http2.c index 91abbf04e..5ca1ac451 100644 --- a/project/jni/curl/lib/http2.c +++ b/project/jni/curl/lib/http2.c @@ -23,7 +23,6 @@ #include "curl_setup.h" #ifdef USE_NGHTTP2 -#include "curl_printf.h" #include #include "urldata.h" #include "http2.h" @@ -35,8 +34,10 @@ #include "conncache.h" #include "url.h" #include "connect.h" +#include "strtoofft.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" @@ -46,6 +47,18 @@ #error too old nghttp2 version, upgrade! #endif +#if (NGHTTP2_VERSION_NUM > 0x010800) +#define NGHTTP2_HAS_HTTP2_STRERROR 1 +#endif + +#if (NGHTTP2_VERSION_NUM >= 0x010900) +/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or + later */ +#define NGHTTP2_HAS_ERROR_CALLBACK 1 +#else +#define nghttp2_session_callbacks_set_error_callback(x,y) +#endif + /* * Curl_http2_init_state() is called when the easy handle is created and * allows for HTTP/2 specific init of state. @@ -155,7 +168,7 @@ void Curl_http2_setup_conn(struct connectdata *conn) * HTTP to HTTP2. */ const struct Curl_handler Curl_handler_http2 = { - "HTTP2", /* scheme */ + "HTTP", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ @@ -175,7 +188,7 @@ const struct Curl_handler Curl_handler_http2 = { }; const struct Curl_handler Curl_handler_http2_ssl = { - "HTTP2", /* scheme */ + "HTTPS", /* scheme */ ZERO_NULL, /* setup_connection */ Curl_http, /* do_it */ Curl_http_done, /* done */ @@ -204,6 +217,34 @@ int Curl_http2_ver(char *p, size_t len) return snprintf(p, len, " nghttp2/%s", h2->version_str); } +/* HTTP/2 error code to name based on the Error Code Registry. +https://tools.ietf.org/html/rfc7540#page-77 +nghttp2_error_code enums are identical. +*/ +const char *Curl_http2_strerror(uint32_t err) { +#ifndef NGHTTP2_HAS_HTTP2_STRERROR + const char *str[] = { + "NO_ERROR", /* 0x0 */ + "PROTOCOL_ERROR", /* 0x1 */ + "INTERNAL_ERROR", /* 0x2 */ + "FLOW_CONTROL_ERROR", /* 0x3 */ + "SETTINGS_TIMEOUT", /* 0x4 */ + "STREAM_CLOSED", /* 0x5 */ + "FRAME_SIZE_ERROR", /* 0x6 */ + "REFUSED_STREAM", /* 0x7 */ + "CANCEL", /* 0x8 */ + "COMPRESSION_ERROR", /* 0x9 */ + "CONNECT_ERROR", /* 0xA */ + "ENHANCE_YOUR_CALM", /* 0xB */ + "INADEQUATE_SECURITY", /* 0xC */ + "HTTP_1_1_REQUIRED" /* 0xD */ + }; + return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown"; +#else + return nghttp2_http2_strerror(err); +#endif +} + /* * The implementation of nghttp2_send_callback type. Here we write |data| with * size |length| to the network and return the number of bytes actually @@ -499,6 +540,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, stream->memlen += ncopy; data_s->state.drain++; + httpc->drain_total++; { /* get the pointer from userp again since it was re-assigned above */ struct connectdata *conn_s = (struct connectdata *)userp; @@ -575,6 +617,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, stream->memlen += nread; data_s->state.drain++; + conn->proto.httpc.drain_total++; /* if we receive data for another handle, wake that up */ if(conn->data != data_s) @@ -594,8 +637,18 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, ", stream %u\n", len - nread, stream_id)); data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; + return NGHTTP2_ERR_PAUSE; } + + /* pause execution of nghttp2 if we received data for another handle + in order to process them first. */ + if(conn->data != data_s) { + data_s->easy_conn->proto.httpc.pause_stream_id = stream_id; + + return NGHTTP2_ERR_PAUSE; + } + return 0; } @@ -647,9 +700,9 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, { struct SessionHandle *data_s; struct HTTP *stream; + struct connectdata *conn = (struct connectdata *)userp; (void)session; (void)stream_id; - (void)userp; if(stream_id) { /* get the stream from the hash based on Stream ID, stream ID zero is for @@ -660,14 +713,16 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, decided to reject stream (e.g., PUSH_PROMISE). */ return 0; } - DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n", - error_code, stream_id)); + DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n", + Curl_http2_strerror(error_code), error_code, stream_id)); stream = data_s->req.protop; if(!stream) return NGHTTP2_ERR_CALLBACK_FAILURE; stream->error_code = error_code; stream->closed = TRUE; + data_s->state.drain++; + conn->proto.httpc.drain_total++; /* remove the entry from the hash as the stream is now gone */ nghttp2_session_set_stream_user_data(session, stream_id, 0); @@ -807,7 +862,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n)); Curl_add_buffer(stream->trailer_recvbuf, name, namelen); - Curl_add_buffer(stream->trailer_recvbuf, ":", 1); + Curl_add_buffer(stream->trailer_recvbuf, ": ", 2); Curl_add_buffer(stream->trailer_recvbuf, value, valuelen); Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3); @@ -824,8 +879,8 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9); Curl_add_buffer(stream->header_recvbuf, value, valuelen); - Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - data_s->state.drain++; + /* the space character after the status code is mandatory */ + Curl_add_buffer(stream->header_recvbuf, " \r\n", 3); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) Curl_expire(data_s, 1); @@ -839,10 +894,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, received, and this is not pseudo-header field . */ /* convert to a HTTP1-style header */ Curl_add_buffer(stream->header_recvbuf, name, namelen); - Curl_add_buffer(stream->header_recvbuf, ":", 1); + Curl_add_buffer(stream->header_recvbuf, ": ", 2); Curl_add_buffer(stream->header_recvbuf, value, valuelen); Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); - data_s->state.drain++; /* if we receive data for another handle, wake that up */ if(conn->data != data_s) Curl_expire(data_s, 1); @@ -912,6 +966,19 @@ static nghttp2_settings_entry settings[] = { #define H2_BUFSIZE 32768 +#ifdef NGHTTP2_HAS_ERROR_CALLBACK +static int error_callback(nghttp2_session *session, + const char *msg, + size_t len, + void *userp) +{ + struct connectdata *conn = (struct connectdata *)userp; + (void)session; + infof(conn->data, "http2 error: %.*s\n", len, msg); + return 0; +} +#endif + /* * Initialize nghttp2 for a Curl connection */ @@ -961,6 +1028,8 @@ CURLcode Curl_http2_init(struct connectdata *conn) /* nghttp2_on_header_callback */ nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header); + 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); @@ -1019,6 +1088,73 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, return result; } +/* + * Returns nonzero if current HTTP/2 session should be closed. + */ +static int should_close_session(struct http_conn *httpc) { + return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && + !nghttp2_session_want_write(httpc->h2); +} + +static int h2_session_send(struct SessionHandle *data, + nghttp2_session *h2); + +/* + * h2_process_pending_input() processes pending input left in + * httpc->inbuf. Then, call h2_session_send() to send pending data. + * This function returns 0 if it succeeds, or -1 and error code will + * be assigned to *err. + */ +static int h2_process_pending_input(struct SessionHandle *data, + struct http_conn *httpc, + CURLcode *err) { + ssize_t nread; + char *inbuf; + ssize_t rv; + + nread = httpc->inbuflen - httpc->nread_inbuf; + inbuf = httpc->inbuf + httpc->nread_inbuf; + + rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread); + if(rv < 0) { + failf(data, + "h2_process_pending_input: nghttp2_session_mem_recv() returned " + "%d:%s\n", rv, nghttp2_strerror((int)rv)); + *err = CURLE_RECV_ERROR; + return -1; + } + + if(nread == rv) { + DEBUGF(infof(data, + "h2_process_pending_input: All data in connection buffer " + "processed\n")); + httpc->inbuflen = 0; + httpc->nread_inbuf = 0; + } + else { + httpc->nread_inbuf += rv; + DEBUGF(infof(data, + "h2_process_pending_input: %zu bytes left in connection " + "buffer\n", + httpc->inbuflen - httpc->nread_inbuf)); + } + + rv = h2_session_send(data, httpc->h2); + if(rv != 0) { + *err = CURLE_SEND_ERROR; + return -1; + } + + if(should_close_session(httpc)) { + DEBUGF(infof(data, + "h2_process_pending_input: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } + + return 0; +} + static ssize_t http2_handle_stream_close(struct connectdata *conn, struct SessionHandle *data, struct HTTP *stream, CURLcode *err) { @@ -1029,13 +1165,35 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, if(httpc->pause_stream_id == stream->stream_id) { httpc->pause_stream_id = 0; } + + DEBUGASSERT(httpc->drain_total >= data->state.drain); + httpc->drain_total -= data->state.drain; + data->state.drain = 0; + + if(httpc->pause_stream_id == 0) { + if(h2_process_pending_input(data, httpc, err) != 0) { + return -1; + } + } + + DEBUGASSERT(data->state.drain == 0); + /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ stream->closed = FALSE; if(stream->error_code != NGHTTP2_NO_ERROR) { - failf(data, "HTTP/2 stream %u was not closed cleanly: error_code = %d", - stream->stream_id, stream->error_code); - *err = CURLE_HTTP2; + failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)", + stream->stream_id, Curl_http2_strerror(stream->error_code), + stream->error_code); + *err = CURLE_HTTP2_STREAM; + return -1; + } + + if(!stream->bodystarted) { + failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " + " all response header fields, teated as error", + stream->stream_id); + *err = CURLE_HTTP2_STREAM; return -1; } @@ -1126,12 +1284,11 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, (void)sockindex; /* we always do HTTP2 on sockindex 0 */ - /* If stream is closed, return 0 to signal the http routine to close - the connection. We need to handle stream closure here, - otherwise, we may be going to read from underlying connection, - and gets EAGAIN, and we will get stuck there. */ - if(stream->memlen == 0 && stream->closed) { - return http2_handle_stream_close(conn, data, stream, err); + if(should_close_session(httpc)) { + DEBUGF(infof(data, + "http2_recv: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; } /* Nullify here because we call nghttp2_session_send() and they @@ -1173,8 +1330,18 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, stream->len = len - stream->memlen; stream->mem = mem; } + if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) { + /* We have paused nghttp2, but we have no pause data (see + on_data_chunk_recv). */ + httpc->pause_stream_id = 0; + if(h2_process_pending_input(data, httpc, &result) != 0) { + *err = result; + return -1; + } + } } else if(stream->pausedata) { + DEBUGASSERT(httpc->pause_stream_id == stream->stream_id); nread = MIN(len, stream->pauselen); memcpy(mem, stream->pausedata, nread); @@ -1197,7 +1364,10 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, frames, then we have to call it again with 0-length data. Without this, on_stream_close callback will not be called, and stream could be hanged. */ - nghttp2_session_mem_recv(httpc->h2, NULL, 0); + if(h2_process_pending_input(data, httpc, &result) != 0) { + *err = result; + return -1; + } } DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n", nread, stream->stream_id)); @@ -1230,6 +1400,10 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, if(nread == -1) { if(result != CURLE_AGAIN) failf(data, "Failed receiving HTTP2 data"); + else if(stream->closed) + /* received when the stream was already closed! */ + return http2_handle_stream_close(conn, data, stream, err); + *err = result; return -1; } @@ -1278,6 +1452,12 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, *err = CURLE_SEND_ERROR; return 0; } + + if(should_close_session(httpc)) { + DEBUGF(infof(data, "http2_recv: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } } if(stream->memlen) { ssize_t retlen = stream->memlen; @@ -1291,8 +1471,11 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, DEBUGF(infof(data, "Data returned for PAUSED stream %u\n", stream->stream_id)); } - else + else if(!stream->closed) { + DEBUGASSERT(httpc->drain_total >= data->state.drain); + httpc->drain_total -= data->state.drain; data->state.drain = 0; /* this stream is hereby drained */ + } return retlen; } @@ -1311,6 +1494,9 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, field list. */ #define AUTHORITY_DST_IDX 3 +#define HEADER_OVERFLOW(x) \ + (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) + /* return number of received (decrypted) bytes */ static ssize_t http2_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) @@ -1323,12 +1509,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, int rv; struct http_conn *httpc = &conn->proto.httpc; struct HTTP *stream = conn->data->req.protop; - nghttp2_nv *nva; + nghttp2_nv *nva = NULL; size_t nheader; size_t i; size_t authority_idx; char *hdbuf = (char*)mem; - char *end; + char *end, *line_end; nghttp2_data_provider data_prd; int32_t stream_id; nghttp2_session *h2 = httpc->h2; @@ -1356,6 +1542,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, stream->upload_mem = NULL; stream->upload_len = 0; + if(should_close_session(httpc)) { + DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } + if(stream->upload_left) { /* we are sure that we have more data to send here. Calling the following API will make nghttp2_session_want_write() return @@ -1373,12 +1565,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, /* Here, we assume the curl http code generate *correct* HTTP header field block */ nheader = 0; - for(i = 0; i < len; ++i) { - if(hdbuf[i] == 0x0a) { + for(i = 1; i < len; ++i) { + if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') { ++nheader; + ++i; } } - /* We counted additional 2 \n in the first and last line. We need 3 + if(nheader < 2) + goto fail; + + /* We counted additional 2 \r\n in the first and last line. We need 3 new headers: :method, :path and :scheme. Therefore we need one more space. */ nheader += 1; @@ -1387,51 +1583,84 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, *err = CURLE_OUT_OF_MEMORY; return -1; } + /* Extract :method, :path from request line */ - end = strchr(hdbuf, ' '); - if(!end) + line_end = strstr(hdbuf, "\r\n"); + + /* Method does not contain spaces */ + end = memchr(hdbuf, ' ', line_end - hdbuf); + if(!end || end == hdbuf) goto fail; nva[0].name = (unsigned char *)":method"; - nva[0].namelen = (uint16_t)strlen((char *)nva[0].name); + nva[0].namelen = strlen((char *)nva[0].name); nva[0].value = (unsigned char *)hdbuf; - nva[0].valuelen = (uint16_t)(end - hdbuf); + nva[0].valuelen = (size_t)(end - hdbuf); nva[0].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[0])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; + } hdbuf = end + 1; - end = strchr(hdbuf, ' '); - if(!end) + /* Path may contain spaces so scan backwards */ + end = NULL; + for(i = (size_t)(line_end - hdbuf); i; --i) { + if(hdbuf[i - 1] == ' ') { + end = &hdbuf[i - 1]; + break; + } + } + if(!end || end == hdbuf) goto fail; nva[1].name = (unsigned char *)":path"; - nva[1].namelen = (uint16_t)strlen((char *)nva[1].name); + nva[1].namelen = strlen((char *)nva[1].name); nva[1].value = (unsigned char *)hdbuf; - nva[1].valuelen = (uint16_t)(end - hdbuf); + nva[1].valuelen = (size_t)(end - hdbuf); nva[1].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[1])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; + } + hdbuf = end + 1; + + end = line_end; nva[2].name = (unsigned char *)":scheme"; - nva[2].namelen = (uint16_t)strlen((char *)nva[2].name); + nva[2].namelen = strlen((char *)nva[2].name); if(conn->handler->flags & PROTOPT_SSL) nva[2].value = (unsigned char *)"https"; else nva[2].value = (unsigned char *)"http"; - nva[2].valuelen = (uint16_t)strlen((char *)nva[2].value); + nva[2].valuelen = strlen((char *)nva[2].value); nva[2].flags = NGHTTP2_NV_FLAG_NONE; - - hdbuf = strchr(hdbuf, 0x0a); - if(!hdbuf) + if(HEADER_OVERFLOW(nva[2])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); goto fail; - ++hdbuf; + } authority_idx = 0; - i = 3; while(i < nheader) { size_t hlen; int skip = 0; - end = strchr(hdbuf, ':'); - if(!end) + + hdbuf = line_end + 2; + + line_end = strstr(hdbuf, "\r\n"); + if(line_end == hdbuf) + goto fail; + + /* header continuation lines are not supported */ + if(*hdbuf == ' ' || *hdbuf == '\t') + goto fail; + + for(end = hdbuf; end < line_end && *end != ':'; ++end) + ; + if(end == hdbuf || end == line_end) goto fail; hlen = end - hdbuf; + if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) { /* skip Connection: headers! */ skip = 1; @@ -1440,21 +1669,24 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; - nva[i].namelen = (uint16_t)strlen((char *)nva[i].name); + nva[i].namelen = strlen((char *)nva[i].name); } else { nva[i].name = (unsigned char *)hdbuf; - nva[i].namelen = (uint16_t)(end - hdbuf); + nva[i].namelen = (size_t)(end - hdbuf); } hdbuf = end + 1; - for(; *hdbuf == ' '; ++hdbuf); - end = strchr(hdbuf, 0x0d); - if(!end) - goto fail; + while(*hdbuf == ' ' || *hdbuf == '\t') + ++hdbuf; + end = line_end; if(!skip) { nva[i].value = (unsigned char *)hdbuf; - nva[i].valuelen = (uint16_t)(end - hdbuf); + nva[i].valuelen = (size_t)(end - hdbuf); nva[i].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[i])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; + } /* Inspect Content-Length header field and retrieve the request entity length so that we can set END_STREAM to the last DATA frame. */ @@ -1462,7 +1694,13 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { size_t j; stream->upload_left = 0; + if(!nva[i].valuelen) + goto fail; for(j = 0; j < nva[i].valuelen; ++j) { + if(nva[i].value[j] < '0' || nva[i].value[j] > '9') + goto fail; + if(stream->upload_left >= CURL_OFF_T_MAX / 10) + goto fail; stream->upload_left *= 10; stream->upload_left += nva[i].value[j] - '0'; } @@ -1473,7 +1711,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, } ++i; } - hdbuf = end + 2; } /* :authority must come before non-pseudo header fields */ @@ -1485,6 +1722,29 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, nva[i] = authority; } + /* Warn stream may be rejected if cumulative length of headers is too large. + It appears nghttp2 will not send a header frame larger than 64KB. */ + { + size_t acc = 0; + const size_t max_acc = 60000; /* <64KB to account for some overhead */ + + for(i = 0; i < nheader; ++i) { + if(nva[i].namelen > max_acc - acc) + break; + acc += nva[i].namelen; + + if(nva[i].valuelen > max_acc - acc) + break; + acc += nva[i].valuelen; + } + + if(i != nheader) { + infof(conn->data, "http2_send: Warning: The cumulative length of all " + "headers exceeds %zu bytes and that could cause the " + "stream to be rejected.\n", max_acc); + } + } + h2_pri_spec(conn->data, &pri_spec); switch(conn->data->set.httpreq) { @@ -1522,6 +1782,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, return -1; } + if(should_close_session(httpc)) { + DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n")); + *err = CURLE_HTTP2; + return -1; + } + if(stream->stream_id != -1) { /* If whole HEADERS frame was sent off to the underlying socket, the nghttp2 library calls data_source_read_callback. But only @@ -1575,6 +1841,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn) httpc->nread_inbuf = 0; httpc->pause_stream_id = 0; + httpc->drain_total = 0; conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ conn->httpversion = 20; @@ -1682,6 +1949,12 @@ CURLcode Curl_http2_switched(struct connectdata *conn, return CURLE_HTTP2; } + if(should_close_session(httpc)) { + DEBUGF(infof(data, + "nghttp2_session_send(): nothing to do in this session\n")); + return CURLE_HTTP2; + } + return CURLE_OK; } diff --git a/project/jni/curl/lib/http2.h b/project/jni/curl/lib/http2.h index 2d073347e..1aec30403 100644 --- a/project/jni/curl/lib/http2.h +++ b/project/jni/curl/lib/http2.h @@ -37,6 +37,8 @@ */ int Curl_http2_ver(char *p, size_t len); +const char *Curl_http2_strerror(uint32_t err); + CURLcode Curl_http2_init(struct connectdata *conn); void Curl_http2_init_state(struct UrlState *state); void Curl_http2_init_userset(struct UserDefined *set); diff --git a/project/jni/curl/lib/http_chunks.c b/project/jni/curl/lib/http_chunks.c index 53091738a..433f76e1c 100644 --- a/project/jni/curl/lib/http_chunks.c +++ b/project/jni/curl/lib/http_chunks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -80,7 +80,7 @@ static bool Curl_isxdigit(char digit) { return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ || (digit >= 0x41 && digit <= 0x46) /* A-F */ - || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE; + || (digit >= 0x61 && digit <= 0x66) /* a-f */) ? TRUE : FALSE; } void Curl_httpchunk_init(struct connectdata *conn) diff --git a/project/jni/curl/lib/http_digest.c b/project/jni/curl/lib/http_digest.c index dc867d52e..a1768b863 100644 --- a/project/jni/curl/lib/http_digest.c +++ b/project/jni/curl/lib/http_digest.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,11 +26,10 @@ #include "urldata.h" #include "rawstr.h" -#include "curl_sasl.h" +#include "vauth/vauth.h" #include "http_digest.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -65,7 +64,7 @@ CURLcode Curl_input_digest(struct connectdata *conn, while(*header && ISSPACE(*header)) header++; - return Curl_sasl_decode_digest_http_message(header, digest); + return Curl_auth_decode_digest_http_message(header, digest); } CURLcode Curl_output_digest(struct connectdata *conn, @@ -152,7 +151,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, if(!path) return CURLE_OUT_OF_MEMORY; - result = Curl_sasl_create_digest_http_message(data, userp, passwdp, request, + result = Curl_auth_create_digest_http_message(data, userp, passwdp, request, path, digest, &response, &len); free(path); if(result) @@ -172,8 +171,8 @@ CURLcode Curl_output_digest(struct connectdata *conn, void Curl_digest_cleanup(struct SessionHandle *data) { - Curl_sasl_digest_cleanup(&data->state.digest); - Curl_sasl_digest_cleanup(&data->state.proxydigest); + Curl_auth_digest_cleanup(&data->state.digest); + Curl_auth_digest_cleanup(&data->state.proxydigest); } #endif diff --git a/project/jni/curl/lib/http_negotiate.c b/project/jni/curl/lib/http_negotiate.c index 4a808f8f3..999bc0c52 100644 --- a/project/jni/curl/lib/http_negotiate.c +++ b/project/jni/curl/lib/http_negotiate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,19 +22,16 @@ #include "curl_setup.h" -#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) #include "urldata.h" #include "sendf.h" -#include "curl_gssapi.h" #include "rawstr.h" -#include "curl_base64.h" #include "http_negotiate.h" -#include "curl_sasl.h" -#include "url.h" -#include "curl_printf.h" +#include "vauth/vauth.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" @@ -42,136 +39,77 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { struct SessionHandle *data = conn->data; - struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: - &data->state.negotiate; - OM_uint32 major_status, minor_status, discard_st; - gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; - gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; size_t len; - size_t rawlen = 0; - CURLcode result; - if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) { - /* We finished successfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_cleanup_negotiate(data); - return CURLE_LOGIN_DENIED; + /* Point to the username, password, service and host */ + const char *userp; + const char *passwdp; + const char *service; + const char *host; + + /* Point to the correct struct with this */ + struct negotiatedata *neg_ctx; + + if(proxy) { + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; + host = conn->proxy.name; + neg_ctx = &data->state.proxyneg; + } + else { + userp = conn->user; + passwdp = conn->passwd; + service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : "HTTP"; + host = conn->host.name; + neg_ctx = &data->state.negotiate; } - if(!neg_ctx->server_name) { - /* Generate our SPN */ - char *spn = Curl_sasl_build_gssapi_spn( - proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : - data->set.str[STRING_SERVICE_NAME], - proxy ? conn->proxy.name : conn->host.name); - if(!spn) - return CURLE_OUT_OF_MEMORY; + /* Not set means empty */ + if(!userp) + userp = ""; - /* Populate the SPN structure */ - spn_token.value = spn; - spn_token.length = strlen(spn); - - /* Import the SPN */ - major_status = gss_import_name(&minor_status, &spn_token, - GSS_C_NT_HOSTBASED_SERVICE, - &neg_ctx->server_name); - if(GSS_ERROR(major_status)) { - Curl_gss_log_error(data, minor_status, "gss_import_name() failed: "); - - free(spn); - - return CURLE_OUT_OF_MEMORY; - } - - free(spn); - } + if(!passwdp) + passwdp = ""; + /* Obtain the input token, if any */ header += strlen("Negotiate"); while(*header && ISSPACE(*header)) header++; len = strlen(header); - if(len > 0) { - result = Curl_base64_decode(header, (unsigned char **)&input_token.value, - &rawlen); - if(result) - return result; - - if(!rawlen) { - infof(data, "Negotiate handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; + if(!len) { + /* Is this the first call in a new negotiation? */ + if(neg_ctx->context) { + /* The server rejected our authentication and hasn't suppled any more + negotiation mechanisms */ + return CURLE_LOGIN_DENIED; } - - input_token.length = rawlen; - - DEBUGASSERT(input_token.value != NULL); } - major_status = Curl_gss_init_sec_context(data, - &minor_status, - &neg_ctx->context, - neg_ctx->server_name, - &Curl_spnego_mech_oid, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - &output_token, - TRUE, - NULL); - Curl_safefree(input_token.value); - - neg_ctx->status = major_status; - if(GSS_ERROR(major_status)) { - if(output_token.value) - gss_release_buffer(&discard_st, &output_token); - Curl_gss_log_error(conn->data, minor_status, - "gss_init_sec_context() failed: "); - return CURLE_OUT_OF_MEMORY; - } - - if(!output_token.value || !output_token.length) { - if(output_token.value) - gss_release_buffer(&discard_st, &output_token); - return CURLE_OUT_OF_MEMORY; - } - - neg_ctx->output_token = output_token; - - return CURLE_OK; + /* Initilise the security context and decode our challenge */ + return Curl_auth_decode_spnego_message(data, userp, passwdp, service, host, + header, neg_ctx); } CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: + struct negotiatedata *neg_ctx = proxy ? &conn->data->state.proxyneg : &conn->data->state.negotiate; - char *encoded = NULL; + char *base64 = NULL; size_t len = 0; char *userp; CURLcode result; - OM_uint32 discard_st; - result = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded, &len); - if(result) { - gss_release_buffer(&discard_st, &neg_ctx->output_token); - neg_ctx->output_token.value = NULL; - neg_ctx->output_token.length = 0; + result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len); + if(result) return result; - } - - if(!encoded || !len) { - gss_release_buffer(&discard_st, &neg_ctx->output_token); - neg_ctx->output_token.value = NULL; - neg_ctx->output_token.length = 0; - return CURLE_REMOTE_ACCESS_DENIED; - } userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - encoded); + base64); + if(proxy) { Curl_safefree(conn->allocptr.proxyuserpwd); conn->allocptr.proxyuserpwd = userp; @@ -181,30 +119,15 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) conn->allocptr.userpwd = userp; } - free(encoded); + free(base64); return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; } -static void cleanup(struct negotiatedata *neg_ctx) -{ - OM_uint32 minor_status; - if(neg_ctx->context != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER); - - if(neg_ctx->output_token.value) - gss_release_buffer(&minor_status, &neg_ctx->output_token); - - if(neg_ctx->server_name != GSS_C_NO_NAME) - gss_release_name(&minor_status, &neg_ctx->server_name); - - memset(neg_ctx, 0, sizeof(*neg_ctx)); -} - void Curl_cleanup_negotiate(struct SessionHandle *data) { - cleanup(&data->state.negotiate); - cleanup(&data->state.proxyneg); + Curl_auth_spnego_cleanup(&data->state.negotiate); + Curl_auth_spnego_cleanup(&data->state.proxyneg); } -#endif /* HAVE_GSSAPI && !CURL_DISABLE_HTTP && USE_SPNEGO */ +#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ diff --git a/project/jni/curl/lib/http_negotiate.h b/project/jni/curl/lib/http_negotiate.h index acbbf6ae5..21b7f8834 100644 --- a/project/jni/curl/lib/http_negotiate.h +++ b/project/jni/curl/lib/http_negotiate.h @@ -33,10 +33,6 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); void Curl_cleanup_negotiate(struct SessionHandle *data); -#ifdef USE_WINDOWS_SSPI -#define GSS_ERROR(status) (status & 0x80000000) -#endif - #endif /* USE_SPNEGO */ #endif /* HEADER_CURL_HTTP_NEGOTIATE_H */ diff --git a/project/jni/curl/lib/http_negotiate_sspi.c b/project/jni/curl/lib/http_negotiate_sspi.c deleted file mode 100644 index d2643bb41..000000000 --- a/project/jni/curl/lib/http_negotiate_sspi.c +++ /dev/null @@ -1,302 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef USE_WINDOWS_SSPI - -#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) - -#include "urldata.h" -#include "sendf.h" -#include "rawstr.h" -#include "warnless.h" -#include "curl_base64.h" -#include "curl_sasl.h" -#include "http_negotiate.h" -#include "curl_multibyte.h" -#include "curl_printf.h" - -/* The last #include files should be: */ -#include "curl_memory.h" -#include "memdebug.h" - -CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, - const char *header) -{ - struct SessionHandle *data = conn->data; - BYTE *input_token = NULL; - SecBufferDesc out_buff_desc; - SecBuffer out_sec_buff; - SecBufferDesc in_buff_desc; - SecBuffer in_sec_buff; - SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - size_t len = 0, input_token_len = 0; - CURLcode result; - - /* Point to the username and password */ - const char *userp; - const char *passwdp; - - /* Point to the correct struct with this */ - struct negotiatedata *neg_ctx; - - if(proxy) { - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - neg_ctx = &data->state.proxyneg; - } - else { - userp = conn->user; - passwdp = conn->passwd; - neg_ctx = &data->state.negotiate; - } - - /* Not set means empty */ - if(!userp) - userp = ""; - - if(!passwdp) - passwdp = ""; - - if(neg_ctx->context && neg_ctx->status == SEC_E_OK) { - /* We finished successfully our part of authentication, but server - * rejected it (since we're again here). Exit with an error since we - * can't invent anything better */ - Curl_cleanup_negotiate(data); - return CURLE_LOGIN_DENIED; - } - - if(!neg_ctx->server_name) { - /* Check proxy auth requested but no given proxy name */ - if(proxy && !conn->proxy.name) - return CURLE_BAD_FUNCTION_ARGUMENT; - - /* Generate our SPN */ - neg_ctx->server_name = Curl_sasl_build_spn( - proxy ? data->set.str[STRING_PROXY_SERVICE_NAME] : - data->set.str[STRING_SERVICE_NAME], - proxy ? conn->proxy.name : conn->host.name); - if(!neg_ctx->server_name) - return CURLE_OUT_OF_MEMORY; - } - - if(!neg_ctx->output_token) { - PSecPkgInfo SecurityPackage; - status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) - TEXT(SP_NAME_NEGOTIATE), - &SecurityPackage); - if(status != SEC_E_OK) - return CURLE_NOT_BUILT_IN; - - /* Allocate input and output buffers according to the max token size - as indicated by the security package */ - neg_ctx->token_max = SecurityPackage->cbMaxToken; - neg_ctx->output_token = malloc(neg_ctx->token_max); - s_pSecFn->FreeContextBuffer(SecurityPackage); - } - - /* Obtain the input token, if any */ - header += strlen("Negotiate"); - while(*header && ISSPACE(*header)) - header++; - - len = strlen(header); - if(!len) { - /* Is this the first call in a new negotiation? */ - if(neg_ctx->context) { - /* The server rejected our authentication and hasn't suppled any more - negotiation mechanisms */ - return CURLE_LOGIN_DENIED; - } - - /* We have to acquire credentials and allocate memory for the context */ - neg_ctx->credentials = malloc(sizeof(CredHandle)); - neg_ctx->context = malloc(sizeof(CtxtHandle)); - - if(!neg_ctx->credentials || !neg_ctx->context) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - result = Curl_create_sspi_identity(userp, passwdp, &neg_ctx->identity); - if(result) - return result; - - /* Allow proper cleanup of the identity structure */ - neg_ctx->p_identity = &neg_ctx->identity; - } - else - /* Use the current Windows user */ - neg_ctx->p_identity = NULL; - - /* Acquire our credientials handle */ - neg_ctx->status = - s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_NEGOTIATE), - SECPKG_CRED_OUTBOUND, NULL, - neg_ctx->p_identity, NULL, NULL, - neg_ctx->credentials, &expiry); - if(neg_ctx->status != SEC_E_OK) - return CURLE_LOGIN_DENIED; - } - else { - result = Curl_base64_decode(header, - (unsigned char **)&input_token, - &input_token_len); - if(result) - return result; - - if(!input_token_len) { - infof(data, - "Negotiate handshake failure (empty challenge message)\n"); - - return CURLE_BAD_CONTENT_ENCODING; - } - } - - /* Setup the "output" security buffer */ - out_buff_desc.ulVersion = SECBUFFER_VERSION; - out_buff_desc.cBuffers = 1; - out_buff_desc.pBuffers = &out_sec_buff; - out_sec_buff.BufferType = SECBUFFER_TOKEN; - out_sec_buff.pvBuffer = neg_ctx->output_token; - out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->token_max); - - /* Setup the "input" security buffer if present */ - if(input_token) { - in_buff_desc.ulVersion = SECBUFFER_VERSION; - in_buff_desc.cBuffers = 1; - in_buff_desc.pBuffers = &in_sec_buff; - in_sec_buff.BufferType = SECBUFFER_TOKEN; - in_sec_buff.pvBuffer = input_token; - in_sec_buff.cbBuffer = curlx_uztoul(input_token_len); - } - - /* Generate our message */ - neg_ctx->status = s_pSecFn->InitializeSecurityContext( - neg_ctx->credentials, - input_token ? neg_ctx->context : NULL, - neg_ctx->server_name, - ISC_REQ_CONFIDENTIALITY, - 0, - SECURITY_NATIVE_DREP, - input_token ? &in_buff_desc : NULL, - 0, - neg_ctx->context, - &out_buff_desc, - &attrs, - &expiry); - - free(input_token); - - if(GSS_ERROR(neg_ctx->status)) - return CURLE_OUT_OF_MEMORY; - - if(neg_ctx->status == SEC_I_COMPLETE_NEEDED || - neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) { - neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context, - &out_buff_desc); - if(GSS_ERROR(neg_ctx->status)) - return CURLE_RECV_ERROR; - } - - neg_ctx->output_token_length = out_sec_buff.cbBuffer; - - return CURLE_OK; -} - -CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) -{ - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; - char *encoded = NULL; - size_t len = 0; - char *userp; - CURLcode result; - - result = Curl_base64_encode(conn->data, - (const char*)neg_ctx->output_token, - neg_ctx->output_token_length, - &encoded, &len); - if(result) - return result; - - if(!len) - return CURLE_REMOTE_ACCESS_DENIED; - - userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "", - encoded); - - if(proxy) { - Curl_safefree(conn->allocptr.proxyuserpwd); - conn->allocptr.proxyuserpwd = userp; - } - else { - Curl_safefree(conn->allocptr.userpwd); - conn->allocptr.userpwd = userp; - } - - free(encoded); - - return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; -} - -static void cleanup(struct negotiatedata *neg_ctx) -{ - /* Free our security context */ - if(neg_ctx->context) { - s_pSecFn->DeleteSecurityContext(neg_ctx->context); - free(neg_ctx->context); - neg_ctx->context = NULL; - } - - /* Free our credentials handle */ - if(neg_ctx->credentials) { - s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials); - free(neg_ctx->credentials); - neg_ctx->credentials = NULL; - } - - /* Free our identity */ - Curl_sspi_free_identity(neg_ctx->p_identity); - neg_ctx->p_identity = NULL; - - /* Free the SPN and output token */ - Curl_safefree(neg_ctx->server_name); - Curl_safefree(neg_ctx->output_token); - - /* Reset any variables */ - neg_ctx->token_max = 0; -} - -void Curl_cleanup_negotiate(struct SessionHandle *data) -{ - cleanup(&data->state.negotiate); - cleanup(&data->state.proxyneg); -} - -#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */ - -#endif /* USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/curl_ntlm.c b/project/jni/curl/lib/http_ntlm.c similarity index 92% rename from project/jni/curl/lib/curl_ntlm.c rename to project/jni/curl/lib/http_ntlm.c index d4842e468..935df25db 100644 --- a/project/jni/curl/lib/curl_ntlm.c +++ b/project/jni/curl/lib/http_ntlm.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,7 +28,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 @@ -36,12 +36,10 @@ #include "urldata.h" #include "sendf.h" #include "rawstr.h" -#include "curl_ntlm.h" -#include "curl_ntlm_msgs.h" +#include "http_ntlm.h" #include "curl_ntlm_wb.h" -#include "curl_sasl.h" +#include "vauth/vauth.h" #include "url.h" -#include "curl_printf.h" #if defined(USE_NSS) #include "vtls/nssg.h" @@ -49,7 +47,8 @@ #include "curl_sspi.h" #endif -/* 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" @@ -77,7 +76,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn, header++; if(*header) { - result = Curl_sasl_decode_ntlm_type2_message(conn->data, header, ntlm); + result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm); if(result) return result; @@ -171,7 +170,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) case NTLMSTATE_TYPE1: default: /* for the weird cases we (re)start here */ /* Create a type-1 message */ - result = Curl_sasl_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, + result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64, &len); if(result) return result; @@ -191,7 +190,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) case NTLMSTATE_TYPE2: /* We already received the type-2 message, create a type-3 message */ - result = Curl_sasl_create_ntlm_type3_message(conn->data, userp, passwdp, + result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp, ntlm, &base64, &len); if(result) return result; @@ -228,8 +227,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) void Curl_http_ntlm_cleanup(struct connectdata *conn) { - Curl_sasl_ntlm_cleanup(&conn->ntlm); - Curl_sasl_ntlm_cleanup(&conn->proxyntlm); + Curl_auth_ntlm_cleanup(&conn->ntlm); + Curl_auth_ntlm_cleanup(&conn->proxyntlm); #if defined(NTLM_WB_ENABLED) Curl_ntlm_wb_cleanup(conn); diff --git a/project/jni/curl/lib/curl_ntlm.h b/project/jni/curl/lib/http_ntlm.h similarity index 100% rename from project/jni/curl/lib/curl_ntlm.h rename to project/jni/curl/lib/http_ntlm.h diff --git a/project/jni/curl/lib/http_proxy.c b/project/jni/curl/lib/http_proxy.c index e082ba291..814c572f6 100644 --- a/project/jni/curl/lib/http_proxy.c +++ b/project/jni/curl/lib/http_proxy.c @@ -35,11 +35,11 @@ #include "progress.h" #include "non-ascii.h" #include "connect.h" -#include "curl_printf.h" #include "curlx.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" CURLcode Curl_proxy_connect(struct connectdata *conn) @@ -49,6 +49,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) /* for [protocol] tunneled through HTTP proxy */ struct HTTP http_proxy; void *prot_save; + const char *hostname; + int remote_port; CURLcode result; /* BLOCKING */ @@ -67,8 +69,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port, FALSE); + if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; + if(conn->bits.conn_to_port) + remote_port = conn->conn_to_port; + else + remote_port = conn->remote_port; + result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname, + remote_port, FALSE); conn->data->req.protop = prot_save; if(CURLE_OK != result) return result; @@ -153,9 +163,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, const char *useragent=""; const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; - char *hostheader= /* host:port with IPv6 support */ - aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"", - hostname, conn->bits.ipv6_ip?"]":"", + bool ipv6_ip = conn->bits.ipv6_ip; + char *hostheader; + + /* the hostname may be different */ + if(hostname != conn->host.name) + ipv6_ip = (strchr(hostname, ':') != NULL); + hostheader= /* host:port with IPv6 support */ + aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"", remote_port); if(!hostheader) { Curl_add_buffer_free(req_buffer); diff --git a/project/jni/curl/lib/if2ip.c b/project/jni/curl/lib/if2ip.c index 63bea541d..2f92b2def 100644 --- a/project/jni/curl/lib/if2ip.c +++ b/project/jni/curl/lib/if2ip.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -53,10 +53,9 @@ #include "inet_ntop.h" #include "strequal.h" #include "if2ip.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* ------------------------------------------------------------------ */ diff --git a/project/jni/curl/lib/imap.c b/project/jni/curl/lib/imap.c index ff25e54e0..16ba402ca 100644 --- a/project/jni/curl/lib/imap.c +++ b/project/jni/curl/lib/imap.c @@ -80,10 +80,10 @@ #include "rawstr.h" #include "curl_sasl.h" #include "warnless.h" -#include "curl_printf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -364,7 +364,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, a space and optionally some text as per RFC-3501 for the AUTHENTICATE and APPEND commands and as outlined in Section 4. Examples of RFC-4959 but some e-mail servers ignore this and only send a single + instead. */ - if(!imap->custom && ((len == 3 && !memcmp("+", line, 1)) || + if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) || (len >= 2 && !memcmp("+ ", line, 2)))) { switch(imapc->state) { /* States which are interested in continuation responses */ @@ -1020,9 +1020,10 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, return result; } -/* For LIST responses */ -static CURLcode imap_state_list_resp(struct connectdata *conn, int imapcode, - imapstate instate) +/* For LIST and SEARCH responses */ +static CURLcode imap_state_listsearch_resp(struct connectdata *conn, + int imapcode, + imapstate instate) { CURLcode result = CURLE_OK; char *line = conn->data->state.buffer; @@ -1249,31 +1250,6 @@ static CURLcode imap_state_append_final_resp(struct connectdata *conn, return result; } -/* For SEARCH responses */ -static CURLcode imap_state_search_resp(struct connectdata *conn, int imapcode, - imapstate instate) -{ - CURLcode result = CURLE_OK; - char *line = conn->data->state.buffer; - size_t len = strlen(line); - - (void)instate; /* No use for this yet */ - - if(imapcode == '*') { - /* Temporarily add the LF character back and send as body to the client */ - line[len] = '\n'; - result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1); - line[len] = '\0'; - } - else if(imapcode != 'O') - result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */ - else - /* End of DO phase */ - state(conn, IMAP_STOP); - - return result; -} - static CURLcode imap_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; @@ -1327,7 +1303,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) break; case IMAP_LIST: - result = imap_state_list_resp(conn, imapcode, imapc->state); + result = imap_state_listsearch_resp(conn, imapcode, imapc->state); break; case IMAP_SELECT: @@ -1351,7 +1327,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) break; case IMAP_SEARCH: - result = imap_state_search_resp(conn, imapcode, imapc->state); + result = imap_state_listsearch_resp(conn, imapcode, imapc->state); break; case IMAP_LOGOUT: @@ -1486,10 +1462,6 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, (void)premature; if(!imap) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the IMAP struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { @@ -1512,8 +1484,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, TODO: when the multi interface is used, this _really_ should be using the imap_multi_statemach function but we have no general support for - non-blocking DONE operations, not in the multi state machine and with - Curl_done() invokes on several places in the code! + non-blocking DONE operations! */ if(!result) result = imap_block_statemach(conn); @@ -1825,6 +1796,7 @@ static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) */ static char *imap_atom(const char *str, bool escape_only) { + /* !checksrc! disable PARENBRACE 1 */ const char atom_specials[] = "(){ %*]"; const char *p1; char *p2; diff --git a/project/jni/curl/lib/inet_ntop.c b/project/jni/curl/lib/inet_ntop.c index da9a3ab43..416005c03 100644 --- a/project/jni/curl/lib/inet_ntop.c +++ b/project/jni/curl/lib/inet_ntop.c @@ -32,9 +32,8 @@ #include #endif -#include "curl_printf.h" - #include "inet_ntop.h" +#include "curl_printf.h" #define IN6ADDRSZ 16 #define INADDRSZ 4 @@ -57,10 +56,10 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) tmp[0] = '\0'; (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", - ((int)((unsigned char)src[0])) & 0xff, - ((int)((unsigned char)src[1])) & 0xff, - ((int)((unsigned char)src[2])) & 0xff, - ((int)((unsigned char)src[3])) & 0xff); + ((int)((unsigned char)src[0])) & 0xff, + ((int)((unsigned char)src[1])) & 0xff, + ((int)((unsigned char)src[2])) & 0xff, + ((int)((unsigned char)src[3])) & 0xff); len = strlen(tmp); if(len == 0 || len >= size) { diff --git a/project/jni/curl/lib/krb5.c b/project/jni/curl/lib/krb5.c index 65869c99d..0b146e06b 100644 --- a/project/jni/curl/lib/krb5.c +++ b/project/jni/curl/lib/krb5.c @@ -47,9 +47,9 @@ #include "sendf.h" #include "curl_sec.h" #include "warnless.h" -#include "curl_printf.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" @@ -152,7 +152,10 @@ krb5_auth(void *app_data, struct connectdata *conn) curl_socklen_t l = sizeof(conn->local_addr); struct SessionHandle *data = conn->data; CURLcode result; - const char *service = "ftp", *srv_host = "host"; + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + "ftp"; + const char *srv_host = "host"; gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp; OM_uint32 maj, min; gss_name_t gssname; @@ -180,9 +183,9 @@ krb5_auth(void *app_data, struct connectdata *conn) /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { result = Curl_ftpsendf(conn, "AUTH GSSAPI"); - if(result) return -2; + if(Curl_GetFTPResponse(&nread, conn, NULL)) return -1; diff --git a/project/jni/curl/lib/ldap.c b/project/jni/curl/lib/ldap.c index 4f4c7072a..1f1f72fba 100644 --- a/project/jni/curl/lib/ldap.c +++ b/project/jni/curl/lib/ldap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -76,9 +76,8 @@ #include "curl_base64.h" #include "rawstr.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -228,7 +227,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) goto quit; } - /* Get the URL scheme ( either ldap or ldaps ) */ + /* Get the URL scheme (either ldap or ldaps) */ if(conn->given->flags & PROTOPT_SSL) ldap_ssl = 1; infof(data, "LDAP local: trying to establish %s connection\n", @@ -717,7 +716,7 @@ static int str2scope (const char *p) return LDAP_SCOPE_BASE; if(strequal(p, "sub")) return LDAP_SCOPE_SUBTREE; - if(strequal( p, "subtree")) + if(strequal(p, "subtree")) return LDAP_SCOPE_SUBTREE; return (-1); } diff --git a/project/jni/curl/lib/llist.c b/project/jni/curl/lib/llist.c index 04b23e77c..482aaa041 100644 --- a/project/jni/curl/lib/llist.c +++ b/project/jni/curl/lib/llist.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #include "llist.h" #include "curl_memory.h" diff --git a/project/jni/curl/lib/md5.c b/project/jni/curl/lib/md5.c index 6df07dc06..84adb9926 100644 --- a/project/jni/curl/lib/md5.c +++ b/project/jni/curl/lib/md5.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,6 +24,8 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH +#include + #include "curl_md5.h" #include "curl_hmac.h" #include "warnless.h" diff --git a/project/jni/curl/lib/memdebug.c b/project/jni/curl/lib/memdebug.c index 804b5fa34..1618bbaf3 100644 --- a/project/jni/curl/lib/memdebug.c +++ b/project/jni/curl/lib/memdebug.c @@ -26,10 +26,12 @@ #include -#include "curl_printf.h" #include "urldata.h" #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" diff --git a/project/jni/curl/lib/memdebug.h b/project/jni/curl/lib/memdebug.h index ce1a842af..835dab38c 100644 --- a/project/jni/curl/lib/memdebug.h +++ b/project/jni/curl/lib/memdebug.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,10 +28,6 @@ * as well as the library. Do not mix with library internals! */ -#include "curl_setup.h" - -#include - #define CURL_MT_LOGFNAME_BUFSIZE 512 #define logfile curl_debuglogfile @@ -57,17 +53,17 @@ CURL_EXTERN void curl_memlog(const char *format, ...); /* file descriptor manipulators */ CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol, - int line , const char *source); + int line, const char *source); CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd, - int line , const char *source); + int line, const char *source); CURL_EXTERN int curl_sclose(curl_socket_t sockfd, - int line , const char *source); + int line, const char *source); CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen, int line, const char *source); #ifdef HAVE_SOCKETPAIR CURL_EXTERN int curl_socketpair(int domain, int type, int protocol, curl_socket_t socket_vector[2], - int line , const char *source); + int line, const char *source); #endif /* FILE functions */ diff --git a/project/jni/curl/lib/mprintf.c b/project/jni/curl/lib/mprintf.c index f5fc9962f..73f854bcb 100644 --- a/project/jni/curl/lib/mprintf.c +++ b/project/jni/curl/lib/mprintf.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1999 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1999 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,11 +36,6 @@ */ #include "curl_setup.h" - -#if defined(DJGPP) && (DJGPP_MINOR < 4) -#undef _MPRINTF_REPLACE /* don't use x_was_used() here */ -#endif - #include #include "curl_memory.h" @@ -465,22 +460,24 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, if(flags & FLAGS_WIDTHPARAM) { /* we have the width specified from a parameter, so we make that parameter's info setup properly */ - vto[i].width = width - 1; - i = width - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ + long k = width - 1; + vto[i].width = k; + vto[k].type = FORMAT_WIDTH; + vto[k].flags = FLAGS_NEW; + /* can't use width or precision of width! */ + vto[k].width = 0; + vto[k].precision = 0; } if(flags & FLAGS_PRECPARAM) { /* we have the precision specified from a parameter, so we make that parameter's info setup properly */ - vto[i].precision = precision - 1; - i = precision - 1; - vto[i].type = FORMAT_WIDTH; - vto[i].flags = FLAGS_NEW; - vto[i].precision = vto[i].width = 0; /* can't use width or precision - of width! */ + long k = precision - 1; + vto[i].precision = k; + vto[k].type = FORMAT_WIDTH; + vto[k].flags = FLAGS_NEW; + /* can't use width or precision of width! */ + vto[k].width = 0; + vto[k].precision = 0; } *endpos++ = fmt + 1; /* end of this sequence */ } @@ -488,11 +485,15 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, /* Read the arg list parameters into our data list */ for(i=0; iflags & FLAGS_WIDTHPARAM) + if(p->flags & FLAGS_WIDTHPARAM) { width = (long)vto[p->width].data.num.as_signed; + param_num++; /* since the width is extracted from a parameter, we + must skip that to get to the next one properly */ + if(width < 0) { + /* "A negative field width is taken as a '-' flag followed by a + positive field width." */ + width = -width; + p->flags |= FLAGS_LEFT; + p->flags &= ~FLAGS_PAD_NIL; + } + } else width = p->width; /* pick up the specified precision */ if(p->flags & FLAGS_PRECPARAM) { prec = (long)vto[p->precision].data.num.as_signed; - param_num++; /* since the precision is extraced from a parameter, we + param_num++; /* since the precision is extracted from a parameter, we must skip that to get to the next one properly */ + if(prec < 0) + /* "A negative precision is taken as if the precision were + omitted." */ + prec = -1; } else if(p->flags & FLAGS_PREC) prec = p->precision; @@ -715,72 +737,68 @@ static int dprintf_formatf( number: /* Number of base BASE. */ - { - char *workend = &work[sizeof(work) - 1]; - char *w; - /* Supply a default precision if none was given. */ - if(prec == -1) - prec = 1; + /* Supply a default precision if none was given. */ + if(prec == -1) + prec = 1; - /* Put the number in WORK. */ - w = workend; - while(num > 0) { - *w-- = digits[num % base]; - num /= base; - } - width -= (long)(workend - w); - prec -= (long)(workend - w); + /* Put the number in WORK. */ + w = workend; + while(num > 0) { + *w-- = digits[num % base]; + num /= base; + } + width -= (long)(workend - w); + prec -= (long)(workend - w); - if(is_alt && base == 8 && prec <= 0) { + if(is_alt && base == 8 && prec <= 0) { + *w-- = '0'; + --width; + } + + if(prec > 0) { + width -= prec; + while(prec-- > 0) *w-- = '0'; - --width; - } + } - if(prec > 0) { - width -= prec; - while(prec-- > 0) - *w-- = '0'; - } + if(is_alt && base == 16) + width -= 2; - if(is_alt && base == 16) - width -= 2; + if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) + --width; - if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE)) - --width; - - if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR(' '); - - if(is_neg) - OUTCHAR('-'); - else if(p->flags & FLAGS_SHOWSIGN) - OUTCHAR('+'); - else if(p->flags & FLAGS_SPACE) + if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL)) + while(width-- > 0) OUTCHAR(' '); - if(is_alt && base == 16) { - OUTCHAR('0'); - if(p->flags & FLAGS_UPPER) - OUTCHAR('X'); - else - OUTCHAR('x'); - } + if(is_neg) + OUTCHAR('-'); + else if(p->flags & FLAGS_SHOWSIGN) + OUTCHAR('+'); + else if(p->flags & FLAGS_SPACE) + OUTCHAR(' '); - if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) - while(width-- > 0) - OUTCHAR('0'); - - /* Write the number. */ - while(++w <= workend) { - OUTCHAR(*w); - } - - if(p->flags & FLAGS_LEFT) - while(width-- > 0) - OUTCHAR(' '); + if(is_alt && base == 16) { + OUTCHAR('0'); + if(p->flags & FLAGS_UPPER) + OUTCHAR('X'); + else + OUTCHAR('x'); } + + if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL)) + while(width-- > 0) + OUTCHAR('0'); + + /* Write the number. */ + while(++w <= workend) { + OUTCHAR(*w); + } + + if(p->flags & FLAGS_LEFT) + while(width-- > 0) + OUTCHAR(' '); break; case FORMAT_STRING: @@ -809,7 +827,7 @@ static int dprintf_formatf( else len = strlen(str); - width -= (long)len; + width -= (len > LONG_MAX) ? LONG_MAX : (long)len; if(p->flags & FLAGS_ALT) OUTCHAR('"'); diff --git a/project/jni/curl/lib/multi.c b/project/jni/curl/lib/multi.c index a147963f8..7e2725bab 100644 --- a/project/jni/curl/lib/multi.c +++ b/project/jni/curl/lib/multi.c @@ -42,9 +42,9 @@ #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* @@ -136,7 +136,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state connection_id = data->easy_conn->connection_id; infof(data, - "STATE: %s => %s handle %p; line %d (connection #%ld) \n", + "STATE: %s => %s handle %p; line %d (connection #%ld)\n", statename[oldstate], statename[data->mstate], (void *)data, lineno, connection_id); } @@ -484,6 +484,167 @@ static void debug_print_sock_hash(void *p) } #endif +/* Mark the connection as 'idle', or close it if the cache is full. + Returns TRUE if the connection is kept, or FALSE if it was closed. */ +static bool +ConnectionDone(struct SessionHandle *data, struct connectdata *conn) +{ + /* data->multi->maxconnects can be negative, deal with it. */ + size_t maxconnects = + (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: + data->multi->maxconnects; + struct connectdata *conn_candidate = NULL; + + /* Mark the current connection as 'unused' */ + conn->inuse = FALSE; + + if(maxconnects > 0 && + data->state.conn_cache->num_connections > maxconnects) { + infof(data, "Connection cache is full, closing the oldest one.\n"); + + conn_candidate = Curl_oldest_idle_connection(data); + + if(conn_candidate) { + /* Set the connection's owner correctly */ + conn_candidate->data = data; + + /* the winner gets the honour of being disconnected */ + (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); + } + } + + return (conn_candidate == conn) ? FALSE : TRUE; +} + +static CURLcode multi_done(struct connectdata **connp, + CURLcode status, /* an error if this is called + after an error was detected */ + bool premature) +{ + CURLcode result; + struct connectdata *conn; + struct SessionHandle *data; + + DEBUGASSERT(*connp); + + conn = *connp; + data = conn->data; + + DEBUGF(infof(data, "multi_done\n")); + + if(data->state.done) + /* Stop if multi_done() has already been called */ + return CURLE_OK; + + Curl_getoff_all_pipelines(data, conn); + + /* Cleanup possible redirect junk */ + free(data->req.newurl); + data->req.newurl = NULL; + free(data->req.location); + data->req.location = NULL; + + switch(status) { + case CURLE_ABORTED_BY_CALLBACK: + case CURLE_READ_ERROR: + case CURLE_WRITE_ERROR: + /* When we're aborted due to a callback return code it basically have to + be counted as premature as there is trouble ahead if we don't. We have + many callbacks and protocols work differently, we could potentially do + this more fine-grained in the future. */ + premature = TRUE; + default: + break; + } + + /* this calls the protocol-specific function pointer previously set */ + if(conn->handler->done) + result = conn->handler->done(conn, status, premature); + else + result = status; + + if(CURLE_ABORTED_BY_CALLBACK != result) { + /* avoid this if we already aborted by callback to avoid this calling + another callback */ + CURLcode rc = Curl_pgrsDone(conn); + if(!result && rc) + result = CURLE_ABORTED_BY_CALLBACK; + } + + if((!premature && + conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close)) { + /* Stop if pipeline is not empty and we do not have to close + connection. */ + DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n")); + return CURLE_OK; + } + + data->state.done = TRUE; /* called just now! */ + Curl_resolver_cancel(conn); + + if(conn->dns_entry) { + Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ + conn->dns_entry = NULL; + } + + /* if the transfer was completed in a paused state there can be buffered + data left to write and then kill */ + free(data->state.tempwrite); + data->state.tempwrite = NULL; + + /* if data->set.reuse_forbid is TRUE, it means the libcurl client has + forced us to close this connection. This is ignored for requests taking + place in a NTLM authentication handshake + + if conn->bits.close is TRUE, it means that the connection should be + closed in spite of all our efforts to be nice, due to protocol + restrictions in our or the server's end + + if premature is TRUE, it means this connection was said to be DONE before + the entire request operation is complete and thus we can't know in what + state it is for re-using, so we're forced to close it. In a perfect world + we can add code that keep track of if we really must close it here or not, + but currently we have no such detail knowledge. + */ + + if((data->set.reuse_forbid +#if defined(USE_NTLM) + && !(conn->ntlm.state == NTLMSTATE_TYPE2 || + conn->proxyntlm.state == NTLMSTATE_TYPE2) +#endif + ) || conn->bits.close || premature) { + CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ + + /* If we had an error already, make sure we return that one. But + if we got a new error, return that. */ + if(!result && res2) + result = res2; + } + else { + /* the connection is no longer in use */ + if(ConnectionDone(data, conn)) { + /* remember the most recently used connection */ + data->state.lastconnect = conn; + + infof(data, "Connection #%ld to host %s left intact\n", + conn->connection_id, + conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + } + else + data->state.lastconnect = NULL; + } + + *connp = NULL; /* to make the caller of this function better detect that + this was either closed or handed over to the connection + cache here, and therefore cannot be used from this point on + */ + Curl_free_request_state(data); + + return result; +} + CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle) { @@ -529,8 +690,8 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, request but not received its response yet, we need to close connection. */ connclose(data->easy_conn, "Removed with partial response"); - /* Set connection owner so that Curl_done() closes it. - We can safely do this here since connection is killed. */ + /* Set connection owner so that the DONE function closes it. We can + safely do this here since connection is killed. */ data->easy_conn->data = easy; easy_owns_conn = TRUE; } @@ -548,26 +709,26 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, if(data->easy_conn) { - /* we must call Curl_done() here (if we still "own it") so that we don't - leave a half-baked one around */ + /* we must call multi_done() here (if we still own the connection) so that + we don't leave a half-baked one around */ if(easy_owns_conn) { - /* Curl_done() clears the conn->data field to lose the association + /* multi_done() clears the conn->data field to lose the association between the easy handle and the connection Note that this ignores the return code simply because there's nothing really useful to do with it anyway! */ - (void)Curl_done(&data->easy_conn, data->result, premature); + (void)multi_done(&data->easy_conn, data->result, premature); } else - /* Clear connection pipelines, if Curl_done above was not called */ + /* Clear connection pipelines, if multi_done above was not called */ Curl_getoff_all_pipelines(data, data->easy_conn); } Curl_wildcard_dtor(&data->wildcard); /* destroy the timeout list that is held in the easy handle, do this *after* - Curl_done() as that may actuall call Curl_expire that uses this */ + multi_done() as that may actually call Curl_expire that uses this */ if(data->state.timeoutlist) { Curl_llist_destroy(data->state.timeoutlist, NULL); data->state.timeoutlist = NULL; @@ -990,6 +1151,139 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, return rc; } +static CURLcode multi_reconnect_request(struct connectdata **connp) +{ + CURLcode result = CURLE_OK; + struct connectdata *conn = *connp; + struct SessionHandle *data = conn->data; + + /* This was a re-use of a connection and we got a write error in the + * DO-phase. Then we DISCONNECT this connection and have another attempt to + * CONNECT and then DO again! The retry cannot possibly find another + * connection to re-use, since we only keep one possible connection for + * each. */ + + infof(data, "Re-used connection seems dead, get a new one\n"); + + connclose(conn, "Reconnect dead connection"); /* enforce close */ + result = multi_done(&conn, result, FALSE); /* we are so done with this */ + + /* conn may no longer be a good pointer, clear it to avoid mistakes by + parent functions */ + *connp = NULL; + + /* + * We need to check for CURLE_SEND_ERROR here as well. This could happen + * when the request failed on a FTP connection and thus multi_done() itself + * tried to use the connection (again). + */ + if(!result || (CURLE_SEND_ERROR == result)) { + bool async; + bool protocol_done = TRUE; + + /* Now, redo the connect and get a new connection */ + result = Curl_connect(data, connp, &async, &protocol_done); + if(!result) { + /* We have connected or sent away a name resolve query fine */ + + conn = *connp; /* setup conn to again point to something nice */ + if(async) { + /* Now, if async is TRUE here, we need to wait for the name + to resolve */ + result = Curl_resolver_wait_resolv(conn, NULL); + if(result) + return result; + + /* Resolved, continue with the connection */ + result = Curl_async_resolved(conn, &protocol_done); + if(result) + return result; + } + } + } + + return result; +} + +/* + * do_complete is called when the DO actions are complete. + * + * We init chunking and trailer bits to their default values here immediately + * before receiving any header data for the current request in the pipeline. + */ +static void do_complete(struct connectdata *conn) +{ + conn->data->req.chunk=FALSE; + conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? + conn->sockfd:conn->writesockfd)+1; + Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); +} + +static CURLcode multi_do(struct connectdata **connp, bool *done) +{ + CURLcode result=CURLE_OK; + struct connectdata *conn = *connp; + struct SessionHandle *data = conn->data; + + if(conn->handler->do_it) { + /* generic protocol-specific function pointer set in curl_connect() */ + result = conn->handler->do_it(conn, done); + + /* This was formerly done in transfer.c, but we better do it here */ + if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { + /* + * If the connection is using an easy handle, call reconnect + * to re-establish the connection. Otherwise, let the multi logic + * figure out how to re-establish the connection. + */ + if(!data->multi) { + result = multi_reconnect_request(connp); + + if(!result) { + /* ... finally back to actually retry the DO phase */ + conn = *connp; /* re-assign conn since multi_reconnect_request + creates a new connection */ + result = conn->handler->do_it(conn, done); + } + } + else + return result; + } + + if(!result && *done) + /* do_complete must be called after the protocol-specific DO function */ + do_complete(conn); + } + return result; +} + +/* + * multi_do_more() is called during the DO_MORE multi state. It is basically a + * second stage DO state which (wrongly) was introduced to support FTP's + * second connection. + * + * TODO: A future libcurl should be able to work away this state. + * + * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to + * DOING state there's more work to do! + */ + +static CURLcode multi_do_more(struct connectdata *conn, int *complete) +{ + CURLcode result=CURLE_OK; + + *complete = 0; + + if(conn->handler->do_more) + result = conn->handler->do_more(conn, complete); + + if(!result && (*complete == 1)) + /* do_complete must be called after the protocol-specific DO function */ + do_complete(conn); + + return result; +} + static CURLMcode multi_runsingle(struct Curl_multi *multi, struct timeval now, struct SessionHandle *data) @@ -1075,7 +1369,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, failf(data, "Operation timed out after %ld milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %" CURL_FORMAT_CURL_OFF_T " bytes received", - Curl_tvdiff(k->now, data->progress.t_startsingle), + Curl_tvdiff(now, data->progress.t_startsingle), k->bytecount, k->size); } else { @@ -1092,7 +1386,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, disconnect_conn = TRUE; } result = CURLE_OPERATION_TIMEDOUT; - (void)Curl_done(&data->easy_conn, result, TRUE); + (void)multi_done(&data->easy_conn, result, TRUE); /* Skip the statemachine and go directly to error handling section. */ goto statemachine_end; } @@ -1170,9 +1464,17 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, { struct Curl_dns_entry *dns = NULL; struct connectdata *conn = data->easy_conn; + const char *hostname; + + if(conn->bits.proxy) + hostname = conn->proxy.name; + else if(conn->bits.conn_to_host) + hostname = conn->conn_to_host.name; + else + hostname = conn->host.name; /* check if we have the name resolved by now */ - dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port); + dns = Curl_fetch_addr(conn, hostname, (int)conn->port); if(dns) { #ifdef CURLRES_ASYNCH @@ -1180,7 +1482,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, conn->async.done = TRUE; #endif result = CURLE_OK; - infof(data, "Hostname was found in DNS cache\n"); + infof(data, "Hostname '%s' was found in DNS cache\n", hostname); } if(!dns) @@ -1237,7 +1539,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, rc = CURLM_CALL_MULTI_PERFORM; /* connect back to proxy again */ result = CURLE_OK; - Curl_done(&data->easy_conn, CURLE_OK, FALSE); + multi_done(&data->easy_conn, CURLE_OK, FALSE); multistate(data, CURLM_STATE_CONNECT); } else if(!result) { @@ -1281,7 +1583,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, TRUE); + multi_done(&data->easy_conn, result, TRUE); disconnect_conn = TRUE; } break; @@ -1298,7 +1600,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, TRUE); + multi_done(&data->easy_conn, result, TRUE); disconnect_conn = TRUE; } break; @@ -1322,9 +1624,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else { /* Perform the protocol's DO action */ - result = Curl_do(&data->easy_conn, &dophase_done); + result = multi_do(&data->easy_conn, &dophase_done); - /* When Curl_do() returns failure, data->easy_conn might be NULL! */ + /* When multi_do() returns failure, data->easy_conn might be NULL! */ if(!result) { if(!dophase_done) { @@ -1333,7 +1635,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, struct WildcardData *wc = &data->wildcard; if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { /* skip some states if it is important */ - Curl_done(&data->easy_conn, CURLE_OK, FALSE); + multi_done(&data->easy_conn, CURLE_OK, FALSE); multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; break; @@ -1380,7 +1682,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, retry = (newurl)?TRUE:FALSE; Curl_posttransfer(data); - drc = Curl_done(&data->easy_conn, result, FALSE); + drc = multi_done(&data->easy_conn, result, FALSE); /* When set to retry the connection, we must to go back to * the CONNECT state */ @@ -1415,7 +1717,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); if(data->easy_conn) - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } } @@ -1437,7 +1739,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; @@ -1446,10 +1748,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* * When we are connected, DO MORE and then go DO_DONE */ - result = Curl_do_more(data->easy_conn, &control); + result = multi_do_more(data->easy_conn, &control); /* No need to remove this handle from the send pipeline here since that - is done in Curl_done() */ + is done in multi_done() */ if(!result) { if(control) { /* if positive, advance to DO_DONE @@ -1466,7 +1768,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else { /* failure detected */ Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); disconnect_conn = TRUE; } break; @@ -1504,7 +1806,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, result = Curl_speedcheck(data, now); if(( (data->set.max_send_speed == 0) || - (data->progress.ulspeed < data->set.max_send_speed )) && + (data->progress.ulspeed < data->set.max_send_speed)) && ( (data->set.max_recv_speed == 0) || (data->progress.dlspeed < data->set.max_recv_speed))) multistate(data, CURLM_STATE_PERFORM); @@ -1586,11 +1888,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, * happened in the data connection. */ - if(!(data->easy_conn->handler->flags & PROTOPT_DUAL)) + if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) && + result != CURLE_HTTP2_STREAM) connclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - Curl_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, FALSE); } else if(done) { followtype follow=FOLLOW_NONE; @@ -1621,7 +1924,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else follow = FOLLOW_RETRY; - result = Curl_done(&data->easy_conn, CURLE_OK, FALSE); + result = multi_done(&data->easy_conn, CURLE_OK, FALSE); if(!result) { result = Curl_follow(data, newurl, follow); if(!result) { @@ -1671,14 +1974,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_multi_process_pending_handles(multi); /* post-transfer command */ - res = Curl_done(&data->easy_conn, result, FALSE); + res = multi_done(&data->easy_conn, result, FALSE); /* allow a previously set error code take precedence */ if(!result) result = res; /* - * If there are other handles on the pipeline, Curl_done won't set + * If there are other handles on the pipeline, multi_done won't set * easy_conn to NULL. In such a case, curl_multi_remove_handle() can * access free'd data, if the connection is free'd and the handle * removed before we perform the processing in CURLM_STATE_COMPLETED @@ -1697,7 +2000,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } /* after we have DONE what we're supposed to do, go COMPLETED, and - it doesn't matter what the Curl_done() returned! */ + it doesn't matter what the multi_done() returned! */ multistate(data, CURLM_STATE_COMPLETED); break; @@ -1813,27 +2116,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) data=multi->easyp; while(data) { CURLMcode result; - struct WildcardData *wc = &data->wildcard; SIGPIPE_VARIABLE(pipe_st); - if(data->set.wildcardmatch) { - if(!wc->filelist) { - CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */ - if(ret) - return CURLM_OUT_OF_MEMORY; - } - } - sigpipe_ignore(data, &pipe_st); result = multi_runsingle(multi, now, data); sigpipe_restore(&pipe_st); - if(data->set.wildcardmatch) { - /* destruct wildcard structures if it is needed */ - if(wc->state == CURLWC_DONE || result) - Curl_wildcard_dtor(wc); - } - if(result) returncode = result; @@ -2184,7 +2472,7 @@ static CURLMcode add_next_timeout(struct timeval now, /* move over the timeout list for this specific handle and remove all timeouts that are now passed tense and store the next pending timeout in *tv */ - for(e = list->head; e; ) { + for(e = list->head; e;) { struct curl_llist_element *n = e->next; long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); if(diff <= 0) diff --git a/project/jni/curl/lib/netrc.c b/project/jni/curl/lib/netrc.c index 541310e2b..46f427a2b 100644 --- a/project/jni/curl/lib/netrc.c +++ b/project/jni/curl/lib/netrc.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,9 +32,9 @@ #include "strequal.h" #include "strtok.h" #include "rawstr.h" -#include "curl_printf.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/project/jni/curl/lib/nwlib.c b/project/jni/curl/lib/nwlib.c index 7feb8fc3b..42b6aa0da 100644 --- a/project/jni/curl/lib/nwlib.c +++ b/project/jni/curl/lib/nwlib.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -58,26 +58,26 @@ rtag_t gAllocTag = (rtag_t) NULL; NXMutex_t *gLibLock = (NXMutex_t *) NULL; /* internal library function prototypes... */ -int DisposeLibraryData( void * ); -void DisposeThreadData( void * ); -int GetOrSetUpData( int id, libdata_t **data, libthreaddata_t **threaddata ); +int DisposeLibraryData(void *); +void DisposeThreadData(void *); +int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata); -int _NonAppStart( void *NLMHandle, - void *errorScreen, - const char *cmdLine, - const char *loadDirPath, - size_t uninitializedDataLength, - void *NLMFileHandle, - int (*readRoutineP)( int conn, - void *fileHandle, size_t offset, - size_t nbytes, - size_t *bytesRead, - void *buffer ), +int _NonAppStart(void *NLMHandle, + void *errorScreen, + const char *cmdLine, + const char *loadDirPath, + size_t uninitializedDataLength, + void *NLMFileHandle, + int (*readRoutineP)(int conn, + void *fileHandle, size_t offset, + size_t nbytes, + size_t *bytesRead, + void *buffer), size_t customDataOffset, size_t customDataSize, int messageCount, - const char **messages ) + const char **messages) { NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); @@ -132,7 +132,7 @@ int _NonAppStart( void *NLMHandle, * Here we clean up any resources we allocated. Resource tags is a big part * of what we created, but NetWare doesn't ask us to free those. */ -void _NonAppStop( void ) +void _NonAppStop(void) { (void) unregister_library(gLibId); NXMutexFree(gLibLock); @@ -149,13 +149,13 @@ void _NonAppStop( void ) * we return a non-zero value. Right now, there isn't any reason not to allow * it. */ -int _NonAppCheckUnload( void ) +int _NonAppCheckUnload(void) { return 0; } int GetOrSetUpData(int id, libdata_t **appData, - libthreaddata_t **threadData ) + libthreaddata_t **threadData) { int err; libdata_t *app_data; @@ -277,7 +277,7 @@ int GetOrSetUpData(int id, libdata_t **appData, return err; } -int DisposeLibraryData( void *data ) +int DisposeLibraryData(void *data) { if(data) { void *tenbytes = ((libdata_t *) data)->tenbytes; @@ -289,7 +289,7 @@ int DisposeLibraryData( void *data ) return 0; } -void DisposeThreadData( void *data ) +void DisposeThreadData(void *data) { if(data) { void *twentybytes = ((libthreaddata_t *) data)->twentybytes; @@ -303,7 +303,7 @@ void DisposeThreadData( void *data ) /* For native CLib-based NLM seems we can do a bit more simple. */ #include -int main ( void ) +int main (void) { /* initialize any globals here... */ diff --git a/project/jni/curl/lib/nwos.c b/project/jni/curl/lib/nwos.c index 28137e919..385f9c8ad 100644 --- a/project/jni/curl/lib/nwos.c +++ b/project/jni/curl/lib/nwos.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ -int netware_init ( void ) +int netware_init (void) { return 0; } @@ -45,7 +45,7 @@ NETDB_DEFINE_CONTEXT #include NETINET_DEFINE_CONTEXT -int netware_init ( void ) +int netware_init (void) { int rc = 0; unsigned int myHandle = GetNLMHandle(); @@ -72,13 +72,13 @@ int netware_init ( void ) } /* dummy function to satisfy newer prelude */ -int __init_environment ( void ) +int __init_environment (void) { return 0; } /* dummy function to satisfy newer prelude */ -int __deinit_environment ( void ) +int __deinit_environment (void) { return 0; } diff --git a/project/jni/curl/lib/openldap.c b/project/jni/curl/lib/openldap.c index 7241bb906..01567acd1 100644 --- a/project/jni/curl/lib/openldap.c +++ b/project/jni/curl/lib/openldap.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, Howard Chu, - * Copyright (C) 2011 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2011 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -46,9 +46,8 @@ #include "curl_ldap.h" #include "curl_base64.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" diff --git a/project/jni/curl/lib/pingpong.c b/project/jni/curl/lib/pingpong.c index 5fea5dee7..ce2b58612 100644 --- a/project/jni/curl/lib/pingpong.c +++ b/project/jni/curl/lib/pingpong.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,10 +34,10 @@ #include "multiif.h" #include "non-ascii.h" #include "vtls/vtls.h" -#include "curl_printf.h" +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #ifdef USE_PINGPONG @@ -88,7 +88,7 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) struct SessionHandle *data=conn->data; CURLcode result = CURLE_OK; - if(timeout_ms <=0 ) { + if(timeout_ms <=0) { failf(data, "server response timeout"); return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } diff --git a/project/jni/curl/lib/pop3.c b/project/jni/curl/lib/pop3.c index 823761d2e..a6b2c3f75 100644 --- a/project/jni/curl/lib/pop3.c +++ b/project/jni/curl/lib/pop3.c @@ -83,9 +83,9 @@ #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -1166,10 +1166,6 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, (void)premature; if(!pop3) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the POP3 struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { diff --git a/project/jni/curl/lib/rtsp.c b/project/jni/curl/lib/rtsp.c index 24bf801d9..5cb104488 100644 --- a/project/jni/curl/lib/rtsp.c +++ b/project/jni/curl/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,9 +36,8 @@ #include "rawstr.h" #include "select.h" #include "connect.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" - -/* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" diff --git a/project/jni/curl/lib/sendf.c b/project/jni/curl/lib/sendf.c index ea04ae83e..22f3bf27c 100644 --- a/project/jni/curl/lib/sendf.c +++ b/project/jni/curl/lib/sendf.c @@ -31,10 +31,11 @@ #include "ssh.h" #include "multiif.h" #include "non-ascii.h" -#include "curl_printf.h" #include "strerror.h" +#include "select.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" @@ -120,6 +121,90 @@ static size_t convert_lineends(struct SessionHandle *data, } #endif /* CURL_DO_LINEEND_CONV */ +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND +static void pre_receive_plain(struct connectdata *conn, int num) +{ + const curl_socket_t sockfd = conn->sock[num]; + struct postponed_data * const psnd = &(conn->postponed[num]); + size_t bytestorecv = psnd->allocated_size - psnd->recv_size; + /* WinSock will destroy unread received data if send() is + failed. + To avoid lossage of received data, recv() must be + performed before every send() if any incoming data is + available. However, skip this, if buffer is already full. */ + if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 && + conn->recv[num] == Curl_recv_plain && + (!psnd->buffer || bytestorecv)) { + const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD, + CURL_SOCKET_BAD, 0); + if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) { + /* Have some incoming data */ + if(!psnd->buffer) { + /* Use buffer double default size for intermediate buffer */ + psnd->allocated_size = 2 * BUFSIZE; + psnd->buffer = malloc(psnd->allocated_size); + psnd->recv_size = 0; + psnd->recv_processed = 0; +#ifdef DEBUGBUILD + psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */ +#endif /* DEBUGBUILD */ + bytestorecv = psnd->allocated_size; + } + if(psnd->buffer) { + ssize_t recvedbytes; + DEBUGASSERT(psnd->bindsock == sockfd); + recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size, + bytestorecv); + if(recvedbytes > 0) + psnd->recv_size += recvedbytes; + } + else + psnd->allocated_size = 0; + } + } +} + +static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf, + size_t len) +{ + struct postponed_data * const psnd = &(conn->postponed[num]); + size_t copysize; + if(!psnd->buffer) + return 0; + + DEBUGASSERT(psnd->allocated_size > 0); + DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); + DEBUGASSERT(psnd->recv_processed <= psnd->recv_size); + /* Check and process data that already received and storied in internal + intermediate buffer */ + if(psnd->recv_size > psnd->recv_processed) { + DEBUGASSERT(psnd->bindsock == conn->sock[num]); + copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed); + memcpy(buf, psnd->buffer + psnd->recv_processed, copysize); + psnd->recv_processed += copysize; + } + else + copysize = 0; /* buffer was allocated, but nothing was received */ + + /* Free intermediate buffer if it has no unprocessed data */ + if(psnd->recv_processed == psnd->recv_size) { + free(psnd->buffer); + psnd->buffer = NULL; + psnd->allocated_size = 0; + psnd->recv_size = 0; + psnd->recv_processed = 0; +#ifdef DEBUGBUILD + psnd->bindsock = CURL_SOCKET_BAD; +#endif /* DEBUGBUILD */ + } + return (ssize_t)copysize; +} +#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ +/* Use "do-nothing" macros instead of functions when workaround not used */ +#define pre_receive_plain(c,n) do {} WHILE_FALSE +#define get_pre_recved(c,n,b,l) 0 +#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ + /* Curl_infof() is for info message along the way */ void Curl_infof(struct SessionHandle *data, const char *fmt, ...) @@ -254,7 +339,23 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num, const void *mem, size_t len, CURLcode *code) { curl_socket_t sockfd = conn->sock[num]; - ssize_t bytes_written = swrite(sockfd, mem, len); + ssize_t bytes_written; + /* WinSock will destroy unread received data if send() is + failed. + To avoid lossage of received data, recv() must be + performed before every send() if any incoming data is + available. */ + pre_receive_plain(conn, num); + +#ifdef MSG_FASTOPEN /* Linux */ + if(conn->bits.tcp_fastopen) { + bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN, + conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen); + conn->bits.tcp_fastopen = FALSE; + } + else +#endif + bytes_written = swrite(sockfd, mem, len); *code = CURLE_OK; if(-1 == bytes_written) { @@ -268,7 +369,8 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num, /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned due to its inability to send off data without blocking. We therefor treat both error codes the same here */ - (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) + (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) || + (EINPROGRESS == err) #endif ) { /* this is just a case of EWOULDBLOCK */ @@ -311,7 +413,16 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, size_t len, CURLcode *code) { curl_socket_t sockfd = conn->sock[num]; - ssize_t nread = sread(sockfd, buf, len); + ssize_t nread; + /* Check and return data that already received and storied in internal + intermediate buffer */ + nread = get_pre_recved(conn, num, buf, len); + if(nread > 0) { + *code = CURLE_OK; + return nread; + } + + nread = sread(sockfd, buf, len); *code = CURLE_OK; if(-1 == nread) { diff --git a/project/jni/curl/lib/share.c b/project/jni/curl/lib/share.c index 01503e06e..58c591231 100644 --- a/project/jni/curl/lib/share.c +++ b/project/jni/curl/lib/share.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -71,14 +71,14 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) /* this is a type this share will share */ type = va_arg(param, int); share->specifier |= (1<cookies) { - share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE ); + share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE); if(!share->cookies) res = CURLSHE_NOMEM; } @@ -114,7 +114,7 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) /* this is a type this share will no longer share */ type = va_arg(param, int); share->specifier &= ~(1<, et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,6 +22,8 @@ #include "curl_setup.h" +#include + #include "slist.h" /* The last #include files should be: */ diff --git a/project/jni/curl/lib/smtp.c b/project/jni/curl/lib/smtp.c index 83e51bf80..83eb1d623 100644 --- a/project/jni/curl/lib/smtp.c +++ b/project/jni/curl/lib/smtp.c @@ -82,9 +82,9 @@ #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local API functions */ @@ -1204,10 +1204,6 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, (void)premature; if(!smtp || !pp->conn) - /* When the easy handle is removed from the multi interface while libcurl - is still trying to resolve the host name, the SMTP struct is not yet - initialized. However, the removal action calls Curl_done() which in - turn calls this function, so we simply return success. */ return CURLE_OK; if(status) { @@ -1262,8 +1258,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, TODO: when the multi interface is used, this _really_ should be using the smtp_multi_statemach function but we have no general support for - non-blocking DONE operations, not in the multi state machine and with - Curl_done() invokes on several places in the code! + non-blocking DONE operations! */ result = smtp_block_statemach(conn); } diff --git a/project/jni/curl/lib/socks.c b/project/jni/curl/lib/socks.c index e7d42e77b..8c4129647 100644 --- a/project/jni/curl/lib/socks.c +++ b/project/jni/curl/lib/socks.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -173,8 +173,8 @@ CURLcode Curl_SOCKS4(const char *proxy_name, unsigned short ip[4]; Curl_printable_address(hp, buf, sizeof(buf)); - if(4 == sscanf( buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { + if(4 == sscanf(buf, "%hu.%hu.%hu.%hu", + &ip[0], &ip[1], &ip[2], &ip[3])) { /* Set DSTIP */ socksreq[4] = (unsigned char)ip[0]; socksreq[5] = (unsigned char)ip[1]; diff --git a/project/jni/curl/lib/socks_gssapi.c b/project/jni/curl/lib/socks_gssapi.c index 09457aecd..1214048bf 100644 --- a/project/jni/curl/lib/socks_gssapi.c +++ b/project/jni/curl/lib/socks_gssapi.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2009, 2011, Markus Moeller, - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,9 +32,10 @@ #include "timeval.h" #include "socks.h" #include "warnless.h" + +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; @@ -120,7 +121,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned short us_length; char *user=NULL; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ - char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; + const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; /* GSS-API request looks like * +----+------+-----+----------------+ diff --git a/project/jni/curl/lib/socks_sspi.c b/project/jni/curl/lib/socks_sspi.c index 356772e1f..ec564b488 100644 --- a/project/jni/curl/lib/socks_sspi.c +++ b/project/jni/curl/lib/socks_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * Copyright (C) 2009, 2011, Markus Moeller, * * This software is licensed as described in the file COPYING, which @@ -34,9 +34,9 @@ #include "curl_sspi.h" #include "curl_multibyte.h" #include "warnless.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* @@ -70,7 +70,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* Needs GSS-API authentication */ SECURITY_STATUS status; unsigned long sspi_ret_flags = 0; - int gss_enc; + unsigned char gss_enc; SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3]; SecBufferDesc input_desc, output_desc, wrap_desc; SecPkgContext_Sizes sspi_sizes; @@ -83,7 +83,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned short us_length; unsigned long qop; unsigned char socksreq[4]; /* room for GSS-API exchange header only */ - char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; + const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? + data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; /* GSS-API request looks like * +----+------+-----+----------------+ diff --git a/project/jni/curl/lib/splay.h b/project/jni/curl/lib/splay.h index 1af9414de..427bfc8eb 100644 --- a/project/jni/curl/lib/splay.h +++ b/project/jni/curl/lib/splay.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1997 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,7 +55,7 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, #define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \ - ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0 )))) + ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0)))) #ifdef DEBUGBUILD void Curl_splayprint(struct Curl_tree * t, int d, char output); diff --git a/project/jni/curl/lib/ssh.c b/project/jni/curl/lib/ssh.c index e63446bed..50a72ac6e 100644 --- a/project/jni/curl/lib/ssh.c +++ b/project/jni/curl/lib/ssh.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -83,9 +83,10 @@ #include "multiif.h" #include "select.h" #include "warnless.h" + +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" #ifdef WIN32 @@ -362,6 +363,9 @@ static void state(struct connectdata *conn, sshstate nowstate) "SSH_SFTP_QUOTE_RENAME", "SSH_SFTP_QUOTE_RMDIR", "SSH_SFTP_QUOTE_UNLINK", + "SSH_SFTP_QUOTE_STATVFS", + "SSH_SFTP_GETINFO", + "SSH_SFTP_FILETIME", "SSH_SFTP_TRANS_INIT", "SSH_SFTP_UPLOAD_INIT", "SSH_SFTP_CREATE_DIRS_INIT", @@ -414,7 +418,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, if(!working_path) return CURLE_OUT_OF_MEMORY; - /* Check for /~/ , indicating relative to the user's home directory */ + /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { real_path = malloc(working_path_len+1); if(real_path == NULL) { @@ -1183,7 +1187,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE); } else { - state(conn, SSH_SFTP_TRANS_INIT); + state(conn, SSH_SFTP_GETINFO); } break; @@ -1361,6 +1365,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_UNLINK); break; } + else if(curl_strnequal(cmd, "statvfs ", 8)) { + state(conn, SSH_SFTP_QUOTE_STATVFS); + break; + } failf(data, "Unknown SFTP command"); Curl_safefree(sshc->quote_path1); @@ -1372,7 +1380,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } } if(!sshc->quote_item) { - state(conn, SSH_SFTP_TRANS_INIT); + state(conn, SSH_SFTP_GETINFO); } break; @@ -1391,7 +1399,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->nextstate = SSH_NO_STATE; } else { - state(conn, SSH_SFTP_TRANS_INIT); + state(conn, SSH_SFTP_GETINFO); } } break; @@ -1611,6 +1619,87 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_NEXT_QUOTE); break; + case SSH_SFTP_QUOTE_STATVFS: + { + LIBSSH2_SFTP_STATVFS statvfs; + rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1, + curlx_uztoui(strlen(sshc->quote_path1)), + &statvfs); + + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + else if(rc != 0 && !sshc->acceptfail) { + err = sftp_libssh2_last_error(sshc->sftp_session); + Curl_safefree(sshc->quote_path1); + failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err)); + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = CURLE_QUOTE_ERROR; + break; + } + else if(rc == 0) { + char *tmp = aprintf("statvfs:\n" + "f_bsize: %llu\n" "f_frsize: %llu\n" + "f_blocks: %llu\n" "f_bfree: %llu\n" + "f_bavail: %llu\n" "f_files: %llu\n" + "f_ffree: %llu\n" "f_favail: %llu\n" + "f_fsid: %llu\n" "f_flag: %llu\n" + "f_namemax: %llu\n", + statvfs.f_bsize, statvfs.f_frsize, + statvfs.f_blocks, statvfs.f_bfree, + statvfs.f_bavail, statvfs.f_files, + statvfs.f_ffree, statvfs.f_favail, + statvfs.f_fsid, statvfs.f_flag, + statvfs.f_namemax); + if(!tmp) { + result = CURLE_OUT_OF_MEMORY; + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + break; + } + + result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp)); + free(tmp); + if(result) { + state(conn, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + sshc->actualcode = result; + } + } + state(conn, SSH_SFTP_NEXT_QUOTE); + break; + } + + case SSH_SFTP_GETINFO: + { + if(data->set.get_filetime) { + state(conn, SSH_SFTP_FILETIME); + } + else { + state(conn, SSH_SFTP_TRANS_INIT); + } + break; + } + + case SSH_SFTP_FILETIME: + { + LIBSSH2_SFTP_ATTRIBUTES attrs; + + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, + curlx_uztoui(strlen(sftp_scp->path)), + LIBSSH2_SFTP_STAT, &attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) { + break; + } + else if(rc == 0) { + data->info.filetime = (long)attrs.mtime; + } + + state(conn, SSH_SFTP_TRANS_INIT); + break; + } + case SSH_SFTP_TRANS_INIT: if(data->set.upload) state(conn, SSH_SFTP_UPLOAD_INIT); @@ -2980,8 +3069,7 @@ static CURLcode ssh_done(struct connectdata *conn, CURLcode status) TODO: when the multi interface is used, this _really_ should be using the ssh_multi_statemach function but we have no general support for - non-blocking DONE operations, not in the multi state machine and with - Curl_done() invokes on several places in the code! + non-blocking DONE operations! */ result = ssh_block_statemach(conn, FALSE); } diff --git a/project/jni/curl/lib/ssh.h b/project/jni/curl/lib/ssh.h index 6a5e73139..5b4b78ff4 100644 --- a/project/jni/curl/lib/ssh.h +++ b/project/jni/curl/lib/ssh.h @@ -66,6 +66,9 @@ typedef enum { SSH_SFTP_QUOTE_RENAME, SSH_SFTP_QUOTE_RMDIR, SSH_SFTP_QUOTE_UNLINK, + SSH_SFTP_QUOTE_STATVFS, + SSH_SFTP_GETINFO, + SSH_SFTP_FILETIME, SSH_SFTP_TRANS_INIT, SSH_SFTP_UPLOAD_INIT, SSH_SFTP_CREATE_DIRS_INIT, diff --git a/project/jni/curl/lib/strdup.c b/project/jni/curl/lib/strdup.c index 30a42f3d9..23f554e51 100644 --- a/project/jni/curl/lib/strdup.c +++ b/project/jni/curl/lib/strdup.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,7 +19,11 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "curl_setup.h" + +#include + #include "strdup.h" #include "curl_memory.h" diff --git a/project/jni/curl/lib/strerror.c b/project/jni/curl/lib/strerror.c index d222a1fc0..0e268d5e3 100644 --- a/project/jni/curl/lib/strerror.c +++ b/project/jni/curl/lib/strerror.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2004 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,9 +44,9 @@ #endif #include "strerror.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" const char * @@ -305,6 +305,9 @@ curl_easy_strerror(CURLcode error) case CURLE_SSL_INVALIDCERTSTATUS: return "SSL server certificate status verification FAILED"; + case CURLE_HTTP2_STREAM: + return "Stream error in the HTTP/2 framing layer"; + /* error codes not used by current libcurl */ case CURLE_OBSOLETE20: case CURLE_OBSOLETE24: @@ -1076,14 +1079,13 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) strncpy(outbuf, txt, outmax); else if(err == SEC_E_ILLEGAL_MESSAGE) snprintf(outbuf, outmax, - "SEC_E_ILLEGAL_MESSAGE (0x%04X%04X) - This error usually occurs " + "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs " "when a fatal SSL/TLS alert is received (e.g. handshake failed). " "More detail may be available in the Windows System event log.", - (err >> 16) & 0xffff, err & 0xffff); + err); else { str = txtbuf; - snprintf(txtbuf, sizeof(txtbuf), "%s (0x%04X%04X)", - txt, (err >> 16) & 0xffff, err & 0xffff); + snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err); txtbuf[sizeof(txtbuf)-1] = '\0'; #ifdef _WIN32_WCE diff --git a/project/jni/curl/lib/telnet.c b/project/jni/curl/lib/telnet.c index 4ebc49252..6b73bc5bd 100644 --- a/project/jni/curl/lib/telnet.c +++ b/project/jni/curl/lib/telnet.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,7 +51,6 @@ #include "telnet.h" #include "connect.h" #include "progress.h" -#include "curl_printf.h" #define TELOPTS #define TELCMDS @@ -62,7 +61,8 @@ #include "rawstr.h" #include "warnless.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" @@ -91,7 +91,7 @@ #ifdef USE_WINSOCK typedef FARPROC WSOCK2_FUNC; -static CURLcode check_wsock2 ( struct SessionHandle *data ); +static CURLcode check_wsock2 (struct SessionHandle *data); #endif static @@ -198,7 +198,7 @@ const struct Curl_handler Curl_handler_telnet = { #ifdef USE_WINSOCK static CURLcode -check_wsock2 ( struct SessionHandle *data ) +check_wsock2(struct SessionHandle *data) { int err; WORD wVersionRequested; diff --git a/project/jni/curl/lib/tftp.c b/project/jni/curl/lib/tftp.c index f44733944..3c3eb5e11 100644 --- a/project/jni/curl/lib/tftp.c +++ b/project/jni/curl/lib/tftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -57,10 +57,10 @@ #include "url.h" #include "rawstr.h" #include "speedcheck.h" -#include "curl_printf.h" #include "select.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" @@ -312,14 +312,14 @@ static const char *tftp_option_get(const char *buf, size_t len, { size_t loc; - loc = Curl_strnlen( buf, len ); + loc = Curl_strnlen(buf, len); loc++; /* NULL term */ if(loc >= len) return NULL; *option = buf; - loc += Curl_strnlen( buf+loc, len-loc ); + loc += Curl_strnlen(buf+loc, len-loc); loc++; /* NULL term */ if(loc > len) @@ -352,7 +352,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, if(checkprefix(option, TFTP_OPTION_BLKSIZE)) { long blksize; - blksize = strtol( value, NULL, 10 ); + blksize = strtol(value, NULL, 10); if(!blksize) { failf(data, "invalid blocksize value in OACK packet"); @@ -384,7 +384,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, else if(checkprefix(option, TFTP_OPTION_TSIZE)) { long tsize = 0; - tsize = strtol( value, NULL, 10 ); + tsize = strtol(value, NULL, 10); infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize); /* tsize should be ignored on upload: Who cares about the size of the @@ -405,7 +405,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, static size_t tftp_option_add(tftp_state_data_t *state, size_t csize, char *buf, const char *option) { - if(( strlen(option) + csize + 1 ) > (size_t)state->blksize) + if(( strlen(option) + csize + 1) > (size_t)state->blksize) return 0; strcpy(buf, option); return strlen(option) + 1; @@ -514,7 +514,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) (char *)state->spacket.data+sbytes, TFTP_OPTION_BLKSIZE); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf ); + (char *)state->spacket.data+sbytes, buf); /* add timeout option */ snprintf(buf, sizeof(buf), "%d", state->retry_time); @@ -522,7 +522,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) (char *)state->spacket.data+sbytes, TFTP_OPTION_INTERVAL); sbytes += tftp_option_add(state, sbytes, - (char *)state->spacket.data+sbytes, buf ); + (char *)state->spacket.data+sbytes, buf); } /* the typecase for the 3rd argument is mostly for systems that do @@ -960,7 +960,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done) /* alloc pkt buffers based on specified blksize */ if(conn->data->set.tftp_blksize) { blksize = (int)conn->data->set.tftp_blksize; - if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN ) + if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN) return CURLE_TFTP_ILLEGAL; } diff --git a/project/jni/curl/lib/transfer.c b/project/jni/curl/lib/transfer.c index 7481e0c8a..4a12ee9a3 100644 --- a/project/jni/curl/lib/transfer.c +++ b/project/jni/curl/lib/transfer.c @@ -75,9 +75,9 @@ #include "multiif.h" #include "connect.h" #include "non-ascii.h" -#include "curl_printf.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" @@ -694,7 +694,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, } nread = (ssize_t) (k->maxdownload - k->bytecount); - if(nread < 0 ) /* this should be unusual */ + if(nread < 0) /* this should be unusual */ nread = 0; k->keepon &= ~KEEP_RECV; /* we're done reading */ @@ -779,7 +779,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, return result; } - } /* if(! header and data to read ) */ + } /* if(!header and data to read) */ if(conn->handler->readwrite && (excess > 0 && !conn->bits.stream_was_rewound)) { @@ -805,7 +805,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, } while(data_pending(conn) && maxloops--); if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && - conn->bits.close ) { + conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server may now close the connection. If there's now any kind of sending going on from our side, we need to stop that immediately. */ @@ -816,6 +816,20 @@ static CURLcode readwrite_data(struct SessionHandle *data, return CURLE_OK; } +static CURLcode done_sending(struct connectdata *conn, + struct SingleRequest *k) +{ + k->keepon &= ~KEEP_SEND; /* we're done writing */ + + if(conn->bits.rewindaftersend) { + CURLcode result = Curl_readrewind(conn); + if(result) + return result; + } + return CURLE_OK; +} + + /* * Send data to upload to the server, when the socket is writable. */ @@ -887,14 +901,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, break; } else if(nread<=0) { - /* done */ - k->keepon &= ~KEEP_SEND; /* we're done writing */ - - if(conn->bits.rewindaftersend) { - result = Curl_readrewind(conn); - if(result) - return result; - } + result = done_sending(conn, k); + if(result) + return result; break; } @@ -1004,8 +1013,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, data->req.upload_present = 0; /* no more bytes left */ if(k->upload_done) { - /* switch off writing, we're done! */ - k->keepon &= ~KEEP_SEND; /* we're done writing */ + result = done_sending(conn, k); + if(result) + return result; } } @@ -1375,6 +1385,16 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) consider to be fine */ data->state.authhost.picked &= data->state.authhost.want; data->state.authproxy.picked &= data->state.authproxy.want; + + if(data->set.wildcardmatch) { + struct WildcardData *wc = &data->wildcard; + if(!wc->filelist) { + result = Curl_wildcard_init(wc); /* init wildcard structures */ + if(result) + return CURLE_OUT_OF_MEMORY; + } + } + } return result; @@ -1838,63 +1858,6 @@ CURLcode Curl_follow(struct SessionHandle *data, #endif /* CURL_DISABLE_HTTP */ } -CURLcode -Curl_reconnect_request(struct connectdata **connp) -{ - CURLcode result = CURLE_OK; - struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; - - /* This was a re-use of a connection and we got a write error in the - * DO-phase. Then we DISCONNECT this connection and have another attempt to - * CONNECT and then DO again! The retry cannot possibly find another - * connection to re-use, since we only keep one possible connection for - * each. */ - - infof(data, "Re-used connection seems dead, get a new one\n"); - - connclose(conn, "Reconnect dead connection"); /* enforce close */ - result = Curl_done(&conn, result, FALSE); /* we are so done with this */ - - /* conn may no longer be a good pointer, clear it to avoid mistakes by - parent functions */ - *connp = NULL; - - /* - * According to bug report #1330310. We need to check for CURLE_SEND_ERROR - * here as well. I figure this could happen when the request failed on a FTP - * connection and thus Curl_done() itself tried to use the connection - * (again). Slight Lack of feedback in the report, but I don't think this - * extra check can do much harm. - */ - if(!result || (CURLE_SEND_ERROR == result)) { - bool async; - bool protocol_done = TRUE; - - /* Now, redo the connect and get a new connection */ - result = Curl_connect(data, connp, &async, &protocol_done); - if(!result) { - /* We have connected or sent away a name resolve query fine */ - - conn = *connp; /* setup conn to again point to something nice */ - if(async) { - /* Now, if async is TRUE here, we need to wait for the name - to resolve */ - result = Curl_resolver_wait_resolv(conn, NULL); - if(result) - return result; - - /* Resolved, continue with the connection */ - result = Curl_async_resolved(conn, &protocol_done); - if(result) - return result; - } - } - } - - return result; -} - /* Returns CURLE_OK *and* sets '*url' if a request retry is wanted. NOTE: that the *url is malloc()ed. */ diff --git a/project/jni/curl/lib/transfer.h b/project/jni/curl/lib/transfer.h index 52b762abf..802344f23 100644 --- a/project/jni/curl/lib/transfer.h +++ b/project/jni/curl/lib/transfer.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,7 +49,6 @@ int Curl_single_getsock(const struct connectdata *conn, int numsocks); CURLcode Curl_readrewind(struct connectdata *conn); CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); -CURLcode Curl_reconnect_request(struct connectdata **connp); CURLcode Curl_retry_request(struct connectdata *conn, char **url); bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc); diff --git a/project/jni/curl/lib/url.c b/project/jni/curl/lib/url.c index d165d9c0a..2a3026650 100644 --- a/project/jni/curl/lib/url.c +++ b/project/jni/curl/lib/url.c @@ -119,7 +119,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "url.h" #include "connect.h" #include "inet_ntop.h" -#include "curl_ntlm.h" +#include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "socks.h" #include "curl_rtmp.h" @@ -130,15 +130,13 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "pipeline.h" #include "dotdot.h" #include "strdup.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" /* Local static prototypes */ static struct connectdata * -find_oldest_idle_connection(struct SessionHandle *data); -static struct connectdata * find_oldest_idle_connection_in_bundle(struct SessionHandle *data, struct connectbundle *bundle); static void conn_free(struct connectdata *conn); @@ -486,6 +484,12 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } + if(data->set.wildcardmatch) { + /* destruct wildcard structures if it is needed */ + struct WildcardData *wc = &data->wildcard; + Curl_wildcard_dtor(wc); + } + Curl_freeset(data); free(data); return CURLE_OK; @@ -573,23 +577,6 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * seem not to follow rfc1961 section 4.3/4.4 */ set->socks5_gssapi_nec = FALSE; - /* set default GSS-API service name */ - result = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE], - CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE); - if(result) - return result; - - /* set default negotiate proxy service name */ - result = setstropt(&set->str[STRING_PROXY_SERVICE_NAME], - CURL_DEFAULT_PROXY_SERVICE_NAME); - if(result) - return result; - - /* set default negotiate service name */ - result = setstropt(&set->str[STRING_SERVICE_NAME], - CURL_DEFAULT_SERVICE_NAME); - if(result) - return result; #endif /* This is our preferred CA cert bundle/path since install time */ @@ -614,6 +601,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->tcp_keepalive = FALSE; set->tcp_keepintvl = 60; set->tcp_keepidle = 60; + set->tcp_fastopen = FALSE; set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; @@ -713,7 +701,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_DNS_USE_GLOBAL_CACHE: /* remember we want this enabled */ arg = va_arg(param, long); - data->set.global_dns_cache = (0 != arg)?TRUE:FALSE; + data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE; break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ @@ -748,33 +736,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ - data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ - data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ - data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ - data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else @@ -784,14 +772,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FAILONERROR: /* * Don't output the >=400 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -799,7 +787,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.httpreq = HTTPREQ_PUT; @@ -815,7 +803,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ - data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_CREATE_MISSING_DIRS: /* @@ -843,7 +831,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Option that specifies how quickly an server response must be obtained * before it is considered failure. For pingpong protocols. */ - data->set.server_response_timeout = va_arg( param , long ) * 1000; + data->set.server_response_timeout = va_arg(param, long) * 1000; break; case CURLOPT_TFTP_NO_OPTIONS: /* @@ -863,13 +851,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * An option that changes the command to one that asks for a list * only, no file info details. */ - data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_APPEND: /* * We want to upload and append to an existing file. */ - data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_FILEMETHOD: /* @@ -897,7 +885,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * * Transfer using ASCII (instead of BINARY). */ - data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_TIMECONDITION: /* @@ -930,7 +918,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_ACCEPT_ENCODING: @@ -950,14 +938,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_transfer_encoding = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on a HTTP-server. */ - data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_UNRESTRICTED_AUTH: @@ -966,7 +955,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * hostname changed. */ data->set.http_disable_hostname_check_before_authentication = - (0 != va_arg(param, long))?TRUE:FALSE; + (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_MAXREDIRS: @@ -1227,7 +1216,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We run mostly with the original cookie spec, as hardly anyone implements * anything else. */ - data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_COOKIELIST: @@ -1326,7 +1315,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; + data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1389,7 +1378,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Tunnel operations through the proxy instead of normal proxy use */ - data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; case CURLOPT_PROXYPORT: @@ -1415,7 +1405,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; + data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1490,32 +1480,28 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #endif /* CURL_DISABLE_PROXY */ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case CURLOPT_SOCKS5_GSSAPI_SERVICE: + case CURLOPT_SOCKS5_GSSAPI_NEC: /* - * Set GSS-API service name + * Set flag for NEC SOCK5 support */ - result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE], - va_arg(param, char *)); + data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_SOCKS5_GSSAPI_SERVICE: case CURLOPT_PROXY_SERVICE_NAME: /* - * Set negotiate proxy service name + * Set proxy authentication service name for Kerberos 5 and SPNEGO */ result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], va_arg(param, char *)); break; +#endif - case CURLOPT_SOCKS5_GSSAPI_NEC: - /* - * set flag for nec socks5 support - */ - data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE; - break; - +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ + defined(USE_SPNEGO) case CURLOPT_SERVICE_NAME: /* - * Set negotiate service identity + * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO */ result = setstropt(&data->set.str[STRING_SERVICE_NAME], va_arg(param, char *)); @@ -1549,20 +1535,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_FTPPORT], va_arg(param, char *)); - data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ? - TRUE:FALSE; + data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_SSL_CCC: @@ -1574,7 +1559,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the * bypass of the IP address in PASV responses. */ - data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_READDATA: @@ -1982,7 +1967,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Kludgy option to enable CRLF conversions. Subject for removal. */ - data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_INTERFACE: @@ -2011,7 +1996,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_KRB_LEVEL], va_arg(param, char *)); - data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE; + data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE; break; case CURLOPT_GSSAPI_DELEGATION: /* @@ -2023,7 +2008,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Enable peer SSL verifying. */ - data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_VERIFYHOST: /* @@ -2041,7 +2026,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; } - data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE; + data->set.ssl.verifyhost = (0 != arg) ? TRUE : FALSE; break; case CURLOPT_SSL_VERIFYSTATUS: /* @@ -2052,7 +2037,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; } - data->set.ssl.verifystatus = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SSL_CTX_FUNCTION: #ifdef have_curlssl_ssl_ctx @@ -2083,22 +2068,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; } - data->set.ssl.falsestart = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CERTINFO: #ifdef have_curlssl_certinfo - data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE; #else result = CURLE_NOT_BUILT_IN; #endif break; case CURLOPT_PINNEDPUBLICKEY: +#ifdef have_curlssl_pinnedpubkey /* only by supported backends */ /* * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif break; case CURLOPT_CAINFO: /* @@ -2150,7 +2139,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ data->set.buffer_size = va_arg(param, long); - if((data->set.buffer_size> (BUFSIZE -1 )) || + if((data->set.buffer_size> (BUFSIZE -1)) || (data->set.buffer_size < 1)) data->set.buffer_size = 0; /* huge internal default */ @@ -2161,7 +2150,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ - data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_SHARE: @@ -2277,7 +2266,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable TCP_NODELAY, which will disable/enable the Nagle * algorithm */ - data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_ACCOUNT: @@ -2286,14 +2275,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CONNECT_ONLY: /* * No data transfer, set up connection and let application use the socket */ - data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: @@ -2346,7 +2335,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.ssl.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifdef USE_LIBSSH2 @@ -2407,14 +2396,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * disable libcurl transfer encoding is used */ - data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE; + data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_HTTP_CONTENT_DECODING: /* * raw data passed to the application when content encoding is used */ - data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE; + data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_NEW_FILE_PERMS: @@ -2594,7 +2583,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_WILDCARDMATCH: - data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_CHUNK_BGN_FUNCTION: data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); @@ -2645,7 +2634,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_TCP_KEEPALIVE: - data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_TCP_KEEPIDLE: data->set.tcp_keepidle = va_arg(param, long); @@ -2653,11 +2642,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_TCP_KEEPINTVL: data->set.tcp_keepintvl = va_arg(param, long); break; + case CURLOPT_TCP_FASTOPEN: +#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) + data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE; +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; case CURLOPT_SSL_ENABLE_NPN: - data->set.ssl_enable_npn = (0 != va_arg(param, long))?TRUE:FALSE; + 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; + data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE; break; #ifdef USE_UNIX_SOCKETS @@ -2668,10 +2664,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #endif case CURLOPT_PATH_AS_IS: - data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_PIPEWAIT: - data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE; + data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLOPT_STREAM_WEIGHT: #ifndef USE_NGHTTP2 @@ -2696,6 +2692,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; #endif } + case CURLOPT_CONNECT_TO: + data->set.connect_to = va_arg(param, struct curl_slist *); + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; @@ -2705,6 +2704,45 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, return result; } +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND +static void conn_reset_postponed_data(struct connectdata *conn, int num) +{ + struct postponed_data * const psnd = &(conn->postponed[num]); + if(psnd->buffer) { + DEBUGASSERT(psnd->allocated_size > 0); + DEBUGASSERT(psnd->recv_size <= psnd->allocated_size); + DEBUGASSERT(psnd->recv_size ? + (psnd->recv_processed < psnd->recv_size) : + (psnd->recv_processed == 0)); + DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD); + free(psnd->buffer); + psnd->buffer = NULL; + psnd->allocated_size = 0; + psnd->recv_size = 0; + psnd->recv_processed = 0; +#ifdef DEBUGBUILD + psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */ +#endif /* DEBUGBUILD */ + } + else { + DEBUGASSERT (psnd->allocated_size == 0); + DEBUGASSERT (psnd->recv_size == 0); + DEBUGASSERT (psnd->recv_processed == 0); + DEBUGASSERT (psnd->bindsock == CURL_SOCKET_BAD); + } +} + +static void conn_reset_all_postponed_data(struct connectdata *conn) +{ + conn_reset_postponed_data(conn, 0); + conn_reset_postponed_data(conn, 1); +} +#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ +/* Use "do-nothing" macros instead of functions when workaround not used */ +#define conn_reset_postponed_data(c,n) do {} WHILE_FALSE +#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE +#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ + static void conn_free(struct connectdata *conn) { if(!conn) @@ -2751,9 +2789,12 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->allocptr.rtsp_transport); Curl_safefree(conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ Curl_safefree(conn->master_buffer); + conn_reset_all_postponed_data(conn); + Curl_llist_destroy(conn->send_pipe, NULL); Curl_llist_destroy(conn->recv_pipe, NULL); @@ -2809,6 +2850,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) Curl_conncache_remove_conn(data->state.conn_cache, conn); free_fixed_hostname(&conn->host); + free_fixed_hostname(&conn->conn_to_host); free_fixed_hostname(&conn->proxy); Curl_ssl_close(conn, FIRSTSOCKET); @@ -2960,8 +3002,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) * Returns the pointer to the oldest idle connection, or NULL if none was * found. */ -static struct connectdata * -find_oldest_idle_connection(struct SessionHandle *data) +struct connectdata * +Curl_oldest_idle_connection(struct SessionHandle *data) { struct conncache *bc = data->state.conn_cache; struct curl_hash_iterator iter; @@ -3168,9 +3210,15 @@ ConnectionExists(struct SessionHandle *data, max_pipeline_length(data->multi):0; size_t best_pipe_len = max_pipe_len; struct curl_llist_element *curr; + const char *hostname; + + if(needle->bits.conn_to_host) + hostname = needle->conn_to_host.name; + else + hostname = needle->host.name; infof(data, "Found bundle for host %s: %p [%s]\n", - needle->host.name, (void *)bundle, + hostname, (void *)bundle, (bundle->multiuse== BUNDLE_PIPELINING? "can pipeline": (bundle->multiuse== BUNDLE_MULTIPLEX? @@ -3207,8 +3255,8 @@ ConnectionExists(struct SessionHandle *data, size_t pipeLen; /* - * Note that if we use a HTTP proxy, we check connections to that - * proxy and not to the actual remote server. + * Note that if we use a HTTP proxy in normal mode (no tunneling), we + * check connections to that proxy and not to the actual remote server. */ check = curr->ptr; curr = curr->next; @@ -3289,6 +3337,25 @@ ConnectionExists(struct SessionHandle *data, /* don't do mixed proxy and non-proxy connections */ continue; + if(needle->bits.proxy && + (needle->proxytype != check->proxytype || + needle->bits.httpproxy != check->bits.httpproxy || + needle->bits.tunnel_proxy != check->bits.tunnel_proxy || + !Curl_raw_equal(needle->proxy.name, check->proxy.name) || + needle->port != check->port)) + /* don't mix connections that use different proxies */ + continue; + + if(needle->bits.conn_to_host != check->bits.conn_to_host) + /* don't mix connections that use the "connect to host" feature and + * connections that don't use this feature */ + continue; + + if(needle->bits.conn_to_port != check->bits.conn_to_port) + /* don't mix connections that use the "connect to port" feature and + * connections that don't use this feature */ + continue; + if(!canPipeline && check->inuse) /* this request can't be pipelined but the checked connection is already in use so we skip it */ @@ -3324,17 +3391,18 @@ ConnectionExists(struct SessionHandle *data, } } - if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL || - (needle->bits.httpproxy && check->bits.httpproxy && - needle->bits.tunnel_proxy && check->bits.tunnel_proxy && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - (needle->port == check->port))) { + if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || + (needle->bits.httpproxy && needle->bits.tunnel_proxy)) { /* The requested connection does not use a HTTP proxy or it uses SSL or it is a non-SSL protocol tunneled over the same HTTP proxy name and port number */ if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == needle->handler->protocol && check->tls_upgraded)) && + (!needle->bits.conn_to_host || Curl_raw_equal( + needle->conn_to_host.name, check->conn_to_host.name)) && + (!needle->bits.conn_to_port || + needle->conn_to_port == check->conn_to_port) && Curl_raw_equal(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { /* The schemes match or the the protocol family is the same and the @@ -3363,16 +3431,10 @@ ConnectionExists(struct SessionHandle *data, match = TRUE; } } - else { /* The requested needle connection is using a proxy, - is the checked one using the same host, port and type? */ - if(check->bits.proxy && - (needle->proxytype == check->proxytype) && - (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) && - Curl_raw_equal(needle->proxy.name, check->proxy.name) && - needle->port == check->port) { - /* This is the same proxy connection, use it! */ - match = TRUE; - } + else { + /* The requested connection is using the same HTTP proxy in normal + mode (no tunneling) */ + match = TRUE; } if(match) { @@ -3394,6 +3456,10 @@ ConnectionExists(struct SessionHandle *data, /* Same for Proxy NTLM authentication */ if(wantProxyNTLMhttp) { + /* Both check->proxyuser and check->proxypasswd can be NULL */ + if(!check->proxyuser || !check->proxypasswd) + continue; + if(!strequal(needle->proxyuser, check->proxyuser) || !strequal(needle->proxypasswd, check->proxypasswd)) continue; @@ -3493,38 +3559,6 @@ ConnectionExists(struct SessionHandle *data, return FALSE; /* no matching connecting exists */ } -/* Mark the connection as 'idle', or close it if the cache is full. - Returns TRUE if the connection is kept, or FALSE if it was closed. */ -static bool -ConnectionDone(struct SessionHandle *data, struct connectdata *conn) -{ - /* data->multi->maxconnects can be negative, deal with it. */ - size_t maxconnects = - (data->multi->maxconnects < 0) ? data->multi->num_easy * 4: - data->multi->maxconnects; - struct connectdata *conn_candidate = NULL; - - /* Mark the current connection as 'unused' */ - conn->inuse = FALSE; - - if(maxconnects > 0 && - data->state.conn_cache->num_connections > maxconnects) { - infof(data, "Connection cache is full, closing the oldest one.\n"); - - conn_candidate = find_oldest_idle_connection(data); - - if(conn_candidate) { - /* Set the connection's owner correctly */ - conn_candidate->data = data; - - /* the winner gets the honour of being disconnected */ - (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE); - } - } - - return (conn_candidate == conn) ? FALSE : TRUE; -} - /* after a TCP connection to the proxy has been verified, this function does the next magic step. @@ -3544,16 +3578,27 @@ CURLcode Curl_connected_proxy(struct connectdata *conn, case CURLPROXY_SOCKS5: case CURLPROXY_SOCKS5_HOSTNAME: return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, - conn->host.name, conn->remote_port, + conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name, + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port, FIRSTSOCKET, conn); case CURLPROXY_SOCKS4: - return Curl_SOCKS4(conn->proxyuser, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn, FALSE); + return Curl_SOCKS4(conn->proxyuser, + conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name, + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port, + FIRSTSOCKET, conn, FALSE); case CURLPROXY_SOCKS4A: - return Curl_SOCKS4(conn->proxyuser, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn, TRUE); + return Curl_SOCKS4(conn->proxyuser, + conn->bits.conn_to_host ? conn->conn_to_host.name : + conn->host.name, + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port, + FIRSTSOCKET, conn, TRUE); #endif /* CURL_DISABLE_PROXY */ case CURLPROXY_HTTP: @@ -3728,17 +3773,16 @@ static bool tld_check_name(struct SessionHandle *data, if(rc != IDNA_SUCCESS) return FALSE; + /* Warning: err_pos receives "the decoded character offset rather than the + byte position in the string." And as of libidn 1.32 that character offset + is for UTF-8, even if the passed in string is another locale. */ rc = tld_check_lz(uc_name, &err_pos, NULL); #ifndef CURL_DISABLE_VERBOSE_STRINGS #ifdef HAVE_TLD_STRERROR if(rc != TLD_SUCCESS) tld_errmsg = tld_strerror((Tld_rc)rc); #endif - if(rc == TLD_INVALID) - infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n", - tld_errmsg, err_pos, uc_name[err_pos], - uc_name[err_pos] & 255); - else if(rc != TLD_SUCCESS) + if(rc != TLD_SUCCESS) infof(data, "WARNING: TLD check for %s failed; %s\n", uc_name, tld_errmsg); #endif /* CURL_DISABLE_VERBOSE_STRINGS */ @@ -3862,6 +3906,10 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ conn->remote_port = -1; /* unknown */ +#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) + conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ + conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ +#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */ /* Default protocol-independent behavior doesn't support persistent connections, so we set this to force-close. Protocols that support @@ -3888,17 +3936,18 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) /* note that these two proxy bits are now just on what looks to be requested, they may be altered down the road */ conn->bits.proxy = (data->set.str[STRING_PROXY] && - *data->set.str[STRING_PROXY])?TRUE:FALSE; + *data->set.str[STRING_PROXY]) ? TRUE : FALSE; conn->bits.httpproxy = (conn->bits.proxy && (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE; - conn->bits.proxy_user_passwd = - (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE; + conn->proxytype == CURLPROXY_HTTP_1_0)) ? + TRUE : FALSE; + conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ? + TRUE : FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ - conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE; + conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; @@ -4368,7 +4417,7 @@ static CURLcode setup_range(struct SessionHandle *data) else s->range = strdup(data->set.str[STRING_SET_RANGE]); - s->rangestringalloc = (s->range)?TRUE:FALSE; + s->rangestringalloc = (s->range) ? TRUE : FALSE; if(!s->range) return CURLE_OUT_OF_MEMORY; @@ -4427,11 +4476,6 @@ static CURLcode setup_connection_internals(struct connectdata *conn) was very likely already set to the proxy port */ conn->port = p->defport; - /* only if remote_port was not already parsed off the URL we use the - default port number */ - if(conn->remote_port < 0) - conn->remote_port = (unsigned short)conn->given->defport; - return CURLE_OK; } @@ -4706,7 +4750,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, if(strncmp("%25", ptr, 3)) infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); ptr++; - /* Allow unresered characters as defined in RFC 3986 */ + /* Allow unreserved characters as defined in RFC 3986 */ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) ptr++; @@ -4733,7 +4777,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, /* now set the local port number */ port = strtol(prox_portno, &endp, 10); if((endp && *endp && (*endp != '/') && (*endp != ' ')) || - (port >= 65536) ) { + (port < 0) || (port > 65535)) { /* meant to detect for example invalid IPv6 numerical addresses without brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only because we then allow "URL style" with the number followed by a @@ -4756,7 +4800,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, a slash so we strip everything from the first slash */ atsign = strchr(proxyptr, '/'); if(atsign) - *atsign = 0x0; /* cut off path part from host name */ + *atsign = '\0'; /* cut off path part from host name */ if(data->set.proxyport) /* None given in the proxy string, then get the default one if it is @@ -5160,6 +5204,12 @@ static CURLcode parse_remote_port(struct SessionHandle *data, use the default port. Firefox and Chrome both do that. */ *portptr = '\0'; } + + /* only if remote_port was not already parsed off the URL we use the + default port number */ + if(conn->remote_port < 0) + conn->remote_port = (unsigned short)conn->given->defport; + return CURLE_OK; } @@ -5202,7 +5252,7 @@ static CURLcode override_login(struct SessionHandle *data, DOT_CHAR "netrc file; using defaults\n", conn->host.name); } - else if(ret < 0 ) { + else if(ret < 0) { return CURLE_OUT_OF_MEMORY; } else { @@ -5265,6 +5315,214 @@ static CURLcode set_login(struct connectdata *conn, return result; } +/* + * Parses a "host:port" string to connect to. + * The hostname and the port may be empty; in this case, NULL is returned for + * the hostname and -1 for the port. + */ +static CURLcode parse_connect_to_host_port(struct SessionHandle *data, + const char *host, + char **hostname_result, + int *port_result) +{ + char *host_dup; + char *hostptr; + char *host_portno; + char *portptr; + int port = -1; + + *hostname_result = NULL; + *port_result = -1; + + if(!host || !*host) + return CURLE_OK; + + host_dup = strdup(host); + if(!host_dup) + return CURLE_OUT_OF_MEMORY; + + hostptr = host_dup; + + /* start scanning for port number at this point */ + portptr = hostptr; + + /* detect and extract RFC6874-style IPv6-addresses */ + if(*hostptr == '[') { + char *ptr = ++hostptr; /* advance beyond the initial bracket */ + while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.'))) + ptr++; + if(*ptr == '%') { + /* There might be a zone identifier */ + if(strncmp("%25", ptr, 3)) + infof(data, "Please URL encode %% as %%25, see RFC 6874.\n"); + ptr++; + /* Allow unreserved characters as defined in RFC 3986 */ + while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') || + (*ptr == '.') || (*ptr == '_') || (*ptr == '~'))) + ptr++; + } + if(*ptr == ']') + /* yeps, it ended nicely with a bracket as well */ + *ptr++ = '\0'; + else + infof(data, "Invalid IPv6 address format\n"); + portptr = ptr; + /* Note that if this didn't end with a bracket, we still advanced the + * hostptr first, but I can't see anything wrong with that as no host + * name nor a numeric can legally start with a bracket. + */ + } + + /* Get port number off server.com:1080 */ + host_portno = strchr(portptr, ':'); + if(host_portno) { + char *endp = NULL; + *host_portno = '\0'; /* cut off number from host name */ + host_portno++; + if(*host_portno) { + long portparse = strtol(host_portno, &endp, 10); + if((endp && *endp) || (portparse < 0) || (portparse > 65535)) { + infof(data, "No valid port number in connect to host string (%s)\n", + host_portno); + hostptr = NULL; + port = -1; + } + else + port = (int)portparse; /* we know it will fit */ + } + } + + /* now, clone the cleaned host name */ + if(hostptr) { + *hostname_result = strdup(hostptr); + if(!*hostname_result) { + free(host_dup); + return CURLE_OUT_OF_MEMORY; + } + } + + *port_result = port; + + free(host_dup); + return CURLE_OK; +} + +/* + * Parses one "connect to" string in the form: + * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". + */ +static CURLcode parse_connect_to_string(struct SessionHandle *data, + struct connectdata *conn, + const char *conn_to_host, + char **host_result, + int *port_result) +{ + CURLcode result = CURLE_OK; + const char *ptr = conn_to_host; + int host_match = FALSE; + int port_match = FALSE; + + if(*ptr == ':') { + /* an empty hostname always matches */ + host_match = TRUE; + ptr++; + } + else { + /* check whether the URL's hostname matches */ + size_t hostname_to_match_len; + char *hostname_to_match = aprintf("%s%s%s", + conn->bits.ipv6_ip ? "[" : "", + conn->host.name, + conn->bits.ipv6_ip ? "]" : ""); + if(!hostname_to_match) + return CURLE_OUT_OF_MEMORY; + hostname_to_match_len = strlen(hostname_to_match); + host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len); + free(hostname_to_match); + ptr += hostname_to_match_len; + + host_match = host_match && *ptr == ':'; + ptr++; + } + + if(host_match) { + if(*ptr == ':') { + /* an empty port always matches */ + port_match = TRUE; + ptr++; + } + else { + /* check whether the URL's port matches */ + char *ptr_next = strchr(ptr, ':'); + if(ptr_next) { + char *endp = NULL; + long port_to_match = strtol(ptr, &endp, 10); + if((endp == ptr_next) && (port_to_match == conn->remote_port)) { + port_match = TRUE; + ptr = ptr_next + 1; + } + } + } + } + + if(host_match && port_match) { + /* parse the hostname and port to connect to */ + result = parse_connect_to_host_port(data, ptr, host_result, port_result); + } + + return result; +} + +/* + * Processes all strings in the "connect to" slist, and uses the "connect + * to host" and "connect to port" of the first string that matches. + */ +static CURLcode parse_connect_to_slist(struct SessionHandle *data, + struct connectdata *conn, + struct curl_slist *conn_to_host) +{ + CURLcode result = CURLE_OK; + char *host = NULL; + int port = 0; + + while(conn_to_host && !host) { + result = parse_connect_to_string(data, conn, conn_to_host->data, + &host, &port); + if(result) + return result; + + if(host && *host) { + bool ipv6host; + conn->conn_to_host.rawalloc = host; + conn->conn_to_host.name = host; + conn->bits.conn_to_host = TRUE; + + ipv6host = strchr(host, ':') != NULL; + infof(data, "Connecting to hostname: %s%s%s\n", + ipv6host ? "[" : "", host, ipv6host ? "]" : ""); + } + else { + /* no "connect to host" */ + conn->bits.conn_to_host = FALSE; + free(host); + } + + if(port >= 0) { + conn->conn_to_port = port; + conn->bits.conn_to_port = TRUE; + infof(data, "Connecting to port: %d\n", port); + } + else { + /* no "connect to port" */ + conn->bits.conn_to_port = FALSE; + } + + conn_to_host = conn_to_host->next; + } + + return result; +} + /************************************************************* * Resolve the address of the server or proxy *************************************************************/ @@ -5316,12 +5574,21 @@ static CURLcode resolve_server(struct SessionHandle *data, else #endif if(!conn->proxy.name || !*conn->proxy.name) { + struct hostname *connhost; + if(conn->bits.conn_to_host) + connhost = &conn->conn_to_host; + else + connhost = &conn->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->remote_port; /* it is the same port */ + if(conn->bits.conn_to_port) + conn->port = conn->conn_to_port; + else + conn->port = conn->remote_port; /* it is the same port */ /* Resolve target host right on */ - rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port, + rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) *async = TRUE; @@ -5330,7 +5597,7 @@ static CURLcode resolve_server(struct SessionHandle *data, result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { - failf(data, "Couldn't resolve host '%s'", conn->host.dispname); + failf(data, "Couldn't resolve host '%s'", connhost->dispname); result = CURLE_COULDNT_RESOLVE_HOST; /* don't return yet, we need to clean up the timeout first */ } @@ -5405,12 +5672,21 @@ static void reuse_conn(struct connectdata *old_conn, /* host can change, when doing keepalive with a proxy or if the case is different this time etc */ free_fixed_hostname(&conn->host); + free_fixed_hostname(&conn->conn_to_host); Curl_safefree(conn->host.rawalloc); + Curl_safefree(conn->conn_to_host.rawalloc); conn->host=old_conn->host; + conn->bits.conn_to_host = old_conn->bits.conn_to_host; + conn->conn_to_host = old_conn->conn_to_host; + conn->bits.conn_to_port = old_conn->bits.conn_to_port; + conn->conn_to_port = old_conn->conn_to_port; /* persist connection info in session handle */ Curl_persistconninfo(conn); + conn_reset_all_postponed_data(old_conn); /* free buffers */ + conn_reset_all_postponed_data(conn); /* reset unprocessed data */ + /* re-use init */ conn->bits.reuse = TRUE; /* yes, we're re-using here */ @@ -5714,13 +5990,48 @@ static CURLcode create_conn(struct SessionHandle *data, if(result) goto out; + /************************************************************* + * Process the "connect to" linked list of hostname/port mappings. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + result = parse_connect_to_slist(data, conn, data->set.connect_to); + if(result) + goto out; + /************************************************************* * IDN-fix the hostnames *************************************************************/ fix_hostname(data, conn, &conn->host); + if(conn->bits.conn_to_host) + fix_hostname(data, conn, &conn->conn_to_host); if(conn->proxy.name && *conn->proxy.name) fix_hostname(data, conn, &conn->proxy); + /************************************************************* + * Check whether the host and the "connect to host" are equal. + * Do this after the hostnames have been IDN-fixed . + *************************************************************/ + if(conn->bits.conn_to_host && + Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) { + conn->bits.conn_to_host = FALSE; + } + + /************************************************************* + * Check whether the port and the "connect to port" are equal. + * Do this after the remote port number has been fixed in the URL. + *************************************************************/ + if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) { + conn->bits.conn_to_port = FALSE; + } + + /************************************************************* + * If the "connect to" feature is used with an HTTP proxy, + * we set the tunnel_proxy bit. + *************************************************************/ + if((conn->bits.conn_to_host || conn->bits.conn_to_port) && + conn->bits.httpproxy) + conn->bits.tunnel_proxy = TRUE; + /************************************************************* * Setup internals depending on protocol. Needs to be done after * we figured out what/if proxy to use. @@ -5734,6 +6045,8 @@ static CURLcode create_conn(struct SessionHandle *data, conn->recv[SECONDARYSOCKET] = Curl_recv_plain; conn->send[SECONDARYSOCKET] = Curl_send_plain; + conn->bits.tcp_fastopen = data->set.tcp_fastopen; + /*********************************************************************** * file: is a special case in that it doesn't need a network connection ***********************************************************************/ @@ -5860,6 +6173,15 @@ static CURLcode create_conn(struct SessionHandle *data, connections we are allowed to open. */ struct connectbundle *bundle = NULL; + if(conn->handler->flags & PROTOPT_ALPN_NPN) { + /* 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) /* There is a connection that *might* become usable for pipelining "soon", and we wait for that */ @@ -5892,7 +6214,7 @@ static CURLcode create_conn(struct SessionHandle *data, struct connectdata *conn_candidate; /* The cache is full. Let's see if we can kill a connection. */ - conn_candidate = find_oldest_idle_connection(data); + conn_candidate = Curl_oldest_idle_connection(data); if(conn_candidate) { /* Set the connection's owner correctly, then kill it */ @@ -6104,135 +6426,6 @@ CURLcode Curl_connect(struct SessionHandle *data, return result; } -CURLcode Curl_done(struct connectdata **connp, - CURLcode status, /* an error if this is called after an - error was detected */ - bool premature) -{ - CURLcode result; - struct connectdata *conn; - struct SessionHandle *data; - - DEBUGASSERT(*connp); - - conn = *connp; - data = conn->data; - - DEBUGF(infof(data, "Curl_done\n")); - - if(data->state.done) - /* Stop if Curl_done() has already been called */ - return CURLE_OK; - - Curl_getoff_all_pipelines(data, conn); - - /* Cleanup possible redirect junk */ - free(data->req.newurl); - data->req.newurl = NULL; - free(data->req.location); - data->req.location = NULL; - - switch(status) { - case CURLE_ABORTED_BY_CALLBACK: - case CURLE_READ_ERROR: - case CURLE_WRITE_ERROR: - /* When we're aborted due to a callback return code it basically have to - be counted as premature as there is trouble ahead if we don't. We have - many callbacks and protocols work differently, we could potentially do - this more fine-grained in the future. */ - premature = TRUE; - default: - break; - } - - /* this calls the protocol-specific function pointer previously set */ - if(conn->handler->done) - result = conn->handler->done(conn, status, premature); - else - result = status; - - if(CURLE_ABORTED_BY_CALLBACK != result) { - /* avoid this if we already aborted by callback to avoid this calling - another callback */ - CURLcode rc = Curl_pgrsDone(conn); - if(!result && rc) - result = CURLE_ABORTED_BY_CALLBACK; - } - - if((!premature && - conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) { - /* Stop if pipeline is not empty and we do not have to close - connection. */ - DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n")); - return CURLE_OK; - } - - data->state.done = TRUE; /* called just now! */ - Curl_resolver_cancel(conn); - - if(conn->dns_entry) { - Curl_resolv_unlock(data, conn->dns_entry); /* done with this */ - conn->dns_entry = NULL; - } - - /* if the transfer was completed in a paused state there can be buffered - data left to write and then kill */ - free(data->state.tempwrite); - data->state.tempwrite = NULL; - - /* if data->set.reuse_forbid is TRUE, it means the libcurl client has - forced us to close this connection. This is ignored for requests taking - place in a NTLM authentication handshake - - if conn->bits.close is TRUE, it means that the connection should be - closed in spite of all our efforts to be nice, due to protocol - restrictions in our or the server's end - - if premature is TRUE, it means this connection was said to be DONE before - the entire request operation is complete and thus we can't know in what - state it is for re-using, so we're forced to close it. In a perfect world - we can add code that keep track of if we really must close it here or not, - but currently we have no such detail knowledge. - */ - - if((data->set.reuse_forbid -#if defined(USE_NTLM) - && !(conn->ntlm.state == NTLMSTATE_TYPE2 || - conn->proxyntlm.state == NTLMSTATE_TYPE2) -#endif - ) || conn->bits.close || premature) { - CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */ - - /* If we had an error already, make sure we return that one. But - if we got a new error, return that. */ - if(!result && res2) - result = res2; - } - else { - /* the connection is no longer in use */ - if(ConnectionDone(data, conn)) { - /* remember the most recently used connection */ - data->state.lastconnect = conn; - - infof(data, "Connection #%ld to host %s left intact\n", - conn->connection_id, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); - } - else - data->state.lastconnect = NULL; - } - - *connp = NULL; /* to make the caller of this function better detect that - this was either closed or handed over to the connection - cache here, and therefore cannot be used from this point on - */ - Curl_free_request_state(data); - - return result; -} - /* * Curl_init_do() inits the readwrite session. This is inited each time (in * the DO function before the protocol-specific DO functions are invoked) for @@ -6251,7 +6444,7 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to * use */ - data->state.done = FALSE; /* Curl_done() is not called yet */ + data->state.done = FALSE; /* *_done() is not called yet */ data->state.expect100header = FALSE; if(data->set.opt_no_body) @@ -6284,85 +6477,6 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) return CURLE_OK; } -/* - * do_complete is called when the DO actions are complete. - * - * We init chunking and trailer bits to their default values here immediately - * before receiving any header data for the current request in the pipeline. - */ -static void do_complete(struct connectdata *conn) -{ - conn->data->req.chunk=FALSE; - conn->data->req.maxfd = (conn->sockfd>conn->writesockfd? - conn->sockfd:conn->writesockfd)+1; - Curl_pgrsTime(conn->data, TIMER_PRETRANSFER); -} - -CURLcode Curl_do(struct connectdata **connp, bool *done) -{ - CURLcode result=CURLE_OK; - struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; - - if(conn->handler->do_it) { - /* generic protocol-specific function pointer set in curl_connect() */ - result = conn->handler->do_it(conn, done); - - /* This was formerly done in transfer.c, but we better do it here */ - if((CURLE_SEND_ERROR == result) && conn->bits.reuse) { - /* - * If the connection is using an easy handle, call reconnect - * to re-establish the connection. Otherwise, let the multi logic - * figure out how to re-establish the connection. - */ - if(!data->multi) { - result = Curl_reconnect_request(connp); - - if(!result) { - /* ... finally back to actually retry the DO phase */ - conn = *connp; /* re-assign conn since Curl_reconnect_request - creates a new connection */ - result = conn->handler->do_it(conn, done); - } - } - else - return result; - } - - if(!result && *done) - /* do_complete must be called after the protocol-specific DO function */ - do_complete(conn); - } - return result; -} - -/* - * Curl_do_more() is called during the DO_MORE multi state. It is basically a - * second stage DO state which (wrongly) was introduced to support FTP's - * second connection. - * - * TODO: A future libcurl should be able to work away this state. - * - * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to - * DOING state there's more work to do! - */ - -CURLcode Curl_do_more(struct connectdata *conn, int *complete) -{ - CURLcode result=CURLE_OK; - - *complete = 0; - - if(conn->handler->do_more) - result = conn->handler->do_more(conn, complete); - - if(!result && (*complete == 1)) - /* do_complete must be called after the protocol-specific DO function */ - do_complete(conn); - - return result; -} - /* * get_protocol_family() * @@ -6387,7 +6501,7 @@ unsigned int get_protocol_family(unsigned int protocol) case CURLPROTO_FTP: case CURLPROTO_FTPS: - family = CURLPROTO_IMAP; + family = CURLPROTO_FTP; break; case CURLPROTO_SCP: @@ -6404,7 +6518,7 @@ unsigned int get_protocol_family(unsigned int protocol) case CURLPROTO_LDAP: case CURLPROTO_LDAPS: - family = CURLPROTO_IMAP; + family = CURLPROTO_LDAP; break; case CURLPROTO_DICT: diff --git a/project/jni/curl/lib/url.h b/project/jni/curl/lib/url.h index bb85e9bb3..2b25731ea 100644 --- a/project/jni/curl/lib/url.h +++ b/project/jni/curl/lib/url.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,9 +37,6 @@ void Curl_freeset(struct SessionHandle * data); CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, bool *async, bool *protocol_connect); -CURLcode Curl_do(struct connectdata **, bool *done); -CURLcode Curl_do_more(struct connectdata *, int *completed); -CURLcode Curl_done(struct connectdata **, CURLcode, bool premature); CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); @@ -60,6 +57,8 @@ CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle, struct curl_llist *pipeline); int Curl_removeHandleFromPipeline(struct SessionHandle *handle, struct curl_llist *pipeline); +struct connectdata * +Curl_oldest_idle_connection(struct SessionHandle *data); /* remove the specified connection from all (possible) pipelines and related queues */ void Curl_getoff_all_pipelines(struct SessionHandle *data, @@ -68,11 +67,6 @@ void Curl_getoff_all_pipelines(struct SessionHandle *data, void Curl_close_connections(struct SessionHandle *data); #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ -#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi - service */ -#define CURL_DEFAULT_PROXY_SERVICE_NAME "HTTP" /* default negotiate proxy - service */ -#define CURL_DEFAULT_SERVICE_NAME "HTTP" /* default negotiate service */ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); diff --git a/project/jni/curl/lib/urldata.h b/project/jni/curl/lib/urldata.h index f832ea886..25594d3b5 100644 --- a/project/jni/curl/lib/urldata.h +++ b/project/jni/curl/lib/urldata.h @@ -290,7 +290,6 @@ struct ssl_connect_data { mbedtls_ctr_drbg_context ctr_drbg; mbedtls_entropy_context entropy; mbedtls_ssl_context ssl; - mbedtls_ssl_session ssn; int server_fd; mbedtls_x509_crt cacert; mbedtls_x509_crt clicert; @@ -302,7 +301,6 @@ struct ssl_connect_data { ctr_drbg_context ctr_drbg; entropy_context entropy; ssl_context ssl; - ssl_session ssn; int server_fd; x509_crt cacert; x509_crt clicert; @@ -375,10 +373,12 @@ struct ssl_config_data { /* information stored about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ + char *conn_to_host; /* host name for the connection (may be NULL) */ void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ - int remote_port; /* remote port to connect to */ + int remote_port; /* remote port */ + int conn_to_port; /* remote port for the connection (may be -1) */ struct ssl_config_data ssl_config; /* setup for this session */ }; @@ -464,7 +464,7 @@ struct negotiatedata { #ifdef HAVE_GSSAPI OM_uint32 status; gss_ctx_id_t context; - gss_name_t server_name; + gss_name_t spn; gss_buffer_desc output_token; #else #ifdef USE_WINDOWS_SSPI @@ -473,7 +473,7 @@ struct negotiatedata { CtxtHandle *context; SEC_WINNT_AUTH_IDENTITY identity; SEC_WINNT_AUTH_IDENTITY *p_identity; - TCHAR *server_name; + TCHAR *spn; size_t token_max; BYTE *output_token; size_t output_token_length; @@ -490,6 +490,10 @@ struct ConnectBits { /* always modify bits.close with the connclose() and connkeep() macros! */ bool close; /* if set, we close the connection after this request */ bool reuse; /* if set, this is a re-used connection */ + bool conn_to_host; /* if set, this connection has a "connect to host" + that overrides the host in the URL */ + bool conn_to_port; /* if set, this connection has a "connect to port" + that overrides the port in the URL (remote port) */ bool proxy; /* if set, this transfer is done through a proxy - any type */ bool httpproxy; /* if set, this transfer is done through a http proxy */ bool user_passwd; /* do we use user+password for this connection? */ @@ -538,6 +542,10 @@ struct ConnectBits { connection */ bool type_set; /* type= was used in the URL */ bool multiplex; /* connection is multiplexed */ + + bool tcp_fastopen; /* use TCP Fast Open */ + bool tls_enable_npn; /* TLS NPN extension? */ + bool tls_enable_alpn; /* TLS ALPN extension? */ }; struct hostname { @@ -809,7 +817,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 */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -825,6 +833,20 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */ size_t len, /* max amount to read */ CURLcode *err); /* error to return */ +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND +struct postponed_data { + char *buffer; /* Temporal store for received data during + sending, must be freed */ + size_t allocated_size; /* Size of temporal store */ + size_t recv_size; /* Size of received data during sending */ + size_t recv_processed; /* Size of processed part of postponed data */ +#ifdef DEBUGBUILD + curl_socket_t bindsock;/* Structure must be bound to specific socket, + used only for DEBUGASSERT */ +#endif /* DEBUGBUILD */ +}; +#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -874,10 +896,14 @@ struct connectdata { int socktype; /* SOCK_STREAM or SOCK_DGRAM */ struct hostname host; + struct hostname conn_to_host; /* the host to connect to. valid only if + bits.conn_to_host is set */ struct hostname proxy; long port; /* which port to use locally */ - int remote_port; /* what remote port to connect to, not the proxy port! */ + 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 */ /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is @@ -919,6 +945,9 @@ struct connectdata { Curl_recv *recv[2]; Curl_send *send[2]; +#ifdef USE_RECV_BEFORE_SEND_WORKAROUND + struct postponed_data postponed[2]; /* two buffers for two sockets */ +#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ struct ssl_config_data ssl_config; bool tls_upgraded; @@ -1226,11 +1255,13 @@ struct UrlState { bytes / second */ bool this_is_a_follow; /* this is a followed Location: request */ - char *first_host; /* if set, this should be the host name that we will + char *first_host; /* host name of the first (not followed) request. + if set, this should be the host name that we will sent authorization to, no else. Used to make Location: following not keep sending user+password... This is strdup() data. */ + int first_remote_port; /* remote port of the first (not followed) request */ struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */ long sessionage; /* number of the most recent session */ char *tempwrite; /* allocated buffer to keep data in when a write @@ -1314,9 +1345,9 @@ struct UrlState { curl_off_t infilesize; /* size of file to upload, -1 means unknown. Copied from set.filesize at start of operation */ - int drain; /* Increased when this stream has data to read, even if its - socket not necessarily is readable. Decreased when - checked. */ + size_t drain; /* Increased when this stream has data to read, even if its + socket is not necessarily is readable. Decreased when + checked. */ bool done; /* set to FALSE when Curl_do() is called and set to TRUE when Curl_done() is called, to prevent Curl_done() to get invoked twice when the multi interface is used. */ @@ -1407,8 +1438,10 @@ enum dupstring { STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */ #endif #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */ STRING_PROXY_SERVICE_NAME, /* Proxy service name */ +#endif +#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \ + defined(USE_SPNEGO) STRING_SERVICE_NAME, /* Service name */ #endif STRING_MAIL_FROM, @@ -1526,6 +1559,8 @@ struct UserDefined { struct curl_slist *telnet_options; /* linked list of telnet options */ 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 */ time_t timevalue; /* what time to compare with */ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ @@ -1573,7 +1608,6 @@ struct UserDefined { bool http_set_referer; /* is a custom referer used */ bool http_auto_referer; /* set "correct" referer when following location: */ bool opt_no_body; /* as set with CURLOPT_NOBODY */ - bool set_port; /* custom port number used */ bool upload; /* upload request */ enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ @@ -1613,7 +1647,7 @@ struct UserDefined { long allowed_protocols; long redir_protocols; #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - long socks5_gssapi_nec; /* flag to support nec socks5 server */ + bool socks5_gssapi_nec; /* Flag to support NEC SOCKS5 server */ #endif struct curl_slist *mail_rcpt; /* linked list of mail recipients */ bool sasl_ir; /* Enable/disable SASL initial response */ @@ -1635,11 +1669,12 @@ struct UserDefined { bool tcp_keepalive; /* use TCP keepalives */ long tcp_keepidle; /* seconds in idle before sending keepalive probe */ long tcp_keepintvl; /* seconds between TCP keepalive probes */ + bool tcp_fastopen; /* use TCP Fast Open */ size_t maxconnects; /* Max idle connections in the connection cache */ - bool ssl_enable_npn; /* TLS NPN extension? */ - bool ssl_enable_alpn; /* TLS ALPN extension? */ + bool ssl_enable_npn; /* TLS NPN extension? */ + bool ssl_enable_alpn; /* TLS ALPN extension? */ bool path_as_is; /* allow dotdots? */ bool pipewait; /* wait for pipe/multiplex status before starting a new connection */ diff --git a/project/jni/curl/lib/vauth/cleartext.c b/project/jni/curl/lib/vauth/cleartext.c new file mode 100644 index 000000000..a003f51de --- /dev/null +++ b/project/jni/curl/lib/vauth/cleartext.c @@ -0,0 +1,157 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC4616 PLAIN authentication + * Draft LOGIN SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_base64.h" +#include "curl_md5.h" +#include "warnless.h" +#include "strtok.h" +#include "strequal.h" +#include "rawstr.h" +#include "sendf.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_plain_message() + * + * This is used to generate an already encoded PLAIN message ready + * for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) +{ + CURLcode result; + char *plainauth; + size_t ulen; + size_t plen; + + ulen = strlen(userp); + plen = strlen(passwdp); + + plainauth = malloc(2 * ulen + plen + 2); + if(!plainauth) { + *outlen = 0; + *outptr = NULL; + return CURLE_OUT_OF_MEMORY; + } + + /* Calculate the reply */ + memcpy(plainauth, userp, ulen); + plainauth[ulen] = '\0'; + memcpy(plainauth + ulen + 1, userp, ulen); + plainauth[2 * ulen + 1] = '\0'; + memcpy(plainauth + 2 * ulen + 2, passwdp, plen); + + /* Base64 encode the reply */ + result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, + outlen); + free(plainauth); + + return result; +} + +/* + * Curl_auth_create_login_message() + * + * This is used to generate an already encoded LOGIN message containing the + * user name or password ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * valuep [in] - The user name or user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_login_message(struct SessionHandle *data, + const char *valuep, char **outptr, + size_t *outlen) +{ + size_t vlen = strlen(valuep); + + if(!vlen) { + /* Calculate an empty reply */ + *outptr = strdup("="); + if(*outptr) { + *outlen = (size_t) 1; + return CURLE_OK; + } + + *outlen = 0; + return CURLE_OUT_OF_MEMORY; + } + + /* Base64 encode the value */ + return Curl_base64_encode(data, valuep, vlen, outptr, outlen); +} + +/* + * Curl_auth_create_external_message() + * + * This is used to generate an already encoded EXTERNAL message containing + * the user name ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * user [in] - The user name. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_external_message(struct SessionHandle *data, + const char *user, char **outptr, + size_t *outlen) +{ + /* This is the same formatting as the login message */ + return Curl_auth_create_login_message(data, user, outptr, outlen); +} diff --git a/project/jni/curl/lib/vauth/cram.c b/project/jni/curl/lib/vauth/cram.c new file mode 100644 index 000000000..cd02e04ba --- /dev/null +++ b/project/jni/curl/lib/vauth/cram.c @@ -0,0 +1,138 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC2195 CRAM-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_base64.h" +#include "curl_hmac.h" +#include "curl_md5.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_decode_cram_md5_message() + * + * This is used to decode an already encoded CRAM-MD5 challenge message. + * + * Parameters: + * + * chlg64 [in] - The base64 encoded challenge message. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlg64len = strlen(chlg64); + + *outptr = NULL; + *outlen = 0; + + /* Decode the challenge if necessary */ + if(chlg64len && *chlg64 != '=') + result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen); + + return result; +} + +/* + * Curl_auth_create_cram_md5_message() + * + * This is used to generate an already encoded CRAM-MD5 response message ready + * for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg [in] - The challenge. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_cram_md5_message(struct SessionHandle *data, + const char *chlg, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + HMAC_context *ctxt; + unsigned char digest[MD5_DIGEST_LEN]; + char *response; + + if(chlg) + chlglen = strlen(chlg); + + /* Compute the digest using the password as the key */ + ctxt = Curl_HMAC_init(Curl_HMAC_MD5, + (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + /* Update the digest with the given challenge */ + if(chlglen > 0) + Curl_HMAC_update(ctxt, (const unsigned char *) chlg, + curlx_uztoui(chlglen)); + + /* Finalise the digest */ + Curl_HMAC_final(ctxt, digest); + + /* Generate the response */ + response = aprintf( + "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + userp, digest[0], digest[1], digest[2], digest[3], digest[4], + digest[5], digest[6], digest[7], digest[8], digest[9], digest[10], + digest[11], digest[12], digest[13], digest[14], digest[15]); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the response */ + result = Curl_base64_encode(data, response, 0, outptr, outlen); + + free(response); + + return result; +} + +#endif /* !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/project/jni/curl/lib/vauth/digest.c b/project/jni/curl/lib/vauth/digest.c new file mode 100644 index 000000000..72cf04829 --- /dev/null +++ b/project/jni/curl/lib/vauth/digest.c @@ -0,0 +1,883 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC2831 DIGEST-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + +#include + +#include "vauth/vauth.h" +#include "vauth/digest.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_hmac.h" +#include "curl_md5.h" +#include "vtls/vtls.h" +#include "warnless.h" +#include "strtok.h" +#include "rawstr.h" +#include "non-ascii.h" /* included for Curl_convert_... prototypes */ +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if !defined(USE_WINDOWS_SSPI) +#define DIGEST_QOP_VALUE_AUTH (1 << 0) +#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1) +#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2) + +#define DIGEST_QOP_VALUE_STRING_AUTH "auth" +#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int" +#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf" + +/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines. + It converts digest text to ASCII so the MD5 will be correct for + what ultimately goes over the network. +*/ +#define CURL_OUTPUT_DIGEST_CONV(a, b) \ + result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ + if(result) { \ + free(b); \ + return result; \ + } +#endif /* !USE_WINDOWS_SSPI */ + +bool Curl_auth_digest_get_pair(const char *str, char *value, char *content, + const char **endptr) +{ + int c; + bool starts_with_quote = FALSE; + bool escape = FALSE; + + for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);) + *value++ = *str++; + *value = 0; + + if('=' != *str++) + /* eek, no match */ + return FALSE; + + if('\"' == *str) { + /* This starts with a quote so it must end with one as well! */ + str++; + starts_with_quote = TRUE; + } + + 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; + + case '\"': + if(!escape && starts_with_quote) { + /* end of string */ + c = 0; + continue; + } + break; + } + + escape = FALSE; + *content++ = *str; + } + + *content = 0; + *endptr = str; + + return TRUE; +} + +#if !defined(USE_WINDOWS_SSPI) +/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ +static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i = 0; i < 16; i++) + snprintf((char *) &dest[i * 2], 3, "%02x", source[i]); +} + +/* Perform quoted-string escaping as described in RFC2616 and its errata */ +static char *auth_digest_string_quoted(const char *source) +{ + char *dest, *d; + const char *s = source; + size_t n = 1; /* null terminator */ + + /* Calculate size needed */ + while(*s) { + ++n; + if(*s == '"' || *s == '\\') { + ++n; + } + ++s; + } + + dest = malloc(n); + if(dest) { + s = source; + d = dest; + while(*s) { + if(*s == '"' || *s == '\\') { + *d++ = '\\'; + } + *d++ = *s++; + } + *d = 0; + } + + return dest; +} + +/* Retrieves the value for a corresponding key from the challenge string + * returns TRUE if the key could be found, FALSE if it does not exists + */ +static bool auth_digest_get_key_value(const char *chlg, + const char *key, + char *value, + size_t max_val_len, + char end_char) +{ + char *find_pos; + size_t i; + + find_pos = strstr(chlg, key); + if(!find_pos) + return FALSE; + + find_pos += strlen(key); + + for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i) + value[i] = *find_pos++; + value[i] = '\0'; + + return TRUE; +} + +static CURLcode auth_digest_get_qop_values(const char *options, int *value) +{ + char *tmp; + char *token; + char *tok_buf; + + /* Initialise the output */ + *value = 0; + + /* Tokenise the list of qop values. Use a temporary clone of the buffer since + strtok_r() ruins it. */ + tmp = strdup(options); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) + *value |= DIGEST_QOP_VALUE_AUTH; + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + *value |= DIGEST_QOP_VALUE_AUTH_INT; + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + *value |= DIGEST_QOP_VALUE_AUTH_CONF; + + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + return CURLE_OK; +} + +/* + * auth_decode_digest_md5_message() + * + * This is used internally to decode an already encoded DIGEST-MD5 challenge + * message into the seperate attributes. + * + * Parameters: + * + * chlg64 [in] - The base64 encoded challenge message. + * nonce [in/out] - The buffer where the nonce will be stored. + * nlen [in] - The length of the nonce buffer. + * realm [in/out] - The buffer where the realm will be stored. + * rlen [in] - The length of the realm buffer. + * alg [in/out] - The buffer where the algorithm will be stored. + * alen [in] - The length of the algorithm buffer. + * qop [in/out] - The buffer where the qop-options will be stored. + * qlen [in] - The length of the qop buffer. + * + * Returns CURLE_OK on success. + */ +static CURLcode auth_decode_digest_md5_message(const char *chlg64, + char *nonce, size_t nlen, + char *realm, size_t rlen, + char *alg, size_t alen, + char *qop, size_t qlen) +{ + CURLcode result = CURLE_OK; + unsigned char *chlg = NULL; + size_t chlglen = 0; + size_t chlg64len = strlen(chlg64); + + /* Decode the base-64 encoded challenge message */ + if(chlg64len && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) + return CURLE_BAD_CONTENT_ENCODING; + + /* Retrieve nonce string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen, + '\"')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Retrieve realm string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen, + '\"')) { + /* Challenge does not have a realm, set empty string [RFC2831] page 6 */ + strcpy(realm, ""); + } + + /* Retrieve algorithm string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Retrieve qop-options string from the challenge */ + if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) { + free(chlg); + return CURLE_BAD_CONTENT_ENCODING; + } + + free(chlg); + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t i; + MD5_context *ctxt; + char *response = NULL; + unsigned char digest[MD5_DIGEST_LEN]; + char HA1_hex[2 * MD5_DIGEST_LEN + 1]; + char HA2_hex[2 * MD5_DIGEST_LEN + 1]; + char resp_hash_hex[2 * MD5_DIGEST_LEN + 1]; + char nonce[64]; + char realm[128]; + char algorithm[64]; + char qop_options[64]; + int qop_values; + char cnonce[33]; + unsigned int entropy[4]; + char nonceCount[] = "00000001"; + char method[] = "AUTHENTICATE"; + char qop[] = DIGEST_QOP_VALUE_STRING_AUTH; + char *spn = NULL; + + /* Decode the challange message */ + result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce), + realm, sizeof(realm), + algorithm, sizeof(algorithm), + qop_options, sizeof(qop_options)); + if(result) + return result; + + /* We only support md5 sessions */ + if(strcmp(algorithm, "md5-sess") != 0) + return CURLE_BAD_CONTENT_ENCODING; + + /* Get the qop-values from the qop-options */ + result = auth_digest_get_qop_values(qop_options, &qop_values); + if(result) + return result; + + /* We only support auth quality-of-protection */ + if(!(qop_values & DIGEST_QOP_VALUE_AUTH)) + return CURLE_BAD_CONTENT_ENCODING; + + /* Generate 16 bytes of random data */ + entropy[0] = Curl_rand(data); + entropy[1] = Curl_rand(data); + entropy[2] = Curl_rand(data); + entropy[3] = Curl_rand(data); + + /* Convert the random data into a 32 byte hex string */ + snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", + entropy[0], entropy[1], entropy[2], entropy[3]); + + /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) userp, + curlx_uztoui(strlen(userp))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) realm, + curlx_uztoui(strlen(realm))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) passwdp, + curlx_uztoui(strlen(passwdp))); + Curl_MD5_final(ctxt, digest); + + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) + return CURLE_OUT_OF_MEMORY; + + Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_final(ctxt, digest); + + /* Convert calculated 16 octet hex into 32 bytes string */ + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate our SPN */ + spn = Curl_auth_build_spn(service, realm, NULL); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Calculate H(A2) */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) method, + curlx_uztoui(strlen(method))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) spn, + curlx_uztoui(strlen(spn))); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]); + + /* Now calculate the response hash */ + ctxt = Curl_MD5_init(Curl_DIGEST_MD5); + if(!ctxt) { + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) nonce, + curlx_uztoui(strlen(nonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) nonceCount, + curlx_uztoui(strlen(nonceCount))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) cnonce, + curlx_uztoui(strlen(cnonce))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + Curl_MD5_update(ctxt, (const unsigned char *) qop, + curlx_uztoui(strlen(qop))); + Curl_MD5_update(ctxt, (const unsigned char *) ":", 1); + + Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN); + Curl_MD5_final(ctxt, digest); + + for(i = 0; i < MD5_DIGEST_LEN; i++) + snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]); + + /* Generate the response */ + response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\"," + "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s," + "qop=%s", + userp, realm, nonce, + cnonce, nonceCount, spn, resp_hash_hex, qop); + free(spn); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the response */ + result = Curl_base64_encode(data, response, 0, outptr, outlen); + + free(response); + + return result; +} + +/* + * Curl_auth_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + bool before = FALSE; /* got a nonce before */ + bool foundAuth = FALSE; + bool foundAuthInt = FALSE; + char *token = NULL; + char *tmp = NULL; + + /* If we already have received a nonce, keep that in mind */ + if(digest->nonce) + before = TRUE; + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_digest_cleanup(digest); + + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "nonce")) { + free(digest->nonce); + digest->nonce = strdup(content); + if(!digest->nonce) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "stale")) { + if(Curl_raw_equal(content, "true")) { + digest->stale = TRUE; + digest->nc = 1; /* we make a new nonce now */ + } + } + else if(Curl_raw_equal(value, "realm")) { + free(digest->realm); + digest->realm = strdup(content); + if(!digest->realm) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "opaque")) { + free(digest->opaque); + digest->opaque = strdup(content); + if(!digest->opaque) + return CURLE_OUT_OF_MEMORY; + } + else if(Curl_raw_equal(value, "qop")) { + char *tok_buf; + /* Tokenize the list and choose auth if possible, use a temporary + clone of the buffer since strtok_r() ruins it */ + tmp = strdup(content); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + token = strtok_r(tmp, ",", &tok_buf); + while(token != NULL) { + if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + foundAuth = TRUE; + } + else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + foundAuthInt = TRUE; + } + token = strtok_r(NULL, ",", &tok_buf); + } + + free(tmp); + + /* Select only auth or auth-int. Otherwise, ignore */ + if(foundAuth) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + else if(foundAuthInt) { + free(digest->qop); + digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT); + if(!digest->qop) + return CURLE_OUT_OF_MEMORY; + } + } + else if(Curl_raw_equal(value, "algorithm")) { + free(digest->algorithm); + digest->algorithm = strdup(content); + if(!digest->algorithm) + return CURLE_OUT_OF_MEMORY; + + if(Curl_raw_equal(content, "MD5-sess")) + digest->algo = CURLDIGESTALGO_MD5SESS; + else if(Curl_raw_equal(content, "MD5")) + digest->algo = CURLDIGESTALGO_MD5; + else + return CURLE_BAD_CONTENT_ENCODING; + } + else { + /* Unknown specifier, ignore it! */ + } + } + else + break; /* We're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + + /* We had a nonce since before, and we got another one now without + 'stale=true'. This means we provided bad credentials in the previous + request */ + if(before && !digest->stale) + return CURLE_BAD_CONTENT_ENCODING; + + /* We got this header without a nonce, that's a bad Digest line! */ + if(!digest->nonce) + return CURLE_BAD_CONTENT_ENCODING; + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + CURLcode result; + unsigned char md5buf[16]; /* 16 bytes/128 bits */ + unsigned char request_digest[33]; + unsigned char *md5this; + unsigned char ha1[33]; /* 32 digits and 1 zero byte */ + unsigned char ha2[33]; /* 32 digits and 1 zero byte */ + char cnoncebuf[33]; + char *cnonce = NULL; + size_t cnonce_sz = 0; + char *userp_quoted; + char *response = NULL; + char *tmp = NULL; + + if(!digest->nc) + digest->nc = 1; + + if(!digest->cnonce) { + snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", + Curl_rand(data), Curl_rand(data), + Curl_rand(data), Curl_rand(data)); + + result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(result) + return result; + + digest->cnonce = cnonce; + } + + /* + If the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + If the algorithm is "MD5-sess" then: + + A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":" + unq(nonce-value) ":" unq(cnonce-value) + */ + + md5this = (unsigned char *) + aprintf("%s:%s:%s", userp, digest->realm, passwdp); + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + auth_digest_md5_to_ascii(md5buf, ha1); + + if(digest->algo == CURLDIGESTALGO_MD5SESS) { + /* nonce and cnonce are OUTSIDE the hash */ + tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */ + Curl_md5it(md5buf, (unsigned char *) tmp); + free(tmp); + auth_digest_md5_to_ascii(md5buf, ha1); + } + + /* + If the "qop" directive's value is "auth" or is unspecified, then A2 is: + + A2 = Method ":" digest-uri-value + + If the "qop" value is "auth-int", then A2 is: + + A2 = Method ":" digest-uri-value ":" H(entity-body) + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + md5this = (unsigned char *) aprintf("%s:%s", request, uripath); + + if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + /* We don't support auth-int for PUT or POST at the moment. + TODO: replace md5 of empty string with entity-body for PUT/POST */ + unsigned char *md5this2 = (unsigned char *) + aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); + free(md5this); + md5this = md5this2; + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + auth_digest_md5_to_ascii(md5buf, ha2); + + if(digest->qop) { + md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s", + ha1, + digest->nonce, + digest->nc, + digest->cnonce, + digest->qop, + ha2); + } + else { + md5this = (unsigned char *) aprintf("%s:%s:%s", + ha1, + digest->nonce, + ha2); + } + + if(!md5this) + return CURLE_OUT_OF_MEMORY; + + CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ + Curl_md5it(md5buf, md5this); + free(md5this); + auth_digest_md5_to_ascii(md5buf, request_digest); + + /* For test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + 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 + characters. algorithm and qop with standard values only contain web-safe + characters. + */ + userp_quoted = auth_digest_string_quoted(userp); + if(!userp_quoted) + return CURLE_OUT_OF_MEMORY; + + if(digest->qop) { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "cnonce=\"%s\", " + "nc=%08x, " + "qop=%s, " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + digest->cnonce, + digest->nc, + digest->qop, + request_digest); + + if(Curl_raw_equal(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 */ + } + else { + response = aprintf("username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"", + userp_quoted, + digest->realm, + digest->nonce, + uripath, + request_digest); + } + free(userp_quoted); + if(!response) + return CURLE_OUT_OF_MEMORY; + + /* Add the optional fields */ + if(digest->opaque) { + /* Append the opaque */ + tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + if(digest->algorithm) { + /* Append the algorithm */ + tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm); + free(response); + if(!tmp) + return CURLE_OUT_OF_MEMORY; + + response = tmp; + } + + /* Return the output */ + *outptr = response; + *outlen = strlen(response); + + return CURLE_OK; +} + +/* + * Curl_auth_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_auth_digest_cleanup(struct digestdata *digest) +{ + Curl_safefree(digest->nonce); + Curl_safefree(digest->cnonce); + Curl_safefree(digest->realm); + Curl_safefree(digest->opaque); + Curl_safefree(digest->qop); + Curl_safefree(digest->algorithm); + + digest->nc = 0; + digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */ + digest->stale = FALSE; /* default means normal, not stale */ +} +#endif /* !USE_WINDOWS_SSPI */ + +#endif /* CURL_DISABLE_CRYPTO_AUTH */ diff --git a/project/jni/curl/lib/vauth/digest.h b/project/jni/curl/lib/vauth/digest.h new file mode 100644 index 000000000..5722dcece --- /dev/null +++ b/project/jni/curl/lib/vauth/digest.h @@ -0,0 +1,43 @@ +#ifndef HEADER_CURL_DIGEST_H +#define HEADER_CURL_DIGEST_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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 + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) + +#define DIGEST_MAX_VALUE_LENGTH 256 +#define DIGEST_MAX_CONTENT_LENGTH 1024 + +enum { + CURLDIGESTALGO_MD5, + CURLDIGESTALGO_MD5SESS +}; + +/* 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); + +#endif + +#endif /* HEADER_CURL_DIGEST_H */ diff --git a/project/jni/curl/lib/vauth/digest_sspi.c b/project/jni/curl/lib/vauth/digest_sspi.c new file mode 100644 index 000000000..d13d08e56 --- /dev/null +++ b/project/jni/curl/lib/vauth/digest_sspi.c @@ -0,0 +1,527 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * Copyright (C) 2015, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC2831 DIGEST-MD5 authentication + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH) + +#include + +#include "vauth/vauth.h" +#include "vauth/digest.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" +#include "strdup.h" +#include "rawstr.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_digest_md5_message() + * + * This is used to generate an already encoded DIGEST-MD5 response message + * ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The base64 encoded challenge message. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + TCHAR *spn = NULL; + size_t chlglen = 0; + size_t token_max = 0; + unsigned char *input_token = NULL; + unsigned char *output_token = NULL; + CredHandle credentials; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Decode the base-64 encoded challenge message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &input_token, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!input_token) { + infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) { + free(input_token); + + return CURLE_NOT_BUILT_IN; + } + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + output_token = malloc(token_max); + if(!output_token) { + free(input_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Generate our SPN */ + spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL); + if(!spn) { + free(output_token); + free(input_token); + + return CURLE_OUT_OF_MEMORY; + } + + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &identity); + if(result) { + free(spn); + free(output_token); + free(input_token); + + return result; + } + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = input_token; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + /* Generate our response message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn, + 0, 0, 0, &chlg_desc, 0, + &context, &resp_desc, &attrs, + &expiry); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + Curl_sspi_free_identity(p_identity); + free(spn); + free(output_token); + free(input_token); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer, + outptr, outlen); + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the SPN */ + free(spn); + + /* Free the response buffer */ + free(output_token); + + /* Free the decoded challenge message */ + free(input_token); + + return result; +} + +/* + * Curl_override_sspi_http_realm() + * + * This is used to populate the domain in a SSPI identity structure + * The realm is extracted from the challenge message and used as the + * domain if it is not already explicitly set. + * + * Parameters: + * + * chlg [in] - The challenge message. + * identity [in/out] - The identity structure. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_override_sspi_http_realm(const char *chlg, + SEC_WINNT_AUTH_IDENTITY *identity) +{ + xcharp_u domain, dup_domain; + + /* If domain is blank or unset, check challenge message for realm */ + if(!identity->Domain || !identity->DomainLength) { + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Extract a value=content pair */ + if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { + if(Curl_raw_equal(value, "realm")) { + + /* Setup identity's domain and length */ + domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); + if(!domain.tchar_ptr) + return CURLE_OUT_OF_MEMORY; + + dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr); + if(!dup_domain.tchar_ptr) { + Curl_unicodefree(domain.tchar_ptr); + return CURLE_OUT_OF_MEMORY; + } + + free(identity->Domain); + identity->Domain = dup_domain.tbyte_ptr; + identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr)); + dup_domain.tchar_ptr = NULL; + + Curl_unicodefree(domain.tchar_ptr); + } + else { + /* Unknown specifier, ignore it! */ + } + } + else + break; /* We're done here */ + + /* Pass all additional spaces here */ + while(*chlg && ISSPACE(*chlg)) + chlg++; + + /* Allow the list to be comma-separated */ + if(',' == *chlg) + chlg++; + } + } + + return CURLE_OK; +} + +/* + * Curl_auth_decode_digest_http_message() + * + * This is used to decode a HTTP DIGEST challenge message into the seperate + * attributes. + * + * Parameters: + * + * chlg [in] - The challenge message. + * digest [in/out] - The digest data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest) +{ + size_t chlglen = strlen(chlg); + + /* We had an input token before and we got another one now. This means we + provided bad credentials in the previous request. */ + if(digest->input_token) + return CURLE_BAD_CONTENT_ENCODING; + + /* Simply store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); + if(!digest->input_token) + return CURLE_OUT_OF_MEMORY; + + digest->input_token_len = chlglen; + + return CURLE_OK; +} + +/* + * Curl_auth_create_digest_http_message() + * + * This is used to generate a HTTP DIGEST response message ready for sending + * to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * request [in] - The HTTP request. + * uripath [in] - The path of the HTTP uri. + * digest [in/out] - The digest data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uripath, + struct digestdata *digest, + char **outptr, size_t *outlen) +{ + size_t token_max; + CredHandle credentials; + CtxtHandle context; + char *resp; + BYTE *output_token; + PSecPkgInfo SecurityPackage; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer chlg_buf[3]; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + TCHAR *spn; + + (void) data; + + /* Query the security package for DigestSSP */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate the output buffer according to the max token size as indicated + by the security package */ + output_token = malloc(token_max); + if(!output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char*) digest->input_token, + &identity)) + return CURLE_OUT_OF_MEMORY; + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + spn = Curl_convert_UTF8_to_tchar((char *) uripath); + if(!spn) { + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Generate our reponse message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, &context, + &resp_desc, &attrs, &expiry); + Curl_unicodefree(spn); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + resp = malloc(resp_buf.cbBuffer + 1); + if(!resp) { + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Copy the generated reponse */ + memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); + resp[resp_buf.cbBuffer] = 0x00; + + /* Return the response */ + *outptr = resp; + *outlen = resp_buf.cbBuffer; + + /* Free our handles */ + s_pSecFn->DeleteSecurityContext(&context); + s_pSecFn->FreeCredentialsHandle(&credentials); + + /* Free the identity structure */ + Curl_sspi_free_identity(p_identity); + + /* Free the response buffer */ + free(output_token); + + return CURLE_OK; +} + +/* + * Curl_auth_digest_cleanup() + * + * This is used to clean up the digest specific data. + * + * Parameters: + * + * digest [in/out] - The digest data struct being cleaned up. + * + */ +void Curl_auth_digest_cleanup(struct digestdata *digest) +{ + /* Free the input token */ + Curl_safefree(digest->input_token); + + /* Reset any variables */ + digest->input_token_len = 0; +} + +#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/project/jni/curl/lib/curl_sasl_gssapi.c b/project/jni/curl/lib/vauth/krb5_gssapi.c similarity index 69% rename from project/jni/curl/lib/curl_sasl_gssapi.c rename to project/jni/curl/lib/vauth/krb5_gssapi.c index dcc0498b9..975675b5d 100644 --- a/project/jni/curl/lib/curl_sasl_gssapi.c +++ b/project/jni/curl/lib/vauth/krb5_gssapi.c @@ -29,6 +29,7 @@ #include +#include "vauth/vauth.h" #include "curl_sasl.h" #include "urldata.h" #include "curl_base64.h" @@ -41,25 +42,7 @@ #include "memdebug.h" /* -* Curl_sasl_build_gssapi_spn() -* -* This is used to build a SPN string in the format service@instance. -* -* Parameters: -* -* service [in] - The service type such as www, smtp, pop or imap. -* instance [in] - The host name or realm. -* -* Returns a pointer to the newly allocated SPN. -*/ -char *Curl_sasl_build_gssapi_spn(const char *service, const char *instance) -{ - /* Generate and return our SPN */ - return aprintf("%s@%s", service, instance); -} - -/* - * Curl_sasl_create_gssapi_user_message() + * Curl_auth_create_gssapi_user_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) user token * message ready for sending to the recipient. @@ -69,7 +52,8 @@ char *Curl_sasl_build_gssapi_spn(const char *service, const char *instance) * data [in] - The session handle. * userp [in] - The user name. * passdwp [in] - The user's password. - * service [in] - The service type such as www, smtp, pop or imap. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in[ - The host name. * mutual_auth [in] - Flag specifing whether or not mutual authentication * is enabled. * chlg64 [in] - Pointer to the optional base64 encoded challenge @@ -81,10 +65,11 @@ char *Curl_sasl_build_gssapi_spn(const char *service, const char *instance) * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, const char *userp, const char *passwdp, const char *service, + const char *host, const bool mutual_auth, const char *chlg64, struct kerberos5data *krb5, @@ -93,9 +78,9 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, CURLcode result = CURLE_OK; size_t chlglen = 0; unsigned char *chlg = NULL; - OM_uint32 gss_status; - OM_uint32 gss_major_status; - OM_uint32 gss_minor_status; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; @@ -103,10 +88,9 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, (void) userp; (void) passwdp; - if(krb5->context == GSS_C_NO_CONTEXT) { + if(!krb5->spn) { /* Generate our SPN */ - char *spn = Curl_sasl_build_gssapi_spn(service, - data->easy_conn->host.name); + char *spn = Curl_auth_build_spn(service, NULL, host); if(!spn) return CURLE_OUT_OF_MEMORY; @@ -115,10 +99,11 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, spn_token.length = strlen(spn); /* Import the SPN */ - gss_major_status = gss_import_name(&gss_minor_status, &spn_token, - GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_import_name() failed: "); + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_import_name() failed: ", + major_status, minor_status); free(spn); @@ -127,9 +112,10 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, free(spn); } - else { + + if(chlg64 && *chlg64) { /* Decode the base-64 encoded challenge message */ - if(strlen(chlg64) && *chlg64 != '=') { + if(*chlg64 != '=') { result = Curl_base64_decode(chlg64, &chlg, &chlglen); if(result) return result; @@ -147,25 +133,26 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, input_token.length = chlglen; } - gss_major_status = Curl_gss_init_sec_context(data, - &gss_minor_status, - &krb5->context, - krb5->spn, - &Curl_krb5_mech_oid, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - &output_token, - mutual_auth, - NULL); + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &krb5->context, + krb5->spn, + &Curl_krb5_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + mutual_auth, + NULL); + /* Free the decoded challenge as it is not required anymore */ free(input_token.value); - if(GSS_ERROR(gss_major_status)) { + if(GSS_ERROR(major_status)) { if(output_token.value) - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); - Curl_gss_log_error(data, gss_minor_status, - "gss_init_sec_context() failed: "); + Curl_gss_log_error(data, "gss_init_sec_context() failed: ", + major_status, minor_status); return CURLE_RECV_ERROR; } @@ -175,14 +162,19 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, result = Curl_base64_encode(data, (char *) output_token.value, output_token.length, outptr, outlen); - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); + } + else if(mutual_auth) { + *outptr = strdup(""); + if(!*outptr) + result = CURLE_OUT_OF_MEMORY; } return result; } /* - * Curl_sasl_create_gssapi_security_message() + * Curl_auth_create_gssapi_security_message() * * This is used to generate an already encoded GSSAPI (Kerberos V5) security * token message ready for sending to the recipient. @@ -198,7 +190,7 @@ CURLcode Curl_sasl_create_gssapi_user_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, @@ -209,9 +201,9 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, size_t messagelen = 0; unsigned char *chlg = NULL; unsigned char *message = NULL; - OM_uint32 gss_status; - OM_uint32 gss_major_status; - OM_uint32 gss_minor_status; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; unsigned int indata = 0; @@ -237,12 +229,12 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* Get the fully qualified username back from the context */ - gss_major_status = gss_inquire_context(&gss_minor_status, krb5->context, - &username, NULL, NULL, NULL, NULL, - NULL, NULL); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, - "gss_inquire_context() failed: "); + major_status = gss_inquire_context(&minor_status, krb5->context, + &username, NULL, NULL, NULL, NULL, + NULL, NULL); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_inquire_context() failed: ", + major_status, minor_status); free(chlg); @@ -250,10 +242,11 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* Convert the username from internal format to a displayable token */ - gss_major_status = gss_display_name(&gss_minor_status, username, - &username_token, NULL); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_display_name() failed: "); + major_status = gss_display_name(&minor_status, username, + &username_token, NULL); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_display_name() failed: ", + major_status, minor_status); free(chlg); @@ -265,12 +258,13 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, input_token.length = chlglen; /* Decrypt the inbound challenge and obtain the qop */ - gss_major_status = gss_unwrap(&gss_minor_status, krb5->context, &input_token, - &output_token, NULL, &qop); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_unwrap() failed: "); + major_status = gss_unwrap(&minor_status, krb5->context, &input_token, + &output_token, NULL, &qop); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_unwrap() failed: ", + major_status, minor_status); - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); free(chlg); return CURLE_BAD_CONTENT_ENCODING; @@ -280,7 +274,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, if(output_token.length != 4) { infof(data, "GSSAPI handshake failure (invalid security data)\n"); - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); free(chlg); return CURLE_BAD_CONTENT_ENCODING; @@ -288,7 +282,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, /* Copy the data out and free the challenge as it is not required anymore */ memcpy(&indata, output_token.value, 4); - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); free(chlg); /* Extract the security layer */ @@ -296,7 +290,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, if(!(sec_layer & GSSAUTH_P_NONE)) { infof(data, "GSSAPI handshake failure (invalid security layer)\n"); - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); return CURLE_BAD_CONTENT_ENCODING; } @@ -314,14 +308,14 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, messagelen = sizeof(outdata) + username_token.length + 1; message = malloc(messagelen); if(!message) { - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); return CURLE_OUT_OF_MEMORY; } /* Populate the message with the security layer, client supported receive message size and authorization identity including the 0x00 based - terminator. Note: Dispite RFC4752 Section 3.1 stating "The authorization + terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization identity is not terminated with the zero-valued (%x00) octet." it seems necessary to include it. */ outdata = htonl(max_size) | sec_layer; @@ -331,18 +325,19 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, message[messagelen - 1] = '\0'; /* Free the username token as it is not required anymore */ - gss_release_buffer(&gss_status, &username_token); + gss_release_buffer(&unused_status, &username_token); /* Setup the "authentication data" security buffer */ input_token.value = message; input_token.length = messagelen; /* Encrypt the data */ - gss_major_status = gss_wrap(&gss_minor_status, krb5->context, 0, - GSS_C_QOP_DEFAULT, &input_token, NULL, - &output_token); - if(GSS_ERROR(gss_major_status)) { - Curl_gss_log_error(data, gss_minor_status, "gss_wrap() failed: "); + major_status = gss_wrap(&minor_status, krb5->context, 0, + GSS_C_QOP_DEFAULT, &input_token, NULL, + &output_token); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_wrap() failed: ", + major_status, minor_status); free(message); @@ -354,7 +349,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, output_token.length, outptr, outlen); /* Free the output buffer */ - gss_release_buffer(&gss_status, &output_token); + gss_release_buffer(&unused_status, &output_token); /* Free the message buffer */ free(message); @@ -363,7 +358,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, } /* - * Curl_sasl_gssapi_cleanup() + * Curl_auth_gssapi_cleanup() * * This is used to clean up the GSSAPI (Kerberos V5) specific data. * @@ -372,7 +367,7 @@ CURLcode Curl_sasl_create_gssapi_security_message(struct SessionHandle *data, * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. * */ -void Curl_sasl_gssapi_cleanup(struct kerberos5data *krb5) +void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5) { OM_uint32 minor_status; diff --git a/project/jni/curl/lib/vauth/krb5_sspi.c b/project/jni/curl/lib/vauth/krb5_sspi.c new file mode 100644 index 000000000..bf56a64e7 --- /dev/null +++ b/project/jni/curl/lib/vauth/krb5_sspi.c @@ -0,0 +1,496 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * 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. + * + * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_gssapi_user_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) user token + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * mutual_auth [in] - Flag specifing whether or not mutual authentication + * is enabled. + * chlg64 [in] - The optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual_auth, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + CtxtHandle context; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + if(!krb5->spn) { + /* Generate our SPN */ + krb5->spn = Curl_auth_build_spn(service, host, NULL); + if(!krb5->spn) + return CURLE_OUT_OF_MEMORY; + } + + if(!krb5->output_token) { + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + if(status != SEC_E_OK) { + return CURLE_NOT_BUILT_IN; + } + + krb5->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our response buffer */ + krb5->output_token = malloc(krb5->token_max); + if(!krb5->output_token) + return CURLE_OUT_OF_MEMORY; + } + + if(!krb5->credentials) { + /* Do we have credientials to use or are we using single sign-on? */ + if(userp && *userp) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + krb5->p_identity = &krb5->identity; + } + else + /* Use the current Windows user */ + krb5->p_identity = NULL; + + /* Allocate our credentials handle */ + krb5->credentials = malloc(sizeof(CredHandle)); + if(!krb5->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(krb5->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) + TEXT(SP_NAME_KERBEROS), + SECPKG_CRED_OUTBOUND, NULL, + krb5->p_identity, NULL, NULL, + krb5->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + krb5->context = malloc(sizeof(CtxtHandle)); + if(!krb5->context) + return CURLE_OUT_OF_MEMORY; + + memset(krb5->context, 0, sizeof(CtxtHandle)); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = chlg; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = krb5->output_token; + resp_buf.cbBuffer = curlx_uztoul(krb5->token_max); + + /* Generate our challenge-response message */ + status = s_pSecFn->InitializeSecurityContext(krb5->credentials, + chlg ? krb5->context : NULL, + krb5->spn, + (mutual_auth ? + ISC_REQ_MUTUAL_AUTH : 0), + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, 0, + &context, + &resp_desc, &attrs, + &expiry); + + /* Free the decoded challenge as it is not required anymore */ + free(chlg); + + if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + return CURLE_RECV_ERROR; + } + + if(memcmp(&context, krb5->context, sizeof(context))) { + s_pSecFn->DeleteSecurityContext(krb5->context); + + memcpy(krb5->context, &context, sizeof(context)); + } + + if(resp_buf.cbBuffer) { + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer, + resp_buf.cbBuffer, outptr, outlen); + } + else if(mutual_auth) { + *outptr = strdup(""); + if(!*outptr) + result = CURLE_OUT_OF_MEMORY; + } + + return result; +} + +/* + * Curl_auth_create_gssapi_security_message() + * + * This is used to generate an already encoded GSSAPI (Kerberos V5) security + * token message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * chlg64 [in] - The optional base64 encoded challenge message. + * krb5 [in/out] - The Kerberos 5 data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen) +{ + CURLcode result = CURLE_OK; + size_t offset = 0; + size_t chlglen = 0; + size_t messagelen = 0; + size_t appdatalen = 0; + unsigned char *chlg = NULL; + unsigned char *trailer = NULL; + unsigned char *message = NULL; + unsigned char *padding = NULL; + unsigned char *appdata = NULL; + SecBuffer input_buf[2]; + SecBuffer wrap_buf[3]; + SecBufferDesc input_desc; + SecBufferDesc wrap_desc; + unsigned long indata = 0; + unsigned long outdata = 0; + unsigned long qop = 0; + unsigned long sec_layer = 0; + unsigned long max_size = 0; + SecPkgContext_Sizes sizes; + SecPkgCredentials_Names names; + SECURITY_STATUS status; + char *user_name; + + /* Decode the base-64 encoded input message */ + if(strlen(chlg64) && *chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Get our response size information */ + status = s_pSecFn->QueryContextAttributes(krb5->context, + SECPKG_ATTR_SIZES, + &sizes); + if(status != SEC_E_OK) { + free(chlg); + + return CURLE_OUT_OF_MEMORY; + } + + /* Get the fully qualified username back from the context */ + status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials, + SECPKG_CRED_ATTR_NAMES, + &names); + if(status != SEC_E_OK) { + free(chlg); + + return CURLE_RECV_ERROR; + } + + /* Setup the "input" security buffer */ + input_desc.ulVersion = SECBUFFER_VERSION; + input_desc.cBuffers = 2; + input_desc.pBuffers = input_buf; + input_buf[0].BufferType = SECBUFFER_STREAM; + input_buf[0].pvBuffer = chlg; + input_buf[0].cbBuffer = curlx_uztoul(chlglen); + input_buf[1].BufferType = SECBUFFER_DATA; + input_buf[1].pvBuffer = NULL; + input_buf[1].cbBuffer = 0; + + /* Decrypt the inbound challenge and obtain the qop */ + status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); + if(status != SEC_E_OK) { + infof(data, "GSSAPI handshake failure (empty security message)\n"); + + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Not 4 octets long so fail as per RFC4752 Section 3.1 */ + if(input_buf[1].cbBuffer != 4) { + infof(data, "GSSAPI handshake failure (invalid security data)\n"); + + free(chlg); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Copy the data out and free the challenge as it is not required anymore */ + memcpy(&indata, input_buf[1].pvBuffer, 4); + s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); + free(chlg); + + /* Extract the security layer */ + sec_layer = indata & 0x000000FF; + if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { + infof(data, "GSSAPI handshake failure (invalid security layer)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Extract the maximum message size the server can receive */ + max_size = ntohl(indata & 0xFFFFFF00); + if(max_size > 0) { + /* The server has told us it supports a maximum receive buffer, however, as + we don't require one unless we are encrypting data, we tell the server + our receive buffer is zero. */ + max_size = 0; + } + + /* Allocate the trailer */ + trailer = malloc(sizes.cbSecurityTrailer); + if(!trailer) + return CURLE_OUT_OF_MEMORY; + + /* Convert the user name to UTF8 when operating with Unicode */ + user_name = Curl_convert_tchar_to_UTF8(names.sUserName); + if(!user_name) { + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate our message */ + messagelen = sizeof(outdata) + strlen(user_name) + 1; + message = malloc(messagelen); + if(!message) { + free(trailer); + Curl_unicodefree(user_name); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the message with the security layer, client supported receive + message size and authorization identity including the 0x00 based + terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization + identity is not terminated with the zero-valued (%x00) octet." it seems + necessary to include it. */ + outdata = htonl(max_size) | sec_layer; + memcpy(message, &outdata, sizeof(outdata)); + strcpy((char *) message + sizeof(outdata), user_name); + Curl_unicodefree(user_name); + + /* Allocate the padding */ + padding = malloc(sizes.cbBlockSize); + if(!padding) { + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Setup the "authentication data" security buffer */ + wrap_desc.ulVersion = SECBUFFER_VERSION; + wrap_desc.cBuffers = 3; + wrap_desc.pBuffers = wrap_buf; + wrap_buf[0].BufferType = SECBUFFER_TOKEN; + wrap_buf[0].pvBuffer = trailer; + wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer; + wrap_buf[1].BufferType = SECBUFFER_DATA; + wrap_buf[1].pvBuffer = message; + wrap_buf[1].cbBuffer = curlx_uztoul(messagelen); + wrap_buf[2].BufferType = SECBUFFER_PADDING; + wrap_buf[2].pvBuffer = padding; + wrap_buf[2].cbBuffer = sizes.cbBlockSize; + + /* Encrypt the data */ + status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT, + &wrap_desc, 0); + if(status != SEC_E_OK) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate the encryption (wrap) buffer */ + appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer + + wrap_buf[2].cbBuffer; + appdata = malloc(appdatalen); + if(!appdata) { + free(padding); + free(message); + free(trailer); + + return CURLE_OUT_OF_MEMORY; + } + + /* Populate the encryption buffer */ + memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer); + offset += wrap_buf[0].cbBuffer; + memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer); + offset += wrap_buf[1].cbBuffer; + memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer); + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr, + outlen); + + /* Free all of our local buffers */ + free(appdata); + free(padding); + free(message); + free(trailer); + + return result; +} + +/* + * Curl_auth_gssapi_cleanup() + * + * This is used to clean up the GSSAPI (Kerberos V5) specific data. + * + * Parameters: + * + * krb5 [in/out] - The Kerberos 5 data struct being cleaned up. + * + */ +void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5) +{ + /* Free our security context */ + if(krb5->context) { + s_pSecFn->DeleteSecurityContext(krb5->context); + free(krb5->context); + krb5->context = NULL; + } + + /* Free our credentials handle */ + if(krb5->credentials) { + s_pSecFn->FreeCredentialsHandle(krb5->credentials); + free(krb5->credentials); + krb5->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(krb5->p_identity); + krb5->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(krb5->spn); + Curl_safefree(krb5->output_token); + + /* Reset any variables */ + krb5->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/ diff --git a/project/jni/curl/lib/curl_ntlm_msgs.c b/project/jni/curl/lib/vauth/ntlm.c similarity index 96% rename from project/jni/curl/lib/curl_ntlm_msgs.c rename to project/jni/curl/lib/vauth/ntlm.c index fc9547207..e27f4237b 100644 --- a/project/jni/curl/lib/curl_ntlm_msgs.c +++ b/project/jni/curl/lib/vauth/ntlm.c @@ -28,7 +28,7 @@ * NTLM details: * * http://davenport.sourceforge.net/ntlm.html - * http://www.innovation.ch/java/ntlm.html + * https://www.innovation.ch/java/ntlm.html */ #define DEBUG_ME 0 @@ -49,8 +49,8 @@ #endif #define BUILDING_CURL_NTLM_MSGS_C -#include "curl_ntlm_msgs.h" -#include "curl_sasl.h" +#include "vauth/vauth.h" +#include "vauth/ntlm.h" #include "curl_endian.h" #include "curl_printf.h" @@ -138,7 +138,9 @@ static void ntlm_print_flags(FILE *handle, unsigned long flags) static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) { const char *p = buf; - (void)handle; + + (void) handle; + fprintf(stderr, "0x"); while(len-- > 0) fprintf(stderr, "%02.2x", (unsigned int)*p++); @@ -215,7 +217,7 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, */ /* - * Curl_sasl_decode_ntlm_type2_message() + * Curl_auth_decode_ntlm_type2_message() * * This is used to decode an already encoded NTLM type-2 message. The message * is first decoded from a base64 string into a raw NTLM message and checked @@ -230,7 +232,7 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_decode_ntlm_type2_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, const char *type2msg, struct ntlmdata *ntlm) { @@ -327,7 +329,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) } /* - * Curl_sasl_create_ntlm_type1_message() + * Curl_auth_create_ntlm_type1_message() * * This is used to generate an already encoded NTLM type-1 message ready for * sending to the recipient using the appropriate compile time crypto API. @@ -343,7 +345,7 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length) * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, +CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, const char *passwdp, struct ntlmdata *ntlm, char **outptr, size_t *outlen) @@ -376,7 +378,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, (void)passwdp; /* Clean up any former leftovers and initialise to defaults */ - Curl_sasl_ntlm_cleanup(ntlm); + Curl_auth_ntlm_cleanup(ntlm); #if USE_NTRESPONSES && USE_NTLM2SESSION #define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY @@ -446,7 +448,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, } /* - * Curl_sasl_create_ntlm_type3_message() + * Curl_auth_create_ntlm_type3_message() * * This is used to generate an already encoded NTLM type-3 message ready for * sending to the recipient using the appropriate compile time crypto API. @@ -463,7 +465,7 @@ CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp, * * Returns CURLE_OK on success. */ -CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, +CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, @@ -813,9 +815,28 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data, /* Return with binary blob encoded into base64 */ result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); - Curl_sasl_ntlm_cleanup(ntlm); + Curl_auth_ntlm_cleanup(ntlm); return result; } +/* +* Curl_auth_ntlm_cleanup() +* +* This is used to clean up the NTLM specific data. +* +* Parameters: +* +* ntlm [in/out] - The NTLM data struct being cleaned up. +* +*/ +void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free the target info */ + Curl_safefree(ntlm->target_info); + + /* Reset any variables */ + ntlm->target_info_len = 0; +} + #endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/project/jni/curl/lib/curl_ntlm_msgs.h b/project/jni/curl/lib/vauth/ntlm.h similarity index 97% rename from project/jni/curl/lib/curl_ntlm_msgs.h rename to project/jni/curl/lib/vauth/ntlm.h index b9026f87c..b14e7a56a 100644 --- a/project/jni/curl/lib/curl_ntlm_msgs.h +++ b/project/jni/curl/lib/vauth/ntlm.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_NTLM_MSGS_H -#define HEADER_CURL_NTLM_MSGS_H +#ifndef HEADER_CURL_NTLM_H +#define HEADER_CURL_NTLM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -140,4 +140,4 @@ #endif /* USE_NTLM */ -#endif /* HEADER_CURL_NTLM_MSGS_H */ +#endif /* HEADER_CURL_NTLM_H */ diff --git a/project/jni/curl/lib/vauth/ntlm_sspi.c b/project/jni/curl/lib/vauth/ntlm_sspi.c new file mode 100644 index 000000000..532e270fd --- /dev/null +++ b/project/jni/curl/lib/vauth/ntlm_sspi.c @@ -0,0 +1,314 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_ntlm_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready for + * sending to the recipient. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + PSecPkgInfo SecurityPackage; + SecBuffer type_1_buf; + SecBufferDesc type_1_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + /* Clean up any former leftovers and initialise to defaults */ + Curl_auth_ntlm_cleanup(ntlm); + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + if(status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + ntlm->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + ntlm->output_token = malloc(ntlm->token_max); + if(!ntlm->output_token) + return CURLE_OUT_OF_MEMORY; + + if(userp && *userp) { + CURLcode result; + + /* Populate our identity structure */ + result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + ntlm->p_identity = &ntlm->identity; + } + else + /* Use the current Windows user */ + ntlm->p_identity = NULL; + + /* Allocate our credentials handle */ + ntlm->credentials = malloc(sizeof(CredHandle)); + if(!ntlm->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_NTLM), + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + ntlm->credentials, &expiry); + if(status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + ntlm->context = malloc(sizeof(CtxtHandle)); + if(!ntlm->context) + return CURLE_OUT_OF_MEMORY; + + memset(ntlm->context, 0, sizeof(CtxtHandle)); + + /* Setup the type-1 "output" security buffer */ + type_1_desc.ulVersion = SECBUFFER_VERSION; + type_1_desc.cBuffers = 1; + type_1_desc.pBuffers = &type_1_buf; + type_1_buf.BufferType = SECBUFFER_TOKEN; + type_1_buf.pvBuffer = ntlm->output_token; + type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-1 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + NULL, 0, + ntlm->context, &type_1_desc, + &attrs, &expiry); + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) + return CURLE_RECV_ERROR; + + /* Base64 encode the response */ + return Curl_base64_encode(NULL, (char *) ntlm->output_token, + type_1_buf.cbBuffer, outptr, outlen); +} + +/* + * Curl_auth_decode_ntlm_type2_message() + * + * This is used to decode an already encoded NTLM type-2 message. + * + * Parameters: + * + * data [in] - The session handle. + * type2msg [in] - The base64 encoded type-2 message. + * ntlm [in/out] - The NTLM data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm) +{ + CURLcode result = CURLE_OK; + unsigned char *type2 = NULL; + size_t type2_len = 0; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + /* Decode the base-64 encoded type-2 message */ + if(strlen(type2msg) && *type2msg != '=') { + result = Curl_base64_decode(type2msg, &type2, &type2_len); + if(result) + return result; + } + + /* Ensure we have a valid type-2 message */ + if(!type2) { + infof(data, "NTLM handshake failure (empty type-2 message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Simply store the challenge for use later */ + ntlm->input_token = type2; + ntlm->input_token_len = type2_len; + + return result; +} + +/* +* Curl_auth_create_ntlm_type3_message() + * Curl_auth_create_ntlm_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready for + * sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The NTLM data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + SecBuffer type_2_buf; + SecBuffer type_3_buf; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + + (void) passwdp; + (void) userp; + + /* Setup the type-2 "input" security buffer */ + type_2_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2_buf; + type_2_buf.BufferType = SECBUFFER_TOKEN; + type_2_buf.pvBuffer = ntlm->input_token; + type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len); + + /* Setup the type-3 "output" security buffer */ + type_3_desc.ulVersion = SECBUFFER_VERSION; + type_3_desc.cBuffers = 1; + type_3_desc.pBuffers = &type_3_buf; + type_3_buf.BufferType = SECBUFFER_TOKEN; + type_3_buf.pvBuffer = ntlm->output_token; + type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max); + + /* Generate our type-3 message */ + status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, + ntlm->context, + (TCHAR *) TEXT(""), + 0, 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, ntlm->context, + &type_3_desc, + &attrs, &expiry); + if(status != SEC_E_OK) { + infof(data, "NTLM handshake failure (type-3 message): Status=%x\n", + status); + + return CURLE_RECV_ERROR; + } + + /* Base64 encode the response */ + result = Curl_base64_encode(data, (char *) ntlm->output_token, + type_3_buf.cbBuffer, outptr, outlen); + + Curl_auth_ntlm_cleanup(ntlm); + + return result; +} + +/* + * Curl_auth_ntlm_cleanup() + * + * This is used to clean up the NTLM specific data. + * + * Parameters: + * + * ntlm [in/out] - The NTLM data struct being cleaned up. + * + */ +void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm) +{ + /* Free our security context */ + if(ntlm->context) { + s_pSecFn->DeleteSecurityContext(ntlm->context); + free(ntlm->context); + ntlm->context = NULL; + } + + /* Free our credentials handle */ + if(ntlm->credentials) { + s_pSecFn->FreeCredentialsHandle(ntlm->credentials); + free(ntlm->credentials); + ntlm->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(ntlm->p_identity); + ntlm->p_identity = NULL; + + /* Free the input and output tokens */ + Curl_safefree(ntlm->input_token); + Curl_safefree(ntlm->output_token); + + /* Reset any variables */ + ntlm->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_NTLM */ diff --git a/project/jni/curl/lib/vauth/oauth2.c b/project/jni/curl/lib/vauth/oauth2.c new file mode 100644 index 000000000..fccdfb86c --- /dev/null +++ b/project/jni/curl/lib/vauth/oauth2.c @@ -0,0 +1,86 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC6749 OAuth 2.0 Authorization Framework + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include +#include "urldata.h" + +#include "vauth/vauth.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_create_oauth_bearer_message() + * + * This is used to generate an already encoded OAuth 2.0 message ready for + * sending to the recipient. + * + * Parameters: + * + * data[in] - The session handle. + * user[in] - The user name. + * host[in] - The host name(for OAUTHBEARER). + * port[in] - The port(for OAUTHBEARER when not Port 80). + * bearer[in] - The bearer token. + * outptr[in / out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen[out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_oauth_bearer_message(struct SessionHandle *data, + const char *user, + const char *host, + const long port, + const char *bearer, + char **outptr, size_t *outlen) +{ + CURLcode result = CURLE_OK; + char *oauth = NULL; + + /* Generate the message */ + if(host == NULL && (port == 0 || port == 80)) + oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer); + else if(port == 0 || port == 80) + oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host, + bearer); + else + oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user, + host, port, bearer); + if(!oauth) + return CURLE_OUT_OF_MEMORY; + + /* Base64 encode the reply */ + result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen); + + free(oauth); + + return result; +} diff --git a/project/jni/curl/lib/vauth/spnego_gssapi.c b/project/jni/curl/lib/vauth/spnego_gssapi.c new file mode 100644 index 000000000..739e35b6e --- /dev/null +++ b/project/jni/curl/lib/vauth/spnego_gssapi.c @@ -0,0 +1,260 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC4178 Simple and Protected GSS-API Negotiation Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "curl_gssapi.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_decode_spnego_message() + * + * This is used to decode an already encoded SPNEGO (Negotiate) challenge + * message. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * chlg64 [in] - The optional base64 encoded challenge message. + * nego [in/out] - The Negotiate data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + OM_uint32 major_status; + OM_uint32 minor_status; + OM_uint32 unused_status; + gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; + + (void) user; + (void) password; + + if(nego->context && nego->status == GSS_S_COMPLETE) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_auth_spnego_cleanup(nego); + return CURLE_LOGIN_DENIED; + } + + if(!nego->spn) { + /* Generate our SPN */ + char *spn = Curl_auth_build_spn(service, NULL, host); + if(!spn) + return CURLE_OUT_OF_MEMORY; + + /* Populate the SPN structure */ + spn_token.value = spn; + spn_token.length = strlen(spn); + + /* Import the SPN */ + major_status = gss_import_name(&minor_status, &spn_token, + GSS_C_NT_HOSTBASED_SERVICE, + &nego->spn); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_import_name() failed: ", + major_status, minor_status); + + free(spn); + + return CURLE_OUT_OF_MEMORY; + } + + free(spn); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "SPNEGO handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + input_token.value = chlg; + input_token.length = chlglen; + } + + /* Generate our challenge-response message */ + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &nego->context, + nego->spn, + &Curl_spnego_mech_oid, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + TRUE, + NULL); + + /* Free the decoded challenge as it is not required anymore */ + Curl_safefree(input_token.value); + + nego->status = major_status; + if(GSS_ERROR(major_status)) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + Curl_gss_log_error(data, "gss_init_sec_context() failed: ", + major_status, minor_status); + + return CURLE_OUT_OF_MEMORY; + } + + if(!output_token.value || !output_token.length) { + if(output_token.value) + gss_release_buffer(&unused_status, &output_token); + + return CURLE_OUT_OF_MEMORY; + } + + nego->output_token = output_token; + + return CURLE_OK; +} + +/* + * Curl_auth_create_spnego_message() + * + * This is used to generate an already encoded SPNEGO (Negotiate) response + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * nego [in/out] - The Negotiate data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, + struct negotiatedata *nego, + char **outptr, size_t *outlen) +{ + CURLcode result; + OM_uint32 minor_status; + + /* Base64 encode the already generated response */ + result = Curl_base64_encode(data, + nego->output_token.value, + nego->output_token.length, + outptr, outlen); + + if(result) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + return result; + } + + if(!*outptr || !*outlen) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + return CURLE_REMOTE_ACCESS_DENIED; + } + + return CURLE_OK; +} + +/* + * Curl_auth_spnego_cleanup() + * + * This is used to clean up the SPNEGO (Negotiate) specific data. + * + * Parameters: + * + * nego [in/out] - The Negotiate data struct being cleaned up. + * + */ +void Curl_auth_spnego_cleanup(struct negotiatedata* nego) +{ + OM_uint32 minor_status; + + /* Free our security context */ + if(nego->context != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER); + nego->context = GSS_C_NO_CONTEXT; + } + + /* Free the output token */ + if(nego->output_token.value) { + gss_release_buffer(&minor_status, &nego->output_token); + nego->output_token.value = NULL; + nego->output_token.length = 0; + + } + + /* Free the SPN */ + if(nego->spn != GSS_C_NO_NAME) { + gss_release_name(&minor_status, &nego->spn); + nego->spn = GSS_C_NO_NAME; + } + + /* Reset any variables */ + nego->status = 0; +} + +#endif /* HAVE_GSSAPI && USE_SPNEGO */ diff --git a/project/jni/curl/lib/vauth/spnego_sspi.c b/project/jni/curl/lib/vauth/spnego_sspi.c new file mode 100644 index 000000000..797466470 --- /dev/null +++ b/project/jni/curl/lib/vauth/spnego_sspi.c @@ -0,0 +1,297 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.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. + * + * RFC4178 Simple and Protected GSS-API Negotiation Mechanism + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO) + +#include + +#include "vauth/vauth.h" +#include "urldata.h" +#include "curl_base64.h" +#include "warnless.h" +#include "curl_multibyte.h" +#include "sendf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_decode_spnego_message() + * + * This is used to decode an already encoded SPNEGO (Negotiate) challenge + * message. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * chlg64 [in] - The optional base64 encoded challenge message. + * nego [in/out] - The Negotiate data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, + const char *user, + const char *password, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego) +{ + CURLcode result = CURLE_OK; + size_t chlglen = 0; + unsigned char *chlg = NULL; + PSecPkgInfo SecurityPackage; + SecBuffer chlg_buf; + SecBuffer resp_buf; + SecBufferDesc chlg_desc; + SecBufferDesc resp_desc; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + + if(nego->context && nego->status == SEC_E_OK) { + /* We finished successfully our part of authentication, but server + * rejected it (since we're again here). Exit with an error since we + * can't invent anything better */ + Curl_auth_spnego_cleanup(nego); + return CURLE_LOGIN_DENIED; + } + + if(!nego->spn) { + /* Generate our SPN */ + nego->spn = Curl_auth_build_spn(service, host, NULL); + if(!nego->spn) + return CURLE_OUT_OF_MEMORY; + } + + if(!nego->output_token) { + /* Query the security package for Negotiate */ + nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + if(nego->status != SEC_E_OK) + return CURLE_NOT_BUILT_IN; + + nego->token_max = SecurityPackage->cbMaxToken; + + /* Release the package buffer as it is not required anymore */ + s_pSecFn->FreeContextBuffer(SecurityPackage); + + /* Allocate our output buffer */ + nego->output_token = malloc(nego->token_max); + if(!nego->output_token) + return CURLE_OUT_OF_MEMORY; + } + + if(!nego->credentials) { + /* Do we have credientials to use or are we using single sign-on? */ + if(user && *user) { + /* Populate our identity structure */ + result = Curl_create_sspi_identity(user, password, &nego->identity); + if(result) + return result; + + /* Allow proper cleanup of the identity structure */ + nego->p_identity = &nego->identity; + } + else + /* Use the current Windows user */ + nego->p_identity = NULL; + + /* Allocate our credentials handle */ + nego->credentials = malloc(sizeof(CredHandle)); + if(!nego->credentials) + return CURLE_OUT_OF_MEMORY; + + memset(nego->credentials, 0, sizeof(CredHandle)); + + /* Acquire our credentials handle */ + nego->status = + s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *)TEXT(SP_NAME_NEGOTIATE), + SECPKG_CRED_OUTBOUND, NULL, + nego->p_identity, NULL, NULL, + nego->credentials, &expiry); + if(nego->status != SEC_E_OK) + return CURLE_LOGIN_DENIED; + + /* Allocate our new context handle */ + nego->context = malloc(sizeof(CtxtHandle)); + if(!nego->context) + return CURLE_OUT_OF_MEMORY; + + memset(nego->context, 0, sizeof(CtxtHandle)); + } + + if(chlg64 && *chlg64) { + /* Decode the base-64 encoded challenge message */ + if(*chlg64 != '=') { + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; + } + + /* Ensure we have a valid challenge message */ + if(!chlg) { + infof(data, "SPNEGO handshake failure (empty challenge message)\n"); + + return CURLE_BAD_CONTENT_ENCODING; + } + + /* Setup the challenge "input" security buffer */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 1; + chlg_desc.pBuffers = &chlg_buf; + chlg_buf.BufferType = SECBUFFER_TOKEN; + chlg_buf.pvBuffer = chlg; + chlg_buf.cbBuffer = curlx_uztoul(chlglen); + } + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = nego->output_token; + resp_buf.cbBuffer = curlx_uztoul(nego->token_max); + + /* Generate our challenge-response message */ + nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials, + chlg ? nego->context : + NULL, + nego->spn, + ISC_REQ_CONFIDENTIALITY, + 0, SECURITY_NATIVE_DREP, + chlg ? &chlg_desc : NULL, + 0, nego->context, + &resp_desc, &attrs, + &expiry); + + /* Free the decoded challenge as it is not required anymore */ + free(chlg); + + if(GSS_ERROR(nego->status)) { + return CURLE_OUT_OF_MEMORY; + } + + if(nego->status == SEC_I_COMPLETE_NEEDED || + nego->status == SEC_I_COMPLETE_AND_CONTINUE) { + nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc); + if(GSS_ERROR(nego->status)) { + return CURLE_RECV_ERROR; + } + } + + nego->output_token_length = resp_buf.cbBuffer; + + return result; +} + +/* + * Curl_auth_create_spnego_message() + * + * This is used to generate an already encoded SPNEGO (Negotiate) response + * message ready for sending to the recipient. + * + * Parameters: + * + * data [in] - The session handle. + * nego [in/out] - The Negotiate data struct being used and modified. + * outptr [in/out] - The address where a pointer to newly allocated memory + * holding the result will be stored upon completion. + * outlen [out] - The length of the output message. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, + struct negotiatedata *nego, + char **outptr, size_t *outlen) +{ + CURLcode result; + + /* Base64 encode the already generated response */ + result = Curl_base64_encode(data, + (const char*) nego->output_token, + nego->output_token_length, + outptr, outlen); + + if(result) + return result; + + if(!*outptr || !*outlen) + return CURLE_REMOTE_ACCESS_DENIED; + + return CURLE_OK; +} + +/* + * Curl_auth_spnego_cleanup() + * + * This is used to clean up the SPNEGO (Negotiate) specific data. + * + * Parameters: + * + * nego [in/out] - The Negotiate data struct being cleaned up. + * + */ +void Curl_auth_spnego_cleanup(struct negotiatedata* nego) +{ + /* Free our security context */ + if(nego->context) { + s_pSecFn->DeleteSecurityContext(nego->context); + free(nego->context); + nego->context = NULL; + } + + /* Free our credentials handle */ + if(nego->credentials) { + s_pSecFn->FreeCredentialsHandle(nego->credentials); + free(nego->credentials); + nego->credentials = NULL; + } + + /* Free our identity */ + Curl_sspi_free_identity(nego->p_identity); + nego->p_identity = NULL; + + /* Free the SPN and output token */ + Curl_safefree(nego->spn); + Curl_safefree(nego->output_token); + + /* Reset any variables */ + nego->status = 0; + nego->token_max = 0; +} + +#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */ diff --git a/project/jni/curl/lib/vauth/vauth.c b/project/jni/curl/lib/vauth/vauth.c new file mode 100644 index 000000000..702e2d4bc --- /dev/null +++ b/project/jni/curl/lib/vauth/vauth.c @@ -0,0 +1,106 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * 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 + +#include "vauth.h" +#include "curl_multibyte.h" +#include "curl_printf.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +/* + * Curl_auth_build_spn() + * + * This is used to build a SPN string in the following formats: + * + * service/host@realm (Not currently used) + * service/host (Not used by GSS-API) + * service@realm (Not used by Windows SSPI) + * + * Parameters: + * + * service [in] - The service type such as http, smtp, pop or imap. + * host [in] - The host name. + * realm [in] - The realm. + * + * Returns a pointer to the newly allocated SPN. + */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_auth_build_spn(const char *service, const char *host, + const char *realm) +{ + char *spn = NULL; + + /* Generate our SPN */ + if(host && realm) + spn = aprintf("%s/%s@%s", service, host, realm); + else if(host) + spn = aprintf("%s/%s", service, host); + else if(realm) + spn = aprintf("%s@%s", service, realm); + + /* Return our newly allocated SPN */ + return spn; +} +#else +TCHAR *Curl_auth_build_spn(const char *service, const char *host, + const char *realm) +{ + char *utf8_spn = NULL; + TCHAR *tchar_spn = NULL; + + (void) realm; + + /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather + than doing this ourselves but the first is only available in Windows XP + and Windows Server 2003 and the latter is only available in Windows 2000 + but not Windows95/98/ME or Windows NT4.0 unless the Active Directory + Client Extensions are installed. As such it is far simpler for us to + formulate the SPN instead. */ + + /* Generate our UTF8 based SPN */ + utf8_spn = aprintf("%s/%s", service, host); + if(!utf8_spn) { + return NULL; + } + + /* Allocate our TCHAR based SPN */ + tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn); + if(!tchar_spn) { + free(utf8_spn); + + return NULL; + } + + /* Release the UTF8 variant when operating with Unicode */ + Curl_unicodefree(utf8_spn); + + /* Return our newly allocated SPN */ + return tchar_spn; +} +#endif /* USE_WINDOWS_SSPI */ + diff --git a/project/jni/curl/lib/vauth/vauth.h b/project/jni/curl/lib/vauth/vauth.h new file mode 100644 index 000000000..2c5131c70 --- /dev/null +++ b/project/jni/curl/lib/vauth/vauth.h @@ -0,0 +1,189 @@ +#ifndef HEADER_CURL_VAUTH_H +#define HEADER_CURL_VAUTH_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2014 - 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * 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 + +struct SessionHandle; + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +struct digestdata; +#endif + +#if defined(USE_NTLM) +struct ntlmdata; +#endif + +#if defined(USE_KERBEROS5) +struct kerberos5data; +#endif + +#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) +struct negotiatedata; +#endif + +#if defined(USE_WINDOWS_SSPI) +#define GSS_ERROR(status) (status & 0x80000000) +#endif + +/* This is used to build a SPN string */ +#if !defined(USE_WINDOWS_SSPI) +char *Curl_auth_build_spn(const char *service, const char *host, + const char *realm); +#else +TCHAR *Curl_auth_build_spn(const char *service, const char *host, + const char *realm); +#endif + +/* This is used to generate a base64 encoded PLAIN cleartext message */ +CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded LOGIN cleartext message */ +CURLcode Curl_auth_create_login_message(struct SessionHandle *data, + const char *valuep, char **outptr, + size_t *outlen); + +/* This is used to generate a base64 encoded EXTERNAL cleartext message */ +CURLcode Curl_auth_create_external_message(struct SessionHandle *data, + const char *user, char **outptr, + size_t *outlen); + +#if !defined(CURL_DISABLE_CRYPTO_AUTH) +/* This is used to decode a CRAM-MD5 challenge message */ +CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, + size_t *outlen); + +/* This is used to generate a CRAM-MD5 response message */ +CURLcode Curl_auth_create_cram_md5_message(struct SessionHandle *data, + const char *chlg, + const char *userp, + const char *passwdp, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded DIGEST-MD5 response message */ +CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, + const char *chlg64, + const char *userp, + const char *passwdp, + const char *service, + char **outptr, size_t *outlen); + +/* This is used to decode a HTTP DIGEST challenge message */ +CURLcode Curl_auth_decode_digest_http_message(const char *chlg, + struct digestdata *digest); + +/* This is used to generate a HTTP DIGEST response message */ +CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const unsigned char *request, + const unsigned char *uri, + struct digestdata *digest, + char **outptr, size_t *outlen); + +/* This is used to clean up the digest specific data */ +void Curl_auth_digest_cleanup(struct digestdata *digest); +#endif /* !CURL_DISABLE_CRYPTO_AUTH */ + +#if defined(USE_NTLM) +/* This is used to generate a base64 encoded NTLM type-1 message */ +CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is used to decode a base64 encoded NTLM type-2 message */ +CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, + const char *type2msg, + struct ntlmdata *ntlm); + +/* This is used to generate a base64 encoded NTLM type-3 message */ +CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, size_t *outlen); + +/* This is used to clean up the NTLM specific data */ +void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm); +#endif /* USE_NTLM */ + +/* This is used to generate a base64 encoded OAuth 2.0 message */ +CURLcode Curl_auth_create_oauth_bearer_message(struct SessionHandle *data, + const char *user, + const char *host, + const long port, + const char *bearer, + char **outptr, size_t *outlen); +#if defined(USE_KERBEROS5) +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token + message */ +CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + const char *service, + const char *host, + const bool mutual, + const char *chlg64, + struct kerberos5data *krb5, + char **outptr, size_t *outlen); + +/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security + token message */ +CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, + const char *input, + struct kerberos5data *krb5, + char **outptr, + size_t *outlen); + +/* This is used to clean up the GSSAPI specific data */ +void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5); +#endif /* USE_KERBEROS5 */ + +#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) +/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge + message */ +CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, + const char *user, + const char *passwood, + const char *service, + const char *host, + const char *chlg64, + struct negotiatedata *nego); + +/* This is used to generate a base64 encoded SPNEGO (Negotiate) response + message */ +CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, + struct negotiatedata *nego, + char **outptr, size_t *outlen); + +/* This is used to clean up the SPNEGO specifiec data */ +void Curl_auth_spnego_cleanup(struct negotiatedata* nego); + +#endif /* (HAVE_GSSAPI || USE_WINDOWS_SSPI) && USE_SPNEGO */ + +#endif /* HEADER_CURL_VAUTH_H */ diff --git a/project/jni/curl/lib/vtls/axtls.c b/project/jni/curl/lib/vtls/axtls.c index d9c5f9935..0afcfaa58 100644 --- a/project/jni/curl/lib/vtls/axtls.c +++ b/project/jni/curl/lib/vtls/axtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu, . - * Copyright (C) 2010 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -518,7 +518,7 @@ static ssize_t axtls_send(struct connectdata *conn, infof(conn->data, " axtls_send\n"); - if(rc < 0 ) { + if(rc < 0) { *err = map_error_to_curl(rc); rc = -1; /* generic error code for send failure */ } diff --git a/project/jni/curl/lib/vtls/cyassl.c b/project/jni/curl/lib/vtls/cyassl.c index f6b57af68..da737c727 100644 --- a/project/jni/curl/lib/vtls/cyassl.c +++ b/project/jni/curl/lib/vtls/cyassl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,7 +51,6 @@ and that's a problem since options.h hasn't been included yet. */ #include "urldata.h" #include "sendf.h" #include "inet_pton.h" -#include "cyassl.h" #include "vtls.h" #include "parsedate.h" #include "connect.h" /* for the connect timeout */ @@ -69,6 +68,8 @@ and that's a problem since options.h hasn't been included yet. */ #include #include +#include "cyassl.h" + /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" @@ -77,6 +78,38 @@ and that's a problem since options.h hasn't been included yet. */ #define CYASSL_MAX_ERROR_SZ 80 #endif +/* To determine what functions are available we rely on one or both of: + - the user's options.h generated by CyaSSL/wolfSSL + - the symbols detected by curl's configure + Since they are markedly different from one another, and one or the other may + not be available, we do some checking below to bring things in sync. */ + +/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */ +#ifndef HAVE_ALPN +#ifdef HAVE_WOLFSSL_USEALPN +#define HAVE_ALPN +#endif +#endif + +/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in + options.h, but is only seen in >= 3.6.6 since that's when they started + disabling SSLv3 by default. */ +#ifndef WOLFSSL_ALLOW_SSLV3 +#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \ + defined(HAVE_WOLFSSLV3_CLIENT_METHOD) +#define WOLFSSL_ALLOW_SSLV3 +#endif +#endif + +/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC + supported curve extension in options.h. Note ECC is enabled separately. */ +#ifndef HAVE_SUPPORTED_CURVES +#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \ + defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE) +#define HAVE_SUPPORTED_CURVES +#endif +#endif + static Curl_recv cyassl_recv; static Curl_send cyassl_send; @@ -143,9 +176,7 @@ cyassl_connect_step1(struct connectdata *conn, use_sni(TRUE); break; case CURL_SSLVERSION_SSLv3: - /* before WolfSSL SSLv3 was enabled by default, and starting in WolfSSL - we check for its presence since it is built without it by default */ -#if !defined(WOLFSSL_VERSION) || defined(HAVE_WOLFSSLV3_CLIENT_METHOD) +#ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); #else @@ -280,6 +311,16 @@ cyassl_connect_step1(struct connectdata *conn, } #endif +#ifdef HAVE_SUPPORTED_CURVES + /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically: + https://github.com/wolfSSL/wolfssl/issues/366 + The supported curves below are those also supported by OpenSSL 1.0.2 and + in the same order. */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */ + CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */ +#endif + /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { CURLcode result = CURLE_OK; @@ -309,6 +350,33 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } +#ifdef HAVE_ALPN + if(conn->bits.tls_enable_alpn) { + char protocols[128]; + *protocols = '\0'; + + /* wolfSSL's ALPN protocol name list format is a comma separated string of + protocols in descending order of preference, eg: "h2,http/1.1" */ + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ","); + infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1); + infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1); + + if(wolfSSL_UseALPN(conssl->handle, protocols, + (unsigned)strlen(protocols), + WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) { + failf(data, "SSL: failed setting ALPN protocols"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* HAVE_ALPN */ + /* Check if there's a cached ID we can/should use here! */ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { /* we got a session id, use it! */ @@ -413,8 +481,7 @@ cyassl_connect_step2(struct connectdata *conn, } if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { -#if defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ - defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) +#ifdef KEEP_PEER_CERT X509 *x509; const char *x509_der; int x509_der_len; @@ -457,6 +524,41 @@ cyassl_connect_step2(struct connectdata *conn, #endif } +#ifdef HAVE_ALPN + if(conn->bits.tls_enable_alpn) { + int rc; + char *protocol = NULL; + unsigned short protocol_len = 0; + + rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len); + + if(rc == SSL_SUCCESS) { + infof(data, "ALPN, server accepted to use %.*s\n", protocol_len, + protocol); + + if(protocol_len == ALPN_HTTP_1_1_LENGTH && + !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) + conn->negnpn = CURL_HTTP_VERSION_1_1; +#ifdef USE_NGHTTP2 + else if(data->set.httpversion >= CURL_HTTP_VERSION_2 && + protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID, + NGHTTP2_PROTO_VERSION_ID_LEN)) + conn->negnpn = CURL_HTTP_VERSION_2; +#endif + else + infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len, + protocol); + } + else if(rc == SSL_ALPN_NOT_FOUND) + infof(data, "ALPN, server did not agree to a protocol\n"); + else { + failf(data, "ALPN, failure getting protocol, error %d", rc); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* HAVE_ALPN */ + conssl->connecting_state = ssl_connect_3; infof(data, "SSL connected\n"); diff --git a/project/jni/curl/lib/vtls/cyassl.h b/project/jni/curl/lib/vtls/cyassl.h index 52a5e15ae..110612555 100644 --- a/project/jni/curl/lib/vtls/cyassl.h +++ b/project/jni/curl/lib/vtls/cyassl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,6 +25,18 @@ #ifdef USE_CYASSL +/* KEEP_PEER_CERT is a product of the presence of build time symbol + OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is + in wolfSSL's settings.h, and the latter two are build time symbols in + options.h. */ +#ifndef KEEP_PEER_CERT +#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \ + defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \ + (defined(OPENSSL_EXTRA) && !defined(NO_CERTS)) +#define KEEP_PEER_CERT +#endif +#endif + CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex); bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex); int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex); @@ -53,6 +65,11 @@ void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ /* this backend supports CURLOPT_SSL_CTX_* */ #define have_curlssl_ssl_ctx 1 +#ifdef KEEP_PEER_CERT +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 +#endif + /* API setup for CyaSSL */ #define curlssl_init Curl_cyassl_init #define curlssl_cleanup() Curl_nop_stmt diff --git a/project/jni/curl/lib/vtls/darwinssl.c b/project/jni/curl/lib/vtls/darwinssl.c index ed587eb37..71d379b90 100644 --- a/project/jni/curl/lib/vtls/darwinssl.c +++ b/project/jni/curl/lib/vtls/darwinssl.c @@ -781,7 +781,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) int mib[2]; char *os_version; size_t os_version_len; - char *os_version_major, *os_version_minor/*, *os_version_point*/; + char *os_version_major, *os_version_minor; char *tok_buf; /* Get the Darwin kernel version from the kernel using sysctl(): */ @@ -800,7 +800,6 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) /* Parse the version: */ os_version_major = strtok_r(os_version, ".", &tok_buf); os_version_minor = strtok_r(NULL, ".", &tok_buf); - /*os_version_point = strtok_r(NULL, ".", &tok_buf);*/ *major = atoi(os_version_major); *minor = atoi(os_version_minor); free(os_version); @@ -1282,14 +1281,21 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS /* Snow Leopard introduced the SSLSetSessionOption() function, but due to a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag - works, it doesn't work as expected under Snow Leopard or Lion. + works, it doesn't work as expected under Snow Leopard, Lion or + Mountain Lion. So we need to call SSLSetEnableCertVerify() on those older cats in order to disable certificate validation if the user turned that off. (SecureTransport will always validate the certificate chain by - default.) */ - /* (Note: Darwin 12.x.x is Mountain Lion.) */ + default.) + Note: + Darwin 11.x.x is Lion (10.7) + Darwin 12.x.x is Mountain Lion (10.8) + Darwin 13.x.x is Mavericks (10.9) + Darwin 14.x.x is Yosemite (10.10) + Darwin 15.x.x is El Capitan (10.11) + */ #if CURL_BUILD_MAC - if(SSLSetSessionOption != NULL && darwinver_maj >= 12) { + if(SSLSetSessionOption != NULL && darwinver_maj >= 13) { #else if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ diff --git a/project/jni/curl/lib/vtls/gtls.c b/project/jni/curl/lib/vtls/gtls.c index 1fef54b48..1b5a6a4d5 100644 --- a/project/jni/curl/lib/vtls/gtls.c +++ b/project/jni/curl/lib/vtls/gtls.c @@ -641,7 +641,7 @@ gtls_connect_step1(struct connectdata *conn, #endif #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { int cur = 0; gnutls_datum_t protocols[2]; @@ -1240,7 +1240,7 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t compression: %s\n", ptr); #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { rc = gnutls_alpn_get_selected_protocol(session, &proto); if(rc == 0) { infof(data, "ALPN, server accepted to use %.*s\n", proto.size, @@ -1381,7 +1381,7 @@ static ssize_t gtls_send(struct connectdata *conn, { ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len); - if(rc < 0 ) { + if(rc < 0) { *curlcode = (rc == GNUTLS_E_AGAIN) ? CURLE_AGAIN : CURLE_SEND_ERROR; diff --git a/project/jni/curl/lib/vtls/gtls.h b/project/jni/curl/lib/vtls/gtls.h index 965f7cf1f..611a2f47b 100644 --- a/project/jni/curl/lib/vtls/gtls.h +++ b/project/jni/curl/lib/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -64,6 +64,9 @@ bool Curl_gtls_cert_status_request(void); /* this backend supports CURLOPT_CERTINFO */ #define have_curlssl_certinfo 1 +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for GnuTLS */ #define curlssl_init Curl_gtls_init #define curlssl_cleanup Curl_gtls_cleanup diff --git a/project/jni/curl/lib/vtls/mbedtls.c b/project/jni/curl/lib/vtls/mbedtls.c index f0900a5af..6fc7214ac 100644 --- a/project/jni/curl/lib/vtls/mbedtls.c +++ b/project/jni/curl/lib/vtls/mbedtls.c @@ -22,7 +22,7 @@ ***************************************************************************/ /* - * Source file for all mbedTSL-specific code for the TLS/SSL layer. No code + * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code * but vtls.c should ever call or use these functions. * */ @@ -67,7 +67,7 @@ #if defined(THREADING_SUPPORT) static mbedtls_entropy_context entropy; -static int entropy_init_initialized = 0; +static int entropy_init_initialized = 0; /* start of entropy_init_mutex() */ static void entropy_init_mutex(mbedtls_entropy_context *ctx) @@ -101,7 +101,8 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) #undef MBEDTLS_DEBUG #ifdef MBEDTLS_DEBUG -static void mbedtls_debug(void *context, int level, const char *line) +static void mbed_debug(void *context, int level, const char *f_name, + int line_nb, const char *line) { struct SessionHandle *data = NULL; @@ -131,12 +132,12 @@ static void mbedtls_debug(void *context, int level, const char *line) const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = { /* Hashes from SHA-1 and above */ - MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | - MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | - MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | - MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | - MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | - MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) | + MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512), 0xFFFFFFF, /* Any PK alg */ 0xFFFFFFF, /* Any curve */ 1024, /* RSA min key len */ @@ -151,12 +152,12 @@ const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr = #define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) -static Curl_recv mbedtls_recv; -static Curl_send mbedtls_send; +static Curl_recv mbed_recv; +static Curl_send mbed_send; static CURLcode -mbedtls_connect_step1(struct connectdata *conn, - int sockindex) +mbed_connect_step1(struct connectdata *conn, + int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; @@ -169,7 +170,6 @@ mbedtls_connect_step1(struct connectdata *conn, struct in_addr addr; #endif void *old_session = NULL; - size_t old_session_size = 0; char errorbuf[128]; errorbuf[0]=0; @@ -186,8 +186,7 @@ mbedtls_connect_step1(struct connectdata *conn, mbedtls_ctr_drbg_init(&connssl->ctr_drbg); ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex, - &entropy, connssl->ssn.id, - connssl->ssn.id_len); + &entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -200,8 +199,7 @@ mbedtls_connect_step1(struct connectdata *conn, mbedtls_ctr_drbg_init(&connssl->ctr_drbg); ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func, - &connssl->entropy, connssl->ssn.id, - connssl->ssn.id_len); + &connssl->entropy, NULL, 0); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); @@ -322,8 +320,8 @@ mbedtls_connect_step1(struct connectdata *conn, } /* new profile with RSA min key len = 1024 ... */ - mbedtls_ssl_conf_cert_profile( &connssl->config, - &mbedtls_x509_crt_profile_fr); + mbedtls_ssl_conf_cert_profile(&connssl->config, + &mbedtls_x509_crt_profile_fr); switch(data->set.ssl.version) { case CURL_SSLVERSION_DEFAULT: @@ -376,14 +374,15 @@ mbedtls_connect_step1(struct connectdata *conn, mbedtls_ssl_conf_ciphersuites(&connssl->config, mbedtls_ssl_list_ciphersuites()); - if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { - memcpy(&connssl->ssn, old_session, old_session_size); + if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { + ret = mbedtls_ssl_set_session(&connssl->ssl, old_session); + if(ret) { + failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } infof(data, "mbedTLS re-using session\n"); } - mbedtls_ssl_set_session(&connssl->ssl, - &connssl->ssn); - mbedtls_ssl_conf_ca_chain(&connssl->config, &connssl->cacert, &connssl->crl); @@ -392,17 +391,16 @@ mbedtls_connect_step1(struct connectdata *conn, mbedtls_ssl_conf_own_cert(&connssl->config, &connssl->clicert, &connssl->pk); } - if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && -#ifdef ENABLE_IPV6 - !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && -#endif - sni && mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) { - infof(data, "WARNING: failed to configure " - "server name indication (SNI) TLS extension\n"); + if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) { + /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* + the name to set in the SNI extension. So even if curl connects to a + host specified as an IP address, this function must be used. */ + failf(data, "couldn't set hostname in mbedTLS"); + return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { const char **p = &connssl->protocols[0]; #ifdef USE_NGHTTP2 if(data->set.httpversion >= CURL_HTTP_VERSION_2) @@ -423,7 +421,7 @@ mbedtls_connect_step1(struct connectdata *conn, #endif #ifdef MBEDTLS_DEBUG - mbedtls_ssl_conf_dbg(&connssl->ssl, mbedtls_debug, data); + mbedtls_ssl_conf_dbg(&connssl->config, mbedtls_debug, data); #endif connssl->connecting_state = ssl_connect_2; @@ -432,8 +430,8 @@ mbedtls_connect_step1(struct connectdata *conn, } static CURLcode -mbedtls_connect_step2(struct connectdata *conn, - int sockindex) +mbed_connect_step2(struct connectdata *conn, + int sockindex) { int ret; struct SessionHandle *data = conn->data; @@ -447,8 +445,8 @@ mbedtls_connect_step2(struct connectdata *conn, char errorbuf[128]; errorbuf[0] = 0; - conn->recv[sockindex] = mbedtls_recv; - conn->send[sockindex] = mbedtls_send; + conn->recv[sockindex] = mbed_recv; + conn->send[sockindex] = mbed_send; ret = mbedtls_ssl_handshake(&connssl->ssl); @@ -562,7 +560,7 @@ mbedtls_connect_step2(struct connectdata *conn, } #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol) { @@ -593,45 +591,39 @@ mbedtls_connect_step2(struct connectdata *conn, } static CURLcode -mbedtls_connect_step3(struct connectdata *conn, - int sockindex) +mbed_connect_step3(struct connectdata *conn, + int sockindex) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; void *old_ssl_sessionid = NULL; - mbedtls_ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn; - int incache; + mbedtls_ssl_session *our_ssl_sessionid; + int ret; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - /* Save the current session data for possible re-use */ - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } + our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; + + mbedtls_ssl_session_init(our_ssl_sessionid); + + ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid); + if(ret) { + failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; } - if(!incache) { - void *new_session = malloc(sizeof(mbedtls_ssl_session)); - if(new_session) { - memcpy(new_session, our_ssl_sessionid, - sizeof(mbedtls_ssl_session)); + /* If there's already a matching session in the cache, delete it */ + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); - retcode = Curl_ssl_addsessionid(conn, new_session, - sizeof(mbedtls_ssl_session)); - } - else { - retcode = CURLE_OUT_OF_MEMORY; - } - - if(retcode) { - failf(data, "failed to store ssl session"); - return retcode; - } + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); + if(retcode) { + free(our_ssl_sessionid); + failf(data, "failed to store ssl session"); + return retcode; } connssl->connecting_state = ssl_connect_done; @@ -639,11 +631,9 @@ mbedtls_connect_step3(struct connectdata *conn, return CURLE_OK; } -static ssize_t mbedtls_send(struct connectdata *conn, - int sockindex, - const void *mem, - size_t len, - CURLcode *curlcode) +static ssize_t mbed_send(struct connectdata *conn, int sockindex, + const void *mem, size_t len, + CURLcode *curlcode) { int ret = -1; @@ -678,11 +668,9 @@ void Curl_mbedtls_close(struct connectdata *conn, int sockindex) #endif /* THREADING_SUPPORT */ } -static ssize_t mbedtls_recv(struct connectdata *conn, - int num, - char *buf, - size_t buffersize, - CURLcode *curlcode) +static ssize_t mbed_recv(struct connectdata *conn, int num, + char *buf, size_t buffersize, + CURLcode *curlcode) { int ret = -1; ssize_t len = -1; @@ -707,6 +695,7 @@ static ssize_t mbedtls_recv(struct connectdata *conn, void Curl_mbedtls_session_free(void *ptr) { + mbedtls_ssl_session_free(ptr); free(ptr); } @@ -718,10 +707,10 @@ size_t Curl_mbedtls_version(char *buffer, size_t size) } static CURLcode -mbedtls_connect_common(struct connectdata *conn, - int sockindex, - bool nonblocking, - bool *done) +mbed_connect_common(struct connectdata *conn, + int sockindex, + bool nonblocking, + bool *done) { CURLcode retcode; struct SessionHandle *data = conn->data; @@ -745,7 +734,7 @@ mbedtls_connect_common(struct connectdata *conn, failf(data, "SSL connection timeout"); return CURLE_OPERATION_TIMEDOUT; } - retcode = mbedtls_connect_step1(conn, sockindex); + retcode = mbed_connect_step1(conn, sockindex); if(retcode) return retcode; } @@ -799,7 +788,7 @@ mbedtls_connect_common(struct connectdata *conn, * ensuring that a client using select() or epoll() will always * have a valid fdset to wait on. */ - retcode = mbedtls_connect_step2(conn, sockindex); + retcode = mbed_connect_step2(conn, sockindex); if(retcode || (nonblocking && (ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || @@ -809,15 +798,15 @@ mbedtls_connect_common(struct connectdata *conn, } /* repeat step2 until all transactions are done. */ if(ssl_connect_3==connssl->connecting_state) { - retcode = mbedtls_connect_step3(conn, sockindex); + retcode = mbed_connect_step3(conn, sockindex); if(retcode) return retcode; } if(ssl_connect_done==connssl->connecting_state) { connssl->state = ssl_connection_complete; - conn->recv[sockindex] = mbedtls_recv; - conn->send[sockindex] = mbedtls_send; + conn->recv[sockindex] = mbed_recv; + conn->send[sockindex] = mbed_send; *done = TRUE; } else @@ -834,7 +823,7 @@ Curl_mbedtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { - return mbedtls_connect_common(conn, sockindex, TRUE, done); + return mbed_connect_common(conn, sockindex, TRUE, done); } @@ -845,7 +834,7 @@ Curl_mbedtls_connect(struct connectdata *conn, CURLcode retcode; bool done = FALSE; - retcode = mbedtls_connect_common(conn, sockindex, FALSE, &done); + retcode = mbed_connect_common(conn, sockindex, FALSE, &done); if(retcode) return retcode; @@ -858,14 +847,21 @@ Curl_mbedtls_connect(struct connectdata *conn, * return 0 error initializing SSL * return 1 SSL initialized successfully */ -int mbedtls_init(void) +int Curl_mbedtls_init(void) { return Curl_polarsslthreadlock_thread_setup(); } -void mbedtls_cleanup(void) +void Curl_mbedtls_cleanup(void) { (void)Curl_polarsslthreadlock_thread_cleanup(); } +int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) +{ + mbedtls_ssl_context *ssl = + (mbedtls_ssl_context *)&conn->ssl[sockindex].ssl; + return ssl->in_msglen != 0; +} + #endif /* USE_MBEDTLS */ diff --git a/project/jni/curl/lib/vtls/mbedtls.h b/project/jni/curl/lib/vtls/mbedtls.h index fcf483ff3..9117fff1c 100644 --- a/project/jni/curl/lib/vtls/mbedtls.h +++ b/project/jni/curl/lib/vtls/mbedtls.h @@ -26,10 +26,12 @@ #ifdef USE_MBEDTLS -/* Called on first use mbedTLS, setup threading if supported */ -int mbedtls_init(void); -void mbedtls_cleanup(void); +#include +/* Called on first use mbedTLS, setup threading if supported */ +int Curl_mbedtls_init(void); +void Curl_mbedtls_cleanup(void); +int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex); CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex); @@ -48,9 +50,12 @@ void Curl_mbedtls_session_free(void *ptr); size_t Curl_mbedtls_version(char *buffer, size_t size); int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); +/* this backends supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for mbedTLS */ -#define curlssl_init() mbedtls_init() -#define curlssl_cleanup() mbedtls_cleanup() +#define curlssl_init() Curl_mbedtls_init() +#define curlssl_cleanup() Curl_mbedtls_cleanup() #define curlssl_connect Curl_mbedtls_connect #define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking #define curlssl_session_free(x) Curl_mbedtls_session_free(x) @@ -62,7 +67,7 @@ int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); #define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL) #define curlssl_version Curl_mbedtls_version #define curlssl_check_cxn(x) (x=x, -1) -#define curlssl_data_pending(x,y) (x=x, y=y, 0) +#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y) #define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS #define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0) diff --git a/project/jni/curl/lib/vtls/nss.c b/project/jni/curl/lib/vtls/nss.c index 3922d9c90..02c8727e4 100644 --- a/project/jni/curl/lib/vtls/nss.c +++ b/project/jni/curl/lib/vtls/nss.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -696,7 +696,7 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) unsigned int buflen; SSLNextProtoState state; - if(!conn->data->set.ssl_enable_npn && !conn->data->set.ssl_enable_alpn) { + if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) { return; } @@ -1744,14 +1744,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) #endif #ifdef SSL_ENABLE_NPN - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, data->set.ssl_enable_npn - ? PR_TRUE : PR_FALSE) != SECSuccess) + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn + ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif #ifdef SSL_ENABLE_ALPN - if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, data->set.ssl_enable_alpn - ? PR_TRUE : PR_FALSE) != SECSuccess) + if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn + ? PR_TRUE : PR_FALSE) != SECSuccess) goto error; #endif @@ -1768,7 +1768,7 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) #endif #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN) - if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; diff --git a/project/jni/curl/lib/vtls/nssg.h b/project/jni/curl/lib/vtls/nssg.h index 601168c21..e388ec0ff 100644 --- a/project/jni/curl/lib/vtls/nssg.h +++ b/project/jni/curl/lib/vtls/nssg.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -74,6 +74,9 @@ bool Curl_nss_false_start(void); /* this backend supports CURLOPT_CERTINFO */ #define have_curlssl_certinfo 1 +/* this backends supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for NSS */ #define curlssl_init Curl_nss_init #define curlssl_cleanup Curl_nss_cleanup diff --git a/project/jni/curl/lib/vtls/openssl.c b/project/jni/curl/lib/vtls/openssl.c index cbf2d2123..fea0dfe4f 100644 --- a/project/jni/curl/lib/vtls/openssl.c +++ b/project/jni/curl/lib/vtls/openssl.c @@ -95,7 +95,8 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 -#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) +#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \ + !defined(LIBRESSL_VERSION_NUMBER) /* OpenSSL 1.1.0-pre4 removed the argument! */ #define HAVE_ERR_REMOVE_THREAD_STATE_NOARG 1 #endif @@ -113,6 +114,7 @@ #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ +#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ @@ -748,7 +750,7 @@ void Curl_ossl_cleanup(void) } /* - * This function uses SSL_peek to determine connection status. + * This function is used to determine connection status. * * Return codes: * 1 means the connection is still in place @@ -757,16 +759,45 @@ void Curl_ossl_cleanup(void) */ int Curl_ossl_check_cxn(struct connectdata *conn) { - int rc; + /* SSL_peek takes data out of the raw recv buffer without peeking so we use + recv MSG_PEEK instead. Bug #795 */ +#ifdef MSG_PEEK char buf; - - rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1); - if(rc > 0) - return 1; /* connection still in place */ - - if(rc == 0) + ssize_t nread; + nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, + (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK); + if(nread == 0) return 0; /* connection has been closed */ - + else if(nread == 1) + return 1; /* connection still in place */ + else if(nread == -1) { + int err = SOCKERRNO; + if(err == EINPROGRESS || +#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) + err == EAGAIN || +#endif + err == EWOULDBLOCK) + return 1; /* connection still in place */ + if(err == ECONNRESET || +#ifdef ECONNABORTED + err == ECONNABORTED || +#endif +#ifdef ENETDOWN + err == ENETDOWN || +#endif +#ifdef ENETRESET + err == ENETRESET || +#endif +#ifdef ESHUTDOWN + err == ESHUTDOWN || +#endif +#ifdef ETIMEDOUT + err == ETIMEDOUT || +#endif + err == ENOTCONN) + return 0; /* connection has been closed */ + } +#endif return -1; /* connection status unknown */ } @@ -1837,12 +1868,12 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) SSL_CTX_set_options(connssl->ctx, ctx_options); #ifdef HAS_NPN - if(data->set.ssl_enable_npn) + if(conn->bits.tls_enable_npn) SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn); #endif #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { int cur = 0; unsigned char protocols[128]; @@ -2163,7 +2194,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) /* Sets data and len to negotiated protocol, len is 0 if no protocol was * negotiated */ - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { const unsigned char* neg_protocol; unsigned int len; SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len); @@ -2226,16 +2257,23 @@ static void pubkey_show(struct SessionHandle *data, snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name); - BN_print(mem, bn); + 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_FALSE +#endif static int X509V3_ext(struct SessionHandle *data, int certnum, @@ -2321,7 +2359,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY *pubkey=NULL; int j; char *ptr; - ASN1_BIT_STRING *psig; + ASN1_BIT_STRING *psig = NULL; X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Subject", i); @@ -2341,16 +2379,18 @@ static CURLcode get_cert_chain(struct connectdata *conn, #if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) { - X509_ALGOR *palg; + X509_ALGOR *palg = NULL; ASN1_STRING *a = ASN1_STRING_new(); if(a) { X509_get0_signature(&psig, &palg, x); X509_signature_print(mem, palg, a); ASN1_STRING_free(a); - } - i2a_ASN1_OBJECT(mem, palg->algorithm); - push_certinfo("Public Key Algorithm", i); + if(palg) { + i2a_ASN1_OBJECT(mem, palg->algorithm); + push_certinfo("Public Key Algorithm", i); + } + } X509V3_ext(data, i, X509_get0_extensions(x)); } #else @@ -2395,9 +2435,35 @@ static CURLcode get_cert_chain(struct connectdata *conn, #else rsa = pubkey->pkey.rsa; #endif + +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + + RSA_get0_key(rsa, &n, &e, &d); + RSA_get0_factors(rsa, &p, &q); + RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp); + BN_print(mem, n); + push_certinfo("RSA Public Key", i); + print_pubkey_BN(rsa, n, i); + print_pubkey_BN(rsa, e, i); + print_pubkey_BN(rsa, d, i); + print_pubkey_BN(rsa, p, i); + print_pubkey_BN(rsa, q, i); + print_pubkey_BN(rsa, dmp1, i); + print_pubkey_BN(rsa, dmq1, i); + print_pubkey_BN(rsa, iqmp, i); + } +#else BIO_printf(mem, "%d", BN_num_bits(rsa->n)); push_certinfo("RSA Public Key", i); - print_pubkey_BN(rsa, n, i); print_pubkey_BN(rsa, e, i); print_pubkey_BN(rsa, d, i); @@ -2406,6 +2472,8 @@ static CURLcode get_cert_chain(struct connectdata *conn, print_pubkey_BN(rsa, dmp1, i); print_pubkey_BN(rsa, dmq1, i); print_pubkey_BN(rsa, iqmp, i); +#endif + break; } case EVP_PKEY_DSA: @@ -2416,11 +2484,30 @@ static CURLcode get_cert_chain(struct connectdata *conn, #else dsa = pubkey->pkey.dsa; #endif +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + BIGNUM *p; + BIGNUM *q; + BIGNUM *g; + BIGNUM *priv_key; + BIGNUM *pub_key; + + DSA_get0_pqg(dsa, &p, &q, &g); + DSA_get0_key(dsa, &pub_key, &priv_key); + + print_pubkey_BN(dsa, p, i); + print_pubkey_BN(dsa, q, i); + print_pubkey_BN(dsa, g, i); + print_pubkey_BN(dsa, priv_key, i); + print_pubkey_BN(dsa, pub_key, i); + } +#else print_pubkey_BN(dsa, p, i); print_pubkey_BN(dsa, q, i); print_pubkey_BN(dsa, g, i); print_pubkey_BN(dsa, priv_key, i); print_pubkey_BN(dsa, pub_key, i); +#endif break; } case EVP_PKEY_DH: @@ -2431,10 +2518,27 @@ static CURLcode get_cert_chain(struct connectdata *conn, #else dh = pubkey->pkey.dh; #endif +#ifdef HAVE_OPAQUE_RSA_DSA_DH + { + BIGNUM *p; + BIGNUM *q; + BIGNUM *g; + BIGNUM *priv_key; + BIGNUM *pub_key; + DH_get0_pqg(dh, &p, &q, &g); + DH_get0_key(dh, &pub_key, &priv_key); + print_pubkey_BN(dh, p, i); + print_pubkey_BN(dh, q, i); + print_pubkey_BN(dh, g, i); + print_pubkey_BN(dh, priv_key, i); + print_pubkey_BN(dh, pub_key, i); + } +#else print_pubkey_BN(dh, p, i); print_pubkey_BN(dh, g, i); print_pubkey_BN(dh, priv_key, i); print_pubkey_BN(dh, pub_key, i); +#endif break; } #if 0 @@ -2446,9 +2550,11 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY_free(pubkey); } - for(j = 0; j < psig->length; j++) - BIO_printf(mem, "%02x:", psig->data[j]); - push_certinfo("Signature", i); + 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); diff --git a/project/jni/curl/lib/vtls/openssl.h b/project/jni/curl/lib/vtls/openssl.h index c8e32af0b..74f128ed1 100644 --- a/project/jni/curl/lib/vtls/openssl.h +++ b/project/jni/curl/lib/vtls/openssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -88,9 +88,12 @@ bool Curl_ossl_cert_status_request(void); /* this backend supports CURLOPT_CERTINFO */ #define have_curlssl_certinfo 1 -/* this backend suppots CURLOPT_SSL_CTX_* */ +/* this backend supports CURLOPT_SSL_CTX_* */ #define have_curlssl_ssl_ctx 1 +/* this backend supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for OpenSSL */ #define curlssl_init Curl_ossl_init #define curlssl_cleanup Curl_ossl_cleanup diff --git a/project/jni/curl/lib/vtls/polarssl.c b/project/jni/curl/lib/vtls/polarssl.c index fcce60f05..0e8b0f500 100644 --- a/project/jni/curl/lib/vtls/polarssl.c +++ b/project/jni/curl/lib/vtls/polarssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * Copyright (C) 2010 - 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -36,6 +36,7 @@ #include #include #include +#include #if POLARSSL_VERSION_NUMBER < 0x01030000 #error too old PolarSSL @@ -60,6 +61,15 @@ /* The last #include file should be: */ #include "memdebug.h" +/* See https://tls.mbed.org/discussions/generic/ + howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der +*/ +#define RSA_PUB_DER_MAX_BYTES (38 + 2 * POLARSSL_MPI_MAX_SIZE) +#define ECP_PUB_DER_MAX_BYTES (30 + 2 * POLARSSL_ECP_MAX_BYTES) + +#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES) + /* apply threading? */ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #define THREADING_SUPPORT @@ -141,7 +151,6 @@ polarssl_connect_step1(struct connectdata *conn, struct in_addr addr; #endif void *old_session = NULL; - size_t old_session_size = 0; char errorbuf[128]; errorbuf[0]=0; @@ -157,7 +166,7 @@ polarssl_connect_step1(struct connectdata *conn, entropy_init_mutex(&entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, - connssl->ssn.id, connssl->ssn.length)) != 0) { + NULL, 0)) != 0) { #ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* POLARSSL_ERROR_C */ @@ -168,7 +177,7 @@ polarssl_connect_step1(struct connectdata *conn, entropy_init(&connssl->entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, - connssl->ssn.id, connssl->ssn.length)) != 0) { + NULL, 0)) != 0) { #ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* POLARSSL_ERROR_C */ @@ -328,14 +337,15 @@ polarssl_connect_step1(struct connectdata *conn, net_send, &conn->sock[sockindex]); ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); - if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { - memcpy(&connssl->ssn, old_session, old_session_size); + if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { + ret = ssl_set_session(&connssl->ssl, old_session); + if(ret) { + failf(data, "ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } infof(data, "PolarSSL re-using session\n"); } - ssl_set_session(&connssl->ssl, - &connssl->ssn); - ssl_set_ca_chain(&connssl->ssl, &connssl->cacert, &connssl->crl, @@ -344,17 +354,16 @@ polarssl_connect_step1(struct connectdata *conn, ssl_set_own_cert_rsa(&connssl->ssl, &connssl->clicert, &connssl->rsa); - if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) && -#ifdef ENABLE_IPV6 - !Curl_inet_pton(AF_INET6, conn->host.name, &addr) && -#endif - sni && ssl_set_hostname(&connssl->ssl, conn->host.name)) { - infof(data, "WARNING: failed to configure " - "server name indication (SNI) TLS extension\n"); + if(ssl_set_hostname(&connssl->ssl, conn->host.name)) { + /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name + to set in the SNI extension. So even if curl connects to a host + specified as an IP address, this function must be used. */ + failf(data, "couldn't set hostname in PolarSSL"); + return CURLE_SSL_CONNECT_ERROR; } #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { static const char* protocols[3]; int cur = 0; @@ -453,8 +462,63 @@ polarssl_connect_step2(struct connectdata *conn, infof(data, "Dumping cert info:\n%s\n", buffer); } + /* adapted from mbedtls.c */ + if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + int size; + CURLcode result; + x509_crt *p; + unsigned char pubkey[PUB_DER_MAX_BYTES]; + const x509_crt *peercert; + + peercert = ssl_get_peer_cert(&connssl->ssl); + + if(!peercert || !peercert->raw.p || !peercert->raw.len) { + failf(data, "Failed due to missing peer certificate"); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + p = calloc(1, sizeof(*p)); + + if(!p) + return CURLE_OUT_OF_MEMORY; + + x509_crt_init(p); + + /* Make a copy of our const peercert because pk_write_pubkey_der + needs a non-const key, for now. + https://github.com/ARMmbed/mbedtls/issues/396 */ + if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { + failf(data, "Failed copying peer certificate"); + x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); + + if(size <= 0) { + failf(data, "Failed copying public key from peer certificate"); + x509_crt_free(p); + free(p); + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; + } + + /* pk_write_pubkey_der writes data at the end of the buffer. */ + result = Curl_pin_peer_pubkey(data, + data->set.str[STRING_SSL_PINNEDPUBLICKEY], + &pubkey[PUB_DER_MAX_BYTES - size], size); + if(result) { + x509_crt_free(p); + free(p); + return result; + } + + x509_crt_free(p); + free(p); + } + #ifdef HAS_ALPN - if(data->set.ssl_enable_alpn) { + if(conn->bits.tls_enable_alpn) { const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl); if(next_protocol != NULL) { @@ -486,40 +550,36 @@ static CURLcode polarssl_connect_step3(struct connectdata *conn, int sockindex) { - CURLcode result = CURLE_OK; + CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct SessionHandle *data = conn->data; void *old_ssl_sessionid = NULL; - ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn; - bool incache; + ssl_session *our_ssl_sessionid; + int ret; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - /* Save the current session data for possible re-use */ - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } + our_ssl_sessionid = malloc(sizeof(ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; + + ssl_session_init(our_ssl_sessionid); + + ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid); + if(ret) { + failf(data, "ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; } - if(!incache) { - void *new_session = malloc(sizeof(ssl_session)); + /* If there's already a matching session in the cache, delete it */ + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); - if(new_session) { - memcpy(new_session, our_ssl_sessionid, sizeof(ssl_session)); - - result = Curl_ssl_addsessionid(conn, new_session, sizeof(ssl_session)); - } - else - result = CURLE_OUT_OF_MEMORY; - - if(result) { - failf(data, "failed to store ssl session"); - return result; - } + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); + if(retcode) { + free(our_ssl_sessionid); + failf(data, "failed to store ssl session"); + return retcode; } connssl->connecting_state = ssl_connect_done; @@ -584,6 +644,7 @@ static ssize_t polarssl_recv(struct connectdata *conn, void Curl_polarssl_session_free(void *ptr) { + ssl_session_free(ptr); free(ptr); } diff --git a/project/jni/curl/lib/vtls/polarssl.h b/project/jni/curl/lib/vtls/polarssl.h index 1ab5a841f..7098b24a4 100644 --- a/project/jni/curl/lib/vtls/polarssl.h +++ b/project/jni/curl/lib/vtls/polarssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * Copyright (C) 2010, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -26,6 +26,8 @@ #ifdef USE_POLARSSL +#include + /* Called on first use PolarSSL, setup threading if supported */ int Curl_polarssl_init(void); void Curl_polarssl_cleanup(void); @@ -50,6 +52,9 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); /* this backend supports the CAPATH option */ #define have_curlssl_ca_path 1 +/* this backends supports CURLOPT_PINNEDPUBLICKEY */ +#define have_curlssl_pinnedpubkey 1 + /* API setup for PolarSSL */ #define curlssl_init() Curl_polarssl_init() #define curlssl_cleanup() Curl_polarssl_cleanup() @@ -65,6 +70,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); #define curlssl_version Curl_polarssl_version #define curlssl_check_cxn(x) ((void)x, -1) #define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0) /* This might cause libcurl to use a weeker random! TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that diff --git a/project/jni/curl/lib/vtls/schannel.c b/project/jni/curl/lib/vtls/schannel.c index 7f7bd357d..a2fba7352 100644 --- a/project/jni/curl/lib/vtls/schannel.c +++ b/project/jni/curl/lib/vtls/schannel.c @@ -5,9 +5,9 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2012 - 2015, Marc Hoersken, + * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -61,6 +61,12 @@ /* The last #include file should be: */ #include "memdebug.h" +/* ALPN requires version 8.1 of the Windows SDK, which was + shipped with Visual Studio 2013, aka _MSC_VER 1800*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1800) +# define HAS_ALPN 1 +#endif + /* Uncomment to force verbose output * #define infof(x, y, ...) printf(y, __VA_ARGS__) * #define failf(x, y, ...) printf(y, __VA_ARGS__) @@ -97,6 +103,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf; SecBufferDesc outbuf_desc; + SecBuffer inbuf; + SecBufferDesc inbuf_desc; +#ifdef HAS_ALPN + unsigned char alpn_buffer[128]; +#endif SCHANNEL_CRED schannel_cred; SECURITY_STATUS sspi_status = SEC_E_OK; struct curl_schannel_cred *old_cred = NULL; @@ -219,6 +230,60 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); } +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + int cur = 0; + int list_start_index = 0; + unsigned int* extension_len = NULL; + unsigned short* list_len = NULL; + + /* The first four bytes will be an unsigned int indicating number + of bytes of data in the rest of the the buffer. */ + extension_len = (unsigned int*)(&alpn_buffer[cur]); + cur += sizeof(unsigned int); + + /* The next four bytes are an indicator that this buffer will contain + ALPN data, as opposed to NPN, for example. */ + *(unsigned int*)&alpn_buffer[cur] = + SecApplicationProtocolNegotiationExt_ALPN; + cur += sizeof(unsigned int); + + /* The next two bytes will be an unsigned short indicating the number + of bytes used to list the preferred protocols. */ + list_len = (unsigned short*)(&alpn_buffer[cur]); + cur += sizeof(unsigned short); + + list_start_index = cur; + +#ifdef USE_NGHTTP2 + if(data->set.httpversion >= CURL_HTTP_VERSION_2) { + memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN); + cur += NGHTTP2_PROTO_ALPN_LEN; + infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID); + } +#endif + + alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH; + memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH); + cur += ALPN_HTTP_1_1_LENGTH; + infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1); + + *list_len = curlx_uitous(cur - list_start_index); + *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); + + InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + } + else + { + InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); + } +#else /* HAS_ALPN */ + InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0); + InitSecBufferDesc(&inbuf_desc, &inbuf, 1); +#endif + /* setup output buffer */ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0); InitSecBufferDesc(&outbuf_desc, &outbuf, 1); @@ -245,7 +310,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) sspi_status = s_pSecFn->InitializeSecurityContext( &connssl->cred->cred_handle, NULL, host_name, - connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle, + connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -535,6 +600,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; struct curl_schannel_cred *old_cred = NULL; +#ifdef HAS_ALPN + SECURITY_STATUS sspi_status = SEC_E_OK; + SecPkgContext_ApplicationProtocol alpn_result; +#endif bool incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); @@ -560,6 +629,41 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; } +#ifdef HAS_ALPN + if(conn->bits.tls_enable_alpn) { + sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); + + if(sspi_status != SEC_E_OK) { + failf(data, "schannel: failed to retrieve ALPN result"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(alpn_result.ProtoNegoStatus == + SecApplicationProtocolNegotiationStatus_Success) { + + infof(data, "schannel: ALPN, server accepted to use %.*s\n", + alpn_result.ProtocolIdSize, alpn_result.ProtocolId); + +#ifdef USE_NGHTTP2 + if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN && + !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId, + NGHTTP2_PROTO_VERSION_ID_LEN)) { + conn->negnpn = 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; + } + } + else + infof(data, "ALPN, server did not agree to a protocol\n"); + } +#endif + /* increment the reference counter of the credential/session handle */ if(connssl->cred && connssl->ctxt) { connssl->cred->refcount++; @@ -1222,7 +1326,7 @@ bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex) if(connssl->use) /* SSL/TLS is in use */ return (connssl->encdata_offset > 0 || - connssl->decdata_offset > 0 ) ? TRUE : FALSE; + connssl->decdata_offset > 0) ? TRUE : FALSE; else return FALSE; } diff --git a/project/jni/curl/lib/vtls/vtls.c b/project/jni/curl/lib/vtls/vtls.c index 36465a7f6..ca505a71c 100644 --- a/project/jni/curl/lib/vtls/vtls.c +++ b/project/jni/curl/lib/vtls/vtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -363,6 +363,12 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, /* not session ID means blank entry */ continue; if(Curl_raw_equal(conn->host.name, check->name) && + ((!conn->bits.conn_to_host && !check->conn_to_host) || + (conn->bits.conn_to_host && check->conn_to_host && + Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) && + ((!conn->bits.conn_to_port && check->conn_to_port == -1) || + (conn->bits.conn_to_port && check->conn_to_port != -1 && + conn->conn_to_port == check->conn_to_port)) && (conn->remote_port == check->remote_port) && Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ @@ -400,6 +406,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) Curl_free_ssl_config(&session->ssl_config); Curl_safefree(session->name); + Curl_safefree(session->conn_to_host); } } @@ -442,6 +449,8 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, struct curl_ssl_session *store = &data->state.session[0]; long oldest_age=data->state.session[0].age; /* zero if unused */ char *clone_host; + char *clone_conn_to_host; + int conn_to_port; long *general_age; /* Even though session ID re-use might be disabled, that only disables USING @@ -452,6 +461,21 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ + if(conn->bits.conn_to_host) { + clone_conn_to_host = strdup(conn->conn_to_host.name); + if(!clone_conn_to_host) { + free(clone_host); + return CURLE_OUT_OF_MEMORY; /* bail out */ + } + } + else + clone_conn_to_host = NULL; + + if(conn->bits.conn_to_port) + conn_to_port = conn->conn_to_port; + else + conn_to_port = -1; + /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ @@ -484,10 +508,12 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->age = *general_age; /* set current age */ /* free it if there's one already present */ free(store->name); + free(store->conn_to_host); store->name = clone_host; /* clone host name */ + store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ + store->conn_to_port = conn_to_port; /* connect to port number */ store->remote_port = conn->remote_port; /* port number */ - /* Unlock */ if(SSLSESSION_SHARED(data)) Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); @@ -495,6 +521,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); + free(clone_conn_to_host); return CURLE_OUT_OF_MEMORY; } @@ -788,9 +815,9 @@ CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, if(!pubkey || !pubkeylen) return result; -#ifdef curlssl_sha256sum /* only do this if pinnedpubkey starts with "sha256//", length 8 */ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) { +#ifdef curlssl_sha256sum /* compute sha256sum of public key */ sha256sumdigest = malloc(SHA256_DIGEST_LENGTH); if(!sha256sumdigest) @@ -843,11 +870,12 @@ CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, } while(end_pos && begin_pos); Curl_safefree(encoded); Curl_safefree(pinkeycopy); +#else + /* without sha256 support, this cannot match */ + (void)data; +#endif return result; } -#else - (void)data; -#endif fp = fopen(pinnedpubkey, "rb"); if(!fp) diff --git a/project/jni/curl/lib/vtls/vtls.h b/project/jni/curl/lib/vtls/vtls.h index b6c66bfa3..31ba9fc50 100644 --- a/project/jni/curl/lib/vtls/vtls.h +++ b/project/jni/curl/lib/vtls/vtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -99,7 +99,7 @@ CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum, /* extract a session ID */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */; + size_t *idsize); /* set 0 if unknown */ /* add a new session ID */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, diff --git a/project/jni/curl/lib/warnless.c b/project/jni/curl/lib/warnless.c index ed06c99a7..0c4472e4a 100644 --- a/project/jni/curl/lib/warnless.c +++ b/project/jni/curl/lib/warnless.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -378,6 +378,63 @@ int curlx_sztosi(ssize_t sznum) #endif } +/* +** unsigned int to unsigned short +*/ + +unsigned short curlx_uitous(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT); + return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned int to unsigned char +*/ + +unsigned char curlx_uitouc(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_UCHAR); + return (unsigned char) (uinum & (unsigned int) CURL_MASK_UCHAR); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + +/* +** unsigned int to signed int +*/ + +int curlx_uitosi(unsigned int uinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_SINT); + return (int) (uinum & (unsigned int) CURL_MASK_SINT); + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + /* ** signed int to unsigned size_t */ diff --git a/project/jni/curl/lib/warnless.h b/project/jni/curl/lib/warnless.h index 499d0a0ab..ab6d29998 100644 --- a/project/jni/curl/lib/warnless.h +++ b/project/jni/curl/lib/warnless.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -52,6 +52,12 @@ size_t curlx_sotouz(curl_off_t sonum); int curlx_sztosi(ssize_t sznum); +unsigned short curlx_uitous(unsigned int uinum); + +unsigned char curlx_uitouc(unsigned int uinum); + +int curlx_uitosi(unsigned int uinum); + size_t curlx_sitouz(int sinum); #ifdef USE_WINSOCK diff --git a/project/jni/curl/lib/wildcard.c b/project/jni/curl/lib/wildcard.c index 216307304..dbbe45f6f 100644 --- a/project/jni/curl/lib/wildcard.c +++ b/project/jni/curl/lib/wildcard.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,9 +25,9 @@ #include "wildcard.h" #include "llist.h" #include "fileinfo.h" +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" CURLcode Curl_wildcard_init(struct WildcardData *wc) diff --git a/project/jni/curl/lib/x509asn1.c b/project/jni/curl/lib/x509asn1.c index dbe57c7b7..c221ba075 100644 --- a/project/jni/curl/lib/x509asn1.c +++ b/project/jni/curl/lib/x509asn1.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,9 +34,10 @@ #include "inet_pton.h" #include "curl_base64.h" #include "x509asn1.h" + +/* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h"