From 4750e6f3c5fd42e19998242ddb63d7d5506b9fd9 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 5 Jan 2007 23:11:14 +0000 Subject: [PATCH] - Linus Nielsen Feltzing introduced the --ftp-ssl-ccc command line option to curl that uses the new CURLOPT_FTP_SSL_CCC option in libcurl. If enabled, it will make libcurl shutdown SSL/TLS after the authentication is done on a FTP-SSL operation. --- CHANGES | 6 ++ RELEASE-NOTES | 5 +- docs/curl.1 | 10 +++- docs/libcurl/curl_easy_setopt.3 | 8 ++- include/curl/curl.h | 7 ++- lib/ftp.c | 24 +++++++- lib/gtls.c | 68 +++++++++++++++++++++- lib/gtls.h | 3 +- lib/sslgen.c | 14 ++++- lib/sslgen.h | 6 +- lib/ssluse.c | 100 +++++++++++++++++++++++++++++++- lib/ssluse.h | 8 ++- lib/strerror.c | 5 +- lib/url.c | 6 +- lib/urldata.h | 7 ++- src/main.c | 12 +++- 16 files changed, 269 insertions(+), 20 deletions(-) diff --git a/CHANGES b/CHANGES index 811122d1d..9aafe8d57 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,12 @@ Changelog +Daniel (5 January 2007) +- Linus Nielsen Feltzing introduced the --ftp-ssl-ccc command line option to + curl that uses the new CURLOPT_FTP_SSL_CCC option in libcurl. If enabled, it + will make libcurl shutdown SSL/TLS after the authentication is done on a + FTP-SSL operation. + Daniel (4 January 2007) - David McCreedy made changes to allow base64 encoding/decoding to work on non-ASCII platforms. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index fe108df67..a9317ea60 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -5,7 +5,7 @@ Curl and libcurl 7.16.1 Available command line options: 112 Available curl_easy_setopt() options: 133 Number of public functions in libcurl: 54 - Amount of public web site mirrors: 39 + Amount of public web site mirrors: 38 Number of known libcurl bindings: 35 Number of contributors: 524 @@ -13,6 +13,7 @@ This release includes the following changes: o Support for SCP and SFTP were added o CURLOPT_CLOSEPOLICY is now deprecated + o --ftp-ssl-ccc and CURLOPT_FTP_SSL_CCC were added This release includes the following bugfixes: @@ -67,6 +68,6 @@ advice from friends like these: Matt Witherspoon, Alexey Simak, Martin Skinner, Sh Diao, Jared Lundell, Stefan Krause, Sebastien Willemijns, Alexey Simak, Brendan Jurd, Robson Braga Araujo, David McCreedy, Robert Foreman, Nathanael Nerode, - Victor Snezhko + Victor Snezhko, Linus Nielsen Feltzing Thanks! (and sorry if I forgot to mention someone) diff --git a/docs/curl.1 b/docs/curl.1 index c87474758..4830179bd 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2007, 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 @@ -432,6 +432,14 @@ If this option is used twice, the second will again disable this. Terminates the connection if the server doesn't support SSL/TLS. (Added in 7.15.5) +If this option is used twice, the second will again disable this. +.IP "--ftp-ssl-ccc" +(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. +(Added in 7.16.1) + If this option is used twice, the second will again disable this. .IP "-F/--form " (HTTP) This lets curl emulate a filled in form in which a user has pressed the diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 4893c0e24..55f4353bc 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. +.\" * Copyright (C) 1998 - 2007, 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 @@ -925,6 +925,12 @@ Try "AUTH SSL" first, and only if that fails try "AUTH TLS" .IP CURLFTPAUTH_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) .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 ea5b46201..8bbdd1b24 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -397,6 +397,8 @@ typedef enum { generic so the error message will be of interest when this has happened */ + CURLE_FTP_SSL_CCC_FAILED, /* 80 - Failed to clear the FTP command + channel */ CURL_LAST /* never use! */ } CURLcode; @@ -1049,6 +1051,9 @@ typedef enum { CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152), CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153), + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/ftp.c b/lib/ftp.c index 015c5ad3f..56b6cf229 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -666,6 +666,7 @@ static void state(struct connectdata *conn, "ACCT", "PBSZ", "PROT", + "CCC", "PWD", "QUOTE", "RETR_PREQUOTE", @@ -2545,6 +2546,27 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* we failed and bails out */ return CURLE_FTP_SSL_FAILED; + if(data->set.ftp_use_ccc) { + /* CCC - Clear Command Channel + */ + NBFTPSENDF(conn, "CCC", NULL); + state(conn, FTP_CCC); + } + else { + result = ftp_state_pwd(conn); + if(result) + return result; + } + break; + + case FTP_CCC: + /* First shut down the SSL layer (note: this call will block) */ + result = Curl_ssl_shutdown(conn, FIRSTSOCKET); + + if(result) + return CURLE_FTP_SSL_CCC_FAILED; + + /* Then continue as normal */ result = ftp_state_pwd(conn); if(result) return result; diff --git a/lib/gtls.c b/lib/gtls.c index bbd87161d..250ecada4 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -516,6 +516,72 @@ void Curl_gtls_close(struct connectdata *conn) close_one(conn, 1); } +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) +{ + int result; + int retval = 0; + struct SessionHandle *data = conn->data; + int done = 0; + ssize_t nread; + char buf[120]; + + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + 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(conn->ssl[sockindex].session) { + while(!done) { + int what = Curl_select(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + result = gnutls_record_recv(conn->ssl[sockindex].session, + buf, sizeof(buf)); + switch(result) { + case 0: + /* This is the expected response. There was no data but only + the close notify alert */ + done = 1; + break; + case GNUTLS_E_AGAIN: + case GNUTLS_E_INTERRUPTED: + infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n"); + break; + default: + retval = -1; + done = 1; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = 1; + break; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + retval = -1; + done = 1; + } + } + gnutls_deinit(conn->ssl[sockindex].session); + } + gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); + + conn->ssl[sockindex].session = NULL; + conn->ssl[sockindex].use = FALSE; + + return retval; +} + /* * If the read would block we return -1 and set 'wouldblock' to TRUE. * Otherwise we return the amount of data read. Other errors should return -1 diff --git a/lib/gtls.h b/lib/gtls.h index 4e7025c89..bff3f8693 100644 --- a/lib/gtls.h +++ b/lib/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -41,5 +41,6 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */ bool *wouldblock); void Curl_gtls_session_free(void *ptr); size_t Curl_gtls_version(char *buffer, size_t size); +int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); #endif diff --git a/lib/sslgen.c b/lib/sslgen.c index 1d88ba343..e4fb5fb24 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -397,6 +397,18 @@ void Curl_ssl_close(struct connectdata *conn) } } +CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) +{ + if(conn->ssl[sockindex].use) { +#ifdef USE_GNUTLS + return Curl_gtls_shutdown(conn, sockindex); +#else + return Curl_ossl_shutdown(conn, sockindex); +#endif + } + return CURLE_OK; +} + /* Selects an (Open)SSL crypto engine */ CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) diff --git a/lib/sslgen.h b/lib/sslgen.h index b910ac74b..11dea3243 100644 --- a/lib/sslgen.h +++ b/lib/sslgen.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -69,9 +69,13 @@ size_t Curl_ssl_version(char *buffer, size_t size); int Curl_ssl_check_cxn(struct connectdata *conn); +CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); + #if !defined(USE_SSL) && !defined(SSLGEN_C) /* set up blank macros for none-SSL builds */ #define Curl_ssl_close_all(x) #endif +#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ + #endif diff --git a/lib/ssluse.c b/lib/ssluse.c index 1c02edc23..5d149ba53 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -728,6 +728,102 @@ void Curl_ossl_close(struct connectdata *conn) } } +/* + * This function is called to shut down the SSL layer but keep the + * socket open (CCC - Clear Command Channel) + */ +int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) +{ + int result; + int retval = 0; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct SessionHandle *data = conn->data; + char buf[120]; /* We will use this for the OpenSSL error buffer, so it has + to be at least 120 bytes long. */ + unsigned long sslerror; + ssize_t nread; + int err; + int done = 0; + + /* This has only been tested on the proftpd server, and the mod_tls code + sends a close notify alert without waiting for a close notify alert in + 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(connssl->handle) { + while(!done) { + int what = Curl_select(conn->sock[sockindex], + CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + if(what > 0) { + /* Something to read, let's do it and hope that it is the close + notify alert from the server */ + nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf, + sizeof(buf)); + err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread); + + switch(err) { + case SSL_ERROR_NONE: /* this is not an error */ + case SSL_ERROR_ZERO_RETURN: /* no more data */ + /* This is the expected response. There was no data but only + the close notify alert */ + done = 1; + break; + case SSL_ERROR_WANT_READ: + /* there's data pending, re-invoke SSL_read() */ + infof(data, "SSL_ERROR_WANT_READ\n"); + break; + case SSL_ERROR_WANT_WRITE: + /* SSL wants a write. Really odd. Let's bail out. */ + infof(data, "SSL_ERROR_WANT_WRITE\n"); + done = 1; + break; + default: + /* openssl/ssl.h says "look at error stack/return value/errno" */ + sslerror = ERR_get_error(); + failf(conn->data, "SSL read: %s, errno %d", + ERR_error_string(sslerror, buf), + Curl_sockerrno() ); + done = 1; + break; + } + } + else if(0 == what) { + /* timeout */ + failf(data, "SSL shutdown timeout"); + done = 1; + break; + } + else { + /* anything that gets here is fatally bad */ + failf(data, "select on SSL socket, errno: %d", Curl_sockerrno()); + retval = -1; + done = 1; + } + } /* while()-loop for the select() */ + + if(data->set.verbose) { + switch(SSL_get_shutdown(connssl->handle)) { + case SSL_SENT_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n"); + break; + case SSL_RECEIVED_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n"); + break; + case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN: + infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|" + "SSL_RECEIVED__SHUTDOWN\n"); + break; + } + } + + connssl->use = FALSE; /* get back to ordinary socket usage */ + + SSL_free (connssl->handle); + connssl->handle = NULL; + } + return retval; +} + void Curl_ossl_session_free(void *ptr) { /* free the ID */ @@ -1629,7 +1725,7 @@ Curl_ossl_connect_common(struct connectdata *conn, while(1) { int what = Curl_select(readfd, writefd, nonblocking?0:(int)timeout_ms); if(what > 0) - /* reabable or writable, go loop in the outer loop */ + /* readable or writable, go loop in the outer loop */ break; else if(0 == what) { if (nonblocking) { diff --git a/lib/ssluse.h b/lib/ssluse.h index 05238f0eb..5bb7090c5 100644 --- a/lib/ssluse.h +++ b/lib/ssluse.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -29,8 +29,8 @@ #include "urldata.h" CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); -CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, - int sockindex, +CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, + int sockindex, bool *done); void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */ /* tell OpenSSL to close down all open information regarding connections (and @@ -66,4 +66,6 @@ size_t Curl_ossl_version(char *buffer, size_t size); int Curl_ossl_check_cxn(struct connectdata *cxn); int Curl_ossl_seed(struct SessionHandle *data); +int Curl_ossl_shutdown(struct connectdata *conn, int sockindex); + #endif diff --git a/lib/strerror.c b/lib/strerror.c index 4c2dacabc..2634dffdb 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2004 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 2004 - 2007, 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 @@ -244,6 +244,9 @@ curl_easy_strerror(CURLcode error) case CURLE_FTP_SSL_FAILED: return "Requested FTP SSL level failed"; + case CURLE_FTP_SSL_CCC_FAILED: + return "Failed to clear the FTP command channel"; + case CURLE_SEND_FAIL_REWIND: return "Send failed since rewinding of the data stream failed"; diff --git a/lib/url.c b/lib/url.c index c988506b0..0f3f85a5f 100644 --- a/lib/url.c +++ b/lib/url.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -1140,6 +1140,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long)); break; + case CURLOPT_FTP_SSL_CCC: + data->set.ftp_use_ccc = (bool)(0 != va_arg(param, long)); + break; + case CURLOPT_FTP_SKIP_PASV_IP: /* * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the diff --git a/lib/urldata.h b/lib/urldata.h index b94761c0b..e2cc0d158 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -302,7 +302,7 @@ struct HTTP { ***************************************************************************/ typedef enum { FTP_STOP, /* do nothing state, stops the state machine */ - FTP_WAIT220, /* waiting for the inintial 220 response immediately after + FTP_WAIT220, /* waiting for the initial 220 response immediately after a connect */ FTP_AUTH, FTP_USER, @@ -310,6 +310,7 @@ typedef enum { FTP_ACCT, FTP_PBSZ, FTP_PROT, + FTP_CCC, FTP_PWD, FTP_QUOTE, /* waiting for a response to a command sent in a quote list */ FTP_RETR_PREQUOTE, @@ -1273,6 +1274,8 @@ 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 */ bool no_signal; /* do not use any signal/alarm handler */ diff --git a/src/main.c b/src/main.c index 5de0229ea..2dc94c115 100644 --- a/src/main.c +++ b/src/main.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2006, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2007, 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 @@ -349,6 +349,7 @@ struct Configurable { bool ftp_ssl; bool ftp_ssl_reqd; bool ftp_ssl_control; + bool ftp_ssl_ccc; char *socksproxy; /* set to server string */ int socksver; /* set to CURLPROXY_SOCKS* define */ @@ -529,6 +530,7 @@ 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)", " -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 []", @@ -1355,6 +1357,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ {"$v", "ftp-ssl-reqd", FALSE}, {"$w", "no-sessionid", FALSE}, {"$x", "ftp-ssl-control", FALSE}, + {"$y", "ftp-ssl-ccc", FALSE}, {"0", "http1.0", FALSE}, {"1", "tlsv1", FALSE}, @@ -1779,6 +1782,9 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ case 'x': /* --ftp-ssl-control */ config->ftp_ssl_control ^= TRUE; break; + case 'y': /* --ftp-ssl-ccc */ + config->ftp_ssl_ccc ^= TRUE; + break; } break; case '#': /* --progress-bar */ @@ -4002,6 +4008,10 @@ operate(struct Configurable *config, int argc, char *argv[]) else if(config->ftp_ssl_control) curl_easy_setopt(curl, CURLOPT_FTP_SSL, CURLFTPSSL_CONTROL); + /* new in curl 7.16.1 */ + if(config->ftp_ssl_ccc) + curl_easy_setopt(curl, CURLOPT_FTP_SSL_CCC, TRUE); + /* new in curl 7.11.1, modified in 7.15.2 */ if(config->socksproxy) { curl_easy_setopt(curl, CURLOPT_PROXY, config->socksproxy);