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#define APR_WANT_STRFUNC /* for strcasecmp */ 19#include "apr_want.h" 20 21#define CORE_PRIVATE 22#include "ap_config.h" 23#include "httpd.h" 24#include "http_config.h" 25#include "http_core.h" 26#include "http_request.h" 27#include "ap_provider.h" 28 29#include "mod_auth.h" 30 31typedef struct provider_alias_rec { 32 char *provider_name; 33 char *provider_alias; 34 ap_conf_vector_t *sec_auth; 35 const authn_provider *provider; 36} provider_alias_rec; 37 38typedef struct authn_alias_srv_conf { 39 apr_hash_t *alias_rec; 40} authn_alias_srv_conf; 41 42module AP_MODULE_DECLARE_DATA authn_alias_module; 43 44static authn_status authn_alias_check_password(request_rec *r, const char *user, 45 const char *password) 46{ 47 /* Look up the provider alias in the alias list */ 48 /* Get the the dir_config and call ap_Merge_per_dir_configs() */ 49 /* Call the real provider->check_password() function */ 50 /* return the result of the above function call */ 51 52 const char *provider_name = apr_table_get(r->notes, AUTHN_PROVIDER_NAME_NOTE); 53 authn_status ret = AUTH_USER_NOT_FOUND; 54 authn_alias_srv_conf *authcfg = 55 (authn_alias_srv_conf *)ap_get_module_config(r->server->module_config, 56 &authn_alias_module); 57 58 if (provider_name) { 59 provider_alias_rec *prvdraliasrec = apr_hash_get(authcfg->alias_rec, 60 provider_name, APR_HASH_KEY_STRING); 61 ap_conf_vector_t *orig_dir_config = r->per_dir_config; 62 63 /* If we found the alias provider in the list, then merge the directory 64 configurations and call the real provider */ 65 if (prvdraliasrec) { 66 r->per_dir_config = ap_merge_per_dir_configs(r->pool, orig_dir_config, 67 prvdraliasrec->sec_auth); 68 ret = prvdraliasrec->provider->check_password(r,user,password); 69 r->per_dir_config = orig_dir_config; 70 } 71 } 72 73 return ret; 74} 75 76static authn_status authn_alias_get_realm_hash(request_rec *r, const char *user, 77 const char *realm, char **rethash) 78{ 79 /* Look up the provider alias in the alias list */ 80 /* Get the the dir_config and call ap_Merge_per_dir_configs() */ 81 /* Call the real provider->get_realm_hash() function */ 82 /* return the result of the above function call */ 83 84 const char *provider_name = apr_table_get(r->notes, AUTHN_PROVIDER_NAME_NOTE); 85 authn_status ret = AUTH_USER_NOT_FOUND; 86 authn_alias_srv_conf *authcfg = 87 (authn_alias_srv_conf *)ap_get_module_config(r->server->module_config, 88 &authn_alias_module); 89 90 if (provider_name) { 91 provider_alias_rec *prvdraliasrec = apr_hash_get(authcfg->alias_rec, 92 provider_name, APR_HASH_KEY_STRING); 93 ap_conf_vector_t *orig_dir_config = r->per_dir_config; 94 95 /* If we found the alias provider in the list, then merge the directory 96 configurations and call the real provider */ 97 if (prvdraliasrec) { 98 r->per_dir_config = ap_merge_per_dir_configs(r->pool, orig_dir_config, 99 prvdraliasrec->sec_auth); 100 ret = prvdraliasrec->provider->get_realm_hash(r,user,realm,rethash); 101 r->per_dir_config = orig_dir_config; 102 } 103 } 104 105 return ret; 106} 107 108static void *create_authn_alias_svr_config(apr_pool_t *p, server_rec *s) 109{ 110 111 authn_alias_srv_conf *authcfg; 112 113 authcfg = (authn_alias_srv_conf *) apr_pcalloc(p, sizeof(authn_alias_srv_conf)); 114 authcfg->alias_rec = apr_hash_make(p); 115 116 return (void *) authcfg; 117} 118 119static const authn_provider authn_alias_provider = 120{ 121 &authn_alias_check_password, 122 &authn_alias_get_realm_hash, 123}; 124 125static const authn_provider authn_alias_provider_nodigest = 126{ 127 &authn_alias_check_password, 128 NULL, 129}; 130 131static const char *authaliassection(cmd_parms *cmd, void *mconfig, const char *arg) 132{ 133 int old_overrides = cmd->override; 134 const char *endp = ap_strrchr_c(arg, '>'); 135 const char *args; 136 char *provider_alias; 137 char *provider_name; 138 const char *errmsg; 139 const authn_provider *provider = NULL; 140 ap_conf_vector_t *new_auth_config = ap_create_per_dir_config(cmd->pool); 141 authn_alias_srv_conf *authcfg = 142 (authn_alias_srv_conf *)ap_get_module_config(cmd->server->module_config, 143 &authn_alias_module); 144 145 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); 146 if (err != NULL) { 147 return err; 148 } 149 150 if (endp == NULL) { 151 return apr_pstrcat(cmd->pool, cmd->cmd->name, 152 "> directive missing closing '>'", NULL); 153 } 154 155 args = apr_pstrndup(cmd->pool, arg, endp - arg); 156 157 if (!args[0]) { 158 return apr_pstrcat(cmd->pool, cmd->cmd->name, 159 "> directive requires additional arguments", NULL); 160 } 161 162 /* Pull the real provider name and the alias name from the block header */ 163 provider_name = ap_getword_conf(cmd->pool, &args); 164 provider_alias = ap_getword_conf(cmd->pool, &args); 165 166 if (!provider_name[0] || !provider_alias[0]) { 167 return apr_pstrcat(cmd->pool, cmd->cmd->name, 168 "> directive requires additional arguments", NULL); 169 } 170 171 if (strcasecmp(provider_name, provider_alias) == 0) { 172 return apr_pstrcat(cmd->pool, 173 "The alias provider name must be different from the base provider name.", NULL); 174 } 175 176 /* Look up the alias provider to make sure that it hasn't already been registered. */ 177 provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, provider_alias, "0"); 178 if (provider) { 179 return apr_pstrcat(cmd->pool, "The alias provider ", provider_alias, 180 " has already be registered previously as either a base provider or an alias provider.", 181 NULL); 182 } 183 184 /* walk the subsection configuration to get the per_dir config that we will 185 merge just before the real provider is called. */ 186 cmd->override = OR_ALL|ACCESS_CONF; 187 errmsg = ap_walk_config(cmd->directive->first_child, cmd, new_auth_config); 188 189 if (!errmsg) { 190 provider_alias_rec *prvdraliasrec = apr_pcalloc(cmd->pool, sizeof(provider_alias_rec)); 191 provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, provider_name, "0"); 192 193 /* Save off the new directory config along with the original provider name 194 and function pointer data */ 195 prvdraliasrec->sec_auth = new_auth_config; 196 prvdraliasrec->provider_name = provider_name; 197 prvdraliasrec->provider_alias = provider_alias; 198 prvdraliasrec->provider = provider; 199 apr_hash_set(authcfg->alias_rec, provider_alias, APR_HASH_KEY_STRING, prvdraliasrec); 200 201 /* Register the fake provider so that we get called first */ 202 ap_register_provider(cmd->pool, AUTHN_PROVIDER_GROUP, provider_alias, "0", 203 provider->get_realm_hash ? 204 &authn_alias_provider : 205 &authn_alias_provider_nodigest); 206 } 207 208 cmd->override = old_overrides; 209 210 return errmsg; 211} 212 213static const command_rec authn_alias_cmds[] = 214{ 215 AP_INIT_RAW_ARGS("<AuthnProviderAlias", authaliassection, NULL, RSRC_CONF, 216 "Container for authentication directives grouped under " 217 "a provider alias"), 218 {NULL} 219}; 220 221 222module AP_MODULE_DECLARE_DATA authn_alias_module = 223{ 224 STANDARD20_MODULE_STUFF, 225 NULL, /* dir config creater */ 226 NULL, /* dir merger --- default is to override */ 227 create_authn_alias_svr_config, /* server config */ 228 NULL, /* merge server config */ 229 authn_alias_cmds, /* command apr_table_t */ 230 NULL /* register hooks */ 231}; 232