curl: switched back to OpenSSL, updated to latest version

This commit is contained in:
Sergii Pylypenko
2016-05-24 19:04:52 +03:00
parent 4df7e9dae9
commit b3a5e10cfa
126 changed files with 6706 additions and 4626 deletions

View File

@@ -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

View File

@@ -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 <curl/curl.h>
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.

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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. */

View File

@@ -8,11 +8,11 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at 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 <stdint.h>
#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 <inttypes.h>
#endif
@@ -152,6 +152,13 @@
# include <sys/socket.h>
#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 <sys/poll.h>
#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 */

View File

@@ -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) \

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -24,8 +24,7 @@
#include <stdarg.h>
#include <stdio.h> /* 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

View File

@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
# Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
@@ -20,6 +20,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)

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -35,7 +35,7 @@ extern int errno, h_errno;
#include <stabs.h>
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()

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 {

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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"
/***********************************************************************

View File

@@ -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;

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
* Copyright (C) 2012, 2016, Linus Nielsen Feltzing, <linus@haxx.se>
* Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, 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

View File

@@ -56,7 +56,6 @@
#include <inet.h>
#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;
}

View File

@@ -88,7 +88,6 @@ Example set of cookies:
# include <libpsl.h>
#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"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -50,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"
/*

View File

@@ -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 <crypto.h> header file. */
/* #undef HAVE_CRYPTO_H */
/* Define to 1 if you have the <des.h> 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 <cyassl/error-ssl.h> 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 <cyassl/options.h> header file. */
/* #undef HAVE_CYASSL_OPTIONS_H */
/* Define to 1 if you have the <dlfcn.h> 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 <gssapi/gssapi_generic.h> header file. */
@@ -310,6 +326,9 @@
/* Define to 1 if you have the <ifaddrs.h> 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 <krb.h> 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 <krb.h> 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 <libgen.h> 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 <librtmp/rtmp.h> 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 <libssh2.h> 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 <net/if.h> header file. */
#define HAVE_NET_IF_H 1
/* Define to 1 if you have the <nghttp2/nghttp2.h> 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 <openssl/ssl.h> 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 <rsa.h> header file. */
/* #undef HAVE_RSA_H */
@@ -611,8 +615,8 @@
/* Define to 1 if you have the <socket.h> 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 <string.h> 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 */

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,6 +22,8 @@
#include "curl_setup.h"
#include <curl/curl.h>
#include "curl_fnmatch.h"
#include "curl_memory.h"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 */

View File

@@ -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

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -83,7 +83,20 @@
#ifndef CURLX_NO_MEMORY_CALLBACKS
#include <curl/curl.h> /* 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;

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -21,6 +21,9 @@
***************************************************************************/
#include "curl_setup.h"
#include <curl/curl.h>
#include "curl_memrchr.h"
#include "curl_memory.h"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -28,7 +28,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"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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"

File diff suppressed because it is too large Load Diff

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 */

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,6 +22,8 @@
#include "curl_setup.h"
#include <curl/curl.h>
#if defined(USE_THREADS_POSIX)
# ifdef HAVE_PTHREAD_H
# include <pthread.h>

View File

@@ -22,9 +22,11 @@
#include "curl_setup.h"
#include "dotdot.h"
#include <curl/curl.h>
#include "dotdot.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"

View File

@@ -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);

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -31,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 {

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 **,

View File

@@ -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) {

View File

@@ -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)

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,9 +22,12 @@
#include "curl_setup.h"
#include <curl/curl.h>
#include "hash.h"
#include "llist.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,8 +26,11 @@
#ifndef CURL_DISABLE_CRYPTO_AUTH
#include <curl/curl.h>
#include "curl_hmac.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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] == '-') {

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -48,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"
/***********************************************************************

View File

@@ -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"
/***********************************************************************

View File

@@ -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!

View File

@@ -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;

View File

@@ -23,7 +23,6 @@
#include "curl_setup.h"
#ifdef USE_NGHTTP2
#include "curl_printf.h"
#include <nghttp2/nghttp2.h>
#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;
}

View File

@@ -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);

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -80,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)

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,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

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 */

View File

@@ -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 */

View File

@@ -1,302 +0,0 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 */

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -28,7 +28,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);

View File

@@ -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);

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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"
/* ------------------------------------------------------------------ */

View File

@@ -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;

View File

@@ -32,9 +32,8 @@
#include <arpa/inet.h>
#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) {

View File

@@ -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;

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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);
}

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,6 +22,8 @@
#include "curl_setup.h"
#include <curl/curl.h>
#include "llist.h"
#include "curl_memory.h"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -24,6 +24,8 @@
#ifndef CURL_DISABLE_CRYPTO_AUTH
#include <curl/curl.h>
#include "curl_md5.h"
#include "curl_hmac.h"
#include "warnless.h"

View File

@@ -26,10 +26,12 @@
#include <curl/curl.h>
#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"

View File

@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -28,10 +28,6 @@
* as well as the library. Do not mix with library internals!
*/
#include "curl_setup.h"
#include <curl/curl.h>
#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 */

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1999 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1999 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -36,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 <curl/mprintf.h>
#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; i<max_param; i++) {
if((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) {
/* Width/precision arguments must be read before the main argument
* they are attached to
*/
vto[i + 1].data.num.as_signed = (mp_intmax_t)va_arg(arglist, int);
/* Width/precision arguments must be read before the main argument
they are attached to */
if(vto[i].flags & FLAGS_WIDTHPARAM) {
vto[vto[i].width].data.num.as_signed =
(mp_intmax_t)va_arg(arglist, int);
}
if(vto[i].flags & FLAGS_PRECPARAM) {
vto[vto[i].precision].data.num.as_signed =
(mp_intmax_t)va_arg(arglist, int);
}
switch (vto[i].type) {
@@ -580,6 +581,11 @@ static int dprintf_formatf(
va_stack_t *p;
/* 'workend' points to the final buffer byte position, but with an extra
byte as margin to avoid the (false?) warning Coverity gives us
otherwise */
char *workend = &work[sizeof(work) - 2];
/* Do the actual %-code parsing */
dprintf_Pass1(format, vto, endpos, ap_save);
@@ -609,6 +615,8 @@ static int dprintf_formatf(
/* Used to convert negative in positive. */
mp_intmax_t signed_num;
char *w;
if(*f != '%') {
/* This isn't a format spec, so write everything out until the next one
OR end of string is reached. */
@@ -645,16 +653,30 @@ static int dprintf_formatf(
p = &vto[param];
/* pick up the specified width */
if(p->flags & 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('"');

View File

@@ -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)

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -32,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"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 <nwthread.h>
int main ( void )
int main (void)
{
/* initialize any globals here... */

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,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 <arpa/inet.h>
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;
}

View File

@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
* Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -34,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 */
}

View File

@@ -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) {

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -36,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"

View File

@@ -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) {

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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<<type);
switch( type ) {
switch(type) {
case CURL_LOCK_DATA_DNS:
break;
case CURL_LOCK_DATA_COOKIE:
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
if(!share->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<<type);
switch( type ) {
switch(type) {
case CURL_LOCK_DATA_DNS:
break;

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -22,6 +22,8 @@
#include "curl_setup.h"
#include <curl/curl.h>
#include "slist.h"
/* The last #include files should be: */

View File

@@ -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);
}

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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];

View File

@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
* Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -32,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
* +----+------+-----+----------------+

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
*
* 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
* +----+------+-----+----------------+

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1997 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1997 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -55,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);

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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);
}

View File

@@ -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,

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -19,7 +19,11 @@
* KIND, either express or implied.
*
***************************************************************************/
#include "curl_setup.h"
#include <curl/curl.h>
#include "strdup.h"
#include "curl_memory.h"

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2004 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2004 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -51,7 +51,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;

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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;
}

View File

@@ -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. */

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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);

View File

@@ -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 */

View File

@@ -0,0 +1,157 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 <draft-murchison-sasl-login-00.txt>
*
***************************************************************************/
#include "curl_setup.h"
#include <curl/curl.h>
#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);
}

View File

@@ -0,0 +1,138 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 <curl/curl.h>
#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 */

View File

@@ -0,0 +1,883 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 <curl/curl.h>
#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 */

View File

@@ -0,0 +1,43 @@
#ifndef HEADER_CURL_DIGEST_H
#define HEADER_CURL_DIGEST_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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/curl.h>
#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 */

View File

@@ -0,0 +1,527 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
* Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 <curl/curl.h>
#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 */

View File

@@ -29,6 +29,7 @@
#include <curl/curl.h>
#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;

View File

@@ -0,0 +1,496 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* 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 <curl/curl.h>
#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*/

View File

@@ -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 */

View File

@@ -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, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -140,4 +140,4 @@
#endif /* USE_NTLM */
#endif /* HEADER_CURL_NTLM_MSGS_H */
#endif /* HEADER_CURL_NTLM_H */

View File

@@ -0,0 +1,314 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at https://curl.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 <curl/curl.h>
#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 */

Some files were not shown because too many files have changed in this diff Show More