mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
Tasks 3.3 and 4.1. - vfc curl and openssl-cve-2021-3449 excerpts re-harvested through the shared library: whole functions with upstream_start headers, the vendored key redacted code-safely, no truncated bodies. - vfc/recipes.toml carries mode, fix_path and function anchors; training/manifest.jsonl regenerated. - Juliet CWE-121 strcpy pair gets its buffer declarations back so the vulnerable side is a real overflow again. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
493 lines
17 KiB
C
493 lines
17 KiB
C
/* Provenance: curl/curl create_conn (fixed).
|
|
* repo: curl/curl
|
|
* commit: 5ea3145850ebff1dc2b13d17440300a01ca38161
|
|
* parent: fd9b40bf8dfd43edcbc0d254d613d95a11061c05
|
|
* commit_url: https://github.com/curl/curl/commit/5ea3145850ebff1dc2b13d17440300a01ca38161
|
|
* cve: CVE-2021-22924
|
|
* license: curl
|
|
* function: create_conn
|
|
* relpath: lib/url.c
|
|
* provenance: human
|
|
* mechanism: other
|
|
*/
|
|
|
|
static CURLcode create_conn(struct Curl_easy *data,
|
|
struct connectdata **in_connect,
|
|
bool *async)
|
|
{
|
|
CURLcode result = CURLE_OK;
|
|
struct connectdata *conn;
|
|
struct connectdata *conn_temp = NULL;
|
|
bool reuse;
|
|
bool connections_available = TRUE;
|
|
bool force_reuse = FALSE;
|
|
bool waitpipe = FALSE;
|
|
size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
|
|
size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
|
|
|
|
*async = FALSE;
|
|
*in_connect = NULL;
|
|
|
|
/*************************************************************
|
|
* Check input data
|
|
*************************************************************/
|
|
if(!data->state.url) {
|
|
result = CURLE_URL_MALFORMAT;
|
|
goto out;
|
|
}
|
|
|
|
/* First, split up the current URL in parts so that we can use the
|
|
parts for checking against the already present connections. In order
|
|
to not have to modify everything at once, we allocate a temporary
|
|
connection data struct and fill in for comparison purposes. */
|
|
conn = allocate_conn(data);
|
|
|
|
if(!conn) {
|
|
result = CURLE_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
/* We must set the return variable as soon as possible, so that our
|
|
parent can cleanup any possible allocs we may have done before
|
|
any failure */
|
|
*in_connect = conn;
|
|
|
|
result = parseurlandfillconn(data, conn);
|
|
if(result)
|
|
goto out;
|
|
|
|
if(data->set.str[STRING_SASL_AUTHZID]) {
|
|
conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
|
|
if(!conn->sasl_authzid) {
|
|
result = CURLE_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
#ifdef USE_UNIX_SOCKETS
|
|
if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
|
|
conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
|
|
if(!conn->unix_domain_socket) {
|
|
result = CURLE_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
|
|
}
|
|
#endif
|
|
|
|
/* After the unix socket init but before the proxy vars are used, parse and
|
|
initialize the proxy vars */
|
|
#ifndef CURL_DISABLE_PROXY
|
|
result = create_conn_helper_init_proxy(data, conn);
|
|
if(result)
|
|
goto out;
|
|
|
|
/*************************************************************
|
|
* If the protocol is using SSL and HTTP proxy is used, we set
|
|
* the tunnel_proxy bit.
|
|
*************************************************************/
|
|
if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
|
|
conn->bits.tunnel_proxy = TRUE;
|
|
#endif
|
|
|
|
/*************************************************************
|
|
* Figure out the remote port number and fix it in the URL
|
|
*************************************************************/
|
|
result = parse_remote_port(data, conn);
|
|
if(result)
|
|
goto out;
|
|
|
|
/* Check for overridden login details and set them accordingly so that
|
|
they are known when protocol->setup_connection is called! */
|
|
result = override_login(data, conn);
|
|
if(result)
|
|
goto out;
|
|
|
|
result = set_login(conn); /* default credentials */
|
|
if(result)
|
|
goto out;
|
|
|
|
/*************************************************************
|
|
* Process the "connect to" linked list of hostname/port mappings.
|
|
* Do this after the remote port number has been fixed in the URL.
|
|
*************************************************************/
|
|
result = parse_connect_to_slist(data, conn, data->set.connect_to);
|
|
if(result)
|
|
goto out;
|
|
|
|
/*************************************************************
|
|
* IDN-convert the hostnames
|
|
*************************************************************/
|
|
result = Curl_idnconvert_hostname(data, &conn->host);
|
|
if(result)
|
|
goto out;
|
|
if(conn->bits.conn_to_host) {
|
|
result = Curl_idnconvert_hostname(data, &conn->conn_to_host);
|
|
if(result)
|
|
goto out;
|
|
}
|
|
#ifndef CURL_DISABLE_PROXY
|
|
if(conn->bits.httpproxy) {
|
|
result = Curl_idnconvert_hostname(data, &conn->http_proxy.host);
|
|
if(result)
|
|
goto out;
|
|
}
|
|
if(conn->bits.socksproxy) {
|
|
result = Curl_idnconvert_hostname(data, &conn->socks_proxy.host);
|
|
if(result)
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
/*************************************************************
|
|
* Check whether the host and the "connect to host" are equal.
|
|
* Do this after the hostnames have been IDN-converted.
|
|
*************************************************************/
|
|
if(conn->bits.conn_to_host &&
|
|
strcasecompare(conn->conn_to_host.name, conn->host.name)) {
|
|
conn->bits.conn_to_host = FALSE;
|
|
}
|
|
|
|
/*************************************************************
|
|
* Check whether the port and the "connect to port" are equal.
|
|
* Do this after the remote port number has been fixed in the URL.
|
|
*************************************************************/
|
|
if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
|
|
conn->bits.conn_to_port = FALSE;
|
|
}
|
|
|
|
#ifndef CURL_DISABLE_PROXY
|
|
/*************************************************************
|
|
* If the "connect to" feature is used with an HTTP proxy,
|
|
* we set the tunnel_proxy bit.
|
|
*************************************************************/
|
|
if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
|
|
conn->bits.httpproxy)
|
|
conn->bits.tunnel_proxy = TRUE;
|
|
#endif
|
|
|
|
/*************************************************************
|
|
* Setup internals depending on protocol. Needs to be done after
|
|
* we figured out what/if proxy to use.
|
|
*************************************************************/
|
|
result = setup_connection_internals(data, conn);
|
|
if(result)
|
|
goto out;
|
|
|
|
conn->recv[FIRSTSOCKET] = Curl_recv_plain;
|
|
conn->send[FIRSTSOCKET] = Curl_send_plain;
|
|
conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
|
|
conn->send[SECONDARYSOCKET] = Curl_send_plain;
|
|
|
|
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
|
|
|
|
/***********************************************************************
|
|
* file: is a special case in that it doesn't need a network connection
|
|
***********************************************************************/
|
|
#ifndef CURL_DISABLE_FILE
|
|
if(conn->handler->flags & PROTOPT_NONETWORK) {
|
|
bool done;
|
|
/* this is supposed to be the connect function so we better at least check
|
|
that the file is present here! */
|
|
DEBUGASSERT(conn->handler->connect_it);
|
|
Curl_persistconninfo(data, conn, NULL, -1);
|
|
result = conn->handler->connect_it(data, &done);
|
|
|
|
/* Setup a "faked" transfer that'll do nothing */
|
|
if(!result) {
|
|
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
|
|
|
|
Curl_attach_connnection(data, conn);
|
|
result = Curl_conncache_add_conn(data);
|
|
if(result)
|
|
goto out;
|
|
|
|
/*
|
|
* Setup whatever necessary for a resumed transfer
|
|
*/
|
|
result = setup_range(data);
|
|
if(result) {
|
|
DEBUGASSERT(conn->handler->done);
|
|
/* we ignore the return code for the protocol-specific DONE */
|
|
(void)conn->handler->done(data, result, FALSE);
|
|
goto out;
|
|
}
|
|
Curl_setup_transfer(data, -1, -1, FALSE, -1);
|
|
}
|
|
|
|
/* since we skip do_init() */
|
|
Curl_init_do(data, conn);
|
|
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
/* 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 Curl_easy struct, but all cloned
|
|
copies will be separately allocated.
|
|
*/
|
|
data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH];
|
|
data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE];
|
|
data->set.ssl.primary.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
|
|
data->set.ssl.primary.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT];
|
|
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
|
|
data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
|
|
data->set.ssl.primary.cipher_list =
|
|
data->set.str[STRING_SSL_CIPHER_LIST];
|
|
data->set.ssl.primary.cipher_list13 =
|
|
data->set.str[STRING_SSL_CIPHER13_LIST];
|
|
data->set.ssl.primary.pinned_key =
|
|
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
|
|
data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT];
|
|
data->set.ssl.primary.ca_info_blob = data->set.blobs[BLOB_CAINFO];
|
|
data->set.ssl.primary.curves = data->set.str[STRING_SSL_EC_CURVES];
|
|
|
|
#ifndef CURL_DISABLE_PROXY
|
|
data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
|
|
data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
|
|
data->set.proxy_ssl.primary.random_file =
|
|
data->set.str[STRING_SSL_RANDOM_FILE];
|
|
data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
|
|
data->set.proxy_ssl.primary.cipher_list =
|
|
data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
|
|
data->set.proxy_ssl.primary.cipher_list13 =
|
|
data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
|
|
data->set.proxy_ssl.primary.pinned_key =
|
|
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
|
|
data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
|
|
data->set.proxy_ssl.primary.ca_info_blob =
|
|
data->set.blobs[BLOB_CAINFO_PROXY];
|
|
data->set.proxy_ssl.primary.issuercert =
|
|
data->set.str[STRING_SSL_ISSUERCERT_PROXY];
|
|
data->set.proxy_ssl.primary.issuercert_blob =
|
|
data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY];
|
|
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
|
|
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
|
|
data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
|
|
data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
|
|
data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
|
|
data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
|
|
data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
|
|
#endif
|
|
data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
|
|
data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE];
|
|
data->set.ssl.key = data->set.str[STRING_KEY];
|
|
data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE];
|
|
data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
|
|
data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
|
|
#ifdef USE_TLS_SRP
|
|
data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME];
|
|
data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD];
|
|
#ifndef CURL_DISABLE_PROXY
|
|
data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
|
|
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
|
|
#endif
|
|
#endif
|
|
data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
|
|
|
|
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
|
|
&conn->ssl_config)) {
|
|
result = CURLE_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
|
|
#ifndef CURL_DISABLE_PROXY
|
|
if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
|
|
&conn->proxy_ssl_config)) {
|
|
result = CURLE_OUT_OF_MEMORY;
|
|
goto out;
|
|
}
|
|
#endif
|
|
|
|
prune_dead_connections(data);
|
|
|
|
/*************************************************************
|
|
* Check the current list of connections to see if we can
|
|
* re-use an already existing one or if we have to create a
|
|
* new one.
|
|
*************************************************************/
|
|
|
|
DEBUGASSERT(conn->user);
|
|
DEBUGASSERT(conn->passwd);
|
|
|
|
/* reuse_fresh is TRUE if we are told to use a new connection by force, but
|
|
we only acknowledge this option if this is not a re-used connection
|
|
already (which happens due to follow-location or during a HTTP
|
|
authentication phase). CONNECT_ONLY transfers also refuse reuse. */
|
|
if((data->set.reuse_fresh && !data->state.this_is_a_follow) ||
|
|
data->set.connect_only)
|
|
reuse = FALSE;
|
|
else
|
|
reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
|
|
|
|
if(reuse) {
|
|
/*
|
|
* We already have a connection for this, we got the former connection in
|
|
* the conn_temp variable and thus we need to cleanup the one we just
|
|
* allocated before we can move along and use the previously existing one.
|
|
*/
|
|
reuse_conn(data, conn, conn_temp);
|
|
#ifdef USE_SSL
|
|
free(conn->ssl_extra);
|
|
#endif
|
|
free(conn); /* we don't need this anymore */
|
|
conn = conn_temp;
|
|
*in_connect = conn;
|
|
|
|
#ifndef CURL_DISABLE_PROXY
|
|
infof(data, "Re-using existing connection! (#%ld) with %s %s",
|
|
conn->connection_id,
|
|
conn->bits.proxy?"proxy":"host",
|
|
conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
|
|
conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
|
|
conn->host.dispname);
|
|
#else
|
|
infof(data, "Re-using existing connection! (#%ld) with host %s",
|
|
conn->connection_id, conn->host.dispname);
|
|
#endif
|
|
}
|
|
else {
|
|
/* We have decided that we want a new connection. However, we may not
|
|
be able to do that if we have reached the limit of how many
|
|
connections we are allowed to open. */
|
|
|
|
if(conn->handler->flags & PROTOPT_ALPN_NPN) {
|
|
/* The protocol wants it, so set the bits if enabled in the easy handle
|
|
(default) */
|
|
if(data->set.ssl_enable_alpn)
|
|
conn->bits.tls_enable_alpn = TRUE;
|
|
if(data->set.ssl_enable_npn)
|
|
conn->bits.tls_enable_npn = TRUE;
|
|
}
|
|
|
|
if(waitpipe)
|
|
/* There is a connection that *might* become usable for multiplexing
|
|
"soon", and we wait for that */
|
|
connections_available = FALSE;
|
|
else {
|
|
/* this gets a lock on the conncache */
|
|
const char *bundlehost;
|
|
struct connectbundle *bundle =
|
|
Curl_conncache_find_bundle(data, conn, data->state.conn_cache,
|
|
&bundlehost);
|
|
|
|
if(max_host_connections > 0 && bundle &&
|
|
(bundle->num_connections >= max_host_connections)) {
|
|
struct connectdata *conn_candidate;
|
|
|
|
/* The bundle is full. Extract the oldest connection. */
|
|
conn_candidate = Curl_conncache_extract_bundle(data, bundle);
|
|
CONNCACHE_UNLOCK(data);
|
|
|
|
if(conn_candidate)
|
|
(void)Curl_disconnect(data, conn_candidate, FALSE);
|
|
else {
|
|
infof(data, "No more connections allowed to host %s: %zu",
|
|
bundlehost, max_host_connections);
|
|
connections_available = FALSE;
|
|
}
|
|
}
|
|
else
|
|
CONNCACHE_UNLOCK(data);
|
|
|
|
}
|
|
|
|
if(connections_available &&
|
|
(max_total_connections > 0) &&
|
|
(Curl_conncache_size(data) >= max_total_connections)) {
|
|
struct connectdata *conn_candidate;
|
|
|
|
/* The cache is full. Let's see if we can kill a connection. */
|
|
conn_candidate = Curl_conncache_extract_oldest(data);
|
|
if(conn_candidate)
|
|
(void)Curl_disconnect(data, conn_candidate, FALSE);
|
|
else {
|
|
infof(data, "No connections available in cache");
|
|
connections_available = FALSE;
|
|
}
|
|
}
|
|
|
|
if(!connections_available) {
|
|
infof(data, "No connections available.");
|
|
|
|
conn_free(conn);
|
|
*in_connect = NULL;
|
|
|
|
result = CURLE_NO_CONNECTION_AVAILABLE;
|
|
goto out;
|
|
}
|
|
else {
|
|
/*
|
|
* This is a brand new connection, so let's store it in the connection
|
|
* cache of ours!
|
|
*/
|
|
Curl_attach_connnection(data, conn);
|
|
result = Curl_conncache_add_conn(data);
|
|
if(result)
|
|
goto out;
|
|
}
|
|
|
|
#if defined(USE_NTLM)
|
|
/* If NTLM is requested in a part of this connection, make sure we don't
|
|
assume the state is fine as this is a fresh connection and NTLM is
|
|
connection based. */
|
|
if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
|
|
data->state.authhost.done) {
|
|
infof(data, "NTLM picked AND auth done set, clear picked!");
|
|
data->state.authhost.picked = CURLAUTH_NONE;
|
|
data->state.authhost.done = FALSE;
|
|
}
|
|
|
|
if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
|
|
data->state.authproxy.done) {
|
|
infof(data, "NTLM-proxy picked AND auth done set, clear picked!");
|
|
data->state.authproxy.picked = CURLAUTH_NONE;
|
|
data->state.authproxy.done = FALSE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* Setup and init stuff before DO starts, in preparing for the transfer. */
|
|
Curl_init_do(data, conn);
|
|
|
|
/*
|
|
* Setup whatever necessary for a resumed transfer
|
|
*/
|
|
result = setup_range(data);
|
|
if(result)
|
|
goto out;
|
|
|
|
/* Continue connectdata initialization here. */
|
|
|
|
/*
|
|
* Inherit the proper values from the urldata struct AFTER we have arranged
|
|
* the persistent connection stuff
|
|
*/
|
|
conn->seek_func = data->set.seek_func;
|
|
conn->seek_client = data->set.seek_client;
|
|
|
|
/*************************************************************
|
|
* Resolve the address of the server or proxy
|
|
*************************************************************/
|
|
result = resolve_server(data, conn, async);
|
|
|
|
/* Strip trailing dots. resolve_server copied the name. */
|
|
strip_trailing_dot(&conn->host);
|
|
#ifndef CURL_DISABLE_PROXY
|
|
if(conn->bits.httpproxy)
|
|
strip_trailing_dot(&conn->http_proxy.host);
|
|
if(conn->bits.socksproxy)
|
|
strip_trailing_dot(&conn->socks_proxy.host);
|
|
#endif
|
|
if(conn->bits.conn_to_host)
|
|
strip_trailing_dot(&conn->conn_to_host);
|
|
|
|
out:
|
|
return result;
|
|
}
|