251 lines
8.5 KiB
C
251 lines
8.5 KiB
C
/*
|
|
*
|
|
* mod_auth_mellon.c: an authentication apache module
|
|
* Copyright © 2003-2007 UNINETT (http://www.uninett.no/)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include "auth_mellon.h"
|
|
|
|
#include <curl/curl.h>
|
|
|
|
#ifdef APLOG_USE_MODULE
|
|
APLOG_USE_MODULE(auth_mellon);
|
|
#endif
|
|
|
|
/* This function is called after the configuration of the server is parsed
|
|
* (it's a post-config hook).
|
|
*
|
|
* It initializes the shared memory and the mutex which is used to protect
|
|
* the shared memory.
|
|
*
|
|
* Parameters:
|
|
* apr_pool_t *conf The configuration pool. Valid as long as this
|
|
* configuration is valid.
|
|
* apr_pool_t *log A pool for memory which is cleared after each read
|
|
* through the config files.
|
|
* apr_pool_t *tmp A pool for memory which will be destroyed after
|
|
* all the post_config hooks are run.
|
|
* server_rec *s The current server record.
|
|
*
|
|
* Returns:
|
|
* OK on successful initialization, or !OK on failure.
|
|
*/
|
|
static int am_global_init(apr_pool_t *conf, apr_pool_t *log,
|
|
apr_pool_t *tmp, server_rec *s)
|
|
{
|
|
apr_size_t mem_size;
|
|
am_mod_cfg_rec *mod;
|
|
int rv;
|
|
const char userdata_key[] = "auth_mellon_init";
|
|
char buffer[512];
|
|
void *data;
|
|
|
|
/* Apache tests loadable modules by loading them (as is the only way).
|
|
* This has the effect that all modules are loaded and initialised twice,
|
|
* and we just want to initialise shared memory and mutexes when the
|
|
* module loads for real!
|
|
*
|
|
* To accomplish this, we store a piece of data as userdata in the
|
|
* process pool the first time the function is run. This data can be
|
|
* detected on all subsequent runs, and then we know that this isn't the
|
|
* first time this function runs.
|
|
*/
|
|
apr_pool_userdata_get(&data, userdata_key, s->process->pool);
|
|
if (!data) {
|
|
/* This is the first time this function is run. */
|
|
apr_pool_userdata_set((const void *)1, userdata_key,
|
|
apr_pool_cleanup_null, s->process->pool);
|
|
return OK;
|
|
}
|
|
|
|
mod = am_get_mod_cfg(s);
|
|
|
|
/* If the session store is initialized then we can't change it. */
|
|
if(mod->cache != NULL) {
|
|
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s,
|
|
"auth_mellon session store already initialized -"
|
|
" reinitialization skipped.");
|
|
return OK;
|
|
}
|
|
|
|
/* Copy from the variables set by the configuration file into variables
|
|
* which will be set only once. We do this to avoid confusion if the user
|
|
* tries to change the parameters of the session store after it is
|
|
* initialized.
|
|
*/
|
|
mod->init_cache_size = mod->cache_size;
|
|
mod->init_lock_file = apr_pstrdup(conf, mod->lock_file);
|
|
mod->init_entry_size = mod->entry_size;
|
|
if (mod->init_entry_size < AM_CACHE_MIN_ENTRY_SIZE) {
|
|
mod->init_entry_size = AM_CACHE_MIN_ENTRY_SIZE;
|
|
}
|
|
|
|
/* find out the memory size of the cache */
|
|
mem_size = mod->init_entry_size * mod->init_cache_size;
|
|
|
|
|
|
/* Create the shared memory, exit if it fails. */
|
|
rv = apr_shm_create(&(mod->cache), mem_size, NULL, conf);
|
|
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
|
|
"shm_create: Error [%d] \"%s\"", rv,
|
|
apr_strerror(rv, buffer, sizeof(buffer)));
|
|
return !OK;
|
|
}
|
|
|
|
/* Initialize the session table. */
|
|
am_cache_init(mod);
|
|
|
|
/* Now create the mutex that we need for locking the shared memory, then
|
|
* test for success. we really need this, so we exit on failure. */
|
|
rv = apr_global_mutex_create(&(mod->lock),
|
|
mod->init_lock_file,
|
|
APR_LOCK_DEFAULT,
|
|
conf);
|
|
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
|
|
"mutex_create: Error [%d] \"%s\"", rv,
|
|
apr_strerror(rv, buffer, sizeof(buffer)));
|
|
return !OK;
|
|
}
|
|
|
|
#ifdef AP_NEED_SET_MUTEX_PERMS
|
|
/* On some platforms the mutex is implemented as a file. To allow child
|
|
* processes running as a different user to open it, it is necessary to
|
|
* change the permissions on it. */
|
|
rv = ap_unixd_set_global_mutex_perms(mod->lock);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
|
|
"Failed to set permissions on session table lock;"
|
|
" check User and Group directives");
|
|
return rv;
|
|
}
|
|
#endif
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
/* This function is run when each child process of apache starts.
|
|
* apr_global_mutex_child_init must be run on the session data mutex for
|
|
* every child process of apache.
|
|
*
|
|
* Parameters:
|
|
* apr_pool_t *p This pool is for data associated with this
|
|
* child process.
|
|
* server_rec *s The server record for the current server.
|
|
*
|
|
* Returns:
|
|
* Nothing.
|
|
*/
|
|
static void am_child_init(apr_pool_t *p, server_rec *s)
|
|
{
|
|
am_mod_cfg_rec *m = am_get_mod_cfg(s);
|
|
apr_status_t rv;
|
|
CURLcode curl_res;
|
|
|
|
/* Reinitialize the mutex for the child process. */
|
|
rv = apr_global_mutex_child_init(&(m->lock), m->init_lock_file, p);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, rv, s,
|
|
"Child process could not connect to mutex");
|
|
}
|
|
|
|
/* lasso_init() must be run before any other lasso-functions. */
|
|
lasso_init();
|
|
|
|
/* curl_global_init() should be called before any other curl
|
|
* function. Relying on curl_easy_init() to call curl_global_init()
|
|
* isn't thread safe.
|
|
*/
|
|
curl_res = curl_global_init(CURL_GLOBAL_SSL);
|
|
if(curl_res != CURLE_OK) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
|
|
"Failed to initialize curl library: %u", curl_res);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static int am_create_request(request_rec *r)
|
|
{
|
|
am_req_cfg_rec *req_cfg;
|
|
|
|
req_cfg = apr_pcalloc(r->pool, sizeof(am_req_cfg_rec));
|
|
|
|
req_cfg->cookie_value = NULL;
|
|
#ifdef HAVE_ECP
|
|
req_cfg->ecp_authn_req = false;
|
|
#endif /* HAVE_ECP */
|
|
#ifdef ENABLE_DIAGNOSTICS
|
|
req_cfg->diag_emitted = false;
|
|
#endif
|
|
|
|
ap_set_module_config(r->request_config, &auth_mellon_module, req_cfg);
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
static void register_hooks(apr_pool_t *p)
|
|
{
|
|
/* Our handler needs to run before mod_proxy so that it can properly
|
|
* return ECP AuthnRequest messages when running as a reverse proxy.
|
|
* See: https://github.com/Uninett/mod_auth_mellon/pull/196
|
|
*/
|
|
static const char * const run_handler_before[]={ "mod_proxy.c", NULL };
|
|
|
|
ap_hook_access_checker(am_auth_mellon_user, NULL, NULL, APR_HOOK_MIDDLE);
|
|
ap_hook_check_user_id(am_check_uid, NULL, NULL, APR_HOOK_MIDDLE);
|
|
ap_hook_post_config(am_global_init, NULL, NULL, APR_HOOK_MIDDLE);
|
|
ap_hook_child_init(am_child_init, NULL, NULL, APR_HOOK_MIDDLE);
|
|
ap_hook_create_request(am_create_request, NULL, NULL, APR_HOOK_MIDDLE);
|
|
|
|
/* Add the hook to handle requests to the mod_auth_mellon endpoint.
|
|
*
|
|
* This is APR_HOOK_FIRST because we do not expect nor require users
|
|
* to add a SetHandler option for the endpoint. Instead, simply
|
|
* setting MellonEndpointPath should be enough.
|
|
*
|
|
* Therefore this hook must run before any handler that may check
|
|
* r->handler and decide that it is the only handler for this URL.
|
|
*/
|
|
ap_hook_handler(am_handler, NULL, run_handler_before, APR_HOOK_FIRST);
|
|
|
|
#ifdef ENABLE_DIAGNOSTICS
|
|
ap_hook_open_logs(am_diag_log_init,NULL,NULL,APR_HOOK_MIDDLE);
|
|
ap_hook_log_transaction(am_diag_finalize_request,NULL,NULL,APR_HOOK_REALLY_LAST);
|
|
#endif
|
|
}
|
|
|
|
|
|
module AP_MODULE_DECLARE_DATA auth_mellon_module =
|
|
{
|
|
STANDARD20_MODULE_STUFF,
|
|
auth_mellon_dir_config,
|
|
auth_mellon_dir_merge,
|
|
auth_mellon_server_config,
|
|
auth_mellon_srv_merge,
|
|
auth_mellon_commands,
|
|
register_hooks
|
|
};
|
|
|