Apache HTTPD
mod_authn_socache.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_strings.h"
18#include "apr_md5.h" /* for apr_password_validate */
19
20#include "ap_config.h"
21#include "ap_provider.h"
22#include "httpd.h"
23#include "http_config.h"
24#include "http_core.h"
25#include "http_log.h"
26#include "http_protocol.h"
27#include "http_request.h"
28
29#include "mod_auth.h"
30
31#include "ap_socache.h"
32#include "util_mutex.h"
33#include "apr_optional.h"
34
35module AP_MODULE_DECLARE_DATA authn_socache_module;
36
42
43/* FIXME:
44 * I think the cache and mutex should be global
45 */
49static const char *const authn_cache_id = "authn-socache";
50static int configured;
51
60
69
71{
74 if (rv != APR_SUCCESS) {
76 "failed to register %s mutex", authn_cache_id);
77 return 500; /* An HTTP status would be a misnomer! */
78 }
82 configured = 0;
83 return OK;
84}
85
88{
89 apr_status_t rv;
90 static struct ap_socache_hints authn_cache_hints = {64, 32, 60000000};
91 const char *errmsg;
92
93 if (!configured) {
94 return OK; /* don't waste the overhead of creating mutex & cache */
95 }
96 if (socache_provider == NULL) {
98 "Please select a socache provider with AuthnCacheSOCache "
99 "(no default found on this platform). Maybe you need to "
100 "load mod_socache_shmcb or another socache module first");
101 return 500; /* An HTTP status would be a misnomer! */
102 }
103
104 /* We have socache_provider, but do not have socache_instance. This should
105 * happen only when using "default" socache_provider, so create default
106 * socache_instance in this case. */
107 if (socache_instance == NULL) {
109 ptmp, pconf);
110 if (errmsg) {
112 "failed to create mod_socache_shmcb socache "
113 "instance: %s", errmsg);
114 return 500;
115 }
116 }
117
119 authn_cache_id, NULL, s, pconf, 0);
120 if (rv != APR_SUCCESS) {
122 "failed to create %s mutex", authn_cache_id);
123 return 500; /* An HTTP status would be a misnomer! */
124 }
126
129 if (rv != APR_SUCCESS) {
131 "failed to initialise %s cache", authn_cache_id);
132 return 500; /* An HTTP status would be a misnomer! */
133 }
135 return OK;
136}
137
139{
140 const char *lock;
141 apr_status_t rv;
142 if (!configured) {
143 return; /* don't waste the overhead of creating mutex & cache */
144 }
147 if (rv != APR_SUCCESS) {
149 "failed to initialise mutex in child_init");
150 }
151}
152
153static const char *authn_cache_socache(cmd_parms *cmd, void *CFG,
154 const char *arg)
155{
156 const char *errmsg = ap_check_cmd_context(cmd, GLOBAL_ONLY);
157 const char *sep, *name;
158
159 if (errmsg)
160 return errmsg;
161
162 /* Argument is of form 'name:args' or just 'name'. */
163 sep = ap_strchr_c(arg, ':');
164 if (sep) {
165 name = apr_pstrmemdup(cmd->pool, arg, sep - arg);
166 sep++;
167 }
168 else {
169 name = arg;
170 }
171
174 if (socache_provider == NULL) {
175 errmsg = apr_psprintf(cmd->pool,
176 "Unknown socache provider '%s'. Maybe you need "
177 "to load the appropriate socache module "
178 "(mod_socache_%s?)", arg, arg);
179 }
180 else {
182 cmd->temp_pool, cmd->pool);
183 }
184
185 if (errmsg) {
186 errmsg = apr_psprintf(cmd->pool, "AuthnCacheSOCache: %s", errmsg);
187 }
188 return errmsg;
189}
190
191static const char *authn_cache_enable(cmd_parms *cmd, void *CFG)
192{
193 const char *errmsg = ap_check_cmd_context(cmd, GLOBAL_ONLY);
194 configured = 1;
195 return errmsg;
196}
197
198static const char *const directory = "directory";
200{
202 ret->timeout = apr_time_from_sec(300);
203 ret->providers = NULL;
204 ret->context = directory;
205 return ret;
206}
207
208/* not sure we want this. Might be safer to document use-all-or-none */
209static void* authn_cache_dircfg_merge(apr_pool_t *pool, void *BASE, void *ADD)
210{
212 authn_cache_dircfg *add = ADD;
214 /* preserve context and timeout if not defaults */
215 if (add->context == directory) {
216 ret->context = base->context;
217 }
218 if (add->timeout == apr_time_from_sec(300)) {
219 ret->timeout = base->timeout;
220 }
221 if (add->providers == NULL) {
222 ret->providers = base->providers;
223 }
224 return ret;
225}
226
227static const char *authn_cache_setprovider(cmd_parms *cmd, void *CFG,
228 const char *arg)
229{
230 authn_cache_dircfg *cfg = CFG;
231 if (cfg->providers == NULL) {
232 cfg->providers = apr_array_make(cmd->pool, 4, sizeof(const char*));
233 }
234 APR_ARRAY_PUSH(cfg->providers, const char*) = arg;
235 configured = 1;
236 return NULL;
237}
238
239static const char *authn_cache_timeout(cmd_parms *cmd, void *CFG,
240 const char *arg)
241{
242 authn_cache_dircfg *cfg = CFG;
243 int secs = atoi(arg);
245 return NULL;
246}
247
249{
250 /* global stuff: cache and mutex */
251 AP_INIT_TAKE1("AuthnCacheSOCache", authn_cache_socache, NULL, RSRC_CONF,
252 "socache provider for authn cache"),
253 AP_INIT_NO_ARGS("AuthnCacheEnable", authn_cache_enable, NULL, RSRC_CONF,
254 "enable socache configuration in htaccess even if not enabled anywhere else"),
255 /* per-dir stuff */
256 AP_INIT_ITERATE("AuthnCacheProvideFor", authn_cache_setprovider, NULL,
257 OR_AUTHCFG, "Determine what authn providers to cache for"),
258 AP_INIT_TAKE1("AuthnCacheTimeout", authn_cache_timeout, NULL,
259 OR_AUTHCFG, "Timeout (secs) for cached credentials"),
260 AP_INIT_TAKE1("AuthnCacheContext", ap_set_string_slot,
262 ACCESS_CONF, "Context for authn cache"),
263 {NULL}
264};
265
266static const char *construct_key(request_rec *r, const char *context,
267 const char *user, const char *realm)
268{
269 /* handle "special" context values */
270 if (!strcmp(context, directory)) {
271 /* FIXME: are we at risk of this blowing up? */
272 char *new_context;
273 char *slash = strrchr(r->uri, '/');
275 strlen(r->server->server_hostname) + 1);
279 }
280 else if (!strcmp(context, "server")) {
282 }
283 /* any other context value is literal */
284
285 if (realm == NULL) { /* basic auth */
286 return apr_pstrcat(r->pool, context, ":", user, NULL);
287 }
288 else { /* digest auth */
289 return apr_pstrcat(r->pool, context, ":", user, ":", realm, NULL);
290 }
291}
292
293static void ap_authn_cache_store(request_rec *r, const char *module,
294 const char *user, const char *realm,
295 const char* data)
296{
297 apr_status_t rv;
299 const char *key;
300 apr_time_t expiry;
301
302 /* first check whether we're caching for this module */
303 dcfg = ap_get_module_config(r->per_dir_config, &authn_socache_module);
304 if (!configured || !dcfg->providers) {
305 return;
306 }
307 if (!ap_array_str_contains(dcfg->providers, module)) {
308 return;
309 }
310
311 /* OK, we're on. Grab mutex to do our business */
313 if (APR_STATUS_IS_EBUSY(rv)) {
314 /* don't wait around; just abandon it */
316 "authn credentials for %s not cached (mutex busy)", user);
317 return;
318 }
319 else if (rv != APR_SUCCESS) {
321 "Failed to cache authn credentials for %s in %s",
322 module, dcfg->context);
323 return;
324 }
325
326 /* We have the mutex, so go ahead */
327 /* first build our key and determine expiry time */
328 key = construct_key(r, dcfg->context, user, realm);
329 expiry = apr_time_now() + dcfg->timeout;
330
331 /* store it */
333 (unsigned char*)key, strlen(key), expiry,
334 (unsigned char*)data, strlen(data), r->pool);
335 if (rv == APR_SUCCESS) {
337 "Cached authn credentials for %s in %s",
338 user, dcfg->context);
339 }
340 else {
342 "Failed to cache authn credentials for %s in %s",
343 module, dcfg->context);
344 }
345
346 /* We're done with the mutex */
348 if (rv != APR_SUCCESS) {
349 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01683) "Failed to release mutex!");
350 }
351}
352
353#define MAX_VAL_LEN 256
354static authn_status check_password(request_rec *r, const char *user,
355 const char *password)
356{
357 /* construct key
358 * look it up
359 * if found, test password
360 *
361 * mutexing here would be a big performance drag.
362 * It's definitely unnecessary with some backends (like ndbm or gdbm)
363 * Is there a risk in the general case? I guess the only risk we
364 * care about is a race condition that gets us a dangling pointer
365 * to no-longer-defined memory. Hmmm ...
366 */
367 apr_status_t rv;
368 const char *key;
370 unsigned char val[MAX_VAL_LEN];
371 unsigned int vallen = MAX_VAL_LEN - 1;
372 dcfg = ap_get_module_config(r->per_dir_config, &authn_socache_module);
373 if (!configured || !dcfg->providers) {
374 return AUTH_USER_NOT_FOUND;
375 }
376 key = construct_key(r, dcfg->context, user, NULL);
378 (unsigned char*)key, strlen(key),
379 val, &vallen, r->pool);
380
381 if (APR_STATUS_IS_NOTFOUND(rv)) {
382 /* not found - just return */
384 "Authn cache: no credentials found for %s", user);
385 return AUTH_USER_NOT_FOUND;
386 }
387 else if (rv == APR_SUCCESS) {
388 /* OK, we got a value */
390 "Authn cache: found credentials for %s", user);
391 val[vallen] = 0;
392 }
393 else {
394 /* error: give up and pass the buck */
395 /* FIXME: getting this for NOTFOUND - prolly a bug in mod_socache */
397 "Error accessing authentication cache");
398 return AUTH_USER_NOT_FOUND;
399 }
400
401 rv = apr_password_validate(password, (char*) val);
402 if (rv != APR_SUCCESS) {
403 return AUTH_DENIED;
404 }
405
406 return AUTH_GRANTED;
407}
408
409static authn_status get_realm_hash(request_rec *r, const char *user,
410 const char *realm, char **rethash)
411{
412 apr_status_t rv;
413 const char *key;
415 unsigned char val[MAX_VAL_LEN];
416 unsigned int vallen = MAX_VAL_LEN - 1;
417 dcfg = ap_get_module_config(r->per_dir_config, &authn_socache_module);
418 if (!configured || !dcfg->providers) {
419 return AUTH_USER_NOT_FOUND;
420 }
421 key = construct_key(r, dcfg->context, user, realm);
423 (unsigned char*)key, strlen(key),
424 val, &vallen, r->pool);
425
426 if (APR_STATUS_IS_NOTFOUND(rv)) {
427 /* not found - just return */
429 "Authn cache: no credentials found for %s", user);
430 return AUTH_USER_NOT_FOUND;
431 }
432 else if (rv == APR_SUCCESS) {
433 /* OK, we got a value */
435 "Authn cache: found credentials for %s", user);
436 }
437 else {
438 /* error: give up and pass the buck */
439 /* FIXME: getting this for NOTFOUND - prolly a bug in mod_socache */
441 "Error accessing authentication cache");
442 return AUTH_USER_NOT_FOUND;
443 }
444 *rethash = apr_pstrmemdup(r->pool, (char *)val, vallen);
445
446 return AUTH_USER_FOUND;
447}
448
454
465
467{
471 NULL,
472 NULL,
475};
Symbol export macros and hook functions.
Apache Provider API.
Small object cache provider interface.
APR MD5 Routines.
APR-UTIL registration of functions exported by modules.
APR Strings library.
static sem_id lock
Definition threadpriv.c:21
static apr_pool_t * pconf
Definition event.c:441
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
#define AP_INIT_ITERATE(directive, func, mconfig, where, help)
const char * ap_set_string_slot(cmd_parms *cmd, void *struct_ptr, const char *arg)
Definition config.c:1469
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
request_rec * r
#define AP_INIT_NO_ARGS(directive, func, mconfig, where, help)
void ap_hook_child_init(ap_HOOK_child_init_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:167
#define OK
Definition httpd.h:456
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define ap_log_perror
Definition http_log.h:412
#define APLOG_CRIT
Definition http_log.h:66
#define APLOG_DEBUG
Definition http_log.h:71
apr_md5_ctx_t * context
Definition util_md5.h:58
apr_status_t ap_global_mutex_create(apr_global_mutex_t **mutex, const char **name, const char *type, const char *instance_id, server_rec *server, apr_pool_t *pool, apr_int32_t options)
Definition util_mutex.c:407
apr_status_t ap_mutex_register(apr_pool_t *pconf, const char *type, const char *default_dir, apr_lockmech_e default_mech, apr_int32_t options)
Definition util_mutex.c:254
void * ap_lookup_provider(const char *provider_group, const char *provider_name, const char *provider_version)
Definition provider.c:99
apr_status_t ap_register_auth_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider, int type)
Definition request.c:2179
#define AP_AUTH_INTERNAL_PER_CONF
void const char * arg
Definition http_vhost.h:63
#define APR_STATUS_IS_NOTFOUND(s)
Definition apr_errno.h:574
#define APR_STATUS_IS_EBUSY(s)
Definition apr_errno.h:628
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_REGISTER_OPTIONAL_FN(name)
#define AP_SOCACHE_DEFAULT_PROVIDER
Definition ap_socache.h:223
#define AP_SOCACHE_PROVIDER_GROUP
Definition ap_socache.h:218
#define AP_SOCACHE_PROVIDER_VERSION
Definition ap_socache.h:220
#define ACCESS_CONF
#define RSRC_CONF
#define OR_AUTHCFG
#define STANDARD20_MODULE_STUFF
#define ap_strchr_c(s, c)
Definition httpd.h:2353
int ap_array_str_contains(const apr_array_header_t *array, const char *s)
Definition util.c:3446
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
@ APR_LOCK_DEFAULT
const char * sep
const char * s
Definition apr_strings.h:95
#define APR_ARRAY_PUSH(ary, type)
Definition apr_tables.h:150
const char const char * password
apr_cmdtype_e cmd
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_from_sec(sec)
Definition apr_time.h:78
Apache Configuration.
CORE HTTP Daemon.
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
Authentication and Authorization Extension for Apache.
#define AUTHN_PROVIDER_VERSION
Definition mod_auth.h:41
#define AUTHN_PROVIDER_GROUP
Definition mod_auth.h:39
authn_status
Definition mod_auth.h:64
@ AUTH_GRANTED
Definition mod_auth.h:66
@ AUTH_DENIED
Definition mod_auth.h:65
@ AUTH_USER_FOUND
Definition mod_auth.h:67
@ AUTH_USER_NOT_FOUND
Definition mod_auth.h:68
static apr_status_t remove_lock(void *data)
static int authn_cache_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp, server_rec *s)
static const command_rec authn_cache_cmds[]
static void * authn_cache_dircfg_create(apr_pool_t *pool, char *s)
#define MAX_VAL_LEN
static ap_socache_provider_t * socache_provider
static authn_status get_realm_hash(request_rec *r, const char *user, const char *realm, char **rethash)
static ap_socache_instance_t * socache_instance
static const char * authn_cache_timeout(cmd_parms *cmd, void *CFG, const char *arg)
static void * authn_cache_dircfg_merge(apr_pool_t *pool, void *BASE, void *ADD)
static void ap_authn_cache_store(request_rec *r, const char *module, const char *user, const char *realm, const char *data)
static apr_status_t destroy_cache(void *data)
static const char * authn_cache_enable(cmd_parms *cmd, void *CFG)
static apr_global_mutex_t * authn_cache_mutex
static const char * authn_cache_setprovider(cmd_parms *cmd, void *CFG, const char *arg)
static void authn_cache_child_init(apr_pool_t *p, server_rec *s)
static authn_status check_password(request_rec *r, const char *user, const char *password)
static const char *const directory
static void register_hooks(apr_pool_t *p)
static int authn_cache_precfg(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp)
static int configured
static const char * construct_key(request_rec *r, const char *context, const char *user, const char *realm)
static const char *const authn_cache_id
static const char * authn_cache_socache(cmd_parms *cmd, void *CFG, const char *arg)
static const authn_provider authn_cache_provider
return NULL
Definition mod_so.c:359
char * name
apr_status_t(* store)(ap_socache_instance_t *instance, server_rec *s, const unsigned char *id, unsigned int idlen, apr_time_t expiry, unsigned char *data, unsigned int datalen, apr_pool_t *pool)
Definition ap_socache.h:151
const char *(* create)(ap_socache_instance_t **instance, const char *arg, apr_pool_t *tmp, apr_pool_t *p)
Definition ap_socache.h:109
void(* destroy)(ap_socache_instance_t *instance, server_rec *s)
Definition ap_socache.h:137
apr_status_t(* init)(ap_socache_instance_t *instance, const char *cname, const struct ap_socache_hints *hints, server_rec *s, apr_pool_t *pool)
Definition ap_socache.h:128
apr_status_t(* retrieve)(ap_socache_instance_t *instance, server_rec *s, const unsigned char *id, unsigned int idlen, unsigned char *data, unsigned int *datalen, apr_pool_t *pool)
Definition ap_socache.h:171
apr_interval_time_t timeout
apr_array_header_t * providers
A structure that represents the current request.
Definition httpd.h:845
char * uri
Definition httpd.h:1016
apr_pool_t * pool
Definition httpd.h:847
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
A structure to store information for each virtual server.
Definition httpd.h:1322
char * server_hostname
Definition httpd.h:1365
static apr_pool_t * ptmp
Apache Mutex support library.