socks: track SOCKS5 authentication per socket, not per connection
No binary (build failed)
—
(log yok)
| @@ -586,6 +586,10 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf, | |
| /* disable username/password auth */ | |
| Curl_creds_unlink(&sx->creds); | |
| + | if(cf->sockindex == FIRSTSOCKET) |
| + | /* the reuse of this connection depends on how this negotiation ends */ |
| + | cf->conn->bits.socks5_authenticated = FALSE; |
| + | |
| req[0] = 5; /* version */ | |
| nauths = 0; | |
| if(!data->set.socks5_auth_only) { | |
| @@ -647,7 +651,8 @@ static CURLproxycode socks5_check_resp0(struct socks_ctx *sx, | |
| return CURLPX_OK; | |
| case 1: | |
| if(data->set.socks5auth & CURLAUTH_GSSAPI) { | |
| - | cf->conn->bits.socks5_authenticated = TRUE; |
| + | if(cf->sockindex == FIRSTSOCKET) |
| + | cf->conn->bits.socks5_authenticated = TRUE; |
| sxstate(sx, cf, data, SOCKS5_ST_GSSAPI_INIT); | |
| return CURLPX_OK; | |
| } | |
| @@ -656,7 +661,8 @@ static CURLproxycode socks5_check_resp0(struct socks_ctx *sx, | |
| case 2: | |
| /* regular name + password authentication */ | |
| if(data->set.socks5auth & CURLAUTH_BASIC) { | |
| - | cf->conn->bits.socks5_authenticated = TRUE; |
| + | if(cf->sockindex == FIRSTSOCKET) |
| + | cf->conn->bits.socks5_authenticated = TRUE; |
| sxstate(sx, cf, data, SOCKS5_ST_AUTH_INIT); | |
| return CURLPX_OK; | |
| } | |
| @@ -184,7 +184,7 @@ struct ConnectBits { | |
| BIT(connect_only); | |
| #ifndef CURL_DISABLE_PROXY | |
| BIT(origin_is_proxy); /* if set, the connection's origin is a proxy */ | |
| - | BIT(socks5_authenticated); /* SOCKS5 negotiated an authentication method */ |
| + | BIT(socks5_authenticated); /* SOCKS5 authenticated on FIRSTSOCKET */ |
| #endif | |
| /* always modify bits.close with the connclose() and connkeep() macros! */ | |
| BIT(close); /* if set, we close the connection after this request */ | |
| @@ -1742,6 +1742,7 @@ TESTCASES = \ | |
| test1742 \ | |
| test1743 \ | |
| test1744 \ | |
| + | test1745 \ |
| test1790 \ | |
| test1791 \ | |
| test1800 \ | |
| @@ -0,0 +1,61 @@ | |
| + | <?xml version="1.0" encoding="US-ASCII"?> |
| + | <testcase> |
| + | <info> |
| + | <keywords> |
| + | FTP |
| + | PASV |
| + | RETR |
| + | SOCKS5 |
| + | </keywords> |
| + | </info> |
| + | |
| + | # Server-side |
| + | <reply> |
| + | <data> |
| + | silly content |
| + | </data> |
| + | <servercmd> |
| + | method 0 |
| + | method2 2 |
| + | user silly |
| + | password person |
| + | </servercmd> |
| + | </reply> |
| + | |
| + | # Client-side |
| + | <client> |
| + | <features> |
| + | proxy |
| + | </features> |
| + | <server> |
| + | ftp |
| + | socks5 |
| + | </server> |
| + | <tool> |
| + | lib%TESTNUMBER |
| + | </tool> |
| + | <name> |
| + | SOCKS5 CURLAUTH_ONLY ignores auth done for the FTP data socket |
| + | </name> |
| + | <command> |
| + | ftp://%HOSTIP:%FTPPORT/%TESTNUMBER %HOSTIP:%SOCKSPORT |
| + | </command> |
| + | </client> |
| + | |
| + | # Verify data after the test has been "shot" |
| + | <verify> |
| + | <errorcode> |
| + | 97 |
| + | </errorcode> |
| + | <protocol crlf="yes"> |
| + | USER anonymous |
| + | PASS [email protected] |
| + | PWD |
| + | EPSV |
| + | TYPE I |
| + | SIZE %TESTNUMBER |
| + | RETR %TESTNUMBER |
| + | QUIT |
| + | </protocol> |
| + | </verify> |
| + | </testcase> |
| @@ -248,6 +248,7 @@ TESTS_C = \ | |
| lib1686.c \ | |
| lib1742.c \ | |
| lib1744.c \ | |
| + | lib1745.c \ |
| lib1791.c \ | |
| lib1900.c \ | |
| lib1901.c \ | |
| @@ -0,0 +1,74 @@ | |
| + | /*************************************************************************** |
| + | * _ _ ____ _ |
| + | * Project ___| | | | _ \| | |
| + | * / __| | | | |_) | | |
| + | * | (__| |_| | _ <| |___ |
| + | * \___|\___/|_| \_\_____| |
| + | * |
| + | * Copyright (C) Daniel Stenberg, <[email protected]>, et al. |
| + | * |
| + | * This software is licensed as described in the file COPYING, which |
| + | * you should have received as part of this distribution. The terms |
| + | * are also available at https://curl.se/docs/copyright.html. |
| + | * |
| + | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| + | * copies of the Software, and permit persons to whom the Software is |
| + | * furnished to do so, under the terms of the COPYING file. |
| + | * |
| + | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| + | * KIND, either express or implied. |
| + | * |
| + | * SPDX-License-Identifier: curl |
| + | * |
| + | ***************************************************************************/ |
| + | /* |
| + | * argv1 = FTP URL |
| + | * argv2 = SOCKS5 proxy |
| + | */ |
| + | |
| + | #include "first.h" |
| + | |
| + | static CURLcode test_lib1745(const char *URL) |
| + | { |
| + | CURLcode result = CURLE_OK; |
| + | CURL *curl = NULL; |
| + | |
| + | if(test_argc < 2) |
| + | return TEST_ERR_MAJOR_BAD; |
| + | |
| + | res_global_init(CURL_GLOBAL_ALL); |
| + | if(result) |
| + | return result; |
| + | |
| + | curl = curl_easy_init(); |
| + | if(!curl) { |
| + | curl_mfprintf(stderr, "curl_easy_init() failed\n"); |
| + | curl_global_cleanup(); |
| + | return TEST_ERR_MAJOR_BAD; |
| + | } |
| + | |
| + | start_test_timing(); |
| + | |
| + | easy_setopt(curl, CURLOPT_URL, URL); |
| + | easy_setopt(curl, CURLOPT_PROXY, libtest_arg2); |
| + | easy_setopt(curl, CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS5); |
| + | easy_setopt(curl, CURLOPT_PROXYUSERPWD, "silly:person"); |
| + | |
| + | /* the proxy picks no authentication for the control connection and |
| + | username/password for the data connection */ |
| + | result = curl_easy_perform(curl); |
| + | if(result) |
| + | goto test_cleanup; |
| + | |
| + | /* the control connection did not authenticate, so it must not be |
| + | reused for this one */ |
| + | easy_setopt(curl, CURLOPT_SOCKS5_AUTH, |
| + | (long)(CURLAUTH_BASIC | CURLAUTH_ONLY)); |
| + | result = curl_easy_perform(curl); |
| + | |
| + | test_cleanup: |
| + | |
| + | curl_easy_cleanup(curl); |
| + | curl_global_cleanup(); |
| + | return result; |
| + | } |
| @@ -49,6 +49,8 @@ | |
| * 0 - no auth | |
| * 1 - GSSAPI (not supported) | |
| * 2 - user + password | |
| + | * "method2 [number]" - connect method to respond with on the second |
| + | * connection, defaults to the "method" one |
| * "response [number]" - the decimal number to respond to a connect | |
| * SOCKS5: 0 is OK, SOCKS4: 90 is ok | |
| * | |
| @@ -58,6 +60,7 @@ | |
| static const char *backendaddr = "127.0.0.1"; | |
| static uint16_t backendport = 0; /* default is use client's */ | |
| + | static unsigned int connections; /* number of clients served */ |
| struct socksd_configurable { | |
| unsigned char version; /* initial version byte in the request must match | |
| @@ -66,6 +69,7 @@ struct socksd_configurable { | |
| unsigned char nmethods_max; /* maximum number of nmethods to expect */ | |
| unsigned char responseversion; | |
| unsigned char responsemethod; | |
| + | unsigned char responsemethod2; |
| unsigned char reqcmd; | |
| unsigned char connectrep; | |
| uint16_t port; /* backend port */ | |
| @@ -79,6 +83,7 @@ struct socksd_configurable { | |
| #define CONFIG_NMETHODS_MAX 3 | |
| #define CONFIG_RESPONSEVERSION CONFIG_VERSION | |
| #define CONFIG_RESPONSEMETHOD 0 /* no auth */ | |
| + | #define CONFIG_RESPONSEMETHOD2 0xff /* unset, use CONFIG_RESPONSEMETHOD */ |
| #define CONFIG_REQCMD 1 /* CONNECT */ | |
| #define CONFIG_PORT backendport | |
| #define CONFIG_ADDR backendaddr | |
| @@ -96,6 +101,7 @@ static void socksd_resetdefaults(void) | |
| s_config.nmethods_max = CONFIG_NMETHODS_MAX; | |
| s_config.responseversion = CONFIG_RESPONSEVERSION; | |
| s_config.responsemethod = CONFIG_RESPONSEMETHOD; | |
| + | s_config.responsemethod2 = CONFIG_RESPONSEMETHOD2; |
| s_config.reqcmd = CONFIG_REQCMD; | |
| s_config.connectrep = CONFIG_CONNECTREP; | |
| s_config.port = CONFIG_PORT; | |
| @@ -175,6 +181,13 @@ static void socksd_getconfig(void) | |
| logmsg("method [%d] set", s_config.responsemethod); | |
| } | |
| } | |
| + | else if(!strcmp(key, "method2")) { |
| + | pval = value; |
| + | if(!curlx_str_number(&pval, &num, 0xff)) { |
| + | s_config.responsemethod2 = (unsigned char)num; |
| + | logmsg("method2 [%d] set", s_config.responsemethod2); |
| + | } |
| + | } |
| else if(!strcmp(key, "response")) { | |
| pval = value; | |
| if(!curlx_str_number(&pval, &num, 0xff)) { | |
| @@ -303,6 +316,10 @@ static curl_socket_t sockit(curl_socket_t fd) | |
| socksd_getconfig(); | |
| + | if((++connections == 2) && (s_config.responsemethod2 != |
| + | CONFIG_RESPONSEMETHOD2)) |
| + | s_config.responsemethod = s_config.responsemethod2; |
| + | |
| rc = sread(fd, buffer, sizeof(buffer)); | |
| if(rc <= 0) { | |
| logmsg("SOCKS identifier message missing, recv returned %zd", rc); | |