1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-15 14:05:03 -05:00

FTPS support added as RFC2228 and the murray-ftp-auth-ssl draft describe it

This commit is contained in:
Daniel Stenberg 2003-11-24 07:15:37 +00:00
parent 1c700b5a5c
commit 1e98727c55
12 changed files with 294 additions and 190 deletions

View File

@ -29,7 +29,7 @@
/* This is the version number of the libcurl package from which this header /* This is the version number of the libcurl package from which this header
file origins: */ 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 /* This is the numeric version of the libcurl version number, meant for easier
parsing and comparions by programs. The LIBCURL_VERSION_NUM define will 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 always a greater number in a more recent release. It makes comparisons with
greater than and less than work. 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 /* The numeric version number is also available "in parts" by using these
defines: */ defines: */
#define LIBCURL_VERSION_MAJOR 7 #define LIBCURL_VERSION_MAJOR 7
#define LIBCURL_VERSION_MINOR 10 #define LIBCURL_VERSION_MINOR 11
#define LIBCURL_VERSION_PATCH 9 #define LIBCURL_VERSION_PATCH 0
#include <stdio.h> #include <stdio.h>

View File

@ -89,6 +89,7 @@ CURLcode Curl_dict(struct connectdata *conn)
by RFC 2229 */ by RFC 2229 */
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
int sockfd = conn->sock[FIRSTSOCKET];
char *path = conn->path; char *path = conn->path;
long *bytecount = &conn->bytecount; long *bytecount = &conn->bytecount;
@ -134,7 +135,7 @@ CURLcode Curl_dict(struct connectdata *conn)
nth = atoi(nthdef); nth = atoi(nthdef);
} }
result = Curl_sendf(conn->firstsocket, conn, result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"MATCH " "MATCH "
"%s " /* database */ "%s " /* database */
@ -149,7 +150,7 @@ CURLcode Curl_dict(struct connectdata *conn)
if(result) if(result)
failf(data, "Failed sending DICT request"); failf(data, "Failed sending DICT request");
else else
result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount,
-1, NULL); /* no upload */ -1, NULL); /* no upload */
if(result) if(result)
return result; return result;
@ -184,7 +185,7 @@ CURLcode Curl_dict(struct connectdata *conn)
nth = atoi(nthdef); nth = atoi(nthdef);
} }
result = Curl_sendf(conn->firstsocket, conn, result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"DEFINE " "DEFINE "
"%s " /* database */ "%s " /* database */
@ -195,7 +196,7 @@ CURLcode Curl_dict(struct connectdata *conn)
if(result) if(result)
failf(data, "Failed sending DICT request"); failf(data, "Failed sending DICT request");
else else
result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount,
-1, NULL); /* no upload */ -1, NULL); /* no upload */
if(result) if(result)
@ -213,14 +214,14 @@ CURLcode Curl_dict(struct connectdata *conn)
if (ppath[i] == ':') if (ppath[i] == ':')
ppath[i] = ' '; ppath[i] = ' ';
} }
result = Curl_sendf(conn->firstsocket, conn, result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n" "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"%s\n" "%s\n"
"QUIT\n", ppath); "QUIT\n", ppath);
if(result) if(result)
failf(data, "Failed sending DICT request"); failf(data, "Failed sending DICT request");
else else
result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount, result = Curl_Transfer(conn, sockfd, -1, FALSE, bytecount,
-1, NULL); -1, NULL);
if(result) if(result)
return result; return result;

119
lib/ftp.c
View File

@ -126,12 +126,12 @@ static void freedirs(struct FTP *ftp)
* connected. * connected.
* *
*/ */
static CURLcode AllowServerConnect(struct SessionHandle *data, static CURLcode AllowServerConnect(struct connectdata *conn)
struct connectdata *conn,
int sock)
{ {
fd_set rdset; fd_set rdset;
struct timeval dt; struct timeval dt;
struct SessionHandle *data = conn->data;
int sock = conn->sock[SECONDARYSOCKET];
FD_ZERO(&rdset); FD_ZERO(&rdset);
@ -169,7 +169,7 @@ static CURLcode AllowServerConnect(struct SessionHandle *data,
} }
infof(data, "Connection accepted from server\n"); infof(data, "Connection accepted from server\n");
conn->secondarysocket = s; conn->sock[SECONDARYSOCKET] = s;
Curl_nonblock(s, TRUE); /* enable non-blocking */ Curl_nonblock(s, TRUE); /* enable non-blocking */
} }
break; 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 * Alas, read as much as possible, split up into lines, use the ending
* line in a response or continue reading. */ * line in a response or continue reading. */
int sockfd = conn->firstsocket; int sockfd = conn->sock[FIRSTSOCKET];
int perline; /* count bytes per line */ int perline; /* count bytes per line */
bool keepon=TRUE; bool keepon=TRUE;
ssize_t gotbytes; ssize_t gotbytes;
@ -438,7 +438,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
if (data->set.tunnel_thru_httpproxy) { if (data->set.tunnel_thru_httpproxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */ /* 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); conn->hostname, conn->remote_port);
if(CURLE_OK != result) if(CURLE_OK != result)
return result; return result;
@ -447,7 +447,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
if(conn->protocol & PROT_FTPS) { if(conn->protocol & PROT_FTPS) {
/* FTPS is simply ftp with SSL for the control channel */ /* FTPS is simply ftp with SSL for the control channel */
/* now, perform the SSL initialization for this socket */ /* now, perform the SSL initialization for this socket */
result = Curl_SSLConnect(conn); result = Curl_SSLConnect(conn, FIRSTSOCKET);
if(result) if(result)
return result; return result;
} }
@ -481,6 +481,71 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
} }
#endif #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 */ /* send USER */
FTPSENDF(conn, "USER %s", ftp->user?ftp->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); Curl_sec_fflush_fd(conn, conn->secondarysocket);
#endif #endif
/* shut down the socket to inform the server we're done */ /* shut down the socket to inform the server we're done */
sclose(conn->secondarysocket); sclose(conn->sock[SECONDARYSOCKET]);
conn->secondarysocket = -1; conn->sock[SECONDARYSOCKET] = -1;
if(!ftp->no_transfer) { if(!ftp->no_transfer) {
/* Let's see what the server says about the transfer we just performed, /* 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. * I believe we should use the same address as the control connection.
*/ */
sslen = sizeof(ss); 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; return CURLE_FTP_PORT_FAILED;
if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0, 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 /* we set the secondary socket variable to this for now, it
is only so that the cleanup function will close it in case is only so that the cleanup function will close it in case
we fail before the true secondary stuff is made */ we fail before the true secondary stuff is made */
conn->secondarysocket = portsock; conn->sock[SECONDARYSOCKET] = portsock;
#else #else
/****************************************************************** /******************************************************************
@ -1249,7 +1314,8 @@ CURLcode ftp_use_port(struct connectdata *conn)
socklen_t sslen; socklen_t sslen;
sslen = sizeof(sa); 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"); failf(data, "getsockname() failed");
return CURLE_FTP_PORT_FAILED; return CURLE_FTP_PORT_FAILED;
} }
@ -1526,7 +1592,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
result = Curl_connecthost(conn, result = Curl_connecthost(conn,
addr, addr,
connectport, connectport,
&conn->secondarysocket, &conn->sock[SECONDARYSOCKET],
&conninfo, &conninfo,
connected); connected);
@ -1547,7 +1613,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
if (data->set.tunnel_thru_httpproxy) { if (data->set.tunnel_thru_httpproxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */ /* We want "seamless" FTP operations through HTTP proxy tunnel */
result = Curl_ConnectHTTPProxyTunnel(conn, conn->secondarysocket, result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
newhostp, newport); newhostp, newport);
if(CURLE_OK != result) if(CURLE_OK != result)
return result; return result;
@ -1684,7 +1750,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
if(data->set.ftp_use_port) { if(data->set.ftp_use_port) {
/* PORT means we are now awaiting the server to connect to us. */ /* PORT means we are now awaiting the server to connect to us. */
result = AllowServerConnect(data, conn, conn->secondarysocket); result = AllowServerConnect(conn);
if( result ) if( result )
return result; return result;
} }
@ -1697,7 +1763,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
Curl_pgrsSetUploadSize(data, data->set.infilesize); Curl_pgrsSetUploadSize(data, data->set.infilesize);
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */ result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
conn->secondarysocket, bytecountp); SECONDARYSOCKET, bytecountp);
if(result) if(result)
return result; return result;
@ -1940,15 +2006,24 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
size = downloadsize; size = downloadsize;
if(data->set.ftp_use_port) { if(data->set.ftp_use_port) {
result = AllowServerConnect(data, conn, conn->secondarysocket); result = AllowServerConnect(conn);
if( result ) if( result )
return 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); infof(data, "Getting file with size: %d\n", size);
/* FTP download: */ /* FTP download: */
result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE, result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
bytecountp, bytecountp,
-1, NULL); /* no upload here */ -1, NULL); /* no upload here */
if(result) if(result)
@ -2232,10 +2307,10 @@ CURLcode Curl_ftp(struct connectdata *conn)
if(connected) if(connected)
retcode = Curl_ftp_nextconnect(conn); 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 */ /* Failure detected, close the second socket if it was created already */
sclose(conn->secondarysocket); sclose(conn->sock[SECONDARYSOCKET]);
conn->secondarysocket = -1; conn->sock[SECONDARYSOCKET] = -1;
} }
if(ftp->no_transfer) if(ftp->no_transfer)
@ -2280,7 +2355,7 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
write_len = strlen(s); write_len = strlen(s);
do { do {
res = Curl_write(conn, conn->firstsocket, sptr, write_len, res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
&bytes_written); &bytes_written);
if(CURLE_OK != res) if(CURLE_OK != res)

View File

@ -500,7 +500,6 @@ send_buffer *add_buffer_init(void)
*/ */
static static
CURLcode add_buffer_send(send_buffer *in, CURLcode add_buffer_send(send_buffer *in,
int sockfd,
struct connectdata *conn, struct connectdata *conn,
long *bytes_written) /* add the number of sent long *bytes_written) /* add the number of sent
bytes to this counter */ bytes to this counter */
@ -511,6 +510,7 @@ CURLcode add_buffer_send(send_buffer *in,
int size; int size;
struct HTTP *http = conn->proto.http; struct HTTP *http = conn->proto.http;
int sendsize; int sendsize;
int sockfd = conn->sock[FIRSTSOCKET];
/* The looping below is required since we use non-blocking sockets, but due /* 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 */ 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, CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
int tunnelsocket, int sockindex,
char *hostname, char *hostname,
int remote_port) int remote_port)
{ {
@ -729,6 +729,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
fd_set readfd; fd_set readfd;
char *line_start; char *line_start;
char *host_port; char *host_port;
int tunnelsocket = conn->sock[sockindex];
#define SELECT_OK 0 #define SELECT_OK 0
#define SELECT_ERROR 1 #define SELECT_ERROR 1
@ -936,7 +937,7 @@ CURLcode Curl_http_connect(struct connectdata *conn)
((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) { ((conn->protocol & PROT_HTTPS) || data->set.tunnel_thru_httpproxy)) {
/* either HTTPS over proxy, OR explicitly asked for a tunnel */ /* 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); conn->hostname, conn->remote_port);
if(CURLE_OK != result) if(CURLE_OK != result)
return result; return result;
@ -944,7 +945,7 @@ CURLcode Curl_http_connect(struct connectdata *conn)
if(conn->protocol & PROT_HTTPS) { if(conn->protocol & PROT_HTTPS) {
/* now, perform the SSL initialization for this socket */ /* now, perform the SSL initialization for this socket */
result = Curl_SSLConnect(conn); result = Curl_SSLConnect(conn, FIRSTSOCKET);
if(result) if(result)
return result; return result;
} }
@ -1491,15 +1492,15 @@ CURLcode Curl_http(struct connectdata *conn)
Curl_pgrsSetUploadSize(data, http->postsize); Curl_pgrsSetUploadSize(data, http->postsize);
/* fire away the whole request to the server */ /* 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); &data->info.request_size);
if(result) if(result)
failf(data, "Failed sending POST request"); failf(data, "Failed sending POST request");
else else
/* setup variables for the upcoming transfer */ /* setup variables for the upcoming transfer */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount, &http->readbytecount,
conn->firstsocket, FIRSTSOCKET,
&http->writebytecount); &http->writebytecount);
if(result) { if(result) {
Curl_formclean(http->sendit); /* free that whole lot */ Curl_formclean(http->sendit); /* free that whole lot */
@ -1521,15 +1522,15 @@ CURLcode Curl_http(struct connectdata *conn)
Curl_pgrsSetUploadSize(data, data->set.infilesize); Curl_pgrsSetUploadSize(data, data->set.infilesize);
/* this sends the buffer and frees all the buffer resources */ /* 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); &data->info.request_size);
if(result) if(result)
failf(data, "Failed sending POST request"); failf(data, "Failed sending POST request");
else else
/* prepare for transfer */ /* prepare for transfer */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount, &http->readbytecount,
conn->firstsocket, FIRSTSOCKET,
&http->writebytecount); &http->writebytecount);
if(result) if(result)
return result; return result;
@ -1602,16 +1603,16 @@ CURLcode Curl_http(struct connectdata *conn)
http->postdata = (char *)&http->postdata; http->postdata = (char *)&http->postdata;
} }
/* issue the request */ /* issue the request */
result = add_buffer_send(req_buffer, conn->firstsocket, conn, result = add_buffer_send(req_buffer, conn,
&data->info.request_size); &data->info.request_size);
if(result) if(result)
failf(data, "Failed sending HTTP POST request"); failf(data, "Failed sending HTTP POST request");
else else
result = result =
Curl_Transfer(conn, conn->firstsocket, -1, TRUE, Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount, &http->readbytecount,
http->postdata?conn->firstsocket:-1, http->postdata?FIRSTSOCKET:-1,
http->postdata?&http->writebytecount:NULL); http->postdata?&http->writebytecount:NULL);
break; break;
@ -1619,16 +1620,16 @@ CURLcode Curl_http(struct connectdata *conn)
add_buffer(req_buffer, "\r\n", 2); add_buffer(req_buffer, "\r\n", 2);
/* issue the request */ /* issue the request */
result = add_buffer_send(req_buffer, conn->firstsocket, conn, result = add_buffer_send(req_buffer, conn,
&data->info.request_size); &data->info.request_size);
if(result) if(result)
failf(data, "Failed sending HTTP request"); failf(data, "Failed sending HTTP request");
else else
/* HTTP GET/HEAD download: */ /* HTTP GET/HEAD download: */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount, &http->readbytecount,
http->postdata?conn->firstsocket:-1, http->postdata?FIRSTSOCKET:-1,
http->postdata?&http->writebytecount:NULL); http->postdata?&http->writebytecount:NULL);
} }
if(result) if(result)

View File

@ -266,7 +266,7 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
int sockfd; int sockfd;
if(CURLM_STATE_WAITCONNECT == easy->state) { if(CURLM_STATE_WAITCONNECT == easy->state) {
sockfd = conn->firstsocket; sockfd = conn->sock[FIRSTSOCKET];
FD_SET(sockfd, write_fd_set); FD_SET(sockfd, write_fd_set);
} }
else { 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 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 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 */ 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); FD_SET(sockfd, write_fd_set);
} }
@ -390,7 +390,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
case CURLM_STATE_WAITCONNECT: case CURLM_STATE_WAITCONNECT:
/* awaiting a completion of an asynch connect */ /* awaiting a completion of an asynch connect */
easy->result = Curl_is_connected(easy->easy_conn, easy->result = Curl_is_connected(easy->easy_conn,
easy->easy_conn->firstsocket, easy->easy_conn->sock[FIRSTSOCKET],
&connected); &connected);
if(connected) if(connected)
easy->result = Curl_protocol_connect(easy->easy_conn, NULL); 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. * First, check if we really are ready to do more.
*/ */
easy->result = Curl_is_connected(easy->easy_conn, easy->result = Curl_is_connected(easy->easy_conn,
easy->easy_conn->secondarysocket, easy->easy_conn->sock[SECONDARYSOCKET],
&connected); &connected);
if(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. */ * possibly know if the connection is in a good shape or not now. */
easy->easy_conn->bits.close = TRUE; 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 /* if we failed anywhere, we must clean up the secondary socket if
it was used */ it was used */
sclose(easy->easy_conn->secondarysocket); sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
easy->easy_conn->secondarysocket=-1; easy->easy_conn->sock[SECONDARYSOCKET]=-1;
} }
Curl_posttransfer(easy->easy_handle); Curl_posttransfer(easy->easy_handle);
Curl_done(easy->easy_conn); Curl_done(easy->easy_conn);

View File

@ -220,23 +220,27 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
* to the server. Works with plain sockets, SSL or kerberos. * 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, void *mem, size_t len,
ssize_t *written) ssize_t *written)
{ {
ssize_t bytes_written; ssize_t bytes_written;
CURLcode retcode; CURLcode retcode;
(void)conn;
#ifdef USE_SSLEAY #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 /* SSL_write() is said to return 'int' while write() and send() returns
'size_t' */ 'size_t' */
if (conn->ssl.use) { if (conn->ssl[num].use) {
int err; int err;
int rc = SSL_write(conn->ssl.handle, mem, len); int rc = SSL_write(conn->ssl[num].handle, mem, len);
if(rc < 0) { if(rc < 0) {
err = SSL_get_error(conn->ssl.handle, rc); err = SSL_get_error(conn->ssl[num].handle, rc);
switch(err) { switch(err) {
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
@ -271,6 +275,8 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd,
bytes_written = rc; bytes_written = rc;
} }
else { else {
#else
(void)conn;
#endif #endif
#ifdef KRB4 #ifdef KRB4
if(conn->sec_complete) { if(conn->sec_complete) {
@ -364,16 +370,20 @@ int Curl_read(struct connectdata *conn,
ssize_t *n) ssize_t *n)
{ {
ssize_t nread; 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 */ *n=0; /* reset amount to zero */
#ifdef USE_SSLEAY if (conn->ssl[num].use) {
if (conn->ssl.use) { nread = SSL_read(conn->ssl[num].handle, buf, buffersize);
nread = SSL_read(conn->ssl.handle, buf, buffersize);
if(nread < 0) { if(nread < 0) {
/* failed SSL_read */ /* failed SSL_read */
int err = SSL_get_error(conn->ssl.handle, nread); int err = SSL_get_error(conn->ssl[num].handle, nread);
switch(err) { switch(err) {
case SSL_ERROR_NONE: /* this is not an error */ case SSL_ERROR_NONE: /* this is not an error */
@ -398,13 +408,16 @@ int Curl_read(struct connectdata *conn,
} }
} }
else { else {
#else
(void)conn;
#endif #endif
*n=0; /* reset amount to zero */
#ifdef KRB4 #ifdef KRB4
if(conn->sec_complete) if(conn->sec_complete)
nread = Curl_sec_read(conn, sockfd, buf, buffersize); nread = Curl_sec_read(conn, sockfd, buf, buffersize);
else else
#endif #endif
nread = sread (sockfd, buf, buffersize); nread = sread(sockfd, buf, buffersize);
if(-1 == nread) { if(-1 == nread) {
int err = Curl_ourerrno(); int err = Curl_ourerrno();

View File

@ -223,6 +223,7 @@ static int do_file_type(const char *type)
static static
int cert_stuff(struct connectdata *conn, int cert_stuff(struct connectdata *conn,
SSL_CTX* ctx,
char *cert_file, char *cert_file,
const char *cert_type, const char *cert_type,
char *key_file, char *key_file,
@ -246,11 +247,11 @@ int cert_stuff(struct connectdata *conn,
/* /*
* We set the password in the callback userdata * 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); data->set.key_passwd);
#endif #endif
/* Set passwd callback: */ /* 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); file_type = do_file_type(cert_type);
@ -258,8 +259,8 @@ int cert_stuff(struct connectdata *conn,
switch(file_type) { switch(file_type) {
case SSL_FILETYPE_PEM: case SSL_FILETYPE_PEM:
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */ /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
if(SSL_CTX_use_certificate_chain_file(conn->ssl.ctx, if(SSL_CTX_use_certificate_chain_file(ctx,
cert_file) != 1) { cert_file) != 1) {
failf(data, "unable to set certificate file (wrong password?)"); failf(data, "unable to set certificate file (wrong password?)");
return 0; return 0;
} }
@ -269,9 +270,9 @@ int cert_stuff(struct connectdata *conn,
/* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but /* 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 we use the case above for PEM so this can only be performed with
ASN1 files. */ ASN1 files. */
if(SSL_CTX_use_certificate_file(conn->ssl.ctx, if(SSL_CTX_use_certificate_file(ctx,
cert_file, cert_file,
file_type) != 1) { file_type) != 1) {
failf(data, "unable to set certificate file (wrong password?)"); failf(data, "unable to set certificate file (wrong password?)");
return 0; return 0;
} }
@ -293,9 +294,7 @@ int cert_stuff(struct connectdata *conn,
/* cert & key can only be in PEM case in the same file */ /* cert & key can only be in PEM case in the same file */
key_file=cert_file; key_file=cert_file;
case SSL_FILETYPE_ASN1: case SSL_FILETYPE_ASN1:
if(SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
key_file,
file_type) != 1) {
failf(data, "unable to set private key file: '%s' type %s\n", failf(data, "unable to set private key file: '%s' type %s\n",
key_file, key_type?key_type:"PEM"); key_file, key_type?key_type:"PEM");
return 0; return 0;
@ -322,7 +321,7 @@ int cert_stuff(struct connectdata *conn,
failf(data, "failed to load private key from crypto engine\n"); failf(data, "failed to load private key from crypto engine\n");
return 0; 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"); failf(data, "unable to set private key\n");
EVP_PKEY_free(priv_key); EVP_PKEY_free(priv_key);
return 0; return 0;
@ -344,7 +343,7 @@ int cert_stuff(struct connectdata *conn,
return 0; return 0;
} }
ssl=SSL_new(conn->ssl.ctx); ssl=SSL_new(ctx);
x509=SSL_get_certificate(ssl); x509=SSL_get_certificate(ssl);
/* This version was provided by Evan Jordan and is supposed to not /* 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 /* Now we know that a key and cert have been set against
* the SSL context */ * 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"); failf(data, "Private key does not match the certificate public key");
return(0); return(0);
} }
@ -453,6 +452,13 @@ void Curl_SSL_cleanup(void)
#endif #endif
} }
#ifndef USE_SSLEAY
void Curl_SSL_Close(struct connectdata *conn)
{
(void)conn;
}
#endif
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
/* /*
@ -460,7 +466,8 @@ void Curl_SSL_cleanup(void)
*/ */
void Curl_SSL_Close(struct connectdata *conn) 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 ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its 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); ERR_remove_state(0);
if(conn->ssl.handle) { for(i=0; i<2; i++) {
(void)SSL_shutdown(conn->ssl.handle); struct ssl_connect_data *connssl = &conn->ssl[i];
SSL_set_connect_state(conn->ssl.handle);
SSL_free (conn->ssl.handle); if(connssl->handle) {
conn->ssl.handle = NULL; (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. * 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; SSL_SESSION *ssl_sessionid;
int i; int i;
@ -609,14 +621,14 @@ static int Store_SSL_Session(struct connectdata *conn)
/* ask OpenSSL, say please */ /* ask OpenSSL, say please */
#ifdef HAVE_SSL_GET1_SESSION #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 /* SSL_get1_session() will increment the reference
count and the session will stay in memory until explicitly freed with count and the session will stay in memory until explicitly freed with
SSL_SESSION_free(3), regardless of its state. SSL_SESSION_free(3), regardless of its state.
This function was introduced in openssl 0.9.5a. */ This function was introduced in openssl 0.9.5a. */
#else #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(). /* if SSL_get1_session() is unavailable, use SSL_get_session().
This is an inferior option because the session can be flushed 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 */ /* now init the session struct wisely */
store->sessionid = ssl_sessionid; 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->name = strdup(conn->name); /* clone host name */
store->remote_port = conn->remote_port; /* port number */ 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. 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]; char peer_CN[257];
bool matched = FALSE; /* no alternative match yet */ bool matched = FALSE; /* no alternative match yet */
@ -793,8 +806,7 @@ static CURLcode verifyhost(struct connectdata *conn)
} }
/* get a "list" of alternative names */ /* get a "list" of alternative names */
altnames = X509_get_ext_d2i(conn->ssl.server_cert, NID_subject_alt_name, altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
NULL, NULL);
if(altnames) { if(altnames) {
int hostlen; int hostlen;
@ -856,7 +868,7 @@ static CURLcode verifyhost(struct connectdata *conn)
infof(data, "\t subjectAltName: %s matched\n", conn->hostname); infof(data, "\t subjectAltName: %s matched\n", conn->hostname);
else { else {
bool obtain=FALSE; 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, NID_commonName,
peer_CN, peer_CN,
sizeof(peer_CN)) < 0) { sizeof(peer_CN)) < 0) {
@ -896,7 +908,8 @@ static CURLcode verifyhost(struct connectdata *conn)
/* ====================================================== */ /* ====================================================== */
CURLcode CURLcode
Curl_SSLConnect(struct connectdata *conn) Curl_SSLConnect(struct connectdata *conn,
int sockindex)
{ {
CURLcode retcode = CURLE_OK; CURLcode retcode = CURLE_OK;
@ -908,9 +921,11 @@ Curl_SSLConnect(struct connectdata *conn)
SSL_METHOD *req_method; SSL_METHOD *req_method;
SSL_SESSION *ssl_sessionid=NULL; SSL_SESSION *ssl_sessionid=NULL;
ASN1_TIME *certdate; 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. */ /* 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) { if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
/* Make funny stuff to get random input */ /* Make funny stuff to get random input */
@ -937,9 +952,9 @@ Curl_SSLConnect(struct connectdata *conn)
break; 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!"); failf(data, "SSL: couldn't create a context!");
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
@ -952,10 +967,11 @@ Curl_SSLConnect(struct connectdata *conn)
implementations is desired." 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(data->set.cert) {
if(!cert_stuff(conn, if(!cert_stuff(conn,
connssl->ctx,
data->set.cert, data->set.cert,
data->set.cert_type, data->set.cert_type,
data->set.key, data->set.key,
@ -966,7 +982,7 @@ Curl_SSLConnect(struct connectdata *conn)
} }
if(data->set.ssl.cipher_list) { 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)) { data->set.ssl.cipher_list)) {
failf(data, "failed setting cipher list"); failf(data, "failed setting cipher list");
return CURLE_SSL_CIPHER; return CURLE_SSL_CIPHER;
@ -976,7 +992,7 @@ Curl_SSLConnect(struct connectdata *conn)
if (data->set.ssl.CAfile || data->set.ssl.CApath) { if (data->set.ssl.CAfile || data->set.ssl.CApath) {
/* tell SSL where to find CA certificates that are used to verify /* tell SSL where to find CA certificates that are used to verify
the servers certificate. */ 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)) { data->set.ssl.CApath)) {
if (data->set.ssl.verifypeer) { if (data->set.ssl.verifypeer) {
/* Fail if we insist on successfully verifying the server. */ /* Fail if we insist on successfully verifying the server. */
@ -989,34 +1005,31 @@ Curl_SSLConnect(struct connectdata *conn)
else { else {
/* Just continue with a warning if no strict certificate verification /* Just continue with a warning if no strict certificate verification
is required. */ is required. */
infof(data,"error setting certificate verify locations," infof(data, "error setting certificate verify locations,"
" continuing anyway:\n"); " 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 { else {
/* Everything is fine. */ /* Everything is fine. */
infof(data,"successfully set certificate verify locations:\n"); 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,
" 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 /* 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 * 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 * anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */ * 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, data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
cert_verify_callback); cert_verify_callback);
/* give application a chance to interfere with SSL set up. */ /* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) { 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); data->set.ssl.fsslctxp);
if(retcode) { if(retcode) {
failf(data,"error signaled by ssl ctx callback"); failf(data,"error signaled by ssl ctx callback");
@ -1025,24 +1038,24 @@ Curl_SSLConnect(struct connectdata *conn)
} }
/* Lets make an SSL structure */ /* Lets make an SSL structure */
conn->ssl.handle = SSL_new (conn->ssl.ctx); connssl->handle = SSL_new(connssl->ctx);
SSL_set_connect_state (conn->ssl.handle); SSL_set_connect_state(connssl->handle);
conn->ssl.server_cert = 0x0; connssl->server_cert = 0x0;
if(!conn->bits.reuse) { if(!conn->bits.reuse) {
/* We're not re-using a connection, check if there's a cached ID we /* We're not re-using a connection, check if there's a cached ID we
can/should use here! */ can/should use here! */
if(!Get_SSL_Session(conn, &ssl_sessionid)) { if(!Get_SSL_Session(conn, &ssl_sessionid)) {
/* we got a session id, use it! */ /* we got a session id, use it! */
SSL_set_session(conn->ssl.handle, ssl_sessionid); SSL_set_session(connssl->handle, ssl_sessionid);
/* Informational message */ /* Informational message */
infof (data, "SSL re-using session ID\n"); infof (data, "SSL re-using session ID\n");
} }
} }
/* pass the raw socket into the SSL layers */ /* pass the raw socket into the SSL layers */
SSL_set_fd(conn->ssl.handle, conn->firstsocket); SSL_set_fd(connssl->handle, sockfd);
do { do {
fd_set writefd; fd_set writefd;
@ -1088,18 +1101,18 @@ Curl_SSLConnect(struct connectdata *conn)
FD_ZERO(&writefd); FD_ZERO(&writefd);
FD_ZERO(&readfd); FD_ZERO(&readfd);
err = SSL_connect(conn->ssl.handle); err = SSL_connect(connssl->handle);
/* 1 is fine /* 1 is fine
0 is "not successful but was shut down controlled" 0 is "not successful but was shut down controlled"
<0 is "handshake was not successful, because a fatal error occurred" */ <0 is "handshake was not successful, because a fatal error occurred" */
if(1 != err) { 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) if(SSL_ERROR_WANT_READ == detail)
FD_SET(conn->firstsocket, &readfd); FD_SET(sockfd, &readfd);
else if(SSL_ERROR_WANT_WRITE == detail) else if(SSL_ERROR_WANT_WRITE == detail)
FD_SET(conn->firstsocket, &writefd); FD_SET(sockfd, &writefd);
else { else {
/* untreated error */ /* untreated error */
char error_buffer[120]; /* OpenSSL documents that this must be at least 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; 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) if(what > 0)
/* reabable or writable, go loop yourself */ /* reabable or writable, go loop yourself */
continue; continue;
@ -1158,12 +1171,12 @@ Curl_SSLConnect(struct connectdata *conn)
/* Informational message */ /* Informational message */
infof (data, "SSL connection using %s\n", infof (data, "SSL connection using %s\n",
SSL_get_cipher(conn->ssl.handle)); SSL_get_cipher(connssl->handle));
if(!ssl_sessionid) { if(!ssl_sessionid) {
/* Since this is not a cached session ID, then we want to stach this one /* Since this is not a cached session ID, then we want to stach this one
in the cache! */ in the cache! */
Store_SSL_Session(conn); Store_SSL_Session(conn, connssl);
} }
@ -1173,38 +1186,38 @@ Curl_SSLConnect(struct connectdata *conn)
* attack * attack
*/ */
conn->ssl.server_cert = SSL_get_peer_certificate(conn->ssl.handle); connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
if(!conn->ssl.server_cert) { if(!connssl->server_cert) {
failf(data, "SSL: couldn't get peer certificate!"); failf(data, "SSL: couldn't get peer certificate!");
return CURLE_SSL_PEER_CERTIFICATE; return CURLE_SSL_PEER_CERTIFICATE;
} }
infof (data, "Server certificate:\n"); 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); NULL, 0);
if(!str) { if(!str) {
failf(data, "SSL: couldn't get X509-subject!"); failf(data, "SSL: couldn't get X509-subject!");
X509_free(conn->ssl.server_cert); X509_free(connssl->server_cert);
return CURLE_SSL_CONNECT_ERROR; return CURLE_SSL_CONNECT_ERROR;
} }
infof(data, "\t subject: %s\n", str); infof(data, "\t subject: %s\n", str);
CRYPTO_free(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); 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); Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate);
if(data->set.ssl.verifyhost) { if(data->set.ssl.verifyhost) {
retcode = verifyhost(conn); retcode = verifyhost(conn, connssl->server_cert);
if(retcode) { if(retcode) {
X509_free(conn->ssl.server_cert); X509_free(connssl->server_cert);
return retcode; 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); NULL, 0);
if(!str) { if(!str) {
failf(data, "SSL: couldn't get X509-issuer name!"); 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 /* We could do all sorts of certificate verification stuff here before
deallocating the certificate. */ 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.certverifyresult != X509_V_OK) {
if(data->set.ssl.verifypeer) { if(data->set.ssl.verifypeer) {
/* We probably never reach this, because SSL_connect() will fail /* 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"); infof(data, "SSL certificate verify ok.\n");
} }
X509_free(conn->ssl.server_cert); X509_free(connssl->server_cert);
#else /* USE_SSLEAY */ #else /* USE_SSLEAY */
/* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
(void) conn; (void) conn;

View File

@ -23,7 +23,7 @@
* $Id$ * $Id$
***************************************************************************/ ***************************************************************************/
#include "urldata.h" #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_init(void); /* Global SSL init */
void Curl_SSL_cleanup(void); /* Global SSL cleanup */ void Curl_SSL_cleanup(void); /* Global SSL cleanup */

View File

@ -262,7 +262,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
buf[1] = cmd; buf[1] = cmd;
buf[2] = option; buf[2] = option;
(void)swrite(conn->firstsocket, buf, 3); (void)swrite(conn->sock[FIRSTSOCKET], buf, 3);
printoption(conn->data, "SENT", cmd, option); printoption(conn->data, "SENT", cmd, option);
} }
@ -826,7 +826,7 @@ static void suboption(struct connectdata *conn)
snprintf((char *)temp, sizeof(temp), snprintf((char *)temp, sizeof(temp),
"%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE, "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE); 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); printsub(data, '>', &temp[2], len-2);
break; break;
case CURL_TELOPT_XDISPLOC: case CURL_TELOPT_XDISPLOC:
@ -834,7 +834,7 @@ static void suboption(struct connectdata *conn)
snprintf((char *)temp, sizeof(temp), snprintf((char *)temp, sizeof(temp),
"%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC, "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE); 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); printsub(data, '>', &temp[2], len-2);
break; break;
case CURL_TELOPT_NEW_ENVIRON: case CURL_TELOPT_NEW_ENVIRON:
@ -857,7 +857,7 @@ static void suboption(struct connectdata *conn)
snprintf((char *)&temp[len], sizeof(temp) - len, snprintf((char *)&temp[len], sizeof(temp) - len,
"%c%c", CURL_IAC, CURL_SE); "%c%c", CURL_IAC, CURL_SE);
len += 2; len += 2;
(void)swrite(conn->firstsocket, temp, len); (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
printsub(data, '>', &temp[2], len-2); printsub(data, '>', &temp[2], len-2);
break; break;
} }
@ -1035,7 +1035,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
{ {
CURLcode code; CURLcode code;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
int sockfd = conn->firstsocket; int sockfd = conn->sock[FIRSTSOCKET];
#ifdef WIN32 #ifdef WIN32
WSAEVENT event_handle; WSAEVENT event_handle;
WSANETWORKEVENTS events; WSANETWORKEVENTS events;
@ -1105,7 +1105,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
if(outbuf[0] == CURL_IAC) if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC; outbuf[out_count++] = CURL_IAC;
Curl_write(conn, conn->firstsocket, outbuf, Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written); out_count, &bytes_written);
} }
} }
@ -1176,7 +1176,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
if(outbuf[0] == CURL_IAC) if(outbuf[0] == CURL_IAC)
outbuf[out_count++] = CURL_IAC; outbuf[out_count++] = CURL_IAC;
Curl_write(conn, conn->firstsocket, outbuf, Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
out_count, &bytes_written); out_count, &bytes_written);
} }
} }

View File

@ -1865,14 +1865,7 @@ CURLcode Curl_perform(struct SessionHandle *data)
res = Curl_do(&conn); res = Curl_do(&conn);
if(res == CURLE_OK) { 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 */ 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) if(res == CURLE_OK)
/* /*
* We must duplicate the new URL here as the connection data * 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. */ * possibly know if the connection is in a good shape or not now. */
conn->bits.close = TRUE; 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 /* if we failed anywhere, we must clean up the secondary socket if
it was used */ it was used */
sclose(conn->secondarysocket); sclose(conn->sock[SECONDARYSOCKET]);
conn->secondarysocket=-1; conn->sock[SECONDARYSOCKET]=-1;
} }
} }
@ -1932,12 +1925,13 @@ CURLcode Curl_perform(struct SessionHandle *data)
CURLcode CURLcode
Curl_Transfer(struct connectdata *c_conn, /* connection data */ 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 */ int size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */ bool getheader, /* TRUE if header parsing is wanted */
long *bytecountp, /* return number of bytes read or NULL */ long *bytecountp, /* return number of bytes read or NULL */
int writesockfd, /* socket to write to, it may very well be int writesockindex, /* socket index to write to, it may very
the same we read from. -1 disables */ well be the same we read from. -1
disables */
long *writebytecountp /* return number of bytes written or long *writebytecountp /* return number of bytes written or
NULL */ NULL */
) )
@ -1947,11 +1941,11 @@ Curl_Transfer(struct connectdata *c_conn, /* connection data */
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
/* now copy all input parameters */ /* now copy all input parameters */
conn->sockfd = sockfd; conn->sockfd = sockindex==-1?-1:conn->sock[sockindex];
conn->size = size; conn->size = size;
conn->bits.getheader = getheader; conn->bits.getheader = getheader;
conn->bytecountp = bytecountp; conn->bytecountp = bytecountp;
conn->writesockfd = writesockfd; conn->writesockfd = writesockindex==-1?-1:conn->sock[writesockindex];
conn->writebytecountp = writebytecountp; conn->writebytecountp = writebytecountp;
return CURLE_OK; return CURLE_OK;

View File

@ -1251,6 +1251,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
data->set.max_filesize = va_arg(param, long); data->set.max_filesize = va_arg(param, long);
break; break;
case CURLOPT_FTP_SSL:
/*
* Make FTP transfers attempt to use SSL/TLS.
*/
data->set.ftp_ssl = va_arg(param, long);
break;
default: default:
/* unknown tag and its companion, just ignore: */ /* unknown tag and its companion, just ignore: */
return CURLE_FAILED_INIT; /* correct this */ return CURLE_FAILED_INIT; /* correct this */
@ -1293,16 +1300,13 @@ CURLcode Curl_disconnect(struct connectdata *conn)
Curl_safefree(conn->proto.generic); Curl_safefree(conn->proto.generic);
Curl_safefree(conn->newurl); Curl_safefree(conn->newurl);
Curl_safefree(conn->path); /* the URL path part */ Curl_safefree(conn->path); /* the URL path part */
#ifdef USE_SSLEAY
Curl_SSL_Close(conn); Curl_SSL_Close(conn);
#endif /* USE_SSLEAY */
/* close possibly still open sockets */ /* close possibly still open sockets */
if(-1 != conn->secondarysocket) if(-1 != conn->sock[SECONDARYSOCKET])
sclose(conn->secondarysocket); sclose(conn->sock[SECONDARYSOCKET]);
if(-1 != conn->firstsocket) if(-1 != conn->sock[FIRSTSOCKET])
sclose(conn->firstsocket); sclose(conn->sock[FIRSTSOCKET]);
Curl_safefree(conn->user); Curl_safefree(conn->user);
Curl_safefree(conn->passwd); Curl_safefree(conn->passwd);
@ -1429,7 +1433,7 @@ ConnectionExists(struct SessionHandle *data,
} }
if(match) { if(match) {
bool dead = SocketIsDead(check->firstsocket); bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
if(dead) { if(dead) {
/* /*
*/ */
@ -1549,16 +1553,15 @@ ConnectionStore(struct SessionHandle *data,
* This function logs in to a SOCKS5 proxy and sends the specifies the final * This function logs in to a SOCKS5 proxy and sends the specifies the final
* desitination server. * desitination server.
*/ */
static int handleSock5Proxy( static int handleSock5Proxy(const char *proxy_name,
const char *proxy_name, const char *proxy_password,
const char *proxy_password, struct connectdata *conn)
struct connectdata *conn,
int sock)
{ {
unsigned char socksreq[600]; /* room for large user/pw (255 max each) */ unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
ssize_t actualread; ssize_t actualread;
ssize_t written; ssize_t written;
CURLcode result; CURLcode result;
int sock = conn->sock[FIRSTSOCKET];
Curl_nonblock(sock, FALSE); Curl_nonblock(sock, FALSE);
@ -1754,7 +1757,7 @@ static CURLcode ConnectPlease(struct connectdata *conn,
result= Curl_connecthost(conn, result= Curl_connecthost(conn,
hostaddr, hostaddr,
conn->port, conn->port,
&conn->firstsocket, &conn->sock[FIRSTSOCKET],
&addr, &addr,
connected); connected);
if(CURLE_OK == result) { if(CURLE_OK == result) {
@ -1776,8 +1779,7 @@ static CURLcode ConnectPlease(struct connectdata *conn,
if (conn->data->set.proxytype == CURLPROXY_SOCKS5) { if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
return handleSock5Proxy(conn->proxyuser, return handleSock5Proxy(conn->proxyuser,
conn->proxypasswd, conn->proxypasswd,
conn, conn) ?
conn->firstsocket) ?
CURLE_COULDNT_CONNECT : CURLE_OK; CURLE_COULDNT_CONNECT : CURLE_OK;
} }
else if (conn->data->set.proxytype == CURLPROXY_HTTP) { 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 */ /* and we setup a few fields in case we end up actually using this struct */
conn->data = data; /* remember our daddy */ conn->data = data; /* remember our daddy */
conn->firstsocket = -1; /* no file descriptor */ conn->sock[FIRSTSOCKET] = -1; /* no file descriptor */
conn->secondarysocket = -1; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = -1; /* no file descriptor */
conn->connectindex = -1; /* no index */ conn->connectindex = -1; /* no index */
conn->bits.httpproxy = (data->change.proxy && *data->change.proxy && conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
(data->set.proxytype == CURLPROXY_HTTP))? (data->set.proxytype == CURLPROXY_HTTP))?
@ -2419,6 +2421,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(strequal(conn->protostr, "FTPS")) { if(strequal(conn->protostr, "FTPS")) {
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
conn->protocol |= PROT_FTPS|PROT_SSL; conn->protocol |= PROT_FTPS|PROT_SSL;
conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */
#else #else
failf(data, LIBCURL_NAME failf(data, LIBCURL_NAME
" was built with SSL disabled, ftps: not supported!"); " was built with SSL disabled, ftps: not supported!");
@ -3100,7 +3103,7 @@ static CURLcode SetupConnection(struct connectdata *conn,
conn->bytecount = 0; conn->bytecount = 0;
conn->headerbytecount = 0; conn->headerbytecount = 0;
if(-1 == conn->firstsocket) { if(-1 == conn->sock[FIRSTSOCKET]) {
bool connected; bool connected;
/* Connect only if not already connected! */ /* Connect only if not already connected! */

View File

@ -130,9 +130,9 @@ enum protection_level {
}; };
#endif #endif
/* struct for data related to SSL and SSL connections */ /* struct for data related to each SSL connection */
struct ssl_connect_data { struct ssl_connect_data {
bool use; /* use ssl encrypted communications TRUE/FALSE */ bool use; /* use ssl encrypted communications TRUE/FALSE */
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
/* these ones requires specific SSL-types */ /* these ones requires specific SSL-types */
SSL_CTX* ctx; SSL_CTX* ctx;
@ -385,6 +385,9 @@ struct Curl_async {
}; };
#endif #endif
#define FIRSTSOCKET 0
#define SECONDARYSOCKET 1
/* /*
* The connectdata struct contains all fields and variables that should be * The connectdata struct contains all fields and variables that should be
* unique for an entire connection. * unique for an entire connection.
@ -442,12 +445,12 @@ struct connectdata {
struct timeval now; /* "current" time */ struct timeval now; /* "current" time */
struct timeval created; /* creation time */ struct timeval created; /* creation time */
int firstsocket; /* the main socket to use */ int sock[2]; /* two sockets, the second is used for the data transfer
int secondarysocket; /* for i.e ftp transfers */ when doing FTP */
long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 long maxdownload; /* in bytes, the maximum amount of data to fetch, 0
means unlimited */ 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 ssl_config_data ssl_config;
struct ConnectBits bits; /* various state-flags for this connection */ struct ConnectBits bits; /* various state-flags for this connection */
@ -486,8 +489,8 @@ struct connectdata {
long *bytecountp; /* return number of bytes read or NULL */ long *bytecountp; /* return number of bytes read or NULL */
/* WRITE stuff */ /* WRITE stuff */
int writesockfd; /* socket to write to, it may very well be int writesockfd; /* socket to write to, it may very
the same we read from. -1 disables */ well be the same we read from. -1 disables */
long *writebytecountp; /* return number of bytes written or NULL */ long *writebytecountp; /* return number of bytes written or NULL */
/** Dynamicly allocated strings, may need to be freed before this **/ /** 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 expect100header; /* TRUE if we added Expect: 100-continue */
bool ftp_use_epsv; /* if EPSV is to be attempted or not */ 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_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 no_signal; /* do not use any signal/alarm handler */
bool global_dns_cache; bool global_dns_cache;