From 1e98727c552ced5f8c7587f64ab69c6eaab743dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 24 Nov 2003 07:15:37 +0000 Subject: [PATCH] FTPS support added as RFC2228 and the murray-ftp-auth-ssl draft describe it --- include/curl/curl.h | 8 +-- lib/dict.c | 13 ++-- lib/ftp.c | 119 ++++++++++++++++++++++++++------ lib/http.c | 33 ++++----- lib/multi.c | 14 ++-- lib/sendf.c | 35 +++++++--- lib/ssluse.c | 163 ++++++++++++++++++++++++-------------------- lib/ssluse.h | 2 +- lib/telnet.c | 14 ++-- lib/transfer.c | 24 +++---- lib/url.c | 41 +++++------ lib/urldata.h | 18 +++-- 12 files changed, 294 insertions(+), 190 deletions(-) diff --git a/include/curl/curl.h b/include/curl/curl.h index 23c89b721..36fff4441 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -29,7 +29,7 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.10.9-CVS" +#define LIBCURL_VERSION "7.11.0-CVS" /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -45,13 +45,13 @@ always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ -#define LIBCURL_VERSION_NUM 0x070a09 +#define LIBCURL_VERSION_NUM 0x070b00 /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 10 -#define LIBCURL_VERSION_PATCH 9 +#define LIBCURL_VERSION_MINOR 11 +#define LIBCURL_VERSION_PATCH 0 #include diff --git a/lib/dict.c b/lib/dict.c index 1c85a1081..86c864cf5 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -89,6 +89,7 @@ CURLcode Curl_dict(struct connectdata *conn) by RFC 2229 */ CURLcode result=CURLE_OK; struct SessionHandle *data=conn->data; + int sockfd = conn->sock[FIRSTSOCKET]; char *path = conn->path; long *bytecount = &conn->bytecount; @@ -134,7 +135,7 @@ CURLcode Curl_dict(struct connectdata *conn) nth = atoi(nthdef); } - result = Curl_sendf(conn->firstsocket, conn, + result = Curl_sendf(sockfd, conn, "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" "MATCH " "%s " /* database */ @@ -149,7 +150,7 @@ CURLcode Curl_dict(struct connectdata *conn) if(result) failf(data, "Failed sending DICT request"); else - result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, + result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount, -1, NULL); /* no upload */ if(result) return result; @@ -184,7 +185,7 @@ CURLcode Curl_dict(struct connectdata *conn) nth = atoi(nthdef); } - result = Curl_sendf(conn->firstsocket, conn, + result = Curl_sendf(sockfd, conn, "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" "DEFINE " "%s " /* database */ @@ -195,7 +196,7 @@ CURLcode Curl_dict(struct connectdata *conn) if(result) failf(data, "Failed sending DICT request"); else - result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, + result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount, -1, NULL); /* no upload */ if(result) @@ -213,14 +214,14 @@ CURLcode Curl_dict(struct connectdata *conn) if (ppath[i] == ':') ppath[i] = ' '; } - result = Curl_sendf(conn->firstsocket, conn, + result = Curl_sendf(sockfd, conn, "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" "%s\n" "QUIT\n", ppath); if(result) failf(data, "Failed sending DICT request"); else - result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, + result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount, -1, NULL); if(result) return result; diff --git a/lib/ftp.c b/lib/ftp.c index c464f746c..c8c44f51f 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -126,12 +126,12 @@ static void freedirs(struct FTP *ftp) * connected. * */ -static CURLcode AllowServerConnect(struct SessionHandle *data, - struct connectdata *conn, - int sock) +static CURLcode AllowServerConnect(struct connectdata *conn) { fd_set rdset; struct timeval dt; + struct SessionHandle *data = conn->data; + int sock = conn->sock[SECONDARYSOCKET]; FD_ZERO(&rdset); @@ -169,7 +169,7 @@ static CURLcode AllowServerConnect(struct SessionHandle *data, } infof(data, "Connection accepted from server\n"); - conn->secondarysocket = s; + conn->sock[SECONDARYSOCKET] = s; Curl_nonblock(s, TRUE); /* enable non-blocking */ } break; @@ -197,7 +197,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ * Alas, read as much as possible, split up into lines, use the ending * line in a response or continue reading. */ - int sockfd = conn->firstsocket; + int sockfd = conn->sock[FIRSTSOCKET]; int perline; /* count bytes per line */ bool keepon=TRUE; ssize_t gotbytes; @@ -438,7 +438,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) if (data->set.tunnel_thru_httpproxy) { /* We want "seamless" FTP operations through HTTP proxy tunnel */ - result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket, + result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET, conn->hostname, conn->remote_port); if(CURLE_OK != result) return result; @@ -447,7 +447,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) if(conn->protocol & PROT_FTPS) { /* FTPS is simply ftp with SSL for the control channel */ /* now, perform the SSL initialization for this socket */ - result = Curl_SSLConnect(conn); + result = Curl_SSLConnect(conn, FIRSTSOCKET); if(result) return result; } @@ -480,6 +480,71 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) infof(data, "Authentication successful\n"); } #endif + + if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) { + /* we don't have a ssl connection, try a FTPS connection now */ + FTPSENDF(conn, "AUTH TLS", NULL); + + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; + + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, and + * does not require any security data, it must respond with reply code + * 234. + */ + + if(234 == ftpcode) { + result = Curl_SSLConnect(conn, FIRSTSOCKET); + if(result) + return result; + conn->protocol |= PROT_FTPS; + conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ + } + } + if(conn->ssl[FIRSTSOCKET].use) { + /* PBSZ = PROTECTION BUFFER SIZE. + + The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says: + + Specifically, the PROT command MUST be preceded by a PBSZ command + and a PBSZ command MUST be preceded by a successful security data + exchange (the TLS negotiation in this case) + + ... (and on page 8): + + Thus the PBSZ command must still be issued, but must have a parameter + of '0' to indicate that no buffering is taking place and the data + connection should not be encapsulated. + */ + FTPSENDF(conn, "PBSZ %d", 0); + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; + + /* For TLS, the data connection can have one of two security levels. + + 1)Clear (requested by 'PROT C') + + 2)Private (requested by 'PROT P') + */ + if(!conn->ssl[SECONDARYSOCKET].use) { + FTPSENDF(conn, "PROT %c", 'P'); + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; + + if(ftpcode == 200) + /* We have enabled SSL for the data connection! */ + conn->ssl[SECONDARYSOCKET].use = TRUE; + + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + } + } + /* send USER */ FTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); @@ -666,8 +731,8 @@ CURLcode Curl_ftp_done(struct connectdata *conn) Curl_sec_fflush_fd(conn, conn->secondarysocket); #endif /* shut down the socket to inform the server we're done */ - sclose(conn->secondarysocket); - conn->secondarysocket = -1; + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = -1; if(!ftp->no_transfer) { /* Let's see what the server says about the transfer we just performed, @@ -1039,7 +1104,7 @@ CURLcode ftp_use_port(struct connectdata *conn) * I believe we should use the same address as the control connection. */ sslen = sizeof(ss); - if (getsockname(conn->firstsocket, (struct sockaddr *)&ss, &sslen) < 0) + if (getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen) < 0) return CURLE_FTP_PORT_FAILED; if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0, @@ -1205,7 +1270,7 @@ CURLcode ftp_use_port(struct connectdata *conn) /* we set the secondary socket variable to this for now, it is only so that the cleanup function will close it in case we fail before the true secondary stuff is made */ - conn->secondarysocket = portsock; + conn->sock[SECONDARYSOCKET] = portsock; #else /****************************************************************** @@ -1249,7 +1314,8 @@ CURLcode ftp_use_port(struct connectdata *conn) socklen_t sslen; sslen = sizeof(sa); - if (getsockname(conn->firstsocket, (struct sockaddr *)&sa, &sslen) < 0) { + if (getsockname(conn->sock[FIRSTSOCKET], + (struct sockaddr *)&sa, &sslen) < 0) { failf(data, "getsockname() failed"); return CURLE_FTP_PORT_FAILED; } @@ -1526,7 +1592,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn, result = Curl_connecthost(conn, addr, connectport, - &conn->secondarysocket, + &conn->sock[SECONDARYSOCKET], &conninfo, connected); @@ -1547,7 +1613,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn, if (data->set.tunnel_thru_httpproxy) { /* We want "seamless" FTP operations through HTTP proxy tunnel */ - result = Curl_ConnectHTTPProxyTunnel(conn, conn->secondarysocket, + result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET, newhostp, newport); if(CURLE_OK != result) return result; @@ -1684,7 +1750,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) if(data->set.ftp_use_port) { /* PORT means we are now awaiting the server to connect to us. */ - result = AllowServerConnect(data, conn, conn->secondarysocket); + result = AllowServerConnect(conn); if( result ) return result; } @@ -1697,7 +1763,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) Curl_pgrsSetUploadSize(data, data->set.infilesize); result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */ - conn->secondarysocket, bytecountp); + SECONDARYSOCKET, bytecountp); if(result) return result; @@ -1940,15 +2006,24 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) size = downloadsize; if(data->set.ftp_use_port) { - result = AllowServerConnect(data, conn, conn->secondarysocket); + result = AllowServerConnect(conn); if( result ) return result; } +#if 1 + if(conn->ssl[SECONDARYSOCKET].use) { + /* since we only have a TCP connection, we must now do the TLS stuff */ + infof(data, "Doing the SSL/TSL handshake on the data stream\n"); + result = Curl_SSLConnect(conn, SECONDARYSOCKET); + if(result) + return result; + } +#endif infof(data, "Getting file with size: %d\n", size); /* FTP download: */ - result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE, + result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE, bytecountp, -1, NULL); /* no upload here */ if(result) @@ -2232,10 +2307,10 @@ CURLcode Curl_ftp(struct connectdata *conn) if(connected) retcode = Curl_ftp_nextconnect(conn); - if(retcode && (conn->secondarysocket >= 0)) { + if(retcode && (conn->sock[SECONDARYSOCKET] >= 0)) { /* Failure detected, close the second socket if it was created already */ - sclose(conn->secondarysocket); - conn->secondarysocket = -1; + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET] = -1; } if(ftp->no_transfer) @@ -2280,7 +2355,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, write_len = strlen(s); do { - res = Curl_write(conn, conn->firstsocket, sptr, write_len, + res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, &bytes_written); if(CURLE_OK != res) diff --git a/lib/http.c b/lib/http.c index d7496ecde..0b36f1eea 100644 --- a/lib/http.c +++ b/lib/http.c @@ -500,7 +500,6 @@ send_buffer *add_buffer_init(void) */ static CURLcode add_buffer_send(send_buffer *in, - int sockfd, struct connectdata *conn, long *bytes_written) /* add the number of sent bytes to this counter */ @@ -511,6 +510,7 @@ CURLcode add_buffer_send(send_buffer *in, int size; struct HTTP *http = conn->proto.http; int sendsize; + int sockfd = conn->sock[FIRSTSOCKET]; /* The looping below is required since we use non-blocking sockets, but due to the circumstances we will just loop and try again and again etc */ @@ -708,7 +708,7 @@ Curl_compareheader(char *headerline, /* line to check */ */ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, - int tunnelsocket, + int sockindex, char *hostname, int remote_port) { @@ -729,6 +729,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, fd_set readfd; char *line_start; char *host_port; + int tunnelsocket = conn->sock[sockindex]; #define SELECT_OK 0 #define SELECT_ERROR 1 @@ -936,7 +937,7 @@ CURLcode Curl_http_connect(struct connectdata *conn) ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) { /* either HTTPS over proxy, OR explicitly asked for a tunnel */ - result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket, + result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET, conn->hostname, conn->remote_port); if(CURLE_OK != result) return result; @@ -944,7 +945,7 @@ CURLcode Curl_http_connect(struct connectdata *conn) if(conn->protocol & PROT_HTTPS) { /* now, perform the SSL initialization for this socket */ - result = Curl_SSLConnect(conn); + result = Curl_SSLConnect(conn, FIRSTSOCKET); if(result) return result; } @@ -1491,15 +1492,15 @@ CURLcode Curl_http(struct connectdata *conn) Curl_pgrsSetUploadSize(data, http->postsize); /* fire away the whole request to the server */ - result = add_buffer_send(req_buffer, conn->firstsocket, conn, + result = add_buffer_send(req_buffer, conn, &data->info.request_size); if(result) failf(data, "Failed sending POST request"); else /* setup variables for the upcoming transfer */ - result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, + result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - conn->firstsocket, + FIRSTSOCKET, &http->writebytecount); if(result) { Curl_formclean(http->sendit); /* free that whole lot */ @@ -1521,15 +1522,15 @@ CURLcode Curl_http(struct connectdata *conn) Curl_pgrsSetUploadSize(data, data->set.infilesize); /* this sends the buffer and frees all the buffer resources */ - result = add_buffer_send(req_buffer, conn->firstsocket, conn, + result = add_buffer_send(req_buffer, conn, &data->info.request_size); if(result) failf(data, "Failed sending POST request"); else /* prepare for transfer */ - result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, + result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - conn->firstsocket, + FIRSTSOCKET, &http->writebytecount); if(result) return result; @@ -1602,16 +1603,16 @@ CURLcode Curl_http(struct connectdata *conn) http->postdata = (char *)&http->postdata; } /* issue the request */ - result = add_buffer_send(req_buffer, conn->firstsocket, conn, + result = add_buffer_send(req_buffer, conn, &data->info.request_size); if(result) failf(data, "Failed sending HTTP POST request"); else result = - Curl_Transfer(conn, conn->firstsocket, -1, TRUE, + Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - http->postdata?conn->firstsocket:-1, + http->postdata?FIRSTSOCKET:-1, http->postdata?&http->writebytecount:NULL); break; @@ -1619,16 +1620,16 @@ CURLcode Curl_http(struct connectdata *conn) add_buffer(req_buffer, "\r\n", 2); /* issue the request */ - result = add_buffer_send(req_buffer, conn->firstsocket, conn, + result = add_buffer_send(req_buffer, conn, &data->info.request_size); if(result) failf(data, "Failed sending HTTP request"); else /* HTTP GET/HEAD download: */ - result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, + result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - http->postdata?conn->firstsocket:-1, + http->postdata?FIRSTSOCKET:-1, http->postdata?&http->writebytecount:NULL); } if(result) diff --git a/lib/multi.c b/lib/multi.c index a89c2b3de..54f8ab5da 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -266,7 +266,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, int sockfd; if(CURLM_STATE_WAITCONNECT == easy->state) { - sockfd = conn->firstsocket; + sockfd = conn->sock[FIRSTSOCKET]; FD_SET(sockfd, write_fd_set); } else { @@ -275,7 +275,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, to connect to us. It makes a difference in the way: if we connect to the site we wait for the socket to become writable, if the site connects to us we wait for it to become readable */ - sockfd = conn->secondarysocket; + sockfd = conn->sock[SECONDARYSOCKET]; FD_SET(sockfd, write_fd_set); } @@ -390,7 +390,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) case CURLM_STATE_WAITCONNECT: /* awaiting a completion of an asynch connect */ easy->result = Curl_is_connected(easy->easy_conn, - easy->easy_conn->firstsocket, + easy->easy_conn->sock[FIRSTSOCKET], &connected); if(connected) easy->result = Curl_protocol_connect(easy->easy_conn, NULL); @@ -437,7 +437,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) * First, check if we really are ready to do more. */ easy->result = Curl_is_connected(easy->easy_conn, - easy->easy_conn->secondarysocket, + easy->easy_conn->sock[SECONDARYSOCKET], &connected); if(connected) { /* @@ -465,11 +465,11 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) * possibly know if the connection is in a good shape or not now. */ easy->easy_conn->bits.close = TRUE; - if(-1 !=easy->easy_conn->secondarysocket) { + if(-1 !=easy->easy_conn->sock[SECONDARYSOCKET]) { /* if we failed anywhere, we must clean up the secondary socket if it was used */ - sclose(easy->easy_conn->secondarysocket); - easy->easy_conn->secondarysocket=-1; + sclose(easy->easy_conn->sock[SECONDARYSOCKET]); + easy->easy_conn->sock[SECONDARYSOCKET]=-1; } Curl_posttransfer(easy->easy_handle); Curl_done(easy->easy_conn); diff --git a/lib/sendf.c b/lib/sendf.c index 2459161d1..1218377b7 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -220,23 +220,27 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn, * to the server. Works with plain sockets, SSL or kerberos. * */ -CURLcode Curl_write(struct connectdata *conn, int sockfd, +CURLcode Curl_write(struct connectdata *conn, + int sockfd, void *mem, size_t len, ssize_t *written) { ssize_t bytes_written; CURLcode retcode; - (void)conn; #ifdef USE_SSLEAY + /* Set 'num' to 0 or 1, depending on which socket that has been sent here. + If it is the second socket, we set num to 1. Otherwise to 0. This lets + us use the correct ssl handle. */ + int num = (sockfd == conn->sock[SECONDARYSOCKET]); /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ - if (conn->ssl.use) { + if (conn->ssl[num].use) { int err; - int rc = SSL_write(conn->ssl.handle, mem, len); + int rc = SSL_write(conn->ssl[num].handle, mem, len); if(rc < 0) { - err = SSL_get_error(conn->ssl.handle, rc); + err = SSL_get_error(conn->ssl[num].handle, rc); switch(err) { case SSL_ERROR_WANT_READ: @@ -271,6 +275,8 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd, bytes_written = rc; } else { +#else + (void)conn; #endif #ifdef KRB4 if(conn->sec_complete) { @@ -364,16 +370,20 @@ int Curl_read(struct connectdata *conn, ssize_t *n) { ssize_t nread; - (void)conn; +#ifdef USE_SSLEAY + /* Set 'num' to 0 or 1, depending on which socket that has been sent here. + If it is the second socket, we set num to 1. Otherwise to 0. This lets + us use the correct ssl handle. */ + int num = (sockfd == conn->sock[SECONDARYSOCKET]); + *n=0; /* reset amount to zero */ -#ifdef USE_SSLEAY - if (conn->ssl.use) { - nread = SSL_read(conn->ssl.handle, buf, buffersize); + if (conn->ssl[num].use) { + nread = SSL_read(conn->ssl[num].handle, buf, buffersize); if(nread < 0) { /* failed SSL_read */ - int err = SSL_get_error(conn->ssl.handle, nread); + int err = SSL_get_error(conn->ssl[num].handle, nread); switch(err) { case SSL_ERROR_NONE: /* this is not an error */ @@ -398,13 +408,16 @@ int Curl_read(struct connectdata *conn, } } else { +#else + (void)conn; #endif + *n=0; /* reset amount to zero */ #ifdef KRB4 if(conn->sec_complete) nread = Curl_sec_read(conn, sockfd, buf, buffersize); else #endif - nread = sread (sockfd, buf, buffersize); + nread = sread(sockfd, buf, buffersize); if(-1 == nread) { int err = Curl_ourerrno(); diff --git a/lib/ssluse.c b/lib/ssluse.c index b0203fd46..7419c4583 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -223,6 +223,7 @@ static int do_file_type(const char *type) static int cert_stuff(struct connectdata *conn, + SSL_CTX* ctx, char *cert_file, const char *cert_type, char *key_file, @@ -246,11 +247,11 @@ int cert_stuff(struct connectdata *conn, /* * We set the password in the callback userdata */ - SSL_CTX_set_default_passwd_cb_userdata(conn->ssl.ctx, + SSL_CTX_set_default_passwd_cb_userdata(ctx, data->set.key_passwd); #endif /* Set passwd callback: */ - SSL_CTX_set_default_passwd_cb(conn->ssl.ctx, passwd_callback); + SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } file_type = do_file_type(cert_type); @@ -258,8 +259,8 @@ int cert_stuff(struct connectdata *conn, switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ - if(SSL_CTX_use_certificate_chain_file(conn->ssl.ctx, - cert_file) != 1) { + if(SSL_CTX_use_certificate_chain_file(ctx, + cert_file) != 1) { failf(data, "unable to set certificate file (wrong password?)"); return 0; } @@ -269,9 +270,9 @@ int cert_stuff(struct connectdata *conn, /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but we use the case above for PEM so this can only be performed with ASN1 files. */ - if(SSL_CTX_use_certificate_file(conn->ssl.ctx, - cert_file, - file_type) != 1) { + if(SSL_CTX_use_certificate_file(ctx, + cert_file, + file_type) != 1) { failf(data, "unable to set certificate file (wrong password?)"); return 0; } @@ -293,9 +294,7 @@ int cert_stuff(struct connectdata *conn, /* cert & key can only be in PEM case in the same file */ key_file=cert_file; case SSL_FILETYPE_ASN1: - if(SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, - key_file, - file_type) != 1) { + if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) { failf(data, "unable to set private key file: '%s' type %s\n", key_file, key_type?key_type:"PEM"); return 0; @@ -322,7 +321,7 @@ int cert_stuff(struct connectdata *conn, failf(data, "failed to load private key from crypto engine\n"); return 0; } - if(SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) { + if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { failf(data, "unable to set private key\n"); EVP_PKEY_free(priv_key); return 0; @@ -344,7 +343,7 @@ int cert_stuff(struct connectdata *conn, return 0; } - ssl=SSL_new(conn->ssl.ctx); + ssl=SSL_new(ctx); x509=SSL_get_certificate(ssl); /* This version was provided by Evan Jordan and is supposed to not @@ -363,7 +362,7 @@ int cert_stuff(struct connectdata *conn, /* Now we know that a key and cert have been set against * the SSL context */ - if(!SSL_CTX_check_private_key(conn->ssl.ctx)) { + if(!SSL_CTX_check_private_key(ctx)) { failf(data, "Private key does not match the certificate public key"); return(0); } @@ -453,6 +452,13 @@ void Curl_SSL_cleanup(void) #endif } +#ifndef USE_SSLEAY +void Curl_SSL_Close(struct connectdata *conn) +{ + (void)conn; +} +#endif + #ifdef USE_SSLEAY /* @@ -460,7 +466,8 @@ void Curl_SSL_cleanup(void) */ void Curl_SSL_Close(struct connectdata *conn) { - if(conn->ssl.use) { + if(conn->ssl[FIRSTSOCKET].use) { + int i; /* ERR_remove_state() frees the error queue associated with thread pid. If pid == 0, the current thread will have its @@ -472,18 +479,22 @@ void Curl_SSL_Close(struct connectdata *conn) */ ERR_remove_state(0); - if(conn->ssl.handle) { - (void)SSL_shutdown(conn->ssl.handle); - SSL_set_connect_state(conn->ssl.handle); - - SSL_free (conn->ssl.handle); - conn->ssl.handle = NULL; + for(i=0; i<2; i++) { + struct ssl_connect_data *connssl = &conn->ssl[i]; + + if(connssl->handle) { + (void)SSL_shutdown(connssl->handle); + SSL_set_connect_state(connssl->handle); + + SSL_free (connssl->handle); + connssl->handle = NULL; + } + if(connssl->ctx) { + SSL_CTX_free (connssl->ctx); + connssl->ctx = NULL; + } + connssl->use = FALSE; /* get back to ordinary socket usage */ } - if(conn->ssl.ctx) { - SSL_CTX_free (conn->ssl.ctx); - conn->ssl.ctx = NULL; - } - conn->ssl.use = FALSE; /* get back to ordinary socket usage */ } } @@ -598,7 +609,8 @@ int Curl_SSL_Close_All(struct SessionHandle *data) /* * Extract the session id and store it in the session cache. */ -static int Store_SSL_Session(struct connectdata *conn) +static int Store_SSL_Session(struct connectdata *conn, + struct ssl_connect_data *ssl) { SSL_SESSION *ssl_sessionid; int i; @@ -609,14 +621,14 @@ static int Store_SSL_Session(struct connectdata *conn) /* ask OpenSSL, say please */ #ifdef HAVE_SSL_GET1_SESSION - ssl_sessionid = SSL_get1_session(conn->ssl.handle); + ssl_sessionid = SSL_get1_session(ssl->handle); /* SSL_get1_session() will increment the reference count and the session will stay in memory until explicitly freed with SSL_SESSION_free(3), regardless of its state. This function was introduced in openssl 0.9.5a. */ #else - ssl_sessionid = SSL_get_session(conn->ssl.handle); + ssl_sessionid = SSL_get_session(ssl->handle); /* if SSL_get1_session() is unavailable, use SSL_get_session(). This is an inferior option because the session can be flushed @@ -647,7 +659,7 @@ static int Store_SSL_Session(struct connectdata *conn) /* now init the session struct wisely */ store->sessionid = ssl_sessionid; - store->age = data->state.sessionage; /* set current age */ + store->age = data->state.sessionage; /* set current age */ store->name = strdup(conn->name); /* clone host name */ store->remote_port = conn->remote_port; /* port number */ @@ -765,7 +777,8 @@ cert_hostcheck(const char *certname, const char *hostname) in the certificate and must exactly match the IP in the URI. */ -static CURLcode verifyhost(struct connectdata *conn) +static CURLcode verifyhost(struct connectdata *conn, + X509 *server_cert) { char peer_CN[257]; bool matched = FALSE; /* no alternative match yet */ @@ -793,8 +806,7 @@ static CURLcode verifyhost(struct connectdata *conn) } /* get a "list" of alternative names */ - altnames = X509_get_ext_d2i(conn->ssl.server_cert, NID_subject_alt_name, - NULL, NULL); + altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); if(altnames) { int hostlen; @@ -856,7 +868,7 @@ static CURLcode verifyhost(struct connectdata *conn) infof(data, "\t subjectAltName: %s matched\n", conn->hostname); else { bool obtain=FALSE; - if(X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert), + if(X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert), NID_commonName, peer_CN, sizeof(peer_CN)) < 0) { @@ -896,7 +908,8 @@ static CURLcode verifyhost(struct connectdata *conn) /* ====================================================== */ CURLcode -Curl_SSLConnect(struct connectdata *conn) +Curl_SSLConnect(struct connectdata *conn, + int sockindex) { CURLcode retcode = CURLE_OK; @@ -908,9 +921,11 @@ Curl_SSLConnect(struct connectdata *conn) SSL_METHOD *req_method; SSL_SESSION *ssl_sessionid=NULL; ASN1_TIME *certdate; + int sockfd = conn->sock[sockindex]; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; /* mark this is being ssl enabled from here on out. */ - conn->ssl.use = TRUE; + connssl->use = TRUE; if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { /* Make funny stuff to get random input */ @@ -937,9 +952,9 @@ Curl_SSLConnect(struct connectdata *conn) break; } - conn->ssl.ctx = SSL_CTX_new(req_method); + connssl->ctx = SSL_CTX_new(req_method); - if(!conn->ssl.ctx) { + if(!connssl->ctx) { failf(data, "SSL: couldn't create a context!"); return CURLE_OUT_OF_MEMORY; } @@ -952,10 +967,11 @@ Curl_SSLConnect(struct connectdata *conn) implementations is desired." */ - SSL_CTX_set_options(conn->ssl.ctx, SSL_OP_ALL); + SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL); if(data->set.cert) { if(!cert_stuff(conn, + connssl->ctx, data->set.cert, data->set.cert_type, data->set.key, @@ -966,7 +982,7 @@ Curl_SSLConnect(struct connectdata *conn) } if(data->set.ssl.cipher_list) { - if(!SSL_CTX_set_cipher_list(conn->ssl.ctx, + if(!SSL_CTX_set_cipher_list(connssl->ctx, data->set.ssl.cipher_list)) { failf(data, "failed setting cipher list"); return CURLE_SSL_CIPHER; @@ -976,7 +992,7 @@ Curl_SSLConnect(struct connectdata *conn) if (data->set.ssl.CAfile || data->set.ssl.CApath) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ - if (!SSL_CTX_load_verify_locations(conn->ssl.ctx, data->set.ssl.CAfile, + if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile, data->set.ssl.CApath)) { if (data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ @@ -989,34 +1005,31 @@ Curl_SSLConnect(struct connectdata *conn) else { /* Just continue with a warning if no strict certificate verification is required. */ - infof(data,"error setting certificate verify locations," + infof(data, "error setting certificate verify locations," " continuing anyway:\n"); - infof(data, " CAfile: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none"); - infof(data, " CApath: %s\n", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); } } else { /* Everything is fine. */ - infof(data,"successfully set certificate verify locations:\n"); - infof(data, " CAfile: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none"); - infof(data, " CApath: %s\n", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); + infof(data, "successfully set certificate verify locations:\n"); } + infof(data, + " CAfile: %s\n" + " CApath: %s\n", + data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", + data->set.ssl.CApath ? data->set.ssl.CApath : "none"); } /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ - SSL_CTX_set_verify(conn->ssl.ctx, + SSL_CTX_set_verify(connssl->ctx, data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, cert_verify_callback); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { - retcode = (*data->set.ssl.fsslctx)(data, conn->ssl.ctx, + retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx, data->set.ssl.fsslctxp); if(retcode) { failf(data,"error signaled by ssl ctx callback"); @@ -1025,24 +1038,24 @@ Curl_SSLConnect(struct connectdata *conn) } /* Lets make an SSL structure */ - conn->ssl.handle = SSL_new (conn->ssl.ctx); - SSL_set_connect_state (conn->ssl.handle); + connssl->handle = SSL_new(connssl->ctx); + SSL_set_connect_state(connssl->handle); - conn->ssl.server_cert = 0x0; + connssl->server_cert = 0x0; if(!conn->bits.reuse) { /* We're not re-using a connection, check if there's a cached ID we can/should use here! */ if(!Get_SSL_Session(conn, &ssl_sessionid)) { /* we got a session id, use it! */ - SSL_set_session(conn->ssl.handle, ssl_sessionid); + SSL_set_session(connssl->handle, ssl_sessionid); /* Informational message */ infof (data, "SSL re-using session ID\n"); } } /* pass the raw socket into the SSL layers */ - SSL_set_fd(conn->ssl.handle, conn->firstsocket); + SSL_set_fd(connssl->handle, sockfd); do { fd_set writefd; @@ -1088,18 +1101,18 @@ Curl_SSLConnect(struct connectdata *conn) FD_ZERO(&writefd); FD_ZERO(&readfd); - err = SSL_connect(conn->ssl.handle); + err = SSL_connect(connssl->handle); /* 1 is fine 0 is "not successful but was shut down controlled" <0 is "handshake was not successful, because a fatal error occurred" */ if(1 != err) { - int detail = SSL_get_error(conn->ssl.handle, err); + int detail = SSL_get_error(connssl->handle, err); if(SSL_ERROR_WANT_READ == detail) - FD_SET(conn->firstsocket, &readfd); + FD_SET(sockfd, &readfd); else if(SSL_ERROR_WANT_WRITE == detail) - FD_SET(conn->firstsocket, &writefd); + FD_SET(sockfd, &writefd); else { /* untreated error */ char error_buffer[120]; /* OpenSSL documents that this must be at least @@ -1143,7 +1156,7 @@ Curl_SSLConnect(struct connectdata *conn) interval.tv_usec = timeout_ms*1000; - what = select(conn->firstsocket+1, &readfd, &writefd, NULL, &interval); + what = select(sockfd+1, &readfd, &writefd, NULL, &interval); if(what > 0) /* reabable or writable, go loop yourself */ continue; @@ -1158,12 +1171,12 @@ Curl_SSLConnect(struct connectdata *conn) /* Informational message */ infof (data, "SSL connection using %s\n", - SSL_get_cipher(conn->ssl.handle)); + SSL_get_cipher(connssl->handle)); if(!ssl_sessionid) { /* Since this is not a cached session ID, then we want to stach this one in the cache! */ - Store_SSL_Session(conn); + Store_SSL_Session(conn, connssl); } @@ -1173,38 +1186,38 @@ Curl_SSLConnect(struct connectdata *conn) * attack */ - conn->ssl.server_cert = SSL_get_peer_certificate(conn->ssl.handle); - if(!conn->ssl.server_cert) { + connssl->server_cert = SSL_get_peer_certificate(connssl->handle); + if(!connssl->server_cert) { failf(data, "SSL: couldn't get peer certificate!"); return CURLE_SSL_PEER_CERTIFICATE; } infof (data, "Server certificate:\n"); - str = X509_NAME_oneline(X509_get_subject_name(conn->ssl.server_cert), + str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert), NULL, 0); if(!str) { failf(data, "SSL: couldn't get X509-subject!"); - X509_free(conn->ssl.server_cert); + X509_free(connssl->server_cert); return CURLE_SSL_CONNECT_ERROR; } infof(data, "\t subject: %s\n", str); CRYPTO_free(str); - certdate = X509_get_notBefore(conn->ssl.server_cert); + certdate = X509_get_notBefore(connssl->server_cert); Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); - certdate = X509_get_notAfter(conn->ssl.server_cert); + certdate = X509_get_notAfter(connssl->server_cert); Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); if(data->set.ssl.verifyhost) { - retcode = verifyhost(conn); + retcode = verifyhost(conn, connssl->server_cert); if(retcode) { - X509_free(conn->ssl.server_cert); + X509_free(connssl->server_cert); return retcode; } } - str = X509_NAME_oneline(X509_get_issuer_name(conn->ssl.server_cert), + str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert), NULL, 0); if(!str) { failf(data, "SSL: couldn't get X509-issuer name!"); @@ -1217,7 +1230,7 @@ Curl_SSLConnect(struct connectdata *conn) /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ - data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle); + data->set.ssl.certverifyresult=SSL_get_verify_result(connssl->handle); if(data->set.ssl.certverifyresult != X509_V_OK) { if(data->set.ssl.verifypeer) { /* We probably never reach this, because SSL_connect() will fail @@ -1234,7 +1247,7 @@ Curl_SSLConnect(struct connectdata *conn) infof(data, "SSL certificate verify ok.\n"); } - X509_free(conn->ssl.server_cert); + X509_free(connssl->server_cert); #else /* USE_SSLEAY */ /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ (void) conn; diff --git a/lib/ssluse.h b/lib/ssluse.h index fd5e017c9..7a3fc3e52 100644 --- a/lib/ssluse.h +++ b/lib/ssluse.h @@ -23,7 +23,7 @@ * $Id$ ***************************************************************************/ #include "urldata.h" -CURLcode Curl_SSLConnect(struct connectdata *conn); +CURLcode Curl_SSLConnect(struct connectdata *conn, int sockfd); void Curl_SSL_init(void); /* Global SSL init */ void Curl_SSL_cleanup(void); /* Global SSL cleanup */ diff --git a/lib/telnet.c b/lib/telnet.c index a4d189a47..7d21a548c 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -262,7 +262,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option) buf[1] = cmd; buf[2] = option; - (void)swrite(conn->firstsocket, buf, 3); + (void)swrite(conn->sock[FIRSTSOCKET], buf, 3); printoption(conn->data, "SENT", cmd, option); } @@ -826,7 +826,7 @@ static void suboption(struct connectdata *conn) snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); - (void)swrite(conn->firstsocket, temp, len); + (void)swrite(conn->sock[FIRSTSOCKET], temp, len); printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_XDISPLOC: @@ -834,7 +834,7 @@ static void suboption(struct connectdata *conn) snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); - (void)swrite(conn->firstsocket, temp, len); + (void)swrite(conn->sock[FIRSTSOCKET], temp, len); printsub(data, '>', &temp[2], len-2); break; case CURL_TELOPT_NEW_ENVIRON: @@ -857,7 +857,7 @@ static void suboption(struct connectdata *conn) snprintf((char *)&temp[len], sizeof(temp) - len, "%c%c", CURL_IAC, CURL_SE); len += 2; - (void)swrite(conn->firstsocket, temp, len); + (void)swrite(conn->sock[FIRSTSOCKET], temp, len); printsub(data, '>', &temp[2], len-2); break; } @@ -1035,7 +1035,7 @@ CURLcode Curl_telnet(struct connectdata *conn) { CURLcode code; struct SessionHandle *data = conn->data; - int sockfd = conn->firstsocket; + int sockfd = conn->sock[FIRSTSOCKET]; #ifdef WIN32 WSAEVENT event_handle; WSANETWORKEVENTS events; @@ -1105,7 +1105,7 @@ CURLcode Curl_telnet(struct connectdata *conn) if(outbuf[0] == CURL_IAC) outbuf[out_count++] = CURL_IAC; - Curl_write(conn, conn->firstsocket, outbuf, + Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, out_count, &bytes_written); } } @@ -1176,7 +1176,7 @@ CURLcode Curl_telnet(struct connectdata *conn) if(outbuf[0] == CURL_IAC) outbuf[out_count++] = CURL_IAC; - Curl_write(conn, conn->firstsocket, outbuf, + Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf, out_count, &bytes_written); } } diff --git a/lib/transfer.c b/lib/transfer.c index 063cd1049..81a52a590 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1865,14 +1865,7 @@ CURLcode Curl_perform(struct SessionHandle *data) res = Curl_do(&conn); if(res == CURLE_OK) { - if(conn->protocol&PROT_FTPS) - /* FTPS, disable ssl while transfering data */ - conn->ssl.use = FALSE; res = Transfer(conn); /* now fetch that URL please */ - if(conn->protocol&PROT_FTPS) - /* FTPS, enable ssl again after havving transferred data */ - conn->ssl.use = TRUE; - if(res == CURLE_OK) /* * We must duplicate the new URL here as the connection data @@ -1885,11 +1878,11 @@ CURLcode Curl_perform(struct SessionHandle *data) * possibly know if the connection is in a good shape or not now. */ conn->bits.close = TRUE; - if(-1 !=conn->secondarysocket) { + if(-1 != conn->sock[SECONDARYSOCKET]) { /* if we failed anywhere, we must clean up the secondary socket if it was used */ - sclose(conn->secondarysocket); - conn->secondarysocket=-1; + sclose(conn->sock[SECONDARYSOCKET]); + conn->sock[SECONDARYSOCKET]=-1; } } @@ -1932,12 +1925,13 @@ CURLcode Curl_perform(struct SessionHandle *data) CURLcode Curl_Transfer(struct connectdata *c_conn, /* connection data */ - int sockfd, /* socket to read from or -1 */ + int sockindex, /* socket index to read from or -1 */ int size, /* -1 if unknown at this point */ bool getheader, /* TRUE if header parsing is wanted */ long *bytecountp, /* return number of bytes read or NULL */ - int writesockfd, /* socket to write to, it may very well be - the same we read from. -1 disables */ + int writesockindex, /* socket index to write to, it may very + well be the same we read from. -1 + disables */ long *writebytecountp /* return number of bytes written or NULL */ ) @@ -1947,11 +1941,11 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */ return CURLE_BAD_FUNCTION_ARGUMENT; /* now copy all input parameters */ - conn->sockfd = sockfd; + conn->sockfd = sockindex==-1?-1:conn->sock[sockindex]; conn->size = size; conn->bits.getheader = getheader; conn->bytecountp = bytecountp; - conn->writesockfd = writesockfd; + conn->writesockfd = writesockindex==-1?-1:conn->sock[writesockindex]; conn->writebytecountp = writebytecountp; return CURLE_OK; diff --git a/lib/url.c b/lib/url.c index 794cfab9f..69de6f8a0 100644 --- a/lib/url.c +++ b/lib/url.c @@ -1251,6 +1251,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) data->set.max_filesize = va_arg(param, long); break; + case CURLOPT_FTP_SSL: + /* + * Make FTP transfers attempt to use SSL/TLS. + */ + data->set.ftp_ssl = va_arg(param, long); + break; + default: /* unknown tag and its companion, just ignore: */ return CURLE_FAILED_INIT; /* correct this */ @@ -1293,16 +1300,13 @@ CURLcode Curl_disconnect(struct connectdata *conn) Curl_safefree(conn->proto.generic); Curl_safefree(conn->newurl); Curl_safefree(conn->path); /* the URL path part */ - -#ifdef USE_SSLEAY Curl_SSL_Close(conn); -#endif /* USE_SSLEAY */ /* close possibly still open sockets */ - if(-1 != conn->secondarysocket) - sclose(conn->secondarysocket); - if(-1 != conn->firstsocket) - sclose(conn->firstsocket); + if(-1 != conn->sock[SECONDARYSOCKET]) + sclose(conn->sock[SECONDARYSOCKET]); + if(-1 != conn->sock[FIRSTSOCKET]) + sclose(conn->sock[FIRSTSOCKET]); Curl_safefree(conn->user); Curl_safefree(conn->passwd); @@ -1429,7 +1433,7 @@ ConnectionExists(struct SessionHandle *data, } if(match) { - bool dead = SocketIsDead(check->firstsocket); + bool dead = SocketIsDead(check->sock[FIRSTSOCKET]); if(dead) { /* */ @@ -1549,16 +1553,15 @@ ConnectionStore(struct SessionHandle *data, * This function logs in to a SOCKS5 proxy and sends the specifies the final * desitination server. */ -static int handleSock5Proxy( - const char *proxy_name, - const char *proxy_password, - struct connectdata *conn, - int sock) +static int handleSock5Proxy(const char *proxy_name, + const char *proxy_password, + struct connectdata *conn) { unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ ssize_t actualread; ssize_t written; CURLcode result; + int sock = conn->sock[FIRSTSOCKET]; Curl_nonblock(sock, FALSE); @@ -1754,7 +1757,7 @@ static CURLcode ConnectPlease(struct connectdata *conn, result= Curl_connecthost(conn, hostaddr, conn->port, - &conn->firstsocket, + &conn->sock[FIRSTSOCKET], &addr, connected); if(CURLE_OK == result) { @@ -1776,8 +1779,7 @@ static CURLcode ConnectPlease(struct connectdata *conn, if (conn->data->set.proxytype == CURLPROXY_SOCKS5) { return handleSock5Proxy(conn->proxyuser, conn->proxypasswd, - conn, - conn->firstsocket) ? + conn) ? CURLE_COULDNT_CONNECT : CURLE_OK; } else if (conn->data->set.proxytype == CURLPROXY_HTTP) { @@ -1953,8 +1955,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* and we setup a few fields in case we end up actually using this struct */ conn->data = data; /* remember our daddy */ - conn->firstsocket = -1; /* no file descriptor */ - conn->secondarysocket = -1; /* no file descriptor */ + conn->sock[FIRSTSOCKET] = -1; /* no file descriptor */ + conn->sock[SECONDARYSOCKET] = -1; /* no file descriptor */ conn->connectindex = -1; /* no index */ conn->bits.httpproxy = (data->change.proxy && *data->change.proxy && (data->set.proxytype == CURLPROXY_HTTP))? @@ -2419,6 +2421,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, if(strequal(conn->protostr, "FTPS")) { #ifdef USE_SSLEAY conn->protocol |= PROT_FTPS|PROT_SSL; + conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */ #else failf(data, LIBCURL_NAME " was built with SSL disabled, ftps: not supported!"); @@ -3100,7 +3103,7 @@ static CURLcode SetupConnection(struct connectdata *conn, conn->bytecount = 0; conn->headerbytecount = 0; - if(-1 == conn->firstsocket) { + if(-1 == conn->sock[FIRSTSOCKET]) { bool connected; /* Connect only if not already connected! */ diff --git a/lib/urldata.h b/lib/urldata.h index c2678ca49..494cfb139 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -130,9 +130,9 @@ enum protection_level { }; #endif -/* struct for data related to SSL and SSL connections */ +/* struct for data related to each SSL connection */ struct ssl_connect_data { - bool use; /* use ssl encrypted communications TRUE/FALSE */ + bool use; /* use ssl encrypted communications TRUE/FALSE */ #ifdef USE_SSLEAY /* these ones requires specific SSL-types */ SSL_CTX* ctx; @@ -385,6 +385,9 @@ struct Curl_async { }; #endif +#define FIRSTSOCKET 0 +#define SECONDARYSOCKET 1 + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. @@ -442,12 +445,12 @@ struct connectdata { struct timeval now; /* "current" time */ struct timeval created; /* creation time */ - int firstsocket; /* the main socket to use */ - int secondarysocket; /* for i.e ftp transfers */ + int sock[2]; /* two sockets, the second is used for the data transfer + when doing FTP */ long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 means unlimited */ - struct ssl_connect_data ssl; /* this is for ssl-stuff */ + struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ struct ssl_config_data ssl_config; struct ConnectBits bits; /* various state-flags for this connection */ @@ -486,8 +489,8 @@ struct connectdata { long *bytecountp; /* return number of bytes read or NULL */ /* WRITE stuff */ - int writesockfd; /* socket to write to, it may very well be - the same we read from. -1 disables */ + int writesockfd; /* socket to write to, it may very + well be the same we read from. -1 disables */ long *writebytecountp; /* return number of bytes written or NULL */ /** Dynamicly allocated strings, may need to be freed before this **/ @@ -863,6 +866,7 @@ struct UserDefined { bool expect100header; /* TRUE if we added Expect: 100-continue */ bool ftp_use_epsv; /* if EPSV is to be attempted or not */ bool ftp_use_eprt; /* if EPRT is to be attempted or not */ + curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */ bool no_signal; /* do not use any signal/alarm handler */ bool global_dns_cache;