From 2f5e99ca02b6716fdac59c299ab7738a2077743d Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Tue, 20 Feb 2007 22:02:11 +0000 Subject: [PATCH] New FTP CCC functionality - adds passive and active mode to accomodate for different server behaviour --- docs/curl.1 | 10 +++++++++- docs/libcurl/curl_easy_setopt.3 | 19 ++++++++++++++----- include/curl/curl.h | 8 ++++++++ lib/ftp.c | 2 +- lib/gtls.c | 3 +++ lib/ssluse.c | 3 +++ lib/url.c | 2 +- lib/urldata.h | 2 +- src/main.c | 23 +++++++++++++++++++++-- 9 files changed, 61 insertions(+), 11 deletions(-) diff --git a/docs/curl.1 b/docs/curl.1 index 881cd77a2..56659e8c8 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -448,10 +448,18 @@ If this option is used twice, the second will again disable this. (FTP) Use CCC (Clear Command Channel) Shuts down the SSL/TLS layer after authenticating. The rest of the control channel communication will be unencrypted. This allows -NAT routers to follow the FTP transaction. +NAT routers to follow the FTP transaction. The default mode is +passive. See --ftp-ssl-ccc-mode for other modes. (Added in 7.16.1) If this option is used twice, the second will again disable this. +.IP "--ftp-ssl-ccc-mode [active/passive]" +(FTP) Use CCC (Clear Command Channel) +Sets the CCC mode. The passive mode will not initiate the shutdown, but +instead wait for the server to do it, and will not reply to the +shutdown from the server. The active mode initiates the shutdown and +waits for a reply from the server. +(Added in 7.16.2) .IP "-F/--form " (HTTP) This lets curl emulate a filled in form in which a user has pressed the submit button. This causes curl to POST data using the Content-Type diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 66ca11f34..9e32f13aa 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -936,11 +936,20 @@ Try "AUTH SSL" first, and only if that fails try "AUTH TLS" Try "AUTH TLS" first, and only if that fails try "AUTH SSL" .RE .IP CURLOPT_FTP_SSL_CCC -Pass a long that is set to 0 to disable and 1 to enable. If enabled, this -option makes libcurl use CCC (Clear Command Channel). It shuts down the -SSL/TLS layer after authenticating. The rest of the control channel -communication will be unencrypted. This allows NAT routers to follow the FTP -transaction. (Added in 7.16.1) +If enabled, this option makes libcurl use CCC (Clear Command Channel). It +shuts down the SSL/TLS layer after authenticating. The rest of the +control channel communication will be unencrypted. This allows NAT routers +to follow the FTP transaction. Pass a long using one of the values below. +(Added in 7.16.1) +.RS +.IP CURLFTPSSL_CCC_NONE +Don't attempt to use CCC. +.IP CURLFTPSSL_CCC_PASSIVE +Do not initiate the shutdown, but wait for the server to do it. Do not send +a reply. +.IP CURLFTPSSL_CCC_ACTIVE +Initiate the shutdown and wait for a reply. +.RE .IP CURLOPT_FTP_ACCOUNT Pass a pointer to a zero-terminated string (or NULL to disable). When an FTP server asks for "account data" after user name and password has been provided, diff --git a/include/curl/curl.h b/include/curl/curl.h index e911fca5a..d7f36645c 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -465,6 +465,14 @@ typedef enum { CURLFTPSSL_LAST /* not an option, never use */ } curl_ftpssl; +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + /* parameter for the CURLOPT_FTPSSLAUTH option */ typedef enum { CURLFTPAUTH_DEFAULT, /* let libcurl decide */ diff --git a/lib/ftp.c b/lib/ftp.c index a23acd43e..8328315dc 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -2566,7 +2566,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* we failed and bails out */ return CURLE_FTP_SSL_FAILED; - if(data->set.ftp_use_ccc) { + if(data->set.ftp_ccc) { /* CCC - Clear Command Channel */ NBFTPSENDF(conn, "CCC", NULL); diff --git a/lib/gtls.c b/lib/gtls.c index daf69aafe..f8c103450 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -533,6 +533,9 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR); + if(conn->ssl[sockindex].session) { while(!done) { int what = Curl_select(conn->sock[sockindex], diff --git a/lib/ssluse.c b/lib/ssluse.c index dc4fc927c..b362ab3f2 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -749,6 +749,9 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) response. Thus we wait for a close notify alert from the server, but we do not send one. Let's hope other servers do the same... */ + if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE) + (void)SSL_shutdown(connssl->handle); + if(connssl->handle) { while(!done) { int what = Curl_select(conn->sock[sockindex], diff --git a/lib/url.c b/lib/url.c index 3bd8dcb6d..05920b72e 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1156,7 +1156,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_FTP_SSL_CCC: - data->set.ftp_use_ccc = (bool)(0 != va_arg(param, long)); + data->set.ftp_ccc = va_arg(param, long); break; case CURLOPT_FTP_SKIP_PASV_IP: diff --git a/lib/urldata.h b/lib/urldata.h index d50f9e44a..3325699d7 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1283,10 +1283,10 @@ struct UserDefined { bool reuse_fresh; /* do not re-use an existing connection */ bool ftp_use_epsv; /* if EPSV is to be attempted or not */ bool ftp_use_eprt; /* if EPRT is to be attempted or not */ - bool ftp_use_ccc; /* if CCC is to be attempted or not */ curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */ + curl_ftpccc ftp_ccc; /* FTP CCC options */ bool no_signal; /* do not use any signal/alarm handler */ bool global_dns_cache; /* subject for future removal */ bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */ diff --git a/src/main.c b/src/main.c index b3f629590..ed6f338ef 100644 --- a/src/main.c +++ b/src/main.c @@ -440,6 +440,7 @@ struct Configurable { bool ftp_ssl_reqd; bool ftp_ssl_control; bool ftp_ssl_ccc; + int ftp_ssl_ccc_mode; char *socksproxy; /* set to server string */ int socksver; /* set to CURLPROXY_SOCKS* define */ @@ -627,7 +628,8 @@ static void help(void) " --ftp-ssl Try SSL/TLS for ftp transfer (F)", " --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)", " --ftp-ssl-reqd Require SSL/TLS for ftp transfer (F)", - " --ftp-ssl-ccc Send CCC after authenticating (F)", + " --ftp-ssl-ccc Send CCC after authenticating. (F)", + " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)", " -F/--form Specify HTTP multipart POST data (H)", " --form-string Specify HTTP multipart POST data (H)", " -g/--globoff Disable URL sequences and ranges using {} and []", @@ -1380,6 +1382,16 @@ static int ftpfilemethod(struct Configurable *config, char *str) return CURLFTPMETHOD_MULTICWD; } +static int ftpcccmethod(struct Configurable *config, char *str) +{ + if(curlx_strequal("passive", str)) + return CURLFTPSSL_CCC_PASSIVE; + if(curlx_strequal("active", str)) + return CURLFTPSSL_CCC_ACTIVE; + warnf(config, "unrecognized ftp CCC method '%s', using default\n", str); + return CURLFTPSSL_CCC_PASSIVE; +} + static ParameterError getparameter(char *flag, /* f or -long-flag */ char *nextarg, /* NULL if unset */ bool *usedarg, /* set to TRUE if the arg @@ -1460,6 +1472,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ {"$w", "no-sessionid", FALSE}, {"$x", "ftp-ssl-control", FALSE}, {"$y", "ftp-ssl-ccc", FALSE}, + {"$j", "ftp-ssl-ccc-mode", TRUE}, {"$z", "libcurl", TRUE}, {"$#", "raw", FALSE}, @@ -1888,6 +1901,12 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ break; case 'y': /* --ftp-ssl-ccc */ config->ftp_ssl_ccc ^= TRUE; + if(!config->ftp_ssl_ccc_mode) + config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; + break; + case 'j': /* --ftp-ssl-ccc-mode */ + config->ftp_ssl_ccc = TRUE; + config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); break; case 'z': /* --libcurl */ GetStr(&config->libcurl, nextarg); @@ -4211,7 +4230,7 @@ operate(struct Configurable *config, int argc, char *argv[]) /* new in curl 7.16.1 */ if(config->ftp_ssl_ccc) - my_setopt(curl, CURLOPT_FTP_SSL_CCC, TRUE); + my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode); /* new in curl 7.11.1, modified in 7.15.2 */ if(config->socksproxy) {