diff --git a/SOURCES/0022-curl-7.29.0-24c3cdce.patch b/SOURCES/0022-curl-7.29.0-24c3cdce.patch index 5dac548..7ed2377 100644 --- a/SOURCES/0022-curl-7.29.0-24c3cdce.patch +++ b/SOURCES/0022-curl-7.29.0-24c3cdce.patch @@ -1,7 +1,7 @@ From ca7b1cd659eb0eb0ef355e3e122742abcea73287 Mon Sep 17 00:00:00 2001 From: Kamil Dudka Date: Wed, 2 Jul 2014 16:34:48 +0200 -Subject: [PATCH 1/2] tool: call PR_Cleanup() on exit if NSPR is used +Subject: [PATCH 1/3] tool: call PR_Cleanup() on exit if NSPR is used This prevents valgrind from reporting possibly lost memory that NSPR uses for file descriptor cache and other globally allocated internal @@ -48,7 +48,7 @@ index 95e9cc7..6a1ed6c 100644 From 295471f8122cf6522c36f8e3588e5b4d15a691ea Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 17 Jul 2014 14:37:28 +0200 -Subject: [PATCH 2/2] build: link curl to NSS libraries when NSS support is +Subject: [PATCH 2/3] build: link curl to NSS libraries when NSS support is enabled This fixes a build failure on Debian caused by commit @@ -140,3 +140,98 @@ index 41fb549..1b578c2 100644 -- 2.1.0 + +From 0631da3859c9868ff317521544a246b5be83e600 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 14 Jul 2015 17:08:44 +0200 +Subject: [PATCH 3/3] libtest: call PR_Cleanup() on exit if NSPR is used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This prevents valgrind from reporting possibly lost memory that NSPR +uses for file descriptor cache and other globally allocated internal +data structures. + +Reported-by: Štefan Kremeň + +Upstream-commit: cd20e81e89ecebc5064e1d3e22e62e2802b2711e +Signed-off-by: Kamil Dudka +--- + tests/libtest/Makefile.am | 4 ++-- + tests/libtest/Makefile.in | 4 ++-- + tests/libtest/first.c | 15 ++++++++++++++- + 3 files changed, 18 insertions(+), 5 deletions(-) + +diff --git a/tests/libtest/Makefile.am b/tests/libtest/Makefile.am +index ba4097f..a844ab2 100644 +--- a/tests/libtest/Makefile.am ++++ b/tests/libtest/Makefile.am +@@ -62,8 +62,8 @@ if USE_EXPLICIT_LIB_DEPS + SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ + TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ + else +-SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ +-TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ ++SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ ++TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ + endif + + # Dependencies (may need to be overriden) +diff --git a/tests/libtest/Makefile.in b/tests/libtest/Makefile.in +index e6826c0..9086af3 100644 +--- a/tests/libtest/Makefile.in ++++ b/tests/libtest/Makefile.in +@@ -949,9 +949,9 @@ AUTOMAKE_OPTIONS = foreign nostdinc + EXTRA_DIST = test75.pl test307.pl test610.pl test613.pl test1013.pl \ + test1022.pl Makefile.inc notexists.pl + +-@USE_EXPLICIT_LIB_DEPS_FALSE@SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ ++@USE_EXPLICIT_LIB_DEPS_FALSE@SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_LIBS@ @NSS_LIBS@ + @USE_EXPLICIT_LIB_DEPS_TRUE@SUPPORTFILES_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ +-@USE_EXPLICIT_LIB_DEPS_FALSE@TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ ++@USE_EXPLICIT_LIB_DEPS_FALSE@TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @CURL_NETWORK_AND_TIME_LIBS@ @NSS_LIBS@ + @USE_EXPLICIT_LIB_DEPS_TRUE@TESTUTIL_LIBS = $(top_builddir)/lib/libcurl.la @LIBCURL_LIBS@ + + # Dependencies (may need to be overriden) +diff --git a/tests/libtest/first.c b/tests/libtest/first.c +index 253acb2..94748a5 100644 +--- a/tests/libtest/first.c ++++ b/tests/libtest/first.c +@@ -25,6 +25,10 @@ + #include /* for setlocale() */ + #endif + ++#ifdef USE_NSS ++#include ++#endif ++ + #ifdef CURLDEBUG + # define MEMDEBUG_NODEFINES + # include "memdebug.h" +@@ -97,6 +101,7 @@ static void memory_tracking_init(void) + int main(int argc, char **argv) + { + char *URL; ++ int result; + + memory_tracking_init(); + +@@ -127,5 +132,13 @@ int main(int argc, char **argv) + + fprintf(stderr, "URL: %s\n", URL); + +- return test(URL); ++ result = test(URL); ++ ++#ifdef USE_NSS ++ if(PR_Initialized()) ++ /* prevent valgrind from reporting possibly lost memory (fd cache, ...) */ ++ PR_Cleanup(); ++#endif ++ ++ return result; + } +-- +2.4.3 + diff --git a/SOURCES/0034-curl-7.29.0-002d58f1.patch b/SOURCES/0034-curl-7.29.0-002d58f1.patch new file mode 100644 index 0000000..820cfe7 --- /dev/null +++ b/SOURCES/0034-curl-7.29.0-002d58f1.patch @@ -0,0 +1,42 @@ +From c90b930b8312bb31f62325a09125cf44dd58d506 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 10 Aug 2015 00:12:12 +0200 +Subject: [PATCH] test46: update cookie expire time + +... since it went old and thus was expired and caused the test to fail! + +Upstream-commit: 002d58f1e8d8e725ba6d676599838983561feff9 +Signed-off-by: Kamil Dudka +--- + tests/data/test46 | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tests/data/test46 b/tests/data/test46 +index b6f8f83..b6ebe80 100644 +--- a/tests/data/test46 ++++ b/tests/data/test46 +@@ -51,8 +51,8 @@ TZ=GMT + + www.fake.come FALSE / FALSE 1022144953 cookiecliente si + www.loser.com FALSE / FALSE 1139150993 UID 99 +-%HOSTIP FALSE / FALSE 1439150993 mooo indeed +-#HttpOnly_%HOSTIP FALSE /want FALSE 1439150993 mooo2 indeed2 ++%HOSTIP FALSE / FALSE 1739150993 mooo indeed ++#HttpOnly_%HOSTIP FALSE /want FALSE 1739150993 mooo2 indeed2 + %HOSTIP FALSE /want FALSE 0 empty + + +@@ -76,8 +76,8 @@ Cookie: empty=; mooo2=indeed2; mooo=indeed + + www.fake.come FALSE / FALSE 1022144953 cookiecliente si + www.loser.com FALSE / FALSE 1139150993 UID 99 +-%HOSTIP FALSE / FALSE 1439150993 mooo indeed +-#HttpOnly_%HOSTIP FALSE /want FALSE 1439150993 mooo2 indeed2 ++%HOSTIP FALSE / FALSE 1739150993 mooo indeed ++#HttpOnly_%HOSTIP FALSE /want FALSE 1739150993 mooo2 indeed2 + %HOSTIP FALSE /want FALSE 0 empty + %HOSTIP FALSE / FALSE 2054030187 ckyPersistent permanent + %HOSTIP FALSE / FALSE 0 ckySession temporary +-- +2.4.6 + diff --git a/SOURCES/0035-curl-7.29.0-2f1a0bc0.patch b/SOURCES/0035-curl-7.29.0-2f1a0bc0.patch new file mode 100644 index 0000000..515c92a --- /dev/null +++ b/SOURCES/0035-curl-7.29.0-2f1a0bc0.patch @@ -0,0 +1,2989 @@ +From 965f26c806a87fbf9ae803d12d57b1e5f91e0754 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sat, 13 Apr 2013 10:49:42 +0100 +Subject: [PATCH 01/28] url: Added support for parsing login options from the + URL + +As well as parsing the username and password from the URL, added support +for parsing the optional options part from the login details, to allow +the following supported URL format: + +schema://username:password;options@example.com/path?q=foobar + +This will only be used by IMAP, POP3 and SMTP at present but any +protocol that may be given login options in the URL will be able to +add support for them. + +Upstream-commit: 73aa95592f47d461f0246eef1187f5d569aa6afa +Signed-off-by: Kamil Dudka +--- + lib/url.c | 79 ++++++++++++++++++++++++++++++++++++++++++++--------------- + lib/urldata.h | 3 +++ + 2 files changed, 62 insertions(+), 20 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 2dc56ae..fdf6bca 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -2461,6 +2461,7 @@ static void conn_free(struct connectdata *conn) + + Curl_safefree(conn->user); + Curl_safefree(conn->passwd); ++ Curl_safefree(conn->options); + Curl_safefree(conn->proxyuser); + Curl_safefree(conn->proxypasswd); + Curl_safefree(conn->allocptr.proxyuserpwd); +@@ -4283,24 +4284,27 @@ static CURLcode parse_url_userpass(struct SessionHandle *data, + struct connectdata *conn, + char *user, char *passwd) + { ++ char options[MAX_CURL_OPTIONS_LENGTH]; ++ + /* At this point, we're hoping all the other special cases have + * been taken care of, so conn->host.name is at most +- * [user[:password]]@]hostname ++ * [user[:password][;options]]@]hostname + * + * We need somewhere to put the embedded details, so do that first. + */ + +- char *ptr=strchr(conn->host.name, '@'); ++ char *ptr = strchr(conn->host.name, '@'); + char *userpass = conn->host.name; + +- user[0] =0; /* to make everything well-defined */ +- passwd[0]=0; ++ user[0] = 0; /* to make everything well-defined */ ++ passwd[0] = 0; ++ options[0] = 0; + + /* We will now try to extract the +- * possible user+password pair in a string like: ++ * possible login information in a string like: + * ftp://user:password@ftp.my.site:8021/README */ + if(ptr != NULL) { +- /* there's a user+password given here, to the left of the @ */ ++ /* There's login information to the left of the @ */ + + conn->host.name = ++ptr; + +@@ -4310,26 +4314,46 @@ static CURLcode parse_url_userpass(struct SessionHandle *data, + * set user/passwd, but doing that first adds more cases here :-( + */ + +- conn->bits.userpwd_in_url = TRUE; + if(data->set.use_netrc != CURL_NETRC_REQUIRED) { +- /* We could use the one in the URL */ +- +- conn->bits.user_passwd = TRUE; /* enable user+password */ +- ++ /* We could use the information in the URL so extract it */ + if(*userpass != ':') { +- /* the name is given, get user+password */ +- sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:" +- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", +- user, passwd); ++ if(*userpass != ';') { ++ /* The user is given so extract the user, password and options */ ++ int result = sscanf(userpass, ++ "%" MAX_CURL_USER_LENGTH_TXT "[^:;@]:" ++ "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];" ++ "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", ++ user, passwd, options); ++ ++ /* The extract failed so extract the user and options instead */ ++ if(result == 1) ++ sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:;@];" ++ "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", ++ user, options); ++ } ++ else { ++ /* No name or password are given so extract the options only */ ++ sscanf(userpass, ";%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", options); ++ } + } + else +- /* no name given, get the password only */ +- sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd); ++ /* No name is given so extract the password and options */ ++ sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];" ++ "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", ++ passwd, options); + + if(user[0]) { +- char *newname=curl_easy_unescape(data, user, 0, NULL); ++ char *newname; ++ ++ /* We have a user in the URL */ ++ conn->bits.userpwd_in_url = TRUE; ++ conn->bits.user_passwd = TRUE; /* enable user+password */ ++ ++ /* Decode the user */ ++ newname = curl_easy_unescape(data, user, 0, NULL); + if(!newname) + return CURLE_OUT_OF_MEMORY; ++ + if(strlen(newname) < MAX_CURL_USER_LENGTH) + strcpy(user, newname); + +@@ -4337,18 +4361,33 @@ static CURLcode parse_url_userpass(struct SessionHandle *data, + the unconverted name, it'll be wrong but what the heck */ + free(newname); + } ++ + if(passwd[0]) { +- /* we have a password found in the URL, decode it! */ +- char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL); ++ /* We have a password in the URL so decode it */ ++ char *newpasswd = curl_easy_unescape(data, passwd, 0, NULL); + if(!newpasswd) + return CURLE_OUT_OF_MEMORY; ++ + if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) + strcpy(passwd, newpasswd); + + free(newpasswd); + } ++ ++ if(options[0]) { ++ /* We have an options list in the URL so decode it */ ++ char *newoptions = curl_easy_unescape(data, options, 0, NULL); ++ if(!newoptions) ++ return CURLE_OUT_OF_MEMORY; ++ ++ if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) ++ conn->options = newoptions; ++ else ++ free(newoptions); ++ } + } + } ++ + return CURLE_OK; + } + +diff --git a/lib/urldata.h b/lib/urldata.h +index 26bc89f..46ef5d5 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -847,6 +847,7 @@ struct connectdata { + + char *user; /* user name string, allocated */ + char *passwd; /* password string, allocated */ ++ char *options; /* options string, allocated */ + + char *proxyuser; /* proxy user name string, allocated */ + char *proxypasswd; /* proxy password string, allocated */ +@@ -1132,8 +1133,10 @@ typedef enum { + * Session-data MUST be put in the connectdata struct and here. */ + #define MAX_CURL_USER_LENGTH 256 + #define MAX_CURL_PASSWORD_LENGTH 256 ++#define MAX_CURL_OPTIONS_LENGTH 256 + #define MAX_CURL_USER_LENGTH_TXT "255" + #define MAX_CURL_PASSWORD_LENGTH_TXT "255" ++#define MAX_CURL_OPTIONS_LENGTH_TXT "255" + + struct auth { + unsigned long want; /* Bitmask set to the authentication methods wanted by +-- +2.4.6 + + +From 8e092594b858dd049e3f4f6660325f703e0a1c44 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Thu, 18 Apr 2013 17:02:28 +0100 +Subject: [PATCH 02/28] url: Reworked URL parsing to allow overriding by + CURLOPT_USERPWD + +Upstream-commit: 90c87f311eb087840008bfe89b19e6e0b808a246 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 50 +++++++++++++++++++++++++++++++------------------- + 1 file changed, 31 insertions(+), 19 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index fdf6bca..4a9df84 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -140,7 +140,7 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); + static CURLcode do_init(struct connectdata *conn); + static CURLcode parse_url_userpass(struct SessionHandle *data, + struct connectdata *conn, +- char *user, char *passwd); ++ char *user, char *passwd, char *options); + /* + * Protocol table. + */ +@@ -3585,8 +3585,7 @@ static CURLcode findprotocol(struct SessionHandle *data, + static CURLcode parseurlandfillconn(struct SessionHandle *data, + struct connectdata *conn, + bool *prot_missing, +- char *user, +- char *passwd) ++ char *user, char *passwd, char *options) + { + char *at; + char *fragment; +@@ -3811,7 +3810,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, + * Parse a user name and password in the URL and strip it out + * of the host name + *************************************************************/ +- result = parse_url_userpass(data, conn, user, passwd); ++ result = parse_url_userpass(data, conn, user, passwd, options); + if(result != CURLE_OK) + return result; + +@@ -4282,10 +4281,8 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, + */ + static CURLcode parse_url_userpass(struct SessionHandle *data, + struct connectdata *conn, +- char *user, char *passwd) ++ char *user, char *passwd, char *options) + { +- char options[MAX_CURL_OPTIONS_LENGTH]; +- + /* At this point, we're hoping all the other special cases have + * been taken care of, so conn->host.name is at most + * [user[:password][;options]]@]hostname +@@ -4381,9 +4378,9 @@ static CURLcode parse_url_userpass(struct SessionHandle *data, + return CURLE_OUT_OF_MEMORY; + + if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) +- conn->options = newoptions; +- else +- free(newoptions); ++ strcpy(options, newoptions); ++ ++ free(newoptions); + } + } + } +@@ -4551,11 +4548,13 @@ static void override_userpass(struct SessionHandle *data, + * Set password so it's available in the connection. + */ + static CURLcode set_userpass(struct connectdata *conn, +- const char *user, const char *passwd) ++ const char *user, const char *passwd, ++ const char *options) + { ++ CURLcode result = CURLE_OK; ++ + /* If our protocol needs a password and we have none, use the defaults */ +- if((conn->handler->flags & PROTOPT_NEEDSPWD) && +- !conn->bits.user_passwd) { ++ if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) { + + conn->user = strdup(CURL_DEFAULT_USER); + if(conn->user) +@@ -4565,17 +4564,28 @@ static CURLcode set_userpass(struct connectdata *conn, + /* This is the default password, so DON'T set conn->bits.user_passwd */ + } + else { +- /* store user + password, zero-length if not set */ ++ /* Store the user, zero-length if not set */ + conn->user = strdup(user); ++ ++ /* Store the password (only if user is present), zero-length if not set */ + if(conn->user) + conn->passwd = strdup(passwd); + else + conn->passwd = NULL; + } ++ + if(!conn->user || !conn->passwd) +- return CURLE_OUT_OF_MEMORY; ++ result = CURLE_OUT_OF_MEMORY; + +- return CURLE_OK; ++ /* Store the options, null if not set */ ++ if(!result && options[0]) { ++ conn->options = strdup(options); ++ ++ if(!conn->options) ++ result = CURLE_OUT_OF_MEMORY; ++ } ++ ++ return result; + } + + /************************************************************* +@@ -4745,12 +4755,13 @@ static CURLcode create_conn(struct SessionHandle *data, + struct connectdata **in_connect, + bool *async) + { +- CURLcode result=CURLE_OK; ++ CURLcode result = CURLE_OK; + struct connectdata *conn; + struct connectdata *conn_temp = NULL; + size_t urllen; + char user[MAX_CURL_USER_LENGTH]; + char passwd[MAX_CURL_PASSWORD_LENGTH]; ++ char options[MAX_CURL_OPTIONS_LENGTH]; + bool reuse; + char *proxy = NULL; + bool prot_missing = FALSE; +@@ -4815,7 +4826,8 @@ static CURLcode create_conn(struct SessionHandle *data, + conn->host.name = conn->host.rawalloc; + conn->host.name[0] = 0; + +- result = parseurlandfillconn(data, conn, &prot_missing, user, passwd); ++ result = parseurlandfillconn(data, conn, &prot_missing, user, passwd, ++ options); + if(result != CURLE_OK) + return result; + +@@ -5016,7 +5028,7 @@ static CURLcode create_conn(struct SessionHandle *data, + * for use + *************************************************************/ + override_userpass(data, conn, user, passwd); +- result = set_userpass(conn, user, passwd); ++ result = set_userpass(conn, user, passwd, options); + if(result != CURLE_OK) + return result; + +-- +2.4.6 + + +From c9099e450c8eebbc3318f827a8532448f6a8631f Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Thu, 18 Apr 2013 17:09:40 +0100 +Subject: [PATCH 03/28] url: Re-factored set_userpass() and + parse_url_userpass() + +Re-factored these functions to reflect their new behaviour following the +addition of login options. + +Upstream-commit: 0d49e408a48246b9a27448473e78ce3fd237b19e +Signed-off-by: Kamil Dudka +--- + lib/url.c | 41 +++++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 18 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 4a9df84..f03ca0f 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -138,9 +138,9 @@ find_oldest_idle_connection(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); +-static CURLcode parse_url_userpass(struct SessionHandle *data, +- struct connectdata *conn, +- char *user, char *passwd, char *options); ++static CURLcode parse_url_login(struct SessionHandle *data, ++ struct connectdata *conn, ++ char *user, char *passwd, char *options); + /* + * Protocol table. + */ +@@ -3806,11 +3806,11 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, + data->change.url_alloc = TRUE; /* free this later */ + } + +- /************************************************************* +- * Parse a user name and password in the URL and strip it out +- * of the host name +- *************************************************************/ +- result = parse_url_userpass(data, conn, user, passwd, options); ++ /* ++ * Parse the login details from the URL and strip them out of ++ * the host name ++ */ ++ result = parse_url_login(data, conn, user, passwd, options); + if(result != CURLE_OK) + return result; + +@@ -4268,7 +4268,8 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, + + /* + * +- * Parse a user name and password in the URL and strip it out of the host name ++ * Parse the login details (user name, password and options) from the URL and ++ * strip them out of the host name + * + * Inputs: data->set.use_netrc (CURLOPT_NETRC) + * conn->host.name +@@ -4276,12 +4277,13 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, + * Outputs: (almost :- all currently undefined) + * conn->bits.user_passwd - non-zero if non-default passwords exist + * user - non-zero length if defined +- * passwd - ditto ++ * passwd - non-zero length if defined ++ * options - non-zero length if defined + * conn->host.name - remove user name and password + */ +-static CURLcode parse_url_userpass(struct SessionHandle *data, +- struct connectdata *conn, +- char *user, char *passwd, char *options) ++static CURLcode parse_url_login(struct SessionHandle *data, ++ struct connectdata *conn, ++ char *user, char *passwd, char *options) + { + /* At this point, we're hoping all the other special cases have + * been taken care of, so conn->host.name is at most +@@ -4547,20 +4549,23 @@ static void override_userpass(struct SessionHandle *data, + /* + * Set password so it's available in the connection. + */ +-static CURLcode set_userpass(struct connectdata *conn, +- const char *user, const char *passwd, +- const char *options) ++static CURLcode set_login(struct connectdata *conn, ++ const char *user, const char *passwd, ++ const char *options) + { + CURLcode result = CURLE_OK; + + /* If our protocol needs a password and we have none, use the defaults */ + if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) { +- ++ /* Store the default user */ + conn->user = strdup(CURL_DEFAULT_USER); ++ ++ /* Store the default password */ + if(conn->user) + conn->passwd = strdup(CURL_DEFAULT_PASSWORD); + else + conn->passwd = NULL; ++ + /* This is the default password, so DON'T set conn->bits.user_passwd */ + } + else { +@@ -5028,7 +5033,7 @@ static CURLcode create_conn(struct SessionHandle *data, + * for use + *************************************************************/ + override_userpass(data, conn, user, passwd); +- result = set_userpass(conn, user, passwd, options); ++ result = set_login(conn, user, passwd, options); + if(result != CURLE_OK) + return result; + +-- +2.4.6 + + +From a66a0feefcb037ffcfaf2dbd3dcd9f17a416ad13 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Thu, 18 Apr 2013 17:52:05 +0100 +Subject: [PATCH 04/28] url: Moved parsing of login details out of + parse_url_login() + +Separated the parsing of login details from the processing of them in +parse_url_login() ready for use by setstropt_userpwd(). + +Upstream-commit: bb20989a6384f95a73fd68b0e109fc860e0c7a57 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 221 +++++++++++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 161 insertions(+), 60 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index f03ca0f..3396944 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -141,6 +141,9 @@ static CURLcode do_init(struct connectdata *conn); + static CURLcode parse_url_login(struct SessionHandle *data, + struct connectdata *conn, + char *user, char *passwd, char *options); ++static CURLcode parse_login_details(const char *login, const size_t len, ++ char **userptr, char **passwdptr, ++ char **optionsptr); + /* + * Protocol table. + */ +@@ -4267,6 +4270,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, + #endif /* CURL_DISABLE_PROXY */ + + /* ++ * parse_url_login() + * + * Parse the login details (user name, password and options) from the URL and + * strip them out of the host name +@@ -4285,6 +4289,11 @@ static CURLcode parse_url_login(struct SessionHandle *data, + struct connectdata *conn, + char *user, char *passwd, char *options) + { ++ CURLcode result = CURLE_OK; ++ char *userp = NULL; ++ char *passwdp = NULL; ++ char *optionsp = NULL; ++ + /* At this point, we're hoping all the other special cases have + * been taken care of, so conn->host.name is at most + * [user[:password][;options]]@]hostname +@@ -4293,7 +4302,7 @@ static CURLcode parse_url_login(struct SessionHandle *data, + */ + + char *ptr = strchr(conn->host.name, '@'); +- char *userpass = conn->host.name; ++ char *login = conn->host.name; + + user[0] = 0; /* to make everything well-defined */ + passwd[0] = 0; +@@ -4302,7 +4311,7 @@ static CURLcode parse_url_login(struct SessionHandle *data, + /* We will now try to extract the + * possible login information in a string like: + * ftp://user:password@ftp.my.site:8021/README */ +- if(ptr != NULL) { ++ if(ptr) { + /* There's login information to the left of the @ */ + + conn->host.name = ++ptr; +@@ -4314,80 +4323,172 @@ static CURLcode parse_url_login(struct SessionHandle *data, + */ + + if(data->set.use_netrc != CURL_NETRC_REQUIRED) { +- /* We could use the information in the URL so extract it */ +- if(*userpass != ':') { +- if(*userpass != ';') { +- /* The user is given so extract the user, password and options */ +- int result = sscanf(userpass, +- "%" MAX_CURL_USER_LENGTH_TXT "[^:;@]:" +- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];" +- "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", +- user, passwd, options); +- +- /* The extract failed so extract the user and options instead */ +- if(result == 1) +- sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:;@];" +- "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", +- user, options); +- } +- else { +- /* No name or password are given so extract the options only */ +- sscanf(userpass, ";%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", options); ++ /* We could use the login information in the URL so extract it */ ++ result = parse_login_details(login, ptr - login - 1, ++ &userp, &passwdp, &optionsp); ++ if(!result) { ++ if(userp) { ++ char *newname; ++ ++ /* We have a user in the URL */ ++ conn->bits.userpwd_in_url = TRUE; ++ conn->bits.user_passwd = TRUE; /* enable user+password */ ++ ++ /* Decode the user */ ++ newname = curl_easy_unescape(data, userp, 0, NULL); ++ if(!newname) ++ return CURLE_OUT_OF_MEMORY; ++ ++ if(strlen(newname) < MAX_CURL_USER_LENGTH) ++ strcpy(user, newname); ++ ++ free(newname); + } +- } +- else +- /* No name is given so extract the password and options */ +- sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];" +- "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", +- passwd, options); + +- if(user[0]) { +- char *newname; ++ if(passwdp) { ++ /* We have a password in the URL so decode it */ ++ char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); ++ if(!newpasswd) ++ return CURLE_OUT_OF_MEMORY; + +- /* We have a user in the URL */ +- conn->bits.userpwd_in_url = TRUE; +- conn->bits.user_passwd = TRUE; /* enable user+password */ ++ if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) ++ strcpy(passwd, newpasswd); + +- /* Decode the user */ +- newname = curl_easy_unescape(data, user, 0, NULL); +- if(!newname) +- return CURLE_OUT_OF_MEMORY; ++ free(newpasswd); ++ } ++ ++ if(optionsp) { ++ /* We have an options list in the URL so decode it */ ++ char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); ++ if(!newoptions) ++ return CURLE_OUT_OF_MEMORY; + +- if(strlen(newname) < MAX_CURL_USER_LENGTH) +- strcpy(user, newname); ++ if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) ++ strcpy(options, newoptions); + +- /* if the new name is longer than accepted, then just use +- the unconverted name, it'll be wrong but what the heck */ +- free(newname); ++ free(newoptions); ++ } + } + +- if(passwd[0]) { +- /* We have a password in the URL so decode it */ +- char *newpasswd = curl_easy_unescape(data, passwd, 0, NULL); +- if(!newpasswd) +- return CURLE_OUT_OF_MEMORY; ++ Curl_safefree(userp); ++ Curl_safefree(passwdp); ++ Curl_safefree(optionsp); ++ } ++ } + +- if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) +- strcpy(passwd, newpasswd); ++ return result; ++} + +- free(newpasswd); +- } ++/* ++ * parse_login_details() ++ * ++ * This is used to parse a login string for user name, password and options in ++ * the following formats: ++ * ++ * user ++ * user:password ++ * user:password;options ++ * user;options ++ * user;options:password ++ * :password ++ * :password;options ++ * ;options ++ * ;options:password ++ * ++ * Parameters: ++ * ++ * login [in] - The login string. ++ * len [in] - The length of the login string. ++ * userp [in/out] - The address where a pointer to newly allocated memory ++ * holding the user will be stored upon completion. ++ * passdwp [in/out] - The address where a pointer to newly allocated memory ++ * holding the password will be stored upon completion. ++ * optionsp [in/out] - The address where a pointer to newly allocated memory ++ * holding the options will be stored upon completion. ++ * ++ * Returns CURLE_OK on success. ++ */ ++static CURLcode parse_login_details(const char *login, const size_t len, ++ char **userp, char **passwdp, ++ char **optionsp) ++{ ++ CURLcode result = CURLE_OK; ++ char *utemp = NULL; ++ char *ptemp = NULL; ++ char *otemp = NULL; ++ const char *psep = NULL; ++ const char *osep = NULL; ++ size_t ulen; ++ size_t plen; ++ size_t olen; ++ ++ /* Attempt to find the password separator */ ++ if(passwdp) ++ psep = strchr(login, ':'); ++ ++ /* Attempt to find the options separator */ ++ if(optionsp) ++ osep = strchr(login, ';'); ++ ++ /* Calculate the portion lengths */ ++ ulen = (psep ? ++ (size_t)(osep && psep > osep ? osep - login : psep - login) : ++ (osep ? (size_t)(osep - login) : len)); ++ plen = (psep ? ++ (osep && osep > psep ? (size_t)(osep - psep) : ++ (size_t)(login + len - psep)) - 1 : 0); ++ olen = (osep ? ++ (psep && psep > osep ? (size_t)(psep - osep) : ++ (size_t)(login + len - osep)) - 1 : 0); ++ ++ /* Allocate the user portion temporary buffer */ ++ if(userp && ulen) { ++ utemp = malloc(ulen + 1); ++ if(!utemp) ++ result = CURLE_OUT_OF_MEMORY; ++ } ++ ++ /* Allocate the password portion temporary buffer */ ++ if(!result && passwdp && plen) { ++ ptemp = malloc(plen + 1); ++ if(!ptemp) ++ result = CURLE_OUT_OF_MEMORY; ++ } ++ ++ /* Allocate the options portion temporary buffer */ ++ if(!result && optionsp && olen) { ++ otemp = malloc(olen + 1); ++ if(!otemp) ++ result = CURLE_OUT_OF_MEMORY; ++ } + +- if(options[0]) { +- /* We have an options list in the URL so decode it */ +- char *newoptions = curl_easy_unescape(data, options, 0, NULL); +- if(!newoptions) +- return CURLE_OUT_OF_MEMORY; ++ if(!result) { ++ /* Copy the user portion if necessary */ ++ if(utemp) { ++ memcpy(utemp, login, ulen); ++ utemp[ulen] = '\0'; ++ Curl_safefree(*userp); ++ *userp = utemp; ++ } + +- if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) +- strcpy(options, newoptions); ++ /* Copy the password portion if necessary */ ++ if(ptemp) { ++ memcpy(ptemp, psep + 1, plen); ++ ptemp[plen] = '\0'; ++ Curl_safefree(*passwdp); ++ *passwdp = ptemp; ++ } + +- free(newoptions); +- } ++ /* Copy the options portion if necessary */ ++ if(otemp) { ++ memcpy(otemp, osep + 1, olen); ++ otemp[olen] = '\0'; ++ Curl_safefree(*optionsp); ++ *optionsp = otemp; + } + } + +- return CURLE_OK; ++ return result; + } + + /************************************************************* +-- +2.4.6 + + +From ce1718fc19267ca33e61ac4bff2e3867d6ed460c Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Fri, 19 Apr 2013 19:37:55 +0100 +Subject: [PATCH 05/28] url: Added bounds checking to parse_login_details() + +Added bounds checking when searching for the separator characters within +the login string as this string may not be NULL terminated (For example +it is the login part of a URL). We do this in preference to allocating a +new string to copy the login details into which could then be passed to +parse_login_details() for performance reasons. + +Upstream-commit: 49184c37233c2cf27b79ebcd29fb8a4f5fb2e1ed +Signed-off-by: Kamil Dudka +--- + lib/url.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 3396944..5381872 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4423,13 +4423,23 @@ static CURLcode parse_login_details(const char *login, const size_t len, + size_t olen; + + /* Attempt to find the password separator */ +- if(passwdp) ++ if(passwdp) { + psep = strchr(login, ':'); + ++ /* Within the constraint of the login string */ ++ if(psep >= login + len) ++ psep = NULL; ++ } ++ + /* Attempt to find the options separator */ +- if(optionsp) ++ if(optionsp) { + osep = strchr(login, ';'); + ++ /* Within the constraint of the login string */ ++ if(osep >= login + len) ++ osep = NULL; ++ } ++ + /* Calculate the portion lengths */ + ulen = (psep ? + (size_t)(osep && psep > osep ? osep - login : psep - login) : +-- +2.4.6 + + +From fb76a0dac86f2b82f68b6b3b7538b5057d1c04d9 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sat, 20 Apr 2013 08:47:59 +0100 +Subject: [PATCH 06/28] url: Added support for parsing login options from the + CURLOPT_USERPWD + +In addition to parsing the optional login options from the URL, added +support for parsing them from CURLOPT_USERPWD, to allow the following +supported command line: + +--user username:password;options + +Upstream-commit: fddb7b44a79d78e05043e1c97e069308b6b85f79 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 66 ++++++++++++++++++++++++++++++++++------------------------- + lib/urldata.h | 1 + + 2 files changed, 39 insertions(+), 28 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 5381872..0a47143 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -295,43 +295,52 @@ static CURLcode setstropt(char **charp, char * s) + } + + static CURLcode setstropt_userpwd(char *option, char **user_storage, +- char **pwd_storage) ++ char **pwd_storage, char **options_storage) + { +- char* separator; + CURLcode result = CURLE_OK; ++ char *userp = NULL; ++ char *passwdp = NULL; ++ char *optionsp = NULL; + + if(!option) { + /* we treat a NULL passed in as a hint to clear existing info */ +- Curl_safefree(*user_storage); +- *user_storage = (char *) NULL; +- Curl_safefree(*pwd_storage); +- *pwd_storage = (char *) NULL; ++ if(user_storage) { ++ Curl_safefree(*user_storage); ++ *user_storage = (char *) NULL; ++ } ++ ++ if(pwd_storage) { ++ Curl_safefree(*pwd_storage); ++ *pwd_storage = (char *) NULL; ++ } ++ ++ if(options_storage) { ++ Curl_safefree(*options_storage); ++ *options_storage = (char *) NULL; ++ } ++ + return CURLE_OK; + } + +- separator = strchr(option, ':'); +- if(separator != NULL) { +- ++ /* Parse the login details */ ++ result = parse_login_details(option, strlen(option), ++ (user_storage ? &userp : NULL), ++ (pwd_storage ? &passwdp : NULL), ++ (options_storage ? &optionsp : NULL)); ++ if(!result) { + /* store username part of option */ +- char * p; +- size_t username_len = (size_t)(separator-option); +- p = malloc(username_len+1); +- if(!p) +- result = CURLE_OUT_OF_MEMORY; +- else { +- memcpy(p, option, username_len); +- p[username_len] = '\0'; +- Curl_safefree(*user_storage); +- *user_storage = p; +- } ++ if(user_storage) ++ setstropt(user_storage, userp); + + /* store password part of option */ +- if(result == CURLE_OK) +- result = setstropt(pwd_storage, separator+1); +- } +- else { +- result = setstropt(user_storage, option); ++ if(pwd_storage) ++ setstropt(pwd_storage, passwdp); ++ ++ /* store options part of option */ ++ if(options_storage) ++ setstropt(options_storage, optionsp); + } ++ + return result; + } + +@@ -1546,11 +1555,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + + case CURLOPT_USERPWD: + /* +- * user:password to use in the operation ++ * user:password;options to use in the operation + */ + result = setstropt_userpwd(va_arg(param, char *), + &data->set.str[STRING_USERNAME], +- &data->set.str[STRING_PASSWORD]); ++ &data->set.str[STRING_PASSWORD], ++ &data->set.str[STRING_OPTIONS]); + break; + case CURLOPT_USERNAME: + /* +@@ -1623,7 +1633,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + */ + result = setstropt_userpwd(va_arg(param, char *), + &data->set.str[STRING_PROXYUSERNAME], +- &data->set.str[STRING_PROXYPASSWORD]); ++ &data->set.str[STRING_PROXYPASSWORD], NULL); + break; + case CURLOPT_PROXYUSERNAME: + /* +diff --git a/lib/urldata.h b/lib/urldata.h +index 46ef5d5..1c2281a 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1354,6 +1354,7 @@ enum dupstring { + STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */ + STRING_USERNAME, /* , if used */ + STRING_PASSWORD, /* , if used */ ++ STRING_OPTIONS, /* , if used */ + STRING_PROXYUSERNAME, /* Proxy , if used */ + STRING_PROXYPASSWORD, /* Proxy , if used */ + STRING_NOPROXY, /* List of hosts which should not use the proxy, if +-- +2.4.6 + + +From 32f237261f2c7592db3ba6378c053e63abb744ce Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sat, 20 Apr 2013 09:06:53 +0100 +Subject: [PATCH 07/28] url: Added overriding of URL login options from + CURLOPT_USERPWD + +Upstream-commit: d535c4a2e1f78d4b54767d67e17cca805e2d1f7c +Signed-off-by: Kamil Dudka +--- + lib/url.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 0a47143..8b7aa3a 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4631,20 +4631,26 @@ static CURLcode parse_remote_port(struct SessionHandle *data, + } + + /* +- * Override a user name and password from the URL with that in the +- * CURLOPT_USERPWD option or a .netrc file, if applicable. ++ * Override the login details from the URL with that in the CURLOPT_USERPWD ++ * option or a .netrc file, if applicable. + */ +-static void override_userpass(struct SessionHandle *data, +- struct connectdata *conn, +- char *user, char *passwd) ++static void override_login(struct SessionHandle *data, ++ struct connectdata *conn, ++ char *user, char *passwd, char *options) + { +- if(data->set.str[STRING_USERNAME] != NULL) { ++ if(data->set.str[STRING_USERNAME]) { + strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH); +- user[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/ ++ user[MAX_CURL_USER_LENGTH - 1] = '\0'; /* To be on safe side */ + } +- if(data->set.str[STRING_PASSWORD] != NULL) { ++ ++ if(data->set.str[STRING_PASSWORD]) { + strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH); +- passwd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ ++ passwd[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */ ++ } ++ ++ if(data->set.str[STRING_OPTIONS]) { ++ strncpy(options, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH); ++ options[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */ + } + + conn->bits.netrc = FALSE; +@@ -5149,11 +5155,8 @@ static CURLcode create_conn(struct SessionHandle *data, + if(result != CURLE_OK) + return result; + +- /************************************************************* +- * Check for an overridden user name and password, then set it +- * for use +- *************************************************************/ +- override_userpass(data, conn, user, passwd); ++ /* Check for overridden login details and set them accordingly */ ++ override_login(data, conn, user, passwd, options); + result = set_login(conn, user, passwd, options); + if(result != CURLE_OK) + return result; +-- +2.4.6 + + +From 4876aa898d1d0b012328c3ddc96fd2023464584e Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sat, 20 Apr 2013 18:40:13 +0100 +Subject: [PATCH 08/28] url: Fixed memory leak in setstropt_userpwd() + +setstropt_userpwd() was calling setstropt() in commit fddb7b44a79d to +set each of the login details which would duplicate the strings and +subsequently cause a memory leak. + +Upstream-commit: fe880475ed3c7e51e32e19112252c79e921cc31b +Signed-off-by: Kamil Dudka +--- + lib/url.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 8b7aa3a..5e27818 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -330,15 +330,18 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage, + if(!result) { + /* store username part of option */ + if(user_storage) +- setstropt(user_storage, userp); ++ Curl_safefree(*user_storage); ++ *user_storage = userp; + + /* store password part of option */ + if(pwd_storage) +- setstropt(pwd_storage, passwdp); ++ Curl_safefree(*pwd_storage); ++ *pwd_storage = passwdp; + + /* store options part of option */ + if(options_storage) +- setstropt(options_storage, optionsp); ++ Curl_safefree(*options_storage); ++ *options_storage = optionsp; + } + + return result; +-- +2.4.6 + + +From d0d89877466515b3ec17bc7c5987f4fec906e92e Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sat, 20 Apr 2013 19:10:10 +0100 +Subject: [PATCH 09/28] url: Correction to scope of if statements when setting + data + +Upstream-commit: e99c81a07c0c8752a286e0f14174ae7ae114090c +Signed-off-by: Kamil Dudka +--- + lib/url.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 5e27818..ffd80a5 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -329,19 +329,22 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage, + (options_storage ? &optionsp : NULL)); + if(!result) { + /* store username part of option */ +- if(user_storage) ++ if(user_storage) { + Curl_safefree(*user_storage); + *user_storage = userp; ++ } + + /* store password part of option */ +- if(pwd_storage) ++ if(pwd_storage) { + Curl_safefree(*pwd_storage); + *pwd_storage = passwdp; ++ } + + /* store options part of option */ +- if(options_storage) ++ if(options_storage) { + Curl_safefree(*options_storage); + *options_storage = optionsp; ++ } + } + + return result; +-- +2.4.6 + + +From f45b4761cdb3b88647aa4b7eee89bb45dfd7c7bc Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sat, 20 Apr 2013 20:01:40 +0100 +Subject: [PATCH 10/28] url: Simplified setstropt_userpwd() following recent + changes + +There is no need to perform separate clearing of data if a NULL option +pointer is passed in. Instead this operation can be performed by simply +not calling parse_login_details() and letting the rest of the code do +the work. + +Upstream-commit: bddf3d4705ed8e0999200c92de191db8e2441b3a +Signed-off-by: Kamil Dudka +--- + lib/url.c | 30 +++++++----------------------- + 1 file changed, 7 insertions(+), 23 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index ffd80a5..5f1bef2 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -302,31 +302,15 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage, + char *passwdp = NULL; + char *optionsp = NULL; + +- if(!option) { +- /* we treat a NULL passed in as a hint to clear existing info */ +- if(user_storage) { +- Curl_safefree(*user_storage); +- *user_storage = (char *) NULL; +- } +- +- if(pwd_storage) { +- Curl_safefree(*pwd_storage); +- *pwd_storage = (char *) NULL; +- } +- +- if(options_storage) { +- Curl_safefree(*options_storage); +- *options_storage = (char *) NULL; +- } +- +- return CURLE_OK; ++ /* Parse the login details if specified. It not then we treat NULL as a hint ++ to clear the existing data */ ++ if(option) { ++ result = parse_login_details(option, strlen(option), ++ (user_storage ? &userp : NULL), ++ (pwd_storage ? &passwdp : NULL), ++ (options_storage ? &optionsp : NULL)); + } + +- /* Parse the login details */ +- result = parse_login_details(option, strlen(option), +- (user_storage ? &userp : NULL), +- (pwd_storage ? &passwdp : NULL), +- (options_storage ? &optionsp : NULL)); + if(!result) { + /* store username part of option */ + if(user_storage) { +-- +2.4.6 + + +From 34d2d13cdc6a50ea80c45366ea78487cca8f0fc4 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 21 Apr 2013 10:08:17 +0100 +Subject: [PATCH 11/28] url: Tidy up of code and comments following recent + changes + +Tidy up of variable names and comments in setstropt_userpwd() and +parse_login_details(). + +Upstream-commit: e8a9f794f048251f94d59cc1d4ef7e9516b0c4e7 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 84 +++++++++++++++++++++++++++++++-------------------------------- + 1 file changed, 42 insertions(+), 42 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 5f1bef2..5f9fd6f 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -261,7 +261,7 @@ static const struct Curl_handler Curl_handler_dummy = { + PROTOPT_NONE /* flags */ + }; + +-void Curl_freeset(struct SessionHandle * data) ++void Curl_freeset(struct SessionHandle *data) + { + /* Free all dynamic strings stored in the data->set substructure. */ + enum dupstring i; +@@ -275,7 +275,7 @@ void Curl_freeset(struct SessionHandle * data) + data->change.referer = NULL; + } + +-static CURLcode setstropt(char **charp, char * s) ++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. */ +@@ -298,43 +298,43 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage, + char **pwd_storage, char **options_storage) + { + CURLcode result = CURLE_OK; +- char *userp = NULL; +- char *passwdp = NULL; +- char *optionsp = NULL; ++ char *user = NULL; ++ char *passwd = NULL; ++ char *options = NULL; + + /* Parse the login details if specified. It not then we treat NULL as a hint + to clear the existing data */ + if(option) { + result = parse_login_details(option, strlen(option), +- (user_storage ? &userp : NULL), +- (pwd_storage ? &passwdp : NULL), +- (options_storage ? &optionsp : NULL)); ++ (user_storage ? &user : NULL), ++ (pwd_storage ? &passwd : NULL), ++ (options_storage ? &options : NULL)); + } + + if(!result) { +- /* store username part of option */ ++ /* Store the username part of option if required */ + if(user_storage) { + Curl_safefree(*user_storage); +- *user_storage = userp; ++ *user_storage = user; + } + +- /* store password part of option */ ++ /* Store the password part of option if required */ + if(pwd_storage) { + Curl_safefree(*pwd_storage); +- *pwd_storage = passwdp; ++ *pwd_storage = passwd; + } + +- /* store options part of option */ ++ /* Store the options part of option if required */ + if(options_storage) { + Curl_safefree(*options_storage); +- *options_storage = optionsp; ++ *options_storage = options; + } + } + + return result; + } + +-CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src) ++CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) + { + CURLcode r = CURLE_OK; + enum dupstring i; +@@ -4413,9 +4413,9 @@ static CURLcode parse_login_details(const char *login, const size_t len, + char **optionsp) + { + CURLcode result = CURLE_OK; +- char *utemp = NULL; +- char *ptemp = NULL; +- char *otemp = NULL; ++ char *ubuf = NULL; ++ char *pbuf = NULL; ++ char *obuf = NULL; + const char *psep = NULL; + const char *osep = NULL; + size_t ulen; +@@ -4451,50 +4451,50 @@ static CURLcode parse_login_details(const char *login, const size_t len, + (psep && psep > osep ? (size_t)(psep - osep) : + (size_t)(login + len - osep)) - 1 : 0); + +- /* Allocate the user portion temporary buffer */ ++ /* Allocate the user portion buffer */ + if(userp && ulen) { +- utemp = malloc(ulen + 1); +- if(!utemp) ++ ubuf = malloc(ulen + 1); ++ if(!ubuf) + result = CURLE_OUT_OF_MEMORY; + } + +- /* Allocate the password portion temporary buffer */ ++ /* Allocate the password portion buffer */ + if(!result && passwdp && plen) { +- ptemp = malloc(plen + 1); +- if(!ptemp) ++ pbuf = malloc(plen + 1); ++ if(!pbuf) + result = CURLE_OUT_OF_MEMORY; + } + +- /* Allocate the options portion temporary buffer */ ++ /* Allocate the options portion buffer */ + if(!result && optionsp && olen) { +- otemp = malloc(olen + 1); +- if(!otemp) ++ obuf = malloc(olen + 1); ++ if(!obuf) + result = CURLE_OUT_OF_MEMORY; + } + + if(!result) { +- /* Copy the user portion if necessary */ +- if(utemp) { +- memcpy(utemp, login, ulen); +- utemp[ulen] = '\0'; ++ /* Store the user portion if necessary */ ++ if(ubuf) { ++ memcpy(ubuf, login, ulen); ++ ubuf[ulen] = '\0'; + Curl_safefree(*userp); +- *userp = utemp; ++ *userp = ubuf; + } + +- /* Copy the password portion if necessary */ +- if(ptemp) { +- memcpy(ptemp, psep + 1, plen); +- ptemp[plen] = '\0'; ++ /* Store the password portion if necessary */ ++ if(pbuf) { ++ memcpy(pbuf, psep + 1, plen); ++ pbuf[plen] = '\0'; + Curl_safefree(*passwdp); +- *passwdp = ptemp; ++ *passwdp = pbuf; + } + +- /* Copy the options portion if necessary */ +- if(otemp) { +- memcpy(otemp, osep + 1, olen); +- otemp[olen] = '\0'; ++ /* Store the options portion if necessary */ ++ if(obuf) { ++ memcpy(obuf, osep + 1, olen); ++ obuf[olen] = '\0'; + Curl_safefree(*optionsp); +- *optionsp = otemp; ++ *optionsp = obuf; + } + } + +-- +2.4.6 + + +From 58e3995c51150621185e9e0ebcbd943403a2df9c Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 21 Apr 2013 10:16:51 +0100 +Subject: [PATCH 12/28] url: Tidy up of setstropt_userpwd() parameters + +Updated the naming convention of the login parameters to match those of +other functions. + +Upstream-commit: 702b0dd408d5e847aad99d44dcd79366c61835eb +Signed-off-by: Kamil Dudka +--- + lib/url.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 5f9fd6f..2e691c3 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -294,8 +294,8 @@ static CURLcode setstropt(char **charp, char *s) + return CURLE_OK; + } + +-static CURLcode setstropt_userpwd(char *option, char **user_storage, +- char **pwd_storage, char **options_storage) ++static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp, ++ char **optionsp) + { + CURLcode result = CURLE_OK; + char *user = NULL; +@@ -306,28 +306,28 @@ static CURLcode setstropt_userpwd(char *option, char **user_storage, + to clear the existing data */ + if(option) { + result = parse_login_details(option, strlen(option), +- (user_storage ? &user : NULL), +- (pwd_storage ? &passwd : NULL), +- (options_storage ? &options : NULL)); ++ (userp ? &user : NULL), ++ (passwdp ? &passwd : NULL), ++ (optionsp ? &options : NULL)); + } + + if(!result) { + /* Store the username part of option if required */ +- if(user_storage) { +- Curl_safefree(*user_storage); +- *user_storage = user; ++ if(userp) { ++ Curl_safefree(*userp); ++ *userp = user; + } + + /* Store the password part of option if required */ +- if(pwd_storage) { +- Curl_safefree(*pwd_storage); +- *pwd_storage = passwd; ++ if(passwdp) { ++ Curl_safefree(*passwdp); ++ *passwdp = passwd; + } + + /* Store the options part of option if required */ +- if(options_storage) { +- Curl_safefree(*options_storage); +- *options_storage = options; ++ if(optionsp) { ++ Curl_safefree(*optionsp); ++ *optionsp = options; + } + } + +-- +2.4.6 + + +From 956dfd17565bb95ebf8cd7f7a2fe5a76e7da1898 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 21 Apr 2013 12:08:35 +0100 +Subject: [PATCH 13/28] url: Updated proxy URL parsing to use + parse_login_details() + +Upstream-commit: 11332577b3cbd76f9fc418f3ae11133e4089fa1c +Signed-off-by: Kamil Dudka +--- + lib/url.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 2e691c3..a272087 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4137,16 +4137,13 @@ static CURLcode parse_proxy(struct SessionHandle *data, + /* Is there a username and password given in this proxy url? */ + atsign = strchr(proxyptr, '@'); + if(atsign) { +- char proxyuser[MAX_CURL_USER_LENGTH]; +- char proxypasswd[MAX_CURL_PASSWORD_LENGTH]; +- proxypasswd[0] = 0; +- +- if(1 <= sscanf(proxyptr, +- "%" MAX_CURL_USER_LENGTH_TXT"[^:@]:" +- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", +- proxyuser, proxypasswd)) { +- CURLcode res = CURLE_OK; ++ CURLcode res = CURLE_OK; ++ char *proxyuser = NULL; ++ char *proxypasswd = NULL; + ++ res = parse_login_details(proxyptr, atsign - proxyptr, ++ &proxyuser, &proxypasswd, NULL); ++ if(!res) { + /* found user and password, rip them out. note that we are + unescaping them, as there is otherwise no way to have a + username or password with reserved characters like ':' in +@@ -4164,7 +4161,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, + res = CURLE_OUT_OF_MEMORY; + } + +- if(CURLE_OK == res) { ++ if(!res) { + conn->bits.proxy_user_passwd = TRUE; /* enable it */ + atsign++; /* the right side of the @-letter */ + +@@ -4173,10 +4170,13 @@ static CURLcode parse_proxy(struct SessionHandle *data, + else + res = CURLE_OUT_OF_MEMORY; + } +- +- if(res) +- return res; + } ++ ++ Curl_safefree(proxyuser); ++ Curl_safefree(proxypasswd); ++ ++ if(res) ++ return res; + } + + /* start scanning for port number at this point */ +-- +2.4.6 + + +From e2480db78651e3d1e2f5939d09b7ada54af0bdf4 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 21 Apr 2013 16:55:19 +0100 +Subject: [PATCH 14/28] url: Fixed crash when no username or password supplied + for proxy + +Fixed an issue in parse_proxy(), introduced in commit 11332577b3cb, +where an empty username or password (For example: http://:@example.com) +would cause a crash. + +Upstream-commit: 416ecc15845c4e6bf7ea6359d9c63adec3385f5b +Signed-off-by: Kamil Dudka +--- + lib/url.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index a272087..736f4d9 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4149,13 +4149,19 @@ static CURLcode parse_proxy(struct SessionHandle *data, + username or password with reserved characters like ':' in + them. */ + Curl_safefree(conn->proxyuser); +- conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); ++ if(proxyuser) ++ conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); ++ else ++ conn->proxyuser = strdup(""); + + if(!conn->proxyuser) + res = CURLE_OUT_OF_MEMORY; + else { + Curl_safefree(conn->proxypasswd); +- conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); ++ if(proxypasswd) ++ conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); ++ else ++ conn->proxypasswd = strdup(""); + + if(!conn->proxypasswd) + res = CURLE_OUT_OF_MEMORY; +-- +2.4.6 + + +From c77ec0c919be4f86cd5fb70fa6813b28b376f48e Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 21 Apr 2013 18:29:33 +0100 +Subject: [PATCH 15/28] url: Fixed missing length check in parse_proxy() + +Commit 11332577b3cb removed the length check that was performed by the +old scanf() code. + +Upstream-commit: ddac43b38e3fd923b71554126652b05e034d6900 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 736f4d9..ede7d1c 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4149,7 +4149,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, + username or password with reserved characters like ':' in + them. */ + Curl_safefree(conn->proxyuser); +- if(proxyuser) ++ if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH) + conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); + else + conn->proxyuser = strdup(""); +@@ -4158,7 +4158,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, + res = CURLE_OUT_OF_MEMORY; + else { + Curl_safefree(conn->proxypasswd); +- if(proxypasswd) ++ if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) + conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); + else + conn->proxypasswd = strdup(""); +-- +2.4.6 + + +From 4d396dba81cde42581a313a2dbe983a1d985045a Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Sun, 30 Jun 2013 19:51:16 +0200 +Subject: [PATCH 16/28] url: restore the functionality of 'curl -u :' + +This commit fixes a regression introduced in +fddb7b44a79d78e05043e1c97e069308b6b85f79. + +Reported by: Markus Moeller +Bug: http://curl.haxx.se/mail/archive-2013-06/0052.html + +Upstream-commit: abca89aaa0fb208cfaf4ead6692014c4e553388a +Signed-off-by: Kamil Dudka +--- + lib/url.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/lib/url.c b/lib/url.c +index ede7d1c..a2b9abb 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -314,6 +314,13 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp, + if(!result) { + /* Store the username part of option if required */ + if(userp) { ++ if(!user && option && option[0] == ':') { ++ /* Allocate an empty string instead of returning NULL as user name */ ++ user = strdup(""); ++ if(!user) ++ result = CURLE_OUT_OF_MEMORY; ++ } ++ + Curl_safefree(*userp); + *userp = user; + } +-- +2.4.6 + + +From 0df43fcefa7ba9f47e509b4a55edd6b287dd962e Mon Sep 17 00:00:00 2001 +From: Yang Tse +Date: Fri, 12 Jul 2013 12:16:48 +0200 +Subject: [PATCH 17/28] url.c: fix parse_login_details() OOM handling + +Upstream-commit: 83f0dae1292b8b9b2507457db6b3ab22ba31c64b +Signed-off-by: Kamil Dudka +--- + lib/url.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index a2b9abb..61ca8e8 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4474,15 +4474,20 @@ static CURLcode parse_login_details(const char *login, const size_t len, + /* Allocate the password portion buffer */ + if(!result && passwdp && plen) { + pbuf = malloc(plen + 1); +- if(!pbuf) ++ if(!pbuf) { ++ Curl_safefree(ubuf); + result = CURLE_OUT_OF_MEMORY; ++ } + } + + /* Allocate the options portion buffer */ + if(!result && optionsp && olen) { + obuf = malloc(olen + 1); +- if(!obuf) ++ if(!obuf) { ++ Curl_safefree(pbuf); ++ Curl_safefree(ubuf); + result = CURLE_OUT_OF_MEMORY; ++ } + } + + if(!result) { +-- +2.4.6 + + +From 386bc0349e102cbe9a0417688e15ea7e13cf4dd8 Mon Sep 17 00:00:00 2001 +From: Yang Tse +Date: Sun, 14 Jul 2013 12:19:57 +0200 +Subject: [PATCH 18/28] url.c: fix parse_url_login() OOM handling + +Upstream-commit: cfc907e43d5f25a50a9fae95a37a4c0e959d591a +Signed-off-by: Kamil Dudka +--- + lib/url.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 61ca8e8..92a126a 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4349,8 +4349,12 @@ static CURLcode parse_url_login(struct SessionHandle *data, + + /* Decode the user */ + newname = curl_easy_unescape(data, userp, 0, NULL); +- if(!newname) ++ if(!newname) { ++ Curl_safefree(userp); ++ Curl_safefree(passwdp); ++ Curl_safefree(optionsp); + return CURLE_OUT_OF_MEMORY; ++ } + + if(strlen(newname) < MAX_CURL_USER_LENGTH) + strcpy(user, newname); +@@ -4361,8 +4365,12 @@ static CURLcode parse_url_login(struct SessionHandle *data, + if(passwdp) { + /* We have a password in the URL so decode it */ + char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); +- if(!newpasswd) ++ if(!newpasswd) { ++ Curl_safefree(userp); ++ Curl_safefree(passwdp); ++ Curl_safefree(optionsp); + return CURLE_OUT_OF_MEMORY; ++ } + + if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) + strcpy(passwd, newpasswd); +@@ -4373,8 +4381,12 @@ static CURLcode parse_url_login(struct SessionHandle *data, + if(optionsp) { + /* We have an options list in the URL so decode it */ + char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); +- if(!newoptions) ++ if(!newoptions) { ++ Curl_safefree(userp); ++ Curl_safefree(passwdp); ++ Curl_safefree(optionsp); + return CURLE_OUT_OF_MEMORY; ++ } + + if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) + strcpy(options, newoptions); +-- +2.4.6 + + +From ca108f78f894fee22eadf46ec6ef4282d1f23949 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Mon, 19 Aug 2013 00:38:08 -0700 +Subject: [PATCH 19/28] url: use goto in create_conn() for exception handling + +Instead of remembering before each "return" statement which temporary +allocations, if any, need to be freed, take care to set pointers to +NULL when no longer needed and use a goto to a common block to exit +the function and free all temporaries. + +No functional change intended. Currently the only temporary buffer in +this function is "proxy" which is already correctly freed when +appropriate, but there will be more soon. + +Upstream-commit: 53333a43a1959ddeef27c26f0983be1b81e558bc +Signed-off-by: Kamil Dudka +--- + lib/url.c | 64 +++++++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 38 insertions(+), 26 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 92a126a..105f2fe 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4924,8 +4924,10 @@ static CURLcode create_conn(struct SessionHandle *data, + * Check input data + *************************************************************/ + +- if(!data->change.url) +- return CURLE_URL_MALFORMAT; ++ if(!data->change.url) { ++ result = CURLE_URL_MALFORMAT; ++ goto out; ++ } + + /* First, split up the current URL in parts so that we can use the + parts for checking against the already present connections. In order +@@ -4933,8 +4935,10 @@ static CURLcode create_conn(struct SessionHandle *data, + connection data struct and fill in for comparison purposes. */ + conn = allocate_conn(data); + +- if(!conn) +- return CURLE_OUT_OF_MEMORY; ++ if(!conn) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } + + /* We must set the return variable as soon as possible, so that our + parent can cleanup any possible allocs we may have done before +@@ -4964,15 +4968,18 @@ static CURLcode create_conn(struct SessionHandle *data, + data->state.path = NULL; + + data->state.pathbuffer = malloc(urllen+2); +- if(NULL == data->state.pathbuffer) +- return CURLE_OUT_OF_MEMORY; /* really bad error */ ++ if(NULL == data->state.pathbuffer) { ++ result = CURLE_OUT_OF_MEMORY; /* really bad error */ ++ goto out; ++ } + data->state.path = data->state.pathbuffer; + + conn->host.rawalloc = malloc(urllen+2); + if(NULL == conn->host.rawalloc) { + Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; +- return CURLE_OUT_OF_MEMORY; ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; + } + + conn->host.name = conn->host.rawalloc; +@@ -4981,7 +4988,7 @@ static CURLcode create_conn(struct SessionHandle *data, + result = parseurlandfillconn(data, conn, &prot_missing, user, passwd, + options); + if(result != CURLE_OK) +- return result; ++ goto out; + + /************************************************************* + * No protocol part in URL was used, add it! +@@ -4995,8 +5002,8 @@ static CURLcode create_conn(struct SessionHandle *data, + reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url); + + if(!reurl) { +- Curl_safefree(proxy); +- return CURLE_OUT_OF_MEMORY; ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; + } + + if(data->change.url_alloc) { +@@ -5033,7 +5040,7 @@ static CURLcode create_conn(struct SessionHandle *data, + if(conn->bits.proxy_user_passwd) { + result = parse_proxy_auth(data, conn); + if(result != CURLE_OK) +- return result; ++ goto out; + } + + /************************************************************* +@@ -5044,7 +5051,8 @@ static CURLcode create_conn(struct SessionHandle *data, + /* if global proxy is set, this is it */ + if(NULL == proxy) { + failf(data, "memory shortage"); +- return CURLE_OUT_OF_MEMORY; ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; + } + } + +@@ -5072,16 +5080,17 @@ static CURLcode create_conn(struct SessionHandle *data, + if(proxy) { + result = parse_proxy(data, conn, proxy); + +- free(proxy); /* parse_proxy copies the proxy string */ ++ Curl_safefree(proxy); /* parse_proxy copies the proxy string */ + + if(result) +- return result; ++ goto out; + + if((conn->proxytype == CURLPROXY_HTTP) || + (conn->proxytype == CURLPROXY_HTTP_1_0)) { + #ifdef CURL_DISABLE_HTTP + /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ +- return CURLE_UNSUPPORTED_PROTOCOL; ++ result = CURLE_UNSUPPORTED_PROTOCOL; ++ goto out; + #else + /* force this connection's protocol to become HTTP if not already + compatible - if it isn't tunneling through */ +@@ -5111,10 +5120,8 @@ static CURLcode create_conn(struct SessionHandle *data, + * we figured out what/if proxy to use. + *************************************************************/ + result = setup_connection_internals(conn); +- if(result != CURLE_OK) { +- Curl_safefree(proxy); +- return result; +- } ++ if(result != CURLE_OK) ++ goto out; + + conn->recv[FIRSTSOCKET] = Curl_recv_plain; + conn->send[FIRSTSOCKET] = Curl_send_plain; +@@ -5147,7 +5154,7 @@ static CURLcode create_conn(struct SessionHandle *data, + DEBUGASSERT(conn->handler->done); + /* we ignore the return code for the protocol-specific DONE */ + (void)conn->handler->done(conn, result, FALSE); +- return result; ++ goto out; + } + + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */ +@@ -5157,7 +5164,7 @@ static CURLcode create_conn(struct SessionHandle *data, + /* since we skip do_init() */ + Curl_speedinit(data); + +- return result; ++ goto out; + } + #endif + +@@ -5173,13 +5180,13 @@ static CURLcode create_conn(struct SessionHandle *data, + *************************************************************/ + result = parse_remote_port(data, conn); + if(result != CURLE_OK) +- return result; ++ goto out; + + /* Check for overridden login details and set them accordingly */ + override_login(data, conn, user, passwd, options); + result = set_login(conn, user, passwd, options); + if(result != CURLE_OK) +- return result; ++ goto out; + + /* Get a cloned copy of the SSL config situation stored in the + connection struct. But to get this going nicely, we must first make +@@ -5202,8 +5209,10 @@ static CURLcode create_conn(struct SessionHandle *data, + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; + #endif + +- if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) +- return CURLE_OUT_OF_MEMORY; ++ if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } + + /************************************************************* + * Check the current list of connections to see if we can +@@ -5256,7 +5265,7 @@ static CURLcode create_conn(struct SessionHandle *data, + */ + result = setup_range(data); + if(result) +- return result; ++ goto out; + + /* Continue connectdata initialization here. */ + +@@ -5274,6 +5283,9 @@ static CURLcode create_conn(struct SessionHandle *data, + *************************************************************/ + result = resolve_server(data, conn, async); + ++ out: ++ ++ Curl_safefree(proxy); + return result; + } + +-- +2.4.6 + + +From 2f81fdaa7a966ba8e0bfaae29d86426b7e8159bd Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Mon, 19 Aug 2013 00:39:05 -0700 +Subject: [PATCH 20/28] url: allocate username, password, and options on the + heap + +This makes it possible to increase the size of the buffers when needed +in later patches. No functional change yet. + +Upstream-commit: 11baffbff67eae225f63fc684d80ce52a79c8ac5 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 105f2fe..6bce0bb 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4911,9 +4911,9 @@ static CURLcode create_conn(struct SessionHandle *data, + struct connectdata *conn; + struct connectdata *conn_temp = NULL; + size_t urllen; +- char user[MAX_CURL_USER_LENGTH]; +- char passwd[MAX_CURL_PASSWORD_LENGTH]; +- char options[MAX_CURL_OPTIONS_LENGTH]; ++ char *user = NULL; ++ char *passwd = NULL; ++ char *options = NULL; + bool reuse; + char *proxy = NULL; + bool prot_missing = FALSE; +@@ -4985,6 +4985,14 @@ static CURLcode create_conn(struct SessionHandle *data, + conn->host.name = conn->host.rawalloc; + conn->host.name[0] = 0; + ++ user = malloc(MAX_CURL_USER_LENGTH); ++ passwd = malloc(MAX_CURL_PASSWORD_LENGTH); ++ options = malloc(MAX_CURL_OPTIONS_LENGTH); ++ if(!user || !passwd || !options) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } ++ + result = parseurlandfillconn(data, conn, &prot_missing, user, passwd, + options); + if(result != CURLE_OK) +@@ -5285,6 +5293,9 @@ static CURLcode create_conn(struct SessionHandle *data, + + out: + ++ Curl_safefree(options); ++ Curl_safefree(passwd); ++ Curl_safefree(user); + Curl_safefree(proxy); + return result; + } +-- +2.4.6 + + +From 978711e025bcbd1654758b648db4317d0e446f84 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Mon, 19 Aug 2013 00:48:24 -0700 +Subject: [PATCH 21/28] netrc: handle longer username and password + +libcurl truncates usernames and passwords it reads from .netrc to +LOGINSIZE and PASSWORDSIZE (64) characters without any indication to +the user, to ensure the values returned from Curl_parsenetrc fit in a +caller-provided buffer. + +Fix the interface by passing back dynamically allocated buffers +allocated to fit the user's input. The parser still relies on a +256-character buffer to read each line, though. + +So now you can include an ~246-character password in your .netrc, +instead of the previous limit of 63 characters. + +Reported-by: Colby Ranger + +Upstream-commit: 36585b539543ca4471ab19c0d738a6e52a827aee +Signed-off-by: Kamil Dudka +--- + lib/netrc.c | 20 ++++++++++++------- + lib/netrc.h | 16 ++++++---------- + lib/url.c | 18 ++++++++--------- + tests/unit/unit1304.c | 53 ++++++++++++++++++++++++++++++--------------------- + 4 files changed, 59 insertions(+), 48 deletions(-) + +diff --git a/lib/netrc.c b/lib/netrc.c +index 2c5942a..f51fdf3 100644 +--- a/lib/netrc.c ++++ b/lib/netrc.c +@@ -52,13 +52,13 @@ enum host_lookup_state { + * @unittest: 1304 + */ + int Curl_parsenetrc(const char *host, +- char *login, +- char *password, ++ char **loginp, ++ char **passwordp, + char *netrcfile) + { + FILE *file; + int retcode=1; +- int specific_login = (login[0] != 0); ++ int specific_login = (**loginp != 0); + char *home = NULL; + bool home_alloc = FALSE; + bool netrc_alloc = FALSE; +@@ -109,7 +109,7 @@ int Curl_parsenetrc(const char *host, + tok=strtok_r(netrcbuffer, " \t\n", &tok_buf); + while(!done && tok) { + +- if(login[0] && password[0]) { ++ if(**loginp && **passwordp) { + done=TRUE; + break; + } +@@ -138,16 +138,22 @@ int Curl_parsenetrc(const char *host, + /* we are now parsing sub-keywords concerning "our" host */ + if(state_login) { + if(specific_login) { +- state_our_login = Curl_raw_equal(login, tok); ++ state_our_login = Curl_raw_equal(*loginp, tok); + } + else { +- strncpy(login, tok, LOGINSIZE-1); ++ free(*loginp); ++ *loginp = strdup(tok); ++ if(!*loginp) ++ return -1; /* allocation failed */ + } + state_login=0; + } + else if(state_password) { + if(state_our_login || !specific_login) { +- strncpy(password, tok, PASSWORDSIZE-1); ++ free(*passwordp); ++ *passwordp = strdup(tok); ++ if(!*passwordp) ++ return -1; /* allocation failed */ + } + state_password=0; + } +diff --git a/lib/netrc.h b/lib/netrc.h +index 4db764d..a145601 100644 +--- a/lib/netrc.h ++++ b/lib/netrc.h +@@ -22,19 +22,15 @@ + * + ***************************************************************************/ + +-/* Make sure we have room for at least this size: */ +-#define LOGINSIZE 64 +-#define PASSWORDSIZE 64 +- + /* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */ + int Curl_parsenetrc(const char *host, +- char *login, +- char *password, ++ char **loginp, ++ char **passwordp, + char *filename); +- /* Assume: password[0]=0, host[0] != 0. +- * If login[0] = 0, search for login and password within a machine section +- * in the netrc. +- * If login[0] != 0, search for password within machine and login. ++ /* Assume: (*passwordp)[0]=0, host[0] != 0. ++ * If (*loginp)[0] = 0, search for login and password within a machine ++ * section in the netrc. ++ * If (*loginp)[0] != 0, search for password within machine and login. + */ + + #endif /* HEADER_CURL_NETRC_H */ +diff --git a/lib/url.c b/lib/url.c +index 6bce0bb..406ef85 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4656,27 +4656,27 @@ static CURLcode parse_remote_port(struct SessionHandle *data, + */ + static void override_login(struct SessionHandle *data, + struct connectdata *conn, +- char *user, char *passwd, char *options) ++ char **userp, char **passwdp, char **optionsp) + { + if(data->set.str[STRING_USERNAME]) { +- strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH); +- user[MAX_CURL_USER_LENGTH - 1] = '\0'; /* To be on safe side */ ++ strncpy(*userp, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH); ++ (*userp)[MAX_CURL_USER_LENGTH - 1] = '\0'; /* To be on safe side */ + } + + if(data->set.str[STRING_PASSWORD]) { +- strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH); +- passwd[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */ ++ strncpy(*passwdp, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH); ++ (*passwdp)[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */ + } + + if(data->set.str[STRING_OPTIONS]) { +- strncpy(options, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH); +- options[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */ ++ strncpy(*optionsp, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH); ++ (*optionsp)[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */ + } + + conn->bits.netrc = FALSE; + if(data->set.use_netrc != CURL_NETRC_IGNORED) { + if(Curl_parsenetrc(conn->host.name, +- user, passwd, ++ userp, passwdp, + data->set.str[STRING_NETRC_FILE])) { + infof(data, "Couldn't find host %s in the " + DOT_CHAR "netrc file; using defaults\n", +@@ -5191,7 +5191,7 @@ static CURLcode create_conn(struct SessionHandle *data, + goto out; + + /* Check for overridden login details and set them accordingly */ +- override_login(data, conn, user, passwd, options); ++ override_login(data, conn, &user, &passwd, &options); + result = set_login(conn, user, passwd, options); + if(result != CURLE_OK) + goto out; +diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c +index 8ddd8ca..9242e80 100644 +--- a/tests/unit/unit1304.c ++++ b/tests/unit/unit1304.c +@@ -23,14 +23,14 @@ + + #include "netrc.h" + +-static char login[LOGINSIZE]; +-static char password[PASSWORDSIZE]; ++static char *login; ++static char *password; + static char filename[64]; + + static CURLcode unit_setup(void) + { +- password[0] = 0; +- login[0] = 0; ++ password = strdup(""); ++ login = strdup(""); + return CURLE_OK; + } + +@@ -47,7 +47,7 @@ UNITTEST_START + /* + * Test a non existent host in our netrc file. + */ +- result = Curl_parsenetrc("test.example.com", login, password, filename); ++ result = Curl_parsenetrc("test.example.com", &login, &password, filename); + fail_unless(result == 1, "Host not found should return 1"); + fail_unless(password[0] == 0, "password should not have been changed"); + fail_unless(login[0] == 0, "login should not have been changed"); +@@ -55,8 +55,9 @@ UNITTEST_START + /* + * Test a non existent login in our netrc file. + */ +- memcpy(login, "me", 2); +- result = Curl_parsenetrc("example.com", login, password, filename); ++ free(login); ++ login = strdup("me"); ++ result = Curl_parsenetrc("example.com", &login, &password, filename); + fail_unless(result == 0, "Host should be found"); + fail_unless(password[0] == 0, "password should not have been changed"); + fail_unless(strncmp(login, "me", 2) == 0, "login should not have been changed"); +@@ -64,8 +65,9 @@ UNITTEST_START + /* + * Test a non existent login and host in our netrc file. + */ +- memcpy(login, "me", 2); +- result = Curl_parsenetrc("test.example.com", login, password, filename); ++ free(login); ++ login = strdup("me"); ++ result = Curl_parsenetrc("test.example.com", &login, &password, filename); + fail_unless(result == 1, "Host should be found"); + fail_unless(password[0] == 0, "password should not have been changed"); + fail_unless(strncmp(login, "me", 2) == 0, "login should not have been changed"); +@@ -74,8 +76,9 @@ UNITTEST_START + * Test a non existent login (substring of an existing one) in our + * netrc file. + */ +- memcpy(login, "admi", 4); +- result = Curl_parsenetrc("example.com", login, password, filename); ++ free(login); ++ login = strdup("admi"); ++ result = Curl_parsenetrc("example.com", &login, &password, filename); + fail_unless(result == 0, "Host should be found"); + fail_unless(password[0] == 0, "password should not have been changed"); + fail_unless(strncmp(login, "admi", 4) == 0, "login should not have been changed"); +@@ -84,8 +87,9 @@ UNITTEST_START + * Test a non existent login (superstring of an existing one) + * in our netrc file. + */ +- memcpy(login, "adminn", 6); +- result = Curl_parsenetrc("example.com", login, password, filename); ++ free(login); ++ login = strdup("adminn"); ++ result = Curl_parsenetrc("example.com", &login, &password, filename); + fail_unless(result == 0, "Host should be found"); + fail_unless(password[0] == 0, "password should not have been changed"); + fail_unless(strncmp(login, "adminn", 6) == 0, "login should not have been changed"); +@@ -94,8 +98,9 @@ UNITTEST_START + * Test for the first existing host in our netrc file + * with login[0] = 0. + */ +- login[0] = 0; +- result = Curl_parsenetrc("example.com", login, password, filename); ++ free(login); ++ login = strdup(""); ++ result = Curl_parsenetrc("example.com", &login, &password, filename); + fail_unless(result == 0, "Host should have been found"); + fail_unless(strncmp(password, "passwd", 6) == 0, + "password should be 'passwd'"); +@@ -105,8 +110,9 @@ UNITTEST_START + * Test for the first existing host in our netrc file + * with login[0] != 0. + */ +- password[0] = 0; +- result = Curl_parsenetrc("example.com", login, password, filename); ++ free(password); ++ password = strdup(""); ++ result = Curl_parsenetrc("example.com", &login, &password, filename); + fail_unless(result == 0, "Host should have been found"); + fail_unless(strncmp(password, "passwd", 6) == 0, + "password should be 'passwd'"); +@@ -116,9 +122,11 @@ UNITTEST_START + * Test for the second existing host in our netrc file + * with login[0] = 0. + */ +- password[0] = 0; +- login[0] = 0; +- result = Curl_parsenetrc("curl.example.com", login, password, filename); ++ free(password); ++ password = strdup(""); ++ free(login); ++ login = strdup(""); ++ result = Curl_parsenetrc("curl.example.com", &login, &password, filename); + fail_unless(result == 0, "Host should have been found"); + fail_unless(strncmp(password, "none", 4) == 0, + "password should be 'none'"); +@@ -128,8 +136,9 @@ UNITTEST_START + * Test for the second existing host in our netrc file + * with login[0] != 0. + */ +- password[0] = 0; +- result = Curl_parsenetrc("curl.example.com", login, password, filename); ++ free(password); ++ password = strdup(""); ++ result = Curl_parsenetrc("curl.example.com", &login, &password, filename); + fail_unless(result == 0, "Host should have been found"); + fail_unless(strncmp(password, "none", 4) == 0, + "password should be 'none'"); +-- +2.4.6 + + +From 96b625ddedb692a41b173cabf0bd5913f4535c70 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Mon, 19 Aug 2013 00:57:54 -0700 +Subject: [PATCH 22/28] Curl_setopt: handle arbitrary-length username and + password + +libcurl truncates usernames, passwords, and options set with +curl_easy_setopt to 255 (= MAX_CURL_PASSWORD_LENGTH - 1) characters. +This doesn't affect the return value from curl_easy_setopt(), so from +the caller's point of view, there is no sign anything strange has +happened, except that authentication fails. + +For example: + + # Prepare a long (300-char) password. + s=0123456789; s=$s$s$s$s$s$s$s$s$s$s; s=$s$s$s; + # Start a server. + nc -l -p 8888 | tee out & pid=$! + # Tell curl to pass the password to the server. + curl --user me:$s http://localhost:8888 & sleep 1; kill $pid + # Extract the password. + userpass=$( + awk '/Authorization: Basic/ {print $3}' +--- + lib/url.c | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 406ef85..515fa67 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4654,23 +4654,29 @@ static CURLcode parse_remote_port(struct SessionHandle *data, + * Override the login details from the URL with that in the CURLOPT_USERPWD + * option or a .netrc file, if applicable. + */ +-static void override_login(struct SessionHandle *data, +- struct connectdata *conn, +- char **userp, char **passwdp, char **optionsp) ++static int override_login(struct SessionHandle *data, ++ struct connectdata *conn, ++ char **userp, char **passwdp, char **optionsp) + { + if(data->set.str[STRING_USERNAME]) { +- strncpy(*userp, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH); +- (*userp)[MAX_CURL_USER_LENGTH - 1] = '\0'; /* To be on safe side */ ++ free(*userp); ++ *userp = strdup(data->set.str[STRING_USERNAME]); ++ if(!*userp) ++ return CURLE_OUT_OF_MEMORY; + } + + if(data->set.str[STRING_PASSWORD]) { +- strncpy(*passwdp, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH); +- (*passwdp)[MAX_CURL_PASSWORD_LENGTH - 1] = '\0'; /* To be on safe side */ ++ free(*passwdp); ++ *passwdp = strdup(data->set.str[STRING_PASSWORD]); ++ if(!*passwdp) ++ return CURLE_OUT_OF_MEMORY; + } + + if(data->set.str[STRING_OPTIONS]) { +- strncpy(*optionsp, data->set.str[STRING_OPTIONS], MAX_CURL_OPTIONS_LENGTH); +- (*optionsp)[MAX_CURL_OPTIONS_LENGTH - 1] = '\0'; /* To be on safe side */ ++ free(*optionsp); ++ *optionsp = strdup(data->set.str[STRING_OPTIONS]); ++ if(!*optionsp) ++ return CURLE_OUT_OF_MEMORY; + } + + conn->bits.netrc = FALSE; +@@ -4691,6 +4697,7 @@ static void override_login(struct SessionHandle *data, + conn->bits.user_passwd = TRUE; /* enable user+password */ + } + } ++ return CURLE_OK; + } + + /* +@@ -5191,7 +5198,9 @@ static CURLcode create_conn(struct SessionHandle *data, + goto out; + + /* Check for overridden login details and set them accordingly */ +- override_login(data, conn, &user, &passwd, &options); ++ result = override_login(data, conn, &user, &passwd, &options); ++ if(result != CURLE_OK) ++ goto out; + result = set_login(conn, user, passwd, options); + if(result != CURLE_OK) + goto out; +-- +2.4.6 + + +From d2fa706f006d393eee63ed686efccf68db5b6337 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Mon, 19 Aug 2013 01:01:26 -0700 +Subject: [PATCH 23/28] url: handle exceptional cases first in + parse_url_login() + +Instead of nesting "if(success)" blocks and leaving the reader in +suspense about what happens in the !success case, deal with failure +cases early, usually with a simple goto to clean up and return from +the function. + +No functional change intended. The main effect is to decrease the +indentation of this function slightly. + +Upstream-commit: 09ddb1d61cdb9ee11ebf481b29dac1be8f0ab848 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 121 ++++++++++++++++++++++++++++++-------------------------------- + 1 file changed, 59 insertions(+), 62 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 515fa67..8fff5ef 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4321,86 +4321,83 @@ static CURLcode parse_url_login(struct SessionHandle *data, + passwd[0] = 0; + options[0] = 0; + ++ if(!ptr) ++ goto out; ++ + /* We will now try to extract the + * possible login information in a string like: + * ftp://user:password@ftp.my.site:8021/README */ +- if(ptr) { +- /* There's login information to the left of the @ */ ++ conn->host.name = ++ptr; + +- conn->host.name = ++ptr; ++ /* So the hostname is sane. Only bother interpreting the ++ * results if we could care. It could still be wasted ++ * work because it might be overtaken by the programmatically ++ * set user/passwd, but doing that first adds more cases here :-( ++ */ + +- /* So the hostname is sane. Only bother interpreting the +- * results if we could care. It could still be wasted +- * work because it might be overtaken by the programmatically +- * set user/passwd, but doing that first adds more cases here :-( +- */ ++ if(data->set.use_netrc == CURL_NETRC_REQUIRED) ++ goto out; + +- if(data->set.use_netrc != CURL_NETRC_REQUIRED) { +- /* We could use the login information in the URL so extract it */ +- result = parse_login_details(login, ptr - login - 1, +- &userp, &passwdp, &optionsp); +- if(!result) { +- if(userp) { +- char *newname; +- +- /* We have a user in the URL */ +- conn->bits.userpwd_in_url = TRUE; +- conn->bits.user_passwd = TRUE; /* enable user+password */ +- +- /* Decode the user */ +- newname = curl_easy_unescape(data, userp, 0, NULL); +- if(!newname) { +- Curl_safefree(userp); +- Curl_safefree(passwdp); +- Curl_safefree(optionsp); +- return CURLE_OUT_OF_MEMORY; +- } ++ /* We could use the login information in the URL so extract it */ ++ result = parse_login_details(login, ptr - login - 1, ++ &userp, &passwdp, &optionsp); ++ if(result != CURLE_OK) ++ goto out; + +- if(strlen(newname) < MAX_CURL_USER_LENGTH) +- strcpy(user, newname); ++ if(userp) { ++ char *newname; + +- free(newname); +- } ++ /* We have a user in the URL */ ++ conn->bits.userpwd_in_url = TRUE; ++ conn->bits.user_passwd = TRUE; /* enable user+password */ + +- if(passwdp) { +- /* We have a password in the URL so decode it */ +- char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); +- if(!newpasswd) { +- Curl_safefree(userp); +- Curl_safefree(passwdp); +- Curl_safefree(optionsp); +- return CURLE_OUT_OF_MEMORY; +- } ++ /* Decode the user */ ++ newname = curl_easy_unescape(data, userp, 0, NULL); ++ if(!newname) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } + +- if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) +- strcpy(passwd, newpasswd); ++ if(strlen(newname) < MAX_CURL_USER_LENGTH) ++ strcpy(user, newname); + +- free(newpasswd); +- } ++ free(newname); ++ } + +- if(optionsp) { +- /* We have an options list in the URL so decode it */ +- char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); +- if(!newoptions) { +- Curl_safefree(userp); +- Curl_safefree(passwdp); +- Curl_safefree(optionsp); +- return CURLE_OUT_OF_MEMORY; +- } ++ if(passwdp) { ++ /* We have a password in the URL so decode it */ ++ char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); ++ if(!newpasswd) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; ++ } + +- if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) +- strcpy(options, newoptions); ++ if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) ++ strcpy(passwd, newpasswd); + +- free(newoptions); +- } +- } ++ free(newpasswd); ++ } + +- Curl_safefree(userp); +- Curl_safefree(passwdp); +- Curl_safefree(optionsp); ++ if(optionsp) { ++ /* We have an options list in the URL so decode it */ ++ char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); ++ if(!newoptions) { ++ result = CURLE_OUT_OF_MEMORY; ++ goto out; + } ++ ++ if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) ++ strcpy(options, newoptions); ++ ++ free(newoptions); + } + ++ out: ++ ++ Curl_safefree(userp); ++ Curl_safefree(passwdp); ++ Curl_safefree(optionsp); ++ + return result; + } + +-- +2.4.6 + + +From 085588f8f1baa68a28e0cc3b7197fcb3f99b8f15 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 21 Apr 2013 12:11:50 +0100 +Subject: [PATCH 24/28] url: Removed unused text length constants + +Upstream-commit: 455ba691a7250b312075a5d91ae89bbbe70d62aa +Signed-off-by: Kamil Dudka +--- + lib/urldata.h | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/lib/urldata.h b/lib/urldata.h +index 1c2281a..219a11a 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1134,9 +1134,6 @@ typedef enum { + #define MAX_CURL_USER_LENGTH 256 + #define MAX_CURL_PASSWORD_LENGTH 256 + #define MAX_CURL_OPTIONS_LENGTH 256 +-#define MAX_CURL_USER_LENGTH_TXT "255" +-#define MAX_CURL_PASSWORD_LENGTH_TXT "255" +-#define MAX_CURL_OPTIONS_LENGTH_TXT "255" + + struct auth { + unsigned long want; /* Bitmask set to the authentication methods wanted by +-- +2.4.6 + + +From 314f6398307783780f416d834295002c4b745251 Mon Sep 17 00:00:00 2001 +From: Jonathan Nieder +Date: Mon, 19 Aug 2013 01:36:46 -0700 +Subject: [PATCH 25/28] url: handle arbitrary-length username and password + before '@' + +libcurl quietly truncates usernames, passwords, and options from +before an '@' sign in a URL to 255 (= MAX_CURL_PASSWORD_LENGTH - 1) +characters to fit in fixed-size buffers on the stack. Allocate a +buffer large enough to fit the parsed fields on the fly instead to +support longer passwords. + +After this change, there are no more uses of MAX_CURL_OPTIONS_LENGTH +left, so stop defining that constant while at it. The hardcoded max +username and password length constants, on the other hand, are still +used in HTTP proxy credential handling (which this patch doesn't +touch). + +Reported-by: Colby Ranger + +Upstream-commit: 2f1a0bc0bf36c5ad0f8755d9c7553e1f5729af43 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 45 +++++++++++++++++++++------------------------ + lib/urldata.h | 1 - + 2 files changed, 21 insertions(+), 25 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 8fff5ef..abf8a43 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -140,7 +140,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); + static CURLcode do_init(struct connectdata *conn); + static CURLcode parse_url_login(struct SessionHandle *data, + struct connectdata *conn, +- char *user, char *passwd, char *options); ++ char **userptr, char **passwdptr, ++ char **optionsptr); + static CURLcode parse_login_details(const char *login, const size_t len, + char **userptr, char **passwdptr, + char **optionsptr); +@@ -3595,7 +3596,8 @@ static CURLcode findprotocol(struct SessionHandle *data, + static CURLcode parseurlandfillconn(struct SessionHandle *data, + struct connectdata *conn, + bool *prot_missing, +- char *user, char *passwd, char *options) ++ char **userp, char **passwdp, ++ char **optionsp) + { + char *at; + char *fragment; +@@ -3820,7 +3822,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, + * Parse the login details from the URL and strip them out of + * the host name + */ +- result = parse_url_login(data, conn, user, passwd, options); ++ result = parse_url_login(data, conn, userp, passwdp, optionsp); + if(result != CURLE_OK) + return result; + +@@ -4300,7 +4302,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, + */ + static CURLcode parse_url_login(struct SessionHandle *data, + struct connectdata *conn, +- char *user, char *passwd, char *options) ++ char **user, char **passwd, char **options) + { + CURLcode result = CURLE_OK; + char *userp = NULL; +@@ -4317,9 +4319,9 @@ static CURLcode parse_url_login(struct SessionHandle *data, + char *ptr = strchr(conn->host.name, '@'); + char *login = conn->host.name; + +- user[0] = 0; /* to make everything well-defined */ +- passwd[0] = 0; +- options[0] = 0; ++ DEBUGASSERT(!**user); ++ DEBUGASSERT(!**passwd); ++ DEBUGASSERT(!**options); + + if(!ptr) + goto out; +@@ -4358,10 +4360,8 @@ static CURLcode parse_url_login(struct SessionHandle *data, + goto out; + } + +- if(strlen(newname) < MAX_CURL_USER_LENGTH) +- strcpy(user, newname); +- +- free(newname); ++ free(*user); ++ *user = newname; + } + + if(passwdp) { +@@ -4372,10 +4372,8 @@ static CURLcode parse_url_login(struct SessionHandle *data, + goto out; + } + +- if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH) +- strcpy(passwd, newpasswd); +- +- free(newpasswd); ++ free(*passwd); ++ *passwd = newpasswd; + } + + if(optionsp) { +@@ -4386,12 +4384,11 @@ static CURLcode parse_url_login(struct SessionHandle *data, + goto out; + } + +- if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH) +- strcpy(options, newoptions); +- +- free(newoptions); ++ free(*options); ++ *options = newoptions; + } + ++ + out: + + Curl_safefree(userp); +@@ -4989,16 +4986,16 @@ static CURLcode create_conn(struct SessionHandle *data, + conn->host.name = conn->host.rawalloc; + conn->host.name[0] = 0; + +- user = malloc(MAX_CURL_USER_LENGTH); +- passwd = malloc(MAX_CURL_PASSWORD_LENGTH); +- options = malloc(MAX_CURL_OPTIONS_LENGTH); ++ user = strdup(""); ++ passwd = strdup(""); ++ options = strdup(""); + if(!user || !passwd || !options) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + +- result = parseurlandfillconn(data, conn, &prot_missing, user, passwd, +- options); ++ result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd, ++ &options); + if(result != CURLE_OK) + goto out; + +diff --git a/lib/urldata.h b/lib/urldata.h +index 219a11a..b3ee7e3 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1133,7 +1133,6 @@ typedef enum { + * Session-data MUST be put in the connectdata struct and here. */ + #define MAX_CURL_USER_LENGTH 256 + #define MAX_CURL_PASSWORD_LENGTH 256 +-#define MAX_CURL_OPTIONS_LENGTH 256 + + struct auth { + unsigned long want; /* Bitmask set to the authentication methods wanted by +-- +2.4.6 + + +From 806203027b9dae8992f9762b056e953ecb118b84 Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Sun, 1 Sep 2013 13:30:12 +0100 +Subject: [PATCH 26/28] url.c: Fixed compilation warning + +An enumerated type is mixed with another type + +Upstream-commit: 322f0bc2f1af4a985e85ee5c8639e3b454314ccd +Signed-off-by: Kamil Dudka +--- + lib/url.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index abf8a43..558799c 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4648,9 +4648,9 @@ static CURLcode parse_remote_port(struct SessionHandle *data, + * Override the login details from the URL with that in the CURLOPT_USERPWD + * option or a .netrc file, if applicable. + */ +-static int override_login(struct SessionHandle *data, +- struct connectdata *conn, +- char **userp, char **passwdp, char **optionsp) ++static CURLcode override_login(struct SessionHandle *data, ++ struct connectdata *conn, ++ char **userp, char **passwdp, char **optionsp) + { + if(data->set.str[STRING_USERNAME]) { + free(*userp); +@@ -4691,6 +4691,7 @@ static int override_login(struct SessionHandle *data, + conn->bits.user_passwd = TRUE; /* enable user+password */ + } + } ++ + return CURLE_OK; + } + +-- +2.4.6 + + +From 7ed75f9bce576390e2c94a797c4520130654b416 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 14 Dec 2013 22:39:27 +0100 +Subject: [PATCH 27/28] login options: remove the ;[options] support from + CURLOPT_USERPWD + +To avoid the regression when users pass in passwords containing semi- +colons, we now drop the ability to set the login options with the same +options. Support for login options in CURLOPT_USERPWD was added in +7.31.0. + +Test case 83 was modified to verify that colons and semi-colons can be +used as part of the password when using -u (CURLOPT_USERPWD). + +Bug: http://curl.haxx.se/bug/view.cgi?id=1311 +Reported-by: Petr Bahula +Assisted-by: Steve Holme +Signed-off-by: Daniel Stenberg + +Upstream-commit: 169fedbdce93ecf14befb6e0e1ce6a2d480252a3 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 19 +++++-------------- + tests/data/test83 | 4 ++-- + 2 files changed, 7 insertions(+), 16 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 558799c..8c76256 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -295,13 +295,11 @@ static CURLcode setstropt(char **charp, char *s) + return CURLE_OK; + } + +-static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp, +- char **optionsp) ++static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) + { + CURLcode result = CURLE_OK; + char *user = NULL; + char *passwd = NULL; +- char *options = NULL; + + /* Parse the login details if specified. It not then we treat NULL as a hint + to clear the existing data */ +@@ -309,7 +307,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp, + result = parse_login_details(option, strlen(option), + (userp ? &user : NULL), + (passwdp ? &passwd : NULL), +- (optionsp ? &options : NULL)); ++ NULL); + } + + if(!result) { +@@ -331,12 +329,6 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp, + Curl_safefree(*passwdp); + *passwdp = passwd; + } +- +- /* Store the options part of option if required */ +- if(optionsp) { +- Curl_safefree(*optionsp); +- *optionsp = options; +- } + } + + return result; +@@ -1553,12 +1545,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + + case CURLOPT_USERPWD: + /* +- * user:password;options to use in the operation ++ * user:password to use in the operation + */ + result = setstropt_userpwd(va_arg(param, char *), + &data->set.str[STRING_USERNAME], +- &data->set.str[STRING_PASSWORD], +- &data->set.str[STRING_OPTIONS]); ++ &data->set.str[STRING_PASSWORD]); + break; + case CURLOPT_USERNAME: + /* +@@ -1631,7 +1622,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + */ + result = setstropt_userpwd(va_arg(param, char *), + &data->set.str[STRING_PROXYUSERNAME], +- &data->set.str[STRING_PROXYPASSWORD], NULL); ++ &data->set.str[STRING_PROXYPASSWORD]); + break; + case CURLOPT_PROXYUSERNAME: + /* +diff --git a/tests/data/test83 b/tests/data/test83 +index 3015c9c..160b40c 100644 +--- a/tests/data/test83 ++++ b/tests/data/test83 +@@ -46,7 +46,7 @@ http-proxy + HTTP over proxy-tunnel with site authentication + + +-http://%HOSTIP:%HTTPPORT/we/want/that/page/83 -p -x %HOSTIP:%PROXYPORT --user iam:myself ++http://%HOSTIP:%HTTPPORT/we/want/that/page/83 -p -x %HOSTIP:%PROXYPORT --user 'iam:my:;self' + + + +@@ -65,7 +65,7 @@ Proxy-Connection: Keep-Alive + + + GET /we/want/that/page/83 HTTP/1.1 +-Authorization: Basic aWFtOm15c2VsZg== ++Authorization: Basic aWFtOm15OjtzZWxm + User-Agent: curl/7.10.7-pre2 (i686-pc-linux-gnu) libcurl/7.10.7-pre2 OpenSSL/0.9.7a zlib/1.1.3 + Host: %HOSTIP:%HTTPPORT + Accept: */* +-- +2.4.6 + + +From ffe3cb2b365e914e364a6c9d7611e6e7f60d3cfa Mon Sep 17 00:00:00 2001 +From: Dan Fandrich +Date: Wed, 29 Jan 2014 08:10:26 +0100 +Subject: [PATCH 28/28] netrc: Fixed a memory leak in an OOM condition + +Upstream-commit: 768151449b386488ac8fe869f48bf2930123d601 +Signed-off-by: Kamil Dudka +--- + lib/url.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 8c76256..57944e4 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -4666,13 +4666,17 @@ static CURLcode override_login(struct SessionHandle *data, + + conn->bits.netrc = FALSE; + if(data->set.use_netrc != CURL_NETRC_IGNORED) { +- if(Curl_parsenetrc(conn->host.name, +- userp, passwdp, +- data->set.str[STRING_NETRC_FILE])) { ++ int ret = Curl_parsenetrc(conn->host.name, ++ userp, passwdp, ++ data->set.str[STRING_NETRC_FILE]); ++ if(ret > 0) { + infof(data, "Couldn't find host %s in the " + DOT_CHAR "netrc file; using defaults\n", + conn->host.name); + } ++ else if(ret < 0 ) { ++ return CURLE_OUT_OF_MEMORY; ++ } + else { + /* set bits.netrc TRUE to remember that we got the name from a .netrc + file, so that it is safe to use even if we followed a Location: to a +-- +2.4.6 + diff --git a/SOURCES/0036-curl-7.29.0-c8644d1f.patch b/SOURCES/0036-curl-7.29.0-c8644d1f.patch new file mode 100644 index 0000000..7f631f8 --- /dev/null +++ b/SOURCES/0036-curl-7.29.0-c8644d1f.patch @@ -0,0 +1,2007 @@ +From 3fef242a1e1a74140a1678d84164086d0f47d83a Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 27 Nov 2014 23:59:19 +0100 +Subject: [PATCH 01/11] sws: move away from IPv4/IPv4-only assumption + +Instead of depending the socket domain type on use_ipv6, specify the +domain type (AF_INET / AF_INET6) as variable. An enum is used here with +switch to avoid compiler warnings in connect_to, complaining that rc +is possibly undefined (which is not possible as socket_domain is +always set). + +Besides abstracting the socket type, make the debugging messages be +independent on IP (introduce location_str which points to "port XXXXX"). +Rename "ipv_inuse" to "socket_type" and tighten the scope (main). + +Signed-off-by: Peter Wu + +Upstream-commit: cf6c5c222d86088cbfc9dee4c23f8ada96ee91e7 +Signed-off-by: Kamil Dudka +--- + tests/server/sws.c | 88 ++++++++++++++++++++++++------------------------------ + 1 file changed, 39 insertions(+), 49 deletions(-) + +diff --git a/tests/server/sws.c b/tests/server/sws.c +index aef55ea..fa10d54 100644 +--- a/tests/server/sws.c ++++ b/tests/server/sws.c +@@ -65,11 +65,13 @@ + #define ERANGE 34 /* errno.h value */ + #endif + ++static enum { ++ socket_domain_inet = AF_INET, + #ifdef ENABLE_IPV6 +-static bool use_ipv6 = FALSE; ++ socket_domain_inet6 = AF_INET6 + #endif ++} socket_domain = AF_INET; + static bool use_gopher = FALSE; +-static const char *ipv_inuse = "IPv4"; + static int serverlogslocked = 0; + static bool is_proxy = FALSE; + +@@ -1285,7 +1287,7 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + #endif + + #ifdef ENABLE_IPV6 +- if(use_ipv6) { ++ if(socket_domain == AF_INET6) { + op_br = "["; + cl_br = "]"; + } +@@ -1297,14 +1299,8 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + logmsg("about to connect to %s%s%s:%hu", + op_br, ipaddr, cl_br, port); + +-#ifdef ENABLE_IPV6 +- if(!use_ipv6) +-#endif +- serverfd = socket(AF_INET, SOCK_STREAM, 0); +-#ifdef ENABLE_IPV6 +- else +- serverfd = socket(AF_INET6, SOCK_STREAM, 0); +-#endif ++ ++ serverfd = socket(socket_domain, SOCK_STREAM, 0); + if(CURL_SOCKET_BAD == serverfd) { + error = SOCKERRNO; + logmsg("Error creating socket for server conection: (%d) %s", +@@ -1322,9 +1318,8 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + logmsg("TCP_NODELAY set for server conection"); + #endif + +-#ifdef ENABLE_IPV6 +- if(!use_ipv6) { +-#endif ++ switch(socket_domain) { ++ case AF_INET: + memset(&serveraddr.sa4, 0, sizeof(serveraddr.sa4)); + serveraddr.sa4.sin_family = AF_INET; + serveraddr.sa4.sin_port = htons(port); +@@ -1335,9 +1330,9 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + } + + rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa4)); ++ break; + #ifdef ENABLE_IPV6 +- } +- else { ++ case AF_INET6: + memset(&serveraddr.sa6, 0, sizeof(serveraddr.sa6)); + serveraddr.sa6.sin6_family = AF_INET6; + serveraddr.sa6.sin6_port = htons(port); +@@ -1348,8 +1343,9 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + } + + rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6)); +- } ++ break; + #endif /* ENABLE_IPV6 */ ++ } + + if(got_exit_signal) { + sclose(serverfd); +@@ -1924,21 +1920,20 @@ int main(int argc, char *argv[]) + int arg=1; + long pid; + const char *hostport = "127.0.0.1"; ++ const char *socket_type = "IPv4"; ++ char port_str[11]; ++ const char *location_str = port_str; + size_t socket_idx; + + memset(&req, 0, sizeof(req)); + + while(argc>arg) { + if(!strcmp("--version", argv[arg])) { +- printf("sws IPv4%s" +- "\n" +- , ++ puts("sws IPv4" + #ifdef ENABLE_IPV6 + "/IPv6" +-#else +- "" + #endif +- ); ++ ); + return 0; + } + else if(!strcmp("--pidfile", argv[arg])) { +@@ -1957,16 +1952,16 @@ int main(int argc, char *argv[]) + end_of_headers = "\r\n"; /* gopher style is much simpler */ + } + else if(!strcmp("--ipv4", argv[arg])) { +-#ifdef ENABLE_IPV6 +- ipv_inuse = "IPv4"; +- use_ipv6 = FALSE; +-#endif ++ socket_type = "IPv4"; ++ socket_domain = AF_INET; ++ location_str = port_str; + arg++; + } + else if(!strcmp("--ipv6", argv[arg])) { + #ifdef ENABLE_IPV6 +- ipv_inuse = "IPv6"; +- use_ipv6 = TRUE; ++ socket_type = "IPv6"; ++ socket_domain = AF_INET6; ++ location_str = port_str; + #endif + arg++; + } +@@ -2018,6 +2013,8 @@ int main(int argc, char *argv[]) + } + } + ++ snprintf(port_str, sizeof(port_str), "port %hu", port); ++ + #ifdef WIN32 + win32_init(); + atexit(win32_cleanup); +@@ -2027,14 +2024,7 @@ int main(int argc, char *argv[]) + + pid = (long)getpid(); + +-#ifdef ENABLE_IPV6 +- if(!use_ipv6) +-#endif +- sock = socket(AF_INET, SOCK_STREAM, 0); +-#ifdef ENABLE_IPV6 +- else +- sock = socket(AF_INET6, SOCK_STREAM, 0); +-#endif ++ sock = socket(socket_domain, SOCK_STREAM, 0); + + all_sockets[0] = sock; + num_sockets = 1; +@@ -2061,33 +2051,33 @@ int main(int argc, char *argv[]) + goto sws_cleanup; + } + +-#ifdef ENABLE_IPV6 +- if(!use_ipv6) { +-#endif ++ switch(socket_domain) { ++ case AF_INET: + memset(&me.sa4, 0, sizeof(me.sa4)); + me.sa4.sin_family = AF_INET; + me.sa4.sin_addr.s_addr = INADDR_ANY; + me.sa4.sin_port = htons(port); + rc = bind(sock, &me.sa, sizeof(me.sa4)); ++ break; + #ifdef ENABLE_IPV6 +- } +- else { ++ case AF_INET6: + memset(&me.sa6, 0, sizeof(me.sa6)); + me.sa6.sin6_family = AF_INET6; + me.sa6.sin6_addr = in6addr_any; + me.sa6.sin6_port = htons(port); + rc = bind(sock, &me.sa, sizeof(me.sa6)); +- } ++ break; + #endif /* ENABLE_IPV6 */ ++ } + if(0 != rc) { + error = SOCKERRNO; +- logmsg("Error binding socket on port %hu: (%d) %s", +- port, error, strerror(error)); ++ logmsg("Error binding socket on %s: (%d) %s", ++ location_str, error, strerror(error)); + goto sws_cleanup; + } + +- logmsg("Running %s %s version on port %d", +- use_gopher?"GOPHER":"HTTP", ipv_inuse, (int)port); ++ logmsg("Running %s %s version on %s", ++ use_gopher?"GOPHER":"HTTP", socket_type, location_str); + + /* start accepting connections */ + rc = listen(sock, 5); +@@ -2251,8 +2241,8 @@ sws_cleanup: + restore_signal_handlers(); + + if(got_exit_signal) { +- logmsg("========> %s sws (port: %d pid: %ld) exits with signal (%d)", +- ipv_inuse, (int)port, pid, exit_signal); ++ logmsg("========> %s sws (%s pid: %ld) exits with signal (%d)", ++ socket_type, location_str, pid, exit_signal); + /* + * To properly set the return status of the process we + * must raise the same signal SIGINT or SIGTERM that we +-- +2.5.2 + + +From d8d875f7c528157feec0795c03bd065420903f5d Mon Sep 17 00:00:00 2001 +From: Steve Holme +Date: Wed, 3 Dec 2014 00:00:40 +0000 +Subject: [PATCH 02/11] sws.c: Fixed compilation warning when IPv6 is disabled + +sws.c:69: warning: comma at end of enumerator list + +Upstream-commit: d784000a1468efc986c7d156d2e7c84d1920af87 +Signed-off-by: Kamil Dudka +--- + tests/server/sws.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tests/server/sws.c b/tests/server/sws.c +index fa10d54..2b7e628 100644 +--- a/tests/server/sws.c ++++ b/tests/server/sws.c +@@ -66,9 +66,9 @@ + #endif + + static enum { +- socket_domain_inet = AF_INET, ++ socket_domain_inet = AF_INET + #ifdef ENABLE_IPV6 +- socket_domain_inet6 = AF_INET6 ++ , socket_domain_inet6 = AF_INET6 + #endif + } socket_domain = AF_INET; + static bool use_gopher = FALSE; +-- +2.5.2 + + +From db2095dec37630309bacca6795cd4cfcf6557c9b Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 27 Nov 2014 23:59:20 +0100 +Subject: [PATCH 03/11] sws: restrict TCP_NODELAY to IP sockets + +TCP_NODELAY does not make sense for Unix sockets, so enable it only if +the socket is using IP. + +Signed-off-by: Peter Wu + +Upstream-commit: fb7d7e0022f22035449bbc506068004f0568f8ae +Signed-off-by: Kamil Dudka +--- + tests/server/sws.c | 73 ++++++++++++++++++++++++++++++++---------------------- + 1 file changed, 44 insertions(+), 29 deletions(-) + +diff --git a/tests/server/sws.c b/tests/server/sws.c +index 2b7e628..0739a70 100644 +--- a/tests/server/sws.c ++++ b/tests/server/sws.c +@@ -331,6 +331,21 @@ static void restore_signal_handlers(void) + #endif + } + ++/* returns true if the current socket is an IP one */ ++static bool socket_domain_is_ip(void) ++{ ++ switch(socket_domain) { ++ case AF_INET: ++#ifdef ENABLE_IPV6 ++ case AF_INET6: ++#endif ++ return true; ++ default: ++ /* case AF_UNIX: */ ++ return false; ++ } ++} ++ + /* based on the testno, parse the correct server commands */ + static int parse_servercmd(struct httprequest *req) + { +@@ -1282,9 +1297,6 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + int rc; + const char *op_br = ""; + const char *cl_br = ""; +-#ifdef TCP_NODELAY +- curl_socklen_t flag; +-#endif + + #ifdef ENABLE_IPV6 + if(socket_domain == AF_INET6) { +@@ -1309,13 +1321,15 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + } + + #ifdef TCP_NODELAY +- /* Disable the Nagle algorithm */ +- flag = 1; +- if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, +- (void *)&flag, sizeof(flag))) +- logmsg("====> TCP_NODELAY for server conection failed"); +- else +- logmsg("TCP_NODELAY set for server conection"); ++ if(socket_domain_is_ip()) { ++ /* Disable the Nagle algorithm */ ++ curl_socklen_t flag = 1; ++ if(0 != setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, ++ (void *)&flag, sizeof(flag))) ++ logmsg("====> TCP_NODELAY for server conection failed"); ++ else ++ logmsg("TCP_NODELAY set for server conection"); ++ } + #endif + + switch(socket_domain) { +@@ -1398,9 +1412,6 @@ static void http_connect(curl_socket_t *infdp, + bool poll_server_rd[2] = { TRUE, TRUE }; + bool poll_client_wr[2] = { TRUE, TRUE }; + bool poll_server_wr[2] = { TRUE, TRUE }; +-#ifdef TCP_NODELAY +- curl_socklen_t flag; +-#endif + bool primary = FALSE; + bool secondary = FALSE; + int max_tunnel_idx; /* CTRL or DATA */ +@@ -1514,13 +1525,15 @@ static void http_connect(curl_socket_t *infdp, + memset(&req2, 0, sizeof(req2)); + logmsg("====> Client connect DATA"); + #ifdef TCP_NODELAY +- /* Disable the Nagle algorithm */ +- flag = 1; +- if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY, +- (void *)&flag, sizeof(flag))) +- logmsg("====> TCP_NODELAY for client DATA conection failed"); +- else +- logmsg("TCP_NODELAY set for client DATA conection"); ++ if(socket_domain_is_ip()) { ++ /* Disable the Nagle algorithm */ ++ curl_socklen_t flag = 1; ++ if(0 != setsockopt(datafd, IPPROTO_TCP, TCP_NODELAY, ++ (void *)&flag, sizeof(flag))) ++ logmsg("====> TCP_NODELAY for client DATA conection failed"); ++ else ++ logmsg("TCP_NODELAY set for client DATA conection"); ++ } + #endif + req2.pipelining = FALSE; + init_httprequest(&req2); +@@ -1826,15 +1839,17 @@ static curl_socket_t accept_connection(curl_socket_t sock) + num_sockets += 1; + + #ifdef TCP_NODELAY +- /* +- * Disable the Nagle algorithm to make it easier to send out a large +- * response in many small segments to torture the clients more. +- */ +- if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY, +- (void *)&flag, sizeof(flag))) +- logmsg("====> TCP_NODELAY failed"); +- else +- logmsg("TCP_NODELAY set"); ++ if(socket_domain_is_ip()) { ++ /* ++ * Disable the Nagle algorithm to make it easier to send out a large ++ * response in many small segments to torture the clients more. ++ */ ++ if(0 != setsockopt(msgsock, IPPROTO_TCP, TCP_NODELAY, ++ (void *)&flag, sizeof(flag))) ++ logmsg("====> TCP_NODELAY failed"); ++ else ++ logmsg("TCP_NODELAY set"); ++ } + #endif + + return msgsock; +-- +2.5.2 + + +From 7ab987459a931e593dc9f533d6e6cb6e9a26d424 Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Wed, 3 Dec 2014 02:20:00 +0100 +Subject: [PATCH 04/11] sws: add UNIX domain socket support + +This extends sws with a --unix-socket option which causes the port to +be ignored (as the server now listens on the path specified by +--unix-socket). This feature will be available in the following patch +that enables checking for UNIX domain socket support. + +Proxy support (CONNECT) is not considered nor tested. It does not make +sense anyway, first connecting through a TCP proxy, then let that TCP +proxy connect to a UNIX socket. + +Signed-off-by: Peter Wu + +Upstream-commit: e9c7a86220ddf4e67b8bff56cddfc7388afcc9ef +Signed-off-by: Kamil Dudka +--- + tests/server/server_sockaddr.h | 9 ++++++- + tests/server/sws.c | 53 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 61 insertions(+), 1 deletion(-) + +diff --git a/tests/server/server_sockaddr.h b/tests/server/server_sockaddr.h +index 6a17fe0..3f4cd67 100644 +--- a/tests/server/server_sockaddr.h ++++ b/tests/server/server_sockaddr.h +@@ -7,7 +7,7 @@ + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. ++ * Copyright (C) 1998 - 2014, 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 +@@ -23,12 +23,19 @@ + ***************************************************************************/ + #include "server_setup.h" + ++#ifdef HAVE_SYS_UN_H ++#include /* for sockaddr_un */ ++#endif ++ + typedef union { + struct sockaddr sa; + struct sockaddr_in sa4; + #ifdef ENABLE_IPV6 + struct sockaddr_in6 sa6; + #endif ++#ifdef USE_UNIX_SOCKETS ++ struct sockaddr_un sau; ++#endif + } srvr_sockaddr_union_t; + + #endif /* HEADER_CURL_SERVER_SOCKADDR_H */ +diff --git a/tests/server/sws.c b/tests/server/sws.c +index 0739a70..24ecb8f 100644 +--- a/tests/server/sws.c ++++ b/tests/server/sws.c +@@ -70,6 +70,9 @@ static enum { + #ifdef ENABLE_IPV6 + , socket_domain_inet6 = AF_INET6 + #endif ++#ifdef USE_UNIX_SOCKETS ++ , socket_domain_unix = AF_UNIX ++#endif + } socket_domain = AF_INET; + static bool use_gopher = FALSE; + static int serverlogslocked = 0; +@@ -1359,6 +1362,11 @@ static curl_socket_t connect_to(const char *ipaddr, unsigned short port) + rc = connect(serverfd, &serveraddr.sa, sizeof(serveraddr.sa6)); + break; + #endif /* ENABLE_IPV6 */ ++#ifdef USE_UNIX_SOCKETS ++ case AF_UNIX: ++ logmsg("Proxying through UNIX socket is not (yet?) supported."); ++ return CURL_SOCKET_BAD; ++#endif /* USE_UNIX_SOCKETS */ + } + + if(got_exit_signal) { +@@ -1928,6 +1936,10 @@ int main(int argc, char *argv[]) + int wrotepidfile = 0; + int flag; + unsigned short port = DEFAULT_PORT; ++#ifdef USE_UNIX_SOCKETS ++ const char *unix_socket = NULL; ++ bool unlink_socket = false; ++#endif + char *pidname= (char *)".http.pid"; + struct httprequest req; + int rc; +@@ -1948,6 +1960,9 @@ int main(int argc, char *argv[]) + #ifdef ENABLE_IPV6 + "/IPv6" + #endif ++#ifdef USE_UNIX_SOCKETS ++ "/unix" ++#endif + ); + return 0; + } +@@ -1980,6 +1995,23 @@ int main(int argc, char *argv[]) + #endif + arg++; + } ++ else if(!strcmp("--unix-socket", argv[arg])) { ++ arg++; ++ if(argc>arg) { ++#ifdef USE_UNIX_SOCKETS ++ unix_socket = argv[arg]; ++ if(strlen(unix_socket) >= sizeof(me.sau.sun_path)) { ++ fprintf(stderr, "sws: socket path must be shorter than %zu chars\n", ++ sizeof(me.sau.sun_path)); ++ return 0; ++ } ++ socket_type = "unix"; ++ socket_domain = AF_UNIX; ++ location_str = unix_socket; ++#endif ++ arg++; ++ } ++ } + else if(!strcmp("--port", argv[arg])) { + arg++; + if(argc>arg) { +@@ -2020,6 +2052,7 @@ int main(int argc, char *argv[]) + " --pidfile [file]\n" + " --ipv4\n" + " --ipv6\n" ++ " --unix-socket [file]\n" + " --port [port]\n" + " --srcdir [path]\n" + " --connect [ip4-addr]\n" +@@ -2083,6 +2116,14 @@ int main(int argc, char *argv[]) + rc = bind(sock, &me.sa, sizeof(me.sa6)); + break; + #endif /* ENABLE_IPV6 */ ++#ifdef USE_UNIX_SOCKETS ++ case AF_UNIX: ++ memset(&me.sau, 0, sizeof(me.sau)); ++ me.sau.sun_family = AF_UNIX; ++ strncpy(me.sau.sun_path, unix_socket, sizeof(me.sau.sun_path)); ++ rc = bind(sock, &me.sa, sizeof(me.sau)); ++ break; ++#endif /* USE_UNIX_SOCKETS */ + } + if(0 != rc) { + error = SOCKERRNO; +@@ -2103,6 +2144,11 @@ int main(int argc, char *argv[]) + goto sws_cleanup; + } + ++#ifdef USE_UNIX_SOCKETS ++ /* listen succeeds, so let's assume a valid listening UNIX socket */ ++ unlink_socket = true; ++#endif ++ + /* + ** As soon as this server writes its pid file the test harness will + ** attempt to connect to this server and initiate its verification. +@@ -2242,6 +2288,13 @@ sws_cleanup: + if(sock != CURL_SOCKET_BAD) + sclose(sock); + ++#ifdef USE_UNIX_SOCKETS ++ if(unlink_socket && socket_domain == AF_UNIX) { ++ rc = unlink(unix_socket); ++ logmsg("unlink(%s) = %d (%s)", unix_socket, rc, strerror(rc)); ++ } ++#endif ++ + if(got_exit_signal) + logmsg("signalled to die"); + +-- +2.5.2 + + +From d04ea6f7f09e1556f80c4bbf4fc9497f83bc37a6 Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 27 Nov 2014 23:59:23 +0100 +Subject: [PATCH 05/11] tests: add HTTP UNIX socket server testing support + +The variable `$ipvnum` can now contain "unix" besides the integers 4 +and 6 since the variable. Functions which receive this parameter +have their `$port` parameter renamed to `$port_or_path` to support a +path to the UNIX domain socket (as a "port" is only meaningful for TCP). + +Signed-off-by: Peter Wu + +Upstream-commit: f1cc2a2c0cf8e191e606c6093c679fbee95e8809 +Signed-off-by: Kamil Dudka +--- + tests/FILEFORMAT | 2 ++ + tests/README | 3 ++ + tests/httpserver.pl | 15 ++++++++- + tests/runtests.pl | 96 +++++++++++++++++++++++++++++++++++++++++++++-------- + tests/serverhelp.pm | 4 +-- + 5 files changed, 104 insertions(+), 16 deletions(-) + +diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT +index 96cd5c8..702368f 100644 +--- a/tests/FILEFORMAT ++++ b/tests/FILEFORMAT +@@ -165,6 +165,7 @@ smtp + httptls+srp + httptls+srp-ipv6 + http-proxy ++http-unix + + Give only one per line. This subsection is mandatory. + +@@ -284,6 +285,7 @@ Available substitute variables include: + %HTTPPORT - Port number of the HTTP server + %HOST6IP - IPv6 address of the host running this test + %HTTP6PORT - IPv6 port number of the HTTP server ++%HTTPUNIXPATH - Path to the UNIX socket of the HTTP server + %HTTPSPORT - Port number of the HTTPS server + %PROXYPORT - Port number of the HTTP proxy + %FTPPORT - Port number of the FTP server +diff --git a/tests/README b/tests/README +index fff618e..b442693 100644 +--- a/tests/README ++++ b/tests/README +@@ -80,6 +80,9 @@ The cURL Test Suite + machine, or just move the servers in case you have local services on any of + those ports. + ++ The HTTP server supports listening on a UNIX domain socket, the default ++ location is 'http.sock'. ++ + 1.4 Run + + 'make test'. This builds the test suite support code and invokes the +diff --git a/tests/httpserver.pl b/tests/httpserver.pl +index a38c3ce..1b8c3d2 100755 +--- a/tests/httpserver.pl ++++ b/tests/httpserver.pl +@@ -36,6 +36,7 @@ use serverhelp qw( + + my $verbose = 0; # set to 1 for debugging + my $port = 8990; # just a default ++my $unix_socket; # location to place a listening UNIX socket + my $ipvnum = 4; # default IP version of http server + my $idnum = 1; # dafault http server instance number + my $proto = 'http'; # protocol the http server speaks +@@ -74,6 +75,13 @@ while(@ARGV) { + elsif($ARGV[0] eq '--ipv6') { + $ipvnum = 6; + } ++ elsif($ARGV[0] eq '--unix-socket') { ++ $ipvnum = 'unix'; ++ if($ARGV[1]) { ++ $unix_socket = $ARGV[1]; ++ shift @ARGV; ++ } ++ } + elsif($ARGV[0] eq '--gopher') { + $gopher = 1; + } +@@ -117,7 +125,12 @@ if(!$logfile) { + $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; + $flags .= "--gopher " if($gopher); + $flags .= "--connect $connect " if($connect); +-$flags .= "--ipv$ipvnum --port $port --srcdir \"$srcdir\""; ++if($ipvnum eq 'unix') { ++ $flags .= "--unix-socket '$unix_socket' "; ++} else { ++ $flags .= "--ipv$ipvnum --port $port "; ++} ++$flags .= "--srcdir \"$srcdir\""; + + if($verbose) { + print STDERR "RUN: server/sws $flags\n"; +diff --git a/tests/runtests.pl b/tests/runtests.pl +index b39da66..fa96345 100755 +--- a/tests/runtests.pl ++++ b/tests/runtests.pl +@@ -140,6 +140,7 @@ my $GOPHER6PORT; # Gopher IPv6 server port + my $HTTPTLSPORT; # HTTP TLS (non-stunnel) server port + my $HTTPTLS6PORT; # HTTP TLS (non-stunnel) IPv6 server port + my $HTTPPROXYPORT; # HTTP proxy port, when using CONNECT ++my $HTTPUNIXPATH; # HTTP server UNIX domain socket path + + my $srcdir = $ENV{'srcdir'} || '.'; + my $CURL="../src/curl".exe_ext(); # what curl executable to run on the tests +@@ -201,10 +202,12 @@ my $ssl_version; # set if libcurl is built with SSL support + my $large_file; # set if libcurl is built with large file support + my $has_idn; # set if libcurl is built with IDN support + my $http_ipv6; # set if HTTP server has IPv6 support ++my $http_unix; # set if HTTP server has UNIX sockets support + my $ftp_ipv6; # set if FTP server has IPv6 support + my $tftp_ipv6; # set if TFTP server has IPv6 support + my $gopher_ipv6; # set if Gopher server has IPv6 support + my $has_ipv6; # set if libcurl is built with IPv6 support ++my $has_unix; # set if libcurl is built with UNIX sockets support + my $has_libz; # set if libcurl is built with libz support + my $has_getrlimit; # set if system has getrlimit() + my $has_ntlm; # set if libcurl is built with NTLM support +@@ -358,6 +361,13 @@ sub init_serverpidfile_hash { + } + } + } ++ for my $proto (('http', 'imap', 'pop3', 'smtp')) { ++ for my $ssl (('', 's')) { ++ my $serv = servername_id("$proto$ssl", "unix", 1); ++ my $pidf = server_pidfilename("$proto$ssl", "unix", 1); ++ $serverpidfile{$serv} = $pidf; ++ } ++ } + } + + ####################################################################### +@@ -641,11 +651,11 @@ sub stopserver { + # All servers relative to the given one must be stopped also + # + my @killservers; +- if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|))$/) { ++ if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) { + # given a stunnel based ssl server, also kill non-ssl underlying one + push @killservers, "${1}${2}"; + } +- elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|))$/) { ++ elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|-unix|))$/) { + # given a non-ssl server, also kill stunnel based ssl piggybacking one + push @killservers, "${1}s${2}"; + } +@@ -691,10 +701,12 @@ sub stopserver { + # assign requested address") + # + sub verifyhttp { +- my ($proto, $ipvnum, $idnum, $ip, $port) = @_; ++ my ($proto, $ipvnum, $idnum, $ip, $port_or_path) = @_; + my $server = servername_id($proto, $ipvnum, $idnum); + my $pid = 0; + my $bonus=""; ++ # $port_or_path contains a path for UNIX sockets, sws ignores the port ++ my $port = ($ipvnum eq "unix") ? 80 : $port_or_path; + + my $verifyout = "$LOGDIR/". + servername_canon($proto, $ipvnum, $idnum) .'_verify.out'; +@@ -714,6 +726,7 @@ sub verifyhttp { + $flags .= "--silent "; + $flags .= "--verbose "; + $flags .= "--globoff "; ++ $flags .= "--unix-socket '$port_or_path' " if $ipvnum eq "unix"; + $flags .= "-1 " if($has_axtls); + $flags .= "--insecure " if($proto eq 'https'); + $flags .= "\"$proto://$ip:$port/${bonus}verifiedserver\""; +@@ -1160,7 +1173,7 @@ sub responsiveserver { + # start the http server + # + sub runhttpserver { +- my ($proto, $verbose, $alt, $port) = @_; ++ my ($proto, $verbose, $alt, $port_or_path) = @_; + my $ip = $HOSTIP; + my $ipvnum = 4; + my $idnum = 1; +@@ -1188,6 +1201,10 @@ sub runhttpserver { + if ($doesntrun{$pidfile}) { + return (0,0); + } ++ elsif($alt eq "unix") { ++ # IP (protocol) is mutually exclusive with UNIX sockets ++ $ipvnum = "unix"; ++ } + + my $pid = processexists($pidfile); + if($pid > 0) { +@@ -1204,7 +1221,12 @@ sub runhttpserver { + $flags .= "--verbose " if($debugprotocol); + $flags .= "--pidfile \"$pidfile\" --logfile \"$logfile\" "; + $flags .= "--id $idnum " if($idnum > 1); +- $flags .= "--ipv$ipvnum --port $port --srcdir \"$srcdir\""; ++ if($ipvnum eq "unix") { ++ $flags .= "--unix-socket '$port_or_path' "; ++ } else { ++ $flags .= "--ipv$ipvnum --port $port_or_path "; ++ } ++ $flags .= "--srcdir \"$srcdir\""; + + my $cmd = "$perl $srcdir/httpserver.pl $flags"; + my ($httppid, $pid2) = startnew($cmd, $pidfile, 15, 0); +@@ -1219,7 +1241,7 @@ sub runhttpserver { + } + + # Server is up. Verify that we can speak to it. +- my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); ++ my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port_or_path); + if(!$pid3) { + logmsg "RUN: $srvrname server failed verification\n"; + # failed to talk to it properly. Kill the server and return failure +@@ -1984,7 +2006,7 @@ sub runsocksserver { + # be used to verify that a server present in %run hash is still functional + # + sub responsive_http_server { +- my ($proto, $verbose, $alt, $port) = @_; ++ my ($proto, $verbose, $alt, $port_or_path) = @_; + my $ip = $HOSTIP; + my $ipvnum = 4; + my $idnum = 1; +@@ -1997,8 +2019,12 @@ sub responsive_http_server { + elsif($alt eq "proxy") { + $idnum = 2; + } ++ elsif($alt eq "unix") { ++ # IP (protocol) is mutually exclusive with UNIX sockets ++ $ipvnum = "unix"; ++ } + +- return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port); ++ return &responsiveserver($proto, $ipvnum, $idnum, $ip, $port_or_path); + } + + ####################################################################### +@@ -2264,9 +2290,10 @@ sub checksystem { + @protocols = split(' ', lc($1)); + + # Generate a "proto-ipv6" version of each protocol to match the +- # IPv6 name. This works even if IPv6 support isn't ++ # IPv6 name and a "proto-unix" to match the variant which ++ # uses UNIX domain sockets. This works even if support isn't + # compiled in because the test will fail. +- push @protocols, map($_ . '-ipv6', @protocols); ++ push @protocols, map(("$_-ipv6", "$_-unix"), @protocols); + + # 'http-proxy' is used in test cases to do CONNECT through + push @protocols, 'http-proxy'; +@@ -2299,6 +2326,9 @@ sub checksystem { + if($feat =~ /IPv6/i) { + $has_ipv6 = 1; + } ++ if($feat =~ /unix-sockets/i) { ++ $has_unix = 1; ++ } + if($feat =~ /libz/i) { + $has_libz = 1; + } +@@ -2396,6 +2426,12 @@ sub checksystem { + } + } + ++ if($has_unix) { ++ # client has UNIX sockets support, check whether the HTTP server has it ++ my @sws = `server/sws --version`; ++ $http_unix = 1 if($sws[0] =~ /unix/); ++ } ++ + if(!$curl_debug && $torture) { + die "can't run torture tests since curl was not built with curldebug"; + } +@@ -2423,6 +2459,7 @@ sub checksystem { + logmsg sprintf(" track memory: %s\n", $curl_debug?"ON ":"OFF"); + logmsg sprintf("* valgrind: %8s", $valgrind?"ON ":"OFF"); + logmsg sprintf(" HTTP IPv6 %s\n", $http_ipv6?"ON ":"OFF"); ++ logmsg sprintf("* HTTP UNIX %s\n", $http_unix?"ON ":"OFF"); + logmsg sprintf("* FTP IPv6 %8s", $ftp_ipv6?"ON ":"OFF"); + logmsg sprintf(" Libtool lib: %s\n", $libtool?"ON ":"OFF"); + logmsg sprintf("* Shared build: %s\n", $has_shared); +@@ -2473,6 +2510,13 @@ sub checksystem { + logmsg "\n"; + } + ++ if($has_unix) { ++ logmsg "* UNIX socket paths:\n"; ++ if($http_unix) { ++ logmsg sprintf("* HTTP-UNIX:%s\n", $HTTPUNIXPATH); ++ } ++ } ++ + $has_textaware = ($^O eq 'MSWin32') || ($^O eq 'msys'); + + logmsg "***************************************** \n"; +@@ -2520,6 +2564,10 @@ sub subVariables { + $$thing =~ s/%TFTP6PORT/$TFTP6PORT/g; + $$thing =~ s/%TFTPPORT/$TFTPPORT/g; + ++ # server UNIX domain socket paths ++ ++ $$thing =~ s/%HTTPUNIXPATH/$HTTPUNIXPATH/g; ++ + # client IP addresses + + $$thing =~ s/%CLIENT6IP/$CLIENT6IP/g; +@@ -2707,6 +2755,11 @@ sub singletest { + next; + } + } ++ elsif($f eq "unix-sockets") { ++ if($has_unix) { ++ next; ++ } ++ } + elsif($f eq "libz") { + if($has_libz) { + next; +@@ -3219,11 +3272,11 @@ sub singletest { + my @killservers; + foreach my $server (@killtestservers) { + chomp $server; +- if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|))$/) { ++ if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) { + # given a stunnel ssl server, also kill non-ssl underlying one + push @killservers, "${1}${2}"; + } +- elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|))$/) { ++ elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|-unix|))$/) { + # given a non-ssl server, also kill stunnel piggybacking one + push @killservers, "${1}s${2}"; + } +@@ -3728,7 +3781,7 @@ sub startservers { + $what =~ s/[^a-z0-9-]//g; + + my $certfile; +- if($what =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|))$/) { ++ if($what =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|-unix|))$/) { + $certfile = ($whatlist[1]) ? $whatlist[1] : 'stunnel.pem'; + } + +@@ -4066,6 +4119,22 @@ sub startservers { + } + } + } ++ elsif($what eq "http-unix") { ++ if($torture && $run{'http-unix'} && ++ !responsive_http_server("http", $verbose, "unix", $HTTPUNIXPATH)) { ++ stopserver('http-unix'); ++ } ++ if(!$run{'http-unix'}) { ++ ($pid, $pid2) = runhttpserver("http", $verbose, "unix", ++ $HTTPUNIXPATH); ++ if($pid <= 0) { ++ return "failed starting HTTP-unix server"; ++ } ++ logmsg sprintf("* pid http-unix => %d %d\n", $pid, $pid2) ++ if($verbose); ++ $run{'http-unix'}="$pid $pid2"; ++ } ++ } + elsif($what eq "none") { + logmsg "* starts no server\n" if ($verbose); + } +@@ -4502,6 +4571,7 @@ $GOPHER6PORT = $base++; # Gopher IPv6 server port + $HTTPTLSPORT = $base++; # HTTP TLS (non-stunnel) server port + $HTTPTLS6PORT = $base++; # HTTP TLS (non-stunnel) IPv6 server port + $HTTPPROXYPORT = $base++; # HTTP proxy port, when using CONNECT ++$HTTPUNIXPATH = 'http.sock'; # HTTP server UNIX domain socket path + + ####################################################################### + # clear and create logging directory: +diff --git a/tests/serverhelp.pm b/tests/serverhelp.pm +index a1d1dc3..1fc621b 100644 +--- a/tests/serverhelp.pm ++++ b/tests/serverhelp.pm +@@ -109,8 +109,8 @@ sub servername_str { + + $ipver = (not $ipver) ? 'ipv4' : lc($ipver); + die "unsupported IP version: '$ipver'" unless($ipver && +- ($ipver =~ /^(4|6|ipv4|ipv6|-ipv4|-ipv6)$/)); +- $ipver = ($ipver =~ /6$/) ? '-IPv6' : ''; ++ ($ipver =~ /^(4|6|ipv4|ipv6|-ipv4|-ipv6|unix)$/)); ++ $ipver = ($ipver =~ /6$/) ? '-IPv6' : (($ipver =~ /unix$/) ? '-unix' : ''); + + $idnum = 1 if(not $idnum); + die "unsupported ID number: '$idnum'" unless($idnum && +-- +2.5.2 + + +From d2f7b1d51e356586356da87d1ae32c0c44274887 Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 27 Nov 2014 23:59:24 +0100 +Subject: [PATCH 06/11] tests: add two HTTP over UNIX socket tests + +test1435: a simple test that checks whether a HTTP request can be +performed over the UNIX socket. The hostname/port are interpreted +by sws and should be ignored by cURL. + +test1436: test for the ability to do two requests to the same host, +interleaved with one to a different hostname. + +Signed-off-by: Peter Wu + +Upstream-commit: 479abdd32eee15dab78d0cd6b1786d569680f0ac +Signed-off-by: Kamil Dudka +--- + tests/data/Makefile.am | 1 + + tests/data/Makefile.in | 1 + + tests/data/test1435 | 46 +++++++++++++++++++++++++++ + tests/data/test1436 | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 133 insertions(+) + create mode 100644 tests/data/test1435 + create mode 100644 tests/data/test1436 + +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index c4f76df..35bc6eb 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -93,6 +93,7 @@ test1379 test1380 test1381 test1382 test1383 test1384 test1385 test1386 \ + test1387 test1388 test1389 test1390 test1391 test1392 test1393 \ + test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \ + test1408 test1409 test1410 test1411 test1412 test1413 test1415 \ ++test1435 test1436 \ + test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ + test1508 test1529 \ + test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ +diff --git a/tests/data/Makefile.in b/tests/data/Makefile.in +index e73ca96..d5e5f01 100644 +--- a/tests/data/Makefile.in ++++ b/tests/data/Makefile.in +@@ -357,6 +357,7 @@ test1379 test1380 test1381 test1382 test1383 test1384 test1385 test1386 \ + test1387 test1388 test1389 test1390 test1391 test1392 test1393 \ + test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \ + test1408 test1409 test1410 test1411 test1412 test1413 test1415 \ ++test1435 test1436 \ + test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ + test1508 test1529 \ + test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ +diff --git a/tests/data/test1435 b/tests/data/test1435 +new file mode 100644 +index 0000000..56ff9d1 +--- /dev/null ++++ b/tests/data/test1435 +@@ -0,0 +1,46 @@ ++ ++ ++ ++HTTP ++HTTP GET ++unix sockets ++ ++ ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Sun, 16 Nov 2014 23:47:38 GMT ++Content-Length: 17 ++ ++Based on test300 ++ ++ ++ ++ ++ ++unix-sockets ++ ++ ++http-unix ++ ++ ++simple HTTP GET over UNIX socket ++ ++ ++--unix-socket %HTTPUNIXPATH http://server-interpreted.example.com/1435 ++ ++ ++ ++ ++ ++^User-Agent:.* ++ ++ ++GET /1435 HTTP/1.1 ++Host: server-interpreted.example.com ++Accept: */* ++ ++ ++ ++ +diff --git a/tests/data/test1436 b/tests/data/test1436 +new file mode 100644 +index 0000000..b16eadd +--- /dev/null ++++ b/tests/data/test1436 +@@ -0,0 +1,85 @@ ++ ++ ++ ++HTTP ++HTTP GET ++unix sockets ++ ++ ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Mon, 17 Nov 2014 13:42:47 GMT ++Content-Length: 6 ++ ++First ++ ++ ++HTTP/1.1 200 OK ++Date: Mon, 17 Nov 2014 13:42:48 GMT ++Content-Length: 7 ++ ++Second ++ ++ ++HTTP/1.1 200 OK ++Date: Mon, 17 Nov 2014 13:42:49 GMT ++Content-Length: 6 ++ ++Third ++ ++ ++ ++ ++ ++unix-sockets ++ ++ ++http-unix ++ ++ ++HTTP requests with multiple connections over UNIX socket ++ ++ ++--unix-socket %HTTPUNIXPATH http://one.example.com/14360001 http://two.example.com/14360002 http://one.example.com/14360003 ++ ++ ++ ++ ++ ++^User-Agent:.* ++ ++ ++GET /14360001 HTTP/1.1 ++Host: one.example.com ++Accept: */* ++ ++GET /14360002 HTTP/1.1 ++Host: two.example.com ++Accept: */* ++ ++GET /14360003 HTTP/1.1 ++Host: one.example.com ++Accept: */* ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Mon, 17 Nov 2014 13:42:47 GMT ++Content-Length: 6 ++ ++First ++HTTP/1.1 200 OK ++Date: Mon, 17 Nov 2014 13:42:48 GMT ++Content-Length: 7 ++ ++Second ++HTTP/1.1 200 OK ++Date: Mon, 17 Nov 2014 13:42:49 GMT ++Content-Length: 6 ++ ++Third ++ ++ ++ +-- +2.5.2 + + +From f784b2d3d6cf08193662a23aae9305f11c4a4559 Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 27 Nov 2014 23:59:25 +0100 +Subject: [PATCH 07/11] libcurl: add UNIX domain sockets support + +The ability to do HTTP requests over a UNIX domain socket has been +requested before, in Apr 2008 [0][1] and Sep 2010 [2]. While a +discussion happened, no patch seems to get through. I decided to give it +a go since I need to test a nginx HTTP server which listens on a UNIX +domain socket. + +One patch [3] seems to make it possible to use the +CURLOPT_OPENSOCKETFUNCTION function to gain a UNIX domain socket. +Another person wrote a Go program which can do HTTP over a UNIX socket +for Docker[4] which uses a special URL scheme (though the name contains +cURL, it has no relation to the cURL library). + +This patch considers support for UNIX domain sockets at the same level +as HTTP proxies / IPv6, it acts as an intermediate socket provider and +not as a separate protocol. Since this feature affects network +operations, a new feature flag was added ("unix-sockets") with a +corresponding CURL_VERSION_UNIX_SOCKETS macro. + +A new CURLOPT_UNIX_SOCKET_PATH option is added and documented. This +option enables UNIX domain sockets support for all requests on the +handle (replacing IP sockets and skipping proxies). + +A new configure option (--enable-unix-sockets) and CMake option +(ENABLE_UNIX_SOCKETS) can disable this optional feature. Note that I +deliberately did not mark this feature as advanced, this is a +feature/component that should easily be available. + + [0]: http://curl.haxx.se/mail/lib-2008-04/0279.html + [1]: http://daniel.haxx.se/blog/2008/04/14/http-over-unix-domain-sockets/ + [2]: http://sourceforge.net/p/curl/feature-requests/53/ + [3]: http://curl.haxx.se/mail/lib-2008-04/0361.html + [4]: https://github.com/Soulou/curl-unix-socket + +Signed-off-by: Peter Wu + +Upstream-commit: 970c22f970f0172e6a4c98ccc3176c740ddaa1c6 +Signed-off-by: Kamil Dudka +--- + configure | 112 +++++++++++++++++++++++++++++++++++++++ + configure.ac | 38 +++++++++++++ + docs/libcurl/curl_easy_setopt.3 | 12 +++++ + docs/libcurl/curl_version_info.3 | 2 + + docs/libcurl/symbols-in-versions | 2 + + include/curl/curl.h | 4 ++ + lib/Makefile.in | 1 + + lib/curl_addrinfo.c | 39 ++++++++++++++ + lib/curl_addrinfo.h | 4 ++ + lib/curl_config.h.in | 3 ++ + lib/url.c | 44 +++++++++++++++ + lib/urldata.h | 4 ++ + lib/version.c | 3 ++ + src/Makefile.in | 1 + + src/tool_getparam.c | 3 +- + tests/server/Makefile.in | 1 + + 16 files changed, 272 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index c5d1817..3e1f5d3 100755 +--- a/configure ++++ b/configure +@@ -889,6 +889,7 @@ SONAME_BUMP_TRUE + CFLAG_CURL_SYMBOL_HIDING + DOING_CURL_SYMBOL_HIDING_FALSE + DOING_CURL_SYMBOL_HIDING_TRUE ++USE_UNIX_SOCKETS + BUILD_LIBHOSTNAME_FALSE + BUILD_LIBHOSTNAME_TRUE + USE_EMBEDDED_ARES_FALSE +@@ -1159,6 +1160,7 @@ enable_sspi + enable_crypto_auth + enable_ntlm_wb + enable_tls_srp ++enable_unix_sockets + enable_cookies + enable_soname_bump + ' +@@ -1873,6 +1875,8 @@ Optional Features: + helper + --enable-tls-srp Enable TLS-SRP authentication + --disable-tls-srp Disable TLS-SRP authentication ++ --enable-unix-sockets Enable UNIX domain sockets ++ --disable-unix-sockets Disable UNIX domain sockets + --enable-cookies Enable cookies support + --disable-cookies Disable cookies support + --enable-soname-bump Enable enforced SONAME bump +@@ -2607,6 +2611,61 @@ $as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + + } # ac_fn_c_check_type ++ ++# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES ++# ---------------------------------------------------- ++# Tries to find if the field MEMBER exists in type AGGR, after including ++# INCLUDES, setting cache variable VAR accordingly. ++ac_fn_c_check_member () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 ++$as_echo_n "checking for $2.$3... " >&6; } ++if eval \${$4+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$5 ++int main (void) ++{ ++static $2 ac_aggr; ++if (ac_aggr.$3) ++return 0; ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ eval "$4=yes" ++else ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$5 ++int main (void) ++{ ++static $2 ac_aggr; ++if (sizeof ac_aggr.$3) ++return 0; ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ eval "$4=yes" ++else ++ eval "$4=no" ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++fi ++eval ac_res=\$$4 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_check_member + cat >config.log <<_ACEOF + This file contains any messages produced by compilers while + running configure, to aid debugging if configure makes a mistake. +@@ -5447,6 +5506,7 @@ PKGADD_VENDOR="curl.haxx.se" + curl_tls_srp_msg="no (--enable-tls-srp)" + curl_res_msg="default (--enable-ares / --enable-threaded-resolver)" + curl_ipv6_msg="no (--enable-ipv6)" ++curl_unix_sockets_msg="no (--enable-unix-sockets)" + curl_idn_msg="no (--with-{libidn,winidn})" + curl_manual_msg="no (--enable-manual)" + curl_libcurl_msg="enabled (--disable-libcurl-option)" +@@ -39239,6 +39299,53 @@ $as_echo "#define USE_TLS_SRP 1" >>confdefs.h + curl_tls_srp_msg="enabled" + fi + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable UNIX domain sockets" >&5 ++$as_echo_n "checking whether to enable UNIX domain sockets... " >&6; } ++# Check whether --enable-unix-sockets was given. ++if test "${enable_unix_sockets+set}" = set; then : ++ enableval=$enable_unix_sockets; case "$enableval" in ++ no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ want_unix_sockets=no ++ ;; ++ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ want_unix_sockets=yes ++ ;; ++ esac ++else ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: auto" >&5 ++$as_echo "auto" >&6; } ++ want_unix_sockets=auto ++ ++ ++fi ++ ++if test "x$want_unix_sockets" != "xno"; then ++ ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_path" "ac_cv_member_struct_sockaddr_un_sun_path" " ++ #include ++ ++" ++if test "x$ac_cv_member_struct_sockaddr_un_sun_path" = xyes; then : ++ ++ ++$as_echo "#define USE_UNIX_SOCKETS 1" >>confdefs.h ++ ++ USE_UNIX_SOCKETS=1 ++ ++ curl_unix_sockets_msg="enabled" ++ ++else ++ ++ if test "x$want_unix_sockets" = "xyes"; then ++ as_fn_error $? "--enable-unix-sockets is not available on this platform!" "$LINENO" 5 ++ fi ++ ++fi ++ ++fi ++ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable support for cookies" >&5 + $as_echo_n "checking whether to enable support for cookies... " >&6; } + # Check whether --enable-cookies was given. +@@ -39357,6 +39464,9 @@ fi + if test "x$IPV6_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES IPv6" + fi ++if test "x$USE_UNIX_SOCKETS" = "x1"; then ++ SUPPORT_FEATURES="$SUPPORT_FEATURES unix-sockets" ++fi + if test "x$HAVE_LIBZ" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES libz" + fi +@@ -42289,6 +42399,7 @@ _EOF + TLS-SRP support: ${curl_tls_srp_msg} + resolver: ${curl_res_msg} + ipv6 support: ${curl_ipv6_msg} ++ UNIX sockets support: ${curl_unix_sockets_msg} + IDN support: ${curl_idn_msg} + Build libcurl: Shared=${enable_shared}, Static=${enable_static} + Built-in manual: ${curl_manual_msg} +@@ -42319,6 +42430,7 @@ $as_echo "$as_me: Configured to build curl/libcurl: + TLS-SRP support: ${curl_tls_srp_msg} + resolver: ${curl_res_msg} + ipv6 support: ${curl_ipv6_msg} ++ UNIX sockets support: ${curl_unix_sockets_msg} + IDN support: ${curl_idn_msg} + Build libcurl: Shared=${enable_shared}, Static=${enable_static} + Built-in manual: ${curl_manual_msg} +diff --git a/configure.ac b/configure.ac +index 60a6b58..9612c2f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -156,6 +156,7 @@ dnl initialize all the info variables + curl_tls_srp_msg="no (--enable-tls-srp)" + curl_res_msg="default (--enable-ares / --enable-threaded-resolver)" + curl_ipv6_msg="no (--enable-ipv6)" ++curl_unix_sockets_msg="no (--enable-unix-sockets)" + curl_idn_msg="no (--with-{libidn,winidn})" + curl_manual_msg="no (--enable-manual)" + curl_libcurl_msg="enabled (--disable-libcurl-option)" +@@ -3302,6 +3303,39 @@ if test "$want_tls_srp" = "yes" && ( test "x$HAVE_GNUTLS_SRP" = "x1" || test "x$ + fi + + dnl ************************************************************ ++dnl disable UNIX domain sockets support ++dnl ++AC_MSG_CHECKING([whether to enable UNIX domain sockets]) ++AC_ARG_ENABLE(unix-sockets, ++AC_HELP_STRING([--enable-unix-sockets],[Enable UNIX domain sockets]) ++AC_HELP_STRING([--disable-unix-sockets],[Disable UNIX domain sockets]), ++[ case "$enableval" in ++ no) AC_MSG_RESULT(no) ++ want_unix_sockets=no ++ ;; ++ *) AC_MSG_RESULT(yes) ++ want_unix_sockets=yes ++ ;; ++ esac ], [ ++ AC_MSG_RESULT(auto) ++ want_unix_sockets=auto ++ ] ++) ++if test "x$want_unix_sockets" != "xno"; then ++ AC_CHECK_MEMBER([struct sockaddr_un.sun_path], [ ++ AC_DEFINE(USE_UNIX_SOCKETS, 1, [Use UNIX domain sockets]) ++ AC_SUBST(USE_UNIX_SOCKETS, [1]) ++ curl_unix_sockets_msg="enabled" ++ ], [ ++ if test "x$want_unix_sockets" = "xyes"; then ++ AC_MSG_ERROR([--enable-unix-sockets is not available on this platform!]) ++ fi ++ ], [ ++ #include ++ ]) ++fi ++ ++dnl ************************************************************ + dnl disable cookies support + dnl + AC_MSG_CHECKING([whether to enable support for cookies]) +@@ -3382,6 +3416,9 @@ fi + if test "x$IPV6_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES IPv6" + fi ++if test "x$USE_UNIX_SOCKETS" = "x1"; then ++ SUPPORT_FEATURES="$SUPPORT_FEATURES unix-sockets" ++fi + if test "x$HAVE_LIBZ" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES libz" + fi +@@ -3557,6 +3594,7 @@ AC_MSG_NOTICE([Configured to build curl/libcurl: + TLS-SRP support: ${curl_tls_srp_msg} + resolver: ${curl_res_msg} + ipv6 support: ${curl_ipv6_msg} ++ UNIX sockets support: ${curl_unix_sockets_msg} + IDN support: ${curl_idn_msg} + Build libcurl: Shared=${enable_shared}, Static=${enable_static} + Built-in manual: ${curl_manual_msg} +diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 +index d73b664..ad739e1 100644 +--- a/docs/libcurl/curl_easy_setopt.3 ++++ b/docs/libcurl/curl_easy_setopt.3 +@@ -961,6 +961,18 @@ systems support this option. (Added in 7.25.0) + Pass a long. Sets the interval, in seconds, that the operating system will wait + between sending keepalive probes. Not all operating systems support this + option. (Added in 7.25.0) ++.IP CURLOPT_UNIX_SOCKET_PATH ++Pass a \fIpath\fP to a UNIX domain socket. This enables the use of UNIX domain ++sockets as connection end point and sets the path to \fIpath\fP. If \fIpath\fP ++is NULL, then UNIX domain sockets are disabled. An empty string will result in ++an error at some point. ++ ++When enabled, cURL will connect to the UNIX domain socket instead of ++establishing a TCP connection to a host. Since no TCP connection is ++established, cURL does not need to resolve the DNS hostname in the URL. ++ ++The maximum path length on Cygwin, Linux and Solaris is 107. On other platforms ++might be even less. + .SH NAMES and PASSWORDS OPTIONS (Authentication) + .IP CURLOPT_NETRC + This parameter controls the preference of libcurl between using user names and +diff --git a/docs/libcurl/curl_version_info.3 b/docs/libcurl/curl_version_info.3 +index ccb2028..c148cbc 100644 +--- a/docs/libcurl/curl_version_info.3 ++++ b/docs/libcurl/curl_version_info.3 +@@ -133,6 +133,8 @@ libcurl was built with support for TLS-SRP. (Added in 7.21.4) + .IP CURL_VERSION_NTLM_WB + libcurl was built with support for NTLM delegation to a winbind helper. + (Added in 7.22.0) ++.IP CURL_VERSION_UNIX_SOCKETS ++libcurl was built with support for UNIX domain sockets. + .RE + \fIssl_version\fP is an ASCII string for the OpenSSL version used. If libcurl + has no SSL support, this is NULL. +diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions +index b275900..0f7469d 100644 +--- a/docs/libcurl/symbols-in-versions ++++ b/docs/libcurl/symbols-in-versions +@@ -503,6 +503,7 @@ CURLOPT_TLSAUTH_TYPE 7.21.4 + CURLOPT_TLSAUTH_USERNAME 7.21.4 + CURLOPT_TRANSFERTEXT 7.1.1 + CURLOPT_TRANSFER_ENCODING 7.21.6 ++CURLOPT_UNIX_SOCKET_PATH 7.40.0 + CURLOPT_UNRESTRICTED_AUTH 7.10.4 + CURLOPT_UPLOAD 7.1 + CURLOPT_URL 7.1 +@@ -703,6 +704,7 @@ CURL_VERSION_SPNEGO 7.10.8 + CURL_VERSION_SSL 7.10 + CURL_VERSION_SSPI 7.13.2 + CURL_VERSION_TLSAUTH_SRP 7.21.4 ++CURL_VERSION_UNIX_SOCKETS 7.40.0 + CURL_WAIT_POLLIN 7.28.0 + CURL_WAIT_POLLOUT 7.28.0 + CURL_WAIT_POLLPRI 7.28.0 +diff --git a/include/curl/curl.h b/include/curl/curl.h +index 8e548e3..14f6fd7 100644 +--- a/include/curl/curl.h ++++ b/include/curl/curl.h +@@ -1536,6 +1536,9 @@ typedef enum { + /* set the SMTP auth originator */ + CINIT(MAIL_AUTH, OBJECTPOINT, 217), + ++ /* Path to UNIX domain socket */ ++ CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231), ++ + CURLOPT_LASTENTRY /* the last unused */ + } CURLoption; + +@@ -2154,6 +2157,7 @@ typedef struct { + #define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */ + #define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ + #define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */ ++#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* UNIX domain sockets support */ + + /* + * NAME curl_version_info() +diff --git a/lib/Makefile.in b/lib/Makefile.in +index ca02e27..5ad2600 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -386,6 +386,7 @@ USE_OPENLDAP = @USE_OPENLDAP@ + USE_POLARSSL = @USE_POLARSSL@ + USE_SCHANNEL = @USE_SCHANNEL@ + USE_SSLEAY = @USE_SSLEAY@ ++USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ + USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ + VERSION = @VERSION@ + VERSIONED_FLAVOUR = @VERSIONED_FLAVOUR@ +diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c +index 10652c6..52e45ce 100644 +--- a/lib/curl_addrinfo.c ++++ b/lib/curl_addrinfo.c +@@ -33,6 +33,9 @@ + #ifdef HAVE_ARPA_INET_H + # include + #endif ++#ifdef HAVE_SYS_UN_H ++# include ++#endif + + #ifdef __VMS + # include +@@ -477,6 +480,42 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) + return NULL; /* bad input format */ + } + ++#ifdef USE_UNIX_SOCKETS ++/** ++ * Given a path to a UNIX domain socket, return a newly allocated Curl_addrinfo ++ * struct initialized with this path. ++ */ ++Curl_addrinfo *Curl_unix2addr(const char *path) ++{ ++ Curl_addrinfo *ai; ++ struct sockaddr_un *sun; ++ size_t path_len; ++ ++ ai = calloc(1, sizeof(Curl_addrinfo)); ++ if(!ai) ++ return NULL; ++ if((ai->ai_addr = calloc(1, sizeof(struct sockaddr_un))) == NULL) { ++ free(ai); ++ return NULL; ++ } ++ /* sun_path must be able to store the NUL-terminated path */ ++ path_len = strlen(path); ++ if(path_len >= sizeof(sun->sun_path)) { ++ free(ai->ai_addr); ++ free(ai); ++ return NULL; ++ } ++ ++ ai->ai_family = AF_UNIX; ++ ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ ++ ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); ++ sun = (void *) ai->ai_addr; ++ sun->sun_family = AF_UNIX; ++ memcpy(sun->sun_path, path, path_len + 1); /* copy NUL byte */ ++ return ai; ++} ++#endif ++ + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) + /* + * curl_dofreeaddrinfo() +diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h +index 6d2b753..4ef8827 100644 +--- a/lib/curl_addrinfo.h ++++ b/lib/curl_addrinfo.h +@@ -79,6 +79,10 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); + + Curl_addrinfo *Curl_str2addr(char *dotted, int port); + ++#ifdef USE_UNIX_SOCKETS ++Curl_addrinfo *Curl_unix2addr(const char *path); ++#endif ++ + #if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) + void + curl_dofreeaddrinfo(struct addrinfo *freethis, +diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in +index 1716c96..19b66fa 100644 +--- a/lib/curl_config.h.in ++++ b/lib/curl_config.h.in +@@ -1017,6 +1017,9 @@ + /* Use TLS-SRP authentication */ + #undef USE_TLS_SRP + ++/* Use UNIX domain sockets */ ++#undef USE_UNIX_SOCKETS ++ + /* Define to 1 if you have the `normaliz' (WinIDN) library (-lnormaliz). */ + #undef USE_WIN32_IDN + +diff --git a/lib/url.c b/lib/url.c +index 57944e4..7257b5e 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -47,6 +47,10 @@ + #include + #endif + ++#ifdef HAVE_SYS_UN_H ++#include ++#endif ++ + #ifndef HAVE_SOCKET + #error "We can't compile without socket() support!" + #endif +@@ -2429,6 +2433,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, + data->set.tcp_keepintvl = va_arg(param, long); + break; + ++#ifdef USE_UNIX_SOCKETS ++ case CURLOPT_UNIX_SOCKET_PATH: ++ result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ++ va_arg(param, char *)); ++ break; ++#endif ++ + default: + /* unknown tag and its companion, just ignore: */ + result = CURLE_UNKNOWN_OPTION; +@@ -4764,6 +4775,32 @@ static CURLcode resolve_server(struct SessionHandle *data, + /* set a pointer to the hostname we display */ + fix_hostname(data, conn, &conn->host); + ++#ifdef USE_UNIX_SOCKETS ++ if(data->set.str[STRING_UNIX_SOCKET_PATH]) { ++ /* UNIX domain sockets are local. The host gets ignored, just use the ++ * specified domain socket address. Do not cache "DNS entries". There is ++ * no DNS involved and we already have the filesystem path available */ ++ const char *path = data->set.str[STRING_UNIX_SOCKET_PATH]; ++ ++ hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); ++ if(!hostaddr) ++ result = CURLE_OUT_OF_MEMORY; ++ else if((hostaddr->addr = Curl_unix2addr(path)) != NULL) ++ hostaddr->inuse++; ++ else { ++ /* Long paths are not supported for now */ ++ if(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { ++ failf(data, "UNIX socket path too long: '%s'", path); ++ result = CURLE_COULDNT_RESOLVE_HOST; ++ } ++ else ++ result = CURLE_OUT_OF_MEMORY; ++ free(hostaddr); ++ hostaddr = NULL; ++ } ++ } ++ else ++#endif + if(!conn->proxy.name || !*conn->proxy.name) { + /* If not connecting via a proxy, extract the port from the URL, if it is + * there, thus overriding any defaults that might have been set above. */ +@@ -5071,6 +5108,13 @@ static CURLcode create_conn(struct SessionHandle *data, + else if(!proxy) + proxy = detect_proxy(conn); + ++#ifdef USE_UNIX_SOCKETS ++ if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) { ++ free(proxy); /* UNIX domain sockets cannot be proxied, so disable it */ ++ proxy = NULL; ++ } ++#endif ++ + if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) { + free(proxy); /* Don't bother with an empty proxy string or if the + protocol doesn't work with network */ +diff --git a/lib/urldata.h b/lib/urldata.h +index b3ee7e3..723e40d 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1375,6 +1375,10 @@ enum dupstring { + STRING_TLSAUTH_PASSWORD, /* TLS auth */ + #endif + ++#ifdef USE_UNIX_SOCKETS ++ STRING_UNIX_SOCKET_PATH, /* path to UNIX socket, if used */ ++#endif ++ + /* -- end of zero-terminated strings -- */ + + STRING_LASTZEROTERMINATED, +diff --git a/lib/version.c b/lib/version.c +index d39fe0c..e798738 100644 +--- a/lib/version.c ++++ b/lib/version.c +@@ -278,6 +278,9 @@ static curl_version_info_data version_info = { + #if defined(USE_TLS_SRP) + | CURL_VERSION_TLSAUTH_SRP + #endif ++#if defined(USE_UNIX_SOCKETS) ++ | CURL_VERSION_UNIX_SOCKETS ++#endif + , + NULL, /* ssl_version */ + 0, /* ssl_version_num, this is kept at zero */ +diff --git a/src/Makefile.in b/src/Makefile.in +index 5f739a9..948092f 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -272,6 +272,7 @@ USE_OPENLDAP = @USE_OPENLDAP@ + USE_POLARSSL = @USE_POLARSSL@ + USE_SCHANNEL = @USE_SCHANNEL@ + USE_SSLEAY = @USE_SSLEAY@ ++USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ + USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ + VERSION = @VERSION@ + VERSIONED_FLAVOUR = @VERSIONED_FLAVOUR@ +diff --git a/src/tool_getparam.c b/src/tool_getparam.c +index 98d53a7..0cd84d5 100644 +--- a/src/tool_getparam.c ++++ b/src/tool_getparam.c +@@ -285,7 +285,8 @@ static const struct feat feats[] = { + {"krb4", CURL_VERSION_KERBEROS4}, + {"libz", CURL_VERSION_LIBZ}, + {"CharConv", CURL_VERSION_CONV}, +- {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP} ++ {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP}, ++ {"unix-sockets", CURL_VERSION_UNIX_SOCKETS} + }; + + ParameterError getparameter(char *flag, /* f or -long-flag */ +diff --git a/tests/server/Makefile.in b/tests/server/Makefile.in +index 0ca4380..055fe9b 100644 +--- a/tests/server/Makefile.in ++++ b/tests/server/Makefile.in +@@ -329,6 +329,7 @@ USE_OPENLDAP = @USE_OPENLDAP@ + USE_POLARSSL = @USE_POLARSSL@ + USE_SCHANNEL = @USE_SCHANNEL@ + USE_SSLEAY = @USE_SSLEAY@ ++USE_UNIX_SOCKETS = @USE_UNIX_SOCKETS@ + USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@ + VERSION = @VERSION@ + VERSIONED_FLAVOUR = @VERSIONED_FLAVOUR@ +-- +2.5.2 + + +From 877e40cd741b5b65f503236a6947e38c28a2d6ce Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 27 Nov 2014 23:59:26 +0100 +Subject: [PATCH 08/11] tool: add --unix-socket option + +Signed-off-by: Peter Wu + +Upstream-commit: c8644d1f638fdd8f4bf34fe64e910ba704fb26c0 +Signed-off-by: Kamil Dudka +--- + src/tool_cfgable.c | 1 + + src/tool_cfgable.h | 2 ++ + src/tool_getparam.c | 6 +++++- + src/tool_help.c | 1 + + src/tool_operate.c | 4 ++++ + 5 files changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c +index da11f4a..2479b73 100644 +--- a/src/tool_cfgable.c ++++ b/src/tool_cfgable.c +@@ -98,6 +98,7 @@ void free_config_fields(struct Configurable *config) + + config->trace_stream = NULL; /* closed elsewhere when appropriate */ + ++ Curl_safefree(config->unix_socket_path); + Curl_safefree(config->writeout); + + config->errors = NULL; /* closed elsewhere when appropriate */ +diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h +index 1f6f948..a9b033b 100644 +--- a/src/tool_cfgable.h ++++ b/src/tool_cfgable.h +@@ -204,6 +204,8 @@ struct Configurable { + bool use_metalink; /* process given URLs as metalink XML file */ + metalinkfile *metalinkfile_list; /* point to the first node */ + metalinkfile *metalinkfile_last; /* point to the last/current node */ ++ ++ char *unix_socket_path; /* path to UNIX domain socket */ + }; /* struct Configurable */ + + void free_config_fields(struct Configurable *config); +diff --git a/src/tool_getparam.c b/src/tool_getparam.c +index 0cd84d5..57cf97d 100644 +--- a/src/tool_getparam.c ++++ b/src/tool_getparam.c +@@ -144,7 +144,7 @@ static const struct LongShort aliases[]= { + {"$v", "ssl-reqd", FALSE}, + /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */ + {"$w", "sessionid", FALSE}, +- /* �sessionid' listed as --no-sessionid in the help */ ++ /* ?sessionid' listed as --no-sessionid in the help */ + {"$x", "ftp-ssl-control", FALSE}, + {"$y", "ftp-ssl-ccc", FALSE}, + {"$j", "ftp-ssl-ccc-mode", TRUE}, +@@ -173,6 +173,7 @@ static const struct LongShort aliases[]= { + {"$H", "mail-auth", TRUE}, + {"$I", "post303", FALSE}, + {"$J", "metalink", FALSE}, ++ {"$M", "unix-socket", TRUE}, + {"0", "http1.0", FALSE}, + {"1", "tlsv1", FALSE}, + {"10", "tlsv1.0", FALSE}, +@@ -862,6 +863,9 @@ ParameterError getparameter(char *flag, /* f or -long-flag */ + #endif + break; + } ++ case 'M': /* --unix-socket */ ++ GetStr(&config->unix_socket_path, nextarg); ++ break; + } + break; + case '#': /* --progress-bar */ +diff --git a/src/tool_help.c b/src/tool_help.c +index f7cd618..3a64e35 100644 +--- a/src/tool_help.c ++++ b/src/tool_help.c +@@ -214,6 +214,7 @@ static const char *const helptext[] = { + " --tlsuser USER TLS username", + " --tlspassword STRING TLS password", + " --tlsauthtype STRING TLS authentication type (default SRP)", ++ " --unix-socket FILE Connect through this UNIX domain socket", + " -A, --user-agent STRING User-Agent to send to server (H)", + " -v, --verbose Make the operation more talkative", + " -V, --version Show version number and quit", +diff --git a/src/tool_operate.c b/src/tool_operate.c +index 4166fc2..7a13fcf 100644 +--- a/src/tool_operate.c ++++ b/src/tool_operate.c +@@ -1320,6 +1320,10 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) + if(config->mail_auth) + my_setopt_str(curl, CURLOPT_MAIL_AUTH, config->mail_auth); + ++ /* new in 7.40.0 */ ++ if(config->unix_socket_path) ++ my_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, config->unix_socket_path); ++ + /* initialize retry vars for loop below */ + retry_sleep_default = (config->retry_delay) ? + config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ +-- +2.5.2 + + +From 60bdcf03a1696b3d09ad1c04824816766c513dcd Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Wed, 3 Dec 2014 02:35:12 +0100 +Subject: [PATCH 09/11] curl.1: added --unix-socket + +Upstream-commit: 7853c1cfe6fc7828afbb812791a383781aca3be3 +Signed-off-by: Kamil Dudka +--- + docs/curl.1 | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/docs/curl.1 b/docs/curl.1 +index 7f3571b..38fa084 100644 +--- a/docs/curl.1 ++++ b/docs/curl.1 +@@ -1471,6 +1471,9 @@ If this option is used several times, the last one will be used. + .IP "--trace-time" + Prepends a time stamp to each trace or verbose line that curl displays. + (Added in 7.14.0) ++.IP "--unix-socket " ++(HTTP) Connect through this UNIX domain socket, instead of using the ++network. (Added in 7.40.0) + .IP "-u, --user " + Specify the user name and password to use for server authentication. Overrides + \fI-n, --netrc\fP and \fI--netrc-optional\fP. +-- +2.5.2 + + +From af6fa1e00657c637d52cc24eab6d769b8eb793a9 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 4 Dec 2014 02:46:15 +0100 +Subject: [PATCH 10/11] updateconninfo: clear destination struct before + getsockname() + +Otherwise we may read uninitialized bytes later in the unix-domain +sockets case. + +Upstream-commit: 9730c9fb7075792a112b65a023379fad3ec8dda4 +Signed-off-by: Kamil Dudka +--- + lib/connect.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/connect.c b/lib/connect.c +index ba9ab92..5aa53fe 100644 +--- a/lib/connect.c ++++ b/lib/connect.c +@@ -630,6 +630,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) + } + + len = sizeof(struct Curl_sockaddr_storage); ++ memset(&ssloc, 0, sizeof(ssloc)); + if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) { + error = SOCKERRNO; + failf(data, "getsockname() failed with errno %d: %s", +-- +2.5.2 + + +From 8d951bb327fb6a1e107e044dbc179096883c4489 Mon Sep 17 00:00:00 2001 +From: Peter Wu +Date: Thu, 4 Dec 2014 11:01:41 -0800 +Subject: [PATCH 11/11] tool: fix CURLOPT_UNIX_SOCKET_PATH in --libcurl output + +Mark CURLOPT_UNIX_SOCKET_PATH as string to ensure that it ends up as +option in the file generated by --libcurl. + +Signed-off-by: Peter Wu + +Upstream-commit: 2e557de09431854e4ad137cd741a582caa917517 +Signed-off-by: Kamil Dudka +--- + src/tool_operate.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/tool_operate.c b/src/tool_operate.c +index 7a13fcf..41b0e6b 100644 +--- a/src/tool_operate.c ++++ b/src/tool_operate.c +@@ -1322,7 +1322,8 @@ int operate(struct Configurable *config, int argc, argv_item_t argv[]) + + /* new in 7.40.0 */ + if(config->unix_socket_path) +- my_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, config->unix_socket_path); ++ my_setopt_str(curl, CURLOPT_UNIX_SOCKET_PATH, ++ config->unix_socket_path); + + /* initialize retry vars for loop below */ + retry_sleep_default = (config->retry_delay) ? +-- +2.5.2 + diff --git a/SOURCES/0037-curl-7.29.0-fa7d04fe.patch b/SOURCES/0037-curl-7.29.0-fa7d04fe.patch new file mode 100644 index 0000000..e4517af --- /dev/null +++ b/SOURCES/0037-curl-7.29.0-fa7d04fe.patch @@ -0,0 +1,271 @@ +From 95924615ab42529e4dc7b95da1115346bf607fc6 Mon Sep 17 00:00:00 2001 +From: Jeremy Lin +Date: Mon, 15 Sep 2014 21:16:46 -0700 +Subject: [PATCH 1/2] ssh: improve key file search + +For private keys, use the first match from: user-specified key file +(if provided), ~/.ssh/id_rsa, ~/.ssh/id_dsa, ./id_rsa, ./id_dsa + +Note that the previous code only looked for id_dsa files. id_rsa is +now generally preferred, as it supports larger key sizes. + +For public keys, use the user-specified key file, if provided. +Otherwise, try to extract the public key from the private key file. +This means that passing --pubkey is typically no longer required, +and makes the key-handling behavior more like OpenSSH. + +Upstream-commit: fa7d04fed4d4578fe29bdff0b5465f6e4a7da81a +Signed-off-by: Kamil Dudka +--- + docs/MANUAL | 26 ++++++++++++++------- + docs/curl.1 | 8 ++++++- + lib/ssh.c | 75 +++++++++++++++++++++++++++++++++++++++---------------------- + 3 files changed, 73 insertions(+), 36 deletions(-) + +diff --git a/docs/MANUAL b/docs/MANUAL +index 4ad2e13..3f8d9b8 100644 +--- a/docs/MANUAL ++++ b/docs/MANUAL +@@ -41,12 +41,19 @@ SIMPLE USAGE + + Get a file from an SSH server using SFTP: + +- curl -u username sftp://shell.example.com/etc/issue ++ curl -u username sftp://example.com/etc/issue + +- Get a file from an SSH server using SCP using a private key to authenticate: ++ Get a file from an SSH server using SCP using a private key ++ (not password-protected) to authenticate: + +- curl -u username: --key ~/.ssh/id_dsa --pubkey ~/.ssh/id_dsa.pub \ +- scp://shell.example.com/~/personal.txt ++ curl -u username: --key ~/.ssh/id_rsa \ ++ scp://example.com/~/file.txt ++ ++ Get a file from an SSH server using SCP using a private key ++ (password-protected) to authenticate: ++ ++ curl -u username: --key ~/.ssh/id_rsa --pass private_key_password \ ++ scp://example.com/~/file.txt + + Get the main page from an IPv6 web server: + +@@ -91,10 +98,13 @@ USING PASSWORDS + + SFTP / SCP + +- This is similar to FTP, but you can specify a private key to use instead of +- a password. Note that the private key may itself be protected by a password +- that is unrelated to the login password of the remote system. If you +- provide a private key file you must also provide a public key file. ++ This is similar to FTP, but you can use the --key option to specify a ++ private key to use instead of a password. Note that the private key may ++ itself be protected by a password that is unrelated to the login password ++ of the remote system; this password is specified using the --pass option. ++ Typically, curl will automatically extract the public key from the private ++ key file, but in cases where curl does not have the proper library support, ++ a matching public key file must be specified using the --pubkey option. + + HTTP + +diff --git a/docs/curl.1 b/docs/curl.1 +index 38fa084..d1675a0 100644 +--- a/docs/curl.1 ++++ b/docs/curl.1 +@@ -724,7 +724,8 @@ If this option is used several times, the last one will be used. If + unspecified, the option defaults to 60 seconds. + .IP "--key " + (SSL/SSH) Private key file name. Allows you to provide your private key in this +-separate file. ++separate file. For SSH, if not specified, curl tries the following candidates ++in order: '~/.ssh/id_rsa', '~/.ssh/id_dsa', './id_rsa', './id_dsa'. + + If this option is used several times, the last one will be used. + .IP "--key-type " +@@ -1124,6 +1125,11 @@ protocol instead of the default HTTP 1.1. + separate file. + + If this option is used several times, the last one will be used. ++ ++(As of 7.39.0, curl attempts to automatically extract the public key from the ++private key file, so passing this option is generally not required. Note that ++this public key extraction requires libcurl to be linked against a copy of ++libssh2 1.2.8 or higher that is itself linked against OpenSSL.) + .IP "-q" + If used as the first parameter on the command line, the \fIcurlrc\fP config + file will not be read and used. See the \fI-K, --config\fP for details on the +diff --git a/lib/ssh.c b/lib/ssh.c +index 43e3342..4ea7d9b 100644 +--- a/lib/ssh.c ++++ b/lib/ssh.c +@@ -780,7 +780,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) && + (strstr(sshc->authlist, "publickey") != NULL)) { + char *home = NULL; +- bool rsa_pub_empty_but_ok = FALSE; ++ bool out_of_memory = FALSE; + + sshc->rsa_pub = sshc->rsa = NULL; + +@@ -788,34 +788,55 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + HOME environment variable etc? */ + home = curl_getenv("HOME"); + +- if(data->set.str[STRING_SSH_PUBLIC_KEY] && +- !*data->set.str[STRING_SSH_PUBLIC_KEY]) +- rsa_pub_empty_but_ok = true; +- else if(data->set.str[STRING_SSH_PUBLIC_KEY]) +- sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]); +- else if(home) +- sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home); +- else +- /* as a final resort, try current dir! */ +- sshc->rsa_pub = strdup("id_dsa.pub"); +- +- if(!rsa_pub_empty_but_ok && (sshc->rsa_pub == NULL)) { +- Curl_safefree(home); +- state(conn, SSH_SESSION_FREE); +- sshc->actualcode = CURLE_OUT_OF_MEMORY; +- break; ++ if(data->set.str[STRING_SSH_PRIVATE_KEY]) ++ sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]); ++ else { ++ /* If no private key file is specified, try some common paths. */ ++ if(home) { ++ /* Try ~/.ssh first. */ ++ sshc->rsa = aprintf("%s/.ssh/id_rsa", home); ++ if(!sshc->rsa) ++ out_of_memory = TRUE; ++ else if(access(sshc->rsa, R_OK) != 0) { ++ Curl_safefree(sshc->rsa); ++ sshc->rsa = aprintf("%s/.ssh/id_dsa", home); ++ if(!sshc->rsa) ++ out_of_memory = TRUE; ++ else if(access(sshc->rsa, R_OK) != 0) { ++ Curl_safefree(sshc->rsa); ++ } ++ } ++ } ++ if(!out_of_memory && !sshc->rsa) { ++ /* Nothing found; try the current dir. */ ++ sshc->rsa = strdup("id_rsa"); ++ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { ++ Curl_safefree(sshc->rsa); ++ sshc->rsa = strdup("id_dsa"); ++ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) { ++ Curl_safefree(sshc->rsa); ++ /* Out of guesses. Set to the empty string to avoid ++ * surprising info messages. */ ++ sshc->rsa = strdup(""); ++ } ++ } ++ } + } + +- if(data->set.str[STRING_SSH_PRIVATE_KEY]) +- sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]); +- else if(home) +- sshc->rsa = aprintf("%s/.ssh/id_dsa", home); +- else +- /* as a final resort, try current dir! */ +- sshc->rsa = strdup("id_dsa"); ++ /* ++ * Unless the user explicitly specifies a public key file, let ++ * libssh2 extract the public key from the private key file. ++ * This is done by simply passing sshc->rsa_pub = NULL. ++ */ ++ if(data->set.str[STRING_SSH_PUBLIC_KEY]) { ++ sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); ++ if(!sshc->rsa_pub) ++ out_of_memory = TRUE; ++ } + +- if(sshc->rsa == NULL) { ++ if(out_of_memory || sshc->rsa == NULL) { + Curl_safefree(home); ++ Curl_safefree(sshc->rsa); + Curl_safefree(sshc->rsa_pub); + state(conn, SSH_SESSION_FREE); + sshc->actualcode = CURLE_OUT_OF_MEMORY; +@@ -828,8 +849,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + + Curl_safefree(home); + +- infof(data, "Using ssh public key file %s\n", sshc->rsa_pub); +- infof(data, "Using ssh private key file %s\n", sshc->rsa); ++ infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); ++ infof(data, "Using SSH private key file '%s'\n", sshc->rsa); + + state(conn, SSH_AUTH_PKEY); + } +-- +2.5.2 + + +From 2e18c6a12fc5dbab278670f22e58fcce51d32cac Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 15 Jan 2016 10:27:33 +0100 +Subject: [PATCH 2/2] ssh: make CURLOPT_SSH_PUBLIC_KEYFILE treat "" as NULL + +The CURLOPT_SSH_PUBLIC_KEYFILE option has been documented to handle +empty strings specially since curl-7_25_0-31-g05a443a but the behavior +was unintentionally removed in curl-7_38_0-47-gfa7d04f. + +This commit restores the original behavior and clarifies it in the +documentation that NULL and "" have both the same meaning when passed +to CURLOPT_SSH_PUBLIC_KEYFILE. + +Bug: http://curl.haxx.se/mail/lib-2016-01/0072.html + +Upstream-commit: be538e07667e1ba880b7201014be706851428d40 +Signed-off-by: Kamil Dudka +--- + docs/libcurl/curl_easy_setopt.3 | 6 +++--- + lib/ssh.c | 7 +++++-- + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 +index ad739e1..0a9375e 100644 +--- a/docs/libcurl/curl_easy_setopt.3 ++++ b/docs/libcurl/curl_easy_setopt.3 +@@ -2446,9 +2446,9 @@ Pass a char * pointing to a file name for your public key. If not used, + libcurl defaults to \fB$HOME/.ssh/id_dsa.pub\fP if the HOME environment + variable is set, and just "id_dsa.pub" in the current directory if HOME is not + set. (Added in 7.16.1) +-If an empty string is passed, libcurl will pass no public key to libssh2 +-which then tries to compute it from the private key, this is known to work +-when libssh2 1.4.0+ is linked against OpenSSL. (Added in 7.26.0) ++If NULL (or an empty string) is passed, libcurl will pass no public key to ++libssh2, which then tries to compute it from the private key. This is known ++to work with libssh2 1.4.0+ linked against OpenSSL. (Added in 7.26.0) + .IP CURLOPT_SSH_PRIVATE_KEYFILE + Pass a char * pointing to a file name for your private key. If not used, + libcurl defaults to \fB$HOME/.ssh/id_dsa\fP if the HOME environment variable +diff --git a/lib/ssh.c b/lib/ssh.c +index 4ea7d9b..589d4a3 100644 +--- a/lib/ssh.c ++++ b/lib/ssh.c +@@ -828,7 +828,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + * libssh2 extract the public key from the private key file. + * This is done by simply passing sshc->rsa_pub = NULL. + */ +- if(data->set.str[STRING_SSH_PUBLIC_KEY]) { ++ if(data->set.str[STRING_SSH_PUBLIC_KEY] ++ /* treat empty string the same way as NULL */ ++ && data->set.str[STRING_SSH_PUBLIC_KEY][0]) { + sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]); + if(!sshc->rsa_pub) + out_of_memory = TRUE; +@@ -849,7 +851,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + + Curl_safefree(home); + +- infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); ++ if(sshc->rsa_pub) ++ infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub); + infof(data, "Using SSH private key file '%s'\n", sshc->rsa); + + state(conn, SSH_AUTH_PKEY); +-- +2.5.0 + diff --git a/SOURCES/0038-curl-7.29.0-958d2ffb.patch b/SOURCES/0038-curl-7.29.0-958d2ffb.patch new file mode 100644 index 0000000..d5e24f2 --- /dev/null +++ b/SOURCES/0038-curl-7.29.0-958d2ffb.patch @@ -0,0 +1,71 @@ +From f3fb07d2576c71a6409c0c1662c3b5ac61c283ab Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 18 Sep 2015 17:07:22 +0200 +Subject: [PATCH 1/2] nss: check return values of NSS functions + +Upstream-commit: a9fd53887ba07cd8313a8b9706f2dc71d6b8ed1b +Signed-off-by: Kamil Dudka +--- + lib/nss.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/lib/nss.c b/lib/nss.c +index 0691394..763390d 100644 +--- a/lib/nss.c ++++ b/lib/nss.c +@@ -1491,9 +1491,13 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) + } + + /* Force handshake on next I/O */ +- SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE); ++ if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE) ++ != SECSuccess) ++ goto error; + +- SSL_SetURL(connssl->handle, conn->host.name); ++ /* propagate hostname to the TLS layer */ ++ if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess) ++ goto error; + + return CURLE_OK; + +-- +2.5.2 + + +From 6b301701920a7b36df02bd94cdde259882e521d2 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 18 Sep 2015 17:10:05 +0200 +Subject: [PATCH 2/2] nss: prevent NSS from incorrectly re-using a session + +Without this workaround, NSS re-uses a session cache entry despite the +server name does not match. This causes SNI host name to differ from +the actual host name. Consequently, certain servers (e.g. github.com) +respond by 400 to such requests. + +Bug: https://bugzilla.mozilla.org/1202264 + +Upstream-commit: 958d2ffb198166a062a0ff20d009c64972a2b374 +Signed-off-by: Kamil Dudka +--- + lib/nss.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/lib/nss.c b/lib/nss.c +index 763390d..88d1a0d 100644 +--- a/lib/nss.c ++++ b/lib/nss.c +@@ -1499,6 +1499,10 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) + if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess) + goto error; + ++ /* prevent NSS from re-using the session for a different hostname */ ++ if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess) ++ goto error; ++ + return CURLE_OK; + + error: +-- +2.5.2 + diff --git a/SOURCES/0039-curl-7.29.0-4ef6b2d6.patch b/SOURCES/0039-curl-7.29.0-4ef6b2d6.patch new file mode 100644 index 0000000..8c623fc --- /dev/null +++ b/SOURCES/0039-curl-7.29.0-4ef6b2d6.patch @@ -0,0 +1,44 @@ +From 853653f4958e73bfd90a74a3ca910484ff86d9b0 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 12 Feb 2016 18:39:57 +0100 +Subject: [PATCH] curl.1: --disable-{eprt,epsv} are ignored for IPv6 hosts + +The behavior has been clarified in CURLOPT_FTP_USE_{EPRT,EPSV}.3 man +pages since curl-7_12_3~131. This patch makes it clear in the curl.1 +man page, too. + +Bug: https://bugzilla.redhat.com/1305970 + +Upstream-commit: 4ef6b2d6c60824d7c598a4ca8a70f0ef4fa3d443 +Signed-off-by: Kamil Dudka +--- + docs/curl.1 | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/docs/curl.1 b/docs/curl.1 +index d1675a0..ad26007 100644 +--- a/docs/curl.1 ++++ b/docs/curl.1 +@@ -357,6 +357,9 @@ the traditional PORT command. + \fB--eprt\fP can be used to explicitly enable EPRT again and \fB--no-eprt\fP + is an alias for \fB--disable-eprt\fP. + ++If the server is an IPv6 host, this option will have no effect as EPRT is ++necessary then. ++ + Disabling EPRT only changes the active behavior. If you want to switch to + passive mode you need to not use \fI-P, --ftp-port\fP or force it with + \fI--ftp-pasv\fP. +@@ -368,6 +371,9 @@ but with this option, it will not try using EPSV. + \fB--epsv\fP can be used to explicitly enable EPSV again and \fB--no-epsv\fP + is an alias for \fB--disable-epsv\fP. + ++If the server is an IPv6 host, this option will have no effect as EPSV is ++necessary then. ++ + Disabling EPSV only changes the passive behavior. If you want to switch to + active mode you need to use \fI-P, --ftp-port\fP. + .IP "-e, --referer " +-- +2.5.0 + diff --git a/SOURCES/0040-curl-7.29.0-513e587c.patch b/SOURCES/0040-curl-7.29.0-513e587c.patch new file mode 100644 index 0000000..b2720da --- /dev/null +++ b/SOURCES/0040-curl-7.29.0-513e587c.patch @@ -0,0 +1,218 @@ +From 070718b3e00d0341d44dd5ad4b48fd4468d047c6 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 9 Mar 2013 22:26:07 +0100 +Subject: [PATCH 1/3] curl_multi_wait: avoid second loop if nothing to do + +... hopefully this will also make clang-analyzer stop warning on +potentional NULL dereferences (which were false positives anyway). + +Upstream-commit: 136a3a0ee25f28fec1dde216467389f9e6e4f65c +Signed-off-by: Kamil Dudka +--- + lib/multi.c | 55 ++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 32 insertions(+), 23 deletions(-) + +diff --git a/lib/multi.c b/lib/multi.c +index 6dfce9b..1136849 100644 +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -804,7 +804,8 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; + int bitmap; + unsigned int i; +- unsigned int nfds = extra_nfds; ++ unsigned int nfds = 0; ++ unsigned int curlfds; + struct pollfd *ufds = NULL; + long timeout_internal; + +@@ -842,6 +843,9 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + easy = easy->next; /* check next handle */ + } + ++ curlfds = nfds; /* number of internal file descriptors */ ++ nfds += extra_nfds; /* add the externally provided ones */ ++ + if(nfds) { + ufds = malloc(nfds * sizeof(struct pollfd)); + if(!ufds) +@@ -849,32 +853,37 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + } + nfds = 0; + +- /* Add the curl handles to our pollfds first */ +- easy=multi->easy.next; +- while(easy != &multi->easy) { +- bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); ++ /* only do the second loop if we found descriptors in the first stage run ++ above */ + +- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { +- curl_socket_t s = CURL_SOCKET_BAD; ++ if(curlfds) { ++ /* Add the curl handles to our pollfds first */ ++ easy=multi->easy.next; ++ while(easy != &multi->easy) { ++ bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE); + +- if(bitmap & GETSOCK_READSOCK(i)) { +- ufds[nfds].fd = sockbunch[i]; +- ufds[nfds].events = POLLIN; +- ++nfds; +- s = sockbunch[i]; +- } +- if(bitmap & GETSOCK_WRITESOCK(i)) { +- ufds[nfds].fd = sockbunch[i]; +- ufds[nfds].events = POLLOUT; +- ++nfds; +- s = sockbunch[i]; +- } +- if(s == CURL_SOCKET_BAD) { +- break; ++ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { ++ curl_socket_t s = CURL_SOCKET_BAD; ++ ++ if(bitmap & GETSOCK_READSOCK(i)) { ++ ufds[nfds].fd = sockbunch[i]; ++ ufds[nfds].events = POLLIN; ++ ++nfds; ++ s = sockbunch[i]; ++ } ++ if(bitmap & GETSOCK_WRITESOCK(i)) { ++ ufds[nfds].fd = sockbunch[i]; ++ ufds[nfds].events = POLLOUT; ++ ++nfds; ++ s = sockbunch[i]; ++ } ++ if(s == CURL_SOCKET_BAD) { ++ break; ++ } + } +- } + +- easy = easy->next; /* check next handle */ ++ easy = easy->next; /* check next handle */ ++ } + } + + /* Add external file descriptions from poll-like struct curl_waitfd */ +-- +2.5.5 + + +From f8b84a52088a99d8128c2234f626ed233beabeae Mon Sep 17 00:00:00 2001 +From: Evgeny Turnaev +Date: Thu, 18 Jul 2013 00:06:09 +0200 +Subject: [PATCH 2/3] curl_multi_wait: set revents for extra fds + +Pass back the revents that happened for the user-provided file +descriptors. + +Upstream-commit: 6d30f8ebed34e7276c2a59ee20d466bff17fee56 +Signed-off-by: Kamil Dudka +--- + lib/multi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/lib/multi.c b/lib/multi.c +index 1136849..81bcfba 100644 +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -803,7 +803,7 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + struct Curl_one_easy *easy; + curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; + int bitmap; +- unsigned int i; ++ unsigned int i, j; + unsigned int nfds = 0; + unsigned int curlfds; + struct pollfd *ufds = NULL; +@@ -905,6 +905,9 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + else + i = 0; + ++ for(j = nfds - extra_nfds; j < nfds; j++) ++ extra_fds[j].revents = ufds[j].revents; ++ + Curl_safefree(ufds); + if(ret) + *ret = i; +-- +2.5.5 + + +From db2e5b5ffe5408aa892dee9e7f036fe0ea16963d Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 18 Jul 2013 23:36:59 +0200 +Subject: [PATCH 3/3] curl_multi_wait: fix revents + +Commit 6d30f8ebed34e7276 didn't work properly. First, it used the wrong +array index, but this fix also: + +1 - only does the copying if indeed there was any activity + +2 - makes sure to properly translate between internal and external +bitfields, which are not guaranteed to match + +Reported-by: Evgeny Turnaev + +Upstream-commit: 513e587c5eb966038731530c8f47fe0cf27513ce +Signed-off-by: Kamil Dudka +--- + lib/multi.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +diff --git a/lib/multi.c b/lib/multi.c +index 81bcfba..0e0bb19 100644 +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -803,7 +803,7 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + struct Curl_one_easy *easy; + curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; + int bitmap; +- unsigned int i, j; ++ unsigned int i; + unsigned int nfds = 0; + unsigned int curlfds; + struct pollfd *ufds = NULL; +@@ -899,15 +899,33 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, + ++nfds; + } + +- if(nfds) ++ if(nfds) { + /* wait... */ + i = Curl_poll(ufds, nfds, timeout_ms); ++ ++ if(i) { ++ unsigned int j; ++ /* copy revents results from the poll to the curl_multi_wait poll ++ struct, the bit values of the actual underlying poll() implementation ++ may not be the same as the ones in the public libcurl API! */ ++ for(j = 0; j < extra_nfds; j++) { ++ unsigned short mask = 0; ++ unsigned r = ufds[curlfds + j].revents; ++ ++ if(r & POLLIN) ++ mask |= CURL_WAIT_POLLIN; ++ if(r & POLLOUT) ++ mask |= CURL_WAIT_POLLOUT; ++ if(r & POLLPRI) ++ mask |= CURL_WAIT_POLLPRI; ++ ++ extra_fds[j].revents = mask; ++ } ++ } ++ } + else + i = 0; + +- for(j = nfds - extra_nfds; j < nfds; j++) +- extra_fds[j].revents = ufds[j].revents; +- + Curl_safefree(ufds); + if(ret) + *ret = i; +-- +2.5.5 + diff --git a/SOURCES/0041-curl-7.29.0-b2dcf034.patch b/SOURCES/0041-curl-7.29.0-b2dcf034.patch new file mode 100644 index 0000000..56a3567 --- /dev/null +++ b/SOURCES/0041-curl-7.29.0-b2dcf034.patch @@ -0,0 +1,59 @@ +From ac2121bf962ecc054dd103ccd42a93912051672e Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Tue, 21 Jun 2016 12:40:26 +0200 +Subject: [PATCH] curl-compilers.m4: improve detection of GCC's -fvisibility= + flag + +Some builds of GCC produce output on both stdout and stderr when --help +--verbose is used. The 2>&1 redirection caused them to be arbitrarily +interleaved with each other because of stream buffering. Consequently, +grep failed to match the fvisibility= string in the mixed output, even +though the string was present in GCC's standard output. + +This led to silently disabling symbol hiding in some builds of curl. + +Upstream-commit: b2dcf0347f1ee5041cccd64632bb8dd7ccbbae91 +Signed-off-by: Kamil Dudka +--- + configure | 2 +- + m4/curl-compilers.m4 | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index 4797e02..fc260ee 100755 +--- a/configure ++++ b/configure +@@ -17636,7 +17636,7 @@ $as_echo_n "checking if compiler supports hiding library internal symbols... " > + ;; + GNU_C) + if test "$compiler_num" -ge "304"; then +- if $CC --help --verbose 2>&1 | grep fvisibility= > /dev/null ; then ++ if $CC --help --verbose 2>/dev/null | grep fvisibility= >/dev/null ; then + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" +diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 +index ca064dd..77371de 100644 +--- a/m4/curl-compilers.m4 ++++ b/m4/curl-compilers.m4 +@@ -21,7 +21,7 @@ + #*************************************************************************** + + # File version for 'aclocal' use. Keep it a single number. +-# serial 65 ++# serial 66 + + + dnl CURL_CHECK_COMPILER +@@ -1391,7 +1391,7 @@ AC_DEFUN([CURL_CHECK_COMPILER_SYMBOL_HIDING], [ + GNU_C) + dnl Only gcc 3.4 or later + if test "$compiler_num" -ge "304"; then +- if $CC --help --verbose 2>&1 | grep fvisibility= > /dev/null ; then ++ if $CC --help --verbose 2>/dev/null | grep fvisibility= >/dev/null ; then + tmp_EXTERN="__attribute__ ((__visibility__ (\"default\")))" + tmp_CFLAGS="-fvisibility=hidden" + supports_symbol_hiding="yes" +-- +2.5.5 + diff --git a/SOURCES/0042-curl-7.29.0-CVE-2016-5419.patch b/SOURCES/0042-curl-7.29.0-CVE-2016-5419.patch new file mode 100644 index 0000000..a634f25 --- /dev/null +++ b/SOURCES/0042-curl-7.29.0-CVE-2016-5419.patch @@ -0,0 +1,105 @@ +From a22c0daa87598a016bf0b5c93bb2ff63be5577f9 Mon Sep 17 00:00:00 2001 +From: Paul Donohue +Date: Tue, 15 Oct 2013 21:36:32 +0200 +Subject: [PATCH 1/2] NSS: acknowledge the + --no-sessionid/CURLOPT_SSL_SESSIONID_CACHE option + +Upstream-commit: f63603dec4519857498602f7a00acc0ffed29753 +Signed-off-by: Kamil Dudka +--- + lib/nss.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/lib/nss.c b/lib/nss.c +index 83bb354..1f02988 100644 +--- a/lib/nss.c ++++ b/lib/nss.c +@@ -1362,8 +1362,9 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) + if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) + goto error; + +- /* do not use SSL cache if we are not going to verify peer */ +- ssl_no_cache = (data->set.ssl.verifypeer) ? PR_FALSE : PR_TRUE; ++ /* do not use SSL cache if disabled or we are not going to verify peer */ ++ ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ? ++ PR_FALSE : PR_TRUE; + if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) + goto error; + +-- +2.5.5 + + +From e164f1a355900f7f164d28ac9f937ad82d9ca45f Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 1 Jul 2016 13:32:31 +0200 +Subject: [PATCH 2/2] TLS: switch off SSL session id when client cert is used + +CVE-2016-5419 +Bug: https://curl.haxx.se/docs/adv_20160803A.html +Reported-by: Bru Rom +Contributions-by: Eric Rescorla and Ray Satiro + +Upstream-commit: 247d890da88f9ee817079e246c59f3d7d12fde5f +Signed-off-by: Kamil Dudka +--- + lib/sslgen.c | 10 ++++++++++ + lib/url.c | 1 + + lib/urldata.h | 1 + + 3 files changed, 12 insertions(+) + +diff --git a/lib/sslgen.c b/lib/sslgen.c +index 4875874..3036bb2 100644 +--- a/lib/sslgen.c ++++ b/lib/sslgen.c +@@ -147,6 +147,15 @@ Curl_clone_ssl_config(struct ssl_config_data *source, + else + dest->random_file = NULL; + ++ if(source->clientcert) { ++ dest->clientcert = strdup(source->clientcert); ++ if(!dest->clientcert) ++ return FALSE; ++ dest->sessionid = FALSE; ++ } ++ else ++ dest->clientcert = NULL; ++ + return TRUE; + } + +@@ -157,6 +166,7 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->random_file); ++ Curl_safefree(sslc->clientcert); + } + + #ifdef USE_SSL +diff --git a/lib/url.c b/lib/url.c +index 7257b5e..959510d 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -5255,6 +5255,7 @@ static CURLcode create_conn(struct SessionHandle *data, + data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; ++ data->set.ssl.clientcert = data->set.str[STRING_CERT]; + #ifdef USE_TLS_SRP + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; +diff --git a/lib/urldata.h b/lib/urldata.h +index 723e40d..f4c6222 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -340,6 +340,7 @@ struct ssl_config_data { + char *CAfile; /* certificate to verify peer against */ + const char *CRLfile; /* CRL to check certificate revocation */ + const char *issuercert;/* optional issuer certificate filename */ ++ char *clientcert; + char *random_file; /* path to file containing "random" data */ + char *egdsocket; /* path to file containing the EGD daemon socket */ + char *cipher_list; /* list of ciphers to use */ +-- +2.5.5 + diff --git a/SOURCES/0043-curl-7.29.0-CVE-2016-5420.patch b/SOURCES/0043-curl-7.29.0-CVE-2016-5420.patch new file mode 100644 index 0000000..532e974 --- /dev/null +++ b/SOURCES/0043-curl-7.29.0-CVE-2016-5420.patch @@ -0,0 +1,75 @@ +From 1b6dc2b543446401fd38795f1ccf2b93633f01c0 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sun, 31 Jul 2016 00:51:48 +0200 +Subject: [PATCH 1/2] TLS: only reuse connections with the same client cert + +CVE-2016-5420 +Bug: https://curl.haxx.se/docs/adv_20160803B.html + +Upstream-commit: 11ec5ad4352bba384404c56e77c7fab9382fd22d +Signed-off-by: Kamil Dudka +--- + lib/sslgen.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/sslgen.c b/lib/sslgen.c +index 3036bb2..79cbb6f 100644 +--- a/lib/sslgen.c ++++ b/lib/sslgen.c +@@ -90,6 +90,7 @@ Curl_ssl_config_matches(struct ssl_config_data* data, + (data->verifyhost == needle->verifyhost) && + safe_strequal(data->CApath, needle->CApath) && + safe_strequal(data->CAfile, needle->CAfile) && ++ safe_strequal(data->clientcert, needle->clientcert) && + safe_strequal(data->random_file, needle->random_file) && + safe_strequal(data->egdsocket, needle->egdsocket) && + safe_strequal(data->cipher_list, needle->cipher_list)) +-- +2.5.5 + + +From 1a7116f8607868b26355c512e5844a9b85f16daf Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Mon, 22 Aug 2016 10:24:35 +0200 +Subject: [PATCH 2/2] nss: refuse previously loaded certificate from file + +... when we are not asked to use a certificate from file + +Upstream-commit: 7700fcba64bf5806de28f6c1c7da3b4f0b38567d +Signed-off-by: Kamil Dudka +--- + lib/nss.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/lib/nss.c b/lib/nss.c +index 1f02988..7b4fe57 100644 +--- a/lib/nss.c ++++ b/lib/nss.c +@@ -760,10 +760,10 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, + struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; + struct SessionHandle *data = connssl->data; + const char *nickname = connssl->client_nickname; ++ static const char pem_slotname[] = "PEM Token #1"; + + if(connssl->obj_clicert) { + /* use the cert/key provided by PEM reader */ +- static const char pem_slotname[] = "PEM Token #1"; + SECItem cert_der = { 0, NULL, 0 }; + void *proto_win = SSL_RevealPinArg(sock); + struct CERTCertificateStr *cert; +@@ -825,6 +825,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, + if(NULL == nickname) + nickname = "[unknown]"; + ++ if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { ++ failf(data, "NSS: refusing previously loaded certificate from file: %s", ++ nickname); ++ return SECFailure; ++ } ++ + if(NULL == *pRetKey) { + failf(data, "NSS: private key not found for certificate: %s", nickname); + return SECFailure; +-- +2.7.4 + diff --git a/SOURCES/0102-curl-7.29.0-debug.patch b/SOURCES/0102-curl-7.29.0-debug.patch index 7f70530..090afdb 100644 --- a/SOURCES/0102-curl-7.29.0-debug.patch +++ b/SOURCES/0102-curl-7.29.0-debug.patch @@ -12,7 +12,7 @@ diff --git a/configure b/configure index 8f079a3..53b4774 100755 --- a/configure +++ b/configure -@@ -15759,18 +15759,11 @@ $as_echo "yes" >&6; } +@@ -15819,18 +15819,11 @@ $as_echo "yes" >&6; } gccvhi=`echo $gccver | cut -d . -f1` gccvlo=`echo $gccver | cut -d . -f2` compiler_num=`(expr $gccvhi "*" 100 + $gccvlo) 2>/dev/null` diff --git a/SPECS/curl.spec b/SPECS/curl.spec index 122a47a..e591f0c 100644 --- a/SPECS/curl.spec +++ b/SPECS/curl.spec @@ -1,7 +1,7 @@ Summary: A utility for getting files from remote servers (FTP, HTTP, and others) Name: curl Version: 7.29.0 -Release: 25%{?dist} +Release: 35%{?dist} License: MIT Group: Applications/Internet Source: http://curl.haxx.se/download/%{name}-%{version}.tar.lzma @@ -106,6 +106,36 @@ Patch32: 0032-curl-7.29.0-CVE-2015-3148.patch # improve handling of timeouts and blocking direction to speed up FTP (#1218272) Patch33: 0033-curl-7.29.0-29bf0598.patch +# prevent test46 from failing due to expired cookie (#1258834) +Patch34: 0034-curl-7.29.0-002d58f1.patch + +# improve parsing of URL-encoded user name and password (#1260178) +Patch35: 0035-curl-7.29.0-2f1a0bc0.patch + +# implement 'curl --unix-socket' and CURLOPT_UNIX_SOCKET_PATH (#1263318) +Patch36: 0036-curl-7.29.0-c8644d1f.patch + +# SSH: do not require public key file for user authentication (#1275769) +Patch37: 0037-curl-7.29.0-fa7d04fe.patch + +# prevent NSS from incorrectly re-using a session (#1269855) +Patch38: 0038-curl-7.29.0-958d2ffb.patch + +# curl.1: --disable-{eprt,epsv} are ignored for IPv6 hosts (#1305974) +Patch39: 0039-curl-7.29.0-4ef6b2d6.patch + +# prevent curl_multi_wait() from missing an event (#1347904) +Patch40: 0040-curl-7.29.0-513e587c.patch + +# configure: improve detection of GCC's -fvisibility= flag +Patch41: 0041-curl-7.29.0-b2dcf034.patch + +# fix TLS session resumption client cert bypass (CVE-2016-5419) +Patch42: 0042-curl-7.29.0-CVE-2016-5419.patch + +# fix re-using connections with wrong client cert (CVE-2016-5420) +Patch43: 0043-curl-7.29.0-CVE-2016-5420.patch + # patch making libcurl multilib ready Patch101: 0101-curl-7.29.0-multilib.patch @@ -254,6 +284,13 @@ documentation of the library, too. %patch31 -p1 %patch32 -p1 %patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 # Fedora/RHEL patches %patch101 -p1 @@ -264,24 +301,24 @@ documentation of the library, too. %patch107 -p1 %patch108 -p1 +# upstream patches +%patch41 -p1 +%patch42 -p1 +%patch43 -p1 + # replace hard wired port numbers in the test suite cd tests/data/ sed -i s/899\\\([0-9]\\\)/%{?__isa_bits}9\\1/ test* cd - -# disable test 1112 (#565305) -printf "1112\n" >> tests/data/DISABLED +# disable test 1112 (#565305) and test 2032 (#1241168) +printf "1112\n2032\n" >> tests/data/DISABLED # disable test 1319 on ppc64 (server times out) %ifarch ppc64 echo "1319" >> tests/data/DISABLED %endif -#skip 2 test from CentOS -echo "46" >> tests/data/DISABLED -echo "2032" >> tests/data/DISABLED -# - %build [ -x /usr/kerberos/bin/krb5-config ] && KRB5_PREFIX="=/usr/kerberos" %configure --disable-static \ @@ -377,8 +414,42 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/aclocal/libcurl.m4 %changelog -* Sun Nov 22 2015 Johnny Hughes 7.29.0-25 -- skip 2 failed tests on centos builds +* Fri Aug 26 2016 Kamil Dudka 7.29.0-35 +- fix incorrect use of a previously loaded certificate from file + (related to CVE-2016-5420) + +* Wed Aug 17 2016 Kamil Dudka 7.29.0-34 +- acknowledge the --no-sessionid/CURLOPT_SSL_SESSIONID_CACHE option + (required by the fix for CVE-2016-5419) + +* Thu Aug 11 2016 Kamil Dudka 7.29.0-33 +- fix re-using connections with wrong client cert (CVE-2016-5420) +- fix TLS session resumption client cert bypass (CVE-2016-5419) + +* Mon Jun 20 2016 Kamil Dudka 7.29.0-32 +- configure: improve detection of GCC's -fvisibility= flag + +* Mon Jun 20 2016 Kamil Dudka 7.29.0-31 +- prevent curl_multi_wait() from missing an event (#1347904) + +* Tue Feb 16 2016 Kamil Dudka 7.29.0-30 +- curl.1: --disable-{eprt,epsv} are ignored for IPv6 hosts (#1305974) + +* Fri Jan 15 2016 Kamil Dudka 7.29.0-29 +- SSH: make CURLOPT_SSH_PUBLIC_KEYFILE treat "" as NULL (#1275769) + +* Mon Nov 02 2015 Kamil Dudka 7.29.0-28 +- prevent NSS from incorrectly re-using a session (#1269855) +- call PR_Cleanup() in the upstream test-suite if NSPR is used (#1243324) +- disable unreliable upstream test-case 2032 (#1241168) + +* Tue Oct 27 2015 Kamil Dudka 7.29.0-27 +- SSH: do not require public key file for user authentication (#1275769) + +* Tue Sep 08 2015 Kamil Dudka 7.29.0-26 +- implement 'curl --unix-socket' and CURLOPT_UNIX_SOCKET_PATH (#1263318) +- improve parsing of URL-encoded user name and password (#1260178) +- prevent test46 from failing due to expired cookie (#1258834) * Mon May 11 2015 Kamil Dudka 7.29.0-25 - fix spurious failure of test 1500 on ppc64le (#1218272)