1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
/*
*
* 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>
/* 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 */
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);
return;
}
module AP_MODULE_DECLARE_DATA auth_mellon_module =
{
STANDARD20_MODULE_STUFF,
auth_mellon_dir_config,
auth_mellon_dir_merge,
auth_mellon_server_config,
NULL,
auth_mellon_commands,
register_hooks
};
|