From 55f3eb588d224d74dc450dd0e9f836757deae685 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 9 Jun 2015 23:57:22 +0200 Subject: INTERNALS: cat lib/README* >> INTERNALS and a conversion to markdown. Removed the lib/README.* files. The idea being to move toward having INTERNALS as the one and only "book" of internals documentation. Added a TOC to top of the document. --- lib/Makefile.am | 5 +--- lib/README.ares | 69 --------------------------------------------- lib/README.curl_off_t | 68 --------------------------------------------- lib/README.curlx | 61 ---------------------------------------- lib/README.encoding | 60 --------------------------------------- lib/README.hostip | 35 ----------------------- lib/README.httpauth | 74 ------------------------------------------------- lib/README.memoryleak | 55 ------------------------------------ lib/README.multi_socket | 53 ----------------------------------- 9 files changed, 1 insertion(+), 479 deletions(-) delete mode 100644 lib/README.ares delete mode 100644 lib/README.curl_off_t delete mode 100644 lib/README.curlx delete mode 100644 lib/README.encoding delete mode 100644 lib/README.hostip delete mode 100644 lib/README.httpauth delete mode 100644 lib/README.memoryleak delete mode 100644 lib/README.multi_socket (limited to 'lib') diff --git a/lib/Makefile.am b/lib/Makefile.am index 1bef388df..a2c3dc56c 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -21,9 +21,6 @@ ########################################################################### AUTOMAKE_OPTIONS = foreign nostdinc -DOCS = README.encoding README.memoryleak README.ares README.curlx \ - README.hostip README.multi_socket README.httpauth README.curl_off_t - CMAKE_DIST = CMakeLists.txt curl_config.h.cmake EXTRA_DIST = Makefile.b32 Makefile.m32 Makefile.vc6 config-win32.h \ @@ -31,7 +28,7 @@ EXTRA_DIST = Makefile.b32 Makefile.m32 Makefile.vc6 config-win32.h \ makefile.dj config-dos.h libcurl.plist libcurl.rc config-amigaos.h \ makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \ config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \ - config-tpf.h $(DOCS) mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ + config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \ firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \ objnames-test08.sh objnames-test10.sh objnames.inc checksrc.whitelist diff --git a/lib/README.ares b/lib/README.ares deleted file mode 100644 index 8c77937eb..000000000 --- a/lib/README.ares +++ /dev/null @@ -1,69 +0,0 @@ - _ _ ____ _ - ___| | | | _ \| | - / __| | | | |_) | | - | (__| |_| | _ <| |___ - \___|\___/|_| \_\_____| - - How To Build libcurl to Use c-ares For Asynch Name Resolves - =========================================================== - -c-ares: - http://c-ares.haxx.se/ - -NOTE - The latest libcurl version requires c-ares 1.6.0 or later. - - Once upon the time libcurl built fine with the "original" ares. That is no - longer true. You need to use c-ares. - -Build c-ares -============ - -1. unpack the c-ares archive -2. cd c-ares-dir -3. ./configure -4. make -5. make install - -Build libcurl to use c-ares in the curl source tree -=================================================== - -1. name or symlink the c-ares source directory 'ares' in the curl source - directory -2. ./configure --enable-ares - - Optionally, you can point out the c-ares install tree root with the the - --enable-ares option. - -3. make - -Build libcurl to use an installed c-ares -======================================== - -1. ./configure --enable-ares=/path/to/ares/install -2. make - -c-ares on win32 -=============== -(description brought by Dominick Meglio) - -First I compiled c-ares. I changed the default C runtime library to be the -single-threaded rather than the multi-threaded (this seems to be required to -prevent linking errors later on). Then I simply build the areslib project (the -other projects adig/ahost seem to fail under MSVC). - -Next was libcurl. I opened lib/config-win32.h and I added a: - #define USE_ARES 1 - -Next thing I did was I added the path for the ares includes to the include -path, and the libares.lib to the libraries. - -Lastly, I also changed libcurl to be single-threaded rather than -multi-threaded, again this was to prevent some duplicate symbol errors. I'm -not sure why I needed to change everything to single-threaded, but when I -didn't I got redefinition errors for several CRT functions (malloc, stricmp, -etc.) - -I would have modified the MSVC++ project files, but I only have VC.NET and it -uses a different format than VC6.0 so I didn't want to go and change -everything and remove VC6.0 support from libcurl. diff --git a/lib/README.curl_off_t b/lib/README.curl_off_t deleted file mode 100644 index 923b2774c..000000000 --- a/lib/README.curl_off_t +++ /dev/null @@ -1,68 +0,0 @@ - - curl_off_t explained - ==================== - -curl_off_t is a data type provided by the external libcurl include headers. It -is the type meant to be used for the curl_easy_setopt() options that end with -LARGE. The type is 64bit large on most modern platforms. - -Transition from < 7.19.0 to >= 7.19.0 -------------------------------------- - -Applications that used libcurl before 7.19.0 that are rebuilt with a libcurl -that is 7.19.0 or later may or may not have to worry about anything of -this. We have made a significant effort to make the transition really seamless -and transparent. - -You have have to take notice if you are in one of the following situations: - -o Your app is using or will after the transition use a libcurl that is built - with LFS (large file support) disabled even though your system otherwise - supports it. - -o Your app is using or will after the transition use a libcurl that doesn't - support LFS at all, but your system and compiler support 64bit data types. - -In both these cases, the curl_off_t type will now (after the transition) be -64bit where it previously was 32bit. This will cause a binary incompatibility -that you MAY need to deal with. - -Benefits --------- - -This new way has several benefits: - -o Platforms without LFS support can still use libcurl to do >32 bit file - transfers and range operations etc as long as they have >32 bit data-types - supported. - -o Applications will no longer easily build with the curl_off_t size - mismatched, which has been a very frequent (and annoying) problem with - libcurl <= 7.18.2 - -Historically ------------- - -Previously, before 7.19.0, the curl_off_t type would be rather strongly -connected to the size of the system off_t type, where currently curl_off_t is -independent of that. - -The strong connection to off_t made it troublesome for application authors -since when they did mistakes, they could get curl_off_t type of different -sizes in the app vs libcurl, and that caused strange effects that were hard to -track and detect by users of libcurl. - -SONAME ------- - -We opted to not bump the soname for the library unconditionally, simply -because soname bumping is causing a lot of grief and moaning all over the -community so we try to keep that at minimum. Also, our selected design path -should be 100% backwards compatible for the vast majority of all libcurl -users. - -Enforce SONAME bump -------------------- - -If configure doesn't detect your case where a bump is necessary, re-run it -with the --enable-soname-bump command line option! diff --git a/lib/README.curlx b/lib/README.curlx deleted file mode 100644 index 5375b0d1d..000000000 --- a/lib/README.curlx +++ /dev/null @@ -1,61 +0,0 @@ - _ _ ____ _ - ___| | | | _ \| | - / __| | | | |_) | | - | (__| |_| | _ <| |___ - \___|\___/|_| \_\_____| - - Source Code Functions Apps Might Use - ==================================== - -The libcurl source code offers a few functions by source only. They are not -part of the official libcurl API, but the source files might be useful for -others so apps can optionally compile/build with these sources to gain -additional functions. - -We provide them through a single header file for easy access for apps: -"curlx.h" - - curlx_strtoofft() - - A macro that converts a string containing a number to a curl_off_t number. - This might use the curlx_strtoll() function which is provided as source - code in strtoofft.c. Note that the function is only provided if no - strtoll() (or equivalent) function exist on your platform. If curl_off_t - is only a 32 bit number on your platform, this macro uses strtol(). - - curlx_tvnow() - - returns a struct timeval for the current time. - - curlx_tvdiff() - - returns the difference between two timeval structs, in number of - milliseconds. - - curlx_tvdiff_secs() - - returns the same as curlx_tvdiff but with full usec resolution (as a - double) - -FUTURE -====== - - Several functions will be removed from the public curl_ name space in a - future libcurl release. They will then only become available as curlx_ - functions instead. To make the transition easier, we already today provide - these functions with the curlx_ prefix to allow sources to get built properly - with the new function names. The functions this concerns are: - - curlx_getenv - curlx_strequal - curlx_strnequal - curlx_mvsnprintf - curlx_msnprintf - curlx_maprintf - curlx_mvaprintf - curlx_msprintf - curlx_mprintf - curlx_mfprintf - curlx_mvsprintf - curlx_mvprintf - curlx_mvfprintf diff --git a/lib/README.encoding b/lib/README.encoding deleted file mode 100644 index 1012bb9ec..000000000 --- a/lib/README.encoding +++ /dev/null @@ -1,60 +0,0 @@ - - Content Encoding Support for libcurl - -* About content encodings: - -HTTP/1.1 [RFC 2616] specifies that a client may request that a server encode -its response. This is usually used to compress a response using one of a set -of commonly available compression techniques. These schemes are `deflate' (the -zlib algorithm), `gzip' and `compress' [sec 3.5, RFC 2616]. A client requests -that the sever perform an encoding by including an Accept-Encoding header in -the request document. The value of the header should be one of the recognized -tokens `deflate', ... (there's a way to register new schemes/tokens, see sec -3.5 of the spec). A server MAY honor the client's encoding request. When a -response is encoded, the server includes a Content-Encoding header in the -response. The value of the Content-Encoding header indicates which scheme was -used to encode the data. - -A client may tell a server that it can understand several different encoding -schemes. In this case the server may choose any one of those and use it to -encode the response (indicating which one using the Content-Encoding header). -It's also possible for a client to attach priorities to different schemes so -that the server knows which it prefers. See sec 14.3 of RFC 2616 for more -information on the Accept-Encoding header. - -* Current support for content encoding: - -Support for the 'deflate' and 'gzip' content encoding are supported by -libcurl. Both regular and chunked transfers should work fine. The library -zlib is required for this feature. 'deflate' support was added by James -Gallagher, and support for the 'gzip' encoding was added by Dan Fandrich. - -* The libcurl interface: - -To cause libcurl to request a content encoding use: - - curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ) - -where is the intended value of the Accept-Encoding header. - -Currently, libcurl only understands how to process responses that use the -"deflate" or "gzip" Content-Encoding, so the only values for -CURLOPT_ACCEPT_ENCODING that will work (besides "identity," which does -nothing) are "deflate" and "gzip" If a response is encoded using the -"compress" or methods, libcurl will return an error indicating that the -response could not be decoded. If is NULL no Accept-Encoding header -is generated. If is a zero-length string, then an Accept-Encoding -header containing all supported encodings will be generated. - -The CURLOPT_ACCEPT_ENCODING must be set to any non-NULL value for content to -be automatically decoded. If it is not set and the server still sends encoded -content (despite not having been asked), the data is returned in its raw form -and the Content-Encoding type is not checked. - -* The curl interface: - -Use the --compressed option with curl to cause it to ask servers to compress -responses using any format supported by curl. - -James Gallagher -Dan Fandrich diff --git a/lib/README.hostip b/lib/README.hostip deleted file mode 100644 index d5688fff1..000000000 --- a/lib/README.hostip +++ /dev/null @@ -1,35 +0,0 @@ - hostip.c explained - ================== - - The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c - source file are these: - - CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use - that. The host may not be able to resolve IPv6, but we don't really have to - take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4 - defined. - - CURLRES_ARES - is defined if libcurl is built to use c-ares for asynchronous - name resolves. This can be Windows or *nix. - - CURLRES_THREADED - is defined if libcurl is built to use threading for - asynchronous name resolves. The name resolve will be done in a new thread, - and the supported asynch API will be the same as for ares-builds. This is - the default under (native) Windows. - - If any of the two previous are defined, CURLRES_ASYNCH is defined too. If - libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is - defined. - - The host*.c sources files are split up like this: - - hostip.c - method-independent resolver functions and utility functions - hostasyn.c - functions for asynchronous name resolves - hostsyn.c - functions for synchronous name resolves - asyn-ares.c - functions for asynchronous name resolves using c-ares - asyn-thread.c - functions for asynchronous name resolves using threads - hostip4.c - IPv4 specific functions - hostip6.c - IPv6 specific functions - - The hostip.h is the single united header file for all this. It defines the - CURLRES_* defines based on the config*.h and curl_setup.h defines. diff --git a/lib/README.httpauth b/lib/README.httpauth deleted file mode 100644 index 960504510..000000000 --- a/lib/README.httpauth +++ /dev/null @@ -1,74 +0,0 @@ - -1. PUT/POST without a known auth to use (possibly no auth required): - - (When explicitly set to use a multi-pass auth when doing a POST/PUT, - libcurl should immediately go the Content-Length: 0 bytes route to avoid - the first send all data phase, step 2. If told to use a single-pass auth, - goto step 3.) - - Issue the proper PUT/POST request immediately, with the correct - Content-Length and Expect: headers. - - If a 100 response is received or the wait for one times out, start sending - the request-body. - - If a 401 (or 407 when talking through a proxy) is received, then: - - If we have "more than just a little" data left to send, close the - connection. Exactly what "more than just a little" means will have to be - determined. Possibly the current transfer speed should be taken into - account as well. - - NOTE: if the size of the POST data is less than MAX_INITIAL_POST_SIZE (when - CURLOPT_POSTFIELDS is used), libcurl will send everything in one single - write() (all request-headers and request-body) and thus it will - unconditionally send the full post data here. - -2. PUT/POST with multi-pass auth but not yet completely negotiated: - - Send a PUT/POST request, we know that it will be rejected and thus we claim - Content-Length zero to avoid having to send the request-body. (This seems - to be what IE does.) - -3. PUT/POST as the last step in the auth negotiation, that is when we have - what we believe is a completed negotiation: - - Send a full and proper PUT/POST request (again) with the proper - Content-Length and a following request-body. - - NOTE: this may very well be the second (or even third) time the whole or at - least parts of the request body is sent to the server. Since the data may - be provided to libcurl with a callback, we need a way to tell the app that - the upload is to be restarted so that the callback will provide data from - the start again. This requires an API method/mechanism that libcurl - doesn't have today. See below. - -Data Rewind - - It will be troublesome for some apps to deal with a rewind like this in all - circumstances. I'm thinking for example when using 'curl' to upload data - from stdin. If libcurl ends up having to rewind the reading for a request - to succeed, of course a lack of this callback or if it returns failure, will - cause the request to fail completely. - - The new callback is set with CURLOPT_IOCTLFUNCTION (in an attempt to add a - more generic function that might be used for other IO-related controls in - the future): - - curlioerr curl_ioctl(CURL *handle, curliocmd cmd, void *clientp); - - And in the case where the read is to be rewinded, it would be called with a - cmd named CURLIOCMD_RESTARTREAD. The callback would then return CURLIOE_OK, - if things are fine, or CURLIOE_FAILRESTART if not. - -Backwards Compatibility - - The approach used until now, that issues a HEAD on the given URL to trigger - the auth negotiation could still be supported and encouraged, but it would - be up to the app to first fetch a URL with GET/HEAD to negotiate on, since - then a following PUT/POST wouldn't need to negotiate authentication and - thus avoid double-sending data. - - Optionally, we keep the current approach if some option is set - (CURLOPT_HEADBEFOREAUTH or similar), since it seems to work fairly well for - POST on most servers. diff --git a/lib/README.memoryleak b/lib/README.memoryleak deleted file mode 100644 index 166177794..000000000 --- a/lib/README.memoryleak +++ /dev/null @@ -1,55 +0,0 @@ - _ _ ____ _ - ___| | | | _ \| | - / __| | | | |_) | | - | (__| |_| | _ <| |___ - \___|\___/|_| \_\_____| - - How To Track Down Suspected Memory Leaks in libcurl - =================================================== - -Single-threaded - - Please note that this memory leak system is not adjusted to work in more - than one thread. If you want/need to use it in a multi-threaded app. Please - adjust accordingly. - - -Build - - Rebuild libcurl with -DCURLDEBUG (usually, rerunning configure with - --enable-debug fixes this). 'make clean' first, then 'make' so that all - files actually are rebuilt properly. It will also make sense to build - libcurl with the debug option (usually -g to the compiler) so that debugging - it will be easier if you actually do find a leak in the library. - - This will create a library that has memory debugging enabled. - -Modify Your Application - - Add a line in your application code: - - curl_memdebug("dump"); - - This will make the malloc debug system output a full trace of all resource - using functions to the given file name. Make sure you rebuild your program - and that you link with the same libcurl you built for this purpose as - described above. - -Run Your Application - - Run your program as usual. Watch the specified memory trace file grow. - - Make your program exit and use the proper libcurl cleanup functions etc. So - that all non-leaks are returned/freed properly. - -Analyze the Flow - - Use the tests/memanalyze.pl perl script to analyze the dump file: - - tests/memanalyze.pl dump - - This now outputs a report on what resources that were allocated but never - freed etc. This report is very fine for posting to the list! - - If this doesn't produce any output, no leak was detected in libcurl. Then - the leak is mostly likely to be in your code. diff --git a/lib/README.multi_socket b/lib/README.multi_socket deleted file mode 100644 index d91e1d9f2..000000000 --- a/lib/README.multi_socket +++ /dev/null @@ -1,53 +0,0 @@ -Implementation of the curl_multi_socket API - - The main ideas of the new API are simply: - - 1 - The application can use whatever event system it likes as it gets info - from libcurl about what file descriptors libcurl waits for what action - on. (The previous API returns fd_sets which is very select()-centric). - - 2 - When the application discovers action on a single socket, it calls - libcurl and informs that there was action on this particular socket and - libcurl can then act on that socket/transfer only and not care about - any other transfers. (The previous API always had to scan through all - the existing transfers.) - - The idea is that curl_multi_socket_action() calls a given callback with - information about what socket to wait for what action on, and the callback - only gets called if the status of that socket has changed. - - We also added a timer callback that makes libcurl call the application when - the timeout value changes, and you set that with curl_multi_setopt() and the - CURLMOPT_TIMERFUNCTION option. To get this to work, Internally, there's an - added a struct to each easy handle in which we store an "expire time" (if - any). The structs are then "splay sorted" so that we can add and remove - times from the linked list and yet somewhat swiftly figure out both how long - time there is until the next nearest timer expires and which timer (handle) - we should take care of now. Of course, the upside of all this is that we get - a curl_multi_timeout() that should also work with old-style applications - that use curl_multi_perform(). - - We created an internal "socket to easy handles" hash table that given - a socket (file descriptor) return the easy handle that waits for action on - that socket. This hash is made using the already existing hash code - (previously only used for the DNS cache). - - To make libcurl able to report plain sockets in the socket callback, we had - to re-organize the internals of the curl_multi_fdset() etc so that the - conversion from sockets to fd_sets for that function is only done in the - last step before the data is returned. I also had to extend c-ares to get a - function that can return plain sockets, as that library too returned only - fd_sets and that is no longer good enough. The changes done to c-ares are - available in c-ares 1.3.1 and later. - - We have done a test runs with up to 9000 connections (with a single active - one). The curl_multi_socket_action() invoke then takes less than 10 - microseconds in average (using the read-only-1-byte-at-a-time hack). We are - now below the 60 microseconds "per socket action" goal (the extra 50 is the - time libevent needs). - -Documentation - - http://curl.haxx.se/libcurl/c/curl_multi_socket_action.html - http://curl.haxx.se/libcurl/c/curl_multi_timeout.html - http://curl.haxx.se/libcurl/c/curl_multi_setopt.html -- cgit v1.2.1 From 8d0d688296b138954b70889cb34ae290d0890b1c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 10 Jun 2015 23:16:17 +0200 Subject: debug: remove http2 debug leftovers --- lib/multi.c | 3 --- lib/transfer.c | 3 --- 2 files changed, 6 deletions(-) (limited to 'lib') diff --git a/lib/multi.c b/lib/multi.c index fcef2e10f..2956022e4 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -1509,9 +1509,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; } - DEBUGF(infof(data, "multi_runsingle:%d call Curl_readwrite\n", - __LINE__)); - /* read/write data if it is ready to do so */ result = Curl_readwrite(data->easy_conn, data, &done); diff --git a/lib/transfer.c b/lib/transfer.c index 42d38b51a..28cc61ecc 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1053,9 +1053,6 @@ CURLcode Curl_readwrite(struct connectdata *conn, return CURLE_SEND_ERROR; } - DEBUGF(infof(data, "Curl_readwrite: keepon: %x select_res %x\n", k->keepon, - select_res)); - /* We go ahead and do a read if we have a readable socket or if the stream was rewound (in which case we have data in a buffer) */ -- cgit v1.2.1 From a3e5a4371b43a68a19e6d73d050846c2f9a20859 Mon Sep 17 00:00:00 2001 From: Joel Depooter Date: Thu, 11 Jun 2015 15:52:25 -0400 Subject: schannel: Add support for optional client certificates Some servers will request a client certificate, but not require one. This change allows libcurl to connect to such servers when using schannel as its ssl/tls backend. When a server requests a client certificate, libcurl will now continue the handshake without one, rather than terminating the handshake. The server can then decide if that is acceptable or not. Prior to this change, libcurl would terminate the handshake, reporting a SEC_I_INCOMPLETE_CREDENTIALS error. --- lib/vtls/schannel.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib') diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index b02e42ecc..543c20657 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -403,6 +403,17 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) return CURLE_OK; } + /* If the server has requested a client certificate, attempt to continue + the handshake without one. This will allow connections to servers which + request a client certificate but do not require it. */ + if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS && + !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) { + connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS; + connssl->connecting_state = ssl_connect_2_writing; + infof(data, "schannel: a client certificate has been requested\n"); + return CURLE_OK; + } + /* check if the handshake needs to be continued */ if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) { for(i = 0; i < 3; i++) { -- cgit v1.2.1 From ff7097f72c26a9d389f135f76cb28e10ca30f4c1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 7 Jun 2015 23:52:34 +0200 Subject: urldata: store POST size in state.infilesize too ... to simplify checking when PUT _or_ POST have completed. Reported-by: Frank Meier Bug: http://curl.haxx.se/mail/lib-2015-06/0019.html --- lib/http.c | 10 +++++----- lib/multi.c | 5 ++++- lib/rtsp.c | 4 ++-- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/http.c b/lib/http.c index 8e422f0bf..7a5137e86 100644 --- a/lib/http.c +++ b/lib/http.c @@ -424,8 +424,8 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) /* figure out how much data we are expected to send */ switch(data->set.httpreq) { case HTTPREQ_POST: - if(data->set.postfieldsize != -1) - expectsend = data->set.postfieldsize; + if(data->state.infilesize != -1) + expectsend = data->state.infilesize; else if(data->set.postfields) expectsend = (curl_off_t)strlen(data->set.postfields); break; @@ -2572,8 +2572,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = 0; else { /* figure out the size of the postfields */ - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: + postsize = (data->state.infilesize != -1)? + data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1); } @@ -2696,7 +2696,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - else if(data->set.postfieldsize) { + else if(data->state.infilesize) { /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize?postsize:-1); diff --git a/lib/multi.c b/lib/multi.c index 2956022e4..b63f8bf70 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -402,7 +402,10 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, /* Point to the multi's connection cache */ data->state.conn_cache = &multi->conn_cache; - data->state.infilesize = data->set.filesize; + if(data->set.httpreq == HTTPREQ_PUT) + data->state.infilesize = data->set.filesize; + else + data->state.infilesize = data->set.postfieldsize; /* This adds the new entry at the 'end' of the doubly-linked circular list of SessionHandle structs to try and maintain a FIFO queue so diff --git a/lib/rtsp.c b/lib/rtsp.c index c5ca75723..5d61c6fe2 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -495,8 +495,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } else { - postsize = (data->set.postfieldsize != -1)? - data->set.postfieldsize: + postsize = (data->state.infilesize != -1)? + data->state.infilesize: (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0); data->set.httpreq = HTTPREQ_POST; } -- cgit v1.2.1 From 99eafc49bbfd45b293b0e7afce7fe4649af6d2e4 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 15 Jun 2015 08:57:31 +0200 Subject: security:choose_mech fix DEAD CODE warning ... by removing the "do {} while (0)" block. Coverity CID 1306669 --- lib/security.c | 89 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 43 insertions(+), 46 deletions(-) (limited to 'lib') diff --git a/lib/security.c b/lib/security.c index 1bea669d5..014bbf1b8 100644 --- a/lib/security.c +++ b/lib/security.c @@ -480,56 +480,54 @@ static CURLcode choose_mech(struct connectdata *conn) void *tmp_allocation; const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; - do { - tmp_allocation = realloc(conn->app_data, mech->size); - if(tmp_allocation == NULL) { - failf(data, "Failed realloc of size %u", mech->size); - mech = NULL; - return CURLE_OUT_OF_MEMORY; - } - conn->app_data = tmp_allocation; - - if(mech->init) { - ret = mech->init(conn->app_data); - if(ret) { - infof(data, "Failed initialization for %s. Skipping it.\n", - mech->name); - continue; - } + tmp_allocation = realloc(conn->app_data, mech->size); + if(tmp_allocation == NULL) { + failf(data, "Failed realloc of size %u", mech->size); + mech = NULL; + return CURLE_OUT_OF_MEMORY; + } + conn->app_data = tmp_allocation; + + if(mech->init) { + ret = mech->init(conn->app_data); + if(ret) { + infof(data, "Failed initialization for %s. Skipping it.\n", + mech->name); + return CURLE_FAILED_INIT; } + } - infof(data, "Trying mechanism %s...\n", mech->name); - ret = ftp_send_command(conn, "AUTH %s", mech->name); - if(ret < 0) - /* FIXME: This error is too generic but it is OK for now. */ - return CURLE_COULDNT_CONNECT; - - if(ret/100 != 3) { - switch(ret) { - case 504: - infof(data, "Mechanism %s is not supported by the server (server " - "returned ftp code: 504).\n", mech->name); - break; - case 534: - infof(data, "Mechanism %s was rejected by the server (server returned " - "ftp code: 534).\n", mech->name); - break; - default: - if(ret/100 == 5) { - infof(data, "server does not support the security extensions\n"); - return CURLE_USE_SSL_FAILED; - } - break; + infof(data, "Trying mechanism %s...\n", mech->name); + ret = ftp_send_command(conn, "AUTH %s", mech->name); + if(ret < 0) + /* FIXME: This error is too generic but it is OK for now. */ + return CURLE_COULDNT_CONNECT; + + if(ret/100 != 3) { + switch(ret) { + case 504: + infof(data, "Mechanism %s is not supported by the server (server " + "returned ftp code: 504).\n", mech->name); + break; + case 534: + infof(data, "Mechanism %s was rejected by the server (server returned " + "ftp code: 534).\n", mech->name); + break; + default: + if(ret/100 == 5) { + infof(data, "server does not support the security extensions\n"); + return CURLE_USE_SSL_FAILED; } - continue; + break; } + return CURLE_LOGIN_DENIED; + } - /* Authenticate */ - ret = mech->auth(conn->app_data, conn); + /* Authenticate */ + ret = mech->auth(conn->app_data, conn); - if(ret == AUTH_CONTINUE) - continue; - else if(ret != AUTH_OK) { + if(ret != AUTH_CONTINUE) { + if(ret != AUTH_OK) { /* Mechanism has dumped the error to stderr, don't error here. */ return -1; } @@ -545,8 +543,7 @@ static CURLcode choose_mech(struct connectdata *conn) /* Set the requested protection level */ /* BLOCKING */ (void)sec_set_protection_level(conn); - - } WHILE_FALSE; + } return CURLE_OK; } -- cgit v1.2.1 From b430cb2a588b4a1912378b044c47341f1abefc49 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 15 Jun 2015 09:05:07 +0200 Subject: rtsp_do: fix DEAD CODE "At condition p_request, the value of p_request cannot be NULL." Coverity CID 1306668. --- lib/rtsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/rtsp.c b/lib/rtsp.c index 5d61c6fe2..e33069a93 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -322,7 +322,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(!p_session_id && (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) { failf(data, "Refusing to issue an RTSP request [%s] without a session ID.", - p_request ? p_request : ""); + p_request); return CURLE_BAD_FUNCTION_ARGUMENT; } -- cgit v1.2.1 From 3e7ec1e8492824f0c6f6dea718624935a1407069 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Wed, 17 Jun 2015 00:17:03 -0400 Subject: schannel: schannel_recv overhaul This commit is several drafts squashed together. The changes from each draft are noted below. If any changes are similar and possibly contradictory the change in the latest draft takes precedence. Bug: https://github.com/bagder/curl/issues/244 Reported-by: Chris Araman %% %% Draft 1 %% - return 0 if len == 0. that will have to be documented. - continue on and process the caches regardless of raw recv - if decrypted data will be returned then set the error code to CURLE_OK and return its count - if decrypted data will not be returned and the connection has closed (eg nread == 0) then return 0 and CURLE_OK - if decrypted data will not be returned and the connection *hasn't* closed then set the error code to CURLE_AGAIN --only if an error code isn't already set-- and return -1 - narrow the Win2k workaround to only Win2k %% %% Draft 2 %% - Trying out a change in flow to handle corner cases. %% %% Draft 3 %% - Back out the lazier decryption change made in draft2. %% %% Draft 4 %% - Some formatting and branching changes - Decrypt all encrypted cached data when len == 0 - Save connection closed state - Change special Win2k check to use connection closed state %% %% Draft 5 %% - Default to CURLE_AGAIN in cleanup if an error code wasn't set and the connection isn't closed. %% %% Draft 6 %% - Save the last error only if it is an unrecoverable error. Prior to this I saved the last error state in all cases; unfortunately the logic to cover that in all cases would lead to some muddle and I'm concerned that could then lead to a bug in the future so I've replaced it by only recording an unrecoverable error and that state will persist. - Do not recurse on renegotiation. Instead we'll continue on to process any trailing encrypted data received during the renegotiation only. - Move the err checks in cleanup after the check for decrypted data. In either case decrypted data is always returned but I think it's easier to understand when those err checks come after the decrypted data check. %% %% Draft 7 %% - Regardless of len value go directly to cleanup if there is an unrecoverable error or a close_notify was already received. Prior to this change we only acknowledged those two states if len != 0. - Fix a bug in connection closed behavior: Set the error state in the cleanup, because we don't know for sure it's an error until that time. - (Related to above) In the case the connection is closed go "greedy" with the decryption to make sure all remaining encrypted data has been decrypted even if it is not needed at that time by the caller. This is necessary because we can only tell if the connection closed gracefully (close_notify) once all encrypted data has been decrypted. - Do not renegotiate when an unrecoverable error is pending. %% %% Draft 8 %% - Don't show 'server closed the connection' info message twice. - Show an info message if server closed abruptly (missing close_notify). --- lib/urldata.h | 3 + lib/vtls/schannel.c | 268 +++++++++++++++++++++++++++++++++++----------------- lib/vtls/schannel.h | 1 + 3 files changed, 186 insertions(+), 86 deletions(-) (limited to 'lib') diff --git a/lib/urldata.h b/lib/urldata.h index 64b855e32..05bda794b 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -322,6 +322,9 @@ struct ssl_connect_data { size_t encdata_offset, decdata_offset; unsigned char *encdata_buffer, *decdata_buffer; unsigned long req_flags, ret_flags; + CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + bool recv_sspi_close_notify; /* true if connection closed by close_notify */ + bool recv_connection_closed; /* true if connection closed, regardless how */ #endif /* USE_SCHANNEL */ #ifdef USE_DARWINSSL SSLContextRef ssl_ctx; diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 543c20657..19aff8f07 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -268,6 +268,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: sent initial handshake data: " "sent %zd bytes\n", written); + connssl->recv_unrecoverable_err = CURLE_OK; + connssl->recv_sspi_close_notify = false; + connssl->recv_connection_closed = false; + /* continue to second handshake step */ connssl->connecting_state = ssl_connect_2; @@ -300,6 +304,17 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) if(!connssl->cred || !connssl->ctxt) return CURLE_SSL_CONNECT_ERROR; + /* buffer to store previously received and decrypted data */ + if(connssl->decdata_buffer == NULL) { + connssl->decdata_offset = 0; + connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; + connssl->decdata_buffer = malloc(connssl->decdata_length); + if(connssl->decdata_buffer == NULL) { + failf(data, "schannel: unable to allocate memory"); + return CURLE_OUT_OF_MEMORY; + } + } + /* buffer to store previously received and encrypted data */ if(connssl->encdata_buffer == NULL) { connssl->encdata_offset = 0; @@ -834,8 +849,7 @@ schannel_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { size_t size = 0; - ssize_t nread = 0; - CURLcode result; + ssize_t nread = -1; struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; @@ -844,72 +858,103 @@ schannel_recv(struct connectdata *conn, int sockindex, SecBuffer inbuf[4]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; + /* we want the length of the encrypted buffer to be at least large enough + that it can hold all the bytes requested and some TLS record overhead. */ + size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE; + + /**************************************************************************** + * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup. + * The pattern for return error is set *err, optional infof, goto cleanup. + * + * Our priority is to always return as much decrypted data to the caller as + * possible, even if an error occurs. The state of the decrypted buffer must + * always be valid. Transfer of decrypted data to the caller's buffer is + * handled in the cleanup. + */ infof(data, "schannel: client wants to read %zu bytes\n", len); *err = CURLE_OK; - /* buffer to store previously received and decrypted data */ - if(connssl->decdata_buffer == NULL) { - connssl->decdata_offset = 0; - connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE; - connssl->decdata_buffer = malloc(connssl->decdata_length); - if(connssl->decdata_buffer == NULL) { - failf(data, "schannel: unable to allocate memory"); - *err = CURLE_OUT_OF_MEMORY; - return -1; - } + if(len && len <= connssl->decdata_offset) { + infof(data, "schannel: enough decrypted data is already available\n"); + goto cleanup; } + else if(connssl->recv_unrecoverable_err) { + *err = connssl->recv_unrecoverable_err; + infof(data, "schannel: an unrecoverable error occurred in a prior call\n"); + goto cleanup; + } + else if(connssl->recv_sspi_close_notify) { + /* once a server has indicated shutdown there is no more encrypted data */ + infof(data, "schannel: server indicated shutdown in a prior call\n"); + goto cleanup; + } + else if(!len) { + /* It's debatable what to return when !len. Regardless we can't return + immediately because there may be data to decrypt (in the case we want to + decrypt all encrypted cached data) so handle !len later in cleanup. + */ + ; /* do nothing */ + } + else if(!connssl->recv_connection_closed) { + /* increase enc buffer in order to fit the requested amount of data */ + size = connssl->encdata_length - connssl->encdata_offset; + if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE || + connssl->encdata_length < min_encdata_length) { + reallocated_length = connssl->encdata_offset + + CURL_SCHANNEL_BUFFER_FREE_SIZE; + if(reallocated_length < min_encdata_length) { + reallocated_length = min_encdata_length; + } + reallocated_buffer = realloc(connssl->encdata_buffer, + reallocated_length); + if(reallocated_buffer == NULL) { + *err = CURLE_OUT_OF_MEMORY; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; + } - /* increase buffer in order to fit the requested amount of data */ - if(connssl->encdata_length - connssl->encdata_offset < - CURL_SCHANNEL_BUFFER_FREE_SIZE || connssl->encdata_length < len) { - /* increase internal encrypted data buffer */ - reallocated_length = connssl->encdata_offset + - CURL_SCHANNEL_BUFFER_FREE_SIZE; - /* make sure that the requested amount of data fits */ - if(reallocated_length < len) { - reallocated_length = len; - } - reallocated_buffer = realloc(connssl->encdata_buffer, - reallocated_length); - - if(reallocated_buffer == NULL) { - failf(data, "schannel: unable to re-allocate memory"); - *err = CURLE_OUT_OF_MEMORY; - return -1; - } - else { connssl->encdata_buffer = reallocated_buffer; connssl->encdata_length = reallocated_length; + size = connssl->encdata_length - connssl->encdata_offset; + infof(data, "schannel: encdata_buffer resized %zu\n", + connssl->encdata_length); } - } - /* read encrypted data from socket */ - infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", - connssl->encdata_offset, connssl->encdata_length); - size = connssl->encdata_length - connssl->encdata_offset; - if(size > 0) { + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + + /* read encrypted data from socket */ *err = Curl_read_plain(conn->sock[sockindex], - (char *) (connssl->encdata_buffer + - connssl->encdata_offset), + (char *)(connssl->encdata_buffer + + connssl->encdata_offset), size, &nread); - /* check for received data */ - if(*err != CURLE_OK) { - return -1; + if(*err) { + nread = -1; + if(*err == CURLE_AGAIN) + infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n"); + else if(*err == CURLE_RECV_ERROR) + infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n"); + else + infof(data, "schannel: Curl_read_plain returned error %d\n", *err); + } + else if(nread == 0) { + connssl->recv_connection_closed = true; + infof(data, "schannel: server closed the connection\n"); } else if(nread > 0) { - /* increase encrypted data buffer offset */ - connssl->encdata_offset += nread; + connssl->encdata_offset += (size_t)nread; + infof(data, "schannel: encrypted data got %zd\n", nread); } - infof(data, "schannel: encrypted data got %zd\n", nread); } infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", connssl->encdata_offset, connssl->encdata_length); - /* check if we still have some data in our buffers */ + /* decrypt loop */ while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK && - connssl->decdata_offset < len) { + (!len || connssl->decdata_offset < len || + connssl->recv_connection_closed)) { /* prepare data buffer for DecryptMessage call */ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer, curlx_uztoul(connssl->encdata_offset)); @@ -924,13 +969,6 @@ schannel_recv(struct connectdata *conn, int sockindex, sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle, &inbuf_desc, 0, NULL); - /* check if we need more data */ - if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { - infof(data, "schannel: failed to decrypt data, need more data\n"); - *err = CURLE_AGAIN; - return -1; - } - /* check if everything went fine (server may want to renegotiate or shutdown the connection context) */ if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE || @@ -943,7 +981,7 @@ schannel_recv(struct connectdata *conn, int sockindex, /* increase buffer in order to fit the received amount of data */ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ? - inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; + inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE; if(connssl->decdata_length - connssl->decdata_offset < size || connssl->decdata_length < len) { /* increase internal decrypted data buffer */ @@ -954,21 +992,18 @@ schannel_recv(struct connectdata *conn, int sockindex, } reallocated_buffer = realloc(connssl->decdata_buffer, reallocated_length); - if(reallocated_buffer == NULL) { - failf(data, "schannel: unable to re-allocate memory"); *err = CURLE_OUT_OF_MEMORY; - return -1; - } - else { - connssl->decdata_buffer = reallocated_buffer; - connssl->decdata_length = reallocated_length; + failf(data, "schannel: unable to re-allocate memory"); + goto cleanup; } + connssl->decdata_buffer = reallocated_buffer; + connssl->decdata_length = reallocated_length; } /* copy decrypted data to internal buffer */ size = inbuf[1].cbBuffer; - if(size > 0) { + if(size) { memcpy(connssl->decdata_buffer + connssl->decdata_offset, inbuf[1].pvBuffer, size); connssl->decdata_offset += size; @@ -1007,56 +1042,117 @@ schannel_recv(struct connectdata *conn, int sockindex, /* check if server wants to renegotiate the connection context */ if(sspi_status == SEC_I_RENEGOTIATE) { infof(data, "schannel: remote party requests renegotiation\n"); - + if(*err && *err != CURLE_AGAIN) { + infof(data, "schannel: can't renogotiate, an error is pending\n"); + goto cleanup; + } + if(connssl->encdata_offset) { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: can't renogotiate, " + "encrypted data available\n"); + goto cleanup; + } /* begin renegotiation */ infof(data, "schannel: renegotiating SSL/TLS connection\n"); connssl->state = ssl_connection_negotiating; connssl->connecting_state = ssl_connect_2_writing; - result = schannel_connect_common(conn, sockindex, FALSE, &done); - if(result) - *err = result; - else { - infof(data, "schannel: SSL/TLS connection renegotiated\n"); - /* now retry receiving data */ - return schannel_recv(conn, sockindex, buf, len, err); + *err = schannel_connect_common(conn, sockindex, FALSE, &done); + if(*err) { + infof(data, "schannel: renegotiation failed\n"); + goto cleanup; } + /* now retry receiving data */ + sspi_status = SEC_E_OK; + infof(data, "schannel: SSL/TLS connection renegotiated\n"); + continue; } + /* check if the server closed the connection */ + else if(sspi_status == SEC_I_CONTEXT_EXPIRED) { + /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not + returned so we have to work around that in cleanup. */ + connssl->recv_sspi_close_notify = true; + if(!connssl->recv_connection_closed) { + connssl->recv_connection_closed = true; + infof(data, "schannel: server closed the connection\n"); + } + goto cleanup; + } + } + else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) { + if(!*err) + *err = CURLE_AGAIN; + infof(data, "schannel: failed to decrypt data, need more data\n"); + goto cleanup; } else { - /* something went wrong and we need to return an error */ + *err = CURLE_RECV_ERROR; infof(data, "schannel: failed to read data from server: %s\n", Curl_sspi_strerror(conn, sspi_status)); - *err = CURLE_RECV_ERROR; - return -1; + goto cleanup; } } + infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n", + connssl->encdata_offset, connssl->encdata_length); + infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", connssl->decdata_offset, connssl->decdata_length); - /* copy requested decrypted data to supplied buffer */ +cleanup: + /* Warning- there is no guarantee the encdata state is valid at this point */ + infof(data, "schannel: schannel_recv cleanup\n"); + + /* Error if the connection has closed without a close_notify. + Behavior here is a matter of debate. We don't want to be vulnerable to a + truncation attack however there's some browser precedent for ignoring the + close_notify for compatibility reasons. + Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't + return close_notify. In that case if the connection was closed we assume it + was graceful (close_notify) since there doesn't seem to be a way to tell. + */ + if(len && !connssl->decdata_offset && connssl->recv_connection_closed && + !connssl->recv_sspi_close_notify) { + DWORD winver_full, winver_major, winver_minor; + winver_full = GetVersion(); + winver_major = (DWORD)(LOBYTE(LOWORD(winver_full))); + winver_minor = (DWORD)(HIBYTE(LOWORD(winver_full))); + + if(winver_major == 5 && winver_minor == 0 && sspi_status == SEC_E_OK) + connssl->recv_sspi_close_notify = true; + else { + *err = CURLE_RECV_ERROR; + infof(data, "schannel: server closed abruptly (missing close_notify)\n"); + } + } + + /* Any error other than CURLE_AGAIN is an unrecoverable error. */ + if(*err && *err != CURLE_AGAIN) + connssl->recv_unrecoverable_err = *err; + size = len < connssl->decdata_offset ? len : connssl->decdata_offset; - if(size > 0) { + if(size) { memcpy(buf, connssl->decdata_buffer, size); - - /* move remaining decrypted data forward to the beginning of buffer */ memmove(connssl->decdata_buffer, connssl->decdata_buffer + size, connssl->decdata_offset - size); connssl->decdata_offset -= size; - infof(data, "schannel: decrypted data returned %zd\n", size); + infof(data, "schannel: decrypted data returned %zu\n", size); infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n", connssl->decdata_offset, connssl->decdata_length); - } - /* check if the server closed the connection, */ - /* including special check for Windows 2000 Professional */ - else if(sspi_status == SEC_I_CONTEXT_EXPIRED || (sspi_status == SEC_E_OK && - connssl->encdata_offset && connssl->encdata_buffer[0] == 0x15)) { - infof(data, "schannel: server closed the connection\n"); *err = CURLE_OK; + return (ssize_t)size; } - return size; + if(!*err && !connssl->recv_connection_closed) + *err = CURLE_AGAIN; + + /* It's debatable what to return when !len. We could return whatever error we + got from decryption but instead we override here so the return is consistent. + */ + if(!len) + *err = CURLE_OK; + + return *err ? -1 : 0; } CURLcode diff --git a/lib/vtls/schannel.h b/lib/vtls/schannel.h index e019a8606..532958483 100644 --- a/lib/vtls/schannel.h +++ b/lib/vtls/schannel.h @@ -72,6 +72,7 @@ #define SECBUFFER_ALERT 17 #endif +/* Both schannel buffer sizes must be > 0 */ #define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096 #define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024 -- cgit v1.2.1 From 50c7f17e503fbab5081b69c97f9d4645389b9270 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 22 May 2015 10:28:21 +0200 Subject: SMB: rangecheck values read off incoming packet CVE-2015-3237 Detected by Coverity. CID 1299430. Bug: http://curl.haxx.se/docs/adv_20150617B.html --- lib/smb.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/smb.c b/lib/smb.c index 8cb350359..d461a712c 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -783,9 +783,15 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) off = Curl_read16_le(((unsigned char *) msg) + sizeof(struct smb_header) + 13); if(len > 0) { - result = Curl_client_write(conn, CLIENTWRITE_BODY, - (char *)msg + off + sizeof(unsigned int), - len); + struct smb_conn *smbc = &conn->proto.smbc; + if(off + sizeof(unsigned int) + len > smbc->got) { + failf(conn->data, "Invalid input packet"); + result = CURLE_RECV_ERROR; + } + else + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *)msg + off + sizeof(unsigned int), + len); if(result) { req->result = result; next_state = SMB_CLOSE; -- cgit v1.2.1 From 24a8359b256f8a3d7892f21f156a4bf0a42710d5 Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Thu, 28 May 2015 20:04:35 +0200 Subject: http: do not leak basic auth credentials on re-used connections CVE-2015-3236 This partially reverts commit curl-7_39_0-237-g87c4abb Reported-by: Tomas Tomecek, Kamil Dudka Bug: http://curl.haxx.se/docs/adv_20150617A.html --- lib/http.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/http.c b/lib/http.c index 7a5137e86..e06c798e9 100644 --- a/lib/http.c +++ b/lib/http.c @@ -2312,20 +2312,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) te ); - /* - * Free userpwd for Negotiate/NTLM. Cannot reuse as it is associated with - * the connection and shouldn't be repeated over it either. - */ - switch (data->state.authhost.picked) { - case CURLAUTH_NEGOTIATE: - case CURLAUTH_NTLM: - case CURLAUTH_NTLM_WB: - Curl_safefree(conn->allocptr.userpwd); - break; - } + /* clear userpwd to avoid re-using credentials from re-used connections */ + Curl_safefree(conn->allocptr.userpwd); /* - * Same for proxyuserpwd + * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated + * with the connection and shouldn't be repeated over it either. */ switch (data->state.authproxy.picked) { case CURLAUTH_NEGOTIATE: -- cgit v1.2.1 From b88f980a7437abc1159a1185c04d381347c8f5b1 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 17 Jun 2015 00:30:06 +0200 Subject: FTP: do the HTTP CONNECT for data connection blocking ** WORK-AROUND ** The introduced non-blocking general behaviour for Curl_proxyCONNECT() didn't work for the data connection establishment unless it was very fast. The newly introduced function argument makes it operate in a more blocking manner, more like it used to work in the past. This blocking approach is only used when the FTP data connecting through HTTP proxy. Blocking like this is bad. A better fix would make it work more asynchronously. Bug: https://github.com/bagder/curl/issues/278 --- lib/ftp.c | 4 ++-- lib/http_proxy.c | 22 ++++++++++++++-------- lib/http_proxy.h | 5 +++-- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/ftp.c b/lib/ftp.c index de628a2dc..fade092e4 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -1887,7 +1887,7 @@ static CURLcode proxy_magic(struct connectdata *conn, memset(&http_proxy, 0, sizeof(http_proxy)); data->req.protop = &http_proxy; - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport); + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE); data->req.protop = ftp_save; @@ -3645,7 +3645,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) { /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port aren't used so we blank their arguments. TODO: make this nicer */ - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0); + result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0, FALSE); return result; } diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 5ab9915a6..4373d6284 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -68,7 +68,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); result = Curl_proxyCONNECT(conn, FIRSTSOCKET, - conn->host.name, conn->remote_port); + conn->host.name, conn->remote_port, FALSE); conn->data->req.protop = prot_save; if(CURLE_OK != result) return result; @@ -85,12 +85,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This * function will issue the necessary commands to get a seamless tunnel through * this proxy. After that, the socket can be used just as a normal socket. + * + * 'blocking' set to TRUE means that this function will do the entire CONNECT + * + response in a blocking fashion. Should be avoided! */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int sockindex, const char *hostname, - int remote_port) + int remote_port, + bool blocking) { int subversion=0; struct SessionHandle *data=conn->data; @@ -225,12 +229,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_RECV_ERROR; } - if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) - /* return so we'll be called again polling-style */ - return CURLE_OK; - else { - DEBUGF(infof(data, - "Read response immediately from proxy CONNECT\n")); + if(!blocking) { + if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) + /* return so we'll be called again polling-style */ + return CURLE_OK; + else { + DEBUGF(infof(data, + "Read response immediately from proxy CONNECT\n")); + } } /* at this point, the tunnel_connecting phase is over. */ diff --git a/lib/http_proxy.h b/lib/http_proxy.h index 2b5e9c9b4..058a29db9 100644 --- a/lib/http_proxy.h +++ b/lib/http_proxy.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,8 @@ /* ftp can use this as well */ CURLcode Curl_proxyCONNECT(struct connectdata *conn, int tunnelsocket, - const char *hostname, int remote_port); + const char *hostname, int remote_port, + bool blocking); /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) -- cgit v1.2.1 From 4a2398627c32c9132b270f6c79492f7bbc5b90c3 Mon Sep 17 00:00:00 2001 From: Paul Howarth Date: Wed, 17 Jun 2015 16:53:34 +0200 Subject: openssl: Fix build with openssl < ~ 0.9.8f The symbol SSL3_MT_NEWSESSION_TICKET appears to have been introduced at around openssl 0.9.8f, and the use of it in lib/vtls/openssl.c breaks builds with older openssls (certainly with 0.9.8b, which is the latest older version I have to try with). --- lib/vtls/openssl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index d1ea5fbf1..872829a00 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1427,8 +1427,10 @@ static const char *ssl_msg_type(int ssl_ver, int msg) return "Client hello"; case SSL3_MT_SERVER_HELLO: return "Server hello"; +#ifdef SSL3_MT_NEWSESSION_TICKET case SSL3_MT_NEWSESSION_TICKET: return "Newsession Ticket"; +#endif case SSL3_MT_CERTIFICATE: return "Certificate"; case SSL3_MT_SERVER_KEY_EXCHANGE: -- cgit v1.2.1 From 46d0eba2e9f600972c56bde04357bb5cfe1bc42b Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Jun 2015 00:06:46 +0200 Subject: openssl: fix build with BoringSSL OPENSSL_load_builtin_modules does not exist in BoringSSL. Regression from cae43a1 --- lib/vtls/openssl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 872829a00..e84193616 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -136,6 +136,11 @@ #define CONF_modules_load_file(a,b,c) #endif +#ifdef OPENSSL_IS_BORINGSSL +/* not present in BoringSSL */ +#define OPENSSL_load_builtin_modules(x) +#endif + /* * Number of bytes to read from the random number seed file. This must be * a finite value (because some entropy "files" like /dev/urandom have -- cgit v1.2.1 From 26ddc536b0ab5fc62d6503c82c34dd3dbf112dc3 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Jun 2015 14:20:31 +0200 Subject: openssl: fix use of uninitialized buffer Make sure that the error buffer is always initialized and simplify the use of it to make the logic easier. Bug: https://github.com/bagder/curl/issues/318 Reported-by: sneis --- lib/vtls/openssl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index e84193616..37d50cb60 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -2137,10 +2137,9 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) else { /* untreated error */ unsigned long errdetail; - char error_buffer[256]; /* OpenSSL documents that this must be at least - 256 bytes long. */ + char error_buffer[256]=""; /* OpenSSL documents that this must be at + least 256 bytes long. */ CURLcode result; - const char *cert_problem = NULL; long lerr; connssl->connecting_state = ssl_connect_2; /* the connection failed, @@ -2172,9 +2171,10 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) X509_verify_cert_error_string(lerr)); } else - cert_problem = "SSL certificate problem, verify that the CA cert is" - " OK."; - + /* strcpy() is fine here as long as the string fits within + error_buffer */ + strcpy(error_buffer, + "SSL certificate problem, check your CA cert"); break; default: result = CURLE_SSL_CONNECT_ERROR; @@ -2195,7 +2195,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) } /* Could be a CERT problem */ - failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer); + failf(data, "%s", error_buffer); return result; } -- cgit v1.2.1 From 307f212379c2ffa2181bdc523a7cc951aa8d1452 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 18 Jun 2015 14:29:57 +0200 Subject: RTSP: removed another piece of dead code Coverity CID 1306668 --- lib/rtsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/rtsp.c b/lib/rtsp.c index e33069a93..c30afd39d 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -440,8 +440,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) Curl_add_bufferf(req_buffer, "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */ "CSeq: %ld\r\n", /* CSeq */ - (p_request ? p_request : ""), p_stream_uri, - rtsp->CSeq_sent); + p_request, p_stream_uri, rtsp->CSeq_sent); if(result) return result; -- cgit v1.2.1 From 93aacc3050bb6c5aeddf6ea37a9b8a849fc0889b Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 18 Jun 2015 14:28:39 +0200 Subject: Makefile.m32: add support for CURL_LDFLAG_EXTRAS It is similar to existing CURL_CFLAG_EXTRAS, but for extra linker option. --- lib/Makefile.m32 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/Makefile.m32 b/lib/Makefile.m32 index ee47d6708..5f88ab724 100644 --- a/lib/Makefile.m32 +++ b/lib/Makefile.m32 @@ -58,7 +58,7 @@ CC = $(CROSSPREFIX)gcc CFLAGS = $(CURL_CFLAG_EXTRAS) -g -O2 -Wall CFLAGS += -fno-strict-aliasing # comment LDFLAGS below to keep debug info -LDFLAGS = -s +LDFLAGS = $(CURL_LDFLAG_EXTRAS) -s AR = $(CROSSPREFIX)ar RANLIB = $(CROSSPREFIX)ranlib RC = $(CROSSPREFIX)windres -- cgit v1.2.1 From 1c3811f4fd46680ca3701c68049d3b50d5882b94 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Thu, 18 Jun 2015 23:20:10 +0200 Subject: FTP: fixed compiling with --disable-proxy, broken in b88f980a --- lib/http_proxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/http_proxy.h b/lib/http_proxy.h index 058a29db9..9c4f0207d 100644 --- a/lib/http_proxy.h +++ b/lib/http_proxy.h @@ -35,7 +35,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, CURLcode Curl_proxy_connect(struct connectdata *conn); #else -#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN +#define Curl_proxyCONNECT(x,y,z,w,v) CURLE_NOT_BUILT_IN #define Curl_proxy_connect(x) CURLE_OK #endif -- cgit v1.2.1 From ef0fdb83b89c87b63e94bf6ecdab5cd8c6458b2e Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Thu, 18 Jun 2015 19:35:04 -0400 Subject: cookie: Fix bug in export if any-domain cookie is present In 3013bb6 I had changed cookie export to ignore any-domain cookies, however the logic I used to do so was incorrect, and would lead to a busy loop in the case of exporting a cookie list that contained any-domain cookies. The result of that is worse though, because in that case the other cookies would not be written resulting in an empty file once the application is terminated to stop the busy loop. --- lib/cookie.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/cookie.c b/lib/cookie.c index 94f2a8b85..22730cff4 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -1274,9 +1274,8 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) "# http://curl.haxx.se/docs/http-cookies.html\n" "# This file was generated by libcurl! Edit at your own risk.\n\n", out); - co = c->cookies; - while(co) { + for(co = c->cookies; co; co = co->next) { if(!co->domain) continue; format_ptr = get_netscape_format(co); @@ -1288,7 +1287,6 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) } fprintf(out, "%s\n", format_ptr); free(format_ptr); - co=co->next; } } @@ -1309,9 +1307,7 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) (data->cookies->numcookies == 0)) return NULL; - c = data->cookies->cookies; - - while(c) { + for(c = data->cookies->cookies; c; c = c->next) { if(!c->domain) continue; line = get_netscape_format(c); @@ -1326,7 +1322,6 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) return NULL; } list = beg; - c = c->next; } return list; -- cgit v1.2.1