/* * Delete the given session ID from the cache. */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { size_t i; struct SessionHandle *data=conn->data; if(SSLSESSION_SHARED(data)) Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { Curl_ssl_kill_session(check); break; } } if(SSLSESSION_SHARED(data)) Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); }
/* * Check if there's a session ID for the given connection in the cache, and if * there's one suitable, it is provided. Returns TRUE when no entry matched. */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, size_t *idsize) /* set 0 if unknown */ { struct curl_ssl_session *check; struct Curl_easy *data = conn->data; size_t i; long *general_age; bool no_match = TRUE; *ssl_sessionid = NULL; DEBUGASSERT(conn->ssl_config.sessionid); if(!conn->ssl_config.sessionid) /* session ID re-use is disabled */ return TRUE; /* Lock if shared */ if(SSLSESSION_SHARED(data)) general_age = &data->share->sessionage; else general_age = &data->state.sessionage; for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { check = &data->state.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; if(strcasecompare(conn->host.name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || (conn->bits.conn_to_host && check->conn_to_host && strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || (conn->bits.conn_to_port && check->conn_to_port != -1 && conn->conn_to_port == check->conn_to_port)) && (conn->remote_port == check->remote_port) && strcasecompare(conn->handler->scheme, check->scheme) && Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ check->age = *general_age; /* set this as used in this age */ *ssl_sessionid = check->sessionid; if(idsize) *idsize = check->idsize; no_match = FALSE; break; } } return no_match; }
void Curl_ssl_close_all(struct SessionHandle *data) { size_t i; /* kill the session ID cache if not shared */ if(data->state.session && !SSLSESSION_SHARED(data)) { for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) /* the single-killer function handles empty table slots */ Curl_ssl_kill_session(&data->state.session[i]); /* free the cache data */ Curl_safefree(data->state.session); } curlssl_close_all(data); }
/* * Store session id in the session cache. The ID passed on to this function * must already have been extracted and allocated the proper way for the SSL * layer. Curl_XXXX_session_free() will be called to free/kill the session ID * later on. */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize) { size_t i; struct SessionHandle *data=conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; long oldest_age=data->state.session[0].age; /* zero if unused */ char *clone_host; long *general_age; /* Even though session ID re-use might be disabled, that only disables USING IT. We still store it here in case the re-using is again enabled for an upcoming transfer */ clone_host = strdup(conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); general_age = &data->share->sessionage; } else { general_age = &data->state.sessionage; } /* find an empty slot for us, or find the oldest */ for(i = 1; (i < data->set.ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } if(i == data->set.ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else store = &data->state.session[i]; /* use this slot */ /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ if(store->name) /* free it if there's one already present */ free(store->name); store->name = clone_host; /* clone host name */ store->remote_port = conn->remote_port; /* port number */ /* Unlock */ if(SSLSESSION_SHARED(data)) Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); return CURLE_OUT_OF_MEMORY; } return CURLE_OK; }
/* * Store session id in the session cache. The ID passed on to this function * must already have been extracted and allocated the proper way for the SSL * layer. Curl_XXXX_session_free() will be called to free/kill the session ID * later on. */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize, int sockindex) { size_t i; struct Curl_easy *data=conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; long oldest_age=data->state.session[0].age; /* zero if unused */ char *clone_host; char *clone_conn_to_host; int conn_to_port; long *general_age; const bool isProxy = CONNECT_PROXY_SSL(); struct ssl_primary_config * const ssl_config = isProxy ? &conn->proxy_ssl_config : &conn->ssl_config; DEBUGASSERT(SSL_SET_OPTION(primary.sessionid)); clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ if(conn->bits.conn_to_host) { clone_conn_to_host = strdup(conn->conn_to_host.name); if(!clone_conn_to_host) { free(clone_host); return CURLE_OUT_OF_MEMORY; /* bail out */ } } else clone_conn_to_host = NULL; if(conn->bits.conn_to_port) conn_to_port = conn->conn_to_port; else conn_to_port = -1; /* Now we should add the session ID and the host name to the cache, (remove the oldest if necessary) */ /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { general_age = &data->share->sessionage; } else { general_age = &data->state.sessionage; } /* find an empty slot for us, or find the oldest */ for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } if(i == data->set.general_ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else store = &data->state.session[i]; /* use this slot */ /* now init the session struct wisely */ store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ /* free it if there's one already present */ free(store->name); free(store->conn_to_host); store->name = clone_host; /* clone host name */ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ /* port number */ store->remote_port = isProxy ? (int)conn->port : conn->remote_port; store->scheme = conn->handler->scheme; if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); return CURLE_OUT_OF_MEMORY; } return CURLE_OK; }
/* * Unlock shared SSL session data */ void Curl_ssl_sessionid_unlock(struct connectdata *conn) { if(SSLSESSION_SHARED(conn->data)) Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION); }