diff --git a/CHANGES b/CHANGES index a245e7d09..ef30dc1e6 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,18 @@ Changelog Daniel S (1 August 2007) +- Patrick Monnerat and I modified libcurl so that now it *copies* all strings + passed to it with curl_easy_setopt()! Previously it has always just refered + to the data, forcing the user to keep the data around until libcurl is done + with it. That is now history and libcurl will instead clone the given + strings and keep private copies. This is also part of Patrick Monnerat's + OS/400 port. + + Due to this being a somewhat interesting change API wise, I've decided to + bump the version of the upcoming release to 7.17.0. Older applications will + of course not notice this change nor do they have to care, but new + applications can be written to take advantage of this. + - Greg Morse reported a problem with POSTing using ANYAUTH to a server requiring NTLM, and he provided test code and a test server and we worked out a bug fix. We failed to count sent body data at times, which then caused diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 5e64b764c..0377adb93 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -12,6 +12,7 @@ Curl and libcurl 7.16.5 This release includes the following changes: o support for OS/400 Secure Sockets Layer library + o curl_easy_setopt() now allocates strings passed to it This release includes the following bugfixes: diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3 index fe13f07c9..95455e3a1 100644 --- a/docs/libcurl/curl_easy_getinfo.3 +++ b/docs/libcurl/curl_easy_getinfo.3 @@ -133,7 +133,9 @@ protocol used doesn't support this. .IP CURLINFO_PRIVATE Pass a pointer to a 'char *' to receive the pointer to the private data associated with the curl handle (set with the CURLOPT_PRIVATE option to -\fIcurl_easy_setopt(3)\fP). (Added in 7.10.3) +\fIcurl_easy_setopt(3)\fP). Please note that for internal reasons, the +value is returned as a 'char *', although effectively being a 'void *'. +(Added in 7.10.3) .IP CURLINFO_HTTPAUTH_AVAIL Pass a pointer to a long to receive a bitmask indicating the authentication method(s) available. The meaning of the bits is explained in the diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 63b53f7c4..016bb9181 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -21,7 +21,7 @@ .\" * $Id$ .\" ************************************************************************** .\" -.TH curl_easy_setopt 3 "22 Feb 2007" "libcurl 7.16.2" "libcurl Manual" +.TH curl_easy_setopt 3 "1 Aug 2007" "libcurl 7.17.0" "libcurl Manual" .SH NAME curl_easy_setopt \- set options for a curl easy handle .SH SYNOPSIS @@ -44,11 +44,13 @@ between transfers, so if you want subsequent transfers with different options, you must change them between the transfers. You can optionally reset all options back to internal default with \fIcurl_easy_reset(3)\fP. -Strings passed to libcurl as 'char *' arguments, will not be copied by the -library. Instead you should keep them available until libcurl no longer needs -them. Failing to do so will cause very odd behavior or even crashes. libcurl -will need them until you call \fIcurl_easy_cleanup(3)\fP or you set the same -option again to use a different pointer. +Strings passed to libcurl as 'char *' arguments, are copied by the library; +thus the string storage associated to the pointer argument may be overwritten +after curl_easy_setopt() returns. Exceptions to this rule are described in +the option details below. + +NOTE: before 7.17.0 strings were not copied. Instead the user was forced keep +them available until libcurl no longer needed them. The \fIhandle\fP is the return code from a \fIcurl_easy_init(3)\fP or \fIcurl_easy_duphandle(3)\fP call. @@ -330,6 +332,12 @@ system. Pass a char * to a buffer that the libcurl may store human readable error messages in. This may be more helpful than just the return code from \fIcurl_easy_perform\fP. The buffer must be at least CURL_ERROR_SIZE big. +Although this argument is a 'char *', it does not describe an input string. +Therefore the (probably undefined) contents of the buffer is NOT copied +by the library. You should keep the associated storage available until +libcurl no longer needs it. Failing to do so will cause very odd behavior +or even crashes. libcurl will need it until you call \fIcurl_easy_cleanup(3)\fP +or you set the same option again to use a different pointer. Use \fICURLOPT_VERBOSE\fP and \fICURLOPT_DEBUGFUNCTION\fP to better debug/trace why errors happen. @@ -1397,7 +1405,7 @@ If the file is password-protected, set the password with \fICURLOPT_SSLKEYPASSWD (Added in 7.16.1) .SH OTHER OPTIONS .IP CURLOPT_PRIVATE -Pass a char * as parameter, pointing to data that should be associated with +Pass a void * as parameter, pointing to data that should be associated with this curl handle. The pointer can subsequently be retrieved using \fIcurl_easy_getinfo(3)\fP with the CURLINFO_PRIVATE option. libcurl itself does nothing with this data. (Added in 7.10.3) diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 11b34dcaf..4657398bc 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -28,13 +28,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.16.5-CVS" +#define LIBCURL_VERSION "7.17.0-CVS" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 16 -#define LIBCURL_VERSION_PATCH 5 +#define LIBCURL_VERSION_MINOR 17 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -51,7 +51,7 @@ and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ -#define LIBCURL_VERSION_NUM 0x071005 +#define LIBCURL_VERSION_NUM 0x071100 /* * This is the date and time when the full source package was created. The diff --git a/lib/connect.c b/lib/connect.c index d608e1e2e..634595766 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -228,11 +228,12 @@ static CURLcode bindlocal(struct connectdata *conn, "random" */ /* how many port numbers to try to bind to, increasing one at a time */ int portnum = data->set.localportrange; + const char *dev = data->set.str[STRING_DEVICE]; /************************************************************* * Select device to bind socket to *************************************************************/ - if (data->set.device && (strlen(data->set.device)<255) ) { + if (dev && (strlen(dev)<255) ) { struct Curl_dns_entry *h=NULL; char myhost[256] = ""; in_addr_t in; @@ -241,10 +242,10 @@ static CURLcode bindlocal(struct connectdata *conn, int in6 = -1; /* First check if the given name is an IP address */ - in=inet_addr(data->set.device); + in=inet_addr(dev); if((in == CURL_INADDR_NONE) && - Curl_if2ip(data->set.device, myhost, sizeof(myhost))) { + Curl_if2ip(dev, myhost, sizeof(myhost))) { /* * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer */ @@ -263,7 +264,7 @@ static CURLcode bindlocal(struct connectdata *conn, * This was not an interface, resolve the name as a host name * or IP number */ - rc = Curl_resolv(conn, data->set.device, 0, &h); + rc = Curl_resolv(conn, dev, 0, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_wait_for_resolv(conn, &h); @@ -275,7 +276,7 @@ static CURLcode bindlocal(struct connectdata *conn, myhost, sizeof myhost); else /* we know data->set.device is shorter than the myhost array */ - strcpy(myhost, data->set.device); + strcpy(myhost, dev); Curl_resolv_unlock(data, h); } } @@ -287,7 +288,7 @@ static CURLcode bindlocal(struct connectdata *conn, hostent_buf, sizeof(hostent_buf)); */ - failf(data, "Couldn't bind to '%s'", data->set.device); + failf(data, "Couldn't bind to '%s'", dev); return CURLE_INTERFACE_FAILED; } @@ -307,11 +308,10 @@ static CURLcode bindlocal(struct connectdata *conn, * hostname or ip address. */ if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - data->set.device, strlen(data->set.device)+1) != 0) { + dev, strlen(dev)+1) != 0) { /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n", - sockfd, data->set.device, Curl_strerror(SOCKERRNO)); */ - infof(data, "SO_BINDTODEVICE %s failed\n", - data->set.device); + sockfd, dev, Curl_strerror(SOCKERRNO)); */ + infof(data, "SO_BINDTODEVICE %s failed\n", dev); /* This is typically "errno 1, error: Operation not permitted" if you're not running as root or another suitable privileged user */ } diff --git a/lib/easy.c b/lib/easy.c index b1080a22d..54915fb88 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -579,7 +579,8 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->state.headersize=HEADERSIZE; /* copy all userdefined values */ - outcurl->set = data->set; + if (Curl_dupset(outcurl, data) != CURLE_OK) + break; if(data->state.used_interface == Curl_if_multi) outcurl->state.connc = data->state.connc; @@ -658,6 +659,7 @@ CURL *curl_easy_duphandle(CURL *incurl) free(outcurl->change.url); if(outcurl->change.referer) free(outcurl->change.referer); + Curl_freeset(outcurl); free(outcurl); /* free the memory again */ outcurl = NULL; } @@ -681,6 +683,7 @@ void curl_easy_reset(CURL *curl) data->reqdata.proto.generic=NULL; /* zero out UserDefined data: */ + Curl_freeset(data); memset(&data->set, 0, sizeof(struct UserDefined)); /* zero out Progress data: */ @@ -732,7 +735,7 @@ void curl_easy_reset(CURL *curl) data->set.ssl.verifyhost = 2; #ifdef CURL_CA_BUNDLE /* This is our prefered CA cert bundle since install time */ - data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; + (void) curl_easy_setopt(curl, CURLOPT_CAINFO, (char *) CURL_CA_BUNDLE); #endif data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth diff --git a/lib/ftp.c b/lib/ftp.c index 4df17decb..6958eb7f2 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -871,11 +871,12 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* Step 1, figure out what address that is requested */ - if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) { + if(data->set.str[STRING_FTPPORT] && + (strlen(data->set.str[STRING_FTPPORT]) > 1)) { /* attempt to get the address of the given interface name */ - if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf))) + if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf))) /* not an interface, use the given string as host name instead */ - host = data->set.ftpport; + host = data->set.str[STRING_FTPPORT]; else host = hbuf; /* use the hbuf for host name */ } /* data->set.ftpport */ @@ -1080,27 +1081,28 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, unsigned short ip[4]; bool freeaddr = TRUE; socklen_t sslen = sizeof(sa); + const char *ftpport = data->set.str[STRING_FTPPORT]; (void)fcmd; /* not used in the IPv4 code */ - if(data->set.ftpport) { + if(ftpport) { in_addr_t in; /* First check if the given name is an IP address */ - in=inet_addr(data->set.ftpport); + in=inet_addr(ftpport); if(in != CURL_INADDR_NONE) /* this is an IPv4 address */ - addr = Curl_ip2addr(in, data->set.ftpport, 0); + addr = Curl_ip2addr(in, ftpport, 0); else { - if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) { + if(Curl_if2ip(ftpport, myhost, sizeof(myhost))) { /* The interface to IP conversion provided a dotted address */ in=inet_addr(myhost); addr = Curl_ip2addr(in, myhost, 0); } - else if(strlen(data->set.ftpport)> 1) { + else if(strlen(ftpport)> 1) { /* might be a host name! */ struct Curl_dns_entry *h=NULL; - int rc = Curl_resolv(conn, data->set.ftpport, 0, &h); + int rc = Curl_resolv(conn, ftpport, 0, &h); if(rc == CURLRESOLV_PENDING) /* BLOCKING */ rc = Curl_wait_for_resolv(conn, &h); @@ -1114,11 +1116,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, since it points to a DNS cache entry! */ } /* (h) */ else { - infof(data, "Failed to resolve host name %s\n", data->set.ftpport); + infof(data, "Failed to resolve host name %s\n", ftpport); } } /* strlen */ } /* CURL_INADDR_NONE */ - } /* data->set.ftpport */ + } /* ftpport */ if(!addr) { /* pick a suitable default here */ @@ -1346,7 +1348,8 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) servers either... */ NBFTPSENDF(conn, "%s", - data->set.customrequest?data->set.customrequest: + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: (data->set.ftp_list_only?"NLST":"LIST")); state(conn, FTP_LIST); @@ -1720,7 +1723,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, return CURLE_FTP_WEIRD_PASV_REPLY; } - if(data->set.proxy && *data->set.proxy) { + if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) { /* * This is a tunnel through a http proxy and we need to connect to the * proxy again here. @@ -2384,8 +2387,8 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, result = ftp_state_loggedin(conn); } else if(ftpcode == 332) { - if(data->set.ftp_account) { - NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account); + if(data->set.str[STRING_FTP_ACCOUNT]) { + NBFTPSENDF(conn, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); state(conn, FTP_ACCT); } else { @@ -2399,10 +2402,11 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, 530 User ... access denied (the server denies to log the specified user) */ - if (conn->data->set.ftp_alternative_to_user && + if (conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && !conn->data->state.ftp_trying_alternative) { /* Ok, USER failed. Let's try the supplied command. */ - NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user); + NBFTPSENDF(conn, "%s", + conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); conn->data->state.ftp_trying_alternative = TRUE; state(conn, FTP_USER); result = CURLE_OK; @@ -2488,7 +2492,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) Curl_sec_request_prot(conn, "private"); /* We set private first as default, in case the line below fails to set a valid level */ - Curl_sec_request_prot(conn, data->set.krb_level); + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); if(Curl_sec_login(conn) != 0) infof(data, "Logging in with password in cleartext!\n"); diff --git a/lib/getinfo.c b/lib/getinfo.c index c94ca2cb9..2ec0242a6 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -176,7 +176,7 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) *param_charp = data->info.contenttype; break; case CURLINFO_PRIVATE: - *param_charp = data->set.private_data; + *param_charp = (char *) data->set.private_data; break; case CURLINFO_HTTPAUTH_AVAIL: *param_longp = data->info.httpauthavail; diff --git a/lib/gtls.c b/lib/gtls.c index 03572d88e..a40ea096b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -299,11 +299,13 @@ Curl_gtls_connect(struct connectdata *conn, if(rc < 0) return CURLE_SSL_CONNECT_ERROR; - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if( gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, data->set.cert, - data->set.key != 0 ? data->set.key : data->set.cert, - do_file_type(data->set.cert_type) ) ) { + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]) ) ) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } diff --git a/lib/gtls.h b/lib/gtls.h index bff3f8693..feb02fd64 100644 --- a/lib/gtls.h +++ b/lib/gtls.h @@ -29,7 +29,9 @@ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); /* tell GnuTLS to close down all open information regarding connections (and thus session ID caching etc) */ void Curl_gtls_close_all(struct SessionHandle *data); -void Curl_gtls_close(struct connectdata *conn); /* close a SSL connection */ + + /* close a SSL connection */ +void Curl_gtls_close(struct connectdata *conn, int index); /* return number of sent (non-SSL) bytes */ ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex, diff --git a/lib/http.c b/lib/http.c index 19e7483df..61511b57a 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1187,7 +1187,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(!checkheaders(data, "Proxy-Connection:")) proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - if(!checkheaders(data, "User-Agent:") && data->set.useragent) + if(!checkheaders(data, "User-Agent:") && + data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; /* Send the connect request to the proxy */ @@ -1770,8 +1771,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } /* Now set the 'request' pointer to the proper request string */ - if(data->set.customrequest) - request = data->set.customrequest; + if(data->set.str[STRING_CUSTOMREQUEST]) + request = data->set.str[STRING_CUSTOMREQUEST]; else { if(conn->bits.no_body) request = (char *)"HEAD"; @@ -1826,14 +1827,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else conn->allocptr.ref = NULL; - if(data->set.cookie && !checkheaders(data, "Cookie:")) - addcookies = data->set.cookie; + if(data->set.str[STRING_COOKIE] && !checkheaders(data, "Cookie:")) + addcookies = data->set.str[STRING_COOKIE]; if(!checkheaders(data, "Accept-Encoding:") && - data->set.encoding) { + data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.encoding); + aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); if(!conn->allocptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } @@ -2107,19 +2108,23 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.userpwd?conn->allocptr.userpwd:"", (data->reqdata.use_range && conn->allocptr.rangeline)? conn->allocptr.rangeline:"", - (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)? + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? conn->allocptr.uagent:"", (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ http->p_pragma?http->p_pragma:"", http->p_accept?http->p_accept:"", - (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !checkheaders(data, "Proxy-Connection:"))? + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)? + conn->allocptr.ref:"" /* Referer: */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !checkheaders(data, "Proxy-Connection:"))? "Proxy-Connection: Keep-Alive\r\n":"", - te + te ); if(result) @@ -2384,7 +2389,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* figure out the size of the postfields */ postsize = (data->set.postfieldsize != -1)? data->set.postfieldsize: - (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0); + (data->set.str[STRING_POSTFIELDS]? + (curl_off_t)strlen(data->set.str[STRING_POSTFIELDS]):0); if(!conn->bits.upload_chunky) { /* We only set Content-Length and allow a custom Content-Length if @@ -2409,7 +2415,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - if(data->set.postfields) { + if(data->set.str[STRING_POSTFIELDS]) { /* for really small posts we don't use Expect: headers at all, and for the somewhat bigger ones we allow the app to disable it */ @@ -2437,7 +2443,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!conn->bits.upload_chunky) { /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ - result = add_buffer(req_buffer, data->set.postfields, + result = add_buffer(req_buffer, data->set.str[STRING_POSTFIELDS], (size_t)postsize); included_body = postsize; } @@ -2445,7 +2451,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Append the POST data chunky-style */ result = add_bufferf(req_buffer, "%x\r\n", (int)postsize); if(CURLE_OK == result) - result = add_buffer(req_buffer, data->set.postfields, + result = add_buffer(req_buffer, data->set.str[STRING_POSTFIELDS], (size_t)postsize); if(CURLE_OK == result) result = add_buffer(req_buffer, @@ -2459,7 +2465,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else { /* A huge POST coming up, do data separate from the request */ http->postsize = postsize; - http->postdata = data->set.postfields; + http->postdata = data->set.str[STRING_POSTFIELDS]; http->sending = HTTPSEND_BODY; diff --git a/lib/nss.c b/lib/nss.c index c99258969..e90156e15 100644 --- a/lib/nss.c +++ b/lib/nss.c @@ -225,8 +225,8 @@ static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) pphrase_arg_t *parg = (pphrase_arg_t *) arg; (void)slot; /* unused */ (void)retry; /* unused */ - if(parg->data->set.key_passwd) - return (char *)PORT_Strdup((char *)parg->data->set.key_passwd); + if(parg->data->set.str[STRING_KEY_PASSWD]) + return (char *)PORT_Strdup((char *)parg->data->set.str[STRING_KEY_PASSWD]); else return NULL; } @@ -488,10 +488,11 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex) NULL) != SECSuccess) goto error; - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if(SSL_GetClientAuthDataHook(model, (SSLGetClientAuthData) SelectClientCert, - (void *)data->set.cert) != SECSuccess) { + (void *)data->set.str[STRING_CERT]) != + SECSuccess) { curlerr = CURLE_SSL_CERTPROBLEM; goto error; } diff --git a/lib/nssg.h b/lib/nssg.h index 3774c0fb3..c8582d389 100644 --- a/lib/nssg.h +++ b/lib/nssg.h @@ -32,7 +32,9 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex); CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -void Curl_nss_close(struct connectdata *conn); /* close a SSL connection */ +/* close a SSL connection */ +void Curl_nss_close(struct connectdata *conn, int index); + /* tell NSS to close down all open information regarding connections (and thus session ID caching etc) */ int Curl_nss_close_all(struct SessionHandle *data); diff --git a/lib/ssh.c b/lib/ssh.c index 58d7c6963..7a0da7475 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -422,8 +422,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) HOME environment variable etc? */ home = curl_getenv("HOME"); - if (data->set.ssh_public_key) - sshc->rsa_pub = aprintf("%s", data->set.ssh_public_key); + if (data->set.str[STRING_SSH_PUBLIC_KEY]) + sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]); else if (home) sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home); @@ -435,8 +435,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) break; } - if (data->set.ssh_private_key) - sshc->rsa = aprintf("%s", data->set.ssh_private_key); + if (data->set.str[STRING_SSH_PRIVATE_KEY]) + sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]); else if (home) sshc->rsa = aprintf("%s/.ssh/id_dsa", home); @@ -450,7 +450,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) break; } - sshc->passphrase = data->set.key_passwd; + sshc->passphrase = data->set.str[STRING_KEY_PASSWD]; if (!sshc->passphrase) sshc->passphrase = ""; diff --git a/lib/sslgen.c b/lib/sslgen.c index 7410a00de..90af86053 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -135,20 +135,11 @@ Curl_clone_ssl_config(struct ssl_config_data *source, void Curl_free_ssl_config(struct ssl_config_data* sslc) { - if(sslc->CAfile) - free(sslc->CAfile); - - if(sslc->CApath) - free(sslc->CApath); - - if(sslc->cipher_list) - free(sslc->cipher_list); - - if(sslc->egdsocket) - free(sslc->egdsocket); - - if(sslc->random_file) - free(sslc->random_file); + Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->random_file); } /** diff --git a/lib/ssluse.c b/lib/ssluse.c index b5fc08d18..f10002eca 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -182,8 +182,9 @@ static int ossl_seed(struct SessionHandle *data) #endif { /* let the option override the define */ - nread += RAND_load_file((data->set.ssl.random_file? - data->set.ssl.random_file:RANDOM_FILE), + nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? + data->set.str[STRING_SSL_RANDOM_FILE]: + RANDOM_FILE), RAND_LOAD_LENGTH); if(seed_enough(nread)) return nread; @@ -195,14 +196,14 @@ static int ossl_seed(struct SessionHandle *data) #ifndef EGD_SOCKET /* If we don't have the define set, we only do this if the egd-option is set */ - if(data->set.ssl.egdsocket) + if(data->set.str[STRING_SSL_EGDSOCKET]) #define EGD_SOCKET "" /* doesn't matter won't be used */ #endif { /* If there's an option and a define, the option overrides the define */ - int ret = RAND_egd(data->set.ssl.egdsocket? - data->set.ssl.egdsocket:EGD_SOCKET); + int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? + data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); if(-1 != ret) { nread += ret; if(seed_enough(nread)) @@ -261,7 +262,8 @@ int Curl_ossl_seed(struct SessionHandle *data) time-consuming seedings in vain */ static bool ssl_seeded = FALSE; - if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { + if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || + data->set.str[STRING_SSL_EGDSOCKET]) { ossl_seed(data); ssl_seeded = TRUE; } @@ -306,7 +308,7 @@ int cert_stuff(struct connectdata *conn, X509 *x509; int cert_done = 0; - if(data->set.key_passwd) { + if(data->set.str[STRING_KEY_PASSWD]) { #ifndef HAVE_USERDATA_IN_PWD_CALLBACK /* * If password has been given, we store that in the global @@ -320,7 +322,7 @@ int cert_stuff(struct connectdata *conn, * We set the password in the callback userdata */ SSL_CTX_set_default_passwd_cb_userdata(ctx, - data->set.key_passwd); + data->set.str[STRING_KEY_PASSWD]); #endif /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); @@ -373,7 +375,8 @@ int cert_stuff(struct connectdata *conn, PKCS12_PBE_add(); - if (!PKCS12_parse(p12, data->set.key_passwd, &pri, &x509, NULL)) { + if (!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, + NULL)) { failf(data, "could not parse PKCS12 file, check password, OpenSSL error %s", ERR_error_string(ERR_get_error(), NULL) ); @@ -446,7 +449,7 @@ int cert_stuff(struct connectdata *conn, #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS ui_method, #endif - data->set.key_passwd); + data->set.str[STRING_KEY_PASSWD]); if(!priv_key) { failf(data, "failed to load private key from crypto engine\n"); return 0; @@ -1340,37 +1343,40 @@ Curl_ossl_connect_step1(struct connectdata *conn, SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL); #endif - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if(!cert_stuff(conn, connssl->ctx, - data->set.cert, - data->set.cert_type, - data->set.key, - data->set.key_type)) { + data->set.str[STRING_CERT], + data->set.str[STRING_CERT_TYPE], + data->set.str[STRING_KEY], + data->set.str[STRING_KEY_TYPE])) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } } - if(data->set.ssl.cipher_list) { + if(data->set.str[STRING_SSL_CIPHER_LIST]) { if(!SSL_CTX_set_cipher_list(connssl->ctx, - data->set.ssl.cipher_list)) { + data->set.str[STRING_SSL_CIPHER_LIST])) { failf(data, "failed setting cipher list"); return CURLE_SSL_CIPHER; } } - if (data->set.ssl.CAfile || data->set.ssl.CApath) { + if (data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ - if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile, - data->set.ssl.CApath)) { + if (!SSL_CTX_load_verify_locations(connssl->ctx, + data->set.str[STRING_SSL_CAFILE], + data->set.str[STRING_SSL_CAPATH])) { if (data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data,"error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); + data->set.str[STRING_SSL_CAFILE]? + data->set.str[STRING_SSL_CAFILE]: "none", + data->set.str[STRING_SSL_CAPATH]? + data->set.str[STRING_SSL_CAPATH] : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -1387,8 +1393,10 @@ Curl_ossl_connect_step1(struct connectdata *conn, 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"); + data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: + "none", + data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_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 diff --git a/lib/transfer.c b/lib/transfer.c index 8cf10f20e..efa8cdd02 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -233,7 +233,7 @@ CURLcode Curl_readrewind(struct connectdata *conn) /* We have sent away data. If not using CURLOPT_POSTFIELDS or CURLOPT_HTTPPOST, call app to rewind */ - if(data->set.postfields || + if(data->set.str[STRING_POSTFIELDS] || (data->set.httpreq == HTTPREQ_POST_FORM)) ; /* do nothing */ else { @@ -992,7 +992,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, } else if (checkprefix("Content-Encoding:", k->p) && - data->set.encoding) { + data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, * gzip, deflate, compress, x-gzip and x-compress. x-gzip and diff --git a/lib/url.c b/lib/url.c index 7a8effb1e..0de87a824 100644 --- a/lib/url.c +++ b/lib/url.c @@ -217,6 +217,59 @@ static void close_connections(struct SessionHandle *data) ; /* empty loop */ } +void Curl_freeset(struct SessionHandle * data) +{ + /* Free all dynamic strings stored in the data->set substructure. */ + enum dupstring i; + for(i=0; i < STRING_LAST; i++) + Curl_safefree(data->set.str[i]); +} + +static CURLcode Curl_setstropt(char **charp, char * s) +{ + /* Release the previous storage at `charp' and replace by a dynamic storage + copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */ + + if (*charp) { + free(*charp); + *charp = (char *) NULL; + } + + if (s) { + s = strdup(s); + + if (!s) + return CURLE_OUT_OF_MEMORY; + + *charp = s; + } + + return CURLE_OK; +} + +CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src) +{ + CURLcode r; + enum dupstring i; + + /* Copy src->set into dst->set first, then deal with the strings + afterwards */ + dst->set = src->set; + + /* clear all string pointers first */ + memset(dst->set.str, 0, STRING_LAST * sizeof(char *)); + + /* duplicate all strings */ + for(i=0; i< STRING_LAST; i++) { + r = Curl_setstropt(&dst->set.str[i], src->set.str[i]); + if (r != CURLE_OK) + break; + } + + /* If a failure occurred, freeing has to be performed externally. */ + return r; +} + /* * This is the internal function curl_easy_cleanup() calls. This should * cleanup and free all resources associated with this sessionhandle. @@ -329,7 +382,7 @@ CURLcode Curl_close(struct SessionHandle *data) #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - if(data->set.cookiejar) { + if(data->set.str[STRING_COOKIEJAR]) { if(data->change.cookielist) { /* If there is a list of cookie files to read, do it first so that we have all the told files read before we write the new jar */ @@ -337,9 +390,9 @@ CURLcode Curl_close(struct SessionHandle *data) } /* we have a "destination" for all the cookies to get dumped to */ - if(Curl_cookie_output(data->cookies, data->set.cookiejar)) + if(Curl_cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR])) infof(data, "WARNING: failed to save cookies in %s\n", - data->set.cookiejar); + data->set.str[STRING_COOKIEJAR]); } else { if(data->change.cookielist) @@ -381,6 +434,7 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } + Curl_freeset(data); free(data); return CURLE_OK; } @@ -609,7 +663,8 @@ CURLcode Curl_open(struct SessionHandle **curl) data->set.ssl.sessionid = TRUE; /* session ID caching enabled by default */ #ifdef CURL_CA_BUNDLE /* This is our preferred CA cert bundle since install time */ - data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; + res = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], + (char *) CURL_CA_BUNDLE); #endif } @@ -617,6 +672,7 @@ CURLcode Curl_open(struct SessionHandle **curl) ares_destroy(data->state.areschannel); if(data->state.headerbuff) free(data->state.headerbuff); + Curl_freeset(data); free(data); data = NULL; } @@ -648,7 +704,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ - data->set.ssl.cipher_list = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], + va_arg(param, char *)); break; case CURLOPT_RANDOM_FILE: @@ -656,13 +713,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * This is the path name to a file that contains random data to seed * the random SSL stuff with. The file is only used for reading. */ - data->set.ssl.random_file = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSL_RANDOM_FILE], + va_arg(param, char *)); break; case CURLOPT_EGDSOCKET: /* * The Entropy Gathering Daemon socket pathname */ - data->set.ssl.egdsocket = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSL_EGDSOCKET], + va_arg(param, char *)); break; case CURLOPT_MAXCONNECTS: /* @@ -785,7 +844,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Use this file instead of the $HOME/.netrc file */ - data->set.netrc_file = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE], + va_arg(param, char *)); break; case CURLOPT_TRANSFERTEXT: /* @@ -836,9 +896,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * and ignore an received Content-Encoding header. * */ - data->set.encoding = va_arg(param, char *); - if(data->set.encoding && !*data->set.encoding) - data->set.encoding = (char*)ALL_CONTENT_ENCODINGS; + argptr = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_ENCODING], + (argptr && !*argptr)? + (char *) ALL_CONTENT_ENCODINGS: argptr); break; case CURLOPT_FOLLOWLOCATION: @@ -881,7 +942,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * A string with POST data. Makes curl HTTP POST. Even if it is NULL. */ - data->set.postfields = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_POSTFIELDS], + va_arg(param, char *)); data->set.httpreq = HTTPREQ_POST; break; @@ -918,15 +980,17 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, free(data->change.referer); data->change.referer_alloc = FALSE; } - data->set.set_referer = va_arg(param, char *); - data->change.referer = data->set.set_referer; + result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], + va_arg(param, char *)); + data->change.referer = data->set.str[STRING_SET_REFERER]; break; case CURLOPT_USERAGENT: /* * String to use in the HTTP User-Agent field */ - data->set.useragent = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_USERAGENT], + va_arg(param, char *)); break; case CURLOPT_HTTPHEADER: @@ -948,7 +1012,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Cookie string to send to the remote server in the request. */ - data->set.cookie = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_COOKIE], + va_arg(param, char *)); break; case CURLOPT_COOKIEFILE: @@ -973,7 +1038,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set cookie file name to dump all cookies to when we're done. */ - data->set.cookiejar = (char *)va_arg(param, void *); + result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], + va_arg(param, char *)); /* * Activate the cookie parser. This may or may not already @@ -1071,7 +1137,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set a custom string to use as request */ - data->set.customrequest = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], + va_arg(param, char *)); /* we don't set data->set.httpreq = HTTPREQ_CUSTOM; @@ -1137,7 +1204,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Setting it to NULL, means no proxy but allows the environment variables * to decide for us. */ - data->set.proxy = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_PROXY], + va_arg(param, char *)); break; case CURLOPT_WRITEHEADER: @@ -1163,8 +1231,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Use FTP PORT, this also specifies which IP address to use */ - data->set.ftpport = va_arg(param, char *); - data->set.ftp_use_port = (bool)(NULL != data->set.ftpport); + result = Curl_setstropt(&data->set.str[STRING_FTPPORT], + va_arg(param, char *)); + data->set.ftp_use_port = (bool)(NULL != data->set.str[STRING_FTPPORT]); break; case CURLOPT_FTP_USE_EPRT: @@ -1247,8 +1316,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, free(data->change.url); data->change.url_alloc=FALSE; } - data->set.set_url = va_arg(param, char *); - data->change.url = data->set.set_url; + result = Curl_setstropt(&data->set.str[STRING_SET_URL], + va_arg(param, char *)); + data->change.url = data->set.str[STRING_SET_URL]; data->change.url_changed = TRUE; break; case CURLOPT_PORT: @@ -1284,7 +1354,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * user:password to use in the operation */ - data->set.userpwd = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_USERPWD], + va_arg(param, char *)); break; case CURLOPT_POSTQUOTE: /* @@ -1325,13 +1396,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * user:password needed to use the proxy */ - data->set.proxyuserpwd = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_PROXYUSERPWD], + va_arg(param, char *)); break; case CURLOPT_RANGE: /* * What range of the file you want to transfer */ - data->set.set_range = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SET_RANGE], + va_arg(param, char *)); break; case CURLOPT_RESUME_FROM: /* @@ -1428,31 +1501,36 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * String that holds file name of the SSL certificate to use */ - data->set.cert = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_CERT], + va_arg(param, char *)); break; case CURLOPT_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use */ - data->set.cert_type = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE], + va_arg(param, char *)); break; case CURLOPT_SSLKEY: /* * String that holds file name of the SSL certificate to use */ - data->set.key = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_KEY], + va_arg(param, char *)); break; case CURLOPT_SSLKEYTYPE: /* * String that holds file type of the SSL certificate to use */ - data->set.key_type = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE], + va_arg(param, char *)); break; case CURLOPT_SSLKEYPASSWD: /* * String that holds the SSL private key password. */ - data->set.key_passwd = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD], + va_arg(param, char *)); break; case CURLOPT_SSLENGINE: /* @@ -1481,7 +1559,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set what interface or address/hostname to bind the socket to when * performing an operation and thus what from-IP your connection will use. */ - data->set.device = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_DEVICE], + va_arg(param, char *)); break; case CURLOPT_LOCALPORT: /* @@ -1499,8 +1578,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * A string that defines the kerberos security level. */ - data->set.krb_level = va_arg(param, char *); - data->set.krb = (bool)(NULL != data->set.krb_level); + result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], + va_arg(param, char *)); + data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]); break; case CURLOPT_SSL_VERIFYPEER: /* @@ -1530,7 +1610,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set CA info for SSL connection. Specify file name of the CA certificate */ - data->set.ssl.CAfile = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], + va_arg(param, char *)); break; case CURLOPT_CAPATH: /* @@ -1538,7 +1619,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * certificates which have been prepared using openssl c_rehash utility. */ /* This does not work on windows. */ - data->set.ssl.CApath = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH], + va_arg(param, char *)); break; case CURLOPT_TELNETOPTIONS: /* @@ -1639,7 +1721,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set private data pointer. */ - data->set.private_data = va_arg(param, char *); + data->set.private_data = va_arg(param, void *); break; case CURLOPT_MAXFILESIZE: @@ -1691,7 +1773,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, These former 3rd party transfer options are deprecated */ case CURLOPT_FTP_ACCOUNT: - data->set.ftp_account = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], + va_arg(param, char *)); break; case CURLOPT_IGNORE_CONTENT_LENGTH: @@ -1706,7 +1789,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: - data->set.ftp_alternative_to_user = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], + va_arg(param, char *)); break; case CURLOPT_SOCKOPTFUNCTION: @@ -1735,14 +1819,16 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Use this file instead of the $HOME/.ssh/id_dsa.pub file */ - data->set.ssh_public_key = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], + va_arg(param, char *)); break; case CURLOPT_SSH_PRIVATE_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa file */ - data->set.ssh_private_key = va_arg(param, char *); + result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], + va_arg(param, char *)); break; case CURLOPT_HTTP_TRANSFER_DECODING: @@ -2780,14 +2866,14 @@ static CURLcode setup_range(struct SessionHandle *data) struct HandleData *req = &data->reqdata; req->resume_from = data->set.set_resume_from; - if (req->resume_from || data->set.set_range) { + if (req->resume_from || data->set.str[STRING_SET_RANGE]) { if (req->rangestringalloc == TRUE) free(req->range); if(req->resume_from) req->range = aprintf("%" FORMAT_OFF_T "-", req->resume_from); else - req->range = strdup(data->set.set_range); + req->range = strdup(data->set.str[STRING_SET_RANGE]); req->rangestringalloc = req->range?TRUE:FALSE; @@ -2892,7 +2978,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, conn->connectindex = -1; /* no index */ conn->proxytype = data->set.proxytype; /* type */ - conn->bits.proxy = (bool)(data->set.proxy && *data->set.proxy); + conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] && + *data->set.str[STRING_PROXY]); conn->bits.httpproxy = (bool)(conn->bits.proxy && (conn->proxytype == CURLPROXY_HTTP)); @@ -2911,8 +2998,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, /* Store creation time to help future close decision making */ conn->created = Curl_tvnow(); - conn->bits.user_passwd = (bool)(NULL != data->set.userpwd); - conn->bits.proxy_user_passwd = (bool)(NULL != data->set.proxyuserpwd); + conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERPWD]); + conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERPWD]); conn->bits.no_body = data->set.opt_no_body; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; @@ -2945,11 +3032,8 @@ static CURLcode CreateConnection(struct SessionHandle *data, if(urllen < LEAST_PATH_ALLOC) urllen=LEAST_PATH_ALLOC; - if (!data->set.source_url /* 3rd party FTP */ - && data->reqdata.pathbuffer) { - /* Free the old buffer */ - free(data->reqdata.pathbuffer); - } + /* Free the old buffer */ + Curl_safefree(data->reqdata.pathbuffer); /* * We malloc() the buffers below urllen+2 to make room for to possibilities: @@ -2981,7 +3065,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, char proxyuser[MAX_CURL_USER_LENGTH]=""; char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; - sscanf(data->set.proxyuserpwd, + sscanf(data->set.str[STRING_PROXYUSERPWD], "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", proxyuser, proxypasswd); @@ -2995,8 +3079,9 @@ static CURLcode CreateConnection(struct SessionHandle *data, return CURLE_OUT_OF_MEMORY; } - if (data->set.proxy) { - proxy = strdup(data->set.proxy); /* if global proxy is set, this is it */ + if (data->set.str[STRING_PROXY]) { + proxy = strdup(data->set.str[STRING_PROXY]); + /* if global proxy is set, this is it */ if(NULL == proxy) { failf(data, "memory shortage"); return CURLE_OUT_OF_MEMORY; @@ -3711,9 +3796,9 @@ static CURLcode CreateConnection(struct SessionHandle *data, * user_password is set in "inherit initial knowledge' above, * so it doesn't have to be set in this block */ - if (data->set.userpwd != NULL) { + if (data->set.str[STRING_USERPWD] != NULL) { /* the name is given, get user+password */ - sscanf(data->set.userpwd, + sscanf(data->set.str[STRING_USERPWD], "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", user, passwd); @@ -3723,7 +3808,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, if (data->set.use_netrc != CURL_NETRC_IGNORED) { if(Curl_parsenetrc(conn->host.name, user, passwd, - data->set.netrc_file)) { + data->set.str[STRING_NETRC_FILE])) { infof(data, "Couldn't find host %s in the " DOT_CHAR "netrc file, using defaults\n", conn->host.name); @@ -3760,8 +3845,21 @@ static CURLcode CreateConnection(struct SessionHandle *data, * new one. *************************************************************/ - /* get a cloned copy of the SSL config situation stored in the - connection struct */ + /* Get a cloned copy of the SSL config situation stored in the + connection struct. But to get this going nicely, we must first make + sure that the strings in the master copy are pointing to the correct + strings in the session handle strings array! + + Keep in mind that the pointers in the master copy are pointing to strings + that will be freed as part of the SessionHandle struct, but all cloned + copies will be separately allocated. + */ + data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH]; + data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE]; + data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; + if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) return CURLE_OUT_OF_MEMORY; @@ -4081,10 +4179,10 @@ static CURLcode SetupConnection(struct connectdata *conn, /************************************************************* * Set user-agent for HTTP *************************************************************/ - if((conn->protocol&PROT_HTTP) && data->set.useragent) { + if((conn->protocol&PROT_HTTP) && data->set.str[STRING_USERAGENT]) { Curl_safefree(conn->allocptr.uagent); conn->allocptr.uagent = - aprintf("User-Agent: %s\r\n", data->set.useragent); + aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]); if(!conn->allocptr.uagent) return CURLE_OUT_OF_MEMORY; } diff --git a/lib/url.h b/lib/url.h index 9f92e693b..0431cb065 100644 --- a/lib/url.h +++ b/lib/url.h @@ -32,6 +32,8 @@ CURLcode Curl_open(struct SessionHandle **curl); CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, va_list arg); +CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src); +void Curl_freeset(struct SessionHandle * data); CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, bool *async, bool *protocol_connect); diff --git a/lib/urldata.h b/lib/urldata.h index d1da3331c..41d852832 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -195,7 +195,7 @@ struct ssl_config_data { long verifyhost; /* 0: no verify 1: check that CN exists 2: CN must match hostname */ - char *CApath; /* DOES NOT WORK ON WINDOWS */ + char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* cerficate to verify peer against */ char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ @@ -1237,43 +1237,69 @@ struct DynamicStatic { * calculated internally for the "session handle" MUST be defined within the * 'struct UrlState' instead. The only exceptions MUST note the changes in * the 'DynamicStatic' struct. + * Character pointer fields point to dynamic storage, unless otherwise stated. */ struct Curl_one_easy; /* declared and used only in multi.c */ struct Curl_multi; /* declared and used only in multi.c */ +enum dupstring { + STRING_CERT, /* client certificate file name */ + STRING_CERT_TYPE, /* format for certificate (default: PEM)*/ + STRING_COOKIE, /* HTTP cookie string to send */ + STRING_COOKIEJAR, /* dump all cookies to this file */ + STRING_CUSTOMREQUEST, /* HTTP/FTP request/method to use */ + STRING_DEVICE, /* local network interface/address to use */ + STRING_ENCODING, /* Accept-Encoding string */ + STRING_FTP_ACCOUNT, /* ftp account data */ + STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ + STRING_FTPPORT, /* port to send with the FTP PORT command */ + STRING_KEY, /* private key file name */ + STRING_KEY_PASSWD, /* plain text private key password */ + STRING_KEY_TYPE, /* format for private key (default: PEM) */ + STRING_KRB_LEVEL, /* krb security level */ + STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find + $HOME/.netrc */ + STRING_POSTFIELDS, /* if POST, set the fields' values here */ + STRING_PROXY, /* proxy to use */ + STRING_PROXYUSERPWD, /* Proxy , if used */ + STRING_SET_RANGE, /* range, if used */ + STRING_SET_REFERER, /* custom string for the HTTP referer field */ + STRING_SET_URL, /* what original URL to work on */ + STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ + STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ + STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAFILE, /* certificate file to verify peer against */ + STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ + STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ + STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ + STRING_USERAGENT, /* User-Agent string */ + STRING_USERPWD, /* , if used */ + + /* -- end of strings -- */ + STRING_LAST /* not used, just an end-of-list marker */ +}; + struct UserDefined { FILE *err; /* the stderr user data goes here */ void *debugdata; /* the data that will be passed to fdebug */ - char *errorbuffer; /* store failure messages in here */ - char *proxyuserpwd; /* Proxy , if used */ + char *errorbuffer; /* (Static) store failure messages in here */ long proxyport; /* If non-zero, use this port number by default. If the proxy string features a ":[port]" that one will override this. */ void *out; /* the fetched file goes here */ void *in; /* the uploaded file is read from here */ void *writeheader; /* write the header to this if non-NULL */ - char *set_url; /* what original URL to work on */ - char *proxy; /* proxy to use */ long use_port; /* which port to use (when not using default) */ - char *userpwd; /* , if used */ long httpauth; /* what kind of HTTP authentication to use (bitmask) */ long proxyauth; /* what kind of proxy authentication to use (bitmask) */ - char *set_range; /* range, if used. See README for detailed specification - on this syntax. */ long followlocation; /* as in HTTP Location: */ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ - char *set_referer; /* custom string */ bool free_referer; /* set TRUE if 'referer' points to a string we allocated */ - char *useragent; /* User-Agent string */ - char *encoding; /* Accept-Encoding string */ - char *postfields; /* if POST, set the fields' values here */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead of strlen(), and then the data *may* be binary (contain zero bytes) */ - char *ftpport; /* port to send with the FTP PORT command */ - char *device; /* local network interface/address to use */ unsigned short localport; /* local port number to bind to */ int localportrange; /* number of additional port numbers to test in case the 'localport' one can't be bind()ed */ @@ -1305,19 +1331,10 @@ struct UserDefined { curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */ curl_off_t set_resume_from; /* continue [ftp] transfer from here */ - char *cookie; /* HTTP cookie string to send */ struct curl_slist *headers; /* linked list of extra headers */ struct curl_httppost *httppost; /* linked list of POST data */ - char *cert; /* certificate */ - char *cert_type; /* format for certificate (default: PEM) */ - char *key; /* private key */ - char *key_type; /* format for private key (default: PEM) */ - char *key_passwd; /* plain text private key password */ - char *cookiejar; /* dump all cookies to this file */ bool cookiesession; /* new cookie session? */ bool crlf; /* convert crlf on ftp upload(?) */ - char *ftp_account; /* ftp account data */ - char *ftp_alternative_to_user; /* command to send if USER/PASS fails */ struct curl_slist *quote; /* after connection is established */ struct curl_slist *postquote; /* after the transfer */ struct curl_slist *prequote; /* before the transfer, after type */ @@ -1330,14 +1347,8 @@ struct UserDefined { curl_TimeCond timecondition; /* kind of time/date comparison */ time_t timevalue; /* what time to compare with */ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ - char *customrequest; /* HTTP/FTP request to use */ long httpversion; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ - char *auth_host; /* if set, this is the allocated string to the host name - * to which to send the authorization data to, and no other - * host (which location-following otherwise could lead to) - */ - char *krb_level; /* what security level */ struct ssl_config_data ssl; /* user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ @@ -1345,7 +1356,7 @@ struct UserDefined { int dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ - char *private_data; /* Private data */ + void *private_data; /* Private data */ struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi handle, an internal 'Curl_one_easy' @@ -1359,9 +1370,6 @@ struct UserDefined { curl_off_t max_filesize; /* Maximum file size to download */ - char *source_url; /* for 3rd party transfer */ - char *source_userpwd; /* for 3rd party transfer */ - curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ /* Here follows boolean settings that define how to behave during @@ -1388,8 +1396,6 @@ struct UserDefined { bool upload; enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ - char *netrc_file; /* if not NULL, use this instead of trying to find - $HOME/.netrc */ bool verbose; bool krb; /* kerberos connection requested */ bool reuse_forbid; /* forbidden to be reused, close after use */ @@ -1408,16 +1414,14 @@ struct UserDefined { us */ bool connect_only; /* make connection, let application use the socket */ long ssh_auth_types; /* allowed SSH auth types */ - char *ssh_public_key; /* the path to the public key file for - authentication */ - char *ssh_private_key; /* the path to the private key file for - authentication */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ bool http_ce_skip; /* pass the raw body data to the user, even when content-encoded (chunked, compressed) */ long new_file_perms; /* Permissions to use when creating remote files */ long new_directory_perms; /* Permissions to use when creating remote dirs */ + + char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ }; struct Names {