/* * This function is called when an SSL connection is closed. */ void Curl_nss_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->handle) { /* NSS closes the socket we previously handed to it, so we must mark it as closed to avoid double close */ fake_sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL)) /* A server might require different authentication based on the * particular path being requested by the client. To support this * scenario, we must ensure that a connection will never reuse the * authentication data from a previous connection. */ SSL_InvalidateSession(connssl->handle); if(connssl->client_nickname != NULL) { free(connssl->client_nickname); connssl->client_nickname = NULL; } /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; connssl->obj_clicert = NULL; PR_Close(connssl->handle); connssl->handle = NULL; } }
/* return 1 on error, 0 is fine */ int Curl_hash_init(struct curl_hash *h, int slots, curl_hash_dtor dtor) { int i; h->dtor = dtor; h->size = 0; h->slots = slots; h->table = (struct curl_llist **) malloc(slots * sizeof(struct curl_llist *)); if(h->table) { for (i = 0; i < slots; ++i) { h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); if(!h->table[i]) { while(i--) Curl_llist_destroy(h->table[i], NULL); free(h->table); return 1; /* failure */ } } return 0; /* fine */ } else return 1; /* failure */ }
void Curl_wildcard_dtor(struct WildcardData *wc) { if(!wc) return; if(wc->tmp_dtor) { wc->tmp_dtor(wc->tmp); wc->tmp_dtor = ZERO_NULL; wc->tmp = NULL; } DEBUGASSERT(wc->tmp == NULL); if(wc->filelist) { Curl_llist_destroy(wc->filelist, NULL); wc->filelist = NULL; } free(wc->path); wc->path = NULL; free(wc->pattern); wc->pattern = NULL; wc->customptr = NULL; wc->state = CURLWC_INIT; }
/* * This function is called when an SSL connection is closed. */ void Curl_nss_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->handle) { /* NSS closes the socket we previously handed to it, so we must mark it as closed to avoid double close */ fake_sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; if(connssl->client_nickname != NULL) { free(connssl->client_nickname); connssl->client_nickname = NULL; /* force NSS to ask again for a client cert when connecting * next time to the same server */ SSL_InvalidateSession(connssl->handle); } /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; connssl->obj_clicert = NULL; PR_Close(connssl->handle); connssl->handle = NULL; } }
/* return 1 on error, 0 is fine */ int Curl_hash_init(struct curl_hash *h, int slots, hash_function hfunc, comp_function comparator, curl_hash_dtor dtor) { int i; if(!slots || !hfunc || !comparator ||!dtor) { return 1; /* failure */ } h->hash_func = hfunc; h->comp_func = comparator; h->dtor = dtor; h->size = 0; h->slots = slots; h->table = malloc(slots * sizeof(struct curl_llist *)); if(h->table) { for(i = 0; i < slots; ++i) { h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); if(!h->table[i]) { while(i--) Curl_llist_destroy(h->table[i], NULL); free(h->table); return 1; /* failure */ } } return 0; /* fine */ } else return 1; /* failure */ }
static void bundle_destroy(struct connectbundle *cb_ptr) { if(!cb_ptr) return; Curl_llist_destroy(&cb_ptr->conn_list, NULL); free(cb_ptr); }
static void bundle_destroy(struct connectbundle *cb_ptr) { if(!cb_ptr) return; if(cb_ptr->conn_list) { Curl_llist_destroy(cb_ptr->conn_list, NULL); cb_ptr->conn_list = NULL; } free(cb_ptr); }
void Curl_hash_clean(struct curl_hash *h) { int i; for (i = 0; i < h->slots; ++i) { Curl_llist_destroy(h->table[i], (void *) h); } free(h->table); }
CURLMcode Curl_pipeline_set_server_blacklist(char **servers, struct curl_llist **list_ptr) { struct curl_llist *old_list = *list_ptr; struct curl_llist *new_list = NULL; if(servers) { new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor); if(!new_list) return CURLM_OUT_OF_MEMORY; /* Parse the URLs and populate the list */ while(*servers) { char *server_name; server_name = strdup(*servers); if(!server_name) { Curl_llist_destroy(new_list, NULL); return CURLM_OUT_OF_MEMORY; } if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) { Curl_llist_destroy(new_list, NULL); Curl_safefree(server_name); return CURLM_OUT_OF_MEMORY; } servers++; } } /* Free the old list */ if(old_list) { Curl_llist_destroy(old_list, NULL); } /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ *list_ptr = new_list; return CURLM_OK; }
CURLMcode Curl_pipeline_set_site_blacklist(char **sites, struct curl_llist **list_ptr) { struct curl_llist *old_list = *list_ptr; struct curl_llist *new_list = NULL; if(sites) { new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor); if(!new_list) return CURLM_OUT_OF_MEMORY; /* Parse the URLs and populate the list */ while(*sites) { char *hostname; char *port; struct site_blacklist_entry *entry; entry = malloc(sizeof(struct site_blacklist_entry)); hostname = strdup(*sites); if(!hostname) return CURLM_OUT_OF_MEMORY; port = strchr(hostname, ':'); if(port) { *port = '\0'; port++; entry->port = (unsigned short)strtol(port, NULL, 10); } else { /* Default port number for HTTP */ entry->port = 80; } entry->hostname = hostname; if(!Curl_llist_insert_next(new_list, new_list->tail, entry)) return CURLM_OUT_OF_MEMORY; sites++; } } /* Free the old list */ if(old_list) { Curl_llist_destroy(old_list, NULL); } /* This might be NULL if sites == NULL, i.e the blacklist is cleared */ *list_ptr = new_list; return CURLM_OK; }
static CURLcode unit_setup(void) { llist = Curl_llist_alloc(test_curl_llist_dtor); if(!llist) return CURLE_OUT_OF_MEMORY; llist_destination = Curl_llist_alloc(test_curl_llist_dtor); if(!llist_destination) { Curl_llist_destroy(llist, NULL); return CURLE_OUT_OF_MEMORY; } return CURLE_OK; }
void Curl_hash_clean(struct curl_hash *h) { int i; for(i = 0; i < h->slots; ++i) { Curl_llist_destroy(h->table[i], (void *) h); h->table[i] = NULL; } Curl_safefree(h->table); h->size = 0; h->slots = 0; }
/* * This function is called when an SSL connection is closed. */ void Curl_nss_close(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->handle) { PR_Close(connssl->handle); /* NSS closes the socket we previously handed to it, so we must mark it as closed to avoid double close */ fake_sclose(conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; if(connssl->client_nickname != NULL) { free(connssl->client_nickname); connssl->client_nickname = NULL; } #ifdef HAVE_PK11_CREATEGENERICOBJECT /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(connssl->obj_list, NULL); #endif connssl->handle = NULL; } }
CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) { PRErrorCode err = 0; PRFileDesc *model = NULL; PRBool ssl2 = PR_FALSE; PRBool ssl3 = PR_FALSE; PRBool tlsv1 = PR_FALSE; PRBool ssl_no_cache; PRBool ssl_cbc_random_iv; struct SessionHandle *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode curlerr; const int *cipher_to_enable; PRSocketOptionData sock_opt; long time_left; PRUint32 timeout; if(connssl->state == ssl_connection_complete) return CURLE_OK; connssl->data = data; /* list of all NSS objects we need to destroy in Curl_nss_close() */ connssl->obj_list = Curl_llist_alloc(nss_destroy_object); if(!connssl->obj_list) return CURLE_OUT_OF_MEMORY; /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); curlerr = nss_init(conn->data); if(CURLE_OK != curlerr) { PR_Unlock(nss_initlock); goto error; } curlerr = CURLE_SSL_CONNECT_ERROR; if(!mod) { char *configstring = aprintf("library=%s name=PEM", pem_library); if(!configstring) { PR_Unlock(nss_initlock); goto error; } mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE); free(configstring); if(!mod || !mod->loaded) { if(mod) { SECMOD_DestroyModule(mod); mod = NULL; } infof(data, "WARNING: failed to load NSS PEM library %s. Using " "OpenSSL PEM certificates will not work.\n", pem_library); } } PK11_SetPasswordFunc(nss_get_password); PR_Unlock(nss_initlock); model = PR_NewTCPSocket(); if(!model) goto error; model = SSL_ImportFD(NULL, model); /* make the socket nonblocking */ sock_opt.option = PR_SockOpt_Nonblocking; sock_opt.value.non_blocking = PR_TRUE; if(PR_SetSocketOption(model, &sock_opt) != PR_SUCCESS) goto error; if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess) goto error; /* do not use SSL cache if we are not going to verify peer */ ssl_no_cache = (data->set.ssl.verifypeer) ? PR_FALSE : PR_TRUE; if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; switch (data->set.ssl.version) { default: case CURL_SSLVERSION_DEFAULT: ssl3 = PR_TRUE; if(data->state.ssl_connect_retry) infof(data, "TLS disabled due to previous handshake failure\n"); else tlsv1 = PR_TRUE; break; case CURL_SSLVERSION_TLSv1: tlsv1 = PR_TRUE; break; case CURL_SSLVERSION_SSLv2: ssl2 = PR_TRUE; break; case CURL_SSLVERSION_SSLv3: ssl3 = PR_TRUE; break; } if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess) goto error; if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess) goto error; ssl_cbc_random_iv = !data->set.ssl_enable_beast; #ifdef SSL_CBC_RANDOM_IV /* unless the user explicitly asks to allow the protocol vulnerability, we use the work-around */ if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess) infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n", ssl_cbc_random_iv); #else if(ssl_cbc_random_iv) infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); #endif /* reset the flag to avoid an infinite loop */ data->state.ssl_connect_retry = FALSE; /* enable all ciphers from enable_ciphers_by_default */ cipher_to_enable = enable_ciphers_by_default; while(SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) { if(SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) { curlerr = CURLE_SSL_CIPHER; goto error; } cipher_to_enable++; } if(data->set.ssl.cipher_list) { if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { curlerr = CURLE_SSL_CIPHER; goto error; } } if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost) infof(data, "warning: ignoring value of ssl.verifyhost\n"); /* bypass the default SSL_AuthCertificate() hook in case we do not want to * verify peer */ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) goto error; data->set.ssl.certverifyresult=0; /* not checked yet */ if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) goto error; if(SSL_HandshakeCallback(model, HandshakeCallback, NULL) != SECSuccess) goto error; if(data->set.ssl.verifypeer) { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); if(CURLE_OK != rv) { curlerr = rv; goto error; } } if(data->set.ssl.CRLfile) { if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) { curlerr = CURLE_SSL_CRL_BADFILE; goto error; } infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none"); } if(data->set.str[STRING_CERT]) { char *nickname = dup_nickname(data, STRING_CERT); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ connssl->obj_clicert = NULL; } else { CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], data->set.str[STRING_KEY]); if(CURLE_OK != rv) { /* failf() is already done in cert_stuff() */ curlerr = rv; goto error; } } /* store the nickname for SelectClientCert() called during handshake */ connssl->client_nickname = nickname; } else connssl->client_nickname = NULL; if(SSL_GetClientAuthDataHook(model, SelectClientCert, (void *)connssl) != SECSuccess) { curlerr = CURLE_SSL_CERTPROBLEM; goto error; } /* Import our model socket onto the existing file descriptor */ connssl->handle = PR_ImportTCPSocket(sockfd); connssl->handle = SSL_ImportFD(model, connssl->handle); if(!connssl->handle) goto error; PR_Close(model); /* We don't need this any more */ model = NULL; /* This is the password associated with the cert that we're using */ if(data->set.str[STRING_KEY_PASSWD]) { SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); } /* Force handshake on next I/O */ SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE); SSL_SetURL(connssl->handle, conn->host.name); /* check timeout situation */ time_left = Curl_timeleft(data, NULL, TRUE); if(time_left < 0L) { failf(data, "timed out before SSL handshake"); curlerr = CURLE_OPERATION_TIMEDOUT; goto error; } timeout = PR_MillisecondsToInterval((PRUint32) time_left); /* Force the handshake now */ if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) curlerr = CURLE_PEER_FAILED_VERIFICATION; else if(conn->data->set.ssl.certverifyresult!=0) curlerr = CURLE_SSL_CACERT; goto error; } connssl->state = ssl_connection_complete; conn->recv[sockindex] = nss_recv; conn->send[sockindex] = nss_send; display_conn_info(conn, connssl->handle); if(data->set.str[STRING_SSL_ISSUERCERT]) { SECStatus ret = SECFailure; char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); if(nickname) { /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ ret = check_issuer_cert(connssl->handle, nickname); free(nickname); } if(SECFailure == ret) { infof(data,"SSL certificate issuer check failed\n"); curlerr = CURLE_SSL_ISSUER_ERROR; goto error; } else { infof(data, "SSL certificate issuer check ok\n"); } } return CURLE_OK; error: /* reset the flag to avoid an infinite loop */ data->state.ssl_connect_retry = FALSE; if(is_nss_error(curlerr)) { /* read NSPR error code */ err = PR_GetError(); if(is_cc_error(err)) curlerr = CURLE_SSL_CERTPROBLEM; /* print the error number and error string */ infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); /* print a human-readable message describing the error if available */ nss_print_error_message(data, err); } if(model) PR_Close(model); /* cleanup on connection failure */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; if(ssl3 && tlsv1 && isTLSIntoleranceError(err)) { /* schedule reconnect through Curl_retry_request() */ data->state.ssl_connect_retry = TRUE; infof(data, "Error in TLS handshake, trying SSLv3...\n"); return CURLE_OK; } return curlerr; }
static void unit_stop(void) { Curl_llist_destroy(llist, NULL); Curl_llist_destroy(llist_destination, NULL); }