00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "apr_strings.h"
00018 #include "apr_md5.h"
00019 #include "apr_lib.h"
00020 #include "apr_base64.h"
00021 #define APR_WANT_STRFUNC
00022 #include "apr_want.h"
00023
00024 #include "ap_config.h"
00025 #include "httpd.h"
00026 #include "http_config.h"
00027 #include "http_core.h"
00028 #include "http_log.h"
00029 #include "http_protocol.h"
00030 #include "http_request.h"
00031 #include "ap_provider.h"
00032
00033 #include "mod_auth.h"
00034
00035 typedef struct {
00036 authn_provider_list *providers;
00037 char *dir;
00038 int authoritative;
00039 } auth_basic_config_rec;
00040
00041 static void *create_auth_basic_dir_config(apr_pool_t *p, char *d)
00042 {
00043 auth_basic_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
00044
00045 conf->dir = d;
00046
00047 conf->authoritative = 1;
00048
00049 return conf;
00050 }
00051
00052 static const char *add_authn_provider(cmd_parms *cmd, void *config,
00053 const char *arg)
00054 {
00055 auth_basic_config_rec *conf = (auth_basic_config_rec*)config;
00056 authn_provider_list *newp;
00057
00058 newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list));
00059 newp->provider_name = apr_pstrdup(cmd->pool, arg);
00060
00061
00062 newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
00063 newp->provider_name, "0");
00064
00065 if (newp->provider == NULL) {
00066
00067
00068 return apr_psprintf(cmd->pool,
00069 "Unknown Authn provider: %s",
00070 newp->provider_name);
00071 }
00072
00073 if (!newp->provider->check_password) {
00074
00075 return apr_psprintf(cmd->pool,
00076 "The '%s' Authn provider doesn't support "
00077 "Basic Authentication", newp->provider_name);
00078 }
00079
00080
00081 if (!conf->providers) {
00082 conf->providers = newp;
00083 }
00084 else {
00085 authn_provider_list *last = conf->providers;
00086
00087 while (last->next) {
00088 last = last->next;
00089 }
00090 last->next = newp;
00091 }
00092
00093 return NULL;
00094 }
00095
00096 static const command_rec auth_basic_cmds[] =
00097 {
00098 AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG,
00099 "specify the auth providers for a directory or location"),
00100 AP_INIT_FLAG("AuthBasicAuthoritative", ap_set_flag_slot,
00101 (void *)APR_OFFSETOF(auth_basic_config_rec, authoritative),
00102 OR_AUTHCFG,
00103 "Set to 'Off' to allow access control to be passed along to "
00104 "lower modules if the UserID is not known to this module"),
00105 {NULL}
00106 };
00107
00108 module AP_MODULE_DECLARE_DATA auth_basic_module;
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 static void note_basic_auth_failure(request_rec *r)
00121 {
00122 apr_table_setn(r->err_headers_out,
00123 (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
00124 : "WWW-Authenticate",
00125 apr_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r),
00126 "\"", NULL));
00127 }
00128
00129 static int get_basic_auth(request_rec *r, const char **user,
00130 const char **pw)
00131 {
00132 const char *auth_line;
00133 char *decoded_line;
00134 int length;
00135
00136
00137 auth_line = apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq)
00138 ? "Proxy-Authorization"
00139 : "Authorization");
00140
00141 if (!auth_line) {
00142 note_basic_auth_failure(r);
00143 return HTTP_UNAUTHORIZED;
00144 }
00145
00146 if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
00147
00148 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00149 "client used wrong authentication scheme: %s", r->uri);
00150 note_basic_auth_failure(r);
00151 return HTTP_UNAUTHORIZED;
00152 }
00153
00154
00155 while (apr_isspace(*auth_line)) {
00156 auth_line++;
00157 }
00158
00159 decoded_line = apr_palloc(r->pool, apr_base64_decode_len(auth_line) + 1);
00160 length = apr_base64_decode(decoded_line, auth_line);
00161
00162 decoded_line[length] = '\0';
00163
00164 *user = ap_getword_nulls(r->pool, (const char**)&decoded_line, ':');
00165 *pw = decoded_line;
00166
00167
00168 r->user = (char *) *user;
00169
00170 return OK;
00171 }
00172
00173
00174
00175
00176 static int authenticate_basic_user(request_rec *r)
00177 {
00178 auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config,
00179 &auth_basic_module);
00180 const char *sent_user, *sent_pw, *current_auth;
00181 int res;
00182 authn_status auth_result;
00183 authn_provider_list *current_provider;
00184
00185
00186 current_auth = ap_auth_type(r);
00187 if (!current_auth || strcasecmp(current_auth, "Basic")) {
00188 return DECLINED;
00189 }
00190
00191
00192 if (!ap_auth_name(r)) {
00193 ap_log_rerror(APLOG_MARK, APLOG_ERR,
00194 0, r, "need AuthName: %s", r->uri);
00195 return HTTP_INTERNAL_SERVER_ERROR;
00196 }
00197
00198 r->ap_auth_type = "Basic";
00199
00200 res = get_basic_auth(r, &sent_user, &sent_pw);
00201 if (res) {
00202 return res;
00203 }
00204
00205 current_provider = conf->providers;
00206 do {
00207 const authn_provider *provider;
00208
00209
00210
00211
00212 if (!current_provider) {
00213 provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP,
00214 AUTHN_DEFAULT_PROVIDER, "0");
00215
00216 if (!provider || !provider->check_password) {
00217 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00218 "No Authn provider configured");
00219 auth_result = AUTH_GENERAL_ERROR;
00220 break;
00221 }
00222 apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER);
00223 }
00224 else {
00225 provider = current_provider->provider;
00226 apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name);
00227 }
00228
00229
00230 auth_result = provider->check_password(r, sent_user, sent_pw);
00231
00232 apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE);
00233
00234
00235 if (auth_result != AUTH_USER_NOT_FOUND) {
00236 break;
00237 }
00238
00239
00240 if (!conf->providers) {
00241 break;
00242 }
00243
00244 current_provider = current_provider->next;
00245 } while (current_provider);
00246
00247 if (auth_result != AUTH_GRANTED) {
00248 int return_code;
00249
00250
00251 if (!(conf->authoritative) && auth_result != AUTH_DENIED) {
00252 return DECLINED;
00253 }
00254
00255 switch (auth_result) {
00256 case AUTH_DENIED:
00257 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00258 "user %s: authentication failure for \"%s\": "
00259 "Password Mismatch",
00260 sent_user, r->uri);
00261 return_code = HTTP_UNAUTHORIZED;
00262 break;
00263 case AUTH_USER_NOT_FOUND:
00264 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
00265 "user %s not found: %s", sent_user, r->uri);
00266 return_code = HTTP_UNAUTHORIZED;
00267 break;
00268 case AUTH_GENERAL_ERROR:
00269 default:
00270
00271
00272
00273 return_code = HTTP_INTERNAL_SERVER_ERROR;
00274 break;
00275 }
00276
00277
00278 if (return_code == HTTP_UNAUTHORIZED) {
00279 note_basic_auth_failure(r);
00280 }
00281 return return_code;
00282 }
00283
00284 return OK;
00285 }
00286
00287 static void register_hooks(apr_pool_t *p)
00288 {
00289 ap_hook_check_user_id(authenticate_basic_user,NULL,NULL,APR_HOOK_MIDDLE);
00290 }
00291
00292 module AP_MODULE_DECLARE_DATA auth_basic_module =
00293 {
00294 STANDARD20_MODULE_STUFF,
00295 create_auth_basic_dir_config,
00296 NULL,
00297 NULL,
00298 NULL,
00299 auth_basic_cmds,
00300 register_hooks
00301 };