diff options
Diffstat (limited to 'lib')
142 files changed, 5372 insertions, 3571 deletions
diff --git a/lib/Makefile.Watcom b/lib/Makefile.Watcom index a780bbb28..10906c942 100644 --- a/lib/Makefile.Watcom +++ b/lib/Makefile.Watcom @@ -89,7 +89,7 @@ ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.5 !ifdef %libssh2_root LIBSSH2_ROOT = $(%libssh2_root) !else -LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.2.8 +LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.3.0 !endif !ifdef %librtmp_root diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 04285b533..ec7f50537 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -14,7 +14,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c krb5.c \ memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \ - http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \ + http_negotiate.c inet_pton.c strtoofft.c strerror.c \ hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c \ select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c \ qssl.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ @@ -22,7 +22,8 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c polarssl.c \ curl_rtmp.c openldap.c curl_gethostname.c gopher.c axtls.c \ idn_win32.c http_negotiate_sspi.c cyassl.c http_proxy.c non-ascii.c \ - asyn-ares.c asyn-thread.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 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ @@ -30,11 +31,12 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h \ curl_fnmatch.h wildcard.h fileinfo.h ftplistparser.h strtok.h \ connect.h llist.h hash.h content_encoding.h share.h curl_md4.h \ - curl_md5.h http_digest.h http_negotiate.h http_ntlm.h inet_pton.h \ + curl_md5.h http_digest.h http_negotiate.h inet_pton.h \ strtoofft.h strerror.h inet_ntop.h curlx.h curl_memory.h setup.h \ transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \ tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.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 polarssl.h curl_rtmp.h curl_gethostname.h \ - gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h + gopher.h axtls.h cyassl.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 diff --git a/lib/Makefile.m32 b/lib/Makefile.m32 index 76171cb9b..140571653 100644 --- a/lib/Makefile.m32 +++ b/lib/Makefile.m32 @@ -1,7 +1,7 @@ -######################################################################### +########################################################################### # -## Makefile for building libcurl.a with MingW32 (GCC-3.2 or later) -## and optionally OpenSSL (0.9.8), libssh2 (1.2), zlib (1.2.5), librtmp (2.3) +## Makefile for building libcurl.a with MingW (GCC-3.2 or later) +## and optionally OpenSSL (0.9.8), libssh2 (1.3), zlib (1.2.5), librtmp (2.3) ## ## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn @@ -9,10 +9,8 @@ ## Hint: you can also set environment vars to control the build, f.e.: ## set ZLIB_PATH=c:/zlib-1.2.5 ## set ZLIB=1 -## -## Comments to: Troy Engel <tengel@sonic.net> or -## Joern Hartroth <hartroth@acm.org> -######################################################################### +# +########################################################################### # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH @@ -22,9 +20,18 @@ endif ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-0.9.8r endif +ifndef OPENSSL_INCLUDE +OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc +endif +ifndef OPENSSL_LIBPATH +OPENSSL_LIBPATH = $(OPENSSL_PATH)/out +endif +ifndef OPENSSL_LIBS +OPENSSL_LIBS = -leay32 -lssl32 +endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2.8 +LIBSSH2_PATH = ../../libssh2-1.3.0 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH @@ -45,22 +52,35 @@ ifndef LDAP_SDK LDAP_SDK = c:/novell/ndk/cldapsdk/win32 endif +PROOT = .. + # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH -LIBCARES_PATH = ../ares +LIBCARES_PATH = $(PROOT)/ares +endif + +# Edit the var below to set to your architecture or set environment var. +ifndef ARCH +ARCH = w32 endif CC = gcc CFLAGS = -g -O2 -Wall +CFLAGS += -fno-strict-aliasing +ifeq ($(ARCH),w64) +CFLAGS += -D_AMD64_ +endif # comment LDFLAGS below to keep debug info LDFLAGS = -s AR = ar RANLIB = ranlib RC = windres -RCFLAGS = --include-dir=../include -DDEBUGBUILD=0 -O COFF -i -RM = del /q /f 2>NUL +RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF -i STRIP = strip -g +RM = del /q /f 2>NUL +CP = copy + ######################################################## ## Nothing more to do below this line! @@ -95,6 +115,9 @@ endif ifeq ($(findstring -sspi,$(CFG)),-sspi) SSPI = 1 endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +SPNEGO = 1 +endif ifeq ($(findstring -ldaps,$(CFG)),-ldaps) LDAPS = 1 endif @@ -104,10 +127,11 @@ endif INCLUDES = -I. -I../include CFLAGS += -DBUILDING_LIBCURL + ifdef ARES - INCLUDES += -I$(LIBCARES_PATH) + INCLUDES += -I"$(LIBCARES_PATH)" CFLAGS += -DUSE_ARES - DLL_LIBS += -L$(LIBCARES_PATH) -lcares + DLL_LIBS += -L"$(LIBCARES_PATH)" -lcares libcurl_dll_DEPENDENCIES = $(LIBCARES_PATH)/libcares.a endif ifdef RTMP @@ -118,37 +142,39 @@ endif ifdef SSH2 INCLUDES += -I"$(LIBSSH2_PATH)/include" -I"$(LIBSSH2_PATH)/win32" CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H - DLL_LIBS += -L$(LIBSSH2_PATH)/win32 -lssh2 + DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2 endif ifdef SSL - INCLUDES += -I"$(OPENSSL_PATH)/outinc" -I"$(OPENSSL_PATH)/outinc/openssl" + INCLUDES += -I"$(OPENSSL_INCLUDE)" CFLAGS += -DUSE_SSLEAY -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \ -DHAVE_ENGINE_LOAD_BUILTIN_ENGINES -DOPENSSL_NO_KRB5 \ -DCURL_WANTS_CA_BUNDLE_ENV - DLL_LIBS += -L$(OPENSSL_PATH)/out -leay32 -lssl32 + DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H - DLL_LIBS += -L$(ZLIB_PATH) -lz + DLL_LIBS += -L"$(ZLIB_PATH)" -lz endif ifdef IDN INCLUDES += -I"$(LIBIDN_PATH)/include" CFLAGS += -DUSE_LIBIDN - DLL_LIBS += -L$(LIBIDN_PATH)/lib -lidn + DLL_LIBS += -L"$(LIBIDN_PATH)/lib" -lidn else ifdef WINIDN - INCLUDES += -I"$(WINIDN_PATH)/include" - CFLAGS += -DHAVE_NORMALIZATION_H CFLAGS += -DUSE_WIN32_IDN + CFLAGS += -DWANT_IDN_PROTOTYPES DLL_LIBS += -L"$(WINIDN_PATH)" -lnormaliz endif endif ifdef SSPI CFLAGS += -DUSE_WINDOWS_SSPI endif +ifdef SPNEGO + CFLAGS += -DHAVE_SPNEGO +endif ifdef IPV6 - CFLAGS += -DENABLE_IPV6 + CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 endif ifdef LDAPS CFLAGS += -DHAVE_LDAP_SSL @@ -165,11 +191,10 @@ ifdef USE_LDAP_OPENLDAP endif ifndef USE_LDAP_NOVELL ifndef USE_LDAP_OPENLDAP -DLL_LIBS += -lwldap32 + DLL_LIBS += -lwldap32 endif endif DLL_LIBS += -lws2_32 -COMPILE = $(CC) $(INCLUDES) $(CFLAGS) # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc @@ -183,7 +208,6 @@ libcurl_a_DEPENDENCIES := $(strip $(CSOURCES) $(HHEADERS)) RESOURCE = libcurl.res -.SUFFIXES: .rc .res all: $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) @@ -200,20 +224,25 @@ $(libcurl_dll_LIBRARY): $(libcurl_a_OBJECTS) $(RESOURCE) $(libcurl_dll_DEPENDENC $(CC) $(LDFLAGS) -shared -Wl,--out-implib,$(libcurl_dll_a_LIBRARY) \ -o $@ $(libcurl_a_OBJECTS) $(RESOURCE) $(DLL_LIBS) -.c.o: - $(COMPILE) -c $< +%.o: %.c $(PROOT)/include/curl/curlbuild.h + $(CC) $(INCLUDES) $(CFLAGS) -c $< -.rc.res: +%.res: %.rc $(RC) $(RCFLAGS) $< -o $@ clean: +ifeq "$(wildcard $(PROOT)/include/curl/curlbuild.h.dist)" "$(PROOT)/include/curl/curlbuild.h.dist" + -$(RM) $(subst /,\,$(PROOT)/include/curl/curlbuild.h) +endif -$(RM) $(libcurl_a_OBJECTS) $(RESOURCE) distclean vclean: clean -$(RM) $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) $(libcurl_dll_a_LIBRARY) -FORCE: ; - $(LIBCARES_PATH)/libcares.a: $(MAKE) -C $(LIBCARES_PATH) -f Makefile.m32 +$(PROOT)/include/curl/curlbuild.h: + @echo Creating $@ + @$(CP) $(subst /,\,$@).dist $(subst /,\,$@) + diff --git a/lib/Makefile.netware b/lib/Makefile.netware index 2cc7c9ecc..43fae2e7a 100644 --- a/lib/Makefile.netware +++ b/lib/Makefile.netware @@ -24,7 +24,7 @@ endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2.8 +LIBSSH2_PATH = ../../libssh2-1.3.0 endif # Edit the path below to point to the base of your axTLS package. @@ -42,6 +42,11 @@ ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.3 endif +# Edit the path below to point to the base of your fbopenssl package. +ifndef FBOPENSSL_PATH +FBOPENSSL_PATH = ../../fbopenssl-0.4 +endif + # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = ../ares @@ -95,7 +100,7 @@ else endif PERL = perl # Here you can find a native Win32 binary of the original awk: -# http://www.gknw.net/development/prgtools/awk-20070501.zip +# http://www.gknw.net/development/prgtools/awk-20100523.zip AWK = awk CP = cp -afv MKDIR = mkdir @@ -181,6 +186,43 @@ CURL_LIB = ../lib INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) +ifeq ($(findstring -static,$(CFG)),-static) +LINK_STATIC = 1 +endif +ifeq ($(findstring -ares,$(CFG)),-ares) +WITH_ARES = 1 +endif +ifeq ($(findstring -rtmp,$(CFG)),-rtmp) +WITH_RTMP = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -ssh2,$(CFG)),-ssh2) +WITH_SSH2 = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -axtls,$(CFG)),-axtls) +WITH_AXTLS = 1 +WITH_SSL = +else +ifeq ($(findstring -ssl,$(CFG)),-ssl) +WITH_SSL = 1 +endif +endif +ifeq ($(findstring -zlib,$(CFG)),-zlib) +WITH_ZLIB = 1 +endif +ifeq ($(findstring -idn,$(CFG)),-idn) +WITH_IDN = 1 +endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +WITH_SPNEGO = 1 +endif +ifeq ($(findstring -ipv6,$(CFG)),-ipv6) +ENABLE_IPV6 = 1 +endif + ifdef WITH_ARES INCLUDES += -I$(LIBCARES_PATH) LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) @@ -204,6 +246,10 @@ ifdef WITH_SSL LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) IMPORTS += GetProcessSwitchCount RunningProcess INSTDEP += ca-bundle.crt +ifdef WITH_SPNEGO + INCLUDES += -I$(FBOPENSSL_PATH)/include + LDLIBS += $(FBOPENSSL_PATH)/nw/fbopenssl.$(LIBEXT) +endif else ifdef WITH_AXTLS INCLUDES += -I$(AXTLS_PATH)/inc @@ -498,6 +544,7 @@ endif @echo $(DL)#define USE_MANUAL 1$(DL) >> $@ @echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@ + @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@ @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@ @@ -583,6 +630,9 @@ ifdef WITH_SSL @echo $(DL)#define HAVE_LIBSSL 1$(DL) >> $@ @echo $(DL)#define HAVE_LIBCRYPTO 1$(DL) >> $@ @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ +ifdef WITH_SPNEGO + @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@ +endif else ifdef WITH_AXTLS @echo $(DL)#define USE_AXTLS 1$(DL) >> $@ diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6 index a778801dc..fb7566660 100644 --- a/lib/Makefile.vc6 +++ b/lib/Makefile.vc6 @@ -20,6 +20,11 @@ #
#***************************************************************************
+# All files in the Makefile.vc* series are generated automatically from the
+# one made for MSVC version 6. Alas, if you want to do changes to any of the
+# fiels and send back to the project, edit the version six, make your diff and
+# mail curl-library.
+
###########################################################################
#
# Makefile for building libcurl with MSVC6
@@ -59,13 +64,14 @@ !INCLUDE ..\Makefile.msvc.names
-
-
-
!IFNDEF OPENSSL_PATH
OPENSSL_PATH = ../../openssl-0.9.8r
!ENDIF
+!IFNDEF LIBSSH2_PATH
+LIBSSH2_PATH = ../../libssh2-1.2.8
+!ENDIF
+
!IFNDEF ZLIB_PATH
ZLIB_PATH = ../../zlib-1.2.5
!ENDIF
@@ -100,6 +106,7 @@ WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK" CCNODBG = cl.exe /O2 /DNDEBUG
CCDEBUG = cl.exe /Od /Gm /Zi /D_DEBUG /GZ
CFLAGSSSL = /DUSE_SSLEAY /I "$(OPENSSL_PATH)/inc32" /I "$(OPENSSL_PATH)/inc32/openssl"
+CFLAGSSSH2 = /DUSE_LIBSSH2 /DCURL_DISABLE_LDAP /DHAVE_LIBSSH2 /DHAVE_LIBSSH2_H /DLIBSSH2_WIN32 /DLIBSSH2_LIBRARY /I "$(LIBSSH2_PATH)/include"
CFLAGSZLIB = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ /I "$(ZLIB_PATH)"
CFLAGS = /I. /I../include /nologo /W3 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL /D_BIND_TO_CURRENT_VCLIBS_VERSION=1
CFLAGSLIB = /DCURL_STATICLIB
@@ -220,6 +227,36 @@ CFGSET = TRUE !ENDIF
######################
+# release-ssl-ssh2-zlib
+
+!IF "$(CFG)" == "release-ssl-ssh2-zlib"
+TARGET = $(LIB_NAME).lib
+DIROBJ = $(CFG)
+LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32"
+LFLAGSSSH2 = "/LIBPATH:$(LIBSSH2_PATH)"
+LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)"
+LNK = $(LNKLIB) $(LFLAGSSSL) $(LFLAGSSSH2) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET)
+CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSSSH2) $(CFLAGSZLIB) $(CFLAGSLIB)
+CFGSET = TRUE
+RESOURCE = $(LIBSSH2_PATH)/Release/src/libssh2.lib $(ZLIB_PATH)/zlib.lib
+!ENDIF
+
+######################
+# debug-ssl-ssh2-zlib
+
+!IF "$(CFG)" == "debug-ssl-ssh2-zlib"
+TARGET = $(LIB_NAME_DEBUG).lib
+DIROBJ = $(CFG)
+LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)"
+LFLAGSSSH2 = "/LIBPATH:$(LIBSSH2_PATH)"
+LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32"
+LNK = $(LNKLIB) $(ZLIBLIBS) $(LFLAGSSSL) $(LFLAGSSSH2) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET)
+CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSSSH2) $(CFLAGSZLIB) $(CFLAGSLIB)
+CFGSET = TRUE
+RESOURCE = $(LIBSSH2_PATH)/Release/src/libssh2.lib $(ZLIB_PATH)/zlib.lib
+!ENDIF
+
+######################
# release-dll
!IF "$(CFG)" == "release-dll"
@@ -418,6 +455,7 @@ RESOURCE = $(DIROBJ)\libcurl.res !MESSAGE release-ssl - release static library with ssl
!MESSAGE release-zlib - release static library with zlib
!MESSAGE release-ssl-zlib - release static library with ssl and zlib
+!MESSAGE release-ssl-ssh2-zlib - release static library with ssl, ssh2 and zlib
!MESSAGE release-ssl-dll - release static library with dynamic ssl
!MESSAGE release-zlib-dll - release static library with dynamic zlib
!MESSAGE release-ssl-dll-zlib-dll - release static library with dynamic ssl and dynamic zlib
@@ -425,6 +463,7 @@ RESOURCE = $(DIROBJ)\libcurl.res !MESSAGE release-dll-ssl-dll - release dynamic library with dynamic ssl
!MESSAGE release-dll-zlib-dll - release dynamic library with dynamic zlib
!MESSAGE release-dll-ssl-dll-zlib-dll - release dynamic library with dynamic ssl and dynamic zlib
+!MESSAGE debug-ssl-ssh2-zlib - debug static library with ssl, ssh2 and zlib
!MESSAGE debug - debug static library
!MESSAGE debug-ssl - debug static library with ssl
!MESSAGE debug-zlib - debug static library with zlib
@@ -467,6 +506,10 @@ X_OBJS= \ $(DIROBJ)\curl_fnmatch.obj \
$(DIROBJ)\curl_gethostname.obj \
$(DIROBJ)\curl_memrchr.obj \
+ $(DIROBJ)\curl_ntlm.obj \
+ $(DIROBJ)\curl_ntlm_core.obj \
+ $(DIROBJ)\curl_ntlm_msgs.obj \
+ $(DIROBJ)\curl_ntlm_wb.obj \
$(DIROBJ)\curl_rand.obj \
$(DIROBJ)\curl_rtmp.obj \
$(DIROBJ)\curl_sspi.obj \
@@ -494,7 +537,6 @@ X_OBJS= \ $(DIROBJ)\http_digest.obj \
$(DIROBJ)\http_negotiate.obj \
$(DIROBJ)\http_negotiate_sspi.obj \
- $(DIROBJ)\http_ntlm.obj \
$(DIROBJ)\http.obj \
$(DIROBJ)\http_proxy.obj \
$(DIROBJ)\if2ip.obj \
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 4165a451d..7f3bdf8a2 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -39,16 +37,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 3341686d9..38cde5df7 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <errno.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -37,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #if defined(USE_THREADS_POSIX) @@ -421,7 +414,7 @@ static bool init_resolve_thread (struct connectdata *conn, socket error string function can be used for this pupose. */ static const char *gai_strerror(int ecode) { - switch (ecode){ + switch (ecode) { case EAI_AGAIN: return "The name could not be resolved at this time"; case EAI_BADFLAGS: @@ -633,14 +626,28 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int *waitp) { struct addrinfo hints; + struct in_addr in; Curl_addrinfo *res; int error; char sbuf[NI_MAXSERV]; int pf = PF_INET; +#ifdef CURLRES_IPV6 + struct in6_addr in6; +#endif /* CURLRES_IPV6 */ *waitp = 0; /* default to synchronous response */ -#ifndef CURLRES_IPV4 + /* First check if this is an IPv4 address string */ + if(Curl_inet_pton(AF_INET, hostname, &in) > 0) + /* This is a dotted IP address 123.123.123.123-style */ + return Curl_ip2addr(AF_INET, &in, hostname, port); + +#ifdef CURLRES_IPV6 + /* check if this is an IPv6 address string */ + if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) + /* This is an IPv6 address literal */ + return Curl_ip2addr(AF_INET6, &in6, hostname, port); + /* * Check if a limited name resolve has been requested. */ @@ -660,7 +667,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, /* the stack seems to be a non-ipv6 one */ pf = PF_INET; -#endif /* !CURLRES_IPV4 */ +#endif /* CURLRES_IPV6 */ memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; diff --git a/lib/asyn.h b/lib/asyn.h index 34f9c14c5..e7c1b886d 100644 --- a/lib/asyn.h +++ b/lib/asyn.h @@ -146,15 +146,15 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, #ifndef CURLRES_ASYNCH /* convert these functions if an asynch resolver isn't used */ -#define Curl_resolver_cancel(x) +#define Curl_resolver_cancel(x) Curl_nop_stmt #define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST #define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST #define Curl_resolver_getsock(x,y,z) 0 #define Curl_resolver_duphandle(x,y) CURLE_OK #define Curl_resolver_init(x) CURLE_OK #define Curl_resolver_global_init() CURLE_OK -#define Curl_resolver_global_cleanup() -#define Curl_resolver_cleanup(x) +#define Curl_resolver_global_cleanup() Curl_nop_stmt +#define Curl_resolver_cleanup(x) Curl_nop_stmt #endif #ifdef CURLRES_ASYNCH diff --git a/lib/axtls.c b/lib/axtls.c index ffbd1d4f3..e37aed50a 100644 --- a/lib/axtls.c +++ b/lib/axtls.c @@ -27,13 +27,11 @@ */ #include "setup.h" + #ifdef USE_AXTLS #include <axTLS/ssl.h> #include "axtls.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -58,7 +56,7 @@ static int SSL_read(SSL *ssl, void *buf, int num) while((ret = ssl_read(ssl, &read_buf)) == SSL_OK); - if(ret > SSL_OK){ + if(ret > SSL_OK) { memcpy(buf, read_buf, ret > num ? num : ret); } @@ -187,10 +185,10 @@ Curl_axtls_connect(struct connectdata *conn, /* Load the trusted CA cert bundle file */ if(data->set.ssl.CAfile) { if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) - != SSL_OK){ + != SSL_OK) { infof(data, "error reading ca cert file %s \n", data->set.ssl.CAfile); - if(data->set.ssl.verifypeer){ + if(data->set.ssl.verifypeer) { Curl_axtls_close(conn, sockindex); return CURLE_SSL_CACERT_BADFILE; } @@ -208,13 +206,13 @@ Curl_axtls_connect(struct connectdata *conn, */ /* Load client certificate */ - if(data->set.str[STRING_CERT]){ + if(data->set.str[STRING_CERT]) { i=0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ - while(cert_types[i] != 0){ + while(cert_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], data->set.str[STRING_CERT], NULL); - if(ssl_fcn_return == SSL_OK){ + if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read cert file %s \n", data->set.str[STRING_CERT]); break; @@ -222,7 +220,7 @@ Curl_axtls_connect(struct connectdata *conn, i++; } /* Tried all cert types, none worked. */ - if(cert_types[i] == 0){ + if(cert_types[i] == 0) { failf(data, "%s is not x509 or pkcs12 format", data->set.str[STRING_CERT]); Curl_axtls_close(conn, sockindex); @@ -233,13 +231,13 @@ Curl_axtls_connect(struct connectdata *conn, /* Load client key. If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ - if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12){ + if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) { i=0; /* Instead of trying to analyze key type here, let axTLS try them all. */ - while(key_types[i] != 0){ + while(key_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], data->set.str[STRING_KEY], NULL); - if(ssl_fcn_return == SSL_OK){ + if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read key file %s \n", data->set.str[STRING_KEY]); break; @@ -247,7 +245,7 @@ Curl_axtls_connect(struct connectdata *conn, i++; } /* Tried all key types, none worked. */ - if(key_types[i] == 0){ + if(key_types[i] == 0) { failf(data, "Failure: %s is not a supported key file", data->set.str[STRING_KEY]); Curl_axtls_close(conn, sockindex); @@ -273,7 +271,7 @@ Curl_axtls_connect(struct connectdata *conn, /* Check to make sure handshake was ok. */ ssl_fcn_return = ssl_handshake_status(ssl); - if(ssl_fcn_return != SSL_OK){ + if(ssl_fcn_return != SSL_OK) { Curl_axtls_close(conn, sockindex); ssl_display_error(ssl_fcn_return); /* goes to stdout. */ return map_error_to_curl(ssl_fcn_return); @@ -285,8 +283,8 @@ Curl_axtls_connect(struct connectdata *conn, */ /* Verify server's certificate */ - if(data->set.ssl.verifypeer){ - if(ssl_verify_cert(ssl) != SSL_OK){ + if(data->set.ssl.verifypeer) { + if(ssl_verify_cert(ssl) != SSL_OK) { Curl_axtls_close(conn, sockindex); failf(data, "server cert verify failed"); return CURLE_SSL_CONNECT_ERROR; @@ -415,7 +413,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf, sizeof(buf)); - if(nread < SSL_OK){ + if(nread < SSL_OK) { failf(data, "close notify alert not received during shutdown"); retval = -1; } @@ -447,13 +445,13 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ infof(conn->data, " axtls_recv\n"); - if(connssl){ + if(connssl) { ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize); /* axTLS isn't terribly generous about error reporting */ /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS team approves proposed fix. */ - if(ret == -3 ){ + if(ret == -3 ) { Curl_axtls_close(conn, num); } else if(ret < 0) { diff --git a/lib/base64.c b/lib/base64.c index 0de1f0100..23ebb4aa9 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -24,9 +24,6 @@ #include "setup.h" -#include <stdlib.h> -#include <string.h> - #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -71,12 +68,19 @@ static void decodeQuantum(unsigned char *dest, const char *src) /* * Curl_base64_decode() * - * Given a base64 string at src, decode it and return an allocated memory in - * the *outptr. Returns the length of the decoded data. + * Given a base64 NUL-terminated string at src, decode it and return a + * pointer in *outptr to a newly allocated memory area holding decoded + * data. Size of decoded data is returned in variable pointed by outlen. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * When decoded data length is 0, returns NULL in *outptr. * * @unittest: 1302 */ -size_t Curl_base64_decode(const char *src, unsigned char **outptr) +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen) { size_t length = 0; size_t equalsTerm = 0; @@ -87,6 +91,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) unsigned char *newstr; *outptr = NULL; + *outlen = 0; while((src[length] != '=') && src[length]) length++; @@ -100,7 +105,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) /* Don't allocate a buffer if the decoded length is 0 */ if(numQuantums == 0) - return 0; + return CURLE_OK; rawlen = (numQuantums * 3) - equalsTerm; @@ -108,7 +113,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) (which may be partially thrown out) and the zero terminator. */ newstr = malloc(rawlen+4); if(!newstr) - return 0; + return CURLE_OUT_OF_MEMORY; *outptr = newstr; @@ -127,23 +132,34 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) newstr[i] = lastQuantum[i]; newstr[i] = '\0'; /* zero terminate */ - return rawlen; + + *outlen = rawlen; /* return size of decoded data */ + + return CURLE_OK; } /* * Curl_base64_encode() * - * Returns the length of the newly created base64 string. The third argument - * is a pointer to an allocated area holding the base64 data. If something - * went wrong, 0 is returned. + * Given a pointer to an input buffer and an input size, encode it and + * return a pointer in *outptr to a newly allocated memory area holding + * encoded data. Size of encoded data is returned in variable pointed by + * outlen. + * + * Input length of 0 indicates input buffer holds a NUL-terminated string. + * + * Returns CURLE_OK on success, otherwise specific error code. Function + * output shall not be considered valid unless CURLE_OK is returned. + * + * When encoded data length is 0, returns NULL in *outptr. * * @unittest: 1302 */ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inputbuff, size_t insize, - char **outptr) +CURLcode Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) { - CURLcode res; + CURLcode error; unsigned char ibuf[3]; unsigned char obuf[4]; int i; @@ -154,24 +170,25 @@ size_t Curl_base64_encode(struct SessionHandle *data, const char *indata = inputbuff; - *outptr = NULL; /* set to NULL in case of failure before we reach the end */ + *outptr = NULL; + *outlen = 0; if(0 == insize) insize = strlen(indata); base64data = output = malloc(insize*4/3+4); if(NULL == output) - return 0; + return CURLE_OUT_OF_MEMORY; /* * The base64 data needs to be created using the network encoding * not the host encoding. And we can't change the actual input * so we copy it to a buffer, translate it, and use that instead. */ - res = Curl_convert_clone(data, indata, insize, &convbuf); - if(res) { + error = Curl_convert_clone(data, indata, insize, &convbuf); + if(error) { free(output); - return 0; + return error; } if(convbuf) @@ -218,12 +235,14 @@ size_t Curl_base64_encode(struct SessionHandle *data, } output += 4; } - *output=0; - *outptr = base64data; /* make it return the actual data memory */ + *output = '\0'; + *outptr = base64data; /* return pointer to new data, allocated memory */ if(convbuf) free(convbuf); - return strlen(base64data); /* return the length of the new data */ + *outlen = strlen(base64data); /* return the length of the new data */ + + return CURLE_OK; } /* ---- End of Base64 Encoding ---- */ diff --git a/lib/checksrc.pl b/lib/checksrc.pl index 5d369496a..9f5058ddb 100755 --- a/lib/checksrc.pl +++ b/lib/checksrc.pl @@ -62,7 +62,7 @@ while(1) { next; } elsif($file =~ /-W(.*)/) { - $wlist = $1; + $wlist .= " $1 "; $file = shift @ARGV; next; } @@ -79,7 +79,7 @@ if(!$file) { } do { - if($file ne "$wlist") { + if("$wlist" !~ / $file /) { my $fullname = $file; $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/'); scanfile($fullname); @@ -145,9 +145,14 @@ sub scanfile { } # check for "} else" - if($l =~ /^(.*)\} else/) { + if($l =~ /^(.*)\} *else/) { checkwarn($line, length($1), $file, $l, "else after closing brace on same line"); } + # check for "){" + if($l =~ /^(.*)\)\{/) { + checkwarn($line, length($1)+1, $file, $l, "missing space after close paren"); + } + # check for open brace first on line but not first column # only alert if previous line ended with a close paren and wasn't a cpp # line diff --git a/lib/config-amigaos.h b/lib/config-amigaos.h index 99b96d656..1474ba915 100644 --- a/lib/config-amigaos.h +++ b/lib/config-amigaos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,7 @@ #define HAVE_ARPA_INET_H 1 #define HAVE_CLOSESOCKET_CAMEL 1 +#define HAVE_ERRNO_H 1 #define HAVE_GETHOSTBYADDR 1 #define HAVE_INET_ADDR 1 #define HAVE_INTTYPES_H 1 diff --git a/lib/config-dos.h b/lib/config-dos.h index 35d21aae2..694a30465 100644 --- a/lib/config-dos.h +++ b/lib/config-dos.h @@ -40,6 +40,7 @@ #define PACKAGE "curl" #define HAVE_ARPA_INET_H 1 +#define HAVE_ERRNO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_GETADDRINFO 1 #define HAVE_GETNAMEINFO 1 diff --git a/lib/config-mac.h b/lib/config-mac.h index 80af84e52..72e8260d1 100644 --- a/lib/config-mac.h +++ b/lib/config-mac.h @@ -30,6 +30,7 @@ #define OS "mac" +#define HAVE_ERRNO_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_SELECT_H 1 diff --git a/lib/config-os400.h b/lib/config-os400.h index 8dba1e4cd..4d2730928 100644 --- a/lib/config-os400.h +++ b/lib/config-os400.h @@ -97,6 +97,9 @@ /* Define if you have the <des.h> header file. */ #undef HAVE_DES_H +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H + /* Define if you have the <err.h> header file. */ #undef HAVE_ERR_H diff --git a/lib/config-riscos.h b/lib/config-riscos.h index 5ccf68124..127dbdb0a 100644 --- a/lib/config-riscos.h +++ b/lib/config-riscos.h @@ -92,6 +92,9 @@ /* Define if you have the <des.h> header file. */ #undef HAVE_DES_H +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H + /* Define if you have the <err.h> header file. */ #undef HAVE_ERR_H diff --git a/lib/config-vms.h b/lib/config-vms.h index e3844f83b..75c77d1b1 100644 --- a/lib/config-vms.h +++ b/lib/config-vms.h @@ -143,6 +143,9 @@ /* Define if you have the uname function. */ #define HAVE_UNAME 1 +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + /* Define if you have the <err.h> header file. */ #define HAVE_ERR_H 1 diff --git a/lib/config-win32.h b/lib/config-win32.h index 6768dda3c..cfbca9ca3 100644 --- a/lib/config-win32.h +++ b/lib/config-win32.h @@ -1,5 +1,5 @@ -#ifndef __LIB_CONFIG_WIN32_H -#define __LIB_CONFIG_WIN32_H +#ifndef HEADER_CURL_CONFIG_WIN32_H +#define HEADER_CURL_CONFIG_WIN32_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -23,49 +23,57 @@ ***************************************************************************/ /* ================================================================ */ -/* lib/config-win32.h - Hand crafted config file for Windows */ +/* Hand crafted config file for Windows */ /* ================================================================ */ /* ---------------------------------------------------------------- */ /* HEADER FILES */ /* ---------------------------------------------------------------- */ -/* Define if you have the <arpa/inet.h> header file. */ +/* Define if you have the <arpa/inet.h> header file. */ /* #define HAVE_ARPA_INET_H 1 */ -/* Define if you have the <assert.h> header file. */ +/* Define if you have the <assert.h> header file. */ #define HAVE_ASSERT_H 1 -/* Define if you have the <crypto.h> header file. */ +/* Define if you have the <crypto.h> header file. */ /* #define HAVE_CRYPTO_H 1 */ -/* Define if you have the <err.h> header file. */ +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the <err.h> header file. */ /* #define HAVE_ERR_H 1 */ -/* Define if you have the <fcntl.h> header file. */ +/* Define if you have the <fcntl.h> header file. */ #define HAVE_FCNTL_H 1 -/* Define if you have the <getopt.h> header file. */ -/* #define HAVE_GETOPT_H 1 */ +/* Define if you have the <getopt.h> header file. */ +#if defined(__MINGW32__) || defined(__POCC__) +#define HAVE_GETOPT_H 1 +#endif -/* Define if you have the <io.h> header file. */ +/* Define if you have the <io.h> header file. */ #define HAVE_IO_H 1 -/* Define if you have the <limits.h> header file. */ +/* Define if you have the <limits.h> header file. */ #define HAVE_LIMITS_H 1 -/* Define if you need the malloc.h header file even with stdlib.h */ +/* Define if you have the <locale.h> header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you need <malloc.h> header even with <stdlib.h> header file. */ #if !defined(__SALFORDC__) && !defined(__POCC__) #define NEED_MALLOC_H 1 #endif -/* Define if you have the <netdb.h> header file. */ +/* Define if you have the <netdb.h> header file. */ /* #define HAVE_NETDB_H 1 */ -/* Define if you have the <netinet/in.h> header file. */ +/* Define if you have the <netinet/in.h> header file. */ /* #define HAVE_NETINET_IN_H 1 */ -/* Define if you have the <process.h> header file. */ +/* Define if you have the <process.h> header file. */ #ifndef __SALFORDC__ #define HAVE_PROCESS_H 1 #endif @@ -73,68 +81,68 @@ /* Define if you have the <signal.h> header file. */ #define HAVE_SIGNAL_H 1 -/* Define if you have the <sgtty.h> header file. */ +/* Define if you have the <sgtty.h> header file. */ /* #define HAVE_SGTTY_H 1 */ -/* Define if you have the <ssl.h> header file. */ +/* Define if you have the <ssl.h> header file. */ /* #define HAVE_SSL_H 1 */ -/* Define if you have the <stdlib.h> header file. */ +/* Define if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 -/* Define if you have the <sys/param.h> header file. */ +/* Define if you have the <sys/param.h> header file. */ /* #define HAVE_SYS_PARAM_H 1 */ -/* Define if you have the <sys/select.h> header file. */ +/* Define if you have the <sys/select.h> header file. */ /* #define HAVE_SYS_SELECT_H 1 */ -/* Define if you have the <sys/socket.h> header file. */ +/* Define if you have the <sys/socket.h> header file. */ /* #define HAVE_SYS_SOCKET_H 1 */ -/* Define if you have the <sys/sockio.h> header file. */ +/* Define if you have the <sys/sockio.h> header file. */ /* #define HAVE_SYS_SOCKIO_H 1 */ -/* Define if you have the <sys/stat.h> header file. */ +/* Define if you have the <sys/stat.h> header file. */ #define HAVE_SYS_STAT_H 1 -/* Define if you have the <sys/time.h> header file */ +/* Define if you have the <sys/time.h> header file. */ /* #define HAVE_SYS_TIME_H 1 */ -/* Define if you have the <sys/types.h> header file. */ +/* Define if you have the <sys/types.h> header file. */ #define HAVE_SYS_TYPES_H 1 -/* Define if you have the <sys/utime.h> header file. */ +/* Define if you have the <sys/utime.h> header file. */ #ifndef __BORLANDC__ #define HAVE_SYS_UTIME_H 1 #endif -/* Define if you have the <termio.h> header file. */ +/* Define if you have the <termio.h> header file. */ /* #define HAVE_TERMIO_H 1 */ -/* Define if you have the <termios.h> header file. */ +/* Define if you have the <termios.h> header file. */ /* #define HAVE_TERMIOS_H 1 */ -/* Define if you have the <time.h> header file. */ +/* Define if you have the <time.h> header file. */ #define HAVE_TIME_H 1 -/* Define if you have the <unistd.h> header file. */ +/* Define if you have the <unistd.h> header file. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \ defined(__POCC__) #define HAVE_UNISTD_H 1 #endif -/* Define if you have the <windows.h> header file. */ +/* Define if you have the <windows.h> header file. */ #define HAVE_WINDOWS_H 1 -/* Define if you have the <winsock.h> header file. */ +/* Define if you have the <winsock.h> header file. */ #define HAVE_WINSOCK_H 1 -/* Define if you have the <winsock2.h> header file. */ +/* Define if you have the <winsock2.h> header file. */ #ifndef __SALFORDC__ #define HAVE_WINSOCK2_H 1 #endif -/* Define if you have the <ws2tcpip.h> header file. */ +/* Define if you have the <ws2tcpip.h> header file. */ #ifndef __SALFORDC__ #define HAVE_WS2TCPIP_H 1 #endif @@ -146,41 +154,44 @@ /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 -/* Define if you have the ANSI C header files. */ +/* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 -/* Define if you can safely include both <sys/time.h> and <time.h>. */ +/* Define if you can safely include both <sys/time.h> and <time.h>. */ /* #define TIME_WITH_SYS_TIME 1 */ /* ---------------------------------------------------------------- */ /* FUNCTIONS */ /* ---------------------------------------------------------------- */ -/* Define if you have the closesocket function. */ +/* Define if you have the closesocket function. */ #define HAVE_CLOSESOCKET 1 -/* Define if you don't have vprintf but do have _doprnt. */ +/* Define if you don't have vprintf but do have _doprnt. */ /* #define HAVE_DOPRNT 1 */ -/* Define if you have the gethostbyaddr function. */ +/* Define if you have the ftruncate function. */ +#define HAVE_FTRUNCATE 1 + +/* Define if you have the gethostbyaddr function. */ #define HAVE_GETHOSTBYADDR 1 -/* Define if you have the gethostname function. */ +/* Define if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 -/* Define if you have the getpass function. */ +/* Define if you have the getpass function. */ /* #define HAVE_GETPASS 1 */ -/* Define if you have the getservbyname function. */ +/* Define if you have the getservbyname function. */ #define HAVE_GETSERVBYNAME 1 -/* Define if you have the getprotobyname function. */ +/* Define if you have the getprotobyname function. */ #define HAVE_GETPROTOBYNAME -/* Define if you have the gettimeofday function. */ +/* Define if you have the gettimeofday function. */ /* #define HAVE_GETTIMEOFDAY 1 */ -/* Define if you have the inet_addr function. */ +/* Define if you have the inet_addr function. */ #define HAVE_INET_ADDR 1 /* Define if you have the ioctlsocket function. */ @@ -189,35 +200,41 @@ /* Define if you have a working ioctlsocket FIONBIO function. */ #define HAVE_IOCTLSOCKET_FIONBIO 1 -/* Define if you have the perror function. */ +/* Define if you have the perror function. */ #define HAVE_PERROR 1 -/* Define if you have the RAND_screen function when using SSL */ +/* Define if you have the RAND_screen function when using SSL. */ #define HAVE_RAND_SCREEN 1 /* Define if you have the `RAND_status' function when using SSL. */ #define HAVE_RAND_STATUS 1 -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. +/* Define if you have the `CRYPTO_cleanup_all_ex_data' function. This is present in OpenSSL versions after 0.9.6b */ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 -/* Define if you have the select function. */ +/* Define if you have the select function. */ #define HAVE_SELECT 1 -/* Define if you have the setvbuf function. */ +/* Define if you have the setlocale function. */ +#define HAVE_SETLOCALE 1 + +/* Define if you have the setmode function. */ +#define HAVE_SETMODE 1 + +/* Define if you have the setvbuf function. */ #define HAVE_SETVBUF 1 -/* Define if you have the socket function. */ +/* Define if you have the socket function. */ #define HAVE_SOCKET 1 -/* Define if you have the strcasecmp function. */ +/* Define if you have the strcasecmp function. */ /* #define HAVE_STRCASECMP 1 */ -/* Define if you have the strdup function. */ +/* Define if you have the strdup function. */ #define HAVE_STRDUP 1 -/* Define if you have the strftime function. */ +/* Define if you have the strftime function. */ #define HAVE_STRFTIME 1 /* Define if you have the stricmp function. */ @@ -229,21 +246,21 @@ /* Define if you have the strnicmp function. */ #define HAVE_STRNICMP 1 -/* Define if you have the strstr function. */ +/* Define if you have the strstr function. */ #define HAVE_STRSTR 1 -/* Define if you have the strtoll function. */ +/* Define if you have the strtoll function. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__) #define HAVE_STRTOLL 1 #endif -/* Define if you have the tcgetattr function. */ +/* Define if you have the tcgetattr function. */ /* #define HAVE_TCGETATTR 1 */ -/* Define if you have the tcsetattr function. */ +/* Define if you have the tcsetattr function. */ /* #define HAVE_TCSETATTR 1 */ -/* Define if you have the utime function */ +/* Define if you have the utime function. */ #ifndef __BORLANDC__ #define HAVE_UTIME 1 #endif @@ -330,13 +347,13 @@ /* TYPEDEF REPLACEMENTS */ /* ---------------------------------------------------------------- */ -/* Define this if in_addr_t is not an available 'typedefed' type */ +/* Define if in_addr_t is not an available 'typedefed' type. */ #define in_addr_t unsigned long -/* Define as the return type of signal handlers (int or void). */ +/* Define to the return type of signal handlers (int or void). */ #define RETSIGTYPE void -/* Define ssize_t if it is not an available 'typedefed' type */ +/* Define if ssize_t is not an available 'typedefed' type. */ #ifndef _SSIZE_T_DEFINED # if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \ defined(__POCC__) || \ @@ -354,19 +371,19 @@ /* TYPE SIZES */ /* ---------------------------------------------------------------- */ -/* The size of `int', as computed by sizeof. */ +/* Define to the size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 -/* The size of `long double', as computed by sizeof. */ +/* Define to the size of `long double', as computed by sizeof. */ #define SIZEOF_LONG_DOUBLE 16 -/* The size of `long long', as computed by sizeof. */ +/* Define to the size of `long long', as computed by sizeof. */ /* #define SIZEOF_LONG_LONG 8 */ -/* The size of `short', as computed by sizeof. */ +/* Define to the size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 -/* The size of `size_t', as computed by sizeof. */ +/* Define to the size of `size_t', as computed by sizeof. */ #if defined(_WIN64) # define SIZEOF_SIZE_T 8 #else @@ -377,14 +394,49 @@ /* STRUCT RELATED */ /* ---------------------------------------------------------------- */ -/* Define this if you have struct sockaddr_storage */ +/* Define if you have struct sockaddr_storage. */ #if !defined(__SALFORDC__) && !defined(__BORLANDC__) #define HAVE_STRUCT_SOCKADDR_STORAGE 1 #endif -/* Define this if you have struct timeval */ +/* Define if you have struct timeval. */ #define HAVE_STRUCT_TIMEVAL 1 +/* Define if struct sockaddr_in6 has the sin6_scope_id member. */ +#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1 + +/* ---------------------------------------------------------------- */ +/* BSD-style lwIP TCP/IP stack SPECIFIC */ +/* ---------------------------------------------------------------- */ + +/* Define to use BSD-style lwIP TCP/IP stack. */ +/* #define USE_LWIPSOCK 1 */ + +#ifdef USE_LWIPSOCK +# undef USE_WINSOCK +# undef HAVE_WINSOCK_H +# undef HAVE_WINSOCK2_H +# undef HAVE_WS2TCPIP_H +# undef HAVE_ERRNO_H +# undef HAVE_GETHOSTNAME +# undef HAVE_GETNAMEINFO +# undef LWIP_POSIX_SOCKETS_IO_NAMES +# undef RECV_TYPE_ARG1 +# undef RECV_TYPE_ARG3 +# undef SEND_TYPE_ARG1 +# undef SEND_TYPE_ARG3 +# define HAVE_FREEADDRINFO +# define HAVE_GETADDRINFO +# define HAVE_GETHOSTBYNAME +# define HAVE_GETHOSTBYNAME_R +# define HAVE_GETHOSTBYNAME_R_6 +# define LWIP_POSIX_SOCKETS_IO_NAMES 0 +# define RECV_TYPE_ARG1 int +# define RECV_TYPE_ARG3 size_t +# define SEND_TYPE_ARG1 int +# define SEND_TYPE_ARG3 size_t +#endif + /* ---------------------------------------------------------------- */ /* Watt-32 tcp/ip SPECIFIC */ /* ---------------------------------------------------------------- */ @@ -413,8 +465,11 @@ /* COMPILER SPECIFIC */ /* ---------------------------------------------------------------- */ -/* Undef keyword 'const' if it does not work. */ -/* #undef const */ +/* Define to nothing if compiler does not support 'const' qualifier. */ +/* #define const */ + +/* Define to nothing if compiler does not support 'volatile' qualifier. */ +/* #define volatile */ /* Windows should not have HAVE_GMTIME_R defined */ /* #undef HAVE_GMTIME_R */ @@ -429,14 +484,14 @@ #define HAVE_LONGLONG 1 #endif -/* Define to avoid VS2005 complaining about portable C functions */ +/* Define to avoid VS2005 complaining about portable C functions. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #endif -/* VS2005 and later dafault size for time_t is 64-bit, unless */ -/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ +/* VS2005 and later dafault size for time_t is 64-bit, unless + _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ #if defined(_MSC_VER) && (_MSC_VER >= 1400) # ifndef _USE_32BIT_TIME_T # define SIZEOF_TIME_T 8 @@ -446,12 +501,13 @@ #endif /* Officially, Microsoft's Windows SDK versions 6.X do not support Windows - 2000 as a supported build target. VS2008 default installations provide an - embedded Windows SDK v6.0A along with the claim that Windows 2000 is a - valid build target for VS2008. Popular belief is that binaries built using - Windows SDK versions 6.X and Windows 2000 as a build target are functional */ + 2000 as a supported build target. VS2008 default installations provide + an embedded Windows SDK v6.0A along with the claim that Windows 2000 is + a valid build target for VS2008. Popular belief is that binaries built + with VS2008 using Windows SDK versions 6.X and Windows 2000 as a build + target are functional. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_MINIMUM_TARGET 0x0500 +# define VS2008_MIN_TARGET 0x0500 #endif /* When no build target is specified VS2008 default build target is Windows @@ -459,18 +515,18 @@ for VS2008 we will target the minimum Officially supported build target, which happens to be Windows XP. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_DEFAULT_TARGET 0x0501 +# define VS2008_DEF_TARGET 0x0501 #endif -/* VS2008 default target settings and minimum build target check */ +/* VS2008 default target settings and minimum build target check. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) # ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2008_DEFAULT_TARGET +# define _WIN32_WINNT VS2008_DEF_TARGET # endif # ifndef WINVER -# define WINVER VS2008_DEFAULT_TARGET +# define WINVER VS2008_DEF_TARGET # endif -# if (_WIN32_WINNT < VS2008_MINIMUM_TARGET) || (WINVER < VS2008_MINIMUM_TARGET) +# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) # error VS2008 does not support Windows build targets prior to Windows 2000 # endif #endif @@ -549,13 +605,13 @@ /* ---------------------------------------------------------------- */ /* - * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS + * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS. */ -/* Define USE_ARES to enable c-ares asynchronous DNS lookups */ +/* Define to enable c-ares asynchronous DNS lookups. */ /* #define USE_ARES 1 */ -/* Define USE_THREADS_WIN32 to enable threaded asynchronous DNS lookups */ +/* Define to enable threaded asynchronous DNS lookups. */ #define USE_THREADS_WIN32 1 #if defined(USE_ARES) && defined(USE_THREADS_WIN32) @@ -597,10 +653,10 @@ #undef OS #if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */ #define OS "i386-pc-win32" +#elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */ +#define OS "x86_64-pc-win32" #elif defined(_M_IA64) /* Itanium */ #define OS "ia64-pc-win32" -#elif defined(_M_X64) /* AMD64/EM64T - Not defined until MSVC 2005 */ -#define OS "amd64-pc-win32" #else #define OS "unknown-pc-win32" #endif @@ -608,8 +664,11 @@ /* Name of package */ #define PACKAGE "curl" +/* If you want to build curl with the built-in manual */ +#define USE_MANUAL 1 + #if defined(__POCC__) || (USE_IPV6) # define ENABLE_IPV6 1 #endif -#endif /* __LIB_CONFIG_WIN32_H */ +#endif /* HEADER_CURL_CONFIG_WIN32_H */ diff --git a/lib/config-win32ce.h b/lib/config-win32ce.h index 872334286..1ade83fbe 100644 --- a/lib/config-win32ce.h +++ b/lib/config-win32ce.h @@ -39,6 +39,9 @@ /* Define if you have the <crypto.h> header file. */ /* #define HAVE_CRYPTO_H 1 */ +/* Define if you have the <errno.h> header file. */ +/* #define HAVE_ERRNO_H 1 */ + /* Define if you have the <err.h> header file. */ /* #define HAVE_ERR_H 1 */ diff --git a/lib/connect.c b/lib/connect.c index a9185978c..2a1876e71 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -22,9 +22,6 @@ #include "setup.h" -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -52,9 +49,6 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include <sys/filio.h> @@ -68,10 +62,6 @@ #include <inet.h> #endif -#include <stdio.h> -#include <errno.h> -#include <string.h> - #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -669,7 +659,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, *connected = FALSE; /* a very negative world view is best */ - if(conn->bits.tcpconnect) { + if(conn->bits.tcpconnect[sockindex]) { /* we are connected already! */ *connected = TRUE; return CURLE_OK; @@ -708,9 +698,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, if(code) return code; - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[sockindex] = TRUE; *connected = TRUE; - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + if(sockindex == FIRSTSOCKET) + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_verboseconnect(conn); Curl_updateconninfo(conn, sockfd); @@ -756,7 +747,7 @@ static void tcpnodelay(struct connectdata *conn, #ifdef TCP_NODELAY struct SessionHandle *data= conn->data; curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay; - int proto = IPPROTO_TCP; + int level = IPPROTO_TCP; #if 0 /* The use of getprotobyname() is disabled since it isn't thread-safe on @@ -768,10 +759,10 @@ static void tcpnodelay(struct connectdata *conn, detected. */ struct protoent *pe = getprotobyname("tcp"); if(pe) - proto = pe->p_proto; + level = pe->p_proto; #endif - if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff, + if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(conn, SOCKERRNO)); @@ -799,10 +790,10 @@ static void nosigpipe(struct connectdata *conn, Curl_strerror(conn, SOCKERRNO)); } #else -#define nosigpipe(x,y) +#define nosigpipe(x,y) Curl_nop_stmt #endif -#ifdef WIN32 +#ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. @@ -845,7 +836,7 @@ singleipconnect(struct connectdata *conn, { struct Curl_sockaddr_ex addr; int rc; - int error; + int error = 0; bool isconnected = FALSE; struct SessionHandle *data = conn->data; curl_socket_t sockfd; @@ -916,11 +907,6 @@ singleipconnect(struct connectdata *conn, Curl_persistconninfo(conn); -#ifdef ENABLE_IPV6 - if(addr.family == AF_INET6) - conn->bits.ipv6 = TRUE; -#endif - if(data->set.tcp_nodelay) tcpnodelay(conn, sockfd); @@ -955,6 +941,8 @@ singleipconnect(struct connectdata *conn, /* Connect TCP sockets, bind UDP */ if(!isconnected && (conn->socktype == SOCK_STREAM)) { rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + if(-1 == rc) + error = SOCKERRNO; conn->connecttime = Curl_tvnow(); if(conn->num_addr > 1) Curl_expire(data, conn->timeoutms_per_addr); @@ -963,8 +951,6 @@ singleipconnect(struct connectdata *conn, rc = 0; if(-1 == rc) { - error = SOCKERRNO; - switch (error) { case EINPROGRESS: case EWOULDBLOCK: @@ -1008,6 +994,10 @@ singleipconnect(struct connectdata *conn, /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ infof(data, "connected\n"); +#ifdef ENABLE_IPV6 + conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE; +#endif + Curl_updateconninfo(conn, sockfd); *sockp = sockfd; return CURLE_OK; diff --git a/lib/connect.h b/lib/connect.h index 3df9d970e..052549368 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -1,5 +1,5 @@ -#ifndef __CONNECT_H -#define __CONNECT_H +#ifndef HEADER_CURL_CONNECT_H +#define HEADER_CURL_CONNECT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ @@ -52,7 +53,7 @@ long Curl_timeleft(struct SessionHandle *data, curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, struct connectdata **connp); -#ifdef WIN32 +#ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. @@ -64,10 +65,11 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, */ void Curl_sndbufset(curl_socket_t sockfd); #else -#define Curl_sndbufset(y) +#define Curl_sndbufset(y) Curl_nop_stmt #endif void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd); void Curl_persistconninfo(struct connectdata *conn); int Curl_closesocket(struct connectdata *conn, curl_socket_t sock); -#endif + +#endif /* HEADER_CURL_CONNECT_H */ diff --git a/lib/content_encoding.c b/lib/content_encoding.c index 876115a32..3276ef988 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -24,9 +24,6 @@ #ifdef HAVE_LIBZ -#include <stdlib.h> -#include <string.h> - #include "urldata.h" #include <curl/curl.h> #include "sendf.h" @@ -52,6 +49,21 @@ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ +static voidpf +zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) +{ + (void) opaque; + /* not a typo, keep it calloc() */ + return (voidpf) calloc(items, size); +} + +static void +zfree_cb(voidpf opaque, voidpf ptr) +{ + (void) opaque; + free(ptr); +} + static CURLcode process_zlib_error(struct connectdata *conn, z_stream *z) { @@ -161,11 +173,10 @@ Curl_unencode_deflate_write(struct connectdata *conn, /* Initialize zlib? */ if(k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; + memset(z, 0, sizeof(z_stream)); + z->zalloc = (alloc_func)zalloc_cb; + z->zfree = (free_func)zfree_cb; + if(inflateInit(z) != Z_OK) return process_zlib_error(conn, z); k->zlib_init = ZLIB_INIT; @@ -272,11 +283,9 @@ Curl_unencode_gzip_write(struct connectdata *conn, /* Initialize zlib? */ if(k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; + memset(z, 0, sizeof(z_stream)); + z->zalloc = (alloc_func)zalloc_cb; + z->zfree = (free_func)zfree_cb; if(strcmp(zlibVersion(), "1.2.0.4") >= 0) { /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */ diff --git a/lib/content_encoding.h b/lib/content_encoding.h index 3aff9d3c0..372da4a3b 100644 --- a/lib/content_encoding.h +++ b/lib/content_encoding.h @@ -1,5 +1,5 @@ -#ifndef __CURL_CONTENT_ENCODING_H -#define __CURL_CONTENT_ENCODING_H +#ifndef HEADER_CURL_CONTENT_ENCODING_H +#define HEADER_CURL_CONTENT_ENCODING_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,7 +32,7 @@ void Curl_unencode_cleanup(struct connectdata *conn); #else #define ALL_CONTENT_ENCODINGS "identity" -#define Curl_unencode_cleanup(x) +#define Curl_unencode_cleanup(x) Curl_nop_stmt #endif CURLcode Curl_unencode_deflate_write(struct connectdata *conn, @@ -45,4 +45,4 @@ Curl_unencode_gzip_write(struct connectdata *conn, ssize_t nread); -#endif +#endif /* HEADER_CURL_CONTENT_ENCODING_H */ diff --git a/lib/cookie.c b/lib/cookie.c index 7657da06e..41ccdbe34 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -81,9 +81,6 @@ Example set of cookies: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) -#include <stdlib.h> -#include <string.h> - #define _MPRINTF_REPLACE #include <curl/mprintf.h> @@ -129,7 +126,7 @@ static bool tailmatch(const char *little, const char *bigone) if(littlelen > biglen) return FALSE; - return (bool)Curl_raw_equal(little, bigone+biglen-littlelen); + return Curl_raw_equal(little, bigone+biglen-littlelen) ? TRUE : FALSE; } /* @@ -147,9 +144,9 @@ void Curl_cookie_loadfiles(struct SessionHandle *data) data->set.cookiesession); list = list->next; } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); curl_slist_free_all(data->change.cookielist); /* clean up list */ data->change.cookielist = NULL; /* don't do this again! */ + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } } @@ -209,7 +206,6 @@ Curl_cookie_add(struct SessionHandle *data, if(httpheader) { /* This line was read off a HTTP-header */ const char *ptr; - const char *sep; const char *semiptr; char *what; @@ -226,185 +222,186 @@ Curl_cookie_add(struct SessionHandle *data, ptr = lineptr; do { - /* we have a <what>=<this> pair or a 'secure' word here */ - sep = strchr(ptr, '='); - if(sep && (!semiptr || (semiptr>sep)) ) { - /* - * There is a = sign and if there was a semicolon too, which make sure - * that the semicolon comes _after_ the equal sign. - */ - - name[0]=what[0]=0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%" - MAX_COOKIE_LINE_TXT "[^;\r\n]", - name, what)) { - /* this is a <name>=<what> pair. We use strstore() below to properly - deal with received cookie headers that have the same string - property set more than once, and then we use the last one. */ - - const char *whatptr; - - /* Strip off trailing whitespace from the 'what' */ - size_t len=strlen(what); - while(len && ISBLANK(what[len-1])) { - what[len-1]=0; - len--; - } + /* we have a <what>=<this> pair or a stand-alone word here */ + name[0]=what[0]=0; /* init the buffers */ + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =]=%" + MAX_COOKIE_LINE_TXT "[^;\r\n]", + name, what)) { + /* Use strstore() below to properly deal with received cookie + headers that have the same string property set more than once, + and then we use the last one. */ + const char *whatptr; + bool done = FALSE; + bool sep; + size_t len=strlen(what); + const char *endofn = &ptr[ strlen(name) ]; + + /* skip trailing spaces in name */ + while(*endofn && ISBLANK(*endofn)) + endofn++; + + /* name ends with a '=' ? */ + sep = (*endofn == '=')?TRUE:FALSE; + + /* Strip off trailing whitespace from the 'what' */ + while(len && ISBLANK(what[len-1])) { + what[len-1]=0; + len--; + } - /* Skip leading whitespace from the 'what' */ - whatptr=what; - while(*whatptr && ISBLANK(*whatptr)) { - whatptr++; - } + /* Skip leading whitespace from the 'what' */ + whatptr=what; + while(*whatptr && ISBLANK(*whatptr)) + whatptr++; - if(Curl_raw_equal("path", name)) { - strstore(&co->path, whatptr); - if(!co->path) { - badcookie = TRUE; /* out of memory bad */ - break; + if(!len) { + /* this was a "<name>=" with no content, and we must allow + 'secure' and 'httponly' specified this weirdly */ + done = TRUE; + if(Curl_raw_equal("secure", name)) + co->secure = TRUE; + else if(Curl_raw_equal("httponly", name)) + co->httponly = TRUE; + else if(sep) + /* there was a '=' so we're not done parsing this field */ + done = FALSE; + } + if(done) + ; + else if(Curl_raw_equal("path", name)) { + strstore(&co->path, whatptr); + if(!co->path) { + badcookie = TRUE; /* out of memory bad */ + break; + } + } + else if(Curl_raw_equal("domain", name)) { + /* note that this name may or may not have a preceding dot, but + we don't care about that, we treat the names the same anyway */ + + const char *domptr=whatptr; + const char *nextptr; + int dotcount=1; + + /* Count the dots, we need to make sure that there are enough + of them. */ + + if('.' == whatptr[0]) + /* don't count the initial dot, assume it */ + domptr++; + + do { + nextptr = strchr(domptr, '.'); + if(nextptr) { + if(domptr != nextptr) + dotcount++; + domptr = nextptr+1; } + } while(nextptr); + + /* The original Netscape cookie spec defined that this domain name + MUST have three dots (or two if one of the seven holy TLDs), + but it seems that these kinds of cookies are in use "out there" + so we cannot be that strict. I've therefore lowered the check + to not allow less than two dots. */ + + if(dotcount < 2) { + /* Received and skipped a cookie with a domain using too few + dots. */ + badcookie=TRUE; /* mark this as a bad cookie */ + infof(data, "skipped cookie with illegal dotcount domain: %s\n", + whatptr); } - else if(Curl_raw_equal("domain", name)) { - /* note that this name may or may not have a preceding dot, but - we don't care about that, we treat the names the same anyway */ - - const char *domptr=whatptr; - const char *nextptr; - int dotcount=1; - - /* Count the dots, we need to make sure that there are enough - of them. */ + else { + /* Now, we make sure that our host is within the given domain, + or the given domain is not valid and thus cannot be set. */ if('.' == whatptr[0]) - /* don't count the initial dot, assume it */ - domptr++; - - do { - nextptr = strchr(domptr, '.'); - if(nextptr) { - if(domptr != nextptr) - dotcount++; - domptr = nextptr+1; + whatptr++; /* ignore preceding dot */ + + if(!domain || tailmatch(whatptr, domain)) { + const char *tailptr=whatptr; + if(tailptr[0] == '.') + tailptr++; + strstore(&co->domain, tailptr); /* don't prefix w/dots + internally */ + if(!co->domain) { + badcookie = TRUE; + break; } - } while(nextptr); - - /* The original Netscape cookie spec defined that this domain name - MUST have three dots (or two if one of the seven holy TLDs), - but it seems that these kinds of cookies are in use "out there" - so we cannot be that strict. I've therefore lowered the check - to not allow less than two dots. */ - - if(dotcount < 2) { - /* Received and skipped a cookie with a domain using too few - dots. */ - badcookie=TRUE; /* mark this as a bad cookie */ - infof(data, "skipped cookie with illegal dotcount domain: %s\n", - whatptr); + co->tailmatch=TRUE; /* we always do that if the domain name was + given */ } else { - /* Now, we make sure that our host is within the given domain, - or the given domain is not valid and thus cannot be set. */ - - if('.' == whatptr[0]) - whatptr++; /* ignore preceding dot */ - - if(!domain || tailmatch(whatptr, domain)) { - const char *tailptr=whatptr; - if(tailptr[0] == '.') - tailptr++; - strstore(&co->domain, tailptr); /* don't prefix w/dots - internally */ - if(!co->domain) { - badcookie = TRUE; - break; - } - co->tailmatch=TRUE; /* we always do that if the domain name was - given */ - } - else { - /* we did not get a tailmatch and then the attempted set domain - is not a domain to which the current host belongs. Mark as - bad. */ - badcookie=TRUE; - infof(data, "skipped cookie with bad tailmatch domain: %s\n", - whatptr); - } - } - } - else if(Curl_raw_equal("version", name)) { - strstore(&co->version, whatptr); - if(!co->version) { - badcookie = TRUE; - break; + /* we did not get a tailmatch and then the attempted set domain + is not a domain to which the current host belongs. Mark as + bad. */ + badcookie=TRUE; + infof(data, "skipped cookie with bad tailmatch domain: %s\n", + whatptr); } } - else if(Curl_raw_equal("max-age", name)) { - /* Defined in RFC2109: - - Optional. The Max-Age attribute defines the lifetime of the - cookie, in seconds. The delta-seconds value is a decimal non- - negative integer. After delta-seconds seconds elapse, the - client should discard the cookie. A value of zero means the - cookie should be discarded immediately. - - */ - strstore(&co->maxage, whatptr); - if(!co->maxage) { - badcookie = TRUE; - break; - } - co->expires = - strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10) - + (long)now; + } + else if(Curl_raw_equal("version", name)) { + strstore(&co->version, whatptr); + if(!co->version) { + badcookie = TRUE; + break; } - else if(Curl_raw_equal("expires", name)) { - strstore(&co->expirestr, whatptr); - if(!co->expirestr) { - badcookie = TRUE; - break; - } - /* Note that if the date couldn't get parsed for whatever reason, - the cookie will be treated as a session cookie */ - co->expires = curl_getdate(what, &now); - - /* Session cookies have expires set to 0 so if we get that back - from the date parser let's add a second to make it a - non-session cookie */ - if(co->expires == 0) - co->expires = 1; - else if(co->expires < 0) - co->expires = 0; + } + else if(Curl_raw_equal("max-age", name)) { + /* Defined in RFC2109: + + Optional. The Max-Age attribute defines the lifetime of the + cookie, in seconds. The delta-seconds value is a decimal non- + negative integer. After delta-seconds seconds elapse, the + client should discard the cookie. A value of zero means the + cookie should be discarded immediately. + + */ + strstore(&co->maxage, whatptr); + if(!co->maxage) { + badcookie = TRUE; + break; } - else if(!co->name) { - co->name = strdup(name); - co->value = strdup(whatptr); - if(!co->name || !co->value) { - badcookie = TRUE; - break; - } + co->expires = + strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10) + + (long)now; + } + else if(Curl_raw_equal("expires", name)) { + strstore(&co->expirestr, whatptr); + if(!co->expirestr) { + badcookie = TRUE; + break; } - /* - else this is the second (or more) name we don't know - about! */ + /* Note that if the date couldn't get parsed for whatever reason, + the cookie will be treated as a session cookie */ + co->expires = curl_getdate(what, &now); + + /* Session cookies have expires set to 0 so if we get that back + from the date parser let's add a second to make it a + non-session cookie */ + if(co->expires == 0) + co->expires = 1; + else if(co->expires < 0) + co->expires = 0; } - else { - /* this is an "illegal" <what>=<this> pair */ + else if(!co->name) { + co->name = strdup(name); + co->value = strdup(whatptr); + if(!co->name || !co->value) { + badcookie = TRUE; + break; + } } + /* + else this is the second (or more) name we don't know + about! */ } else { - if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]", - what)) { - if(Curl_raw_equal("secure", what)) { - co->secure = TRUE; - } - else if(Curl_raw_equal("httponly", what)) { - co->httponly = TRUE; - } - /* else, - unsupported keyword without assign! */ - - } + /* this is an "illegal" <what>=<this> pair */ } + if(!semiptr || !*semiptr) { /* we already know there are no more cookies */ semiptr = NULL; @@ -530,7 +527,7 @@ Curl_cookie_add(struct SessionHandle *data, As far as I can see, it is set to true when the cookie says .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch=(bool)Curl_raw_equal(ptr, "TRUE"); + co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* It turns out, that sometimes the file format allows the path @@ -550,7 +547,7 @@ Curl_cookie_add(struct SessionHandle *data, fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: - co->secure = (bool)Curl_raw_equal(ptr, "TRUE"); + co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; break; case 4: co->expires = curlx_strtoofft(ptr, NULL, 10); @@ -1110,23 +1107,20 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) c = data->cookies->cookies; - beg = list; while(c) { /* fill the list with _all_ the cookies we know */ line = get_netscape_format(c); - if(line == NULL) { - curl_slist_free_all(beg); + if(!line) { + curl_slist_free_all(list); return NULL; } - list = curl_slist_append(list, line); + beg = curl_slist_append(list, line); free(line); - if(list == NULL) { - curl_slist_free_all(beg); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; c = c->next; } @@ -1151,10 +1145,12 @@ void Curl_flush_cookies(struct SessionHandle *data, int cleanup) data->set.str[STRING_COOKIEJAR]); } else { - if(cleanup && data->change.cookielist) + if(cleanup && data->change.cookielist) { /* since nothing is written, we can just free the list of cookie file names */ curl_slist_free_all(data->change.cookielist); /* clean up list */ + data->change.cookielist = NULL; + } Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); } diff --git a/lib/cookie.h b/lib/cookie.h index a950e359b..5997e4680 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -21,15 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include <stdio.h> -#if defined(WIN32) -#include <time.h> -#else -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#endif +#include "setup.h" #include <curl/curl.h> @@ -95,10 +87,10 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies); #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES) #define Curl_cookie_list(x) NULL -#define Curl_cookie_loadfiles(x) do { } while (0) +#define Curl_cookie_loadfiles(x) Curl_nop_stmt #define Curl_cookie_init(x,y,z,w) NULL -#define Curl_cookie_cleanup(x) do { } while (0) -#define Curl_flush_cookies(x,y) +#define Curl_cookie_cleanup(x) Curl_nop_stmt +#define Curl_flush_cookies(x,y) Curl_nop_stmt #else void Curl_flush_cookies(struct SessionHandle *data, int cleanup); void Curl_cookie_cleanup(struct CookieInfo *); diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 074bf17dc..bae403f95 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -40,7 +40,6 @@ #ifdef __VMS # include <in.h> # include <inet.h> -# include <stdlib.h> #endif #if defined(NETWARE) && defined(__NOVELL_LIBC__) diff --git a/lib/curl_base64.h b/lib/curl_base64.h index 2498a0a22..6e200d2ec 100644 --- a/lib/curl_base64.h +++ b/lib/curl_base64.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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,10 +22,11 @@ * ***************************************************************************/ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inputbuff, size_t insize, - char **outptr); +CURLcode Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen); -size_t Curl_base64_decode(const char *src, unsigned char **outptr); +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen); #endif /* HEADER_CURL_BASE64_H */ diff --git a/lib/curl_gethostname.c b/lib/curl_gethostname.c index 7f0bfed54..aafa45b59 100644 --- a/lib/curl_gethostname.c +++ b/lib/curl_gethostname.c @@ -32,12 +32,16 @@ * Curl_gethostname() is a wrapper around gethostname() which allows * overriding the host name that the function would normally return. * This capability is used by the test suite to verify exact matching - * of NTLM authentication, which exercises libcurl's MD4 and DES code. + * of NTLM authentication, which exercises libcurl's MD4 and DES code + * as well as by the SMTP module when a hostname is not provided. * * For libcurl debug enabled builds host name overriding takes place * when environment variable CURL_GETHOSTNAME is set, using the value * held by the variable to override returned host name. * + * Note: The function always returns the un-qualified hostname rather + * than being provider dependent. + * * For libcurl shared library release builds the test suite preloads * another shared library named libhostname using the LD_PRELOAD * mechanism which intercepts, and might override, the gethostname() @@ -58,6 +62,8 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { return -1; #else + int err; + char* dot; #ifdef DEBUGBUILD @@ -65,17 +71,34 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { const char *force_hostname = getenv("CURL_GETHOSTNAME"); if(force_hostname) { strncpy(name, force_hostname, namelen); - name[namelen-1] = '\0'; - return 0; + err = 0; + } + else { + name[0] = '\0'; + err = gethostname(name, namelen); } -#endif /* DEBUGBUILD */ +#else /* DEBUGBUILD */ /* The call to system's gethostname() might get intercepted by the libhostname library when libcurl is built as a non-debug shared library when running the test suite. */ - return gethostname(name, namelen); + name[0] = '\0'; + err = gethostname(name, namelen); + +#endif + + name[namelen - 1] = '\0'; + + if(err) + return err; + + /* Truncate domain, leave only machine name */ + dot = strchr(name, '.'); + if(dot) + *dot = '\0'; + return 0; #endif } diff --git a/lib/curl_gethostname.h b/lib/curl_gethostname.h index b8ecf88d6..48740f62a 100644 --- a/lib/curl_gethostname.h +++ b/lib/curl_gethostname.h @@ -22,6 +22,10 @@ * ***************************************************************************/ +/* Hostname buffer size */ +#define HOSTNAME_MAX 1024 + +/* This returns the local machine's un-qualified hostname */ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen); #endif /* HEADER_CURL_GETHOSTNAME_H */ diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c new file mode 100644 index 000000000..b9c8ad0cf --- /dev/null +++ b/lib/curl_gssapi.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#ifdef HAVE_GSSAPI + +#include "curl_gssapi.h" +#include "sendf.h" + +OM_uint32 Curl_gss_init_sec_context( + struct SessionHandle *data, + OM_uint32 * minor_status, + gss_ctx_id_t * context, + gss_name_t target_name, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags) +{ + OM_uint32 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG; + + if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { +#ifdef GSS_C_DELEG_POLICY_FLAG + req_flags |= GSS_C_DELEG_POLICY_FLAG; +#else + infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " + "compiled in\n"); +#endif + } + + if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG) + req_flags |= GSS_C_DELEG_FLAG; + + return gss_init_sec_context(minor_status, + GSS_C_NO_CREDENTIAL, /* cred_handle */ + context, + target_name, + GSS_C_NO_OID, /* mech_type */ + req_flags, + 0, /* time_req */ + input_chan_bindings, + input_token, + NULL, /* actual_mech_type */ + output_token, + ret_flags, + NULL /* time_rec */); +} + +#endif /* HAVE_GSSAPI */ diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h new file mode 100644 index 000000000..fd4596b80 --- /dev/null +++ b/lib/curl_gssapi.h @@ -0,0 +1,57 @@ +#ifndef HEADER_CURL_GSSAPI_H +#define HEADER_CURL_GSSAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" +#include "urldata.h" + +#ifdef HAVE_GSSAPI + +#ifdef HAVE_GSSGNU +# include <gss.h> +#elif defined HAVE_GSSMIT + /* MIT style */ +# include <gssapi/gssapi.h> +# include <gssapi/gssapi_generic.h> +# include <gssapi/gssapi_krb5.h> +#else + /* Heimdal-style */ +# include <gssapi.h> +#endif + + +/* Common method for using gss api */ + +OM_uint32 Curl_gss_init_sec_context( + struct SessionHandle *data, + OM_uint32 * minor_status, + gss_ctx_id_t * context, + gss_name_t target_name, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags); + +#endif /* HAVE_GSSAPI */ + +#endif /* HEADER_CURL_GSSAPI_H */ diff --git a/lib/curl_ntlm.c b/lib/curl_ntlm.c new file mode 100644 index 000000000..c7d67a0de --- /dev/null +++ b/lib/curl_ntlm.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#ifdef USE_NTLM + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#include "urldata.h" +#include "sendf.h" +#include "rawstr.h" +#include "curl_ntlm.h" +#include "curl_ntlm_msgs.h" +#include "curl_ntlm_wb.h" +#include "url.h" +#include "curl_memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +#if defined(USE_NSS) +#include "nssg.h" +#elif defined(USE_WINDOWS_SSPI) +#include "curl_sspi.h" +#endif + +/* The last #include file should be: */ +#include "memdebug.h" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +CURLcode Curl_input_ntlm(struct connectdata *conn, + bool proxy, /* if proxy or not */ + const char *header) /* rest of the www-authenticate: + header */ +{ + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + CURLcode result = CURLE_OK; + +#ifdef USE_NSS + result = Curl_nss_force_init(conn->data); + if(result) + return result; +#endif + + ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; + + /* skip initial whitespaces */ + while(*header && ISSPACE(*header)) + header++; + + if(checkprefix("NTLM", header)) { + header += strlen("NTLM"); + + while(*header && ISSPACE(*header)) + header++; + + if(*header) { + result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm); + if(CURLE_OK != result) + return result; + + ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ + } + else { + if(ntlm->state >= NTLMSTATE_TYPE1) { + infof(conn->data, "NTLM handshake failure (internal error)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ + } + } + + return result; +} + +/* + * This is for creating ntlm header output + */ +CURLcode Curl_output_ntlm(struct connectdata *conn, + bool proxy) +{ + char *base64 = NULL; + size_t len = 0; + CURLcode error; + + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a HTTP proxy */ + char **allocuserpwd; + + /* point to the name and password for this */ + const char *userp; + const char *passwdp; + + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + struct auth *authp; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + +#ifdef USE_NSS + if(CURLE_OK != Curl_nss_force_init(conn->data)) + return CURLE_OUT_OF_MEMORY; +#endif + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + passwdp = conn->passwd; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + +#ifdef USE_WINDOWS_SSPI + if(s_hSecDll == NULL) { + /* not thread safe and leaks - use curl_global_init() to avoid */ + CURLcode err = Curl_sspi_global_init(); + if(s_hSecDll == NULL) + return err; + } +#endif + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: /* for the weird cases we (re)start here */ + /* Create a type-1 message */ + error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64, + &len); + + if(error) + return error; + + if(base64) { + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + free(base64); + } + break; + + case NTLMSTATE_TYPE2: + /* We already received the type-2 message, create a type-3 message */ + error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp, + ntlm, &base64, &len); + if(error) + return error; + + if(base64) { + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + free(base64); + + ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ + authp->done = TRUE; + } + break; + + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + if(*allocuserpwd) { + free(*allocuserpwd); + *allocuserpwd = NULL; + } + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +void Curl_http_ntlm_cleanup(struct connectdata *conn) +{ +#ifdef USE_WINDOWS_SSPI + Curl_ntlm_sspi_cleanup(&conn->ntlm); + Curl_ntlm_sspi_cleanup(&conn->proxyntlm); +#elif defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); +#else + (void)conn; +#endif +} + +#endif /* USE_NTLM */ diff --git a/lib/curl_ntlm.h b/lib/curl_ntlm.h new file mode 100644 index 000000000..b2783778b --- /dev/null +++ b/lib/curl_ntlm.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_NTLM_H +#define HEADER_CURL_NTLM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#ifdef USE_NTLM + +/* this is for ntlm header input */ +CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, + const char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); + +void Curl_http_ntlm_cleanup(struct connectdata *conn); + +#else + +#define Curl_http_ntlm_cleanup(a) Curl_nop_stmt + +#endif + +#endif /* HEADER_CURL_NTLM_H */ diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c new file mode 100644 index 000000000..0be16b474 --- /dev/null +++ b/lib/curl_ntlm_core.c @@ -0,0 +1,379 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#ifdef USE_SSLEAY + +# ifdef USE_OPENSSL +# include <openssl/des.h> +# ifndef OPENSSL_NO_MD4 +# include <openssl/md4.h> +# endif +# include <openssl/md5.h> +# include <openssl/ssl.h> +# include <openssl/rand.h> +# else +# include <des.h> +# ifndef OPENSSL_NO_MD4 +# include <md4.h> +# endif +# include <md5.h> +# include <ssl.h> +# include <rand.h> +# endif +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) +# define DES_key_schedule des_key_schedule +# define DES_cblock des_cblock +# define DES_set_odd_parity des_set_odd_parity +# define DES_set_key des_set_key +# define DES_ecb_encrypt des_ecb_encrypt +# define DESKEY(x) x +# define DESKEYARG(x) x +# else +# define DESKEYARG(x) *x +# define DESKEY(x) &x +# endif + +#elif defined(USE_GNUTLS) + +# include <gcrypt.h> +# define MD5_DIGEST_LENGTH 16 +# define MD4_DIGEST_LENGTH 16 + +#elif defined(USE_NSS) + +# include <nss.h> +# include <pk11pub.h> +# include <hasht.h> +# include "curl_md4.h" +# define MD5_DIGEST_LENGTH MD5_LENGTH + +#else +# error "Can't compile NTLM support without a crypto library." +#endif + +#include "urldata.h" +#include "non-ascii.h" +#include "rawstr.h" +#include "curl_memory.h" +#include "curl_ntlm_core.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifdef USE_SSLEAY +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The + * key schedule ks is also set. + */ +static void setup_des_key(const unsigned char *key_56, + DES_key_schedule DESKEYARG(ks)) +{ + DES_cblock key; + + key[0] = key_56[0]; + key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); + key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); + key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); + key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); + key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); + key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); + key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); + + DES_set_odd_parity(&key); + DES_set_key(&key, ks); +} + +#else /* defined(USE_SSLEAY) */ + +/* + * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. + */ +static void extend_key_56_to_64(const unsigned char *key_56, char *key) +{ + key[0] = key_56[0]; + key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); + key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); + key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); + key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); + key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); + key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); + key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); +} + +#if defined(USE_GNUTLS) + +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. + */ +static void setup_des_key(const unsigned char *key_56, + gcry_cipher_hd_t *des) +{ + char key[8]; + extend_key_56_to_64(key_56, key); + gcry_cipher_setkey(*des, key, 8); +} + +#elif defined(USE_NSS) + +/* + * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using + * the expanded key. The caller is responsible for giving 64 bit of valid + * data is IN and (at least) 64 bit large buffer as OUT. + */ +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ + PK11SlotInfo *slot = NULL; + char key[8]; /* expanded 64 bit key */ + SECItem key_item; + PK11SymKey *symkey = NULL; + SECItem *param = NULL; + PK11Context *ctx = NULL; + int out_len; /* not used, required by NSS */ + bool rv = FALSE; + + /* use internal slot for DES encryption (requires NSS to be initialized) */ + slot = PK11_GetInternalKeySlot(); + if(!slot) + return FALSE; + + /* expand the 56 bit key to 64 bit and wrap by NSS */ + extend_key_56_to_64(key_56, key); + key_item.data = (unsigned char *)key; + key_item.len = /* hard-wired */ 8; + symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, + &key_item, NULL); + if(!symkey) + goto fail; + + /* create DES encryption context */ + param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); + if(!param) + goto fail; + ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); + if(!ctx) + goto fail; + + /* perform the encryption */ + if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, + (unsigned char *)in, /* inbuflen */ 8) + && SECSuccess == PK11_Finalize(ctx)) + rv = /* all OK */ TRUE; + +fail: + /* cleanup */ + if(ctx) + PK11_DestroyContext(ctx, PR_TRUE); + if(symkey) + PK11_FreeSymKey(symkey); + if(param) + SECITEM_FreeItem(param, PR_TRUE); + PK11_FreeSlot(slot); + return rv; +} + +#endif /* defined(USE_NSS) */ + +#endif /* defined(USE_SSLEAY) */ + + /* + * takes a 21 byte array and treats it as 3 56-bit DES keys. The + * 8 byte plaintext is encrypted with each key and the resulting 24 + * bytes are stored in the results array. + */ +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results) +{ +#ifdef USE_SSLEAY + DES_key_schedule ks; + + setup_des_key(keys, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys + 7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8), + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(keys + 14, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16), + DESKEY(ks), DES_ENCRYPT); +#elif defined(USE_GNUTLS) + gcry_cipher_hd_t des; + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys, &des); + gcry_cipher_encrypt(des, results, 8, plaintext, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys + 7, &des); + gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys + 14, &des); + gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); + gcry_cipher_close(des); +#elif defined(USE_NSS) + encrypt_des(plaintext, results, keys); + encrypt_des(plaintext, results + 8, keys + 7); + encrypt_des(plaintext, results + 16, keys + 14); +#endif +} + +/* + * Set up lanmanager hashed password + */ +void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */) +{ + CURLcode res; + unsigned char pw[14]; + static const unsigned char magic[] = { + 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ + }; + size_t len = CURLMIN(strlen(password), 14); + + Curl_strntoupper((char *)pw, password, len); + memset(&pw[len], 0, 14 - len); + + /* + * The LanManager hashed password needs to be created using the + * password in the network encoding not the host encoding. + */ + res = Curl_convert_to_network(data, (char *)pw, 14); + if(res) + return; + + { + /* Create LanManager hashed password. */ + +#ifdef USE_SSLEAY + DES_key_schedule ks; + + setup_des_key(pw, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, + DESKEY(ks), DES_ENCRYPT); + + setup_des_key(pw + 7, DESKEY(ks)); + DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8), + DESKEY(ks), DES_ENCRYPT); +#elif defined(USE_GNUTLS) + gcry_cipher_hd_t des; + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(pw, &des); + gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(pw + 7, &des); + gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); + gcry_cipher_close(des); +#elif defined(USE_NSS) + encrypt_des(magic, lmbuffer, pw); + encrypt_des(magic, lmbuffer + 8, pw + 7); +#endif + + memset(lmbuffer + 16, 0, 21 - 16); + } +} + +#if USE_NTRESPONSES +static void ascii_to_unicode_le(unsigned char *dest, const char *src, + size_t srclen) +{ + size_t i; + for(i = 0; i < srclen; i++) { + dest[2 * i] = (unsigned char)src[i]; + dest[2 * i + 1] = '\0'; + } +} + +/* + * Set up nt hashed passwords + */ +CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, + const char *password, + unsigned char *ntbuffer /* 21 bytes */) +{ + size_t len = strlen(password); + unsigned char *pw = malloc(len * 2); + CURLcode result; + if(!pw) + return CURLE_OUT_OF_MEMORY; + + ascii_to_unicode_le(pw, password, len); + + /* + * The NT hashed password needs to be created using the password in the + * network encoding not the host encoding. + */ + result = Curl_convert_to_network(data, (char *)pw, len * 2); + if(result) + return result; + + { + /* Create NT hashed password. */ +#ifdef USE_SSLEAY + MD4_CTX MD4pw; + MD4_Init(&MD4pw); + MD4_Update(&MD4pw, pw, 2 * len); + MD4_Final(ntbuffer, &MD4pw); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD4pw; + gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); + gcry_md_write(MD4pw, pw, 2 * len); + memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); + gcry_md_close(MD4pw); +#elif defined(USE_NSS) + Curl_md4it(ntbuffer, pw, 2 * len); +#endif + + memset(ntbuffer + 16, 0, 21 - 16); + } + + free(pw); + + return CURLE_OK; +} +#endif /* USE_NTRESPONSES */ + +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h new file mode 100644 index 000000000..5615b3504 --- /dev/null +++ b/lib/curl_ntlm_core.h @@ -0,0 +1,68 @@ +#ifndef HEADER_CURL_NTLM_CORE_H +#define HEADER_CURL_NTLM_CORE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) + +#ifdef USE_SSLEAY +# if !defined(OPENSSL_VERSION_NUMBER) && \ + !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H) +# error "curl_ntlm_core.h shall not be included before OpenSSL headers." +# endif +# ifdef OPENSSL_NO_MD4 +# define USE_NTRESPONSES 0 +# define USE_NTLM2SESSION 0 +# endif +#endif + +/* + * Define USE_NTRESPONSES to 1 in order to make the type-3 message include + * the NT response message. Define USE_NTLM2SESSION to 1 in order to make + * the type-3 message include the NTLM2Session response message, requires + * USE_NTRESPONSES defined to 1. + */ + +#ifndef USE_NTRESPONSES +# define USE_NTRESPONSES 1 +# define USE_NTLM2SESSION 1 +#endif + +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results); + +void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */); + +#if USE_NTRESPONSES +CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, + const char *password, + unsigned char *ntbuffer /* 21 bytes */); +#endif + +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ + +#endif /* HEADER_CURL_NTLM_CORE_H */ diff --git a/lib/curl_ntlm_msgs.c b/lib/curl_ntlm_msgs.c new file mode 100644 index 000000000..bfd3e2814 --- /dev/null +++ b/lib/curl_ntlm_msgs.c @@ -0,0 +1,958 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#ifdef USE_NTLM + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#ifdef USE_SSLEAY + +# ifdef USE_OPENSSL +# include <openssl/des.h> +# ifndef OPENSSL_NO_MD4 +# include <openssl/md4.h> +# endif +# include <openssl/md5.h> +# include <openssl/ssl.h> +# include <openssl/rand.h> +# else +# include <des.h> +# ifndef OPENSSL_NO_MD4 +# include <md4.h> +# endif +# include <md5.h> +# include <ssl.h> +# include <rand.h> +# endif +# include "ssluse.h" + +#elif defined(USE_GNUTLS) + +# include <gcrypt.h> +# include "gtls.h" +# define MD5_DIGEST_LENGTH 16 +# define MD4_DIGEST_LENGTH 16 + +#elif defined(USE_NSS) + +# include <nss.h> +# include <pk11pub.h> +# include <hasht.h> +# include "nssg.h" +# include "curl_md4.h" +# define MD5_DIGEST_LENGTH MD5_LENGTH + +#elif defined(USE_WINDOWS_SSPI) +# include "curl_sspi.h" +#else +# error "Can't compile NTLM support without a crypto library." +#endif + +#include "urldata.h" +#include "non-ascii.h" +#include "sendf.h" +#include "curl_base64.h" +#include "curl_ntlm_core.h" +#include "curl_gethostname.h" +#include "curl_memory.h" + +#define BUILDING_CURL_NTLM_MSGS_C +#include "curl_ntlm_msgs.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + +/* "NTLMSSP" signature is always in ASCII regardless of the platform */ +#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" + +#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) +#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \ + (((x) >> 16) & 0xff), (((x) >> 24) & 0xff) + +#if DEBUG_ME +# define DEBUG_OUT(x) x +static void ntlm_print_flags(FILE *handle, unsigned long flags) +{ + if(flags & NTLMFLAG_NEGOTIATE_UNICODE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); + if(flags & NTLMFLAG_NEGOTIATE_OEM) + fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); + if(flags & NTLMFLAG_REQUEST_TARGET) + fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); + if(flags & (1<<3)) + fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); + if(flags & NTLMFLAG_NEGOTIATE_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); + if(flags & NTLMFLAG_NEGOTIATE_SEAL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); + if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); + if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_NETWARE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); + if(flags & (1<<10)) + fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); + if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); + if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) + fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); + if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) + fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); + if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) + fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); + if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); + if(flags & NTLMFLAG_TARGET_TYPE_SERVER) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); + if(flags & NTLMFLAG_TARGET_TYPE_SHARE) + fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); + if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); + if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) + fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); + if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) + fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); + if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) + fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); + if(flags & (1<<24)) + fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); + if(flags & (1<<25)) + fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); + if(flags & (1<<26)) + fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); + if(flags & (1<<27)) + fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); + if(flags & (1<<28)) + fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); + if(flags & NTLMFLAG_NEGOTIATE_128) + fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); + if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); + if(flags & NTLMFLAG_NEGOTIATE_56) + fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); +} + +static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) +{ + const char *p = buf; + (void)handle; + fprintf(stderr, "0x"); + while(len-- > 0) + fprintf(stderr, "%02.2x", (unsigned int)*p++); +} +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +#ifndef USE_WINDOWS_SSPI +/* + * This function converts from the little endian format used in the + * incoming package to whatever endian format we're using natively. + * Argument is a pointer to a 4 byte buffer. + */ +static unsigned int readint_le(unsigned char *buf) +{ + return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | + ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); +} +#endif + +/* + NTLM message structure notes: + + A 'short' is a 'network short', a little-endian 16-bit unsigned value. + + A 'long' is a 'network long', a little-endian, 32-bit unsigned value. + + A 'security buffer' represents a triplet used to point to a buffer, + consisting of two shorts and one long: + + 1. A 'short' containing the length of the buffer content in bytes. + 2. A 'short' containing the allocated space for the buffer in bytes. + 3. A 'long' containing the offset to the start of the buffer in bytes, + from the beginning of the NTLM message. +*/ + +/* + * Curl_ntlm_decode_type2_message() + * + * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP + * or POP3 server. The message is first decoded from a base64 string into a + * raw ntlm message and checked for validity before the appropriate data for + * creating a type-3 message is written to the given ntlm data structure. + * + * Parameters: + * + * data [in] - Pointer to session handle. + * header [in] - Pointer to the input buffer. + * ntlm [in] - Pointer to ntlm data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, + const char* header, + struct ntlmdata* ntlm) +{ +#ifndef USE_WINDOWS_SSPI + static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; +#endif + + /* NTLM type-2 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x02000000) + 12 Target Name security buffer + 20 Flags long + 24 Challenge 8 bytes + (32) Context 8 bytes (two consecutive longs) (*) + (40) Target Information security buffer (*) + (48) OS Version Structure 8 bytes (*) + 32 (48) (56) Start of data block (*) + (*) -> Optional + */ + + size_t size = 0; + unsigned char *buffer = NULL; + CURLcode error; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI) + (void)data; +#endif + + error = Curl_base64_decode(header, &buffer, &size); + if(error) + return error; + + if(!buffer) { + infof(data, "NTLM handshake failure (unhandled condition)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + +#ifdef USE_WINDOWS_SSPI + ntlm->type_2 = malloc(size + 1); + if(ntlm->type_2 == NULL) { + free(buffer); + return CURLE_OUT_OF_MEMORY; + } + ntlm->n_type_2 = (unsigned long)size; + memcpy(ntlm->type_2, buffer, size); +#else + ntlm->flags = 0; + + if((size < 32) || + (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || + (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) { + /* This was not a good enough type-2 message */ + free(buffer); + infof(data, "NTLM handshake failure (bad type-2 message)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + ntlm->flags = readint_le(&buffer[20]); + memcpy(ntlm->nonce, &buffer[24], 8); + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); + ntlm_print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n nonce="); + ntlm_print_hex(stderr, (char *)ntlm->nonce, 8); + fprintf(stderr, "\n****\n"); + fprintf(stderr, "**** Header %s\n ", header); + }); +#endif + free(buffer); + + return CURLE_OK; +} + +#ifdef USE_WINDOWS_SSPI +void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm) +{ + if(ntlm->type_2) { + free(ntlm->type_2); + ntlm->type_2 = NULL; + } + if(ntlm->has_handles) { + s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); + s_pSecFn->FreeCredentialsHandle(&ntlm->handle); + ntlm->has_handles = 0; + } + if(ntlm->p_identity) { + if(ntlm->identity.User) free(ntlm->identity.User); + if(ntlm->identity.Password) free(ntlm->identity.Password); + if(ntlm->identity.Domain) free(ntlm->identity.Domain); + ntlm->p_identity = NULL; + } +} +#endif + +#ifndef USE_WINDOWS_SSPI +/* copy the source to the destination and fill in zeroes in every + other destination byte! */ +static void unicodecpy(unsigned char *dest, + const char *src, size_t length) +{ + size_t i; + for(i = 0; i < length; i++) { + dest[2 * i] = (unsigned char)src[i]; + dest[2 * i + 1] = '\0'; + } +} +#endif + +/* + * Curl_ntlm_create_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready + * for sending to the recipient, be it a: HTTP, SMTP or POP3 server, + * using the appropriate compile time crypo API. + * + * 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 adress 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_ntlm_create_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen) +{ + /* NTLM type-1 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x01000000) + 12 Flags long + (16) Supplied Domain security buffer (*) + (24) Supplied Workstation security buffer (*) + (32) OS Version Structure 8 bytes (*) + (32) (40) Start of data block (*) + (*) -> Optional + */ + + unsigned char ntlmbuf[NTLM_BUFSIZE]; + size_t size; + +#ifdef USE_WINDOWS_SSPI + + SecBuffer buf; + SecBufferDesc desc; + SECURITY_STATUS status; + ULONG attrs; + const char *dest = ""; + const char *user; + const char *domain = ""; + size_t userlen = 0; + size_t domlen = 0; + size_t passwdlen = 0; + TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ + + Curl_ntlm_sspi_cleanup(ntlm); + + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if(user) { + domain = userp; + domlen = user - userp; + user++; + } + else { + user = userp; + domain = ""; + domlen = 0; + } + + if(user) + userlen = strlen(user); + + if(passwdp) + passwdlen = strlen(passwdp); + + if(userlen > 0) { + /* note: initialize all of this before doing the mallocs so that + * it can be cleaned up later without leaking memory. + */ + ntlm->p_identity = &ntlm->identity; + memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); + if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) + return CURLE_OUT_OF_MEMORY; + + ntlm->identity.UserLength = (unsigned long)userlen; + if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) + return CURLE_OUT_OF_MEMORY; + + ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp); + if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL) + return CURLE_OUT_OF_MEMORY; + + strncpy((char *)ntlm->identity.Domain, domain, domlen); + ntlm->identity.Domain[domlen] = '\0'; + ntlm->identity.DomainLength = (unsigned long)domlen; + ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + } + else + ntlm->p_identity = NULL; + + status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM", + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + &ntlm->handle, &tsDummy); + if(status != SEC_E_OK) + return CURLE_OUT_OF_MEMORY; + + desc.ulVersion = SECBUFFER_VERSION; + desc.cBuffers = 1; + desc.pBuffers = &buf; + buf.cbBuffer = NTLM_BUFSIZE; + buf.BufferType = SECBUFFER_TOKEN; + buf.pvBuffer = ntlmbuf; + + status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL, + (void *)dest, + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, + NULL, 0, + &ntlm->c_handle, &desc, + &attrs, &tsDummy); + + if(status == SEC_I_COMPLETE_AND_CONTINUE || + status == SEC_I_CONTINUE_NEEDED) + s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); + else if(status != SEC_E_OK) { + s_pSecFn->FreeCredentialsHandle(&ntlm->handle); + return CURLE_RECV_ERROR; + } + + ntlm->has_handles = 1; + size = buf.cbBuffer; + +#else + + const char *host = ""; /* empty */ + const char *domain = ""; /* empty */ + size_t hostlen = 0; + size_t domlen = 0; + size_t hostoff = 0; + size_t domoff = hostoff + hostlen; /* This is 0: remember that host and + domain are empty */ + (void)userp; + (void)passwdp; + (void)ntlm; + +#if USE_NTLM2SESSION +#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY +#else +#define NTLM2FLAG 0 +#endif + snprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x01%c%c%c" /* 32-bit type = 1 */ + "%c%c%c%c" /* 32-bit NTLM flag field */ + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host name offset */ + "%c%c" /* 2 zeroes */ + "%s" /* host name */ + "%s", /* domain string */ + 0, /* trailing zero */ + 0, 0, 0, /* part of type-1 long */ + + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0, 0, + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0, 0, + host, /* this is empty */ + domain /* this is empty */); + + /* Initial packet length */ + size = 32 + hostlen + domlen; + +#endif + + DEBUG_OUT({ + fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " + "0x%08.8x ", + LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + ntlm_print_flags(stderr, + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + fprintf(stderr, "\n****\n"); + }); + + /* Return with binary blob encoded into base64 */ + return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); +} + +/* + * Curl_ntlm_create_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready + * for sending to the recipient, be it a: HTTP, SMTP or POP3 server, + * using the appropriate compile time crypo API. + * + * 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 adress 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_ntlm_create_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen) +{ + /* NTLM type-3 message structure: + + Index Description Content + 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" + (0x4e544c4d53535000) + 8 NTLM Message Type long (0x03000000) + 12 LM/LMv2 Response security buffer + 20 NTLM/NTLMv2 Response security buffer + 28 Target Name security buffer + 36 User Name security buffer + 44 Workstation Name security buffer + (52) Session Key security buffer (*) + (60) Flags long (*) + (64) OS Version Structure 8 bytes (*) + 52 (64) (72) Start of data block + (*) -> Optional + */ + + unsigned char ntlmbuf[NTLM_BUFSIZE]; + size_t size; + +#ifdef USE_WINDOWS_SSPI + const char *dest = ""; + SecBuffer type_2; + SecBuffer type_3; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + ULONG attrs; + TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ + + (void)passwdp; + (void)userp; + (void)data; + + type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = type_3_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2; + type_3_desc.pBuffers = &type_3; + + type_2.BufferType = SECBUFFER_TOKEN; + type_2.pvBuffer = ntlm->type_2; + type_2.cbBuffer = ntlm->n_type_2; + type_3.BufferType = SECBUFFER_TOKEN; + type_3.pvBuffer = ntlmbuf; + type_3.cbBuffer = NTLM_BUFSIZE; + + status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, + &ntlm->c_handle, + (void *)dest, + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, &ntlm->c_handle, + &type_3_desc, + &attrs, &tsDummy); + if(status != SEC_E_OK) + return CURLE_RECV_ERROR; + + size = type_3.cbBuffer; + + Curl_ntlm_sspi_cleanup(ntlm); + +#else + int lmrespoff; + unsigned char lmresp[24]; /* fixed-size */ +#if USE_NTRESPONSES + int ntrespoff; + unsigned char ntresp[24]; /* fixed-size */ +#endif + bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE; + char host[HOSTNAME_MAX + 1] = ""; + const char *user; + const char *domain = ""; + size_t hostoff = 0; + size_t useroff = 0; + size_t domoff = 0; + size_t hostlen = 0; + size_t userlen = 0; + size_t domlen = 0; + CURLcode res; + + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if(user) { + domain = userp; + domlen = (user - domain); + user++; + } + else + user = userp; + + if(user) + userlen = strlen(user); + + /* Get the machine's un-qualified host name as NTLM doesn't like the fully + qualified domain name */ + if(Curl_gethostname(host, sizeof(host))) { + infof(data, "gethostname() failed, continuing without!"); + hostlen = 0; + } + else { + hostlen = strlen(host); + } + + if(unicode) { + domlen = domlen * 2; + userlen = userlen * 2; + hostlen = hostlen * 2; + } + +#if USE_NTLM2SESSION + /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ + if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { + unsigned char ntbuffer[0x18]; + unsigned char tmp[0x18]; + unsigned char md5sum[MD5_DIGEST_LENGTH]; + unsigned char entropy[8]; + + /* Need to create 8 bytes random data */ +#ifdef USE_SSLEAY + MD5_CTX MD5pw; + Curl_ossl_seed(data); /* Initiate the seed if not already done */ + RAND_bytes(entropy, 8); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD5pw; + Curl_gtls_seed(data); /* Initiate the seed if not already done */ + gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM); +#elif defined(USE_NSS) + PK11Context *MD5pw; + unsigned int MD5len; + Curl_nss_seed(data); /* Initiate the seed if not already done */ + PK11_GenerateRandom(entropy, 8); +#endif + + /* 8 bytes random data as challenge in lmresp */ + memcpy(lmresp, entropy, 8); + + /* Pad with zeros */ + memset(lmresp + 8, 0, 0x10); + + /* Fill tmp with challenge(nonce?) + entropy */ + memcpy(tmp, &ntlm->nonce[0], 8); + memcpy(tmp + 8, entropy, 8); + +#ifdef USE_SSLEAY + MD5_Init(&MD5pw); + MD5_Update(&MD5pw, tmp, 16); + MD5_Final(md5sum, &MD5pw); +#elif defined(USE_GNUTLS) + gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); + gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH); + memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH); + gcry_md_close(MD5pw); +#elif defined(USE_NSS) + MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); + PK11_DigestOp(MD5pw, tmp, 16); + PK11_DigestFinal(MD5pw, md5sum, &MD5len, MD5_DIGEST_LENGTH); + PK11_DestroyContext(MD5pw, PR_TRUE); +#endif + + /* We shall only use the first 8 bytes of md5sum, but the des + code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ + if(CURLE_OUT_OF_MEMORY == + Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) + return CURLE_OUT_OF_MEMORY; + Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); + + /* End of NTLM2 Session code */ + } + else +#endif + { + +#if USE_NTRESPONSES + unsigned char ntbuffer[0x18]; +#endif + unsigned char lmbuffer[0x18]; + +#if USE_NTRESPONSES + if(CURLE_OUT_OF_MEMORY == + Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) + return CURLE_OUT_OF_MEMORY; + Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); +#endif + + Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); + Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + /* A safer but less compatible alternative is: + * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); + * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ + } + + lmrespoff = 64; /* size of the message header */ +#if USE_NTRESPONSES + ntrespoff = lmrespoff + 0x18; + domoff = ntrespoff + 0x18; +#else + domoff = lmrespoff + 0x18; +#endif + useroff = domoff + domlen; + hostoff = useroff + userlen; + + /* Create the big type-3 message binary blob */ + size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE, + NTLMSSP_SIGNATURE "%c" + "\x03%c%c%c" /* 32-bit type = 3 */ + + "%c%c" /* LanManager length */ + "%c%c" /* LanManager allocated space */ + "%c%c" /* LanManager offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* NT-response length */ + "%c%c" /* NT-response allocated space */ + "%c%c" /* NT-response offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* domain length */ + "%c%c" /* domain allocated space */ + "%c%c" /* domain name offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* user length */ + "%c%c" /* user allocated space */ + "%c%c" /* user offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* host length */ + "%c%c" /* host allocated space */ + "%c%c" /* host offset */ + "%c%c" /* 2 zeroes */ + + "%c%c" /* session key length (unknown purpose) */ + "%c%c" /* session key allocated space (unknown purpose) */ + "%c%c" /* session key offset (unknown purpose) */ + "%c%c" /* 2 zeroes */ + + "%c%c%c%c", /* flags */ + + /* domain string */ + /* user string */ + /* host string */ + /* LanManager response */ + /* NT response */ + + 0, /* zero termination */ + 0, 0, 0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, + +#if USE_NTRESPONSES + SHORTPAIR(0x18), /* NT-response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(ntrespoff), + 0x0, 0x0, +#else + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, +#endif + SHORTPAIR(domlen), + SHORTPAIR(domlen), + SHORTPAIR(domoff), + 0x0, 0x0, + + SHORTPAIR(userlen), + SHORTPAIR(userlen), + SHORTPAIR(useroff), + 0x0, 0x0, + + SHORTPAIR(hostlen), + SHORTPAIR(hostlen), + SHORTPAIR(hostoff), + 0x0, 0x0, + + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + + LONGQUARTET(ntlm->flags)); + + DEBUGASSERT(size == 64); + DEBUGASSERT(size == (size_t)lmrespoff); + + /* We append the binary hashes */ + if(size < (NTLM_BUFSIZE - 0x18)) { + memcpy(&ntlmbuf[size], lmresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "**** TYPE3 header lmresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); + }); + +#if USE_NTRESPONSES + if(size < (NTLM_BUFSIZE - 0x18)) { + DEBUGASSERT(size == (size_t)ntrespoff); + memcpy(&ntlmbuf[size], ntresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "\n ntresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); + }); + +#endif + + DEBUG_OUT({ + fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", + LONGQUARTET(ntlm->flags), ntlm->flags); + ntlm_print_flags(stderr, ntlm->flags); + fprintf(stderr, "\n****\n"); + }); + + /* Make sure that the domain, user and host strings fit in the + buffer before we copy them there. */ + if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) { + failf(data, "user + domain + host name too big"); + return CURLE_OUT_OF_MEMORY; + } + + DEBUGASSERT(size == domoff); + if(unicode) + unicodecpy(&ntlmbuf[size], domain, domlen / 2); + else + memcpy(&ntlmbuf[size], domain, domlen); + + size += domlen; + + DEBUGASSERT(size == useroff); + if(unicode) + unicodecpy(&ntlmbuf[size], user, userlen / 2); + else + memcpy(&ntlmbuf[size], user, userlen); + + size += userlen; + + DEBUGASSERT(size == hostoff); + if(unicode) + unicodecpy(&ntlmbuf[size], host, hostlen / 2); + else + memcpy(&ntlmbuf[size], host, hostlen); + + size += hostlen; + + /* Convert domain, user, and host to ASCII but leave the rest as-is */ + res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], + size - domoff); + if(res) + return CURLE_CONV_FAILED; + +#endif + + /* Return with binary blob encoded into base64 */ + return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); +} + +#endif /* USE_NTLM */ diff --git a/lib/http_ntlm.h b/lib/curl_ntlm_msgs.h index c7422d701..7acf7229f 100644 --- a/lib/http_ntlm.h +++ b/lib/curl_ntlm_msgs.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_NTLM_H -#define __HTTP_NTLM_H +#ifndef HEADER_CURL_NTLM_MSGS_H +#define HEADER_CURL_NTLM_MSGS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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,26 +22,42 @@ * ***************************************************************************/ -typedef enum { - CURLNTLM_NONE, /* not a ntlm */ - CURLNTLM_BAD, /* an ntlm, but one we don't like */ - CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */ - CURLNTLM_FINE, /* an ntlm we act on */ - - CURLNTLM_LAST /* last entry in this enum, don't use */ -} CURLntlm; - -/* this is for ntlm header input */ -CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, - const char *header); +#include "setup.h" + +#ifdef USE_NTLM + +/* This is to generate a base64 encoded NTLM type-1 message */ +CURLcode Curl_ntlm_create_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is to generate a base64 encoded NTLM type-3 message */ +CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is to decode a NTLM type-2 message */ +CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, + const char* header, + struct ntlmdata* ntlm); + +/* This is to clean up the ntlm data structure */ +#ifdef USE_WINDOWS_SSPI +void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm); +#else +#define Curl_ntlm_sspi_cleanup(x) +#endif -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); +/* NTLM buffer fixed size, large enough for long user + host + domain */ +#define NTLM_BUFSIZE 1024 -void Curl_ntlm_cleanup(struct connectdata *conn); -#ifndef USE_NTLM -#define Curl_ntlm_cleanup(x) -#endif +/* Stuff only required for curl_ntlm_msgs.c */ +#ifdef BUILDING_CURL_NTLM_MSGS_C /* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ @@ -146,4 +162,9 @@ void Curl_ntlm_cleanup(struct connectdata *conn); #define NTLMFLAG_NEGOTIATE_56 (1<<31) /* Indicates that 56-bit encryption is supported. */ -#endif + +#endif /* BUILDING_CURL_NTLM_MSGS_C */ + +#endif /* USE_NTLM */ + +#endif /* HEADER_CURL_NTLM_MSGS_H */ diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c new file mode 100644 index 000000000..18d0d13f8 --- /dev/null +++ b/lib/curl_ntlm_wb.c @@ -0,0 +1,394 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#include "urldata.h" +#include "sendf.h" +#include "select.h" +#include "curl_ntlm_wb.h" +#include "url.h" +#include "strerror.h" +#include "curl_memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + +#if DEBUG_ME +# define DEBUG_OUT(x) x +#else +# define DEBUG_OUT(x) Curl_nop_stmt +#endif + +/* Portable 'sclose_nolog' used only in child process instead of 'sclose' + to avoid fooling the socket leak detector */ +#if defined(HAVE_CLOSESOCKET) +# define sclose_nolog(x) closesocket((x)) +#elif defined(HAVE_CLOSESOCKET_CAMEL) +# define sclose_nolog(x) CloseSocket((x)) +#else +# define sclose_nolog(x) close((x)) +#endif + +void Curl_ntlm_wb_cleanup(struct connectdata *conn) +{ + if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { + sclose(conn->ntlm_auth_hlpr_socket); + conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + } + + if(conn->ntlm_auth_hlpr_pid) { + int i; + for(i = 0; i < 4; i++) { + pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG); + if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD) + break; + switch(i) { + case 0: + kill(conn->ntlm_auth_hlpr_pid, SIGTERM); + break; + case 1: + /* Give the process another moment to shut down cleanly before + bringing down the axe */ + Curl_wait_ms(1); + break; + case 2: + kill(conn->ntlm_auth_hlpr_pid, SIGKILL); + break; + case 3: + break; + } + } + conn->ntlm_auth_hlpr_pid = 0; + } + + Curl_safefree(conn->challenge_header); + conn->challenge_header = NULL; + Curl_safefree(conn->response_header); + conn->response_header = NULL; +} + +static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) +{ + curl_socket_t sockfds[2]; + pid_t child_pid; + const char *username; + char *slash, *domain = NULL; + const char *ntlm_auth = NULL; + char *ntlm_auth_alloc = NULL; + int error; + + /* Return if communication with ntlm_auth already set up */ + if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || + conn->ntlm_auth_hlpr_pid) + return CURLE_OK; + + username = userp; + slash = strpbrk(username, "\\/"); + if(slash) { + if((domain = strdup(username)) == NULL) + return CURLE_OUT_OF_MEMORY; + slash = domain + (slash - username); + *slash = '\0'; + username = username + (slash - domain) + 1; + } + + /* For testing purposes, when DEBUGBUILD is defined and environment + variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform + NTLM challenge/response which only accepts commands and output + strings pre-written in test case definitions */ +#ifdef DEBUGBUILD + ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE"); + if(ntlm_auth_alloc) + ntlm_auth = ntlm_auth_alloc; + else +#endif + ntlm_auth = NTLM_WB_FILE; + + if(access(ntlm_auth, X_OK) != 0) { + error = ERRNO; + failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s", + ntlm_auth, error, Curl_strerror(conn, error)); + goto done; + } + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { + error = ERRNO; + failf(conn->data, "Could not open socket pair. errno %d: %s", + error, Curl_strerror(conn, error)); + goto done; + } + + child_pid = fork(); + if(child_pid == -1) { + error = ERRNO; + sclose(sockfds[0]); + sclose(sockfds[1]); + failf(conn->data, "Could not fork. errno %d: %s", + error, Curl_strerror(conn, error)); + goto done; + } + else if(!child_pid) { + /* + * child process + */ + + /* Don't use sclose in the child since it fools the socket leak detector */ + sclose_nolog(sockfds[0]); + if(dup2(sockfds[1], STDIN_FILENO) == -1) { + error = ERRNO; + failf(conn->data, "Could not redirect child stdin. errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + if(dup2(sockfds[1], STDOUT_FILENO) == -1) { + error = ERRNO; + failf(conn->data, "Could not redirect child stdout. errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + if(domain) + execl(ntlm_auth, ntlm_auth, + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + "--domain", domain, + NULL); + else + execl(ntlm_auth, ntlm_auth, + "--helper-protocol", "ntlmssp-client-1", + "--use-cached-creds", + "--username", username, + NULL); + + error = ERRNO; + sclose_nolog(sockfds[1]); + failf(conn->data, "Could not execl(). errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + sclose(sockfds[1]); + conn->ntlm_auth_hlpr_socket = sockfds[0]; + conn->ntlm_auth_hlpr_pid = child_pid; + Curl_safefree(domain); + Curl_safefree(ntlm_auth_alloc); + return CURLE_OK; + +done: + Curl_safefree(domain); + Curl_safefree(ntlm_auth_alloc); + return CURLE_REMOTE_ACCESS_DENIED; +} + +static CURLcode ntlm_wb_response(struct connectdata *conn, + const char *input, curlntlm state) +{ + ssize_t size; + char buf[200]; /* enough, type 1, 3 message length is less then 200 */ + char *tmpbuf = buf; + size_t len_in = strlen(input), len_out = sizeof(buf); + + while(len_in > 0) { + ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in); + if(written == -1) { + /* Interrupted by a signal, retry it */ + if(errno == EINTR) + continue; + /* write failed if other errors happen */ + goto done; + } + input += written; + len_in -= written; + } + /* Read one line */ + while(len_out > 0) { + size = sread(conn->ntlm_auth_hlpr_socket, tmpbuf, len_out); + if(size == -1) { + if(errno == EINTR) + continue; + goto done; + } + else if(size == 0) + goto done; + else if(tmpbuf[size - 1] == '\n') { + tmpbuf[size - 1] = '\0'; + goto wrfinish; + } + tmpbuf += size; + len_out -= size; + } + goto done; +wrfinish: + /* Samba/winbind installed but not configured */ + if(state == NTLMSTATE_TYPE1 && + size == 3 && + buf[0] == 'P' && buf[1] == 'W') + return CURLE_REMOTE_ACCESS_DENIED; + /* invalid response */ + if(size < 4) + goto done; + if(state == NTLMSTATE_TYPE1 && + (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) + goto done; + if(state == NTLMSTATE_TYPE2 && + (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && + (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) + goto done; + + conn->response_header = aprintf("NTLM %.*s", size - 4, buf + 3); + return CURLE_OK; +done: + return CURLE_REMOTE_ACCESS_DENIED; +} + +/* + * This is for creating ntlm header output by delegating challenge/response + * to Samba's winbind daemon helper ntlm_auth. + */ +CURLcode Curl_output_ntlm_wb(struct connectdata *conn, + bool proxy) +{ + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a HTTP proxy */ + char **allocuserpwd; + /* point to the name and password for this */ + const char *userp; + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + struct auth *authp; + + CURLcode res = CURLE_OK; + char *input; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp=""; + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: + /* Use Samba's 'winbind' daemon to support NTLM authentication, + * by delegating the NTLM challenge/response protocal to a helper + * in ntlm_auth. + * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html + * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html + * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html + * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this + * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute + * filename of ntlm_auth helper. + * If NTLM authentication using winbind fails, go back to original + * request handling process. + */ + /* Create communication with ntlm_auth */ + res = ntlm_wb_init(conn, userp); + if(res) + return res; + res = ntlm_wb_response(conn, "YR\n", ntlm->state); + if(res) + return res; + + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + proxy ? "Proxy-" : "", + conn->response_header); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + Curl_safefree(conn->response_header); + conn->response_header = NULL; + break; + case NTLMSTATE_TYPE2: + input = aprintf("TT %s", conn->challenge_header); + if(!input) + return CURLE_OUT_OF_MEMORY; + res = ntlm_wb_response(conn, input, ntlm->state); + free(input); + input = NULL; + if(res) + return res; + + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + proxy ? "Proxy-" : "", + conn->response_header); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ + authp->done = TRUE; + Curl_ntlm_wb_cleanup(conn); + break; + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + if(*allocuserpwd) { + free(*allocuserpwd); + *allocuserpwd=NULL; + } + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +#endif /* USE_NTLM && NTLM_WB_ENABLED */ diff --git a/lib/curl_ntlm_wb.h b/lib/curl_ntlm_wb.h new file mode 100644 index 000000000..e3eaffe17 --- /dev/null +++ b/lib/curl_ntlm_wb.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CURL_NTLM_WB_H +#define HEADER_CURL_NTLM_WB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. + * + * 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 "setup.h" + +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + +/* this is for creating ntlm header output by delegating challenge/response + to Samba's winbind daemon helper ntlm_auth */ +CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy); + +void Curl_ntlm_wb_cleanup(struct connectdata *conn); + +#endif /* USE_NTLM && NTLM_WB_ENABLED */ + +#endif /* HEADER_CURL_NTLM_WB_H */ diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c index 44b7e1524..725b8f995 100644 --- a/lib/curl_rtmp.c +++ b/lib/curl_rtmp.c @@ -71,6 +71,7 @@ const struct Curl_handler Curl_handler_rtmp = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -90,6 +91,7 @@ const struct Curl_handler Curl_handler_rtmpt = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -109,6 +111,7 @@ const struct Curl_handler Curl_handler_rtmpe = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -128,6 +131,7 @@ const struct Curl_handler Curl_handler_rtmpte = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -147,6 +151,7 @@ const struct Curl_handler Curl_handler_rtmps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -166,6 +171,7 @@ const struct Curl_handler Curl_handler_rtmpts = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ diff --git a/lib/curl_threads.c b/lib/curl_threads.c index e9636440f..411ccc81d 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -19,6 +19,7 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #if defined(USE_THREADS_POSIX) diff --git a/lib/cyassl.c b/lib/cyassl.c index 81bcabaa1..cda18a8cb 100644 --- a/lib/cyassl.c +++ b/lib/cyassl.c @@ -27,16 +27,17 @@ */ #include "setup.h" + #ifdef USE_CYASSL -#include <string.h> -#include <stdlib.h> -#include <ctype.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif - #include "urldata.h" #include "sendf.h" #include "inet_pton.h" @@ -412,7 +413,7 @@ int Curl_cyassl_init(void) bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex) { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (bool)(0 != SSL_pending(conn->ssl[connindex].handle)); + return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; else return FALSE; } diff --git a/lib/cyassl.h b/lib/cyassl.h index a21592a28..56d68066f 100644 --- a/lib/cyassl.h +++ b/lib/cyassl.h @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #ifdef USE_CYASSL @@ -45,7 +46,7 @@ CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, /* API setup for CyaSSL */ #define curlssl_init Curl_cyassl_init -#define curlssl_cleanup() +#define curlssl_cleanup() Curl_nop_stmt #define curlssl_connect Curl_cyassl_connect #define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking #define curlssl_session_free(x) Curl_cyassl_session_free(x) diff --git a/lib/dict.c b/lib/dict.c index 0baaeec3a..b326054d1 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -24,28 +24,18 @@ #ifndef CURL_DISABLE_DICT -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -64,9 +54,6 @@ #include <sys/select.h> #endif - -#endif - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -105,6 +92,7 @@ const struct Curl_handler Curl_handler_dict = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ diff --git a/lib/easy.c b/lib/easy.c index ac037d266..60a55edf8 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -22,29 +22,12 @@ #include "setup.h" -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - -#include "strequal.h" - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -65,8 +48,7 @@ #include <sys/param.h> #endif -#endif /* WIN32 ... */ - +#include "strequal.h" #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -81,7 +63,7 @@ #include "easyif.h" #include "select.h" #include "sendf.h" /* for failf function prototype */ -#include "http_ntlm.h" +#include "curl_ntlm.h" #include "connect.h" /* for Curl_getconnectinfo */ #include "slist.h" #include "curl_rand.h" @@ -143,6 +125,8 @@ static CURLcode win32_init(void) return CURLE_FAILED_INIT; } /* The Windows Sockets DLL is acceptable. Proceed. */ +#elif defined(USE_LWIPSOCK) + lwip_init(); #endif #ifdef USE_WINDOWS_SSPI @@ -692,16 +676,15 @@ CURL *curl_easy_duphandle(CURL *incurl) if(outcurl) { if(outcurl->state.connc && - (outcurl->state.connc->type == CONNCACHE_PRIVATE)) + (outcurl->state.connc->type == CONNCACHE_PRIVATE)) { Curl_rm_connc(outcurl->state.connc); - if(outcurl->state.headerbuff) - free(outcurl->state.headerbuff); - if(outcurl->change.cookielist) - curl_slist_free_all(outcurl->change.cookielist); - if(outcurl->change.url) - free(outcurl->change.url); - if(outcurl->change.referer) - free(outcurl->change.referer); + outcurl->state.connc = NULL; + } + curl_slist_free_all(outcurl->change.cookielist); + outcurl->change.cookielist = NULL; + Curl_safefree(outcurl->state.headerbuff); + Curl_safefree(outcurl->change.url); + Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); free(outcurl); } @@ -718,10 +701,10 @@ void curl_easy_reset(CURL *curl) struct SessionHandle *data = (struct SessionHandle *)curl; Curl_safefree(data->state.pathbuffer); - data->state.pathbuffer=NULL; + + data->state.path = NULL; Curl_safefree(data->state.proto.generic); - data->state.proto.generic=NULL; /* zero out UserDefined data: */ Curl_freeset(data); diff --git a/lib/escape.c b/lib/escape.c index 5500a92bf..b0922bc93 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -24,12 +24,9 @@ * allocated string or NULL if an error occurred. */ #include "setup.h" -#include <ctype.h> + #include <curl/curl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include "curl_memory.h" #include "urldata.h" #include "warnless.h" diff --git a/lib/file.c b/lib/file.c index 4f3ea1bb4..00d5fc09b 100644 --- a/lib/file.c +++ b/lib/file.c @@ -23,27 +23,13 @@ #include "setup.h" #ifndef CURL_DISABLE_FILE -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#include <fcntl.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -68,8 +54,6 @@ #include <fcntl.h> #endif -#endif /* WIN32 */ - #include "strtoofft.h" #include "urldata.h" #include <curl/curl.h> @@ -83,6 +67,7 @@ #include "url.h" #include "curl_memory.h" #include "parsedate.h" /* for the week day and month names */ +#include "warnless.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -109,6 +94,9 @@ static CURLcode file_do(struct connectdata *, bool *done); static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode file_connect(struct connectdata *conn, bool *done); +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection); + /* * FILE scheme handler. @@ -125,8 +113,9 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ + file_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ 0, /* defport */ CURLPROTO_FILE, /* protocol */ @@ -222,10 +211,9 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) /* file is not a protocol that can deal with "persistancy" */ file = data->state.proto.file; Curl_safefree(file->freepath); + file->path = NULL; if(file->fd != -1) close(file->fd); - file->path = NULL; - file->freepath = NULL; file->fd = -1; } @@ -282,10 +270,31 @@ static CURLcode file_done(struct connectdata *conn, struct FILEPROTO *file = conn->data->state.proto.file; (void)status; /* not used */ (void)premature; /* not used */ - Curl_safefree(file->freepath); - if(file->fd != -1) - close(file->fd); + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } + + return CURLE_OK; +} + +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection) +{ + struct FILEPROTO *file = conn->data->state.proto.file; + (void)dead_connection; /* not used */ + + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } return CURLE_OK; } @@ -438,7 +447,6 @@ static CURLcode file_do(struct connectdata *conn, bool *done) curl_off_t expected_size=0; bool fstated=FALSE; ssize_t nread; - size_t bytestoread; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; @@ -560,7 +568,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done) while(res == CURLE_OK) { /* Don't fill a whole buffer if we want less than all data */ - bytestoread = (expected_size < BUFSIZE-1)?(size_t)expected_size:BUFSIZE-1; + size_t bytestoread = + (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? + curlx_sotouz(expected_size) : BUFSIZE - 1; + nread = read(fd, buf, bytestoread); if(nread > 0) diff --git a/lib/fileinfo.c b/lib/fileinfo.c index 5495f560d..4ffcbbe29 100644 --- a/lib/fileinfo.c +++ b/lib/fileinfo.c @@ -22,7 +22,6 @@ #include "setup.h" -#include <stdlib.h> #include "strdup.h" #include "fileinfo.h" @@ -49,9 +48,7 @@ void Curl_fileinfo_dtor(void *user, void *element) if(!finfo) return; - if(finfo->b_data){ - free(finfo->b_data); - } + Curl_safefree(finfo->b_data); free(finfo); } diff --git a/lib/formdata.c b/lib/formdata.c index aa5a79ac1..cbef51171 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include <curl/curl.h> /* Length of the random boundary string. */ @@ -28,14 +29,10 @@ #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include <libgen.h> #endif + #include "urldata.h" /* for struct SessionHandle */ #include "formdata.h" #include "curl_rand.h" @@ -462,7 +459,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(current_form->flags & HTTPPOST_FILENAME) { if(filename) { if((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) + NULL, current_form)) == NULL) return_value = CURL_FORMADD_MEMORY; } else @@ -487,46 +484,18 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } - case CURLFORM_BUFFER: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - - if(current_form->value) { - if(current_form->flags & HTTPPOST_BUFFER) { - if(filename) { - if((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - } - else - return_value = CURL_FORMADD_OPTION_TWICE; - } - else { - if(filename) { - current_form->value = strdup(filename); - if(!current_form->value) - return_value = CURL_FORMADD_MEMORY; - } - else - return_value = CURL_FORMADD_NULL; - current_form->flags |= HTTPPOST_BUFFER; - } - break; - } - case CURLFORM_BUFFERPTR: - current_form->flags |= HTTPPOST_PTRBUFFER; + current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER; if(current_form->buffer) return_value = CURL_FORMADD_OPTION_TWICE; else { char *buffer = array_state?array_value:va_arg(params, char *); - if(buffer) + if(buffer) { current_form->buffer = buffer; /* store for the moment */ + current_form->value = buffer; /* make it non-NULL to be accepted + as fine */ + } else return_value = CURL_FORMADD_NULL; } @@ -567,8 +536,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(current_form->flags & HTTPPOST_FILENAME) { if(contenttype) { if((current_form = AddFormInfo(NULL, - strdup(contenttype), - current_form)) == NULL) + strdup(contenttype), + current_form)) == NULL) return_value = CURL_FORMADD_MEMORY; } else @@ -606,6 +575,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } case CURLFORM_FILENAME: + case CURLFORM_BUFFER: { const char *filename = array_state?array_value: va_arg(params, char *); @@ -622,6 +592,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } default: return_value = CURL_FORMADD_UNKNOWN_OPTION; + break; } } @@ -884,10 +855,11 @@ int curl_formget(struct curl_httppost *form, void *arg, do { nread = readfromfile(&temp, buffer, sizeof(buffer)); - if((nread == (size_t) -1) || (nread != append(arg, buffer, nread))) { - if(temp.fp) { + if((nread == (size_t) -1) || + (nread > sizeof(buffer)) || + (nread != append(arg, buffer, nread))) { + if(temp.fp) fclose(temp.fp); - } Curl_formclean(&data); return -1; } @@ -925,7 +897,8 @@ void curl_formfree(struct curl_httppost *form) if(!(form->flags & HTTPPOST_PTRNAME) && form->name) free(form->name); /* free the name */ - if(!(form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_CALLBACK)) && + if(!(form->flags & + (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) && form->contents) free(form->contents); /* free the contents */ if(form->contenttype) @@ -1297,22 +1270,24 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata ) return 0; } +/* + * readfromfile() + * + * The read callback that this function may use can return a value larger than + * 'size' (which then this function returns) that indicates a problem and it + * must be properly dealt with + */ static size_t readfromfile(struct Form *form, char *buffer, size_t size) { size_t nread; - bool callback = (bool)(form->data->type == FORM_CALLBACK); + bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE; if(callback) { if(form->fread_func == ZERO_NULL) return 0; else nread = form->fread_func(buffer, 1, size, form->data->line); - - if(nread > size) - /* the read callback can return a value larger than the buffer but - treat any such as no data in this case */ - nread = 0; } else { if(!form->fp) { @@ -23,11 +23,6 @@ #include "setup.h" #ifndef CURL_DISABLE_FTP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -109,7 +104,7 @@ #endif #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define ftp_pasv_verbose(a,b,c,d) do { } while(0) +#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt #endif /* Local API functions */ @@ -139,9 +134,10 @@ static CURLcode ftp_connect(struct connectdata *conn, bool *done); static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode ftp_nextconnect(struct connectdata *conn); static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); -static int ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode ftp_setup_connection(struct connectdata * conn); @@ -176,6 +172,7 @@ const struct Curl_handler Curl_handler_ftp = { ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -201,6 +198,7 @@ const struct Curl_handler Curl_handler_ftps = { ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -227,6 +225,7 @@ static const struct Curl_handler Curl_handler_ftp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -252,6 +251,7 @@ static const struct Curl_handler Curl_handler_ftps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -279,7 +279,7 @@ static void freedirs(struct ftp_conn *ftpc) { int i; if(ftpc->dirs) { - for(i=0; i < ftpc->dirdepth; i++){ + for(i=0; i < ftpc->dirdepth; i++) { if(ftpc->dirs[i]) { free(ftpc->dirs[i]); ftpc->dirs[i]=NULL; @@ -303,8 +303,8 @@ static void freedirs(struct ftp_conn *ftpc) */ static bool isBadFtpString(const char *string) { - return (bool)((NULL != strchr(string, '\r')) || - (NULL != strchr(string, '\n'))); + return ((NULL != strchr(string, '\r')) || + (NULL != strchr(string, '\n'))) ? TRUE : FALSE; } /*********************************************************************** @@ -639,6 +639,37 @@ static int ftp_getsock(struct connectdata *conn, return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); } +/* For the FTP "DO_MORE" phase only */ +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(!numsocks) + return GETSOCK_BLANK; + + /* When in DO_MORE state, we could be either waiting for us to connect to a + remote site, or we could wait for that site to connect to us. Or just + handle ordinary commands. + + When waiting for a connect, we will be in FTP_STOP state and then we wait + for the secondary socket to become writeable. If we're in another state, + we're still handling commands on the control (primary) connection. + + */ + + switch(ftpc->state) { + case FTP_STOP: + break; + default: + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); + } + + socks[0] = conn->sock[SECONDARYSOCKET]; + + return GETSOCK_READSOCK(0); +} + /* This is called after the FTP_QUOTE state is passed. ftp_state_cwd() sends the range of CWD commands to the server to change to @@ -810,7 +841,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, host = addr; else host = hbuf; /* use the hbuf for host name */ - }else + } + else /* there was only a port(-range) given, default the host */ host = NULL; } /* data->set.ftpport */ @@ -857,7 +889,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, free(addr); if(res == NULL) { - failf(data, "Curl_resolv failed, we can not recover!"); + failf(data, "failed to resolve the address provided to PORT: %s", host); return CURLE_FTP_PORT_FAILED; } @@ -1004,8 +1036,16 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], sa->sa_family == AF_INET?1:2, myhost, port); - if(result) + if(result) { + failf(data, "Failure sending EPRT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* don't retry using PORT */ + ftpc->count1 = PORT; + /* bail out */ + state(conn, FTP_STOP); return result; + } break; } else if(PORT == fcmd) { @@ -1025,8 +1065,14 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); - if(result) + if(result) { + failf(data, "Failure sending PORT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* bail out */ + state(conn, FTP_STOP); return result; + } break; } } @@ -1048,7 +1094,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, The *proper* fix is to make sure that the active connection from the server is done in a non-blocking way. Currently, it is still BLOCKING. */ - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; state(conn, FTP_PORT); return result; @@ -1234,13 +1280,16 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; } - PPSENDF(&conn->proto.ftpc.pp, "%s",cmd); + result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); if(lstArg) free(lstArg); free(cmd); + if(result != CURLE_OK) + return result; + state(conn, FTP_LIST); return result; @@ -1708,7 +1757,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, if(result) return result; - conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */ + conn->bits.tcpconnect[SECONDARYSOCKET] = connected; /* * When this is used from the multi interface, this might've returned with @@ -1746,6 +1795,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, break; } + if(result) + return result; + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { /* FIX: this MUST wait for a proper connect first if 'connected' is * FALSE */ @@ -1768,10 +1820,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, data->state.proto.ftp = ftp_save; - if(CURLE_OK != result) + if(result) return result; } + conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; state(conn, FTP_STOP); /* this phase is completed */ @@ -2528,7 +2581,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(ftpcode/100 == 2) /* We have enabled SSL for the data connection! */ conn->ssl[SECONDARYSOCKET].use = - (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL); + (data->set.ftp_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; /* FTP servers typically responds with 500 if they decide to reject our 'P' request */ else if(data->set.ftp_ssl > CURLUSESSL_CONTROL) @@ -2604,12 +2657,6 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) store++; ptr++; } - if(ftpc->entrypath) - free(ftpc->entrypath); - ftpc->entrypath =dir; /* remember this */ - infof(data, "Entry path is '%s'\n", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; /* If the path name does not look like an absolute path (i.e.: it does not start with a '/'), we probably need some server-dependent @@ -2623,11 +2670,27 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if the path name looks strange to minimize overhead on other systems. */ - if(!ftpc->server_os && ftpc->entrypath[0] != '/') { - PPSENDF(&ftpc->pp, "SYST", NULL); + if(!ftpc->server_os && dir[0] != '/') { + + result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL); + if(result != CURLE_OK) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; state(conn, FTP_SYST); break; } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; } else { /* couldn't get the path */ @@ -2657,19 +2720,28 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) for(store = os; *ptr && *ptr != ' ';) *store++ = *ptr++; *store = '\0'; /* zero terminate */ - ftpc->server_os = os; /* Check for special servers here. */ - if(strequal(ftpc->server_os, "OS/400")) { + if(strequal(os, "OS/400")) { /* Force OS400 name format 1. */ - PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL); + result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL); + if(result != CURLE_OK) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; state(conn, FTP_NAMEFMT); break; } - else { - /* Nothing special for the target server. */ - } + else { + /* Nothing special for the target server. */ + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; + } } else { /* Cannot identify server OS. Continue anyway and cross fingers. */ @@ -2820,7 +2892,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, /* Check for the state outside of the Curl_socket_ready() return code checks since at times we are in fact already in this state when this function gets called. */ - *done = (bool)(ftpc->state == FTP_STOP); + *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; return result; } @@ -2874,9 +2946,9 @@ static CURLcode ftp_init(struct connectdata *conn) */ ftp->user = conn->user; ftp->passwd = conn->passwd; - if(TRUE == isBadFtpString(ftp->user)) + if(isBadFtpString(ftp->user)) return CURLE_URL_MALFORMAT; - if(TRUE == isBadFtpString(ftp->passwd)) + if(isBadFtpString(ftp->passwd)) return CURLE_URL_MALFORMAT; conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ @@ -3478,7 +3550,7 @@ CURLcode ftp_perform(struct connectdata *conn, result = ftp_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -3631,8 +3703,7 @@ static CURLcode wc_statemach(struct connectdata *conn) strcat(tmp_path, finfo->filename); /* switch default "state.pathbuffer" and tmp_path, good to see ftp_parse_url_path function to understand this trick */ - if(conn->data->state.pathbuffer) - free(conn->data->state.pathbuffer); + Curl_safefree(conn->data->state.pathbuffer); conn->data->state.pathbuffer = tmp_path; conn->data->state.path = tmp_path; @@ -4099,12 +4170,13 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, /* called from multi.c while DOing */ static CURLcode ftp_doing(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { - CURLcode result; - result = ftp_multi_statemach(conn, dophase_done); + CURLcode result = ftp_multi_statemach(conn, dophase_done); - if(*dophase_done) { + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { result = ftp_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index a3fef3971..bbf6e9ef9 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -37,8 +37,6 @@ #include "setup.h" -#include <time.h> - #include "ftplistparser.h" #include "curl_fnmatch.h" diff --git a/lib/getenv.c b/lib/getenv.c index 36fbb7583..6b40dd68d 100644 --- a/lib/getenv.c +++ b/lib/getenv.c @@ -22,10 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #ifdef __VMS #include <unixlib.h> #endif diff --git a/lib/getinfo.c b/lib/getinfo.c index bb289741a..aa7af2c86 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -27,10 +27,6 @@ #include "urldata.h" #include "getinfo.h" -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> #include "curl_memory.h" #include "sslgen.h" #include "connect.h" /* Curl_getconnectinfo() */ diff --git a/lib/gopher.c b/lib/gopher.c index b2d2689d1..b4efae8cc 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -24,28 +24,18 @@ #ifndef CURL_DISABLE_GOPHER -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -64,9 +54,6 @@ #include <sys/select.h> #endif - -#endif - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -110,6 +97,7 @@ const struct Curl_handler Curl_handler_gopher = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ diff --git a/lib/gtls.c b/lib/gtls.c index a376fb0b9..7ca46c812 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -29,14 +29,13 @@ */ #include "setup.h" + #ifdef USE_GNUTLS + #include <gnutls/gnutls.h> #include <gnutls/x509.h> #include <gcrypt.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -477,8 +476,10 @@ gtls_connect_step1(struct connectdata *conn, gnutls_transport_set_push_function(session, Curl_gtls_push); gnutls_transport_set_pull_function(session, Curl_gtls_pull); +#if GNUTLS_VERSION_NUMBER < 0x020c00 /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); +#endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ diff --git a/lib/gtls.h b/lib/gtls.h index 6275b49a3..733122e6c 100644 --- a/lib/gtls.h +++ b/lib/gtls.h @@ -1,5 +1,5 @@ -#ifndef __GTLS_H -#define __GTLS_H +#ifndef HEADER_CURL_GTLS_H +#define HEADER_CURL_GTLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -22,8 +22,12 @@ * ***************************************************************************/ +#include "setup.h" + #ifdef USE_GNUTLS +#include "urldata.h" + int Curl_gtls_init(void); int Curl_gtls_cleanup(void); CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); @@ -60,4 +64,4 @@ int Curl_gtls_seed(struct SessionHandle *data); #define curlssl_data_pending(x,y) (x=x, y=y, 0) #endif /* USE_GNUTLS */ -#endif +#endif /* HEADER_CURL_GTLS_H */ diff --git a/lib/hash.c b/lib/hash.c index 6c921e442..3704eea41 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> - #include "hash.h" #include "llist.h" @@ -41,11 +38,14 @@ hash_element_dtor(void *user, void *element) struct curl_hash *h = (struct curl_hash *) user; struct curl_hash_element *e = (struct curl_hash_element *) element; - if(e->key) - free(e->key); + Curl_safefree(e->key); - if(e->ptr) + if(e->ptr) { h->dtor(e->ptr); + e->ptr = NULL; + } + + e->key_len = 0; free(e); } @@ -75,16 +75,22 @@ Curl_hash_init(struct curl_hash *h, for(i = 0; i < slots; ++i) { h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); if(!h->table[i]) { - while(i--) + while(i--) { Curl_llist_destroy(h->table[i], NULL); + h->table[i] = NULL; + } free(h->table); + h->table = NULL; + h->slots = 0; return 1; /* failure */ } } return 0; /* fine */ } - else + else { + h->slots = 0; return 1; /* failure */ + } } struct curl_hash * @@ -190,6 +196,7 @@ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) he = le->ptr; if(h->comp_func(he->key, he->key_len, key, key_len)) { Curl_llist_remove(l, le, (void *) h); + --h->size; return 0; } } @@ -243,6 +250,9 @@ Curl_hash_clean(struct curl_hash *h) } free(h->table); + h->table = NULL; + h->size = 0; + h->slots = 0; } void diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 50f6b01fb..771562fd1 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/hostip.c b/lib/hostip.c index 084ee86ac..d261a163a 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_SETJMP_H @@ -560,6 +554,10 @@ int Curl_resolv_timeout(struct connectdata *conn, *entry = NULL; + if(timeoutms < 0) + /* got an already expired timeout */ + return CURLRESOLV_TIMEDOUT; + #ifdef USE_ALARM_TIMEOUT if(data->set.no_signal) /* Ignore the timeout when signals are disabled */ diff --git a/lib/hostip4.c b/lib/hostip4.c index 67aefda29..1a5e26585 100644 --- a/lib/hostip4.c +++ b/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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,6 @@ #include "setup.h" -#include <string.h> -#include <errno.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -37,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/hostip6.c b/lib/hostip6.c index b944401c5..8241cb4bc 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H @@ -160,7 +154,7 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) } } #else -#define dump_addrinfo(x,y) +#define dump_addrinfo(x,y) Curl_nop_stmt #endif /* diff --git a/lib/hostsyn.c b/lib/hostsyn.c index a5e97658e..b60188708 100644 --- a/lib/hostsyn.c +++ b/lib/hostsyn.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/http.c b/lib/http.c index 56d263b91..f85cd6c55 100644 --- a/lib/http.c +++ b/lib/http.c @@ -23,32 +23,13 @@ #include "setup.h" #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#ifdef HAVE_TIME_H -#ifdef TIME_WITH_SYS_TIME -#include <time.h> -#endif -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -70,8 +51,6 @@ #include <sys/param.h> #endif -#endif - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -83,7 +62,8 @@ #include "strequal.h" #include "sslgen.h" #include "http_digest.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" +#include "curl_ntlm_wb.h" #include "http_negotiate.h" #include "url.h" #include "share.h" @@ -138,6 +118,7 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -161,6 +142,7 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* doing */ https_getsock, /* proto_getsock */ http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -252,11 +234,13 @@ static char *copy_header_value(const char *h) */ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) { - char *authorization; - struct SessionHandle *data=conn->data; + size_t size = 0; + char *authorization = NULL; + struct SessionHandle *data = conn->data; char **userp; const char *user; const char *pwd; + CURLcode error; if(proxy) { userp = &conn->allocptr.proxyuserpwd; @@ -270,20 +254,24 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) } snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); - if(Curl_base64_encode(data, data->state.buffer, - strlen(data->state.buffer), - &authorization) > 0) { - if(*userp) - free(*userp); - *userp = aprintf( "%sAuthorization: Basic %s\r\n", - proxy?"Proxy-":"", - authorization); - free(authorization); - if(!*userp) - return CURLE_OUT_OF_MEMORY; - } - else + + error = Curl_base64_encode(data, + data->state.buffer, strlen(data->state.buffer), + &authorization, &size); + if(error) + return error; + + if(!authorization) + return CURLE_REMOTE_ACCESS_DENIED; + + Curl_safefree(*userp); + *userp = aprintf("%sAuthorization: Basic %s\r\n", + proxy?"Proxy-":"", + authorization); + free(authorization); + if(!*userp) return CURLE_OUT_OF_MEMORY; + return CURLE_OK; } @@ -307,6 +295,8 @@ static bool pickoneauth(struct auth *pick) pick->picked = CURLAUTH_DIGEST; else if(avail & CURLAUTH_NTLM) pick->picked = CURLAUTH_NTLM; + else if(avail & CURLAUTH_NTLM_WB) + pick->picked = CURLAUTH_NTLM_WB; else if(avail & CURLAUTH_BASIC) pick->picked = CURLAUTH_BASIC; else { @@ -393,15 +383,19 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) if((expectsend == -1) || (expectsend > bytessent)) { /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NTLM) || - (data->state.authhost.picked == CURLAUTH_NTLM)) { + (data->state.authhost.picked == CURLAUTH_NTLM) || + (data->state.authproxy.picked == CURLAUTH_NTLM_WB) || + (data->state.authhost.picked == CURLAUTH_NTLM_WB)) { if(((expectsend - bytessent) < 2000) || (conn->ntlm.state != NTLMSTATE_NONE)) { /* The NTLM-negotiation has started *OR* there is just a little (<2K) data left to send, keep on sending. */ /* rewind data when completely done sending! */ - if(!conn->bits.authneg) + if(!conn->bits.authneg) { conn->bits.rewindaftersend = TRUE; + infof(data, "Rewind stream after send\n"); + } return CURLE_OK; } @@ -554,6 +548,15 @@ output_auth_headers(struct connectdata *conn, } else #endif +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + if(authstatus->picked == CURLAUTH_NTLM_WB) { + auth="NTLM_WB"; + result = Curl_output_ntlm_wb(conn, proxy); + if(result) + return result; + } + else +#endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(authstatus->picked == CURLAUTH_DIGEST) { auth="Digest"; @@ -587,7 +590,7 @@ output_auth_headers(struct connectdata *conn, proxy?"Proxy":"Server", auth, proxy?(conn->proxyuser?conn->proxyuser:""): (conn->user?conn->user:"")); - authstatus->multi = (bool)(!authstatus->done); + authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } else authstatus->multi = FALSE; @@ -730,73 +733,73 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, * */ + while(*start) { #ifdef USE_HTTP_NEGOTIATE - if(checkprefix("GSS-Negotiate", start) || - checkprefix("Negotiate", start)) { - int neg; - *availp |= CURLAUTH_GSSNEGOTIATE; - authp->avail |= CURLAUTH_GSSNEGOTIATE; - - if(data->state.negotiate.state == GSS_AUTHSENT) { - /* if we sent GSS authentication in the outgoing request and we get this - back, we're in trouble */ - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - else { - neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start); - if(neg == 0) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received GSS auth info and we dealt with it fine */ - data->state.negotiate.state = GSS_AUTHRECV; - } - else { + if(checkprefix("GSS-Negotiate", start) || + checkprefix("Negotiate", start)) { + int neg; + *availp |= CURLAUTH_GSSNEGOTIATE; + authp->avail |= CURLAUTH_GSSNEGOTIATE; + + if(data->state.negotiate.state == GSS_AUTHSENT) { + /* if we sent GSS authentication in the outgoing request and we get + this back, we're in trouble */ + infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } - } - } - else -#endif -#ifdef USE_NTLM - /* NTLM support requires the SSL crypto libs */ - if(checkprefix("NTLM", start)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM) { - /* NTLM authentication is picked and activated */ - CURLntlm ntlm = - Curl_input_ntlm(conn, (bool)(httpcode == 407), start); - - if(CURLNTLM_BAD != ntlm) + else { + neg = Curl_input_negotiate(conn, (httpcode == 407)?TRUE:FALSE, start); + if(neg == 0) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->change.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; data->state.authproblem = FALSE; + /* we received GSS auth info and we dealt with it fine */ + data->state.negotiate.state = GSS_AUTHRECV; + } else { - infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } } else #endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(checkprefix("Digest", start)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { - infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { - CURLdigest dig; - *availp |= CURLAUTH_DIGEST; - authp->avail |= CURLAUTH_DIGEST; - - /* We call this function on input Digest headers even if Digest - * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are gonna use Digest. */ - dig = Curl_input_digest(conn, (bool)(httpcode == 407), start); - - if(CURLDIGEST_FINE != dig) { +#ifdef USE_NTLM + /* NTLM support requires the SSL crypto libs */ + if(checkprefix("NTLM", start)) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode ntlm = + Curl_input_ntlm(conn, (httpcode == 407)?TRUE:FALSE, start); + if(CURLE_OK == ntlm) { + data->state.authproblem = FALSE; +#ifdef NTLM_WB_ENABLED + if(authp->picked == CURLAUTH_NTLM_WB) { + *availp &= ~CURLAUTH_NTLM; + authp->avail &= ~CURLAUTH_NTLM; + *availp |= CURLAUTH_NTLM_WB; + authp->avail |= CURLAUTH_NTLM_WB; + + /* Get the challenge-message which will be passed to + * ntlm_auth for generating the type 3 message later */ + while(*start && ISSPACE(*start)) + start++; + if(checkprefix("NTLM", start)) { + start += strlen("NTLM"); + while(*start && ISSPACE(*start)) + start++; + if(*start) + if((conn->challenge_header = strdup(start)) == NULL) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + } + else { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } @@ -804,19 +807,51 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, } else #endif - if(checkprefix("Basic", start)) { - *availp |= CURLAUTH_BASIC; - authp->avail |= CURLAUTH_BASIC; - if(authp->picked == CURLAUTH_BASIC) { - /* We asked for Basic authentication but got a 40X back - anyway, which basically means our name+password isn't - valid. */ - authp->avail = CURLAUTH_NONE; - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(checkprefix("Digest", start)) { + if((authp->avail & CURLAUTH_DIGEST) != 0) { + infof(data, "Ignoring duplicate digest auth header.\n"); + } + else { + CURLdigest dig; + *availp |= CURLAUTH_DIGEST; + authp->avail |= CURLAUTH_DIGEST; + + /* We call this function on input Digest headers even if Digest + * authentication isn't activated yet, as we need to store the + * incoming data from this header in case we are gonna use + * Digest. */ + dig = Curl_input_digest(conn, (httpcode == 407)?TRUE:FALSE, start); + + if(CURLDIGEST_FINE != dig) { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } } - } + else +#endif + if(checkprefix("Basic", start)) { + *availp |= CURLAUTH_BASIC; + authp->avail |= CURLAUTH_BASIC; + if(authp->picked == CURLAUTH_BASIC) { + /* We asked for Basic authentication but got a 40X back + anyway, which basically means our name+password isn't + valid. */ + authp->avail = CURLAUTH_NONE; + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } + /* there may be multiple methods on one line, so keep reading */ + while(*start && *start != ',') /* read up to the next comma */ + start++; + if(*start == ',') /* if we're on a comma, skip it */ + start++; + while(*start && ISSPACE(*start)) + start++; + } return CURLE_OK; } @@ -923,7 +958,7 @@ static size_t readmoredata(char *buffer, return 0; /* make sure that a HTTP request is never sent away chunked! */ - conn->data->req.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST); + conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; if(http->postsize <= (curl_off_t)fullsize) { memcpy(buffer, http->postdata, (size_t)http->postsize); @@ -1456,11 +1491,11 @@ CURLcode Curl_http_done(struct connectdata *conn, static bool use_http_1_1(const struct SessionHandle *data, const struct connectdata *conn) { - return (bool)((data->set.httpversion == CURL_HTTP_VERSION_1_1) || + return ((data->set.httpversion == CURL_HTTP_VERSION_1_1) || ((data->set.httpversion != CURL_HTTP_VERSION_1_0) && ((conn->httpversion == 11) || ((conn->httpversion != 10) && - (data->state.httpversion != 10))))); + (data->state.httpversion != 10))))) ? TRUE : FALSE; } /* check and possibly add an Expect: header */ @@ -1536,6 +1571,31 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, } } } + else { + ptr = strchr(headers->data, ';'); + if(ptr) { + + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + } + else { + if(*(--ptr) == ';') { + CURLcode result; + + /* send no-value custom header if terminated by semicolon */ + *ptr = ':'; + result = Curl_add_bufferf(req_buffer, "%s\r\n", + headers->data); + if(result) + return result; + } + } + } + } headers = headers->next; } return CURLE_OK; @@ -1615,7 +1675,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) curl_off_t included_body = 0; const char *httpstring; Curl_send_buffer *req_buffer; - curl_off_t postsize; /* off_t type to be able to hold a large file size */ + curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ int seekerr = CURL_SEEKFUNC_OK; /* Always consider the DO phase done after this function call, even if there @@ -1648,6 +1708,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!data->state.first_host) return CURLE_OUT_OF_MEMORY; } + http->writebytecount = http->readbytecount = 0; if((conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_FTP)) && data->set.upload) { @@ -1754,8 +1815,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } else { if((conn->handler->protocol&CURLPROTO_HTTP) && - data->set.upload && - (data->set.infilesize == -1)) { + data->set.upload && + (data->set.infilesize == -1)) { if(conn->bits.authneg) /* don't enable chunked during auth neg */ ; @@ -1863,8 +1924,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) memcpy(newurl + newlen + (ptr - url), ptr + currlen, /* copy the trailing zero byte too */ urllen - (ptr-url) - currlen + 1); - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = newurl; data->change.url_alloc = TRUE; } @@ -1933,7 +1996,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * This is meant to get the size of the present remote-file by itself. * We don't support this now. Bail out! */ - data->state.resume_from = 0; + data->state.resume_from = 0; } if(data->state.resume_from && !data->state.this_is_a_follow) { @@ -2024,17 +2087,17 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) curl_off_t total_expected_size= data->state.resume_from + data->set.infilesize; conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s%" FORMAT_OFF_T - "/%" FORMAT_OFF_T "\r\n", - data->state.range, total_expected_size-1, - total_expected_size); + aprintf("Content-Range: bytes %s%" FORMAT_OFF_T + "/%" FORMAT_OFF_T "\r\n", + data->state.range, total_expected_size-1, + total_expected_size); } else { /* Range was selected and then we just pass the incoming range and append total size */ conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", - data->state.range, data->set.infilesize); + aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", + data->state.range, data->set.infilesize); } if(!conn->allocptr.rangeline) return CURLE_OUT_OF_MEMORY; @@ -2067,45 +2130,47 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(result) return result; - result = Curl_add_bufferf(req_buffer, - "%s" /* ftp typecode (;type=x) */ - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* host */ - "%s" /* accept */ - "%s" /* TE: */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s",/* transfer-encoding */ - - ftp_typecode, - httpstring, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? - conn->allocptr.uagent:"", - (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ - http->p_accept?http->p_accept:"", - conn->allocptr.te?conn->allocptr.te:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: <data> */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkheaders(data, "Proxy-Connection:"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te + result = + Curl_add_bufferf(req_buffer, + "%s" /* ftp typecode (;type=x) */ + " HTTP/%s\r\n" /* HTTP version */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* host */ + "%s" /* accept */ + "%s" /* TE: */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s" /* Proxy-Connection */ + "%s",/* transfer-encoding */ + + ftp_typecode, + httpstring, + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + conn->allocptr.userpwd?conn->allocptr.userpwd:"", + (data->state.use_range && conn->allocptr.rangeline)? + conn->allocptr.rangeline:"", + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + conn->allocptr.uagent)? + conn->allocptr.uagent:"", + (conn->allocptr.host?conn->allocptr.host:""), + http->p_accept?http->p_accept:"", + conn->allocptr.te?conn->allocptr.te:"", + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)? + conn->allocptr.ref:"" /* Referer: <data> */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkheaders(data, "Proxy-Connection:"))? + "Proxy-Connection: Keep-Alive\r\n":"", + te ); /* @@ -2130,8 +2195,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.cookiehost? conn->allocptr.cookiehost:host, data->state.path, - (bool)(conn->handler->protocol&CURLPROTO_HTTPS? - TRUE:FALSE)); + (conn->handler->protocol&CURLPROTO_HTTPS)? + TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { @@ -2145,8 +2210,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) break; } result = Curl_add_bufferf(req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); + "%s%s=%s", count?"; ":"", + co->name, co->value); if(result) break; count++; @@ -2160,8 +2225,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) result = Curl_add_bufferf(req_buffer, "Cookie: "); if(CURLE_OK == result) { result = Curl_add_bufferf(req_buffer, "%s%s", - count?"; ":"", - addcookies); + count?"; ":"", + addcookies); count++; } } @@ -2228,11 +2293,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; - if(!data->req.upload_chunky) { + if(!data->req.upload_chunky && + !Curl_checkheaders(data, "Content-Length:")) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - http->postsize); + "Content-Length: %" FORMAT_OFF_T "\r\n", + http->postsize); if(result) return result; } @@ -2299,11 +2365,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else postsize = data->set.infilesize; - if((postsize != -1) && !data->req.upload_chunky) { + if((postsize != -1) && !data->req.upload_chunky && + !Curl_checkheaders(data, "Content-Length:")) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - postsize ); + "Content-Length: %" FORMAT_OFF_T "\r\n", + postsize ); if(result) return result; } @@ -2353,8 +2420,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T"\r\n", - postsize); + "Content-Length: %" FORMAT_OFF_T"\r\n", + postsize); if(result) return result; } @@ -2404,7 +2471,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); + (size_t)postsize); included_body = postsize; } else { @@ -2412,10 +2479,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize); if(CURLE_OK == result) result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); + (size_t)postsize); if(CURLE_OK == result) result = Curl_add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); + "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); /* CR LF 0 CR LF CR LF */ included_body = postsize + 7; } @@ -2451,7 +2518,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ result = Curl_add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); + "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); /* CR LF 0 CR LF CR LF */ if(result) return result; @@ -2508,6 +2575,17 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_pgrsSetUploadCounter(data, http->writebytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; + + if(http->writebytecount >= postsize) { + /* already sent the entire request body, mark the "upload" as + complete */ + infof(data, "upload completely sent off: %" FORMAT_OFF_T " out of " + "%" FORMAT_OFF_T " bytes\n", + http->writebytecount, postsize); + data->req.upload_done = TRUE; + data->req.keepon &= ~KEEP_SEND; /* we're done writing */ + data->req.exp100 = EXP100_SEND_DATA; /* already sent */ + } } return result; @@ -2547,7 +2625,7 @@ checkhttpprefix(struct SessionHandle *data, head = head->next; } - if((rc != TRUE) && (checkprefix("HTTP/", s))) + if(!rc && (checkprefix("HTTP/", s))) rc = TRUE; #ifdef CURL_DOES_CONVERSIONS @@ -2779,17 +2857,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } } - if(417 == k->httpcode) { - /* - * we got: "417 Expectation Failed" this means: - * we have made a HTTP call and our Expect Header - * seems to cause a problem => abort the write operations - * (or prevent them from starting). - */ - k->exp100 = EXP100_FAILED; - k->keepon &= ~KEEP_SEND; - } - /* * When all the headers have been parsed, see if we should give * up and return an error. @@ -2829,6 +2896,46 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, if(result) return result; + if(k->httpcode >= 300) { + if((!conn->bits.authneg) && !conn->bits.close && + !conn->bits.rewindaftersend) { + /* + * General treatment of errors when about to send data. Including : + * "417 Expectation Failed", while waiting for 100-continue. + * + * The check for close above is done simply because of something + * else has already deemed the connection to get closed then + * something else should've considered the big picture and we + * avoid this check. + * + * rewindaftersend indicates that something has told libcurl to + * continue sending even if it gets discarded + */ + + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + /* We got an error response. If this happened before the whole + * request body has been sent we stop sending and mark the + * connection for closure after we've read the entire response. + */ + if(!k->upload_done) { + infof(data, "HTTP error before end of send, stop sending\n"); + conn->bits.close = TRUE; /* close after this */ + k->upload_done = TRUE; + k->keepon &= ~KEEP_SEND; /* don't send */ + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; + } + break; + + default: /* default label present to avoid compiler warnings */ + break; + } + } + } + if(conn->bits.rewindaftersend) { /* We rewind after a complete send, so thus we continue sending now */ @@ -2929,23 +3036,23 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, if(conn->handler->protocol & CURLPROTO_HTTP) { nc = sscanf(HEADER1, - " HTTP/%d.%d %3d", - &httpversion_major, - &conn->httpversion, - &k->httpcode); + " HTTP/%d.%d %3d", + &httpversion_major, + &conn->httpversion, + &k->httpcode); if(nc==3) { conn->httpversion += 10 * httpversion_major; } else { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 - */ + */ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); conn->httpversion = 10; /* If user has set option HTTP200ALIASES, compare header line against list of aliases - */ + */ if(!nc) { if(checkhttpprefix(data, k->p)) { nc = 1; diff --git a/lib/http_chunks.c b/lib/http_chunks.c index 93de1d968..d6a0bec13 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -19,15 +19,10 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" /* it includes http_chunks.h */ #include "sendf.h" /* for the client write stuff */ @@ -84,9 +79,9 @@ We avoid the use of isxdigit to accommodate non-ASCII hosts. */ static bool Curl_isxdigit(char digit) { - return (bool)( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ - || (digit >= 0x41 && digit <= 0x46) /* A-F */ - || (digit >= 0x61 && digit <= 0x66) ); /* a-f */ + return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ + || (digit >= 0x41 && digit <= 0x46) /* A-F */ + || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE; } void Curl_httpchunk_init(struct connectdata *conn) diff --git a/lib/http_digest.c b/lib/http_digest.c index c3a39fcee..b41e62306 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -19,15 +19,10 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" #include "sendf.h" @@ -285,7 +280,8 @@ CURLcode Curl_output_digest(struct connectdata *conn, unsigned char *ha1; unsigned char ha2[33];/* 32 digits and 1 zero byte */ char cnoncebuf[7]; - char *cnonce; + char *cnonce = NULL; + size_t cnonce_sz = 0; char *tmp = NULL; struct timeval now; @@ -348,10 +344,12 @@ CURLcode Curl_output_digest(struct connectdata *conn, /* Generate a cnonce */ now = Curl_tvnow(); snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", (long)now.tv_sec); - if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce)) - d->cnonce = cnonce; - else - return CURLE_OUT_OF_MEMORY; + + rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(rc) + return rc; + d->cnonce = cnonce; } /* diff --git a/lib/http_digest.h b/lib/http_digest.h index 75fcba929..3b22ce10e 100644 --- a/lib/http_digest.h +++ b/lib/http_digest.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_DIGEST_H -#define __HTTP_DIGEST_H +#ifndef HEADER_CURL_HTTP_DIGEST_H +#define HEADER_CURL_HTTP_DIGEST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" typedef enum { CURLDIGEST_NONE, /* not a digest */ @@ -50,7 +51,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) void Curl_digest_cleanup(struct SessionHandle *data); #else -#define Curl_digest_cleanup(x) do {} while(0) +#define Curl_digest_cleanup(x) Curl_nop_stmt #endif -#endif +#endif /* HEADER_CURL_HTTP_DIGEST_H */ diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 5127e6480..4e68ab762 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -19,27 +19,25 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #ifdef HAVE_GSSAPI #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 #endif #ifndef CURL_DISABLE_HTTP - /* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" #include "sendf.h" +#include "curl_gssapi.h" #include "rawstr.h" #include "curl_base64.h" #include "http_negotiate.h" #include "curl_memory.h" +#include "url.h" #ifdef HAVE_SPNEGO # include <spnegohelp.h> @@ -134,15 +132,18 @@ log_gss_error(struct connectdata *conn, OM_uint32 error_status, int Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; + struct SessionHandle *data = conn->data; + struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: + &data->state.negotiate; OM_uint32 major_status, minor_status, minor_status2; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; int ret; - size_t len, rawlen; + size_t len; + size_t rawlen = 0; bool gss; const char* protocol; + CURLcode error; while(*header && ISSPACE(*header)) header++; @@ -171,7 +172,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, /* 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(conn->data); + Curl_cleanup_negotiate(data); return -1; } @@ -185,9 +186,9 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, len = strlen(header); if(len > 0) { - rawlen = Curl_base64_decode(header, - (unsigned char **)&input_token.value); - if(rawlen == 0) + error = Curl_base64_decode(header, + (unsigned char **)&input_token.value, &rawlen); + if(error || rawlen == 0) return -1; input_token.length = rawlen; @@ -220,7 +221,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, NULL)) { free(spnegoToken); spnegoToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token failed\n"); + infof(data, "Parse SPNEGO Target Token failed\n"); } else { free(input_token.value); @@ -232,30 +233,25 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, input_token.length = mechTokenLength; free(mechToken); mechToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); + infof(data, "Parse SPNEGO Target Token succeeded\n"); } } #endif } - major_status = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, - &neg_ctx->context, - neg_ctx->server_name, - GSS_C_NO_OID, - 0, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - NULL, - &output_token, - NULL, - NULL); + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &neg_ctx->context, + neg_ctx->server_name, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + NULL); if(input_token.length > 0) gss_release_buffer(&minor_status2, &input_token); neg_ctx->status = major_status; if(GSS_ERROR(major_status)) { - /* Curl_cleanup_negotiate(conn->data) ??? */ + /* Curl_cleanup_negotiate(data) ??? */ log_gss_error(conn, minor_status, "gss_init_sec_context() failed: "); return -1; @@ -277,8 +273,9 @@ 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; + size_t len = 0; char *userp; + CURLcode error; #ifdef HAVE_SPNEGO /* Handle SPNEGO */ if(checkprefix("Negotiate", neg_ctx->protocol)) { @@ -324,13 +321,21 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) } } #endif - len = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded); + error = Curl_base64_encode(conn->data, + neg_ctx->output_token.value, + neg_ctx->output_token.length, + &encoded, &len); + if(error) { + Curl_safefree(neg_ctx->output_token.value); + neg_ctx->output_token.value = NULL; + return error; + } - if(len == 0) - return CURLE_OUT_OF_MEMORY; + if(len == 0) { + Curl_safefree(neg_ctx->output_token.value); + neg_ctx->output_token.value = NULL; + return CURLE_REMOTE_ACCESS_DENIED; + } userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", neg_ctx->protocol, encoded); diff --git a/lib/http_negotiate_sspi.c b/lib/http_negotiate_sspi.c index 809870168..08d016274 100644 --- a/lib/http_negotiate_sspi.c +++ b/lib/http_negotiate_sspi.c @@ -19,17 +19,12 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #ifdef USE_WINDOWS_SSPI #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" #include "sendf.h" @@ -45,13 +40,16 @@ #include "memdebug.h" static int -get_gss_name(struct connectdata *conn, bool proxy, char *server) +get_gss_name(struct connectdata *conn, bool proxy, + struct negotiatedata *neg_ctx) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; const char* service; size_t length; + if(proxy && !conn->proxy.name) + /* proxy auth requested but no given proxy name, error out! */ + return -1; + /* GSSAPI implementation by Globus (known as GSI) requires the name to be of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead of at-sign). Also GSI servers are often identified as 'host' not 'khttp'. @@ -71,7 +69,7 @@ get_gss_name(struct connectdata *conn, bool proxy, char *server) if(length + 1 > sizeof(neg_ctx->server_name)) return EMSGSIZE; - snprintf(server, sizeof(neg_ctx->server_name), "%s/%s", + snprintf(neg_ctx->server_name, sizeof(neg_ctx->server_name), "%s/%s", service, proxy ? conn->proxy.name : conn->host.name); return 0; @@ -84,7 +82,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, { struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: &conn->data->state.negotiate; - BYTE *input_token = 0; + BYTE *input_token = 0; SecBufferDesc out_buff_desc; SecBuffer out_sec_buff; SecBufferDesc in_buff_desc; @@ -96,6 +94,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, size_t len = 0, input_token_len = 0; bool gss = FALSE; const char* protocol; + CURLcode error; while(*header && ISSPACE(*header)) header++; @@ -129,9 +128,11 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, return -1; } - if(strlen(neg_ctx->server_name) == 0 && - (ret = get_gss_name(conn, proxy, neg_ctx->server_name))) - return ret; + if(0 == strlen(neg_ctx->server_name)) { + ret = get_gss_name(conn, proxy, neg_ctx); + if(ret) + return ret; + } if(!neg_ctx->output_token) { PSecPkgInfo SecurityPackage; @@ -176,9 +177,10 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, if(!input_token) return -1; - input_token_len = Curl_base64_decode(header, - (unsigned char **)&input_token); - if(input_token_len == 0) + error = Curl_base64_decode(header, + (unsigned char **)&input_token, + &input_token_len); + if(error || input_token_len == 0) return -1; } @@ -238,16 +240,19 @@ 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; + size_t len = 0; char *userp; + CURLcode error; - len = Curl_base64_encode(conn->data, - (const char*)neg_ctx->output_token, - neg_ctx->output_token_length, - &encoded); + error = Curl_base64_encode(conn->data, + (const char*)neg_ctx->output_token, + neg_ctx->output_token_length, + &encoded, &len); + if(error) + return error; if(len == 0) - return CURLE_OUT_OF_MEMORY; + return CURLE_REMOTE_ACCESS_DENIED; userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", neg_ctx->protocol, encoded); diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c deleted file mode 100644 index c3ceadc35..000000000 --- a/lib/http_ntlm.c +++ /dev/null @@ -1,1329 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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. - * - * 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 "setup.h" - -/* NTLM details: - - http://davenport.sourceforge.net/ntlm.html - http://www.innovation.ch/java/ntlm.html -*/ - -#ifndef CURL_DISABLE_HTTP -#ifdef USE_NTLM - -#define DEBUG_ME 0 - -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -#include <netdb.h> -#endif - -#include "urldata.h" -#include "non-ascii.h" /* for Curl_convert_... prototypes */ -#include "sendf.h" -#include "rawstr.h" -#include "curl_base64.h" -#include "http_ntlm.h" -#include "url.h" -#include "curl_gethostname.h" -#include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* "NTLMSSP" signature is always in ASCII regardless of the platform */ -#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" - -#ifdef USE_SSLEAY -#include "ssluse.h" -# ifdef USE_OPENSSL -# include <openssl/des.h> -# ifndef OPENSSL_NO_MD4 -# include <openssl/md4.h> -# endif -# include <openssl/md5.h> -# include <openssl/ssl.h> -# include <openssl/rand.h> -# else -# include <des.h> -# ifndef OPENSSL_NO_MD4 -# include <md4.h> -# endif -# include <md5.h> -# include <ssl.h> -# include <rand.h> -# endif - -#ifndef OPENSSL_VERSION_NUMBER -#error "OPENSSL_VERSION_NUMBER not defined" -#endif - -#if OPENSSL_VERSION_NUMBER < 0x00907001L -#define DES_key_schedule des_key_schedule -#define DES_cblock des_cblock -#define DES_set_odd_parity des_set_odd_parity -#define DES_set_key des_set_key -#define DES_ecb_encrypt des_ecb_encrypt - -/* This is how things were done in the old days */ -#define DESKEY(x) x -#define DESKEYARG(x) x -#else -/* Modern version */ -#define DESKEYARG(x) *x -#define DESKEY(x) &x -#endif - -#ifdef OPENSSL_NO_MD4 -/* This requires MD4, but OpenSSL was compiled without it */ -#define USE_NTRESPONSES 0 -#define USE_NTLM2SESSION 0 -#endif - -#elif defined(USE_GNUTLS) - -#include "gtls.h" -#include <gcrypt.h> - -#define MD5_DIGEST_LENGTH 16 -#define MD4_DIGEST_LENGTH 16 - -#elif defined(USE_NSS) - -#include "curl_md4.h" -#include "nssg.h" -#include <nss.h> -#include <pk11pub.h> -#include <hasht.h> -#define MD5_DIGEST_LENGTH MD5_LENGTH - -#elif defined(USE_WINDOWS_SSPI) - -#include "curl_sspi.h" - -#else -# error "Can't compile NTLM support without a crypto library." -#endif - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef USE_NTRESPONSES -/* Define this to make the type-3 message include the NT response message */ -#define USE_NTRESPONSES 1 - -/* Define this to make the type-3 message include the NTLM2Session response - message, requires USE_NTRESPONSES. */ -#define USE_NTLM2SESSION 1 -#endif - -#ifndef USE_WINDOWS_SSPI -/* this function converts from the little endian format used in the incoming - package to whatever endian format we're using natively */ -static unsigned int readint_le(unsigned char *buf) /* must point to a - 4 bytes buffer*/ -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | - ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); -} -#endif - -#if DEBUG_ME -# define DEBUG_OUT(x) x -static void print_flags(FILE *handle, unsigned long flags) -{ - if(flags & NTLMFLAG_NEGOTIATE_UNICODE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE "); - if(flags & NTLMFLAG_NEGOTIATE_OEM) - fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM "); - if(flags & NTLMFLAG_REQUEST_TARGET) - fprintf(handle, "NTLMFLAG_REQUEST_TARGET "); - if(flags & (1<<3)) - fprintf(handle, "NTLMFLAG_UNKNOWN_3 "); - if(flags & NTLMFLAG_NEGOTIATE_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN "); - if(flags & NTLMFLAG_NEGOTIATE_SEAL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL "); - if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE "); - if(flags & NTLMFLAG_NEGOTIATE_LM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_NETWARE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY "); - if(flags & (1<<10)) - fprintf(handle, "NTLMFLAG_UNKNOWN_10 "); - if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS "); - if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED) - fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED "); - if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL) - fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL "); - if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN) - fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN "); - if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN "); - if(flags & NTLMFLAG_TARGET_TYPE_SERVER) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER "); - if(flags & NTLMFLAG_TARGET_TYPE_SHARE) - fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE "); - if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY "); - if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE) - fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE "); - if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY) - fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY "); - if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) - fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO "); - if(flags & (1<<24)) - fprintf(handle, "NTLMFLAG_UNKNOWN_24 "); - if(flags & (1<<25)) - fprintf(handle, "NTLMFLAG_UNKNOWN_25 "); - if(flags & (1<<26)) - fprintf(handle, "NTLMFLAG_UNKNOWN_26 "); - if(flags & (1<<27)) - fprintf(handle, "NTLMFLAG_UNKNOWN_27 "); - if(flags & (1<<28)) - fprintf(handle, "NTLMFLAG_UNKNOWN_28 "); - if(flags & NTLMFLAG_NEGOTIATE_128) - fprintf(handle, "NTLMFLAG_NEGOTIATE_128 "); - if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE "); - if(flags & NTLMFLAG_NEGOTIATE_56) - fprintf(handle, "NTLMFLAG_NEGOTIATE_56 "); -} - -static void print_hex(FILE *handle, const char *buf, size_t len) -{ - const char *p = buf; - fprintf(stderr, "0x"); - while(len-- > 0) - fprintf(stderr, "%02.2x", (unsigned int)*p++); -} -#else -# define DEBUG_OUT(x) -#endif - -/* - (*) = A "security buffer" is a triplet consisting of two shorts and one - long: - - 1. a 'short' containing the length of the buffer in bytes - 2. a 'short' containing the allocated space for the buffer in bytes - 3. a 'long' containing the offset to the start of the buffer from the - beginning of the NTLM message, in bytes. -*/ - - -CURLntlm Curl_input_ntlm(struct connectdata *conn, - bool proxy, /* if proxy or not */ - const char *header) /* rest of the www-authenticate: - header */ -{ - /* point to the correct struct with this */ - struct ntlmdata *ntlm; -#ifndef USE_WINDOWS_SSPI - static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; -#endif - -#ifdef USE_NSS - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLNTLM_BAD; -#endif - - ntlm = proxy?&conn->proxyntlm:&conn->ntlm; - - /* skip initial whitespaces */ - while(*header && ISSPACE(*header)) - header++; - - if(checkprefix("NTLM", header)) { - header += strlen("NTLM"); - - while(*header && ISSPACE(*header)) - header++; - - if(*header) { - /* We got a type-2 message here: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x02000000) - 12 Target Name security buffer(*) - 20 Flags long - 24 Challenge 8 bytes - (32) Context (optional) 8 bytes (two consecutive longs) - (40) Target Information (optional) security buffer(*) - 32 (48) start of data block - */ - size_t size; - unsigned char *buffer; - size = Curl_base64_decode(header, &buffer); - if(!buffer) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */ - -#ifdef USE_WINDOWS_SSPI - ntlm->type_2 = malloc(size+1); - if(ntlm->type_2 == NULL) { - free(buffer); - return CURLE_OUT_OF_MEMORY; - } - ntlm->n_type_2 = size; - memcpy(ntlm->type_2, buffer, size); -#else - ntlm->flags = 0; - - if((size < 32) || - (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || - (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) { - /* This was not a good enough type-2 message */ - free(buffer); - return CURLNTLM_BAD; - } - - ntlm->flags = readint_le(&buffer[20]); - memcpy(ntlm->nonce, &buffer[24], 8); - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n nonce="); - print_hex(stderr, (char *)ntlm->nonce, 8); - fprintf(stderr, "\n****\n"); - fprintf(stderr, "**** Header %s\n ", header); - }); -#endif - free(buffer); - } - else { - if(ntlm->state >= NTLMSTATE_TYPE1) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */ - } - } - return CURLNTLM_FINE; -} - -#ifndef USE_WINDOWS_SSPI - -#ifdef USE_SSLEAY -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The - * key schedule ks is also set. - */ -static void setup_des_key(const unsigned char *key_56, - DES_key_schedule DESKEYARG(ks)) -{ - DES_cblock key; - - key[0] = key_56[0]; - key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); - key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); - key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); - key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); - key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); - key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); - key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); - - DES_set_odd_parity(&key); - DES_set_key(&key, ks); -} - -#else /* defined(USE_SSLEAY) */ - -/* - * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. - */ -static void extend_key_56_to_64(const unsigned char *key_56, char *key) -{ - key[0] = key_56[0]; - key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1)); - key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2)); - key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3)); - key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4)); - key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5)); - key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6)); - key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF); -} - -#if defined(USE_GNUTLS) - -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. - */ -static void setup_des_key(const unsigned char *key_56, - gcry_cipher_hd_t *des) -{ - char key[8]; - extend_key_56_to_64(key_56, key); - gcry_cipher_setkey(*des, key, 8); -} - -#elif defined(USE_NSS) - -/* - * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using - * the expanded key. The caller is responsible for giving 64 bit of valid - * data is IN and (at least) 64 bit large buffer as OUT. - */ -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ - PK11SlotInfo *slot = NULL; - char key[8]; /* expanded 64 bit key */ - SECItem key_item; - PK11SymKey *symkey = NULL; - SECItem *param = NULL; - PK11Context *ctx = NULL; - int out_len; /* not used, required by NSS */ - bool rv = FALSE; - - /* use internal slot for DES encryption (requires NSS to be initialized) */ - slot = PK11_GetInternalKeySlot(); - if(!slot) - return FALSE; - - /* expand the 56 bit key to 64 bit and wrap by NSS */ - extend_key_56_to_64(key_56, key); - key_item.data = (unsigned char *)key; - key_item.len = /* hard-wired */ 8; - symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, - &key_item, NULL); - if(!symkey) - goto fail; - - /* create DES encryption context */ - param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); - if(!param) - goto fail; - ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); - if(!ctx) - goto fail; - - /* perform the encryption */ - if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, - (unsigned char *)in, /* inbuflen */ 8) - && SECSuccess == PK11_Finalize(ctx)) - rv = /* all OK */ TRUE; - -fail: - /* cleanup */ - if(ctx) - PK11_DestroyContext(ctx, PR_TRUE); - if(symkey) - PK11_FreeSymKey(symkey); - if(param) - SECITEM_FreeItem(param, PR_TRUE); - PK11_FreeSlot(slot); - return rv; -} - -#endif /* defined(USE_NSS) */ - -#endif /* defined(USE_SSLEAY) */ - - /* - * takes a 21 byte array and treats it as 3 56-bit DES keys. The - * 8 byte plaintext is encrypted with each key and the resulting 24 - * bytes are stored in the results array. - */ -static void lm_resp(const unsigned char *keys, - const unsigned char *plaintext, - unsigned char *results) -{ -#ifdef USE_SSLEAY - DES_key_schedule ks; - - setup_des_key(keys, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys+7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8), - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(keys+14, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16), - DESKEY(ks), DES_ENCRYPT); -#elif defined(USE_GNUTLS) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys, &des); - gcry_cipher_encrypt(des, results, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys+7, &des); - gcry_cipher_encrypt(des, results+8, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys+14, &des); - gcry_cipher_encrypt(des, results+16, 8, plaintext, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) - encrypt_des(plaintext, results, keys); - encrypt_des(plaintext, results+8, keys+7); - encrypt_des(plaintext, results+16, keys+14); -#endif -} - - -/* - * Set up lanmanager hashed password - */ -static void mk_lm_hash(struct SessionHandle *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */) -{ - CURLcode res; - unsigned char pw[14]; - static const unsigned char magic[] = { - 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ - }; - size_t len = CURLMIN(strlen(password), 14); - - Curl_strntoupper((char *)pw, password, len); - memset(&pw[len], 0, 14-len); - - /* - * The LanManager hashed password needs to be created using the - * password in the network encoding not the host encoding. - */ - res = Curl_convert_to_network(data, (char *)pw, 14); - if(res) - return; - - { - /* Create LanManager hashed password. */ - -#ifdef USE_SSLEAY - DES_key_schedule ks; - - setup_des_key(pw, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer, - DESKEY(ks), DES_ENCRYPT); - - setup_des_key(pw+7, DESKEY(ks)); - DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8), - DESKEY(ks), DES_ENCRYPT); -#elif defined(USE_GNUTLS) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw, &des); - gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw+7, &des); - gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) - encrypt_des(magic, lmbuffer, pw); - encrypt_des(magic, lmbuffer+8, pw+7); -#endif - - memset(lmbuffer + 16, 0, 21 - 16); - } -} - -#if USE_NTRESPONSES -static void ascii_to_unicode_le(unsigned char *dest, const char *src, - size_t srclen) -{ - size_t i; - for(i=0; i<srclen; i++) { - dest[2*i] = (unsigned char)src[i]; - dest[2*i+1] = '\0'; - } -} - -/* - * Set up nt hashed passwords - */ -static CURLcode mk_nt_hash(struct SessionHandle *data, - const char *password, - unsigned char *ntbuffer /* 21 bytes */) -{ - size_t len = strlen(password); - unsigned char *pw = malloc(len*2); - CURLcode result; - if(!pw) - return CURLE_OUT_OF_MEMORY; - - ascii_to_unicode_le(pw, password, len); - - /* - * The NT hashed password needs to be created using the password in the - * network encoding not the host encoding. - */ - result = Curl_convert_to_network(data, (char *)pw, len*2); - if(result) - return result; - - { - /* Create NT hashed password. */ -#ifdef USE_SSLEAY - MD4_CTX MD4pw; - MD4_Init(&MD4pw); - MD4_Update(&MD4pw, pw, 2*len); - MD4_Final(ntbuffer, &MD4pw); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD4pw; - gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); - gcry_md_write(MD4pw, pw, 2*len); - memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); - gcry_md_close(MD4pw); -#elif defined(USE_NSS) - Curl_md4it(ntbuffer, pw, 2*len); -#endif - - memset(ntbuffer + 16, 0, 21 - 16); - } - - free(pw); - return CURLE_OK; -} -#endif - - -#endif - -#ifdef USE_WINDOWS_SSPI - -static void -ntlm_sspi_cleanup(struct ntlmdata *ntlm) -{ - if(ntlm->type_2) { - free(ntlm->type_2); - ntlm->type_2 = NULL; - } - if(ntlm->has_handles) { - s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - ntlm->has_handles = 0; - } - if(ntlm->p_identity) { - if(ntlm->identity.User) free(ntlm->identity.User); - if(ntlm->identity.Password) free(ntlm->identity.Password); - if(ntlm->identity.Domain) free(ntlm->identity.Domain); - ntlm->p_identity = NULL; - } -} - -#endif - -#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) -#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ - (((x) >>16)&0xff), (((x)>>24) & 0xff) - -#define HOSTNAME_MAX 1024 - -#ifndef USE_WINDOWS_SSPI -/* copy the source to the destination and fill in zeroes in every - other destination byte! */ -static void unicodecpy(unsigned char *dest, - const char *src, size_t length) -{ - size_t i; - for(i=0; i<length; i++) { - dest[2*i] = (unsigned char)src[i]; - dest[2*i+1] = '\0'; - } -} -#endif - -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, - bool proxy) -{ - const char *domain=""; /* empty */ - char host [HOSTNAME_MAX+ 1] = ""; /* empty */ -#ifndef USE_WINDOWS_SSPI - size_t domlen = strlen(domain); - size_t hostlen = strlen(host); - size_t hostoff; /* host name offset */ - size_t domoff; /* domain name offset */ -#endif - size_t size; - char *base64=NULL; - unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very - long */ - - /* point to the address of the pointer that holds the string to sent to the - server, which is for a plain host or for a HTTP proxy */ - char **allocuserpwd; - - /* point to the name and password for this */ - const char *userp; - const char *passwdp; - /* point to the correct struct with this */ - struct ntlmdata *ntlm; - struct auth *authp; - - DEBUGASSERT(conn); - DEBUGASSERT(conn->data); - -#ifdef USE_NSS - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLE_OUT_OF_MEMORY; -#endif - - if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - ntlm = &conn->proxyntlm; - authp = &conn->data->state.authproxy; - } - else { - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - ntlm = &conn->ntlm; - authp = &conn->data->state.authhost; - } - authp->done = FALSE; - - /* not set means empty */ - if(!userp) - userp=""; - - if(!passwdp) - passwdp=""; - -#ifdef USE_WINDOWS_SSPI - if(s_hSecDll == NULL) { - /* not thread safe and leaks - use curl_global_init() to avoid */ - CURLcode err = Curl_sspi_global_init(); - if(s_hSecDll == NULL) - return err; - } -#endif - - switch(ntlm->state) { - case NTLMSTATE_TYPE1: - default: /* for the weird cases we (re)start here */ -#ifdef USE_WINDOWS_SSPI - { - SecBuffer buf; - SecBufferDesc desc; - SECURITY_STATUS status; - ULONG attrs; - const char *user; - int domlen; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - ntlm_sspi_cleanup(ntlm); - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = user - userp; - user++; - } - else { - user = userp; - domain = ""; - domlen = 0; - } - - if(user && *user) { - /* note: initialize all of this before doing the mallocs so that - * it can be cleaned up later without leaking memory. - */ - ntlm->p_identity = &ntlm->identity; - memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); - if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.UserLength = strlen(user); - if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.PasswordLength = strlen(passwdp); - if((ntlm->identity.Domain = malloc(domlen+1)) == NULL) - return CURLE_OUT_OF_MEMORY; - strncpy((char *)ntlm->identity.Domain, domain, domlen); - ntlm->identity.Domain[domlen] = '\0'; - ntlm->identity.DomainLength = domlen; - ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; - } - else { - ntlm->p_identity = NULL; - } - - if(s_pSecFn->AcquireCredentialsHandleA( - NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, - NULL, NULL, &ntlm->handle, &tsDummy - ) != SEC_E_OK) { - return CURLE_OUT_OF_MEMORY; - } - - desc.ulVersion = SECBUFFER_VERSION; - desc.cBuffers = 1; - desc.pBuffers = &buf; - buf.cbBuffer = sizeof(ntlmbuf); - buf.BufferType = SECBUFFER_TOKEN; - buf.pvBuffer = ntlmbuf; - - status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - NULL, 0, - &ntlm->c_handle, &desc, - &attrs, &tsDummy); - - if(status == SEC_I_COMPLETE_AND_CONTINUE || - status == SEC_I_CONTINUE_NEEDED) { - s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); - } - else if(status != SEC_E_OK) { - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - return CURLE_RECV_ERROR; - } - - ntlm->has_handles = 1; - size = buf.cbBuffer; - } -#else - hostoff = 0; - domoff = hostoff + hostlen; /* This is 0: remember that host and domain - are empty */ - - /* Create and send a type-1 message: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x01000000) - 12 Flags long - 16 Supplied Domain security buffer(*) - 24 Supplied Workstation security buffer(*) - 32 start of data block - - */ -#if USE_NTLM2SESSION -#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY -#else -#define NTLM2FLAG 0 -#endif - snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c" - "\x01%c%c%c" /* 32-bit type = 1 */ - "%c%c%c%c" /* 32-bit NTLM flag field */ - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host name offset */ - "%c%c" /* 2 zeroes */ - "%s" /* host name */ - "%s", /* domain string */ - 0, /* trailing zero */ - 0,0,0, /* part of type-1 long */ - - LONGQUARTET( - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN - ), - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0,0, - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0,0, - host /* this is empty */, domain /* this is empty */); - - /* initial packet length */ - size = 32 + hostlen + domlen; -#endif - - DEBUG_OUT({ - fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x " - "0x%08.8x ", - LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - print_flags(stderr, - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - fprintf(stderr, "\n****\n"); - }); - - /* now size is the size of the base64 encoded package size */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - break; - - case NTLMSTATE_TYPE2: - /* We received the type-2 message already, create a type-3 message: - - Index Description Content - 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP" - (0x4e544c4d53535000) - 8 NTLM Message Type long (0x03000000) - 12 LM/LMv2 Response security buffer(*) - 20 NTLM/NTLMv2 Response security buffer(*) - 28 Domain Name security buffer(*) - 36 User Name security buffer(*) - 44 Workstation Name security buffer(*) - (52) Session Key (optional) security buffer(*) - (60) Flags (optional) long - 52 (64) start of data block - - */ - - { -#ifdef USE_WINDOWS_SSPI - SecBuffer type_2, type_3; - SecBufferDesc type_2_desc, type_3_desc; - SECURITY_STATUS status; - ULONG attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = type_3_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2; - type_3_desc.pBuffers = &type_3; - - type_2.BufferType = SECBUFFER_TOKEN; - type_2.pvBuffer = ntlm->type_2; - type_2.cbBuffer = ntlm->n_type_2; - type_3.BufferType = SECBUFFER_TOKEN; - type_3.pvBuffer = ntlmbuf; - type_3.cbBuffer = sizeof(ntlmbuf); - - status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, - &ntlm->c_handle, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, &ntlm->c_handle, - &type_3_desc, - &attrs, &tsDummy); - - if(status != SEC_E_OK) - return CURLE_RECV_ERROR; - - size = type_3.cbBuffer; - - ntlm_sspi_cleanup(ntlm); - -#else - int lmrespoff; - unsigned char lmresp[24]; /* fixed-size */ -#if USE_NTRESPONSES - int ntrespoff; - unsigned char ntresp[24]; /* fixed-size */ -#endif - bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE)?TRUE:FALSE; - size_t useroff; - const char *user; - size_t userlen; - CURLcode res; - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = (user - domain); - user++; - } - else - user = userp; - userlen = strlen(user); - - if(Curl_gethostname(host, HOSTNAME_MAX)) { - infof(conn->data, "gethostname() failed, continuing without!"); - hostlen = 0; - } - else { - /* If the workstation if configured with a full DNS name (i.e. - * workstation.somewhere.net) gethostname() returns the fully qualified - * name, which NTLM doesn't like. - */ - char *dot = strchr(host, '.'); - if(dot) - *dot = '\0'; - hostlen = strlen(host); - } - - if(unicode) { - domlen = domlen * 2; - userlen = userlen * 2; - hostlen = hostlen * 2; - } - -#if USE_NTLM2SESSION - /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ - if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { - unsigned char ntbuffer[0x18]; - unsigned char tmp[0x18]; - unsigned char md5sum[MD5_DIGEST_LENGTH]; - unsigned char entropy[8]; - - /* Need to create 8 bytes random data */ -#ifdef USE_SSLEAY - MD5_CTX MD5pw; - Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */ - RAND_bytes(entropy,8); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD5pw; - Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */ - gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM); -#elif defined(USE_NSS) - PK11Context *MD5pw; - unsigned int outlen; - Curl_nss_seed(conn->data); /* Initiate the seed if not already done */ - PK11_GenerateRandom(entropy, 8); -#endif - - /* 8 bytes random data as challenge in lmresp */ - memcpy(lmresp,entropy,8); - /* Pad with zeros */ - memset(lmresp+8,0,0x10); - - /* Fill tmp with challenge(nonce?) + entropy */ - memcpy(tmp,&ntlm->nonce[0],8); - memcpy(tmp+8,entropy,8); - -#ifdef USE_SSLEAY - MD5_Init(&MD5pw); - MD5_Update(&MD5pw, tmp, 16); - MD5_Final(md5sum, &MD5pw); -#elif defined(USE_GNUTLS) - gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); - gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH); - memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH); - gcry_md_close(MD5pw); -#elif defined(USE_NSS) - MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); - PK11_DigestOp(MD5pw, tmp, 16); - PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH); - PK11_DestroyContext(MD5pw, PR_TRUE); -#endif - - /* We shall only use the first 8 bytes of md5sum, - but the des code in lm_resp only encrypt the first 8 bytes */ - if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, md5sum, ntresp); - - /* End of NTLM2 Session code */ - } - else -#endif - { - -#if USE_NTRESPONSES - unsigned char ntbuffer[0x18]; -#endif - unsigned char lmbuffer[0x18]; - -#if USE_NTRESPONSES - if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); -#endif - - mk_lm_hash(conn->data, passwdp, lmbuffer); - lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); - /* A safer but less compatible alternative is: - * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ - } - - lmrespoff = 64; /* size of the message header */ -#if USE_NTRESPONSES - ntrespoff = lmrespoff + 0x18; - domoff = ntrespoff + 0x18; -#else - domoff = lmrespoff + 0x18; -#endif - useroff = domoff + domlen; - hostoff = useroff + userlen; - - /* Create the big type-3 message binary blob */ - size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf), - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* type-3, 32 bits */ - - "%c%c" /* LanManager length */ - "%c%c" /* LanManager allocated space */ - "%c%c" /* LanManager offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* NT-response length */ - "%c%c" /* NT-response allocated space */ - "%c%c" /* NT-response offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* domain length */ - "%c%c" /* domain allocated space */ - "%c%c" /* domain name offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* user length */ - "%c%c" /* user allocated space */ - "%c%c" /* user offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* host length */ - "%c%c" /* host allocated space */ - "%c%c" /* host offset */ - "%c%c" /* 2 zeroes */ - - "%c%c" /* session key length (unknown purpose) */ - "%c%c" /* session key allocated space (unknown purpose) */ - "%c%c" /* session key offset (unknown purpose) */ - "%c%c" /* 2 zeroes */ - - "%c%c%c%c" /* flags */ - - /* domain string */ - /* user string */ - /* host string */ - /* LanManager response */ - /* NT response */ - , - 0, /* zero termination */ - 0,0,0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, - -#if USE_NTRESPONSES - SHORTPAIR(0x18), /* NT-response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(ntrespoff), - 0x0, 0x0, -#else - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, -#endif - SHORTPAIR(domlen), - SHORTPAIR(domlen), - SHORTPAIR(domoff), - 0x0, 0x0, - - SHORTPAIR(userlen), - SHORTPAIR(userlen), - SHORTPAIR(useroff), - 0x0, 0x0, - - SHORTPAIR(hostlen), - SHORTPAIR(hostlen), - SHORTPAIR(hostoff), - 0x0, 0x0, - - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - - LONGQUARTET(ntlm->flags)); - DEBUGASSERT(size==64); - - DEBUGASSERT(size == (size_t)lmrespoff); - /* We append the binary hashes */ - if(size < (sizeof(ntlmbuf) - 0x18)) { - memcpy(&ntlmbuf[size], lmresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE3 header lmresp="); - print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); - }); - -#if USE_NTRESPONSES - if(size < (sizeof(ntlmbuf) - 0x18)) { - DEBUGASSERT(size == (size_t)ntrespoff); - memcpy(&ntlmbuf[size], ntresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "\n ntresp="); - print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); - }); - -#endif - - DEBUG_OUT({ - fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(ntlm->flags), ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n****\n"); - }); - - - /* Make sure that the domain, user and host strings fit in the target - buffer before we copy them there. */ - if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) { - failf(conn->data, "user + domain + host name too big"); - return CURLE_OUT_OF_MEMORY; - } - - DEBUGASSERT(size == domoff); - if(unicode) - unicodecpy(&ntlmbuf[size], domain, domlen/2); - else - memcpy(&ntlmbuf[size], domain, domlen); - - size += domlen; - - DEBUGASSERT(size == useroff); - if(unicode) - unicodecpy(&ntlmbuf[size], user, userlen/2); - else - memcpy(&ntlmbuf[size], user, userlen); - - size += userlen; - - DEBUGASSERT(size == hostoff); - if(unicode) - unicodecpy(&ntlmbuf[size], host, hostlen/2); - else - memcpy(&ntlmbuf[size], host, hostlen); - - size += hostlen; - - /* convert domain, user, and host to ASCII but leave the rest as-is */ - res = Curl_convert_to_network(conn->data, (char *)&ntlmbuf[domoff], - size-domoff); - if(res) - return CURLE_CONV_FAILED; - -#endif - - /* convert the binary blob into base64 */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ - authp->done = TRUE; - } - break; - - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - if(*allocuserpwd) { - free(*allocuserpwd); - *allocuserpwd=NULL; - } - authp->done = TRUE; - break; - } - - return CURLE_OK; -} - - -void -Curl_ntlm_cleanup(struct connectdata *conn) -{ -#ifdef USE_WINDOWS_SSPI - ntlm_sspi_cleanup(&conn->ntlm); - ntlm_sspi_cleanup(&conn->proxyntlm); -#else - (void)conn; -#endif -} - - -#endif /* USE_NTLM */ -#endif /* !CURL_DISABLE_HTTP */ diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 9fa832e4d..f3b02c975 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -27,6 +27,7 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif + #include "urldata.h" #include <curl/curl.h> #include "http_proxy.h" diff --git a/lib/idn_win32.c b/lib/idn_win32.c index 96d3f0959..70286c0fd 100644 --- a/lib/idn_win32.c +++ b/lib/idn_win32.c @@ -19,13 +19,15 @@ * KIND, either express or implied. * ***************************************************************************/ -/*************************************************************************** - * IDN Implementation using windows native APIs - * Pierre Joye <pierre@php.net> - ***************************************************************************/ -#if defined(WIN32) && defined(USE_WIN32_IDN) -#include <windows.h> -#include <stdio.h> + + /* + * IDN conversions using Windows kernel32 and normaliz libraries. + */ + +#include "setup.h" + +#ifdef USE_WIN32_IDN + #include <tchar.h> #ifdef WANT_IDN_PROTOTYPES @@ -121,7 +123,5 @@ int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8) } return 1; } -#else -typedef int dummy; /* because ISO C forbids an empty translation unit! */ -#endif - /* WIN32 */ + +#endif /* USE_WIN32_IDN */ diff --git a/lib/imap.c b/lib/imap.c index b135443d3..986b79a56 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -26,11 +26,6 @@ #include "setup.h" #ifndef CURL_DISABLE_IMAP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -124,6 +119,7 @@ const struct Curl_handler Curl_handler_imap = { imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -149,6 +145,7 @@ const struct Curl_handler Curl_handler_imaps = { imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -174,6 +171,7 @@ static const struct Curl_handler Curl_handler_imap_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -199,6 +197,7 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -215,9 +214,6 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { * * Sends the formated string as an IMAP command to a server * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * Designed to never block. */ static CURLcode imapsendf(struct connectdata *conn, @@ -343,7 +339,7 @@ static void imap_to_imaps(struct connectdata *conn) conn->handler = &Curl_handler_imaps; } #else -#define imap_to_imaps(x) +#define imap_to_imaps(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -638,7 +634,7 @@ static CURLcode imap_multi_statemach(struct connectdata *conn, else result = Curl_pp_multi_statemach(&imapc->pp); - *done = (bool)(imapc->state == IMAP_STOP); + *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE; return result; } @@ -846,7 +842,7 @@ CURLcode imap_perform(struct connectdata *conn, result = imap_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c index 34cae801a..1bb97443b 100644 --- a/lib/inet_ntop.c +++ b/lib/inet_ntop.c @@ -34,8 +34,6 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#include <string.h> -#include <errno.h> #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> diff --git a/lib/inet_pton.c b/lib/inet_pton.c index d08c7c666..021f48d52 100644 --- a/lib/inet_pton.c +++ b/lib/inet_pton.c @@ -32,8 +32,6 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#include <string.h> -#include <errno.h> #include "inet_pton.h" diff --git a/lib/krb4.c b/lib/krb4.c index 7da47f31f..b53a6104c 100644 --- a/lib/krb4.c +++ b/lib/krb4.c @@ -44,11 +44,9 @@ #ifndef CURL_DISABLE_FTP #ifdef HAVE_KRB4 -#include <stdlib.h> #ifdef HAVE_NETDB_H #include <netdb.h> #endif -#include <string.h> #include <krb.h> #include <des.h> @@ -203,7 +201,7 @@ krb4_auth(void *app_data, struct connectdata *conn) int ret; char *p; unsigned char *ptr; - size_t len; + size_t len = 0; KTEXT_ST adat; MSG_DAT msg_data; int checksum; @@ -214,6 +212,7 @@ krb4_auth(void *app_data, struct connectdata *conn) int l = sizeof(conn->local_addr); struct SessionHandle *data = conn->data; CURLcode result; + size_t base64_sz = 0; if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)LOCAL_ADDR, &l) < 0) @@ -249,8 +248,10 @@ krb4_auth(void *app_data, struct connectdata *conn) } #endif - if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) { - Curl_failf(data, "Out of memory base64-encoding"); + result = Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, + &p, &base64_sz); + if(result) { + Curl_failf(data, "base64-encoding: %s", curl_easy_strerror(result)); return AUTH_CONTINUE; } @@ -264,7 +265,7 @@ krb4_auth(void *app_data, struct connectdata *conn) if(Curl_GetFTPResponse(&nread, conn, NULL)) return -1; - if(data->state.buffer[0] != '2'){ + if(data->state.buffer[0] != '2') { Curl_failf(data, "Server didn't accept auth data"); return AUTH_ERROR; } @@ -275,10 +276,15 @@ krb4_auth(void *app_data, struct connectdata *conn) return AUTH_ERROR; } p += 5; - len = Curl_base64_decode(p, &ptr); + result = Curl_base64_decode(p, &ptr, &len); + if(result) { + Curl_failf(data, "base64-decoding: %s", curl_easy_strerror(result)); + return AUTH_ERROR; + } if(len > sizeof(adat.dat)-1) { free(ptr); - len=0; + ptr = NULL; + len = 0; } if(!len || !ptr) { Curl_failf(data, "Failed to decode base64 from server"); @@ -332,11 +338,12 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) char *name; char *p; char passwd[100]; - size_t tmp; + size_t tmp = 0; ssize_t nread; enum protection_level save; CURLcode result; unsigned char *ptr; + size_t base64_sz = 0; save = krb4_set_command_prot(conn, PROT_PRIVATE); @@ -349,7 +356,7 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) if(result) return result; - if(conn->data->state.buffer[0] != '3'){ + if(conn->data->state.buffer[0] != '3') { krb4_set_command_prot(conn, save); return CURLE_FTP_WEIRD_SERVER_REPLY; } @@ -362,10 +369,15 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) } p += 2; - tmp = Curl_base64_decode(p, &ptr); + result = Curl_base64_decode(p, &ptr, &tmp); + if(result) { + Curl_failf(conn->data, "base64-decoding: %s", curl_easy_strerror(result)); + return result; + } if(tmp >= sizeof(tkt.dat)) { free(ptr); - tmp=0; + ptr = NULL; + tmp = 0; } if(!tmp || !ptr) { Curl_failf(conn->data, "Failed to decode base64 in reply"); @@ -406,11 +418,12 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) memset(key, 0, sizeof(key)); memset(schedule, 0, sizeof(schedule)); memset(passwd, 0, sizeof(passwd)); - if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p) - < 1) { - failf(conn->data, "Out of memory base64-encoding."); + result = Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, + &p, &base64_sz); + if(result) { + Curl_failf(conn->data, "base64-encoding: %s", curl_easy_strerror(result)); krb4_set_command_prot(conn, save); - return CURLE_OUT_OF_MEMORY; + return result; } memset (tktcopy.dat, 0, tktcopy.length); diff --git a/lib/krb5.c b/lib/krb5.c index f128d515f..96938dd6e 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -39,29 +39,17 @@ #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 #endif -#include <stdlib.h> #ifdef HAVE_NETDB_H #include <netdb.h> #endif -#include <string.h> - -#ifdef HAVE_GSSGNU -# include <gss.h> -#elif defined HAVE_GSSMIT - /* MIT style */ -# include <gssapi/gssapi.h> -# include <gssapi/gssapi_generic.h> -# include <gssapi/gssapi_krb5.h> -#else - /* Heimdal-style */ -# include <gssapi.h> -#endif #include "urldata.h" #include "curl_base64.h" #include "ftp.h" +#include "curl_gssapi.h" #include "sendf.h" #include "krb4.h" #include "curl_memory.h" @@ -94,16 +82,16 @@ krb5_check_prot(void *app_data, int level) } static int -krb5_decode(void *app_data, void *buf, int len, int level, - struct connectdata *conn) +krb5_decode(void *app_data, void *buf, int len, + int level UNUSED_PARAM, + struct connectdata *conn UNUSED_PARAM) { gss_ctx_id_t *context = app_data; OM_uint32 maj, min; gss_buffer_desc enc, dec; - /* shut gcc up */ - level = 0; - conn = NULL; + (void)level; + (void)conn; enc.value = buf; enc.length = len; @@ -133,7 +121,7 @@ krb5_overhead(void *app_data, int level, int len) static int krb5_encode(void *app_data, const void *from, int length, int level, void **to, - struct connectdata *conn) + struct connectdata *conn UNUSED_PARAM) { gss_ctx_id_t *context = app_data; gss_buffer_desc dec, enc; @@ -184,6 +172,7 @@ krb5_auth(void *app_data, struct connectdata *conn) gss_name_t gssname; gss_ctx_id_t *context = app_data; struct gss_channel_bindings_struct chan; + size_t base64_sz = 0; if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)LOCAL_ADDR, &l) < 0) @@ -201,7 +190,7 @@ krb5_auth(void *app_data, struct connectdata *conn) chan.application_data.value = NULL; /* this loop will execute twice (once for service, once for host) */ - while(1) { + for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { result = Curl_ftpsendf(conn, "AUTH GSSAPI"); @@ -242,19 +231,14 @@ krb5_auth(void *app_data, struct connectdata *conn) taken care by a final gss_release_buffer. */ gss_release_buffer(&min, &output_buffer); ret = AUTH_OK; - maj = gss_init_sec_context(&min, - GSS_C_NO_CREDENTIAL, - context, - gssname, - GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, - 0, - &chan, - gssresp, - NULL, - &output_buffer, - NULL, - NULL); + maj = Curl_gss_init_sec_context(data, + &min, + context, + gssname, + &chan, + gssresp, + &output_buffer, + NULL); if(gssresp) { free(_gssresp.value); @@ -268,9 +252,10 @@ krb5_auth(void *app_data, struct connectdata *conn) } if(output_buffer.length != 0) { - if(Curl_base64_encode(data, (char *)output_buffer.value, - output_buffer.length, &p) < 1) { - Curl_infof(data, "Out of memory base64-encoding\n"); + result = Curl_base64_encode(data, (char *)output_buffer.value, + output_buffer.length, &p, &base64_sz); + if(result) { + Curl_infof(data,"base64-encoding: %s\n", curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } @@ -289,7 +274,7 @@ krb5_auth(void *app_data, struct connectdata *conn) break; } - if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3'){ + if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { Curl_infof(data, "Server didn't accept auth data\n"); ret = AUTH_ERROR; break; @@ -298,10 +283,11 @@ krb5_auth(void *app_data, struct connectdata *conn) p = data->state.buffer + 4; p = strstr(p, "ADAT="); if(p) { - _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **) - &_gssresp.value); - if(_gssresp.length < 1) { - Curl_failf(data, "Out of memory base64-encoding\n"); + result = Curl_base64_decode(p + 5, + (unsigned char **)&_gssresp.value, + &_gssresp.length); + if(result) { + Curl_failf(data,"base64-decoding: %s", curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } diff --git a/lib/ldap.c b/lib/ldap.c index 62a9ffc19..737847649 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -35,14 +35,6 @@ * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - #ifdef CURL_LDAP_WIN /* Use Windows LDAP implementation. */ # include <winldap.h> # ifndef LDAP_VENDOR_NAME @@ -113,11 +105,11 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp); #define LDAP_TRACE(x) do { \ _ldap_trace ("%u: ", __LINE__); \ _ldap_trace x; \ - } while(0) + } WHILE_FALSE static void _ldap_trace (const char *fmt, ...); #else - #define LDAP_TRACE(x) ((void)0) + #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -138,6 +130,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -162,6 +155,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -184,9 +178,9 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) struct SessionHandle *data=conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; - char *val_b64; - size_t val_b64_sz; - curl_off_t dlsize=0; + char *val_b64 = NULL; + size_t val_b64_sz = 0; + curl_off_t dlsize = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */ #endif @@ -413,10 +407,20 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) (char *)attribute + (strlen((char *)attribute) - 7)) == 0)) { /* Binary attribute, encode to base64. */ - val_b64_sz = Curl_base64_encode(data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64); + CURLcode error = Curl_base64_encode(data, + vals[i]->bv_val, + vals[i]->bv_len, + &val_b64, + &val_b64_sz); + if(error) { + ldap_value_free_len(vals); + ldap_memfree(attribute); + ldap_memfree(dn); + if(ber) + ber_free(ber, 0); + status = error; + goto quit; + } if(val_b64_sz > 0) { Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); free(val_b64); diff --git a/lib/libcurl.imp b/lib/libcurl.imp index 74943afa7..7c99a9468 100644 --- a/lib/libcurl.imp +++ b/lib/libcurl.imp @@ -9,6 +9,8 @@ curl_easy_init, curl_easy_pause, curl_easy_perform, + curl_easy_recv, + curl_easy_send, curl_easy_setopt, curl_escape, curl_unescape, @@ -38,6 +40,8 @@ curl_multi_perform, curl_multi_cleanup, curl_multi_info_read, + curl_multi_setopt, + curl_multi_timeout, curl_free, curl_version_info, curl_share_init, diff --git a/lib/llist.c b/lib/llist.c index 8b4bc7f20..a302e32d5 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> - #include "llist.h" #include "curl_memory.h" @@ -49,7 +46,7 @@ Curl_llist_alloc(curl_llist_dtor dtor) struct curl_llist *list; list = malloc(sizeof(struct curl_llist)); - if(NULL == list) + if(!list) return NULL; llist_init(list, dtor); @@ -134,6 +131,10 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, list->dtor(user, e->ptr); + e->ptr = NULL; + e->prev = NULL; + e->next = NULL; + free(e); --list->size; @@ -27,7 +27,6 @@ #ifdef USE_NSS #include "curl_md4.h" -#include <string.h> typedef unsigned int UINT4; @@ -24,8 +24,6 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH -#include <string.h> - #include "curl_md5.h" #include "curl_hmac.h" diff --git a/lib/memdebug.c b/lib/memdebug.c index 69e204b6a..0b81621cb 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -32,10 +32,6 @@ #define _MPRINTF_REPLACE #include <curl/mprintf.h> #include "urldata.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -46,12 +42,59 @@ #include "memdebug.h" #ifndef HAVE_ASSERT_H -# define assert(x) do { } while (0) +# define assert(x) Curl_nop_stmt +#endif + +/* + * Until 2011-08-17 libcurl's Memory Tracking feature also performed + * automatic malloc and free filling operations using 0xA5 and 0x13 + * values. Our own preinitialization of dynamically allocated memory + * might be useful when not using third party memory debuggers, but + * on the other hand this would fool memory debuggers into thinking + * that all dynamically allocated memory is properly initialized. + * + * As a default setting, libcurl's Memory Tracking feature no longer + * performs preinitialization of dynamically allocated memory on its + * own. If you know what you are doing, and really want to retain old + * behavior, you can achieve this compiling with preprocessor symbols + * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate + * values. + */ + +#ifdef CURL_MT_MALLOC_FILL +# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff) +# error "invalid CURL_MT_MALLOC_FILL or out of range" +# endif +#endif + +#ifdef CURL_MT_FREE_FILL +# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff) +# error "invalid CURL_MT_FREE_FILL or out of range" +# endif +#endif + +#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL) +# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL) +# error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL" +# endif +#endif + +#ifdef CURL_MT_MALLOC_FILL +# define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len)) +#else +# define mt_malloc_fill(buf,len) Curl_nop_stmt +#endif + +#ifdef CURL_MT_FREE_FILL +# define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len)) +#else +# define mt_free_fill(buf,len) Curl_nop_stmt #endif struct memdebug { size_t size; union { + curl_off_t o; double d; void * p; } mem[1]; @@ -76,7 +119,7 @@ static long memsize = 0; /* set number of mallocs allowed */ void curl_memdebug(const char *logname) { if(!logfile) { - if(logname) + if(logname && *logname) logfile = fopen(logname, "w"); else logfile = stderr; @@ -144,7 +187,7 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source) mem = (Curl_cmalloc)(size); if(mem) { /* fill memory with junk */ - memset(mem->mem, 0xA5, wantedsize); + mt_malloc_fill(mem->mem, wantedsize); mem->size = wantedsize; } @@ -170,12 +213,9 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size, user_size = wanted_size * wanted_elements; size = sizeof(struct memdebug) + user_size; - mem = (Curl_cmalloc)(size); - if(mem) { - /* fill memory with zeroes */ - memset(mem->mem, 0, user_size); + mem = (Curl_ccalloc)(1, size); + if(mem) mem->size = user_size; - } if(source) curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n", @@ -264,8 +304,8 @@ void curl_dofree(void *ptr, int line, const char *source) # pragma warning(pop) #endif - /* destroy */ - memset(mem->mem, 0x13, mem->size); + /* destroy */ + mt_free_fill(mem->mem, mem->size); /* free for real */ (Curl_cfree)(mem); @@ -289,6 +329,24 @@ curl_socket_t curl_socket(int domain, int type, int protocol, return sockfd; } +#ifdef HAVE_SOCKETPAIR +int curl_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line, const char *source) +{ + const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? + "FD %s:%d socketpair() = %d %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d socketpair() = %ld %ld\n" : + "FD %s:%d socketpair() = %zd %zd\n" ; + + int res = socketpair(domain, type, protocol, socket_vector); + if(source && (0 == res)) + curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]); + return res; +} +#endif + curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, int line, const char *source) { diff --git a/lib/memdebug.h b/lib/memdebug.h index 77a4f4774..1e02645f9 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -1,6 +1,6 @@ +#ifndef HEADER_CURL_MEMDEBUG_H +#define HEADER_CURL_MEMDEBUG_H #ifdef CURLDEBUG -#ifndef _CURL_MEMDEBUG_H -#define _CURL_MEMDEBUG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -32,14 +32,11 @@ #include <curl/curl.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif -#include <stdio.h> + +#define CURL_MT_LOGFNAME_BUFSIZE 512 #define logfile curl_debuglogfile @@ -66,6 +63,11 @@ CURL_EXTERN int curl_sclose(curl_socket_t sockfd, 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); +#endif /* FILE functions */ CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line, @@ -91,6 +93,10 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #undef accept /* for those with accept as a macro */ #define accept(sock,addr,len)\ curl_accept(sock,addr,len,__LINE__,__FILE__) +#ifdef HAVE_SOCKETPAIR +#define socketpair(domain,type,protocol,socket_vector)\ + curl_socketpair(domain,type,protocol,socket_vector,__LINE__,__FILE__) +#endif #ifdef HAVE_GETADDRINFO #if defined(getaddrinfo) && defined(__osf__) @@ -133,9 +139,23 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #endif /* MEMDEBUG_NODEFINES */ -#endif /* _CURL_MEMDEBUG_H */ #endif /* CURLDEBUG */ +/* +** Following section applies even when CURLDEBUG is not defined. +*/ + #ifndef fake_sclose -#define fake_sclose(x) +#define fake_sclose(x) Curl_nop_stmt #endif + +/* + * Curl_safefree defined as a macro to allow MemoryTracking feature + * to log free() calls at same location where Curl_safefree is used. + * This macro also assigns NULL to given pointer when free'd. + */ + +#define Curl_safefree(ptr) \ + do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE + +#endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/lib/mk-ca-bundle.pl b/lib/mk-ca-bundle.pl index 231762e60..189ed01b6 100755 --- a/lib/mk-ca-bundle.pl +++ b/lib/mk-ca-bundle.pl @@ -40,7 +40,7 @@ my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/ # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; -my $version = '1.15'; +my $version = '1.16'; getopts('bhilnqtuv'); @@ -77,15 +77,13 @@ my $resp; unless ($opt_n and -e $txt) { print "Downloading '$txt' ...\n" if (!$opt_q); - my $ua = new LWP::UserAgent(agent => "$0/$version"); $ua->env_proxy(); $resp = $ua->mirror($url, $txt); -} - -if ($resp && $resp->code eq '304') { + if ($resp && $resp->code eq '304') { print "Not modified\n" unless $opt_q; exit 0; + } } my $currentdate = scalar gmtime($resp ? $resp->last_modified : (stat($txt))[9]); @@ -124,6 +122,7 @@ close(CRT) or die "Couldn't close $crt: $!"; print "Processing '$txt' ...\n" if (!$opt_q); my $caname; my $certnum = 0; +my $skipnum = 0; open(TXT,"$txt") or die "Couldn't open $txt: $!"; while (<TXT>) { if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { @@ -147,6 +146,7 @@ while (<TXT>) { if (/^CKA_LABEL\s+[A-Z0-9]+\s+\"(.*)\"/) { $caname = $1; } + my $untrusted = 0; if (/^CKA_VALUE MULTILINE_OCTAL/) { my $data; while (<TXT>) { @@ -158,28 +158,37 @@ while (<TXT>) { $data .= chr(oct); } } - my $pem = "-----BEGIN CERTIFICATE-----\n" - . MIME::Base64::encode($data) - . "-----END CERTIFICATE-----\n"; - open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; - print CRT "\n$caname\n"; - print CRT ("=" x length($caname) . "\n"); - if (!$opt_t) { - print CRT $pem; + while (<TXT>) { + last if (/^#$/); + $untrusted = 1 if (/^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_NOT_TRUSTED$/ + or /^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_TRUST_UNKNOWN$/); } - close(CRT) or die "Couldn't close $crt: $!"; - if ($opt_t) { - open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; + if ($untrusted) { + $skipnum ++; + } else { + my $pem = "-----BEGIN CERTIFICATE-----\n" + . MIME::Base64::encode($data) + . "-----END CERTIFICATE-----\n"; + open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; + print CRT "\n$caname\n"; + print CRT ("=" x length($caname) . "\n"); + if (!$opt_t) { + print CRT $pem; + } + close(CRT) or die "Couldn't close $crt: $!"; + if ($opt_t) { + open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + } + print "Parsing: $caname\n" if ($opt_v); + $certnum ++; } - print "Parsing: $caname\n" if ($opt_v); - $certnum ++; } } close(TXT) or die "Couldn't close $txt: $!"; unlink $txt if ($opt_u); -print "Done ($certnum CA certs processed).\n" if (!$opt_q); +print "Done ($certnum CA certs processed, $skipnum untrusted skipped).\n" if (!$opt_q); exit; diff --git a/lib/mprintf.c b/lib/mprintf.c index dd7a1e09b..0990f4024 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -36,11 +36,6 @@ */ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> -#include <string.h> #if defined(DJGPP) && (DJGPP_MINOR < 4) #undef _MPRINTF_REPLACE /* don't use x_was_used() here */ @@ -108,7 +103,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; done++; \ else \ return done; /* return immediately on failure */ \ - } while(0) + } WHILE_FALSE /* Data type to read from the arglist */ typedef enum { diff --git a/lib/multi.c b/lib/multi.c index aee190cea..6e4ec37a8 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -41,6 +41,7 @@ #include "sendf.h" #include "timeval.h" #include "http.h" +#include "select.h" #include "warnless.h" #define _MPRINTF_REPLACE /* use our functions only */ @@ -124,9 +125,9 @@ struct Curl_one_easy { #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ - ((x)&&(((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) + ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) #define GOOD_EASY_HANDLE(x) \ - (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER) + ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) /* This is the struct known as CURLM on the outside */ struct Curl_multi { @@ -134,7 +135,7 @@ struct Curl_multi { this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ long type; - /* We have a linked list with easy handles */ + /* We have a doubly-linked circular list with easy handles */ struct Curl_one_easy easy; int num_easy; /* amount of entries in the linked list above. */ @@ -424,12 +425,13 @@ CURLM *curl_multi_init(void) return (CURLM *) multi; error: - if(multi->sockhash) - Curl_hash_destroy(multi->sockhash); - if(multi->hostcache) - Curl_hash_destroy(multi->hostcache); - if(multi->connc) - Curl_rm_connc(multi->connc); + + Curl_hash_destroy(multi->sockhash); + multi->sockhash = NULL; + Curl_hash_destroy(multi->hostcache); + multi->hostcache = NULL; + Curl_rm_connc(multi->connc); + multi->connc = NULL; free(multi); return NULL; @@ -438,11 +440,12 @@ CURLM *curl_multi_init(void) CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct curl_llist *timeoutlist; struct Curl_one_easy *easy; struct closure *cl; - struct closure *prev=NULL; - struct SessionHandle *data = easy_handle; + struct closure *prev = NULL; + struct Curl_multi *multi = (struct Curl_multi *)multi_handle; + struct SessionHandle *data = (struct SessionHandle *)easy_handle; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -452,39 +455,74 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, if(!GOOD_EASY_HANDLE(easy_handle)) return CURLM_BAD_EASY_HANDLE; - /* Prevent users to add the same handle more than once! */ - if(((struct SessionHandle *)easy_handle)->multi) + /* Prevent users from adding same easy handle more than + once and prevent adding to more than one multi stack */ + if(data->multi) /* possibly we should create a new unique error code for this condition */ return CURLM_BAD_EASY_HANDLE; - data->state.timeoutlist = Curl_llist_alloc(multi_freetimeout); - if(!data->state.timeoutlist) + /* We want the connection cache to have plenty of room. Before we supported + the shared cache every single easy handle had 5 entries in their cache + by default. */ + if(((multi->num_easy + 1) * 4) > multi->connc->num) { + long newmax = (multi->num_easy + 1) * 4; + + if(multi->maxconnects && (newmax > multi->maxconnects)) + /* don't grow beyond the allowed size */ + newmax = multi->maxconnects; + + if(newmax > multi->connc->num) { + /* we only do this is we can in fact grow the cache */ + CURLcode res = Curl_ch_connc(data, multi->connc, newmax); + if(res) + return CURLM_OUT_OF_MEMORY; + } + } + + /* Allocate and initialize timeout list for easy handle */ + timeoutlist = Curl_llist_alloc(multi_freetimeout); + if(!timeoutlist) return CURLM_OUT_OF_MEMORY; - /* Now, time to add an easy handle to the multi stack */ + /* Allocate new node for the doubly-linked circular list of + Curl_one_easy structs that holds pointers to easy handles */ easy = calloc(1, sizeof(struct Curl_one_easy)); - if(!easy) + if(!easy) { + Curl_llist_destroy(timeoutlist, NULL); return CURLM_OUT_OF_MEMORY; + } + + /* + ** No failure allowed in this function beyond this point. And + ** no modification of easy nor multi handle allowed before this + ** except for potential multi's connection cache growing which + ** won't be undone in this function no matter what. + */ + + /* Make easy handle use timeout list initialized above */ + data->state.timeoutlist = timeoutlist; + timeoutlist = NULL; + /* Remove handle from the list of 'closure handles' in case it is there */ cl = multi->closure; while(cl) { struct closure *next = cl->next; - if(cl->easy_handle == (struct SessionHandle *)easy_handle) { - /* remove this handle from the closure list */ + if(cl->easy_handle == data) { + /* Remove node from list */ free(cl); if(prev) prev->next = next; else multi->closure = next; - break; /* no need to continue since this handle can only be present once - in the list */ + /* No need to continue, handle can only be present once in the list */ + break; } prev = cl; cl = next; } /* set the easy handle */ - easy->easy_handle = easy_handle; + easy->easy_handle = data; multistate(easy, CURLM_STATE_INIT); /* set the back pointer to one_easy to assist in removal */ @@ -505,25 +543,21 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, easy->easy_handle->dns.hostcachetype = HCACHE_MULTI; } - if(easy->easy_handle->state.connc) { - if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) { - /* kill old private version */ - Curl_rm_connc(easy->easy_handle->state.connc); - /* point out our shared one instead */ - easy->easy_handle->state.connc = multi->connc; - } - /* else it is already using multi? */ + /* On a multi stack the connection cache, owned by the multi handle, + is shared between all easy handles within the multi handle. */ + if(easy->easy_handle->state.connc && + (easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE)) { + /* kill old private connection cache */ + Curl_rm_connc(easy->easy_handle->state.connc); + easy->easy_handle->state.connc = NULL; } - else - /* point out our shared one */ - easy->easy_handle->state.connc = multi->connc; - - /* Make sure the type is setup correctly */ + /* Point now to this multi's connection cache */ + easy->easy_handle->state.connc = multi->connc; easy->easy_handle->state.connc->type = CONNCACHE_MULTI; - /* This adds the new entry at the back of the list - to try and maintain a FIFO queue so the pipelined - requests are in order. */ + /* This adds the new entry at the 'end' of the doubly-linked circular + list of Curl_one_easy structs to try and maintain a FIFO queue so + the pipelined requests are in order. */ /* We add this new entry last in the list. We make our 'next' point to the 'first' struct and our 'prev' point to the previous 'prev' */ @@ -537,6 +571,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, the new node */ easy->prev->next = easy; + /* make the SessionHandle refer back to this multi handle */ Curl_easy_addmulti(easy_handle, multi_handle); /* make the SessionHandle struct refer back to this struct */ @@ -553,27 +588,6 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, /* increase the node-counter */ multi->num_easy++; - if((multi->num_easy * 4) > multi->connc->num) { - /* We want the connection cache to have plenty room. Before we supported - the shared cache every single easy handle had 5 entries in their cache - by default. */ - long newmax = multi->num_easy * 4; - - if(multi->maxconnects && (multi->maxconnects < newmax)) - /* don't grow beyond the allowed size */ - newmax = multi->maxconnects; - - if(newmax > multi->connc->num) { - /* we only do this is we can in fact grow the cache */ - CURLcode res = Curl_ch_connc(easy_handle, multi->connc, newmax); - if(res != CURLE_OK) { - /* FIXME: may need to do more cleanup here */ - curl_multi_remove_handle(multi_handle, easy_handle); - return CURLM_OUT_OF_MEMORY; - } - } - } - /* increase the alive-counter */ multi->num_alive++; @@ -628,9 +642,10 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, easy = data->multi_pos; if(easy) { - bool premature = (bool)(easy->state < CURLM_STATE_COMPLETED); - bool easy_owns_conn = (bool)(easy->easy_conn && - (easy->easy_conn->data == easy->easy_handle)); + bool premature = (easy->state < CURLM_STATE_COMPLETED) ? TRUE : FALSE; + bool easy_owns_conn = (easy->easy_conn && + (easy->easy_conn->data == easy->easy_handle)) ? + TRUE : FALSE; /* If the 'state' is not INIT or COMPLETED, we might need to do something nice to put the easy_handle in a good known state when this returns. */ @@ -801,20 +816,12 @@ static int waitconnect_getsock(struct connectdata *conn, } static int domore_getsock(struct connectdata *conn, - curl_socket_t *sock, + curl_socket_t *socks, int numsocks) { - if(!numsocks) - return GETSOCK_BLANK; - - /* When in DO_MORE state, we could be either waiting for us - to connect to a remote site, or we could wait for that site - to connect to us. It makes a difference in the way: if we - connect to the site we wait for the socket to become writable, if - the site connects to us we wait for it to become readable */ - sock[0] = conn->sock[SECONDARYSOCKET]; - - return GETSOCK_WRITESOCK(0); + if(conn && conn->handler->domore_getsock) + return conn->handler->domore_getsock(conn, socks, numsocks); + return GETSOCK_BLANK; } /* returns bitmapped flags for this handle and its sockets */ @@ -906,11 +913,11 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; - if(bitmap & GETSOCK_READSOCK(i)) { + if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], read_fd_set); s = sockbunch[i]; } - if(bitmap & GETSOCK_WRITESOCK(i)) { + if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], write_fd_set); s = sockbunch[i]; } @@ -952,8 +959,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, data = easy->easy_handle; do { - /* this is a do-while loop just to allow a break to skip to the end - of it */ + /* this is a single-iteration do-while loop just to allow a + break to skip to the end of it */ bool disconnect_conn = FALSE; /* Handle the case when the pipe breaks, i.e., the connection @@ -1039,7 +1046,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Add this handle to the send or pend pipeline */ easy->result = addHandleToSendOrPendPipeline(data, easy->easy_conn); - if(CURLE_OK == easy->result) { + if(CURLE_OK != easy->result) + disconnect_conn = TRUE; + else { if(async) /* We're now waiting for an asynchronous name lookup */ multistate(easy, CURLM_STATE_WAITRESOLVE); @@ -1282,7 +1291,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, disconnect_conn = TRUE; } else - retry = (bool)(newurl?TRUE:FALSE); + retry = (newurl)?TRUE:FALSE; Curl_posttransfer(data); drc = Curl_done(&easy->easy_conn, easy->result, FALSE); @@ -1481,14 +1490,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(data); Curl_done(&easy->easy_conn, easy->result, FALSE); } - else if(TRUE == done) { + else if(done) { char *newurl = NULL; bool retry = FALSE; followtype follow=FOLLOW_NONE; easy->result = Curl_retry_request(easy->easy_conn, &newurl); if(!easy->result) - retry = (bool)(newurl?TRUE:FALSE); + retry = (newurl)?TRUE:FALSE; /* call this even if the readwrite function returned error */ Curl_posttransfer(data); @@ -1537,8 +1546,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, newurl = data->req.location; data->req.location = NULL; easy->result = Curl_follow(data, newurl, FOLLOW_FAKE); - if(easy->result) + if(easy->result) { + disconnect_conn = TRUE; free(newurl); + } } multistate(easy, CURLM_STATE_DONE); @@ -1615,7 +1626,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_INTERNAL_ERROR; } - if(CURLM_STATE_COMPLETED > easy->state) { + if(easy->state < CURLM_STATE_COMPLETED) { if(CURLE_OK != easy->result) { /* * If an error was returned, and we aren't in completed state now, @@ -1639,25 +1650,37 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, easy->easy_conn->done_pipe); /* Check if we can move pending requests to send pipe */ checkPendPipeline(easy->easy_conn); - } - if(disconnect_conn) { - /* disconnect properly */ - Curl_disconnect(easy->easy_conn, /* dead_connection */ FALSE); + if(disconnect_conn) { + /* disconnect properly */ + Curl_disconnect(easy->easy_conn, /* dead_connection */ FALSE); - /* This is where we make sure that the easy_conn pointer is reset. - We don't have to do this in every case block above where a - failure is detected */ - easy->easy_conn = NULL; + /* This is where we make sure that the easy_conn pointer is reset. + We don't have to do this in every case block above where a + failure is detected */ + easy->easy_conn = NULL; + } + } + else if(easy->state == CURLM_STATE_CONNECT) { + /* Curl_connect() failed */ + (void)Curl_posttransfer(data); } multistate(easy, CURLM_STATE_COMPLETED); } /* if there's still a connection to use, call the progress function */ - else if(easy->easy_conn && Curl_pgrsUpdate(easy->easy_conn)) - easy->result = CURLE_ABORTED_BY_CALLBACK; + else if(easy->easy_conn && Curl_pgrsUpdate(easy->easy_conn)) { + /* aborted due to progress callback return code must close the + connection */ + easy->easy_conn->bits.close = TRUE; + + /* if not yet in DONE state, go there, otherwise COMPLETED */ + multistate(easy, (easy->state < CURLM_STATE_DONE)? + CURLM_STATE_DONE: CURLM_STATE_COMPLETED); + result = CURLM_CALL_MULTI_PERFORM; + } } - } while(0); + } WHILE_FALSE; /* just to break out from! */ if(CURLM_STATE_COMPLETED == easy->state) { if(data->dns.hostcachetype == HCACHE_MULTI) { @@ -1787,9 +1810,11 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) } Curl_rm_connc(multi->connc); + multi->connc = NULL; /* remove the pending list of messages */ Curl_llist_destroy(multi->msglist, NULL); + multi->msglist = NULL; /* remove all easy handles */ easy = multi->easy.next; @@ -2213,7 +2238,7 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, multi->socket_userp = va_arg(param, void *); break; case CURLMOPT_PIPELINING: - multi->pipelining_enabled = (bool)(0 != va_arg(param, long)); + multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLMOPT_TIMERFUNCTION: multi->timer_cb = va_arg(param, curl_multi_timer_callback); @@ -2478,7 +2503,7 @@ static bool isHandleAtHead(struct SessionHandle *handle, { struct curl_llist_element *curr = pipeline->head; if(curr) - return (bool)(curr->ptr == handle); + return (curr->ptr == handle) ? TRUE : FALSE; return FALSE; } diff --git a/lib/netrc.c b/lib/netrc.c index 5541a2f29..6764b974d 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -22,10 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #ifdef HAVE_UNISTD_H #include <unistd.h> #endif diff --git a/lib/non-ascii.h b/lib/non-ascii.h index 4e303dff8..6dcbe0044 100644 --- a/lib/non-ascii.h +++ b/lib/non-ascii.h @@ -51,9 +51,9 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data, CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form); #else #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) -#define Curl_convert_init(x) -#define Curl_convert_setup(x) -#define Curl_convert_close(x) +#define Curl_convert_init(x) Curl_nop_stmt +#define Curl_convert_setup(x) Curl_nop_stmt +#define Curl_convert_close(x) Curl_nop_stmt #define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK) diff --git a/lib/nonblock.c b/lib/nonblock.c index cd819506c..529ce8bca 100644 --- a/lib/nonblock.c +++ b/lib/nonblock.c @@ -34,9 +34,6 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include <sys/filio.h> @@ -65,7 +62,7 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ /* most recent unix versions */ int flags; flags = fcntl(sockfd, F_GETFL, 0); - if(FALSE != nonblock) + if(nonblock) return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); else return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); @@ -73,26 +70,25 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ #elif defined(HAVE_IOCTL_FIONBIO) /* older unix versions */ - int flags; - flags = nonblock; + int flags = nonblock ? 1 : 0; return ioctl(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_FIONBIO) /* Windows */ - unsigned long flags; - flags = nonblock; + unsigned long flags = nonblock ? 1UL : 0UL; return ioctlsocket(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) /* Amiga */ - return IoctlSocket(sockfd, FIONBIO, (long)nonblock); + long flags = nonblock ? 1L : 0L; + return IoctlSocket(sockfd, FIONBIO, flags); #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) /* BeOS */ - long b = nonblock ? 1 : 0; + long b = nonblock ? 1L : 0L; return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); #else @@ -27,9 +27,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -95,7 +92,7 @@ typedef struct { ptr->type = (_type); \ ptr->pValue = (_val); \ ptr->ulValueLen = (_len); \ -} while(0) +} WHILE_FALSE #define CERT_NewTempCertificate __CERT_NewTempCertificate @@ -281,17 +278,16 @@ static int is_file(const char *filename) return 0; } -/* Return on heap allocated filename/nickname of a certificate. The returned - * string should be later deallocated using free(). *is_nickname is set to - * TRUE if the given string is treated as nickname; FALSE if the given string - * is treated as file name. +/* Check if the given string is filename or nickname of a certificate. If the + * given string is recognized as filename, return NULL. If the given string is + * recognized as nickname, return a duplicated string. The returned string + * should be later deallocated using free(). If the OOM failure occurs, we + * return NULL, too. */ -static char *fmt_nickname(struct SessionHandle *data, enum dupstring cert_kind, - bool *is_nickname) +static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind) { const char *str = data->set.str[cert_kind]; const char *n; - *is_nickname = TRUE; if(!is_file(str)) /* no such file exists, use the string as nickname */ @@ -306,10 +302,7 @@ static char *fmt_nickname(struct SessionHandle *data, enum dupstring cert_kind, } /* we'll use the PEM reader to read the certificate from file */ - *is_nickname = FALSE; - - n++; /* skip last slash */ - return aprintf("PEM Token #%d:%s", 1, n); + return NULL; } #ifdef HAVE_PK11_CREATEGENERICOBJECT @@ -326,6 +319,9 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, CK_BBOOL ckfalse = CK_FALSE; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; int attr_cnt = 0; + CURLcode err = (cacert) + ? CURLE_SSL_CACERT_BADFILE + : CURLE_SSL_CERTPROBLEM; const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); @@ -335,7 +331,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, slot = PK11_FindSlotByName(slot_name); free(slot_name); if(!slot) - return CURLE_SSL_CERTPROBLEM; + return err; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); @@ -350,13 +346,17 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE); PK11_FreeSlot(slot); if(!obj) - return CURLE_SSL_CERTPROBLEM; + return err; if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } + if(!cacert && CKO_CERTIFICATE == obj_class) + /* store reference to a client certificate */ + ssl->obj_clicert = obj; + return CURLE_OK; } @@ -371,76 +371,43 @@ static void nss_destroy_object(void *user, void *ptr) } #endif -static int nss_load_cert(struct ssl_connect_data *ssl, - const char *filename, PRBool cacert) +static CURLcode nss_load_cert(struct ssl_connect_data *ssl, + const char *filename, PRBool cacert) { -#ifdef HAVE_PK11_CREATEGENERICOBJECT - /* All CA and trust objects go into slot 0. Other slots are used - * for storing certificates. - */ - const int slot_id = (cacert) ? 0 : 1; -#endif - CERTCertificate *cert; - char *nickname = NULL; - char *n = NULL; + CURLcode err = (cacert) + ? CURLE_SSL_CACERT_BADFILE + : CURLE_SSL_CERTPROBLEM; - /* If there is no slash in the filename it is assumed to be a regular - * NSS nickname. - */ - if(is_file(filename)) { - n = strrchr(filename, '/'); +#ifdef HAVE_PK11_CREATEGENERICOBJECT + /* libnsspem.so leaks memory if the requested file does not exist. For more + * details, go to <https://bugzilla.redhat.com/734760>. */ + if(is_file(filename)) + err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); + + if(CURLE_OK == err && !cacert) { + /* we have successfully loaded a client certificate */ + CERTCertificate *cert; + char *nickname = NULL; + char *n = strrchr(filename, '/'); if(n) n++; - if(!mod) - return 1; - } - else { - /* A nickname from the NSS internal database */ - if(cacert) - return 0; /* You can't specify an NSS CA nickname this way */ - nickname = strdup(filename); - if(!nickname) - return 0; - goto done; - } - -#ifdef HAVE_PK11_CREATEGENERICOBJECT - nickname = aprintf("PEM Token #%d:%s", slot_id, n); - if(!nickname) - return 0; - - if(CURLE_OK != nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert)) { - free(nickname); - return 0; - } -#else - /* We don't have PK11_CreateGenericObject but a file-based cert was passed - * in. We need to fail. - */ - return 0; -#endif + /* The following undocumented magic helps to avoid a SIGSEGV on call + * of PK11_ReadRawAttribute() from SelectClientCert() when using an + * immature version of libnsspem.so. For more details, go to + * <https://bugzilla.redhat.com/733685>. */ + nickname = aprintf("PEM Token #1:%s", n); + if(nickname) { + cert = PK11_FindCertFromNickname(nickname, NULL); + if(cert) + CERT_DestroyCertificate(cert); - done: - /* Double-check that the certificate or nickname requested exists in - * either the token or the NSS certificate database. - */ - if(!cacert) { - cert = PK11_FindCertFromNickname((char *)nickname, NULL); - - /* An invalid nickname was passed in */ - if(cert == NULL) { free(nickname); - PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0); - return 0; } - - CERT_DestroyCertificate(cert); } +#endif - free(nickname); - - return 1; + return err; } /* add given CRL to cache if it is not already there */ @@ -529,23 +496,23 @@ fail: return SECFailure; } -static int nss_load_key(struct connectdata *conn, int sockindex, - char *key_file) +static CURLcode nss_load_key(struct connectdata *conn, int sockindex, + char *key_file) { #ifdef HAVE_PK11_CREATEGENERICOBJECT PK11SlotInfo *slot; SECStatus status; struct ssl_connect_data *ssl = conn->ssl; - (void)sockindex; /* unused */ - if(CURLE_OK != nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE)) { + CURLcode rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); + if(CURLE_OK != rv) { PR_SetError(SEC_ERROR_BAD_KEY, 0); - return 0; + return rv; } slot = PK11_FindSlotByName("PEM Token #1"); if(!slot) - return 0; + return CURLE_SSL_CERTPROBLEM; /* This will force the token to be seen as re-inserted */ SECMOD_WaitForAnyTokenEvent(mod, 0, 0); @@ -554,16 +521,18 @@ static int nss_load_key(struct connectdata *conn, int sockindex, status = PK11_Authenticate(slot, PR_TRUE, conn->data->set.str[STRING_KEY_PASSWD]); PK11_FreeSlot(slot); - return (SECSuccess == status) ? 1 : 0; + return (SECSuccess == status) + ? CURLE_OK + : CURLE_SSL_CERTPROBLEM; #else /* If we don't have PK11_CreateGenericObject then we can't load a file-based * key. */ (void)conn; /* unused */ (void)key_file; /* unused */ - (void)sockindex; /* unused */ - return 0; + return CURLE_SSL_CERTPROBLEM; #endif + (void)sockindex; /* unused */ } static int display_error(struct connectdata *conn, PRInt32 err, @@ -582,34 +551,37 @@ static int display_error(struct connectdata *conn, PRInt32 err, return 0; /* The caller will print a generic error */ } -static int cert_stuff(struct connectdata *conn, - int sockindex, char *cert_file, char *key_file) +static CURLcode cert_stuff(struct connectdata *conn, int sockindex, + char *cert_file, char *key_file) { struct SessionHandle *data = conn->data; - int rv = 0; + CURLcode rv; if(cert_file) { rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); - if(!rv) { + if(CURLE_OK != rv) { if(!display_error(conn, PR_GetError(), cert_file)) failf(data, "Unable to load client cert %d.", PR_GetError()); - return 0; + + return rv; } } + if(key_file || (is_file(cert_file))) { if(key_file) rv = nss_load_key(conn, sockindex, key_file); else /* In case the cert file also has the key */ rv = nss_load_key(conn, sockindex, cert_file); - if(!rv) { + if(CURLE_OK != rv) { if(!display_error(conn, PR_GetError(), key_file)) failf(data, "Unable to load client key %d.", PR_GetError()); - return 0; + return rv; } } - return 1; + + return CURLE_OK; } static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) @@ -776,7 +748,6 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner); proto_win = SSL_RevealPinArg(sock); - issuer = NULL; issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); if((!cert_issuer) || (!issuer)) @@ -800,44 +771,51 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { - static const char pem_nickname[] = "PEM Token #1"; - const char *pem_slotname = pem_nickname; - struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct SessionHandle *data = connssl->data; const char *nickname = connssl->client_nickname; - if(mod && nickname && - 0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) { - +#ifdef HAVE_PK11_CREATEGENERICOBJECT + if(connssl->obj_clicert) { /* use the cert/key provided by PEM reader */ - PK11SlotInfo *slot; + static const char pem_slotname[] = "PEM Token #1"; + SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); - *pRetKey = NULL; - *pRetCert = PK11_FindCertFromNickname(nickname, proto_win); - if(NULL == *pRetCert) { - failf(data, "NSS: client certificate not found: %s", nickname); + PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); + if(NULL == slot) { + failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } - slot = PK11_FindSlotByName(pem_slotname); - if(NULL == slot) { - failf(data, "NSS: PK11 slot not found: %s", pem_slotname); + if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE, + &cert_der) != SECSuccess) { + failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); + PK11_FreeSlot(slot); + return SECFailure; + } + + *pRetCert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); + SECITEM_FreeItem(&cert_der, PR_FALSE); + if(NULL == *pRetCert) { + failf(data, "NSS: client certificate from file not found"); + PK11_FreeSlot(slot); return SECFailure; } *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL); PK11_FreeSlot(slot); if(NULL == *pRetKey) { - failf(data, "NSS: private key not found for certificate: %s", nickname); + failf(data, "NSS: private key from file not found"); + CERT_DestroyCertificate(*pRetCert); return SECFailure; } - infof(data, "NSS: client certificate: %s\n", nickname); + infof(data, "NSS: client certificate from file\n"); display_cert_info(data, *pRetCert); return SECSuccess; } +#endif /* use the default NSS hook */ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, @@ -898,10 +876,42 @@ isTLSIntoleranceError(PRInt32 err) } } -static CURLcode init_nss(struct SessionHandle *data) +static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) +{ + if(NSS_IsInitialized()) + return CURLE_OK; + + if(cert_dir) { + SECStatus rv; + const bool use_sql = NSS_VersionCheck("3.12.0"); + char *certpath = aprintf("%s%s", use_sql ? "sql:" : "", cert_dir); + if(!certpath) + return CURLE_OUT_OF_MEMORY; + + infof(data, "Initializing NSS with certpath: %s\n", certpath); + rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY); + free(certpath); + + if(rv == SECSuccess) + return CURLE_OK; + + infof(data, "Unable to initialize NSS database\n"); + } + + infof(data, "Initializing NSS with certpath: none\n"); + if(NSS_NoDB_Init(NULL) == SECSuccess) + return CURLE_OK; + + infof(data, "Unable to initialize NSS\n"); + return CURLE_SSL_CACERT_BADFILE; +} + +static CURLcode nss_init(struct SessionHandle *data) { char *cert_dir; struct_stat st; + CURLcode rv; + if(initialized) return CURLE_OK; @@ -922,31 +932,14 @@ static CURLcode init_nss(struct SessionHandle *data) } } - if(!NSS_IsInitialized()) { - SECStatus rv; - initialized = 1; - infof(data, "Initializing NSS with certpath: %s\n", - cert_dir ? cert_dir : "none"); - if(!cert_dir) { - rv = NSS_NoDB_Init(NULL); - } - else { - char *certpath = - PR_smprintf("%s%s", NSS_VersionCheck("3.12.0") ? "sql:" : "", - cert_dir); - rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY); - PR_smprintf_free(certpath); - } - if(rv != SECSuccess) { - infof(data, "Unable to initialize NSS database\n"); - initialized = 0; - return CURLE_SSL_CACERT_BADFILE; - } - } + rv = nss_init_core(data, cert_dir); + if(rv) + return rv; if(num_enabled_ciphers() == 0) NSS_SetDomesticPolicy(); + initialized = 1; return CURLE_OK; } @@ -981,7 +974,7 @@ CURLcode Curl_nss_force_init(struct SessionHandle *data) } PR_Lock(nss_initlock); - rv = init_nss(data); + rv = nss_init(data); PR_Unlock(nss_initlock); return rv; } @@ -1064,6 +1057,7 @@ void Curl_nss_close(struct connectdata *conn, int sockindex) /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; + connssl->obj_clicert = NULL; #endif PR_Close(connssl->handle); connssl->handle = NULL; @@ -1111,8 +1105,11 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, const char *cafile = data->set.ssl.CAfile; const char *capath = data->set.ssl.CApath; - if(cafile && !nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE)) - return CURLE_SSL_CACERT_BADFILE; + if(cafile) { + CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); + if(CURLE_OK != rv) + return rv; + } if(capath) { struct_stat st; @@ -1132,7 +1129,7 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(!nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) + if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) /* This is purposefully tolerant of errors so non-PEM files can * be in the same directory */ infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath); @@ -1184,7 +1181,7 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); - curlerr = init_nss(conn->data); + curlerr = nss_init(conn->data); if(CURLE_OK != curlerr) { PR_Unlock(nss_initlock); goto error; @@ -1327,16 +1324,21 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) } if(data->set.str[STRING_CERT]) { - bool is_nickname; - char *nickname = fmt_nickname(data, STRING_CERT, &is_nickname); - if(!nickname) - return CURLE_OUT_OF_MEMORY; - - if(!is_nickname && !cert_stuff(conn, sockindex, data->set.str[STRING_CERT], - data->set.str[STRING_KEY])) { - /* failf() is already done in cert_stuff() */ - free(nickname); - return CURLE_SSL_CERTPROBLEM; + char *nickname = dup_nickname(data, STRING_CERT); + if(nickname) { + /* we are not going to use libnsspem.so to read the client cert */ +#ifdef HAVE_PK11_CREATEGENERICOBJECT + connssl->obj_clicert = NULL; +#endif + } + else { + CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], + data->set.str[STRING_KEY]); + if(CURLE_OK != rv) { + /* failf() is already done in cert_stuff() */ + curlerr = rv; + goto error; + } } /* store the nickname for SelectClientCert() called during handshake */ @@ -1395,16 +1397,12 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) if(data->set.str[STRING_SSL_ISSUERCERT]) { SECStatus ret = SECFailure; - bool is_nickname; - char *nickname = fmt_nickname(data, STRING_SSL_ISSUERCERT, &is_nickname); - if(!nickname) - return CURLE_OUT_OF_MEMORY; - - if(is_nickname) + char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); + if(nickname) { /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ ret = check_issuer_cert(connssl->handle, nickname); - - free(nickname); + free(nickname); + } if(SECFailure == ret) { infof(data,"SSL certificate issuer check failed\n"); diff --git a/lib/nssg.h b/lib/nssg.h index 438d5a636..4d7df5efa 100644 --- a/lib/nssg.h +++ b/lib/nssg.h @@ -1,5 +1,5 @@ -#ifndef __NSSG_H -#define __NSSG_H +#ifndef HEADER_CURL_NSSG_H +#define HEADER_CURL_NSSG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #ifdef USE_NSS /* @@ -28,6 +29,7 @@ */ #include "urldata.h" + CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex); CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, int sockindex, @@ -55,7 +57,7 @@ CURLcode Curl_nss_force_init(struct SessionHandle *data); #define curlssl_connect Curl_nss_connect /* NSS has its own session ID cache */ -#define curlssl_session_free(x) +#define curlssl_session_free(x) Curl_nop_stmt #define curlssl_close_all Curl_nss_close_all #define curlssl_close Curl_nss_close /* NSS has no shutdown function provided and thus always fail */ @@ -68,4 +70,4 @@ CURLcode Curl_nss_force_init(struct SessionHandle *data); #define curlssl_data_pending(x,y) (x=x, y=y, 0) #endif /* USE_NSS */ -#endif +#endif /* HEADER_CURL_NSSG_H */ diff --git a/lib/nwlib.c b/lib/nwlib.c index f9c8a4298..c87ca0d29 100644 --- a/lib/nwlib.c +++ b/lib/nwlib.c @@ -20,14 +20,12 @@ * ***************************************************************************/ -#ifdef NETWARE /* Novell NetWare */ +#include "setup.h" -#include <stdlib.h> +#ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to register as a real lib. */ -#include <errno.h> -#include <string.h> #include <library.h> #include <netware.h> #include <screen.h> diff --git a/lib/nwos.c b/lib/nwos.c index ac365124f..bd695b3f9 100644 --- a/lib/nwos.c +++ b/lib/nwos.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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,9 +20,9 @@ * ***************************************************************************/ -#ifdef NETWARE /* Novell NetWare */ +#include "setup.h" -#include <stdlib.h> +#ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ @@ -34,7 +34,6 @@ int netware_init ( void ) #else /* __NOVELL_LIBC__ */ /* For native CLib-based NLM we need to initialize the LONG namespace. */ -#include <stdio.h> #include <nwnspace.h> #include <nwthread.h> #include <nwadv.h> @@ -86,10 +85,4 @@ int __deinit_environment ( void ) #endif /* __NOVELL_LIBC__ */ -#else /* NETWARE */ - -#ifdef __POCC__ -# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ -#endif - #endif /* NETWARE */ diff --git a/lib/openldap.c b/lib/openldap.c index 69523cb37..e5a3369a1 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -83,6 +83,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -107,6 +108,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -544,12 +546,21 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, } } if(binary || binval) { - char *val_b64; + char *val_b64 = NULL; + size_t val_b64_sz = 0; /* Binary value, encode to base64. */ - size_t val_b64_sz = Curl_base64_encode(data, - bvals[i].bv_val, - bvals[i].bv_len, - &val_b64); + CURLcode error = Curl_base64_encode(data, + bvals[i].bv_val, + bvals[i].bv_len, + &val_b64, + &val_b64_sz); + if(error) { + ber_memfree(bvals); + ber_free(ber, 0); + ldap_msgfree(result); + *err = error; + return -1; + } Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); data->req.bytecount += 2; if(val_b64_sz > 0) { diff --git a/lib/parsedate.c b/lib/parsedate.c index 62f1a4181..ec60e78e7 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -72,14 +72,8 @@ 20040911 +0200 */ -#include "setup.h" -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* for strtol() */ -#endif +#include "setup.h" #include <curl/curl.h> #include "rawstr.h" diff --git a/lib/pingpong.c b/lib/pingpong.c index 23ab69fb2..84ce88148 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -177,9 +177,6 @@ void Curl_pp_init(struct pingpong *pp) * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, @@ -187,12 +184,10 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, va_list args) { ssize_t bytes_written; -/* may still not be big enough for some krb5 tokens */ -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; size_t write_len; - char *sptr=s; - CURLcode res = CURLE_OK; + char *fmt_crlf; + char *s; + CURLcode error; struct connectdata *conn = pp->conn; struct SessionHandle *data = conn->data; @@ -200,55 +195,64 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, enum protection_level data_sec = conn->data_prot; #endif - vsnprintf(s, SBUF_SIZE-3, fmt, args); + DEBUGASSERT(pp->sendleft == 0); + DEBUGASSERT(pp->sendsize == 0); + DEBUGASSERT(pp->sendthis == NULL); + + fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */ + if(!fmt_crlf) + return CURLE_OUT_OF_MEMORY; - strcat(s, "\r\n"); /* append a trailing CRLF */ + s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */ + free(fmt_crlf); + if(!s) + return CURLE_OUT_OF_MEMORY; - bytes_written=0; + bytes_written = 0; write_len = strlen(s); Curl_pp_init(pp); - res = Curl_convert_to_network(data, s, write_len); + error = Curl_convert_to_network(data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res) - return res; + if(error) { + free(s); + return error; + } #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) conn->data_prot = PROT_CMD; #endif - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); + error = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, + &bytes_written); #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif - if(CURLE_OK != res) - return res; + if(error) { + free(s); + return error; + } if(conn->data->set.verbose) Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); + s, (size_t)bytes_written, conn); if(bytes_written != (ssize_t)write_len) { - /* the whole chunk was not sent, store the rest of the data */ - write_len -= bytes_written; - sptr += bytes_written; - pp->sendthis = malloc(write_len); - if(pp->sendthis) { - memcpy(pp->sendthis, sptr, write_len); - pp->sendsize = pp->sendleft = write_len; - } - else { - failf(data, "out of memory"); - res = CURLE_OUT_OF_MEMORY; - } + /* the whole chunk was not sent, keep it around and adjust sizes */ + pp->sendthis = s; + pp->sendsize = write_len; + pp->sendleft = write_len - bytes_written; } - else + else { + free(s); + pp->sendthis = NULL; + pp->sendleft = pp->sendsize = 0; pp->response = Curl_tvnow(); + } - return res; + return CURLE_OK; } @@ -260,9 +264,6 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, diff --git a/lib/pingpong.h b/lib/pingpong.h index cbbff8f3e..1d104cfbc 100644 --- a/lib/pingpong.h +++ b/lib/pingpong.h @@ -1,5 +1,5 @@ -#ifndef __PINGPONG_H -#define __PINGPONG_H +#ifndef HEADER_CURL_PINGPONG_H +#define HEADER_CURL_PINGPONG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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,8 +22,6 @@ * ***************************************************************************/ -#include <stdarg.h> - #include "setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \ @@ -100,9 +98,6 @@ long Curl_pp_state_timeout(struct pingpong *pp); * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, @@ -116,9 +111,6 @@ CURLcode Curl_pp_sendf(struct pingpong *pp, * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, @@ -144,4 +136,4 @@ CURLcode Curl_pp_disconnect(struct pingpong *pp); int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks, int numsocks); -#endif /* __PINGPONG_H */ +#endif /* HEADER_CURL_PINGPONG_H */ diff --git a/lib/polarssl.c b/lib/polarssl.c index 2e70a28d5..09446f995 100644 --- a/lib/polarssl.c +++ b/lib/polarssl.c @@ -27,11 +27,9 @@ */ #include "setup.h" + #ifdef USE_POLARSSL -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -41,6 +39,15 @@ #include <polarssl/havege.h> #include <polarssl/certs.h> #include <polarssl/x509.h> +#include <polarssl/version.h> + +#if POLARSSL_VERSION_NUMBER<0x01000000 +/* + Earlier versions of polarssl had no WANT_READ or WANT_WRITE, only TRY_AGAIN +*/ +#define POLARSSL_ERR_NET_WANT_READ POLARSSL_ERR_NET_TRY_AGAIN +#define POLARSSL_ERR_NET_WANT_WRITE POLARSSL_ERR_NET_TRY_AGAIN +#endif #include "urldata.h" #include "sendf.h" @@ -188,8 +195,12 @@ Curl_polarssl_connect(struct connectdata *conn, net_recv, &conn->sock[sockindex], net_send, &conn->sock[sockindex]); - ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers); +#if POLARSSL_VERSION_NUMBER<0x01000000 + ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers); +#else + ssl_set_ciphersuites(&conn->ssl[sockindex].ssl, ssl_default_ciphersuites); +#endif if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { memcpy(&conn->ssl[sockindex].ssn, old_session, old_session_size); infof(data, "PolarSSL re-using session\n"); @@ -224,7 +235,8 @@ Curl_polarssl_connect(struct connectdata *conn, for(;;) { if(!(ret = ssl_handshake(&conn->ssl[sockindex].ssl))) break; - else if(ret != POLARSSL_ERR_NET_TRY_AGAIN) { + else if(ret != POLARSSL_ERR_NET_WANT_READ && + ret != POLARSSL_ERR_NET_WANT_WRITE) { failf(data, "ssl_handshake returned -0x%04X", -ret); return CURLE_SSL_CONNECT_ERROR; } @@ -254,7 +266,11 @@ Curl_polarssl_connect(struct connectdata *conn, } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", +#if POLARSSL_VERSION_NUMBER<0x01000000 ssl_get_cipher(&conn->ssl[sockindex].ssl)); +#else + ssl_get_ciphersuite_name(&conn->ssl[sockindex].ssl)); +#endif ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); @@ -318,7 +334,7 @@ static ssize_t polarssl_send(struct connectdata *conn, (unsigned char *)mem, len); if(ret < 0) { - *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ? + *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ? CURLE_AGAIN : CURLE_SEND_ERROR; ret = -1; } @@ -356,7 +372,7 @@ static ssize_t polarssl_recv(struct connectdata *conn, if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) return 0; - *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ? + *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ? CURLE_AGAIN : CURLE_RECV_ERROR; return -1; } diff --git a/lib/polarssl.h b/lib/polarssl.h index 9e983aac9..91f63afbf 100644 --- a/lib/polarssl.h +++ b/lib/polarssl.h @@ -20,8 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - * $Id: polarssl.h,v 1.10 2009-02-12 20:48:43 danf Exp $ ***************************************************************************/ +#include "setup.h" #ifdef USE_POLARSSL @@ -40,7 +40,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); /* API setup for PolarSSL */ #define curlssl_init() (1) -#define curlssl_cleanup() +#define curlssl_cleanup() Curl_nop_stmt #define curlssl_connect Curl_polarssl_connect #define curlssl_session_free(x) Curl_polarssl_session_free(x) #define curlssl_close_all Curl_polarssl_close_all diff --git a/lib/pop3.c b/lib/pop3.c index dc5a1c2fa..cb70679c5 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -27,11 +27,6 @@ #include "setup.h" #ifndef CURL_DISABLE_POP3 -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -124,6 +119,7 @@ const struct Curl_handler Curl_handler_pop3 = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -149,6 +145,7 @@ const struct Curl_handler Curl_handler_pop3s = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -174,6 +171,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -199,6 +197,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -285,7 +284,7 @@ static void pop3_to_pop3s(struct connectdata *conn) conn->handler = &Curl_handler_pop3s; } #else -#define pop3_to_pop3s(x) +#define pop3_to_pop3s(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -575,7 +574,7 @@ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) struct pop3_conn *pop3c = &conn->proto.pop3c; CURLcode result = Curl_pp_multi_statemach(&pop3c->pp); - *done = (bool)(pop3c->state == POP3_STOP); + *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; return result; } @@ -792,7 +791,7 @@ CURLcode pop3_perform(struct connectdata *conn, result = pop3_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/progress.c b/lib/progress.c index 8655dc4c2..1514e1edd 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -201,6 +201,8 @@ void Curl_pgrsStartNow(struct SessionHandle *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + /* clear all bits except HIDE and HEADERS_OUT */ + data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) diff --git a/lib/qssl.c b/lib/qssl.c index 60ea6da23..172df3141 100644 --- a/lib/qssl.c +++ b/lib/qssl.c @@ -23,9 +23,9 @@ #include "setup.h" #ifdef USE_QSOSSL + #include <qsossl.h> -#include <errno.h> -#include <string.h> + #ifdef HAVE_LIMITS_H # include <limits.h> #endif diff --git a/lib/qssl.h b/lib/qssl.h index bd195ff7b..a523cb1f3 100644 --- a/lib/qssl.h +++ b/lib/qssl.h @@ -1,5 +1,5 @@ -#ifndef __QSSL_H -#define __QSSL_H +#ifndef HEADER_CURL_QSSL_H +#define HEADER_CURL_QSSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" /* * This header should only be needed to get included by sslgen.c and qssl.c @@ -45,7 +46,7 @@ int Curl_qsossl_check_cxn(struct connectdata * cxn); #define curlssl_connect Curl_qsossl_connect /* No session handling for QsoSSL */ -#define curlssl_session_free(x) +#define curlssl_session_free(x) Curl_nop_stmt #define curlssl_close_all Curl_qsossl_close_all #define curlssl_close Curl_qsossl_close #define curlssl_shutdown(x,y) Curl_qsossl_shutdown(x,y) @@ -56,4 +57,5 @@ int Curl_qsossl_check_cxn(struct connectdata * cxn); #define curlssl_check_cxn(x) Curl_qsossl_check_cxn(x) #define curlssl_data_pending(x,y) 0 #endif /* USE_QSOSSL */ -#endif + +#endif /* HEADER_CURL_QSSL_H */ diff --git a/lib/rtsp.c b/lib/rtsp.c index 3ce8ad51e..5d62ac7c7 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -113,6 +113,7 @@ const struct Curl_handler Curl_handler_rtsp = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ rtsp_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtsp_disconnect, /* disconnect */ rtsp_rtp_readwrite, /* readwrite */ @@ -294,6 +295,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) case RTSPREQ_GET_PARAMETER: /* GET_PARAMETER's no_body status is determined later */ p_request = "GET_PARAMETER"; + data->set.opt_no_body = FALSE; break; case RTSPREQ_SET_PARAMETER: p_request = "SET_PARAMETER"; diff --git a/lib/security.c b/lib/security.c index 010a5504e..536d7c229 100644 --- a/lib/security.c +++ b/lib/security.c @@ -46,9 +46,6 @@ #ifndef CURL_DISABLE_FTP #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) -#include <stdarg.h> -#include <string.h> - #ifdef HAVE_NETDB_H #include <netdb.h> #endif @@ -57,6 +54,10 @@ #include <unistd.h> #endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + #include "urldata.h" #include "curl_base64.h" #include "curl_memory.h" @@ -64,6 +65,7 @@ #include "ftp.h" #include "sendf.h" #include "rawstr.h" +#include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" @@ -283,12 +285,13 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, static void do_sec_send(struct connectdata *conn, curl_socket_t fd, const char *from, int length) { - size_t bytes; - size_t htonl_bytes; - char *buffer; + int bytes, htonl_bytes; /* 32-bit integers for htonl */ + char *buffer = NULL; char *cmd_buffer; + size_t cmd_size = 0; + CURLcode error; enum protection_level prot_level = conn->data_prot; - bool iscmd = prot_level == PROT_CMD; + bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE; DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); @@ -300,9 +303,17 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, (void**)&buffer, conn); + if(!buffer || bytes <= 0) + return; /* error */ + if(iscmd) { - bytes = Curl_base64_encode(conn->data, buffer, bytes, &cmd_buffer); - if(bytes > 0) { + error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes), + &cmd_buffer, &cmd_size); + if(error) { + free(buffer); + return; /* error */ + } + if(cmd_size > 0) { static const char *enc = "ENC "; static const char *mic = "MIC "; if(prot_level == PROT_PRIVATE) @@ -310,7 +321,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else socket_write(conn, fd, mic, 4); - socket_write(conn, fd, cmd_buffer, bytes); + socket_write(conn, fd, cmd_buffer, cmd_size); socket_write(conn, fd, "\r\n", 2); infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic, cmd_buffer); @@ -320,7 +331,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else { htonl_bytes = htonl(bytes); socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(conn, fd, buffer, bytes); + socket_write(conn, fd, buffer, curlx_sitouz(bytes)); } free(buffer); } @@ -365,14 +376,20 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int decoded_len; char *buf; int ret_code; + size_t decoded_sz = 0; + CURLcode error; DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - decoded_len = Curl_base64_decode(buffer + 4, (unsigned char **)&buf); - if(decoded_len <= 0) { + error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); + if(error || decoded_sz == 0) + return -1; + + if(decoded_sz > (size_t)INT_MAX) { free(buf); return -1; } + decoded_len = curlx_uztosi(decoded_sz); decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len, level, conn); diff --git a/lib/select.c b/lib/select.c index 8f6541dee..6cecbf701 100644 --- a/lib/select.c +++ b/lib/select.c @@ -25,9 +25,6 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) #error "We can't compile without select() or poll() support." @@ -49,20 +46,6 @@ #include "select.h" #include "warnless.h" -/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */ - -#if defined(USE_WINSOCK) || defined(TPF) -#define VERIFY_SOCK(x) do { } while(0) -#else -#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) -#define VERIFY_SOCK(x) do { \ - if(!VALID_SOCK(x)) { \ - SET_SOCKERRNO(EINVAL); \ - return -1; \ - } \ -} while(0) -#endif - /* Convenience local macros */ #define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) @@ -93,7 +76,7 @@ * -1 = system call error, invalid timeout value, or interrupted * 0 = specified timeout has elapsed */ -static int wait_ms(int timeout_ms) +int Curl_wait_ms(int timeout_ms) { #if !defined(MSDOS) && !defined(USE_WINSOCK) #ifndef HAVE_POLL_FINE @@ -180,7 +163,7 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int ret; if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { - r = wait_ms((int)timeout_ms); + r = Curl_wait_ms((int)timeout_ms); return r; } @@ -364,7 +347,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } if(fds_none) { - r = wait_ms((int)timeout_ms); + r = Curl_wait_ms(timeout_ms); return r; } diff --git a/lib/select.h b/lib/select.h index e012c63f3..56729a3b2 100644 --- a/lib/select.h +++ b/lib/select.h @@ -89,9 +89,27 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); +int Curl_wait_ms(int timeout_ms); + #ifdef TPF int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, fd_set* excepts, struct timeval* tv); #endif +/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which + unfortunately makes it impossible for us to easily check if they're valid +*/ +#if defined(USE_WINSOCK) || defined(TPF) +#define VALID_SOCK(x) 1 +#define VERIFY_SOCK(x) Curl_nop_stmt +#else +#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x)) { \ + SET_SOCKERRNO(EINVAL); \ + return -1; \ + } \ +} WHILE_FALSE +#endif + #endif /* __SELECT_H */ diff --git a/lib/sendf.c b/lib/sendf.c index 0172ae7c3..847090be3 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -22,11 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <errno.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> /* required for send() & recv() prototypes */ #endif @@ -55,7 +50,6 @@ #define Curl_sec_read(a,b,c,d) -1 #endif -#include <string.h> #include "curl_memory.h" #include "strerror.h" @@ -79,7 +73,7 @@ static size_t convert_lineends(struct SessionHandle *data, return(size); } - if(data->state.prev_block_had_trailing_cr == TRUE) { + if(data->state.prev_block_had_trailing_cr) { /* The previous block of incoming data had a trailing CR, which was turned into a LF. */ if(*startPtr == '\n') { @@ -533,17 +527,17 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, * Returns a regular CURLcode value. */ CURLcode Curl_read(struct connectdata *conn, /* connection data */ - curl_socket_t sockfd, /* read from this socket */ - char *buf, /* store read data here */ - size_t sizerequested, /* max amount to read */ - ssize_t *n) /* amount bytes read */ + curl_socket_t sockfd, /* read from this socket */ + char *buf, /* store read data here */ + size_t sizerequested, /* max amount to read */ + ssize_t *n) /* amount bytes read */ { CURLcode curlcode = CURLE_RECV_ERROR; ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; - bool pipelining = (bool)(conn->data->multi && - Curl_multi_canPipeline(conn->data->multi)); + bool pipelining = (conn->data->multi && + Curl_multi_canPipeline(conn->data->multi)) ? TRUE : FALSE; /* Set 'num' to 0 or 1, depending on which socket that has been sent here. If it is the second socket, we set num to 1. Otherwise to 0. This lets diff --git a/lib/sendf.h b/lib/sendf.h index 8f0ea24d7..39911d016 100644 --- a/lib/sendf.h +++ b/lib/sendf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...); #if defined(CURL_DISABLE_VERBOSE_STRINGS) #if defined(HAVE_VARIADIC_MACROS_C99) -#define infof(...) do { } while (0) +#define infof(...) Curl_nop_stmt #elif defined(HAVE_VARIADIC_MACROS_GCC) -#define infof(x...) do { } while (0) +#define infof(x...) Curl_nop_stmt #else #define infof (void) #endif diff --git a/lib/setup.h b/lib/setup.h index 1e96c76dd..84c9b1feb 100644 --- a/lib/setup.h +++ b/lib/setup.h @@ -251,6 +251,12 @@ # endif #endif +#ifdef USE_LWIPSOCK +# include <lwip/init.h> +# include <lwip/sockets.h> +# include <lwip/netdb.h> +#endif + #ifdef HAVE_EXTRA_STRICMP_H # include <extra/stricmp.h> #endif @@ -279,7 +285,6 @@ #ifdef HAVE_ASSERT_H #include <assert.h> #endif -#include <errno.h> #ifdef __TANDEM /* for nsr-tandem-nsk systems */ #include <floss.h> @@ -563,6 +568,7 @@ int netware_init(void); #define USE_HTTP_NEGOTIATE #endif +/* Single point where USE_NTLM definition might be done */ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM) #if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || \ defined(USE_GNUTLS) || defined(USE_NSS) @@ -580,6 +586,15 @@ int netware_init(void); #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif +/* Provide a mechanism to silence picky compilers, such as gcc 4.6+. + Parameters should of course normally not be unused, but for example when we + have multiple implementations of the same interface it may happen. */ +#ifndef __GNUC__ +#define UNUSED_PARAM /*NOTHING*/ +#else +#define UNUSED_PARAM __attribute__((unused)) +#endif + /* * Include macros and defines that should only be processed once. */ @@ -588,4 +603,27 @@ int netware_init(void); #include "setup_once.h" #endif +/* + * Definition of our NOP statement Object-like macro + */ + +#ifndef Curl_nop_stmt +# define Curl_nop_stmt do { } WHILE_FALSE +#endif + +/* + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. + */ + +#if defined(__LWIP_OPT_H__) +# if defined(SOCKET) || \ + defined(USE_WINSOCK) || \ + defined(HAVE_ERRNO_H) || \ + defined(HAVE_WINSOCK_H) || \ + defined(HAVE_WINSOCK2_H) || \ + defined(HAVE_WS2TCPIP_H) +# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" +# endif +#endif + #endif /* HEADER_CURL_LIB_SETUP_H */ diff --git a/lib/setup_once.h b/lib/setup_once.h index b449807db..8bdb472df 100644 --- a/lib/setup_once.h +++ b/lib/setup_once.h @@ -42,7 +42,10 @@ #include <string.h> #include <stdarg.h> #include <ctype.h> + +#ifdef HAVE_ERRNO_H #include <errno.h> +#endif #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -254,10 +257,13 @@ struct timeval { #define ISPRINT(x) (isprint((int) ((unsigned char)x))) #define ISUPPER(x) (isupper((int) ((unsigned char)x))) #define ISLOWER(x) (islower((int) ((unsigned char)x))) +#define ISASCII(x) (isascii((int) ((unsigned char)x))) #define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ (((unsigned char)x) == '\t')) +#define TOLOWER(x) (tolower((int) ((unsigned char)x))) + /* * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms. @@ -300,6 +306,27 @@ struct timeval { /* + * Macro WHILE_FALSE may be used to build single-iteration do-while loops, + * avoiding compiler warnings. Mostly intended for other macro definitions. + */ + +#define WHILE_FALSE while(0) + +#if defined(_MSC_VER) && !defined(__POCC__) +# undef WHILE_FALSE +# if (_MSC_VER < 1500) +# define WHILE_FALSE while(1, 0) +# else +# define WHILE_FALSE \ +__pragma(warning(push)) \ +__pragma(warning(disable:4127)) \ +while(0) \ +__pragma(warning(pop)) +# endif +#endif + + +/* * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. */ @@ -336,7 +363,7 @@ typedef int sig_atomic_t; #ifdef DEBUGBUILD #define DEBUGF(x) x #else -#define DEBUGF(x) do { } while (0) +#define DEBUGF(x) do { } WHILE_FALSE #endif @@ -347,7 +374,7 @@ typedef int sig_atomic_t; #if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) #define DEBUGASSERT(x) assert(x) #else -#define DEBUGASSERT(x) do { } while (0) +#define DEBUGASSERT(x) do { } WHILE_FALSE #endif @@ -487,5 +514,5 @@ typedef int sig_atomic_t; #define ZERO_NULL 0 -#endif /* __SETUP_ONCE_H */ +#endif /* __SETUP_ONCE_H */ diff --git a/lib/share.c b/lib/share.c index 33dcecf4c..71c2ef308 100644 --- a/lib/share.c +++ b/lib/share.c @@ -21,12 +21,11 @@ ***************************************************************************/ #include "setup.h" -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> + #include <curl/curl.h> #include "urldata.h" #include "share.h" +#include "sslgen.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -74,17 +73,32 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) } break; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) 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 ); if(!share->cookies) return CURLSHE_NOMEM; } break; -#endif /* CURL_DISABLE_HTTP */ +#else /* CURL_DISABLE_HTTP */ + return CURLSHE_NOT_BUILT_IN; +#endif + + case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + if(!share->sslsession) { + share->nsslsession = 8; + share->sslsession = calloc(share->nsslsession, + sizeof(struct curl_ssl_session)); + if(!share->sslsession) + return CURLSHE_NOMEM; + } + break; +#else + return CURLSHE_NOT_BUILT_IN; +#endif - case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */ case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ default: @@ -104,17 +118,28 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) } break; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) case CURL_LOCK_DATA_COOKIE: +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(share->cookies) { Curl_cookie_cleanup(share->cookies); share->cookies = NULL; } break; -#endif /* CURL_DISABLE_HTTP */ +#else /* CURL_DISABLE_HTTP */ + return CURLSHE_NOT_BUILT_IN; +#endif case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + if(share->sslsession) { + free(share->sslsession); + share->sslsession = NULL; + share->nsslsession = 0; + } break; +#else + return CURLSHE_NOT_BUILT_IN; +#endif case CURL_LOCK_DATA_CONNECT: break; @@ -169,8 +194,19 @@ curl_share_cleanup(CURLSH *sh) share->hostcache = NULL; } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(share->cookies) Curl_cookie_cleanup(share->cookies); +#endif + +#ifdef USE_SSL + if(share->sslsession) { + unsigned int i; + for(i = 0; i < share->nsslsession; ++i) + Curl_ssl_kill_session(&(share->sslsession[i])); + free(share->sslsession); + } +#endif if(share->unlockfunc) share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); diff --git a/lib/share.h b/lib/share.h index ea8e233d2..c9546567d 100644 --- a/lib/share.h +++ b/lib/share.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,7 @@ #include "setup.h" #include <curl/curl.h> #include "cookie.h" +#include "urldata.h" /* SalfordC says "A structure member may not be volatile". Hence: */ @@ -45,7 +46,12 @@ struct Curl_share { void *clientdata; struct curl_hash *hostcache; +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) struct CookieInfo *cookies; +#endif + + struct curl_ssl_session *sslsession; + unsigned int nsslsession; }; CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, diff --git a/lib/slist.c b/lib/slist.c index e2006f4be..4ddebb609 100644 --- a/lib/slist.c +++ b/lib/slist.c @@ -22,11 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> - -#include <string.h> #include "curl_memory.h" #include "slist.h" @@ -124,10 +119,7 @@ void curl_slist_free_all(struct curl_slist *list) item = list; do { next = item->next; - - if(item->data) { - free(item->data); - } + Curl_safefree(item->data); free(item); item = next; } while(next); diff --git a/lib/smtp.c b/lib/smtp.c index 1626ae7da..8835b07a5 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -29,11 +29,6 @@ #include "setup.h" #ifndef CURL_DISABLE_SMTP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -90,6 +85,7 @@ #include "curl_md5.h" #include "curl_hmac.h" #include "curl_gethostname.h" +#include "curl_ntlm_msgs.h" #include "warnless.h" #include "http_proxy.h" @@ -116,7 +112,6 @@ static CURLcode smtp_doing(struct connectdata *conn, static CURLcode smtp_setup_connection(struct connectdata * conn); static CURLcode smtp_state_upgrade_tls(struct connectdata *conn); - /* * SMTP protocol handler. */ @@ -132,6 +127,7 @@ const struct Curl_handler Curl_handler_smtp = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -140,7 +136,6 @@ const struct Curl_handler Curl_handler_smtp = { PROTOPT_CLOSEACTION /* flags */ }; - #ifdef USE_SSL /* * SMTPS protocol handler. @@ -157,6 +152,7 @@ const struct Curl_handler Curl_handler_smtps = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -182,6 +178,7 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -190,7 +187,6 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed SMTPS protocol handler. @@ -207,6 +203,7 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -217,7 +214,6 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { #endif #endif - /* Function that checks for an ending smtp status code at the start of the given string. As a side effect, it also flags allowed authentication mechanisms according @@ -272,6 +268,8 @@ static int smtp_endofresp(struct pingpong *pp, int *resp) smtpc->authmechs |= SMTP_AUTH_GSSAPI; else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) smtpc->authmechs |= SMTP_AUTH_EXTERNAL; + else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) + smtpc->authmechs |= SMTP_AUTH_NTLM; line += wordlen; len -= wordlen; @@ -288,7 +286,7 @@ static void state(struct connectdata *conn, struct smtp_conn *smtpc = &conn->proto.smtpc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ + static const char * const names[] = { "STOP", "SERVERGREET", "EHLO", @@ -299,6 +297,8 @@ static void state(struct connectdata *conn, "AUTHLOGIN", "AUTHPASSWD", "AUTHCRAM", + "AUTHNTLM", + "AUTHNTLM_TYPE2MSG", "AUTH", "MAIL", "RCPT", @@ -320,6 +320,8 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn) struct smtp_conn *smtpc = &conn->proto.smtpc; smtpc->authmechs = 0; /* No known authentication mechanisms yet. */ + smtpc->authused = 0; /* Clear the authentication mechanism used + for esmtp connections */ /* send EHLO */ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); @@ -336,6 +338,9 @@ static CURLcode smtp_state_helo(struct connectdata *conn) CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; + smtpc->authused = 0; /* No authentication mechanism used in smtp + connections */ + /* send HELO */ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); @@ -346,7 +351,8 @@ static CURLcode smtp_state_helo(struct connectdata *conn) return CURLE_OK; } -static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) +static CURLcode smtp_auth_plain_data(struct connectdata *conn, + char **outptr, size_t *outlen) { char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH]; size_t ulen; @@ -355,8 +361,11 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) ulen = strlen(conn->user); plen = strlen(conn->passwd); - if(2 * ulen + plen + 2 > sizeof plainauth) - return 0; + if(2 * ulen + plen + 2 > sizeof plainauth) { + *outlen = 0; + *outptr = NULL; + return CURLE_OUT_OF_MEMORY; /* plainauth too small */ + } memcpy(plainauth, conn->user, ulen); plainauth[ulen] = '\0'; @@ -364,89 +373,108 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) plainauth[2 * ulen + 1] = '\0'; memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen); return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2, - outptr); + outptr, outlen); } -static size_t smtp_auth_login_user(struct connectdata * conn, char * * outptr) +static CURLcode smtp_auth_login_user(struct connectdata *conn, + char **outptr, size_t *outlen) { - size_t ulen; - - ulen = strlen(conn->user); + size_t ulen = strlen(conn->user); if(!ulen) { *outptr = strdup("="); - return *outptr? 1: 0; + if(*outptr) { + *outlen = (size_t) 1; + return CURLE_OK; + } + *outlen = 0; + return CURLE_OUT_OF_MEMORY; } - return Curl_base64_encode(conn->data, conn->user, ulen, outptr); + return Curl_base64_encode(conn->data, conn->user, ulen, outptr, outlen); +} + +#ifdef USE_NTLM +static CURLcode smtp_auth_ntlm_type1_message(struct connectdata *conn, + char **outptr, size_t *outlen) +{ + return Curl_ntlm_create_type1_message(conn->user, conn->passwd, + &conn->ntlm, outptr, outlen); } +#endif static CURLcode smtp_authenticate(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - char * initresp; - const char * mech; - size_t l; - smtpstate state1; - smtpstate state2; - - if(!conn->bits.user_passwd) - state(conn, SMTP_STOP); /* End of connect phase. */ - else { - initresp = (char *) NULL; - l = 1; + char *initresp = NULL; + const char *mech = NULL; + size_t len = 0; + smtpstate state1 = SMTP_STOP; + smtpstate state2 = SMTP_STOP; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't. */ + if(!conn->bits.user_passwd) { + state(conn, SMTP_STOP); - /* Check supported authentication mechanisms by decreasing order of - preference. */ - mech = (const char *) NULL; /* Avoid compiler warnings. */ - state1 = SMTP_STOP; - state2 = SMTP_STOP; + return result; + } + /* Check supported authentication mechanisms by decreasing order of + security. */ #ifndef CURL_DISABLE_CRYPTO_AUTH - if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { - mech = "CRAM-MD5"; - state1 = SMTP_AUTHCRAM; - } - else + if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { + mech = "CRAM-MD5"; + state1 = SMTP_AUTHCRAM; + smtpc->authused = SMTP_AUTH_CRAM_MD5; + } + else #endif - if(smtpc->authmechs & SMTP_AUTH_PLAIN) { - mech = "PLAIN"; - state1 = SMTP_AUTHPLAIN; - state2 = SMTP_AUTH; - l = smtp_auth_plain_data(conn, &initresp); - } - else if(smtpc->authmechs & SMTP_AUTH_LOGIN) { - mech = "LOGIN"; - state1 = SMTP_AUTHLOGIN; - state2 = SMTP_AUTHPASSWD; - l = smtp_auth_login_user(conn, &initresp); - } - else { - infof(conn->data, "No known auth mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ - } +#ifdef USE_NTLM + if(smtpc->authmechs & SMTP_AUTH_NTLM) { + mech = "NTLM"; + state1 = SMTP_AUTHNTLM; + state2 = SMTP_AUTHNTLM_TYPE2MSG; + smtpc->authused = SMTP_AUTH_NTLM; + result = smtp_auth_ntlm_type1_message(conn, &initresp, &len); + } + else +#endif + if(smtpc->authmechs & SMTP_AUTH_LOGIN) { + mech = "LOGIN"; + state1 = SMTP_AUTHLOGIN; + state2 = SMTP_AUTHPASSWD; + smtpc->authused = SMTP_AUTH_LOGIN; + result = smtp_auth_login_user(conn, &initresp, &len); + } + else if(smtpc->authmechs & SMTP_AUTH_PLAIN) { + mech = "PLAIN"; + state1 = SMTP_AUTHPLAIN; + state2 = SMTP_AUTH; + smtpc->authused = SMTP_AUTH_PLAIN; + result = smtp_auth_plain_data(conn, &initresp, &len); + } + else { + infof(conn->data, "No known auth mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ + } - if(!result) { - if(!l) - result = CURLE_OUT_OF_MEMORY; - else if(initresp && - l + strlen(mech) <= 512 - 8) { /* AUTH <mech> ...<crlf> */ - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - free(initresp); + if(!result) { + if(initresp && + strlen(mech) + len <= 512 - 8) { /* AUTH <mech> ...<crlf> */ + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - if(!result) - state(conn, state2); - } - else { - Curl_safefree(initresp); - - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); + if(!result) + state(conn, state2); + } + else { + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - if(!result) - state(conn, state1); - } + if(!result) + state(conn, state1); } + Curl_safefree(initresp); } return result; @@ -466,7 +494,7 @@ static void smtp_to_smtps(struct connectdata *conn) conn->handler = &Curl_handler_smtps; } #else -#define smtp_to_smtps(x) +#define smtp_to_smtps(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -499,6 +527,7 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, } } } + return result; } @@ -566,6 +595,7 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, /* end the connect phase */ state(conn, SMTP_STOP); } + return result; } @@ -576,8 +606,8 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - size_t l; - char * plainauth; + size_t len = 0; + char *plainauth = NULL; (void)instate; /* no use for this yet */ @@ -586,16 +616,16 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - l = smtp_auth_plain_data(conn, &plainauth); + result = smtp_auth_plain_data(conn, &plainauth, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - free(plainauth); + if(!result) { + if(plainauth) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - if(!result) - state(conn, SMTP_AUTH); + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(plainauth); } } @@ -609,8 +639,8 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - size_t l; - char * authuser; + size_t len = 0; + char *authuser = NULL; (void)instate; /* no use for this yet */ @@ -619,16 +649,16 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - l = smtp_auth_login_user(conn, &authuser); + result = smtp_auth_login_user(conn, &authuser, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - free(authuser); + if(!result) { + if(authuser) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - if(!result) - state(conn, SMTP_AUTHPASSWD); + if(!result) + state(conn, SMTP_AUTHPASSWD); + } + Curl_safefree(authuser); } } @@ -643,8 +673,8 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; size_t plen; - size_t l; - char *authpasswd; + size_t len = 0; + char *authpasswd = NULL; (void)instate; /* no use for this yet */ @@ -658,16 +688,16 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, if(!plen) result = Curl_pp_sendf(&conn->proto.smtpc.pp, "="); else { - l = Curl_base64_encode(data, conn->passwd, plen, &authpasswd); + result = Curl_base64_encode(data, conn->passwd, plen, &authpasswd, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - free(authpasswd); + if(!result) { + if(authpasswd) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - if(!result) - state(conn, SMTP_AUTH); + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(authpasswd); } } } @@ -687,9 +717,9 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, char * chlg64 = data->state.buffer; unsigned char * chlg; size_t chlglen; - size_t l; - char * rplyb64; - HMAC_context * ctxt; + size_t len = 0; + char *rplyb64 = NULL; + HMAC_context *ctxt; unsigned char digest[16]; char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1]; @@ -708,17 +738,17 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, chlglen = 0; if(*chlg64 != '=') { - for(l = strlen(chlg64); l--;) - if(chlg64[l] != '\r' && chlg64[l] != '\n' && chlg64[l] != ' ' && - chlg64[l] != '\t') + for(len = strlen(chlg64); len--;) + if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' && + chlg64[len] != '\t') break; - if(++l) { - chlg64[l] = '\0'; + if(++len) { + chlg64[len] = '\0'; - chlglen = Curl_base64_decode(chlg64, &chlg); - if(!chlglen) - return CURLE_OUT_OF_MEMORY; + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; } } @@ -728,17 +758,14 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, (unsigned int)(strlen(conn->passwd))); if(!ctxt) { - if(chlg) - free(chlg); - + Curl_safefree(chlg); return CURLE_OUT_OF_MEMORY; } if(chlglen > 0) Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen)); - if(chlg) - free(chlg); + Curl_safefree(chlg); Curl_HMAC_final(ctxt, digest); @@ -751,21 +778,94 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, digest[12], digest[13], digest[14], digest[15]); /* Encode it to base64 and send it. */ - l = Curl_base64_encode(data, reply, 0, &rplyb64); + result = Curl_base64_encode(data, reply, 0, &rplyb64, &len); + + if(!result) { + if(rplyb64) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); + + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(rplyb64); + } + + return result; +} + +#endif - if(!l) - result = CURLE_OUT_OF_MEMORY; +#ifdef USE_NTLM +/* for the AUTH NTLM (without initial response) response. */ +static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *type1msg = NULL; + size_t len = 0; + + (void)instate; /* no use for this yet */ + + if(smtpcode != 334) { + failf(data, "Access denied: %d", smtpcode); + result = CURLE_LOGIN_DENIED; + } else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - free(rplyb64); + result = smtp_auth_ntlm_type1_message(conn, &type1msg, &len); - if(!result) - state(conn, SMTP_AUTH); + if(!result) { + if(type1msg) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg); + + if(!result) + state(conn, SMTP_AUTHNTLM_TYPE2MSG); + } + Curl_safefree(type1msg); + } } return result; } +/* for the NTLM type-2 response (sent in reponse to our type-1 message). */ +static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *type3msg = NULL; + size_t len = 0; + + (void)instate; /* no use for this yet */ + + if(smtpcode != 334) { + failf(data, "Access denied: %d", smtpcode); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_ntlm_decode_type2_message(data, data->state.buffer + 4, + &conn->ntlm); + if(!result) { + result = Curl_ntlm_create_type3_message(conn->data, conn->user, + conn->passwd, &conn->ntlm, + &type3msg, &len); + if(!result) { + if(type3msg) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg); + + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(type3msg); + } + } + } + + return result; +} #endif /* for final responses to AUTH sequences. */ @@ -791,20 +891,49 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn, /* start the DO phase */ static CURLcode smtp_mail(struct connectdata *conn) { + char *from = NULL; + char *size = NULL; CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + /* calculate the FROM parameter */ + if(!data->set.str[STRING_MAIL_FROM]) + /* null reverse-path, RFC-2821, sect. 3.7 */ + from = strdup("<>"); + else if(data->set.str[STRING_MAIL_FROM][0] == '<') + from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); + else + from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); + + if(!from) + return CURLE_OUT_OF_MEMORY; + + /* calculate the optional SIZE parameter */ + if(conn->data->set.infilesize > 0) { + size = aprintf("%" FORMAT_OFF_T, data->set.infilesize); + + if(!size) { + Curl_safefree(from); + + return CURLE_OUT_OF_MEMORY; + } + } + /* send MAIL FROM */ - if(data->set.str[STRING_MAIL_FROM][0] == '<') - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", - data->set.str[STRING_MAIL_FROM]); + if(!size) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", from); else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:<%s>", - data->set.str[STRING_MAIL_FROM]); + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s SIZE=%s", + from, size); + + Curl_safefree(size); + Curl_safefree(from); + if(result) return result; state(conn, SMTP_MAIL); + return result; } @@ -824,6 +953,7 @@ static CURLcode smtp_rcpt_to(struct connectdata *conn) if(!result) state(conn, SMTP_RCPT); } + return result; } @@ -884,6 +1014,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, state(conn, SMTP_DATA); } + return result; } @@ -924,6 +1055,7 @@ static CURLcode smtp_state_postdata_resp(struct connectdata *conn, result = CURLE_RECV_ERROR; state(conn, SMTP_STOP); + return result; } @@ -931,7 +1063,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; @@ -993,6 +1125,17 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) break; #endif +#ifdef USE_NTLM + case SMTP_AUTHNTLM: + result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state); + break; + + case SMTP_AUTHNTLM_TYPE2MSG: + result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode, + smtpc->state); + break; +#endif + case SMTP_AUTH: result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; @@ -1021,6 +1164,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) break; } } + return result; } @@ -1036,7 +1180,7 @@ static CURLcode smtp_multi_statemach(struct connectdata *conn, else result = Curl_pp_multi_statemach(&smtpc->pp); - *done = (bool)(smtpc->state == SMTP_STOP); + *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; return result; } @@ -1087,20 +1231,20 @@ static CURLcode smtp_init(struct connectdata *conn) * smtp_connect() should do everything that is to be considered a part of * the connection phase. * - * The variable 'done' points to will be TRUE if the protocol-layer connect - * phase is done when this function returns, or FALSE is not. When called as - * a part of the easy interface, it will always be TRUE. + * The variable pointed to by 'done' will be TRUE if the protocol-layer + * connect phase is done when this function returns, or FALSE if not. When + * called as a part of the easy interface, it will always be TRUE. */ static CURLcode smtp_connect(struct connectdata *conn, bool *done) /* see description above */ { CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; - struct SessionHandle *data=conn->data; - struct pingpong *pp=&smtpc->pp; + struct SessionHandle *data = conn->data; + struct pingpong *pp = &smtpc->pp; const char *path = conn->data->state.path; int len; - char localhost[1024 + 1]; + char localhost[HOSTNAME_MAX + 1]; *done = FALSE; /* default to not done yet */ @@ -1204,7 +1348,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, { struct SessionHandle *data = conn->data; struct FTP *smtp = data->state.proto.smtp; - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; ssize_t bytes_written; (void)premature; @@ -1234,7 +1378,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, if(status == CURLE_OK) { struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp= &smtpc->pp; + struct pingpong *pp = &smtpc->pp; pp->response = Curl_tvnow(); /* timeout relative now */ state(conn, SMTP_POSTDATA); @@ -1268,7 +1412,7 @@ CURLcode smtp_perform(struct connectdata *conn, bool *dophase_done) { /* this is SMTP and no proxy */ - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -1292,7 +1436,7 @@ CURLcode smtp_perform(struct connectdata *conn, result = smtp_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -1361,9 +1505,10 @@ static CURLcode smtp_quit(struct connectdata *conn) * Disconnect from an SMTP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ -static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) +static CURLcode smtp_disconnect(struct connectdata *conn, + bool dead_connection) { - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the @@ -1377,6 +1522,13 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&smtpc->pp); +#ifdef USE_NTLM + /* Cleanup the ntlm structure */ + if(smtpc->authused == SMTP_AUTH_NTLM) { + Curl_ntlm_sspi_cleanup(&conn->ntlm); + } +#endif + /* This won't already be freed in some error cases */ Curl_safefree(smtpc->domain); smtpc->domain = NULL; @@ -1389,7 +1541,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) { struct FTP *smtp = conn->data->state.proto.smtp; - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; (void)connected; if(smtp->transfer != FTPTRANSFER_BODY) @@ -1404,7 +1556,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, /* called from multi.c while DOing */ static CURLcode smtp_doing(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { CURLcode result; result = smtp_multi_statemach(conn, dophase_done); @@ -1414,6 +1566,7 @@ static CURLcode smtp_doing(struct connectdata *conn, DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -1428,10 +1581,10 @@ static CURLcode smtp_doing(struct connectdata *conn, */ static CURLcode smtp_regular_transfer(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; data->req.size = -1; /* make sure this is unknown at this point */ @@ -1458,7 +1611,7 @@ CURLcode smtp_regular_transfer(struct connectdata *conn, return result; } -static CURLcode smtp_setup_connection(struct connectdata * conn) +static CURLcode smtp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; @@ -1505,42 +1658,43 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) struct SessionHandle *data = conn->data; if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); + data->state.scratch = malloc(2 * BUFSIZE); if(data->state.scratch == NULL) { failf (data, "Failed to alloc scratch buffer!"); return CURLE_OUT_OF_MEMORY; } /* This loop can be improved by some kind of Boyer-Moore style of approach but that is saved for later... */ - for(i = 0, si = 0; i < nread; i++, si++) { - ssize_t left = nread - i; - - if(left>= (ssize_t)(SMTP_EOB_LEN-smtpc->eob)) { - if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - SMTP_EOB_LEN-smtpc->eob)) { - /* It matched, copy the replacement data to the target buffer - instead. Note that the replacement does not contain the - trailing CRLF but we instead continue to match on that one - to deal with repeated sequences. Like CRLF.CRLF.CRLF etc - */ - memcpy(&data->state.scratch[si], SMTP_EOB_REPL, - SMTP_EOB_REPL_LEN); - si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments - it */ - i+=SMTP_EOB_LEN-smtpc->eob-1-2; - smtpc->eob = 0; /* start over */ - continue; - } + for(i = 0, si = 0; i < nread; i++) { + + if(SMTP_EOB[smtpc->eob] == data->req.upload_fromhere[i]) + smtpc->eob++; + else if(smtpc->eob) { + /* previously a substring matched, output that first */ + memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob); + si += smtpc->eob; + + /* then compare the first byte */ + if(SMTP_EOB[0] == data->req.upload_fromhere[i]) + smtpc->eob = 1; + else + smtpc->eob = 0; } - else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - left)) { - /* the last piece of the data matches the EOB so we can't send that - until we know the rest of it */ - smtpc->eob += left; - break; + + if(SMTP_EOB_LEN == smtpc->eob) { + /* It matched, copy the replacement data to the target buffer + instead. Note that the replacement does not contain the + trailing CRLF but we instead continue to match on that one + to deal with repeated sequences. Like CRLF.CRLF.CRLF etc + */ + memcpy(&data->state.scratch[si], SMTP_EOB_REPL, + SMTP_EOB_REPL_LEN); + si += SMTP_EOB_REPL_LEN; + smtpc->eob = 2; /* start over at two bytes */ } + else if(!smtpc->eob) + data->state.scratch[si++] = data->req.upload_fromhere[i]; - data->state.scratch[si] = data->req.upload_fromhere[i]; } /* for() */ if(si != nread) { @@ -1553,6 +1707,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) /* set the new amount too */ data->req.upload_present = nread; } + return CURLE_OK; } diff --git a/lib/smtp.h b/lib/smtp.h index bc4b91eaa..144d49615 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -40,6 +40,8 @@ typedef enum { SMTP_AUTHLOGIN, SMTP_AUTHPASSWD, SMTP_AUTHCRAM, + SMTP_AUTHNTLM, + SMTP_AUTHNTLM_TYPE2MSG, SMTP_AUTH, SMTP_MAIL, /* MAIL FROM */ SMTP_RCPT, /* RCPT TO */ @@ -57,6 +59,7 @@ struct smtp_conn { size_t eob; /* number of bytes of the EOB (End Of Body) that has been received thus far */ unsigned int authmechs; /* Accepted authentication methods. */ + unsigned int authused; /* Authentication method used for the connection */ smtpstate state; /* always use smtp.c:state() to change state! */ struct curl_slist *rcpt; bool ssldone; /* is connect() over SSL done? only relevant in multi mode */ @@ -69,6 +72,7 @@ struct smtp_conn { #define SMTP_AUTH_DIGEST_MD5 0x0008 #define SMTP_AUTH_GSSAPI 0x0010 #define SMTP_AUTH_EXTERNAL 0x0020 +#define SMTP_AUTH_NTLM 0x0040 extern const struct Curl_handler Curl_handler_smtp; extern const struct Curl_handler Curl_handler_smtps; diff --git a/lib/socks.c b/lib/socks.c index 82293019b..b382de798 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -23,11 +23,7 @@ #include "setup.h" #if !defined(CURL_DISABLE_PROXY) || defined(USE_WINDOWS_SSPI) -#include <string.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -60,28 +56,21 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ curl_socket_t sockfd, /* read from this socket */ char *buf, /* store read data here */ ssize_t buffersize, /* max amount to read */ - ssize_t *n, /* amount bytes read */ - long conn_timeout) /* timeout for data wait - relative to - conn->created */ + ssize_t *n) /* amount bytes read */ { ssize_t nread; ssize_t allread = 0; int result; - struct timeval tvnow; - long conntime; + long timeleft; *n = 0; for(;;) { - tvnow = Curl_tvnow(); - /* calculating how long connection is establishing */ - conntime = Curl_tvdiff(tvnow, conn->created); - if(conntime > conn_timeout) { + timeleft = Curl_timeleft(conn->data, NULL, TRUE); + if(timeleft < 0) { /* we already got the timeout */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, - conn_timeout - conntime) <= 0) { + if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) { result = ~CURLE_OK; break; } @@ -133,13 +122,9 @@ CURLcode Curl_SOCKS4(const char *proxy_name, int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - long timeout; struct SessionHandle *data = conn->data; - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - - if(timeout < 0) { + if(Curl_timeleft(data, NULL, TRUE) < 0) { /* time-out, bail out, go home */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; @@ -264,7 +249,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* Receive response */ result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); + &actualread); if((result != CURLE_OK) || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS4 connect request ack."); return CURLE_COULDNT_CONNECT; @@ -299,10 +284,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* Result */ switch(socksreq[1]) { case 90: - if(protocol4a) - infof(data, "SOCKS4a request granted.\n"); - else - infof(data, "SOCKS4 request granted.\n"); + infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); break; case 91: failf(data, @@ -386,7 +368,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, curl_socket_t sock = conn->sock[sockindex]; struct SessionHandle *data = conn->data; long timeout; - bool socks5_resolve_local = (bool)(conn->proxytype == CURLPROXY_SOCKS5); + bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE; const size_t hostname_len = strlen(hostname); ssize_t packetsize = 0; @@ -466,8 +448,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, curlx_nonblock(sock, FALSE); - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); if((result != CURLE_OK) || (actualread != 2)) { failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; @@ -527,8 +508,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_COULDNT_CONNECT; } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); if((result != CURLE_OK) || (actualread != 2)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; @@ -664,7 +644,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, else #endif result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); + &actualread); if((result != CURLE_OK) || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; @@ -720,7 +700,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(packetsize > 10) { packetsize -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - packetsize, &actualread, timeout); + packetsize, &actualread); if((result != CURLE_OK) || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; diff --git a/lib/socks.h b/lib/socks.h index 42b8080b0..fc4cc7f02 100644 --- a/lib/socks.h +++ b/lib/socks.h @@ -39,8 +39,7 @@ int Curl_blockread_all(struct connectdata *conn, curl_socket_t sockfd, char *buf, ssize_t buffersize, - ssize_t *n, - long conn_timeout); + ssize_t *n); /* * This function logs in to a SOCKS4(a) proxy and sends the specifics to the diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 653306cce..d23a944d7 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -27,16 +27,13 @@ #ifdef HAVE_GSSAPI #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 #endif #ifndef gss_nt_service_name #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE #endif -#include <string.h> - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif +#include "curl_gssapi.h" #include "urldata.h" #include "sendf.h" #include "connect.h" @@ -121,7 +118,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, ssize_t actualread; ssize_t written; int result; - long timeout; OM_uint32 gss_major_status, gss_minor_status, gss_status; OM_uint32 gss_ret_flags; int gss_conf_state, gss_enc; @@ -137,9 +133,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for gssapi exchange header only */ char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - /* GSSAPI request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | @@ -183,19 +176,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { - gss_major_status = gss_init_sec_context(&gss_minor_status, - GSS_C_NO_CREDENTIAL, - &gss_context, server, - GSS_C_NULL_OID, - GSS_C_MUTUAL_FLAG | - GSS_C_REPLAY_FLAG, - 0, - NULL, - gss_token, - NULL, - &gss_send_token, - &gss_ret_flags, - NULL); + gss_major_status = Curl_gss_init_sec_context(data, + &gss_minor_status, + &gss_context, + server, + NULL, + gss_token, + &gss_send_token, + &gss_ret_flags); if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); @@ -253,8 +241,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive GSSAPI authentication response."); gss_release_name(&gss_status, &server); @@ -294,8 +281,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, - &actualread, timeout); + gss_recv_token.length, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive GSSAPI authentication token."); @@ -452,8 +438,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_w_token); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive GSSAPI encryption response."); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -485,8 +470,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, - &actualread, timeout); + gss_recv_token.length, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive GSSAPI encryptrion type."); diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 6d42af3a5..d96a82e8a 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -20,17 +20,10 @@ * ***************************************************************************/ - #include "setup.h" #ifdef USE_WINDOWS_SSPI -#include <string.h> - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif - #include "urldata.h" #include "sendf.h" #include "connect.h" @@ -167,7 +160,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, ssize_t actualread; ssize_t written; int result; - long timeout; /* Needs GSSAPI authentication */ SECURITY_STATUS sspi_major_status, sspi_minor_status=0; unsigned long sspi_ret_flags=0; @@ -186,9 +178,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for gssapi exchange header only */ char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - /* GSSAPI request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | @@ -283,7 +272,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "InitializeSecurityContextA") ){ + "InitializeSecurityContextA") ) { free(service_name); service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); @@ -344,8 +333,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive SSPI authentication response."); free(service_name); @@ -390,8 +378,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, - &actualread, timeout); + sspi_recv_token.cbBuffer, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive SSPI authentication token."); @@ -416,7 +403,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, &names); s_pSecFn->FreeCredentialsHandle(&cred_handle); if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "QueryCredentialAttributes") ){ + "QueryCredentialAttributes") ) { s_pSecFn->DeleteSecurityContext(&sspi_context); s_pSecFn->FreeContextBuffer(names.sUserName); failf(data, "Failed to determine user name."); @@ -499,7 +486,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_w_token[1].cbBuffer = 1; sspi_w_token[1].pvBuffer = malloc(1); - if(!sspi_w_token[1].pvBuffer){ + if(!sspi_w_token[1].pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; @@ -592,8 +579,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive SSPI encryption response."); s_pSecFn->DeleteSecurityContext(&sspi_context); @@ -626,8 +612,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, - &actualread, timeout); + sspi_w_token[0].cbBuffer, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive SSPI encryption type."); diff --git a/lib/speedcheck.c b/lib/speedcheck.c index 56ac34aef..ca2323f57 100644 --- a/lib/speedcheck.c +++ b/lib/speedcheck.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <string.h> - #include <curl/curl.h> #include "urldata.h" #include "sendf.h" @@ -44,12 +41,12 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, (Curl_tvlong(data->state.keeps_speed) != 0) && (data->progress.current_speed < data->set.low_speed_limit)) { long howlong = Curl_tvdiff(now, data->state.keeps_speed); + long nextcheck = (data->set.low_speed_time * 1000) - howlong; /* We are now below the "low speed limit". If we are below it for "low speed time" seconds we consider that enough reason to abort the download. */ - - if((howlong/1000) > data->set.low_speed_time) { + if(nextcheck <= 0) { /* we have been this slow for long enough, now die */ failf(data, "Operation too slow. " @@ -58,7 +55,10 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, data->set.low_speed_time); return CURLE_OPERATION_TIMEDOUT; } - Curl_expire(data, howlong); + else { + /* wait complete low_speed_time */ + Curl_expire(data, nextcheck); + } } else { /* we keep up the required speed all right */ diff --git a/lib/splay.h b/lib/splay.h index 832e4e2bb..49a6dec41 100644 --- a/lib/splay.h +++ b/lib/splay.h @@ -1,5 +1,5 @@ -#ifndef __SPLAY_H -#define __SPLAY_H +#ifndef HEADER_CURL_SPLAY_H +#define HEADER_CURL_SPLAY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1997 - 2011, Daniel Stenberg, <daniel@haxx.se>, 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,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" struct Curl_tree { struct Curl_tree *smaller; /* smaller node */ @@ -59,7 +60,7 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, #ifdef DEBUGBUILD void Curl_splayprint(struct Curl_tree * t, int d, char output); #else -#define Curl_splayprint(x,y,z) +#define Curl_splayprint(x,y,z) Curl_nop_stmt #endif -#endif +#endif /* HEADER_CURL_SPLAY_H */ @@ -25,11 +25,7 @@ #include "setup.h" #ifdef USE_LIBSSH2 -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> + #ifdef HAVE_LIMITS_H # include <limits.h> #endif @@ -45,11 +41,6 @@ #include <fcntl.h> #endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#ifndef WIN32 #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -69,7 +60,6 @@ #include <in.h> #include <inet.h> #endif -#endif /* !WIN32 */ #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t @@ -108,6 +98,11 @@ /* The last #include file should be: */ #include "memdebug.h" +#ifdef WIN32 +# undef PATH_MAX +# define PATH_MAX MAX_PATH +#endif + #ifndef PATH_MAX #define PATH_MAX 1024 /* just an extra precaution since there are systems that have their definition hidden well */ @@ -170,6 +165,7 @@ const struct Curl_handler Curl_handler_scp = { scp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -194,6 +190,7 @@ const struct Curl_handler Curl_handler_sftp = { sftp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -649,6 +646,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) const char *fingerprint; #endif /* CURL_LIBSSH2_DEBUG */ const char *host_public_key_md5; + char *new_readdir_line; int rc = LIBSSH2_ERROR_NONE, i; int err; int seekerr = CURL_SEEKFUNC_OK; @@ -1581,7 +1579,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) SEEK_SET); } - if(seekerr != CURL_SEEKFUNC_OK){ + if(seekerr != CURL_SEEKFUNC_OK) { if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); @@ -1864,10 +1862,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } Curl_safefree(sshc->readdir_linkPath); sshc->readdir_linkPath = NULL; - sshc->readdir_line = realloc(sshc->readdir_line, - sshc->readdir_totalLen + 4 + - sshc->readdir_len); - if(!sshc->readdir_line) { + + new_readdir_line = realloc(sshc->readdir_line, + sshc->readdir_totalLen + 4 + + sshc->readdir_len); + if(!new_readdir_line) { + Curl_safefree(sshc->readdir_line); + sshc->readdir_line = NULL; Curl_safefree(sshc->readdir_filename); sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); @@ -1876,6 +1877,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } + sshc->readdir_line = new_readdir_line; sshc->readdir_currLen += snprintf(sshc->readdir_line + sshc->readdir_currLen, @@ -2388,10 +2390,39 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } sshc->ssh_session = NULL; } + + /* worst-case scenario cleanup */ + + DEBUGASSERT(sshc->ssh_session == NULL); + DEBUGASSERT(sshc->ssh_channel == NULL); + DEBUGASSERT(sshc->sftp_session == NULL); + DEBUGASSERT(sshc->sftp_handle == NULL); +#ifdef HAVE_LIBSSH2_KNOWNHOST_API + DEBUGASSERT(sshc->kh == NULL); +#endif + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + + Curl_safefree(sshc->homedir); + + Curl_safefree(sshc->readdir_filename); + Curl_safefree(sshc->readdir_longentry); + Curl_safefree(sshc->readdir_line); + Curl_safefree(sshc->readdir_linkPath); + + /* the code we are about to return */ + result = sshc->actualcode; + + memset(sshc, 0, sizeof(struct ssh_conn)); + conn->bits.close = TRUE; + sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); - result = sshc->actualcode; break; case SSH_QUIT: @@ -2488,7 +2519,7 @@ static void ssh_block2waitfor(struct connectdata *conn, bool block) } #else /* no libssh2 directional support so we simply don't know */ -#define ssh_block2waitfor(x,y) +#define ssh_block2waitfor(x,y) Curl_nop_stmt #endif /* called repeatedly until done from multi.c */ @@ -2500,7 +2531,7 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done) implementation */ result = ssh_statemach_act(conn, &block); - *done = (bool)(sshc->state == SSH_STOP); + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; ssh_block2waitfor(conn, block); return result; @@ -2706,7 +2737,7 @@ CURLcode scp_perform(struct connectdata *conn, result = ssh_easy_statemach(conn, FALSE); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -2913,7 +2944,7 @@ CURLcode sftp_perform(struct connectdata *conn, result = ssh_easy_statemach(conn, FALSE); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/sslgen.c b/lib/sslgen.c index 779d9e9c3..3b7340244 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -43,9 +43,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -65,6 +62,7 @@ #include "url.h" #include "curl_memory.h" #include "progress.h" +#include "share.h" /* The last #include file should be: */ #include "memdebug.h" @@ -72,10 +70,10 @@ static bool safe_strequal(char* str1, char* str2) { if(str1 && str2) /* both pointers point to something then compare them */ - return (bool)(0 != Curl_raw_equal(str1, str2)); + return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE; else /* if both pointers are NULL then treat them as equal */ - return (bool)(!str1 && !str2); + return (!str1 && !str2) ? TRUE : FALSE; } bool @@ -213,7 +211,7 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, /* mark this is being ssl requested from here on. */ conn->ssl[sockindex].use = TRUE; res = curlssl_connect_nonblocking(conn, sockindex, done); - if(!res && *done == TRUE) + if(!res && *done) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ return res; #else @@ -239,6 +237,10 @@ int Curl_ssl_getsessionid(struct connectdata *conn, /* session ID re-use is disabled */ return TRUE; + /* Lock for reading if shared */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SHARED); + for(i=0; i< data->set.ssl.numsessions; i++) { check = &data->state.session[i]; if(!check->sessionid) @@ -257,13 +259,19 @@ int Curl_ssl_getsessionid(struct connectdata *conn, } } *ssl_sessionid = NULL; + + /* Unlock for reading */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); + + return TRUE; } /* * Kill a single session ID entry in the cache. */ -static int kill_session(struct curl_ssl_session *session) +int Curl_ssl_kill_session(struct curl_ssl_session *session) { if(session->sessionid) { /* defensive check */ @@ -291,14 +299,23 @@ static int kill_session(struct curl_ssl_session *session) void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { int i; - for(i=0; i< conn->data->set.ssl.numsessions; i++) { - struct curl_ssl_session *check = &conn->data->state.session[i]; + struct SessionHandle *data=conn->data; + + if(data->share && data->share->sslsession == data->state.session) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_ACCESS_SINGLE); + + for(i=0; i< data->set.ssl.numsessions; i++) { + struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { - kill_session(check); + Curl_ssl_kill_session(check); break; } } + + if(data->share && data->share->sslsession == data->state.session) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } /* @@ -328,6 +345,10 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ + /* If using shared SSL session, lock! */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + /* find an empty slot for us, or find the oldest */ for(i=1; (i<data->set.ssl.numsessions) && data->state.session[i].sessionid; i++) { @@ -338,7 +359,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } if(i == data->set.ssl.numsessions) /* cache is full, we must "kill" the oldest entry! */ - kill_session(store); + Curl_ssl_kill_session(store); else store = &data->state.session[i]; /* use this slot */ @@ -352,6 +373,11 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->name = clone_host; /* clone host name */ store->remote_port = conn->remote_port; /* port number */ + + /* Unlock */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); + if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); @@ -366,14 +392,20 @@ void Curl_ssl_close_all(struct SessionHandle *data) { long i; /* kill the session ID cache */ - if(data->state.session) { + if(data->state.session && + !(data->share && data->share->sslsession == data->state.session)) { + + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + for(i=0; i< data->set.ssl.numsessions; i++) /* the single-killer function handles empty table slots */ - kill_session(&data->state.session[i]); + Curl_ssl_kill_session(&data->state.session[i]); /* free the cache data */ free(data->state.session); data->state.session = NULL; + + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } curlssl_close_all(data); @@ -472,9 +504,12 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data) struct curl_certinfo *ci = &data->info.certs; if(ci->num_of_certs) { /* free all individual lists used */ - for(i=0; i<ci->num_of_certs; i++) + for(i=0; i<ci->num_of_certs; i++) { curl_slist_free_all(ci->certinfo[i]); + ci->certinfo[i] = NULL; + } free(ci->certinfo); /* free the actual array too */ + ci->certinfo = NULL; ci->num_of_certs = 0; } } diff --git a/lib/sslgen.h b/lib/sslgen.h index b0a0fab12..516817618 100644 --- a/lib/sslgen.h +++ b/lib/sslgen.h @@ -1,5 +1,5 @@ -#ifndef __SSLGEN_H -#define __SSLGEN_H +#ifndef HEADER_CURL_SSLGEN_H +#define HEADER_CURL_SSLGEN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" bool Curl_ssl_config_matches(struct ssl_config_data* data, struct ssl_config_data* needle); @@ -63,6 +64,8 @@ int Curl_ssl_getsessionid(struct connectdata *conn, CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize); +/* Kill a single session ID entry in the cache */ +int Curl_ssl_kill_session(struct curl_ssl_session *session); /* delete a session from the cache */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); @@ -71,10 +74,10 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); #else /* When SSL support is not present, just define away these function calls */ #define Curl_ssl_init() 1 -#define Curl_ssl_cleanup() do { } while (0) +#define Curl_ssl_cleanup() Curl_nop_stmt #define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN -#define Curl_ssl_close_all(x) -#define Curl_ssl_close(x,y) +#define Curl_ssl_close_all(x) Curl_nop_stmt +#define Curl_ssl_close(x,y) Curl_nop_stmt #define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN @@ -85,8 +88,9 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); #define Curl_ssl_version(x,y) 0 #define Curl_ssl_data_pending(x,y) 0 #define Curl_ssl_check_cxn(x) 0 -#define Curl_ssl_free_certinfo(x) +#define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN +#define Curl_ssl_kill_session(x) 0 #endif -#endif /* USE_SSL */ +#endif /* HEADER_CURL_SSLGEN_H */ diff --git a/lib/ssluse.c b/lib/ssluse.c index 5bdc536a3..d65fd98b9 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -32,9 +32,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -123,7 +120,7 @@ /* 0.9.6 didn't have X509_STORE_set_flags() */ #define HAVE_X509_STORE_SET_FLAGS 1 #else -#define X509_STORE_set_flags(x,y) +#define X509_STORE_set_flags(x,y) Curl_nop_stmt #endif /* @@ -169,14 +166,14 @@ static int passwd_callback(char *buf, int num, int verify #define seed_enough(x) rand_enough() static bool rand_enough(void) { - return (bool)(0 != RAND_status()); + return (0 != RAND_status()) ? TRUE : FALSE; } #else #define seed_enough(x) rand_enough(x) static bool rand_enough(int nread) { /* this is a very silly decision to make */ - return (bool)(nread > 500); + return (nread > 500) ? TRUE : FALSE; } #endif @@ -813,18 +810,16 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) { struct curl_slist *list = NULL; #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - struct curl_slist *beg = NULL; + struct curl_slist *beg; ENGINE *e; for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - list = curl_slist_append(list, ENGINE_get_id(e)); - if(list == NULL) { - curl_slist_free_all(beg); + beg = curl_slist_append(list, ENGINE_get_id(e)); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; } #endif (void) data; @@ -1410,7 +1405,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME # define use_sni(x) sni = (x) #else -# define use_sni(x) do { } while (0) +# define use_sni(x) Curl_nop_stmt #endif static CURLcode @@ -1492,6 +1487,10 @@ ossl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS); +#endif + #ifdef SSL_CTRL_SET_MSG_CALLBACK if(data->set.fdebug && data->set.verbose) { /* the SSL trace callback is only used for verbose logging so we only @@ -1856,15 +1855,15 @@ static CURLcode push_certinfo_len(struct SessionHandle *data, equivalent of curl_slist_append but doesn't strdup() the given data as like in this place the extra malloc/free is totally pointless */ nl = curl_slist_append(ci->certinfo[certnum], output); + free(output); if(!nl) { curl_slist_free_all(ci->certinfo[certnum]); + ci->certinfo[certnum] = NULL; res = CURLE_OUT_OF_MEMORY; } else ci->certinfo[certnum] = nl; - free(output); - return res; } @@ -1918,7 +1917,7 @@ do { \ pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \ } \ } \ -} while(0) +} WHILE_FALSE static int X509V3_ext(struct SessionHandle *data, int certnum, @@ -2563,7 +2562,7 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (bool)(0 != SSL_pending(conn->ssl[connindex].handle)); + return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; else return FALSE; } diff --git a/lib/ssluse.h b/lib/ssluse.h index 2ac0ad2ec..732ec7c72 100644 --- a/lib/ssluse.h +++ b/lib/ssluse.h @@ -1,5 +1,5 @@ -#ifndef __SSLUSE_H -#define __SSLUSE_H +#ifndef HEADER_CURL_SSLUSE_H +#define HEADER_CURL_SSLUSE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -22,12 +22,15 @@ * ***************************************************************************/ +#include "setup.h" + #ifdef USE_SSLEAY /* * This header should only be needed to get included by sslgen.c and ssluse.c */ #include "urldata.h" + CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, int sockindex, @@ -81,4 +84,4 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y) #endif /* USE_SSLEAY */ -#endif /* __SSLUSE_H */ +#endif /* HEADER_CURL_SSLUSE_H */ diff --git a/lib/strdup.c b/lib/strdup.c index a3107cff7..02d480c26 100644 --- a/lib/strdup.c +++ b/lib/strdup.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include "strdup.h" #ifndef HAVE_STRDUP diff --git a/lib/strequal.c b/lib/strequal.c index 15896b9fd..89ad8a6e8 100644 --- a/lib/strequal.c +++ b/lib/strequal.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <ctype.h> - #ifdef HAVE_STRINGS_H #include <strings.h> #endif diff --git a/lib/strerror.c b/lib/strerror.c index 0a883421e..fcb617cf2 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -34,9 +34,6 @@ #endif #include <curl/curl.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> #ifdef USE_LIBIDN #include <idna.h> @@ -387,6 +384,9 @@ curl_share_strerror(CURLSHcode error) case CURLSHE_NOMEM: return "Out of memory"; + case CURLSHE_NOT_BUILT_IN: + return "Feature not enabled in this library"; + case CURLSHE_LAST: break; } diff --git a/lib/strtok.c b/lib/strtok.c index 91c254156..94eac0e64 100644 --- a/lib/strtok.c +++ b/lib/strtok.c @@ -24,7 +24,6 @@ #ifndef HAVE_STRTOK_R #include <stddef.h> -#include <string.h> #include "strtok.h" diff --git a/lib/strtoofft.c b/lib/strtoofft.c index 55a6ffd0d..c61459de8 100644 --- a/lib/strtoofft.c +++ b/lib/strtoofft.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include "strtoofft.h" /* @@ -32,15 +33,11 @@ */ #ifdef NEED_CURL_STRTOLL -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> /* Range tests can be used for alphanum decoding if characters are consecutive, like in ASCII. Else an array is scanned. Determine this condition now. */ #if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25 -#include <string.h> #define NO_RANGE_TEST diff --git a/lib/telnet.c b/lib/telnet.c index 80592d27e..59094b674 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -23,28 +23,19 @@ #include "setup.h" #ifndef CURL_DISABLE_TELNET -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#if defined(WIN32) -#include <time.h> -#include <io.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -59,8 +50,6 @@ #include <sys/param.h> #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -99,7 +88,7 @@ #define CURL_SB_LEN(x) (x->subend - x->subpointer) #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define printoption(a,b,c,d) do { } while(0) +#define printoption(a,b,c,d) Curl_nop_stmt #endif #ifdef USE_WINSOCK @@ -193,6 +182,7 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -774,18 +764,24 @@ static void printsub(struct SessionHandle *data, static CURLcode check_telnet_options(struct connectdata *conn) { struct curl_slist *head; + struct curl_slist *beg; char option_keyword[128]; char option_arg[256]; - char *buf; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; + CURLcode result = CURLE_OK; /* Add the user name as an environment variable if it was given on the command line */ if(conn->bits.user_passwd) { snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg); - + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + return CURLE_OUT_OF_MEMORY; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } @@ -811,24 +807,33 @@ static CURLcode check_telnet_options(struct connectdata *conn) /* Environment variable */ if(Curl_raw_equal(option_keyword, "NEW_ENV")) { - buf = strdup(option_arg); - if(!buf) - return CURLE_OUT_OF_MEMORY; - tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf); + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + result = CURLE_OUT_OF_MEMORY; + break; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; continue; } failf(data, "Unknown telnet option %s", head->data); - return CURLE_UNKNOWN_TELNET_OPTION; + result = CURLE_UNKNOWN_TELNET_OPTION; + break; } else { failf(data, "Syntax error in telnet option: %s", head->data); - return CURLE_TELNET_OPTION_SYNTAX; + result = CURLE_TELNET_OPTION_SYNTAX; + break; } } - return CURLE_OK; + if(result) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + } + + return result; } /* @@ -1120,6 +1125,7 @@ static CURLcode telnet_done(struct connectdata *conn, (void)premature; /* not used */ curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; free(conn->data->state.proto.telnet); conn->data->state.proto.telnet = NULL; @@ -1238,13 +1244,6 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) return CURLE_FAILED_INIT; } - /* The get the Windows file handle for stdin */ - stdin_handle = GetStdHandle(STD_INPUT_HANDLE); - - /* Create the list of objects to wait for */ - objs[0] = event_handle; - objs[1] = stdin_handle; - /* Tell winsock what events we want to listen to */ if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { @@ -1253,9 +1252,17 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) return CURLE_OK; } + /* The get the Windows file handle for stdin */ + stdin_handle = GetStdHandle(STD_INPUT_HANDLE); + + /* Create the list of objects to wait for */ + objs[0] = event_handle; + objs[1] = stdin_handle; + /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it, else use the old WaitForMultipleObjects() way */ - if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) { + if(GetFileType(stdin_handle) == FILE_TYPE_PIPE || + data->set.is_fread_set) { /* Don't wait for stdin_handle, just wait for event_handle */ obj_count = 1; /* Check stdin_handle per 100 milliseconds */ @@ -1273,20 +1280,41 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_TIMEOUT: { for(;;) { - if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { - keepon = FALSE; - code = CURLE_READ_ERROR; - break; + if(obj_count == 1) { + /* read from user-supplied method */ + code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in); + if(code == CURL_READFUNC_ABORT) { + keepon = FALSE; + code = CURLE_READ_ERROR; + break; + } + + if(code == CURL_READFUNC_PAUSE) + break; + + if(code == 0) /* no bytes */ + break; + + readfile_read = code; /* fall thru with number of bytes read */ } + else { + /* read from stdin */ + if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, + &readfile_read, NULL)) { + keepon = FALSE; + code = CURLE_READ_ERROR; + break; + } - if(!readfile_read) - break; + if(!readfile_read) + break; - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), - &readfile_read, NULL)) { - keepon = FALSE; - code = CURLE_READ_ERROR; - break; + if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + &readfile_read, NULL)) { + keepon = FALSE; + code = CURLE_READ_ERROR; + break; + } } code = send_telnet_data(conn, buf, readfile_read); @@ -1375,7 +1403,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } /* We called WSACreateEvent, so call WSACloseEvent */ - if(close_event_func(event_handle) == FALSE) { + if(!close_event_func(event_handle)) { infof(data,"WSACloseEvent failed (%d)", SOCKERRNO); } diff --git a/lib/tftp.c b/lib/tftp.c index 46b3ecfcb..9b44a9b3d 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -23,27 +23,19 @@ #include "setup.h" #ifndef CURL_DISABLE_TFTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#if defined(WIN32) -#include <time.h> -#include <io.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -58,8 +50,6 @@ #include <sys/param.h> #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -194,6 +184,7 @@ const struct Curl_handler Curl_handler_tftp = { tftp_doing, /* doing */ tftp_getsock, /* proto_getsock */ tftp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -216,7 +207,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) { time_t maxtime, timeout; long timeout_ms; - bool start = (bool)(state->state == TFTP_STATE_START); + bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; time(&state->start_time); @@ -258,11 +249,11 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; - /* Set per-block timeout to 10% of total */ - timeout = maxtime/10 ; + /* Set per-block timeout to total */ + timeout = maxtime; - /* Average reposting an ACK after 15 seconds */ - state->retry_max = (int)timeout/15; + /* Average reposting an ACK after 5 seconds */ + state->retry_max = (int)timeout/5; } /* But bound the total number */ if(state->retry_max<3) @@ -601,15 +592,10 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) /* Is this the block we expect? */ rblock = getrpacketblock(&state->rpacket); if(NEXT_BLOCKNUM(state->block) != rblock) { - /* No, log it, up the retry count and fail if over the limit */ + /* No, log it */ infof(data, - "Received unexpected DATA packet block %d\n", rblock); - state->retries++; - if(state->retries > state->retry_max) { - failf(data, "tftp_rx: giving up waiting for block %d", - NEXT_BLOCKNUM(state->block)); - return CURLE_TFTP_ILLEGAL; - } + "Received unexpected DATA packet block %d, expecting block %d\n", + rblock, NEXT_BLOCKNUM(state->block)); break; } /* This is the expected block. Reset counters and ACK it. */ @@ -627,7 +613,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) } /* Check if completed (That is, a less than full packet is received) */ - if(state->rbytes < (ssize_t)state->blksize+4){ + if(state->rbytes < (ssize_t)state->blksize+4) { state->state = TFTP_STATE_FIN; } else { @@ -1344,7 +1330,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) result = tftp_state_machine(state, event); if(result != CURLE_OK) return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1366,7 +1352,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) result = tftp_state_machine(state, state->event); if(result != CURLE_OK) return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); diff --git a/lib/transfer.c b/lib/transfer.c index 94cd6d6f9..413a28082 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -22,31 +22,16 @@ #include "setup.h" -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - #include "strtoofft.h" #include "strequal.h" #include "rawstr.h" -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -78,8 +63,6 @@ #error "We can't compile without socket() support!" #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "netrc.h" @@ -95,7 +78,7 @@ #include "getinfo.h" #include "sslgen.h" #include "http_digest.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" #include "http_negotiate.h" #include "share.h" #include "curl_memory.h" @@ -186,11 +169,12 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) const char *endofline_native; const char *endofline_network; int hexlen; + + if( #ifdef CURL_DO_LINEEND_CONV - if((data->set.crlf) || (data->set.prefer_ascii)) { -#else - if(data->set.crlf) { -#endif /* CURL_DO_LINEEND_CONV */ + (data->set.prefer_ascii) || +#endif + (data->set.crlf)) { /* \n will become \r\n later on */ endofline_native = "\n"; endofline_network = "\x0a"; @@ -302,7 +286,7 @@ CURLcode Curl_readrewind(struct connectdata *conn) else { /* If no CURLOPT_READFUNCTION is used, we know that we operate on a given FILE * stream and we can actually attempt to rewind that - ourself with fseek() */ + ourselves with fseek() */ if(data->set.fread_func == (curl_read_callback)fread) { if(-1 != fseek(data->set.in, 0, SEEK_SET)) /* successful rewind */ @@ -446,7 +430,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, *didwhat |= KEEP_RECV; /* indicates data of zero size, i.e. empty file */ - is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0)); + is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; /* NUL terminate, allowing string ops to be used */ if(0 < nread || is_empty_data) { @@ -522,7 +506,6 @@ static CURLcode readwrite_data(struct SessionHandle *data, is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { - #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to @@ -570,9 +553,10 @@ static CURLcode readwrite_data(struct SessionHandle *data, } } /* we have a time condition */ - } /* this is HTTP */ + } /* this is HTTP or RTSP */ } /* this is the first time we write a body part */ #endif /* CURL_DISABLE_HTTP */ + k->bodywrites++; /* pass data to the debug function before it gets "dechunked" */ @@ -606,7 +590,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, failf(data, "Failed writing data"); return CURLE_WRITE_ERROR; } - failf(data, "Received problem %d in the chunky parser", (int)res); + failf(data, "Problem (%d) in the Chunked-Encoded data", (int)res); return CURLE_RECV_ERROR; } else if(CHUNKE_STOP == res) { @@ -816,6 +800,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* * We loop here to do the READ and SEND loop until we run out of * data to send or until we get EWOULDBLOCK back + * + * FIXME: above comment is misleading. Currently no looping is + * actually done in do-while loop below. */ do { @@ -892,13 +879,12 @@ static CURLcode readwrite_upload(struct SessionHandle *data, #endif /* CURL_DISABLE_SMTP */ /* convert LF to CRLF if so asked */ - if((!sending_http_headers) && + if((!sending_http_headers) && ( #ifdef CURL_DO_LINEEND_CONV - /* always convert if we're FTPing in ASCII mode */ - ((data->set.crlf) || (data->set.prefer_ascii))) { -#else - (data->set.crlf)) { + /* always convert if we're FTPing in ASCII mode */ + (data->set.prefer_ascii) || #endif + (data->set.crlf))) { if(data->state.scratch == NULL) data->state.scratch = malloc(2*BUFSIZE); if(data->state.scratch == NULL) { @@ -988,7 +974,7 @@ static CURLcode readwrite_upload(struct SessionHandle *data, Curl_pgrsSetUploadCounter(data, k->writebytecount); - } while(0); /* just to break out from! */ + } WHILE_FALSE; /* just to break out from! */ return CURLE_OK; } @@ -1043,6 +1029,12 @@ CURLcode Curl_readwrite(struct connectdata *conn, if(result || *done) return result; } + else if(k->keepon & KEEP_RECV) { + DEBUGF(infof(data, "additional stuff not fine %s:%d: %d %d\n", + __FILE__, __LINE__, + select_res & CURL_CSELECT_IN, + conn->bits.stream_was_rewound)); + } /* If we still have writing to do, we check if we have a writable socket. */ if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) { @@ -1136,7 +1128,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, (conn->chunk.state != CHUNK_STOP)) { /* * In chunked mode, return an error if the connection is closed prior to - * the empty (terminiating) chunk is read. + * the empty (terminating) chunk is read. * * The condition above used to check for * conn->proto.http->chunk.datasize != 0 which is true after reading @@ -1151,8 +1143,8 @@ CURLcode Curl_readwrite(struct connectdata *conn, } /* Now update the "done" boolean we return */ - *done = (bool)(0 == (k->keepon&(KEEP_RECV|KEEP_SEND| - KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))); + *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| + KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; return CURLE_OK; } @@ -1213,11 +1205,11 @@ int Curl_single_getsock(const struct connectdata *conn, /* * Determine optimum sleep time based on configured rate, current rate, * and packet size. - * Returns value in mili-seconds. + * Returns value in milliseconds. * * The basic idea is to adjust the desired rate up/down in this method * based on whether we are running too slow or too fast. Then, calculate - * how many miliseconds to wait for the next packet to achieve this new + * how many milliseconds to wait for the next packet to achieve this new * rate. */ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, @@ -1243,7 +1235,7 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, rate_bps += rate_bps >> 6; } - /* Determine number of miliseconds to wait until we do + /* Determine number of milliseconds to wait until we do * the next packet at the adjusted rate. We should wait * longer when using larger packets, for instance. */ @@ -1448,8 +1440,10 @@ static CURLcode loadhostpairs(struct SessionHandle *data) if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - if(!dns) + if(!dns) { + Curl_freeaddrinfo(addr); return CURLE_OUT_OF_MEMORY; + } } } data->change.resolve = NULL; /* dealt with now */ @@ -1613,7 +1607,7 @@ static bool is_absolute_url(const char *url) char prot[16]; /* URL protocol string storage */ char letter; /* used for a silly sscanf */ - return (bool)(2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)); + return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE; } /* @@ -1705,26 +1699,37 @@ static char *concat_url(const char *base, const char *relurl) } } else { - /* We got a new absolute path for this server, cut off from the - first slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) { - /* When people use badly formatted URLs, such as - "http://www.url.com?dir=/home/daniel" we must not use the first - slash, if there's a ?-letter before it! */ - char *sep = strchr(protsep, '?'); - if(sep && (sep < pathsep)) - pathsep = sep; - *pathsep=0; + /* We got a new absolute path for this server */ + + if((relurl[0] == '/') && (relurl[1] == '/')) { + /* the new URL starts with //, just keep the protocol part from the + original one */ + *protsep=0; + useurl = &relurl[2]; /* we keep the slashes from the original, so we + skip the new ones */ } else { - /* There was no slash. Now, since we might be operating on a badly - formatted URL, such as "http://www.url.com?id=2380" which doesn't - use a slash separator as it is supposed to, we need to check for a - ?-letter as well! */ - pathsep = strchr(protsep, '?'); - if(pathsep) + /* cut off the original URL from the first slash, or deal with URLs + without slash */ + pathsep = strchr(protsep, '/'); + if(pathsep) { + /* When people use badly formatted URLs, such as + "http://www.url.com?dir=/home/daniel" we must not use the first + slash, if there's a ?-letter before it! */ + char *sep = strchr(protsep, '?'); + if(sep && (sep < pathsep)) + pathsep = sep; *pathsep=0; + } + else { + /* There was no slash. Now, since we might be operating on a badly + formatted URL, such as "http://www.url.com?id=2380" which doesn't + use a slash separator as it is supposed to, we need to check for a + ?-letter as well! */ + pathsep = strchr(protsep, '?'); + if(pathsep) + *pathsep=0; + } } } @@ -1737,8 +1742,8 @@ static char *concat_url(const char *base, const char *relurl) urllen = strlen(url_clone); - newest = malloc( urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); + newest = malloc(urllen + 1 + /* possible slash */ + newlen + 1 /* zero byte */); if(!newest) { free(url_clone); /* don't leak this */ @@ -1801,15 +1806,14 @@ CURLcode Curl_follow(struct SessionHandle *data, when we get the next URL. We pick the ->url field, which may or may not be 100% correct */ - if(data->change.referer_alloc) - /* If we already have an allocated referer, free this first */ - free(data->change.referer); + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } data->change.referer = strdup(data->change.url); - if(!data->change.referer) { - data->change.referer_alloc = FALSE; + if(!data->change.referer) return CURLE_OUT_OF_MEMORY; - } data->change.referer_alloc = TRUE; /* yes, free this later */ } } @@ -1856,12 +1860,13 @@ CURLcode Curl_follow(struct SessionHandle *data, if(disallowport) data->state.allow_port = FALSE; - if(data->change.url_alloc) - free(data->change.url); - else - data->change.url_alloc = TRUE; /* the URL is allocated */ + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = newurl; + data->change.url_alloc = TRUE; newurl = NULL; /* don't free! */ infof(data, "Issue another request to this URL: '%s'\n", data->change.url); @@ -1889,19 +1894,18 @@ CURLcode Curl_follow(struct SessionHandle *data, case 301: /* Moved Permanently */ /* (quote from RFC2616, section 10.3.2): * - * Note: When automatically redirecting a POST request after receiving a - * 301 status code, some existing HTTP/1.0 user agents will erroneously - * change it into a GET request. + * When automatically redirecting a POST request after receiving a 301 + * status code, some existing HTTP/1.0 user agents will erroneously change + * it into a GET request. * * ---- * - * Warning: Because most of importants user agents do this obvious RFC2616 - * violation, many webservers expect this misbehavior. So these servers - * often answers to a POST request with an error page. To be sure that - * libcurl gets the page that most user agents would get, libcurl has to - * force GET. + * As most of the important user agents do this obvious RFC2616 violation, + * many webservers expect this. So these servers often answers to a POST + * request with an error page. To be sure that libcurl gets the page that + * most user agents would get, libcurl has to force GET. * - * This behaviour can be overridden with CURLOPT_POSTREDIR. + * This behavior can be overridden with CURLOPT_POSTREDIR. */ if((data->set.httpreq == HTTPREQ_POST || data->set.httpreq == HTTPREQ_POST_FORM) @@ -1929,7 +1933,7 @@ CURLcode Curl_follow(struct SessionHandle *data, 302 status code may be used instead, since most user agents react to a 302 response as described here for 303. - This behaviour can be overriden with CURLOPT_POSTREDIR + This behavior can be overridden with CURLOPT_POSTREDIR */ if((data->set.httpreq == HTTPREQ_POST || data->set.httpreq == HTTPREQ_POST_FORM) @@ -2092,7 +2096,7 @@ CURLcode Curl_retry_request(struct connectdata *conn, transferred! */ if(data->state.proto.http->writebytecount) - Curl_readrewind(conn); + return Curl_readrewind(conn); } return CURLE_OK; } @@ -20,30 +20,14 @@ * ***************************************************************************/ -/* -- WIN32 approved -- */ - #include "setup.h" -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -73,8 +57,6 @@ #error "We can't compile without socket() support!" #endif -#endif /* WIN32 */ - #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -137,7 +119,8 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "url.h" #include "connect.h" #include "inet_ntop.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" +#include "curl_ntlm_wb.h" #include "socks.h" #include "curl_rtmp.h" #include "gopher.h" @@ -153,6 +136,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out); static long ConnectionKillOne(struct SessionHandle *data); static void conn_free(struct connectdata *conn); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); +static CURLcode do_init(struct connectdata *conn); /* * Protocol table. @@ -262,6 +246,7 @@ static const struct Curl_handler Curl_handler_dummy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -270,12 +255,6 @@ static const struct Curl_handler Curl_handler_dummy = { PROTOPT_NONE /* flags */ }; -void Curl_safefree(void *ptr) -{ - if(ptr) - free(ptr); -} - static void close_connections(struct SessionHandle *data) { /* Loop through all open connections and kill them one by one */ @@ -298,10 +277,7 @@ static CURLcode setstropt(char **charp, char * s) /* Release the previous storage at `charp' and replace by a dynamic storage copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ - if(*charp) { - free(*charp); - *charp = (char *) NULL; - } + Curl_safefree(*charp); if(s) { s = strdup(s); @@ -480,6 +456,7 @@ CURLcode Curl_close(struct SessionHandle *data) /* free the connection cache if allocated privately */ Curl_rm_connc(data->state.connc); + data->state.connc = NULL; } } @@ -501,6 +478,8 @@ CURLcode Curl_close(struct SessionHandle *data) /* Free the pathbuffer */ Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; + Curl_safefree(data->state.proto.generic); /* Close down all open SSL info and sessions */ @@ -509,11 +488,17 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_safefree(data->state.scratch); Curl_ssl_free_certinfo(data); - if(data->change.referer_alloc) - free(data->change.referer); + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } + data->change.referer = NULL; - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + data->change.url = NULL; Curl_safefree(data->state.headerbuff); @@ -640,13 +625,19 @@ CURLcode Curl_ch_connc(struct SessionHandle *data, curl_multi_cleanup(). */ void Curl_rm_connc(struct conncache *c) { + if(!c) + return; + if(c->connects) { long i; - for(i = 0; i < c->num; ++i) + for(i = 0; i < c->num; ++i) { conn_free(c->connects[i]); - + c->connects[i] = NULL; + } free(c->connects); + c->connects = NULL; } + c->num = 0; free(c); } @@ -844,7 +835,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, { /* remember we want this enabled */ long use_cache = va_arg(param, long); - data->set.global_dns_cache = (bool)(0 != use_cache); + data->set.global_dns_cache = (0 != use_cache)?TRUE:FALSE; } break; case CURLOPT_SSL_CIPHER_LIST: @@ -880,33 +871,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ - data->set.reuse_forbid = (bool)(0 != va_arg(param, long)); + data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ - data->set.reuse_fresh = (bool)(0 != va_arg(param, long)); + data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ - data->set.verbose = (bool)(0 != va_arg(param, long)); + data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = (bool)(0 != va_arg(param, long)); + data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ - data->set.hide_progress = (bool)(0 != va_arg(param, long)); + data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else @@ -916,14 +907,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = (bool)(0 != va_arg(param, long)); + data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FAILONERROR: /* * Don't output the >=300 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = (bool)(0 != va_arg(param, long)); + data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -931,7 +922,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - data->set.upload = (bool)(0 != va_arg(param, long)); + data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.httpreq = HTTPREQ_PUT; @@ -947,7 +938,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ - data->set.get_filetime = (bool)(0 != va_arg(param, long)); + data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_CREATE_MISSING_DIRS: /* @@ -988,13 +979,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * An option that changes the command to one that asks for a list * only, no file info details. */ - data->set.ftp_list_only = (bool)(0 != va_arg(param, long)); + data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_APPEND: /* * We want to upload and append to an existing file. */ - data->set.ftp_append = (bool)(0 != va_arg(param, long)); + data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_FILEMETHOD: /* @@ -1022,7 +1013,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * * Transfer using ASCII (instead of BINARY). */ - data->set.prefer_ascii = (bool)(0 != va_arg(param, long)); + data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_TIMECONDITION: /* @@ -1051,7 +1042,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = (bool)(0 != va_arg(param, long)); + data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_ACCEPT_ENCODING: @@ -1071,14 +1062,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = (bool)(0 != va_arg(param, long)); + data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on a HTTP-server. */ - data->set.http_follow_location = (bool)(0 != va_arg(param, long)); + data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_UNRESTRICTED_AUTH: @@ -1087,7 +1078,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * hostname changed. */ data->set.http_disable_hostname_check_before_authentication = - (bool)(0 != va_arg(param, long)); + (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_MAXREDIRS: @@ -1109,8 +1100,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * other - POST is kept as POST after 301 and 302 */ long postRedir = va_arg(param, long); - data->set.post301 = (bool)((postRedir & CURL_REDIR_POST_301)?TRUE:FALSE); - data->set.post302 = (bool)((postRedir & CURL_REDIR_POST_302)?TRUE:FALSE); + data->set.post301 = (postRedir & CURL_REDIR_POST_301)?TRUE:FALSE; + data->set.post302 = (postRedir & CURL_REDIR_POST_302)?TRUE:FALSE; } break; @@ -1231,7 +1222,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * String to set in the HTTP Referer: field. */ if(data->change.referer_alloc) { - free(data->change.referer); + Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } result = setstropt(&data->set.str[STRING_SET_REFERER], @@ -1280,10 +1271,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* append the cookie file name to the list of file names, and deal with them later */ cl = curl_slist_append(data->change.cookielist, argptr); - - if(!cl) + if(!cl) { + curl_slist_free_all(data->change.cookielist); + data->change.cookielist = NULL; return CURLE_OUT_OF_MEMORY; - + } data->change.cookielist = cl; /* store the list for later use */ } break; @@ -1319,7 +1311,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We run mostly with the original cookie spec, as hardly anyone implements * anything else. */ - data->set.cookiesession = (bool)(0 != va_arg(param, long)); + data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_COOKIELIST: @@ -1394,8 +1386,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authhost.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE)? - TRUE:FALSE); + data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1404,7 +1395,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* switch off bits we can't support */ #ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ + auth &= ~CURLAUTH_NTLM; /* no NTLM support */ + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#elif !defined(NTLM_WB_ENABLED) + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #endif #ifndef USE_HTTP_NEGOTIATE auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI or @@ -1437,7 +1431,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Tunnel operations through the proxy instead of normal proxy use */ - data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long)); + data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_PROXYPORT: @@ -1456,8 +1450,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* the DIGEST_IE bit is only used to set a special marker, for all the rest we need to handle it as normal DIGEST */ - data->state.authproxy.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE)? - TRUE:FALSE); + data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1465,7 +1458,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, } /* switch off bits we can't support */ #ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ + auth &= ~CURLAUTH_NTLM; /* no NTLM support */ + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ +#elif !defined(NTLM_WB_ENABLED) + auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */ #endif #ifndef USE_HTTP_NEGOTIATE auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI or @@ -1531,7 +1527,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * set flag for nec socks5 support */ - data->set.socks5_gssapi_nec = (bool)(0 != va_arg(param, long)); + data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE; break; #endif @@ -1560,19 +1556,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_FTPPORT], va_arg(param, char *)); - data->set.ftp_use_port = (bool)(NULL != data->set.str[STRING_FTPPORT]); + data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ? + TRUE:FALSE; break; case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_SSL_CCC: @@ -1584,7 +1581,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the * bypass of the IP address in PASV responses. */ - data->set.ftp_skip_ip = (bool)(0 != va_arg(param, long)); + data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_INFILE: @@ -1642,8 +1639,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ if(data->change.url_alloc) { /* the already set URL is allocated, free it first! */ - free(data->change.url); - data->change.url_alloc=FALSE; + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; } result = setstropt(&data->set.str[STRING_SET_URL], va_arg(param, char *)); @@ -1954,7 +1951,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Kludgy option to enable CRLF conversions. Subject for removal. */ - data->set.crlf = (bool)(0 != va_arg(param, long)); + data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_INTERFACE: @@ -1983,7 +1980,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_KRB_LEVEL], va_arg(param, char *)); - data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]); + data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE; + break; + case CURLOPT_GSSAPI_DELEGATION: + /* + * GSSAPI credential delegation + */ + data->set.gssapi_delegation = va_arg(param, long); break; case CURLOPT_SSL_VERIFYPEER: /* @@ -2015,7 +2018,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ssl.fsslctxp = va_arg(param, void *); break; case CURLOPT_CERTINFO: - data->set.ssl.certinfo = (bool)(0 != va_arg(param, long)); + data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE; break; #endif case CURLOPT_CAINFO: @@ -2075,7 +2078,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ - data->set.no_signal = (bool)(0 != va_arg(param, long)); + data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_SHARE: @@ -2092,8 +2095,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->dns.hostcachetype = HCACHE_NONE; } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies == data->cookies) data->cookies = NULL; +#endif + + if(data->share->sslsession == data->state.session) { + data->state.session = NULL; + data->set.ssl.numsessions = 0; + } data->share->dirty--; @@ -2126,6 +2136,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->cookies = data->share->cookies; } #endif /* CURL_DISABLE_HTTP */ + if(data->share->sslsession) { + data->set.ssl.numsessions = data->share->nsslsession; + data->state.session = data->share->sslsession; + } Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } @@ -2179,7 +2193,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable TCP_NODELAY, which will disable/enable the Nagle * algorithm */ - data->set.tcp_nodelay = (bool)(0 != va_arg(param, long)); + data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_ACCOUNT: @@ -2188,14 +2202,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (bool)(0 != va_arg(param, long)); + data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CONNECT_ONLY: /* * No data transfer, set up connection and let application use the socket */ - data->set.connect_only = (bool)(0 != va_arg(param, long)); + data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: @@ -2248,7 +2262,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (bool)(0 != va_arg(param, long)); + data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE; break; #ifdef USE_LIBSSH2 @@ -2309,14 +2323,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * disable libcurl transfer encoding is used */ - data->set.http_te_skip = (bool)(0 == va_arg(param, long)); + data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HTTP_CONTENT_DECODING: /* * raw data passed to the application when content encoding is used */ - data->set.http_ce_skip = (bool)(0 == va_arg(param, long)); + data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_NEW_FILE_PERMS: @@ -2478,7 +2492,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_WILDCARDMATCH: - data->set.wildcardmatch = (bool)(0 != va_arg(param, long)); + data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CHUNK_BGN_FUNCTION: data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); @@ -2543,6 +2557,10 @@ static void conn_free(struct connectdata *conn) if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) Curl_closesocket(conn, conn->sock[FIRSTSOCKET]); +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); +#endif + Curl_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->proxyuser); @@ -2567,6 +2585,11 @@ static void conn_free(struct connectdata *conn) Curl_llist_destroy(conn->pend_pipe, NULL); Curl_llist_destroy(conn->done_pipe, NULL); + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + conn->pend_pipe = NULL; + conn->done_pipe = NULL; + Curl_safefree(conn->localdev); Curl_free_ssl_config(&conn->ssl_config); @@ -2621,7 +2644,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) if(has_host_ntlm || has_proxy_ntlm) { data->state.authproblem = FALSE; - Curl_ntlm_cleanup(conn); + Curl_http_ntlm_cleanup(conn); } } @@ -2773,11 +2796,11 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) void Curl_getoff_all_pipelines(struct SessionHandle *data, struct connectdata *conn) { - bool recv_head = (bool)(conn->readchannel_inuse && - (gethandleathead(conn->recv_pipe) == data)); + bool recv_head = (conn->readchannel_inuse && + (gethandleathead(conn->recv_pipe) == data)) ? TRUE : FALSE; - bool send_head = (bool)(conn->writechannel_inuse && - (gethandleathead(conn->send_pipe) == data)); + bool send_head = (conn->writechannel_inuse && + (gethandleathead(conn->send_pipe) == data)) ? TRUE : FALSE; if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head) conn->readchannel_inuse = FALSE; @@ -3002,7 +3025,8 @@ ConnectionExists(struct SessionHandle *data, } if((needle->handler->protocol & CURLPROTO_FTP) || ((needle->handler->protocol & CURLPROTO_HTTP) && - (data->state.authhost.want==CURLAUTH_NTLM))) { + ((data->state.authhost.want==CURLAUTH_NTLM) || + (data->state.authhost.want==CURLAUTH_NTLM_WB)))) { /* This is FTP or HTTP+NTLM, verify that we're using the same name and password as well */ if(!strequal(needle->user, check->user) || @@ -3203,8 +3227,13 @@ static CURLcode ConnectPlease(struct SessionHandle *data, /* All is cool, we store the current information */ conn->ip_addr = addr; - if(*connected) + if(*connected) { result = Curl_connected_proxy(conn); + if(!result) { + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + } + } } if(result) @@ -3297,7 +3326,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, *protocol_done = FALSE; - if(conn->bits.tcpconnect && conn->bits.protoconnstart) { + if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) { /* We already are connected, get back. This may happen when the connect worked fine in the first call, like when we connect to a local server or proxy. Note that we don't know if the protocol is actually done. @@ -3310,7 +3339,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, return CURLE_OK; } - if(!conn->bits.tcpconnect) { + if(!conn->bits.tcpconnect[FIRSTSOCKET]) { Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_verboseconnect(conn); @@ -3504,18 +3533,20 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) #else /* CURL_DISABLE_PROXY */ - conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] && - *data->set.str[STRING_PROXY]); - conn->bits.httpproxy = (bool)(conn->bits.proxy && - (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0)); + /* note that these two proxy bits are now just on what looks to be + requested, they may be altered down the road */ + conn->bits.proxy = (data->set.str[STRING_PROXY] && + *data->set.str[STRING_PROXY])?TRUE:FALSE; + conn->bits.httpproxy = (conn->bits.proxy && + (conn->proxytype == CURLPROXY_HTTP || + conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE; conn->bits.proxy_user_passwd = - (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]); + (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ - conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]); + conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; @@ -3524,6 +3555,13 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->ip_version = data->set.ipver; +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + conn->ntlm_auth_hlpr_pid = 0; + conn->challenge_header = NULL; + conn->response_header = NULL; +#endif + if(data->multi && Curl_multi_canPipeline(data->multi) && !conn->master_buffer) { /* Allocate master_buffer to be used for pipelining */ @@ -3566,6 +3604,12 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) Curl_llist_destroy(conn->recv_pipe, NULL); Curl_llist_destroy(conn->pend_pipe, NULL); Curl_llist_destroy(conn->done_pipe, NULL); + + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + conn->pend_pipe = NULL; + conn->done_pipe = NULL; + Curl_safefree(conn->master_buffer); Curl_safefree(conn->localdev); Curl_safefree(conn); @@ -3852,7 +3896,7 @@ static CURLcode setup_range(struct SessionHandle *data) else s->range = strdup(data->set.str[STRING_SET_RANGE]); - s->rangestringalloc = (bool)(s->range?TRUE:FALSE); + s->rangestringalloc = (s->range)?TRUE:FALSE; if(!s->range) return CURLE_OUT_OF_MEMORY; @@ -4392,8 +4436,10 @@ static CURLcode parse_remote_port(struct SessionHandle *data, if(!url) return CURLE_OUT_OF_MEMORY; - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = url; data->change.url_alloc = TRUE; @@ -4617,11 +4663,12 @@ static void reuse_conn(struct connectdata *old_conn, /* host can change, when doing keepalive with a proxy ! */ if(conn->bits.proxy) { - free(conn->host.rawalloc); + Curl_safefree(conn->host.rawalloc); conn->host=old_conn->host; } else - free(old_conn->host.rawalloc); /* free the newly allocated name buffer */ + /* free the newly allocated name buffer */ + Curl_safefree(old_conn->host.rawalloc); /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -4633,10 +4680,17 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->passwd); Curl_safefree(old_conn->proxyuser); Curl_safefree(old_conn->proxypasswd); + Curl_llist_destroy(old_conn->send_pipe, NULL); Curl_llist_destroy(old_conn->recv_pipe, NULL); Curl_llist_destroy(old_conn->pend_pipe, NULL); Curl_llist_destroy(old_conn->done_pipe, NULL); + + old_conn->send_pipe = NULL; + old_conn->recv_pipe = NULL; + old_conn->pend_pipe = NULL; + old_conn->done_pipe = NULL; + Curl_safefree(old_conn->master_buffer); } @@ -4713,14 +4767,19 @@ static CURLcode create_conn(struct SessionHandle *data, */ Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; + data->state.pathbuffer = malloc(urllen+2); if(NULL == data->state.pathbuffer) return CURLE_OUT_OF_MEMORY; /* really bad error */ data->state.path = data->state.pathbuffer; conn->host.rawalloc = malloc(urllen+2); - if(NULL == conn->host.rawalloc) + if(NULL == conn->host.rawalloc) { + Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; return CURLE_OUT_OF_MEMORY; + } conn->host.name = conn->host.rawalloc; conn->host.name[0] = 0; @@ -4745,6 +4804,11 @@ static CURLcode create_conn(struct SessionHandle *data, return CURLE_OUT_OF_MEMORY; } + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + data->change.url = reurl; data->change.url_alloc = TRUE; /* free this later */ } @@ -4821,6 +4885,8 @@ static CURLcode create_conn(struct SessionHandle *data, conn->bits.httpproxy = TRUE; #endif } + else + conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ conn->bits.proxy = TRUE; } else { @@ -4862,7 +4928,7 @@ static CURLcode create_conn(struct SessionHandle *data, /* Setup a "faked" transfer that'll do nothing */ if(CURLE_OK == result) { conn->data = data; - conn->bits.tcpconnect = TRUE; /* we are "connected */ + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ ConnectionStore(data, conn); @@ -4970,6 +5036,9 @@ static CURLcode create_conn(struct SessionHandle *data, ConnectionStore(data, conn); } + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + do_init(conn); + /* * Setup whatever necessary for a resumed transfer */ @@ -5007,7 +5076,7 @@ static CURLcode create_conn(struct SessionHandle *data, CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; Curl_pgrsTime(data, TIMER_NAMELOOKUP); @@ -5053,13 +5122,19 @@ CURLcode Curl_setup_conn(struct connectdata *conn, result = ConnectPlease(data, conn, &connected); + if(result && !conn->ip_addr) { + /* transport connection failure not related with authentication */ + conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; + return result; + } + if(connected) { result = Curl_protocol_connect(conn, protocol_done); if(CURLE_OK == result) - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; } else - conn->bits.tcpconnect = FALSE; + conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; /* if the connection was closed by the server while exchanging authentication informations, retry with the new set @@ -5078,7 +5153,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn, else { Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; *protocol_done = TRUE; Curl_verboseconnect(conn); Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]); @@ -5316,9 +5391,6 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) struct connectdata *conn = *connp; struct SessionHandle *data = conn->data; - /* setup and init stuff before DO starts, in preparing for the transfer */ - do_init(conn); - if(conn->handler->do_it) { /* generic protocol-specific function pointer set in curl_connect() */ result = conn->handler->do_it(conn, done); @@ -1,5 +1,5 @@ -#ifndef __URL_H -#define __URL_H +#ifndef HEADER_CURL_URL_H +#define HEADER_CURL_URL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,8 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include <stdarg.h> /* to make sure we have ap_list */ +#include "setup.h" /* * Prototypes for library-wide functions provided by url.c @@ -44,7 +43,6 @@ 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); CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); -void Curl_safefree(void *ptr); CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done); @@ -88,10 +86,10 @@ void Curl_reset_reqproto(struct connectdata *conn); CURLcode Curl_connected_proxy(struct connectdata *conn); #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define Curl_verboseconnect(x) do { } while (0) +#define Curl_verboseconnect(x) Curl_nop_stmt #else void Curl_verboseconnect(struct connectdata *conn); #endif -#endif +#endif /* HEADER_CURL_URL_H */ diff --git a/lib/urldata.h b/lib/urldata.h index d256968db..5b3dc059e 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -273,6 +273,7 @@ struct ssl_connect_data { struct SessionHandle *data; #ifdef HAVE_PK11_CREATEGENERICOBJECT struct curl_llist *obj_list; + PK11GenericObject *obj_clicert; #endif #endif /* USE_NSS */ #ifdef USE_QSOSSL @@ -360,7 +361,7 @@ struct ntlmdata { SEC_WINNT_AUTH_IDENTITY *p_identity; int has_handles; void *type_2; - int n_type_2; + unsigned long n_type_2; #else unsigned int flags; unsigned char nonce[8]; @@ -411,7 +412,7 @@ struct ConnectBits { bool do_more; /* this is set TRUE if the ->curl_do_more() function is supposed to be called, after ->curl_do() */ - bool tcpconnect; /* the TCP layer (or similar) is connected, this is set + bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set the first time on the first connect function call */ bool protoconnstart;/* the protocol layer has STARTED its operation after the TCP layer connect */ @@ -670,6 +671,12 @@ struct Curl_handler { curl_socket_t *socks, int numsocks); + /* Called from the multi interface during the DO_MORE phase, and it should + then return a proper fd set */ + int (*domore_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + /* Called from the multi interface during the DO_DONE, PERFORM and WAITPERFORM phases, and it should then return a proper fd set. Not setting this will make libcurl use the generic default one. */ @@ -905,6 +912,14 @@ struct connectdata { single requests! */ struct ntlmdata proxyntlm; /* NTLM data for proxy */ +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + /* used for communication with Samba's winbind daemon helper ntlm_auth */ + curl_socket_t ntlm_auth_hlpr_socket; + pid_t ntlm_auth_hlpr_pid; + char* challenge_header; + char* response_header; +#endif + char syserr_buf [256]; /* buffer for Curl_strerror() */ #ifdef CURLRES_ASYNCH @@ -1517,6 +1532,9 @@ struct UserDefined { curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds to pattern (e.g. if WILDCARDMATCH is on) */ void *fnmatch_data; + + long gssapi_delegation; /* GSSAPI credential delegation, see the + documentation of CURLOPT_GSSAPI_DELEGATION */ }; struct Names { diff --git a/lib/version.c b/lib/version.c index c471dc106..c56ad3962 100644 --- a/lib/version.c +++ b/lib/version.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <stdio.h> - #include <curl/curl.h> #include "urldata.h" #include "sslgen.h" @@ -243,6 +240,9 @@ static curl_version_info_data version_info = { #ifdef USE_NTLM | CURL_VERSION_NTLM #endif +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + | CURL_VERSION_NTLM_WB +#endif #ifdef USE_WINDOWS_SSPI | CURL_VERSION_SSPI #endif diff --git a/lib/warnless.c b/lib/warnless.c index 37d15ce87..0f5fb5f4d 100644 --- a/lib/warnless.c +++ b/lib/warnless.c @@ -268,6 +268,25 @@ size_t curlx_sotouz(curl_off_t sonum) #endif } +/* +** signed int to unsigned size_t +*/ + +size_t curlx_sitouz(int sinum) +{ +#ifdef __INTEL_COMPILER +# pragma warning(push) +# pragma warning(disable:810) /* conversion may lose significant bits */ +#endif + + DEBUGASSERT(sinum >= 0); + return (size_t) sinum; + +#ifdef __INTEL_COMPILER +# pragma warning(pop) +#endif +} + #if defined(__INTEL_COMPILER) && defined(__unix__) int curlx_FD_ISSET(int fd, fd_set *fdset) diff --git a/lib/warnless.h b/lib/warnless.h index 9ac59ac29..27cf57c31 100644 --- a/lib/warnless.h +++ b/lib/warnless.h @@ -38,6 +38,8 @@ ssize_t curlx_uztosz(size_t uznum); size_t curlx_sotouz(curl_off_t sonum); +size_t curlx_sitouz(int sinum); + #if defined(__INTEL_COMPILER) && defined(__unix__) int curlx_FD_ISSET(int fd, fd_set *fdset); diff --git a/lib/wildcard.c b/lib/wildcard.c index 9fe5d5135..6f4c7380c 100644 --- a/lib/wildcard.c +++ b/lib/wildcard.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include "wildcard.h" #include "llist.h" #include "fileinfo.h" |