diff options
author | manu@netbsd.org <manu@netbsd.org@a716ebb1-153a-0410-b759-cfb97c6a1b53> | 2009-05-12 15:28:49 +0000 |
---|---|---|
committer | manu@netbsd.org <manu@netbsd.org@a716ebb1-153a-0410-b759-cfb97c6a1b53> | 2009-05-12 15:28:49 +0000 |
commit | 4c740a21c1f88bcc941f355fd52877e0666d05e0 (patch) | |
tree | aaf51cfc0c47c7999d960846a87128bb58038d0e | |
parent | 6b2fb648fff2828c093db414cd8f00d8624af966 (diff) | |
download | mod_auth_mellon-4c740a21c1f88bcc941f355fd52877e0666d05e0.tar.gz mod_auth_mellon-4c740a21c1f88bcc941f355fd52877e0666d05e0.tar.xz mod_auth_mellon-4c740a21c1f88bcc941f355fd52877e0666d05e0.zip |
- Support for multiple IdP
- IdP discovery service
- add a dimple built-in IdP discovery mechanism: send HTTP GET on ProviderID
URL. If we get HTTP 200, the IdP is selected
git-svn-id: https://modmellon.googlecode.com/svn/trunk@44 a716ebb1-153a-0410-b759-cfb97c6a1b53
-rw-r--r-- | auth_mellon.h | 12 | ||||
-rw-r--r-- | auth_mellon_config.c | 123 | ||||
-rw-r--r-- | auth_mellon_handler.c | 359 | ||||
-rw-r--r-- | auth_mellon_httpclient.c | 51 | ||||
-rw-r--r-- | mod_auth_mellon.c | 1 |
5 files changed, 473 insertions, 73 deletions
diff --git a/auth_mellon.h b/auth_mellon.h index b1880eb..57e5ffb 100644 --- a/auth_mellon.h +++ b/auth_mellon.h @@ -49,6 +49,7 @@ #include "apr_md5.h" #include "apr_file_info.h" #include "apr_file_io.h" +#include "apr_xml.h" #include "ap_config.h" #include "httpd.h" @@ -116,7 +117,6 @@ typedef enum { am_decoder_feide, } am_decoder_t; - typedef struct am_dir_cfg_rec { /* enable_mellon is used to enable auth_mellon for a location. */ @@ -144,7 +144,7 @@ typedef struct am_dir_cfg_rec { const char *sp_metadata_file; const char *sp_private_key_file; const char *sp_cert_file; - const char *idp_metadata_file; + apr_hash_t *idp_metadata_files; const char *idp_public_key_file; const char *idp_ca_file; @@ -157,6 +157,9 @@ typedef struct am_dir_cfg_rec { /* Login path for IdP initiated logins */ const char *login_path; + /* IdP discovery service */ + const char *discovery_url; + /* Mutex to prevent us from creating several lasso server objects. */ apr_thread_mutex_t *server_mutex; /* Cached lasso server object. */ @@ -242,8 +245,9 @@ int am_check_uid(request_rec *r); int am_handle_metadata(request_rec *r); -int am_httpclient_get(request_rec *r, const char *uri, - void **buffer, apr_size_t *size); +int am_httpclient_get(request_rec *r, const char *uri, + void **buffer, apr_size_t *size, + apr_time_t timeout, long *status); int am_httpclient_post(request_rec *r, const char *uri, const void *post_data, apr_size_t post_length, const char *content_type, diff --git a/auth_mellon_config.c b/auth_mellon_config.c index 767663f..6e805e1 100644 --- a/auth_mellon_config.c +++ b/auth_mellon_config.c @@ -83,6 +83,103 @@ static const char *am_set_filestring_slot(cmd_parms *cmd, } +/* This function extracts an IdP ProviderID from metadata + * + * Parameters: + * apr_pool_t *p Pool to allocate temporary items from. + * server_rec *s The server. + * const char *file File containing metadata. + * const char **provider The providerID + * + * Returns: + * NULL on success or an error string on failure. + * + */ +static const char *am_get_proovider_id(apr_pool_t *p, + server_rec *s, + const char *file, + const char **provider) +{ + char *data; + apr_xml_parser *xp; + apr_xml_doc *xd; + apr_xml_attr *xa; + char error[1024]; + + *provider = NULL; + + /* + * Get the data + */ + if ((data = am_getfile(p, s, file)) == NULL) + return apr_psprintf(p, "Cannot read file %s", file); + + /* + * Parse + */ + xp = apr_xml_parser_create(p); + if (apr_xml_parser_feed(xp, data, strlen(data)) != 0) + return apr_psprintf(p, "Cannot parse %s: %s", file, + apr_xml_parser_geterror(xp, error, sizeof(error))); + + if (apr_xml_parser_done(xp, &xd) != 0) + return apr_psprintf(p, "Parse error %s: %s", file, + apr_xml_parser_geterror(xp, error, sizeof(error))); + + /* + * Extract /EntityDescriptor@EntityID + */ + if (strcasecmp(xd->root->name, "EntityDescriptor") != 0) + return apr_psprintf(p, "<EntityDescriptor> is not root in %s", file); + + for (xa = xd->root->attr; xa; xa = xa->next) + if (strcasecmp(xa->name, "entityID") == 0) + break; + + if (xa == NULL) + return apr_psprintf(p, "entityID not found in %s", file); + + *provider = xa->value; + return NULL; +} + +/* This function handles configuration directives which set an + * idp related slot in the module configuration. + * + * Parameters: + * cmd_parms *cmd The command structure for this configuration + * directive. + * void *struct_ptr Pointer to the current directory configuration. + * NULL if we are not in a directory configuration. + * const char *arg The string argument following this configuration + * directive in the configuraion file. + * + * Returns: + * NULL on success or an error string on failure. + */ +static const char *ap_set_idp_string_slot(cmd_parms *cmd, + void *struct_ptr, + const char *arg) +{ + server_rec *s = cmd->server; + apr_pool_t *pconf = s->process->pconf; + am_dir_cfg_rec *cfg = (am_dir_cfg_rec *)struct_ptr; + const char *error; + const char *provider_id; + + if ((error = am_get_proovider_id(cmd->pool, s, + arg, &provider_id)) != NULL) + return apr_psprintf(cmd->pool, "%s - %s", cmd->cmd->name, error); + + apr_hash_set(cfg->idp_metadata_files, + apr_pstrdup(pconf, provider_id), + APR_HASH_KEY_STRING, + apr_pstrdup(pconf, arg)); + + return NULL; +} + + /* This function handles configuration directives which set a string * slot in the module configuration. * @@ -431,8 +528,8 @@ const command_rec auth_mellon_commands[] = { ), AP_INIT_TAKE1( "MellonIdPMetadataFile", - ap_set_string_slot, - (void *)APR_OFFSETOF(am_dir_cfg_rec, idp_metadata_file), + ap_set_idp_string_slot, + NULL, OR_AUTHCFG, "Full path to xml metadata file for the IdP." ), @@ -459,6 +556,13 @@ const command_rec auth_mellon_commands[] = { " Default value is \"/\"." ), AP_INIT_TAKE1( + "MellonDiscoveryURL", + ap_set_string_slot, + (void *)APR_OFFSETOF(am_dir_cfg_rec, discovery_url), + OR_AUTHCFG, + "The URL of IdP discovery service. Default is unset." + ), + AP_INIT_TAKE1( "MellonEndpointPath", am_set_endpoint_path, NULL, @@ -506,11 +610,11 @@ void *auth_mellon_dir_config(apr_pool_t *p, char *d) dir->sp_metadata_file = NULL; dir->sp_private_key_file = NULL; dir->sp_cert_file = NULL; - dir->idp_metadata_file = NULL; + dir->idp_metadata_files = apr_hash_make(p); dir->idp_public_key_file = NULL; dir->idp_ca_file = NULL; dir->login_path = default_login_path; - + dir->discovery_url = NULL; apr_thread_mutex_create(&dir->server_mutex, APR_THREAD_MUTEX_DEFAULT, p); @@ -602,9 +706,10 @@ void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add) add_cfg->sp_cert_file : base_cfg->sp_cert_file); - new_cfg->idp_metadata_file = (add_cfg->idp_metadata_file ? - add_cfg->idp_metadata_file : - base_cfg->idp_metadata_file); + new_cfg->idp_metadata_files = apr_hash_copy(p, + (apr_hash_count(add_cfg->idp_metadata_files) > 0) ? + add_cfg->idp_metadata_files : + base_cfg->idp_metadata_files); new_cfg->idp_public_key_file = (add_cfg->idp_public_key_file ? add_cfg->idp_public_key_file : @@ -618,6 +723,10 @@ void *auth_mellon_dir_merge(apr_pool_t *p, void *base, void *add) add_cfg->login_path : base_cfg->login_path); + new_cfg->discovery_url = (add_cfg->discovery_url ? + add_cfg->discovery_url : + base_cfg->discovery_url); + apr_thread_mutex_create(&new_cfg->server_mutex, APR_THREAD_MUTEX_DEFAULT, p); new_cfg->server = NULL; diff --git a/auth_mellon_handler.c b/auth_mellon_handler.c index da0fc61..ad76027 100644 --- a/auth_mellon_handler.c +++ b/auth_mellon_handler.c @@ -30,7 +30,6 @@ #endif /* HAVE_lasso_server_new_from_buffers */ -#ifdef HAVE_lasso_server_new_from_buffers /* This function produces the endpoint URL * * Parameters: @@ -69,6 +68,7 @@ static char *am_get_endpoint_url(request_rec *r) port, cfg->endpoint_path); } +#ifdef HAVE_lasso_server_new_from_buffers /* This function generates metadata * * Parameters: @@ -132,12 +132,213 @@ static char *am_generate_metadata(apr_pool_t *p, request_rec *r) } #endif /* HAVE_lasso_server_new_from_buffers */ -static LassoServer *am_get_lasso_server(request_rec *r) +/* This function returns the first configured IdP + * + * Parameters: + * request_rec *r The request we received. + * + * Returns: + * the providerID, or NULL if an error occured + */ +static const char *am_first_idp(request_rec *r) { - am_dir_cfg_rec *cfg; - gint ret; + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); + apr_hash_index_t *index; + const char *provider_id; + apr_ssize_t len; + void *idp_metadata_file; + + index = apr_hash_first(r->pool, cfg->idp_metadata_files); + if (index == NULL) + return NULL; + + apr_hash_this(index, (const void **)&provider_id, + &len, &idp_metadata_file); + return provider_id; +} + +/* This returns built-in IdP discovery timeout + * + * Parameters: + * request_rec *r The request we received. + * + * Returns: + * the timeout, -1 if not enabled. + */ +static long am_builtin_discovery_timeout(request_rec *r) +{ + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); + const char *builtin = "builtin:get-metadata"; + const char *timeout = "?timeout="; + const char *cp; + const long default_timeout = 1L; + + if ((cfg->discovery_url == NULL) || + (strncmp(cfg->discovery_url, builtin, strlen(builtin)) != 0)) + return -1; + + cp = cfg->discovery_url + strlen(builtin); + if (strncmp(cp, timeout, strlen(timeout)) != 0) + return default_timeout; + + cp += strlen(timeout); + return atoi(cp); +} + +/* This function selects an IdP and returns its provider_id + * + * Parameters: + * request_rec *r The request we received. + * + * Returns: + * the provider_id, or NULL if an error occured + */ +static const char *am_get_idp(request_rec *r) +{ + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); + const char *idp_provider_id; + const char *idp_metadata_file; + apr_hash_index_t *index; + long timeout; + + /* + * If we have a single IdP, return that one. + */ + if (apr_hash_count(cfg->idp_metadata_files) == 1) + return am_first_idp(r); + + /* + * If IdP discovery handed us an IdP, try to use it. + */ + idp_provider_id = am_extract_query_parameter(r->pool, r->args, "IdP"); + if (idp_provider_id != NULL) { + int rc; + + rc = am_urldecode((char *)idp_provider_id); + if (rc != OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, + "Could not urldecode IdP discovery value."); + idp_provider_id = NULL; + } else { + idp_metadata_file = apr_hash_get(cfg->idp_metadata_files, + idp_provider_id, + APR_HASH_KEY_STRING); + if (idp_metadata_file == NULL) + idp_provider_id = NULL; + } + + /* + * If we do not know about it, fall back to default. + */ + if (idp_provider_id == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + "IdP discovery returned unknown or inexistant IdP"); + idp_provider_id = am_first_idp(r); + } + + return idp_provider_id; + } + + /* + * If built-in IdP discovery is not configured, return default. + */ + timeout = am_builtin_discovery_timeout(r); + if (timeout == -1) + return am_first_idp(r); + + /* + * Otherwise, proceed with built-in IdP discovery: + * send probes for all configures IdP to check availability. + * The first to answer is chosen. On error, use default. + */ + for (index = apr_hash_first(r->pool, cfg->idp_metadata_files); + index; + index = apr_hash_next(index)) { + void *buffer; + apr_size_t len; + apr_ssize_t slen; + long status; + + apr_hash_this(index, + (const void **)&idp_provider_id, + &slen, + (void *)&idp_metadata_file); + + status = 0; + if (am_httpclient_get(r, idp_provider_id, &buffer, &len, + timeout, &status) != OK) + continue; + + if (status != HTTP_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Cannot probe %s: IdP returned HTTP %ld", + idp_provider_id, status); + continue; + } + + /* We got some succes */ + return idp_provider_id; + } + + /* + * No IdP answered, use default + * Perhaps we should redirect to an error page instead. + */ + return am_first_idp(r); +} + +/* + * This function loads all IdP metadata in a lasso server + * + * Parameters: + * request_rec *r The request we received. + * + * Returns: + * number of loaded providers + */ +static int am_server_add_providers(request_rec *r) +{ + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); + const char *idp_metadata_file; + const char *idp_public_key_file; + apr_hash_index_t *index; + int count = 0; + + if (apr_hash_count(cfg->idp_metadata_files) == 1) + idp_public_key_file = cfg->idp_public_key_file; + else + idp_public_key_file = NULL; + + for (index = apr_hash_first(r->pool, cfg->idp_metadata_files); + index; + index = apr_hash_next(index)) { + const char *idp_provider_id; + apr_ssize_t len; + int ret; + + apr_hash_this(index, (const void **)&idp_provider_id, + &len, (void *)&idp_metadata_file); + + + ret = lasso_server_add_provider(cfg->server, LASSO_PROVIDER_ROLE_IDP, + idp_metadata_file, + idp_public_key_file, + cfg->idp_ca_file); + if (ret != 0) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Error adding IdP \"%s\" to lasso server object.", + idp_provider_id); + } else { + count++; + } + } + + return count; +} - cfg = am_get_dir_cfg(r); +static LassoServer *am_get_lasso_server(request_rec *r) +{ + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); apr_thread_mutex_lock(cfg->server_mutex); if(cfg->server == NULL) { @@ -166,12 +367,7 @@ static LassoServer *am_get_lasso_server(request_rec *r) return NULL; } - - ret = lasso_server_add_provider(cfg->server, LASSO_PROVIDER_ROLE_IDP, - cfg->idp_metadata_file, - cfg->idp_public_key_file, - cfg->idp_ca_file); - if(ret != 0) { + if (am_server_add_providers(r) == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Error adding IdP to lasso server object. Please" " verify the following configuration directives:" @@ -1452,59 +1648,58 @@ int am_handle_metadata(request_rec *r) } -/* This function takes a request for an endpoint and passes it on to the - * correct handler function. - * - * Parameters: - * request_rec *r The request we are currently handling. - * - * Returns: - * The return value of the endpoint handler function, - * or HTTP_NOT_FOUND if we don't have a handler for the requested - * endpoint. - */ -static int am_endpoint_handler(request_rec *r) -{ - const char *endpoint; - am_dir_cfg_rec *dir = am_get_dir_cfg(r); - - /* r->uri starts with cfg->endpoint_path, so we can find the endpoint - * by extracting the string following chf->endpoint_path. - */ - endpoint = &r->uri[strlen(dir->endpoint_path)]; - - - if(!strcmp(endpoint, "postResponse")) { - return am_handle_post_reply(r); - } else if(!strcmp(endpoint, "artifactResponse")) { - return am_handle_artifact_reply(r); - } else if(!strcmp(endpoint, "metadata")) { - return OK; - } else if(!strcmp(endpoint, "logout") - || !strcmp(endpoint, "logoutRequest")) { - /* logoutRequest is included for backwards-compatibility - * with version 0.0.6 and older. - */ - return am_handle_logout(r); - } else { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Endpoint \"%s\" not handled by mod_auth_mellon.", - endpoint); - - return HTTP_NOT_FOUND; - } - -} - - static int am_auth_new_ticket(request_rec *r) { + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); LassoServer *server; LassoLogin *login; LassoSamlp2AuthnRequest *request; gint ret; char *redirect_to; + const char *relay_state; + relay_state = am_reconstruct_url(r); + + /* Check if IdP discovery is in use and no IdP was selected yet */ + if ((cfg->discovery_url != NULL) && + (am_builtin_discovery_timeout(r) == -1) && /* no built-in discovery */ + (am_extract_query_parameter(r->pool, r->args, "IdP") == NULL)) { + char *discovery_url; + char *return_url; + char *endpoint = am_get_endpoint_url(r); + char *sep; + + /* If discovery URL already has a ? we append a & */ + sep = (strchr(cfg->discovery_url, '?')) ? "&" : "?"; + + return_url = apr_psprintf(r->pool, "%sauth?ReturnTo=%s", + endpoint, + am_urlencode(r->pool, relay_state)); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "return_url = %s", return_url); + discovery_url = apr_psprintf(r->pool, "%s%sentityID=%smetadata&" + "return=%s&returnIDParam=IdP", + cfg->discovery_url, sep, + am_urlencode(r->pool, endpoint), + am_urlencode(r->pool, return_url)); + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "discovery_url = %s", discovery_url); + apr_table_setn(r->headers_out, "Location", discovery_url); + return HTTP_SEE_OTHER; + } + + /* If IdP discovery is in use and we have an IdP selected, + * set the relay_state + */ + if ((cfg->discovery_url != NULL) && + (am_builtin_discovery_timeout(r) == -1)) { /* no built-in discovery */ + char *return_url; + + return_url = am_extract_query_parameter(r->pool, r->args, "ReturnTo"); + if ((return_url != NULL) && am_urldecode((char *)return_url) == 0) + relay_state = return_url; + } /* Add cookie for cookie test. We know that we should have * a valid cookie when we return from the IdP after SP-initiated @@ -1525,7 +1720,7 @@ static int am_auth_new_ticket(request_rec *r) return HTTP_INTERNAL_SERVER_ERROR; } - ret = lasso_login_init_authn_request(login, NULL, + ret = lasso_login_init_authn_request(login, am_get_idp(r), LASSO_HTTP_METHOD_REDIRECT); if(ret != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, @@ -1552,7 +1747,7 @@ static int am_auth_new_ticket(request_rec *r) LASSO_SAMLP2_REQUEST_ABSTRACT(request)->Consent = g_strdup(LASSO_SAML2_CONSENT_IMPLICIT); - LASSO_PROFILE(login)->msg_relayState = g_strdup(am_reconstruct_url(r)); + LASSO_PROFILE(login)->msg_relayState = g_strdup(relay_state); ret = lasso_login_build_authn_request_msg(login); if(ret != 0) { @@ -1588,6 +1783,53 @@ static int am_auth_new_ticket(request_rec *r) return HTTP_SEE_OTHER; } +/* This function takes a request for an endpoint and passes it on to the + * correct handler function. + * + * Parameters: + * request_rec *r The request we are currently handling. + * + * Returns: + * The return value of the endpoint handler function, + * or HTTP_NOT_FOUND if we don't have a handler for the requested + * endpoint. + */ +static int am_endpoint_handler(request_rec *r) +{ + const char *endpoint; + am_dir_cfg_rec *dir = am_get_dir_cfg(r); + + /* r->uri starts with cfg->endpoint_path, so we can find the endpoint + * by extracting the string following chf->endpoint_path. + */ + endpoint = &r->uri[strlen(dir->endpoint_path)]; + + + if(!strcmp(endpoint, "postResponse")) { + return am_handle_post_reply(r); + } else if(!strcmp(endpoint, "artifactResponse")) { + return am_handle_artifact_reply(r); + } else if(!strcmp(endpoint, "auth")) { + return am_auth_new_ticket(r); + } else if(!strcmp(endpoint, "metadata")) { + return OK; + } else if(!strcmp(endpoint, "logout") + || !strcmp(endpoint, "logoutRequest")) { + /* logoutRequest is included for backwards-compatibility + * with version 0.0.6 and older. + */ + return am_handle_logout(r); + } else { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Endpoint \"%s\" not handled by mod_auth_mellon.", + endpoint); + + return HTTP_NOT_FOUND; + } + +} + + int am_auth_mellon_user(request_rec *r) { @@ -1606,7 +1848,6 @@ int am_auth_mellon_user(request_rec *r) return DECLINED; } - /* Disable all caching within this location. */ am_set_nocache(r); diff --git a/auth_mellon_httpclient.c b/auth_mellon_httpclient.c index 6f2f04b..5d274ba 100644 --- a/auth_mellon_httpclient.c +++ b/auth_mellon_httpclient.c @@ -246,6 +246,7 @@ static CURL *am_httpclient_init_curl(request_rec *r, const char *uri, am_hc_block_header_t *bh, char *curl_error) { + am_dir_cfg_rec *cfg = am_get_dir_cfg(r); CURL *curl; CURLcode res; @@ -311,6 +312,17 @@ static CURL *am_httpclient_init_curl(request_rec *r, const char *uri, goto cleanup_fail; } + /* If we have a CA configured, try to use it */ + if (cfg->idp_ca_file != NULL) { + res = curl_easy_setopt(curl, CURLOPT_CAINFO, cfg->idp_ca_file); + if(res != CURLE_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Failed to set SSL CA info %s:" + " [%u] %s", cfg->idp_ca_file, res, curl_error); + goto cleanup_fail; + } + } + /* Enable fail on http error. */ res = curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); if(res != CURLE_OK) { @@ -359,7 +371,7 @@ static CURL *am_httpclient_init_curl(request_rec *r, const char *uri, } -/* This function downloads data from a specified URI. +/* This function downloads data from a specified URI, with specified timeout * * Parameters: * request_rec *r The apache request this download is associated @@ -371,13 +383,16 @@ static CURL *am_httpclient_init_curl(request_rec *r, const char *uri, * apr_size_t *size This is a pointer to where we will store the length * of the downloaded data, not including the * null-terminator we add. This parameter can be NULL. + * apr_time_t timeout Timeout in seconds, 0 for no timeout. + * long *status Pointer to HTTP status code. * * Returns: * OK on success, or HTTP_INTERNAL_SERVER_ERROR on failure. On failure we * will write a log message describing the error. */ int am_httpclient_get(request_rec *r, const char *uri, - void **buffer, apr_size_t *size) + void **buffer, apr_size_t *size, + apr_time_t timeout, long *status) { am_hc_block_header_t bh; CURL *curl; @@ -393,15 +408,45 @@ int am_httpclient_get(request_rec *r, const char *uri, return HTTP_INTERNAL_SERVER_ERROR; } + res = curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); + if(res != CURLE_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Failed to download data from the uri \"%s\", " + "cannot set timeout to %ld: [%u] %s", + uri, (long)timeout, res, curl_error); + goto cleanup_fail; + } + + res = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + if(res != CURLE_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Failed to download data from the uri \"%s\", " + "cannot set connect timeout to %ld: [%u] %s", + uri, (long)timeout, res, curl_error); + goto cleanup_fail; + } + /* Do the download. */ res = curl_easy_perform(curl); if(res != CURLE_OK) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "Failed to download data from the uri \"%s\": [%u] %s", + "Failed to download data from the uri \"%s\", " + "transaction aborted: [%u] %s", uri, res, curl_error); goto cleanup_fail; } + if (status != NULL) { + res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status); + if(res != CURLE_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "Failed to download data from the uri \"%s\", " + "no status report: [%u] %s", + uri, res, curl_error); + goto cleanup_fail; + } + } + /* Free the curl object. */ curl_easy_cleanup(curl); diff --git a/mod_auth_mellon.c b/mod_auth_mellon.c index 1697a7b..98ecfce 100644 --- a/mod_auth_mellon.c +++ b/mod_auth_mellon.c @@ -47,6 +47,7 @@ static apr_status_t am_global_kill(void *p) server_rec *s = (server_rec *) p; am_mod_cfg_rec *m = am_get_mod_cfg(s); + if (m->cache) { /* Destroy the shared memory for session data. */ apr_shm_destroy(m->cache); |