/* mod_fba.c * * Copyright 2004 Rici Lake * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* This software was developed for Oxfam GB ( /* * #define FBA_DONT_BLANK_USERNAMES if you don't mind usernames showing * up in Apache error logs. I don't think it's a good idea, so the * default is to blank them. */ static const char* xxx = "XXXXX"; #ifdef FBA_DONT_BLANK_USERNAMES #define XXX(foo) (foo) #else #define XXX(foo) xxx #endif /* Sigh */ #if FBA_APACHE_VERSION == 13 #define APR_SUCCESS 0 #define apr_pool_t pool #define apr_array_header_t array_header #define apr_table_get ap_table_get #define apr_table_set ap_table_set #define apr_table_unset ap_table_unset #define apr_array_push ap_push_array #define apr_array_make ap_make_array #define apr_pcalloc ap_pcalloc #define apr_pstrdup ap_pstrdup #define apr_pstrcat ap_pstrcat #define apr_fnmatch ap_fnmatch #define APR_FNM_CASE_BLIND FNM_CASE_BLIND #define ap_pbase64encode ap_uuencode #define AP_MODULE_DECLARE_DATA MODULE_VAR_EXPORT /* I know, I know */ #define user connection->user #define ap_auth_type connection->ap_auth_type #endif /* * Configuration record. */ typedef enum threeway { FBA_MAYBE = 0, FBA_OFF, FBA_ON } threeway; typedef struct fba_config_rec { apr_array_header_t *allow; apr_array_header_t *except; threeway onoffmaybe; } fba_config_rec; typedef const char *globp; module AP_MODULE_DECLARE_DATA fba_module; static apr_array_header_t *add_entry(apr_pool_t *p, apr_array_header_t *tab, const char *glob) { apr_array_header_t *rv = (tab == NULL) ? apr_array_make(p, 2, sizeof(const char *)) : tab; *(globp*)apr_array_push(rv) = apr_pstrdup(p, glob); return rv; } static void *fba_create_config(apr_pool_t *p, char *d) { fba_config_rec *cfg = apr_pcalloc(p, sizeof(fba_config_rec)); cfg->allow = NULL; cfg->except = NULL; cfg->onoffmaybe = FBA_MAYBE; return cfg; } static void *fba_merge_config(apr_pool_t *p, void *basev, void *subv) { fba_config_rec *base = basev; fba_config_rec *sub = subv; fba_config_rec *cfg = fba_create_config(p, NULL); if (sub->allow != NULL || sub->except != NULL) { cfg->allow = sub->allow; cfg->except = sub->except; } else { cfg->allow = base->allow; cfg->except = base->except; } cfg->onoffmaybe = (base->onoffmaybe != FBA_MAYBE) ? base->onoffmaybe : sub->onoffmaybe; return cfg; } static fba_config_rec *get_config (cmd_parms *cmd, void *mconfig) { return mconfig; } static const char *cmd_FakeBasicAuthType (cmd_parms *cmd, void *mconfig, const char *w) { fba_config_rec *cfg = get_config(cmd, mconfig); if (w[0] == '!') cfg->except = add_entry(cmd->pool, cfg->except, &w[1]); else cfg->allow = add_entry(cmd->pool, cfg->allow, w); return NULL; } static const char *cmd_FakeBasicAuthEnable (cmd_parms *cmd, void *mconfig, int yesno) { (get_config(cmd, mconfig))->onoffmaybe = yesno ? FBA_ON : FBA_OFF; return NULL; } static int fba_match(apr_array_header_t *tab, const char *target) { if (tab != NULL) { int i, n = tab->nelts; globp *globs = (globp *)tab->elts; for (i = 0; i < n; ++i) { if (apr_fnmatch(globs[i], target, APR_FNM_CASE_BLIND) == APR_SUCCESS) { return 1; } } } return 0; } static int fba_makeitso(request_rec *r) { fba_config_rec *cfg = ap_get_module_config(r->per_dir_config, &fba_module); threeway enabled = (cfg && cfg->onoffmaybe != FBA_MAYBE) ? cfg->onoffmaybe : FBA_OFF; if (enabled == FBA_ON) { /* We ditch the Authorization header regardless of whether we match */ if (apr_table_get(r->headers_in, "Authorization")) { /* Possible script-kiddie attack, maybe you care */ #if FBA_APACHE_VERSION == 20 ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "Removing incoming Authorization header"); #else ap_log_rerror(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r, "Removing incoming Authorization header"); #endif } apr_table_unset(r->headers_in, "Authorization"); #if FBA_APACHE_VERSION == 20 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "User %s auth_type %s", XXX(r->user), r->ap_auth_type); #else ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r, "User %s auth_type %s", XXX(r->user), r->ap_auth_type); #endif if (cfg != NULL && r->user && r->ap_auth_type && !fba_match(cfg->except, r->ap_auth_type) && fba_match(cfg->allow, r->ap_auth_type)) { /* * Construct a fake basic authorisation header. * Code copied from mod_ssl, thanks. * RSE is *not* responsible for my bizarre indentation style. */ const char *auth_line = apr_pstrcat(r->pool, "Basic ", ap_pbase64encode(r->pool, apr_pstrcat(r->pool, r->user, ":password", NULL)), NULL); apr_table_set(r->headers_in, "Authorization", auth_line); #if FBA_APACHE_VERSION == 20 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, "Faking HTTP Basic Auth header: \"Authorization: %s\"", XXX(auth_line)); #else ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r, "Faking HTTP Basic Auth header: \"Authorization: %s\"", XXX(auth_line)); #endif } } return OK; } #if FBA_APACHE_VERSION == 20 static void fba_register_hooks(apr_pool_t *p) { ap_hook_fixups(fba_makeitso, NULL, NULL, APR_HOOK_MIDDLE); } static const command_rec fba_cmds[] = { AP_INIT_FLAG("FakeBasicAuthEnable", cmd_FakeBasicAuthEnable, NULL, ACCESS_CONF | RSRC_CONF, "Whether or not to enable fake basic authorisation"), AP_INIT_ITERATE("FakeBasicAuthType", cmd_FakeBasicAuthType, NULL, ACCESS_CONF | RSRC_CONF, "A list of auth types (as globs) which will be faked (!foo means ignore foo)"), {NULL} }; module AP_MODULE_DECLARE_DATA fba_module = { STANDARD20_MODULE_STUFF, fba_create_config, /* per-directory config creator */ fba_merge_config, /* dir config merger */ NULL, /* server config creator */ NULL, /* server config merger */ fba_cmds, /* command table */ fba_register_hooks, /* set up other request processing hooks */ }; #else static const command_rec fba_cmds[] = { {"FakeBasicAuthEnable", cmd_FakeBasicAuthEnable, NULL, ACCESS_CONF | RSRC_CONF, FLAG, "Whether or not to enable fake basic authorisation"}, {"FakeBasicAuthType", cmd_FakeBasicAuthType, NULL, ACCESS_CONF | RSRC_CONF, ITERATE, "A list of auth types (as globs) which will be faked (!foo means ignore foo)"}, {NULL} }; module AP_MODULE_DECLARE_DATA fba_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ fba_create_config, /* dir config creater */ fba_merge_config, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ fba_cmds, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ fba_makeitso, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ }; #endif