/* 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
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 <stdio.h>
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;
nth = atoi(nthdef);
}
- result = Curl_sendf(conn->firstsocket, conn,
+ result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"MATCH "
"%s " /* database */
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;
nth = atoi(nthdef);
}
- result = Curl_sendf(conn->firstsocket, conn,
+ result = Curl_sendf(sockfd, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"DEFINE "
"%s " /* database */
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)
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;
* 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);
}
infof(data, "Connection accepted from server\n");
- conn->secondarysocket = s;
+ conn->sock[SECONDARYSOCKET] = s;
Curl_nonblock(s, TRUE); /* enable non-blocking */
}
break;
* 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;
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;
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;
}
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:"");
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,
* 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,
/* 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
/******************************************************************
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;
}
result = Curl_connecthost(conn,
addr,
connectport,
- &conn->secondarysocket,
+ &conn->sock[SECONDARYSOCKET],
&conninfo,
connected);
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;
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;
}
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;
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)
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)
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)
*/
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 */
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 */
*/
CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
- int tunnelsocket,
+ int sockindex,
char *hostname,
int remote_port)
{
fd_set readfd;
char *line_start;
char *host_port;
+ int tunnelsocket = conn->sock[sockindex];
#define SELECT_OK 0
#define SELECT_ERROR 1
((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;
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;
}
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 */
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;
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;
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)
int sockfd;
if(CURLM_STATE_WAITCONNECT == easy->state) {
- sockfd = conn->firstsocket;
+ sockfd = conn->sock[FIRSTSOCKET];
FD_SET(sockfd, write_fd_set);
}
else {
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);
}
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);
* 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) {
/*
* 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);
* 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:
bytes_written = rc;
}
else {
+#else
+ (void)conn;
#endif
#ifdef KRB4
if(conn->sec_complete) {
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 */
}
}
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();
static
int cert_stuff(struct connectdata *conn,
+ SSL_CTX* ctx,
char *cert_file,
const char *cert_type,
char *key_file,
/*
* 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);
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;
}
/* 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;
}
/* 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;
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;
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
/* 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);
}
#endif
}
+#ifndef USE_SSLEAY
+void Curl_SSL_Close(struct connectdata *conn)
+{
+ (void)conn;
+}
+#endif
+
#ifdef USE_SSLEAY
/*
*/
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
*/
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;
- }
- if(conn->ssl.ctx) {
- SSL_CTX_free (conn->ssl.ctx);
- conn->ssl.ctx = 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 */
}
- conn->ssl.use = FALSE; /* get back to ordinary socket usage */
}
}
/*
* 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;
/* 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
/* 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 */
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 */
}
/* 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;
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) {
/* ====================================================== */
CURLcode
-Curl_SSLConnect(struct connectdata *conn)
+Curl_SSLConnect(struct connectdata *conn,
+ int sockindex)
{
CURLcode retcode = CURLE_OK;
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 */
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;
}
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,
}
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;
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. */
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");
}
/* 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;
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
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;
/* 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);
}
* 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!");
/* 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
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;
* $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 */
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);
}
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:
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:
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;
}
{
CURLcode code;
struct SessionHandle *data = conn->data;
- int sockfd = conn->firstsocket;
+ int sockfd = conn->sock[FIRSTSOCKET];
#ifdef WIN32
WSAEVENT event_handle;
WSANETWORKEVENTS events;
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);
}
}
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);
}
}
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
* 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;
}
}
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 */
)
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;
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 */
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);
}
if(match) {
- bool dead = SocketIsDead(check->firstsocket);
+ bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
if(dead) {
/*
*/
* 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);
result= Curl_connecthost(conn,
hostaddr,
conn->port,
- &conn->firstsocket,
+ &conn->sock[FIRSTSOCKET],
&addr,
connected);
if(CURLE_OK == result) {
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) {
/* 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))?
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!");
conn->bytecount = 0;
conn->headerbytecount = 0;
- if(-1 == conn->firstsocket) {
+ if(-1 == conn->sock[FIRSTSOCKET]) {
bool connected;
/* Connect only if not already connected! */
};
#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;
};
#endif
+#define FIRSTSOCKET 0
+#define SECONDARYSOCKET 1
+
/*
* The connectdata struct contains all fields and variables that should be
* unique for an entire connection.
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 */
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 **/
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;