| /* Licensed to the Apache Software Foundation (ASF) under one or more | |
| * contributor license agreements. See the NOTICE file distributed with | |
| * this work for additional information regarding copyright ownership. | |
| * The ASF licenses this file to You 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. | |
| */ | |
| #include "apr_strings.h" | |
| #include "apr_lib.h" /* for apr_isspace */ | |
| #include "apr_base64.h" /* for apr_base64_decode et al */ | |
| #define APR_WANT_STRFUNC /* for strcasecmp */ | |
| #include "apr_want.h" | |
| #include "ap_config.h" | |
| #include "httpd.h" | |
| #include "http_config.h" | |
| #include "http_core.h" | |
| #include "http_log.h" | |
| #include "http_protocol.h" | |
| #include "http_request.h" | |
| #include "ap_provider.h" | |
| #include "util_md5.h" | |
| #include "ap_expr.h" | |
| #include "mod_auth.h" | |
| #include "mod_session.h" | |
| #include "mod_request.h" | |
| #define FORM_LOGIN_HANDLER "form-login-handler" | |
| #define FORM_LOGOUT_HANDLER "form-logout-handler" | |
| #define FORM_REDIRECT_HANDLER "form-redirect-handler" | |
| #define MOD_AUTH_FORM_HASH "site" | |
| static APR_OPTIONAL_FN_TYPE(ap_session_load) *ap_session_load_fn = NULL; | |
| static APR_OPTIONAL_FN_TYPE(ap_session_get) *ap_session_get_fn = NULL; | |
| static APR_OPTIONAL_FN_TYPE(ap_session_set) *ap_session_set_fn = NULL; | |
| static void (*ap_request_insert_filter_fn) (request_rec * r) = NULL; | |
| static void (*ap_request_remove_filter_fn) (request_rec * r) = NULL; | |
| typedef struct { | |
| authn_provider_list *providers; | |
| char *dir; | |
| int authoritative; | |
| int authoritative_set; | |
| const char *site; | |
| int site_set; | |
| const char *username; | |
| int username_set; | |
| const char *password; | |
| int password_set; | |
| apr_size_t form_size; | |
| int form_size_set; | |
| int fakebasicauth; | |
| int fakebasicauth_set; | |
| const char *location; | |
| int location_set; | |
| const char *method; | |
| int method_set; | |
| const char *mimetype; | |
| int mimetype_set; | |
| const char *body; | |
| int body_set; | |
| int disable_no_store; | |
| int disable_no_store_set; | |
| ap_expr_info_t *loginsuccess; | |
| int loginsuccess_set; | |
| ap_expr_info_t *loginrequired; | |
| int loginrequired_set; | |
| ap_expr_info_t *logout; | |
| int logout_set; | |
| } auth_form_config_rec; | |
| static void *create_auth_form_dir_config(apr_pool_t * p, char *d) | |
| { | |
| auth_form_config_rec *conf = apr_pcalloc(p, sizeof(*conf)); | |
| conf->dir = d; | |
| /* Any failures are fatal. */ | |
| conf->authoritative = 1; | |
| /* form size defaults to 8k */ | |
| conf->form_size = HUGE_STRING_LEN; | |
| /* default form field names */ | |
| conf->username = "httpd_username"; | |
| conf->password = "httpd_password"; | |
| conf->location = "httpd_location"; | |
| conf->method = "httpd_method"; | |
| conf->mimetype = "httpd_mimetype"; | |
| conf->body = "httpd_body"; | |
| return conf; | |
| } | |
| static void *merge_auth_form_dir_config(apr_pool_t * p, void *basev, void *addv) | |
| { | |
| auth_form_config_rec *new = (auth_form_config_rec *) apr_pcalloc(p, sizeof(auth_form_config_rec)); | |
| auth_form_config_rec *add = (auth_form_config_rec *) addv; | |
| auth_form_config_rec *base = (auth_form_config_rec *) basev; | |
| new->providers = !add->providers ? base->providers : add->providers; | |
| new->authoritative = (add->authoritative_set == 0) ? base->authoritative : add->authoritative; | |
| new->authoritative_set = add->authoritative_set || base->authoritative_set; | |
| new->site = (add->site_set == 0) ? base->site : add->site; | |
| new->site_set = add->site_set || base->site_set; | |
| new->username = (add->username_set == 0) ? base->username : add->username; | |
| new->username_set = add->username_set || base->username_set; | |
| new->password = (add->password_set == 0) ? base->password : add->password; | |
| new->password_set = add->password_set || base->password_set; | |
| new->location = (add->location_set == 0) ? base->location : add->location; | |
| new->location_set = add->location_set || base->location_set; | |
| new->form_size = (add->form_size_set == 0) ? base->form_size : add->form_size; | |
| new->form_size_set = add->form_size_set || base->form_size_set; | |
| new->fakebasicauth = (add->fakebasicauth_set == 0) ? base->fakebasicauth : add->fakebasicauth; | |
| new->fakebasicauth_set = add->fakebasicauth_set || base->fakebasicauth_set; | |
| new->method = (add->method_set == 0) ? base->method : add->method; | |
| new->method_set = add->method_set || base->method_set; | |
| new->mimetype = (add->mimetype_set == 0) ? base->mimetype : add->mimetype; | |
| new->mimetype_set = add->mimetype_set || base->mimetype_set; | |
| new->body = (add->body_set == 0) ? base->body : add->body; | |
| new->body_set = add->body_set || base->body_set; | |
| new->disable_no_store = (add->disable_no_store_set == 0) ? base->disable_no_store : add->disable_no_store; | |
| new->disable_no_store_set = add->disable_no_store_set || base->disable_no_store_set; | |
| new->loginsuccess = (add->loginsuccess_set == 0) ? base->loginsuccess : add->loginsuccess; | |
| new->loginsuccess_set = add->loginsuccess_set || base->loginsuccess_set; | |
| new->loginrequired = (add->loginrequired_set == 0) ? base->loginrequired : add->loginrequired; | |
| new->loginrequired_set = add->loginrequired_set || base->loginrequired_set; | |
| new->logout = (add->logout_set == 0) ? base->logout : add->logout; | |
| new->logout_set = add->logout_set || base->logout_set; | |
| return new; | |
| } | |
| static const char *add_authn_provider(cmd_parms * cmd, void *config, | |
| const char *arg) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| authn_provider_list *newp; | |
| newp = apr_pcalloc(cmd->pool, sizeof(authn_provider_list)); | |
| newp->provider_name = arg; | |
| /* lookup and cache the actual provider now */ | |
| newp->provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, | |
| newp->provider_name, | |
| AUTHN_PROVIDER_VERSION); | |
| if (newp->provider == NULL) { | |
| /* | |
| * by the time they use it, the provider should be loaded and | |
| * registered with us. | |
| */ | |
| return apr_psprintf(cmd->pool, | |
| "Unknown Authn provider: %s", | |
| newp->provider_name); | |
| } | |
| if (!newp->provider->check_password) { | |
| /* if it doesn't provide the appropriate function, reject it */ | |
| return apr_psprintf(cmd->pool, | |
| "The '%s' Authn provider doesn't support " | |
| "Form Authentication", newp->provider_name); | |
| } | |
| /* Add it to the list now. */ | |
| if (!conf->providers) { | |
| conf->providers = newp; | |
| } | |
| else { | |
| authn_provider_list *last = conf->providers; | |
| while (last->next) { | |
| last = last->next; | |
| } | |
| last->next = newp; | |
| } | |
| return NULL; | |
| } | |
| /** | |
| * Sanity check a given string that it exists, is not empty, | |
| * and does not contain special characters. | |
| */ | |
| static const char *check_string(cmd_parms * cmd, const char *string) | |
| { | |
| if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&')) { | |
| return apr_pstrcat(cmd->pool, cmd->directive->directive, | |
| " cannot be empty, or contain '=' or '&'.", | |
| NULL); | |
| } | |
| return NULL; | |
| } | |
| static const char *set_cookie_form_location(cmd_parms * cmd, void *config, const char *location) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->location = location; | |
| conf->location_set = 1; | |
| return check_string(cmd, location); | |
| } | |
| static const char *set_cookie_form_username(cmd_parms * cmd, void *config, const char *username) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->username = username; | |
| conf->username_set = 1; | |
| return check_string(cmd, username); | |
| } | |
| static const char *set_cookie_form_password(cmd_parms * cmd, void *config, const char *password) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->password = password; | |
| conf->password_set = 1; | |
| return check_string(cmd, password); | |
| } | |
| static const char *set_cookie_form_method(cmd_parms * cmd, void *config, const char *method) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->method = method; | |
| conf->method_set = 1; | |
| return check_string(cmd, method); | |
| } | |
| static const char *set_cookie_form_mimetype(cmd_parms * cmd, void *config, const char *mimetype) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->mimetype = mimetype; | |
| conf->mimetype_set = 1; | |
| return check_string(cmd, mimetype); | |
| } | |
| static const char *set_cookie_form_body(cmd_parms * cmd, void *config, const char *body) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->body = body; | |
| conf->body_set = 1; | |
| return check_string(cmd, body); | |
| } | |
| static const char *set_cookie_form_size(cmd_parms * cmd, void *config, | |
| const char *arg) | |
| { | |
| auth_form_config_rec *conf = config; | |
| apr_off_t size; | |
| if (APR_SUCCESS != ap_size_parameter_parse(arg, &size) | |
| || size < 0 || size > APR_SIZE_MAX) { | |
| return "AuthCookieFormSize must be a size in bytes, or zero."; | |
| } | |
| conf->form_size = (apr_size_t)size; | |
| conf->form_size_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_login_required_location(cmd_parms * cmd, void *config, const char *loginrequired) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| const char *err; | |
| conf->loginrequired = ap_expr_parse_cmd(cmd, loginrequired, AP_EXPR_FLAG_STRING_RESULT, | |
| &err, NULL); | |
| if (err) { | |
| return apr_psprintf(cmd->pool, | |
| "Could not parse login required expression '%s': %s", | |
| loginrequired, err); | |
| } | |
| conf->loginrequired_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_login_success_location(cmd_parms * cmd, void *config, const char *loginsuccess) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| const char *err; | |
| conf->loginsuccess = ap_expr_parse_cmd(cmd, loginsuccess, AP_EXPR_FLAG_STRING_RESULT, | |
| &err, NULL); | |
| if (err) { | |
| return apr_psprintf(cmd->pool, | |
| "Could not parse login success expression '%s': %s", | |
| loginsuccess, err); | |
| } | |
| conf->loginsuccess_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_logout_location(cmd_parms * cmd, void *config, const char *logout) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| const char *err; | |
| conf->logout = ap_expr_parse_cmd(cmd, logout, AP_EXPR_FLAG_STRING_RESULT, | |
| &err, NULL); | |
| if (err) { | |
| return apr_psprintf(cmd->pool, | |
| "Could not parse logout required expression '%s': %s", | |
| logout, err); | |
| } | |
| conf->logout_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_site_passphrase(cmd_parms * cmd, void *config, const char *site) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->site = site; | |
| conf->site_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_authoritative(cmd_parms * cmd, void *config, int flag) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->authoritative = flag; | |
| conf->authoritative_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_fake_basic_auth(cmd_parms * cmd, void *config, int flag) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->fakebasicauth = flag; | |
| conf->fakebasicauth_set = 1; | |
| return NULL; | |
| } | |
| static const char *set_disable_no_store(cmd_parms * cmd, void *config, int flag) | |
| { | |
| auth_form_config_rec *conf = (auth_form_config_rec *) config; | |
| conf->disable_no_store = flag; | |
| conf->disable_no_store_set = 1; | |
| return NULL; | |
| } | |
| static const command_rec auth_form_cmds[] = | |
| { | |
| AP_INIT_ITERATE("AuthFormProvider", add_authn_provider, NULL, OR_AUTHCFG, | |
| "specify the auth providers for a directory or location"), | |
| AP_INIT_TAKE1("AuthFormUsername", set_cookie_form_username, NULL, OR_AUTHCFG, | |
| "The field of the login form carrying the username"), | |
| AP_INIT_TAKE1("AuthFormPassword", set_cookie_form_password, NULL, OR_AUTHCFG, | |
| "The field of the login form carrying the password"), | |
| AP_INIT_TAKE1("AuthFormLocation", set_cookie_form_location, NULL, OR_AUTHCFG, | |
| "The field of the login form carrying the URL to redirect on " | |
| "successful login."), | |
| AP_INIT_TAKE1("AuthFormMethod", set_cookie_form_method, NULL, OR_AUTHCFG, | |
| "The field of the login form carrying the original request method."), | |
| AP_INIT_TAKE1("AuthFormMimetype", set_cookie_form_mimetype, NULL, OR_AUTHCFG, | |
| "The field of the login form carrying the original request mimetype."), | |
| AP_INIT_TAKE1("AuthFormBody", set_cookie_form_body, NULL, OR_AUTHCFG, | |
| "The field of the login form carrying the urlencoded original request " | |
| "body."), | |
| AP_INIT_TAKE1("AuthFormSize", set_cookie_form_size, NULL, ACCESS_CONF, | |
| "Maximum size of body parsed by the form parser"), | |
| AP_INIT_TAKE1("AuthFormLoginRequiredLocation", set_login_required_location, | |
| NULL, OR_AUTHCFG, | |
| "If set, redirect the browser to this URL rather than " | |
| "return 401 Not Authorized."), | |
| AP_INIT_TAKE1("AuthFormLoginSuccessLocation", set_login_success_location, | |
| NULL, OR_AUTHCFG, | |
| "If set, redirect the browser to this URL when a login " | |
| "processed by the login handler is successful."), | |
| AP_INIT_TAKE1("AuthFormLogoutLocation", set_logout_location, | |
| NULL, OR_AUTHCFG, | |
| "The URL of the logout successful page. An attempt to access an " | |
| "URL handled by the handler " FORM_LOGOUT_HANDLER " will result " | |
| "in an redirect to this page after logout."), | |
| AP_INIT_TAKE1("AuthFormSitePassphrase", set_site_passphrase, | |
| NULL, OR_AUTHCFG, | |
| "If set, use this passphrase to determine whether the user should " | |
| "be authenticated. Bypasses the user authentication check on " | |
| "every website hit, and is useful for high traffic sites."), | |
| AP_INIT_FLAG("AuthFormAuthoritative", set_authoritative, | |
| NULL, OR_AUTHCFG, | |
| "Set to 'Off' to allow access control to be passed along to " | |
| "lower modules if the UserID is not known to this module"), | |
| AP_INIT_FLAG("AuthFormFakeBasicAuth", set_fake_basic_auth, | |
| NULL, OR_AUTHCFG, | |
| "Set to 'On' to pass through authentication to the rest of the " | |
| "server as a basic authentication header."), | |
| AP_INIT_FLAG("AuthFormDisableNoStore", set_disable_no_store, | |
| NULL, OR_AUTHCFG, | |
| "Set to 'on' to stop the sending of a Cache-Control no-store header with " | |
| "the login screen. This allows the browser to cache the credentials, but " | |
| "at the risk of it being possible for the login form to be resubmitted " | |
| "and revealed to the backend server through XSS. Use at own risk."), | |
| {NULL} | |
| }; | |
| module AP_MODULE_DECLARE_DATA auth_form_module; | |
| static void note_cookie_auth_failure(request_rec * r) | |
| { | |
| auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config, | |
| &auth_form_module); | |
| if (conf->location && ap_strchr_c(conf->location, ':')) { | |
| apr_table_setn(r->err_headers_out, "Location", conf->location); | |
| } | |
| } | |
| static int hook_note_cookie_auth_failure(request_rec * r, | |
| const char *auth_type) | |
| { | |
| if (ap_cstr_casecmp(auth_type, "form")) | |
| return DECLINED; | |
| note_cookie_auth_failure(r); | |
| return OK; | |
| } | |
| /** | |
| * Set the auth username and password into the main request | |
| * notes table. | |
| */ | |
| static void set_notes_auth(request_rec * r, | |
| const char *user, const char *pw, | |
| const char *method, const char *mimetype) | |
| { | |
| apr_table_t *notes = NULL; | |
| const char *authname; | |
| /* find the main request */ | |
| while (r->main) { | |
| r = r->main; | |
| } | |
| /* find the first redirect */ | |
| while (r->prev) { | |
| r = r->prev; | |
| } | |
| notes = r->notes; | |
| /* have we isolated the user and pw before? */ | |
| authname = ap_auth_name(r); | |
| if (user) { | |
| apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-user", NULL), user); | |
| } | |
| if (pw) { | |
| apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-pw", NULL), pw); | |
| } | |
| if (method) { | |
| apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-method", NULL), method); | |
| } | |
| if (mimetype) { | |
| apr_table_setn(notes, apr_pstrcat(r->pool, authname, "-mimetype", NULL), mimetype); | |
| } | |
| } | |
| /** | |
| * Get the auth username and password from the main request | |
| * notes table, if present. | |
| */ | |
| static void get_notes_auth(request_rec *r, | |
| const char **user, const char **pw, | |
| const char **method, const char **mimetype) | |
| { | |
| const char *authname; | |
| request_rec *m = r; | |
| /* find the main request */ | |
| while (m->main) { | |
| m = m->main; | |
| } | |
| /* find the first redirect */ | |
| while (m->prev) { | |
| m = m->prev; | |
| } | |
| /* have we isolated the user and pw before? */ | |
| authname = ap_auth_name(m); | |
| if (user) { | |
| *user = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-user", NULL)); | |
| } | |
| if (pw) { | |
| *pw = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-pw", NULL)); | |
| } | |
| if (method) { | |
| *method = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-method", NULL)); | |
| } | |
| if (mimetype) { | |
| *mimetype = (char *) apr_table_get(m->notes, apr_pstrcat(m->pool, authname, "-mimetype", NULL)); | |
| } | |
| /* set the user, even though the user is unauthenticated at this point */ | |
| if (user && *user) { | |
| r->user = (char *) *user; | |
| } | |
| ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, | |
| "from notes: user: %s, pw: %s, method: %s, mimetype: %s", | |
| user ? *user : "<null>", pw ? *pw : "<null>", | |
| method ? *method : "<null>", mimetype ? *mimetype : "<null>"); | |
| } | |
| /** | |
| * Set the auth username and password into the session. | |
| * | |
| * If either the username, or the password are NULL, the username | |
| * and/or password will be removed from the session. | |
| */ | |
| static apr_status_t set_session_auth(request_rec * r, | |
| const char *user, const char *pw, const char *site) | |
| { | |
| const char *hash = NULL; | |
| const char *authname = ap_auth_name(r); | |
| session_rec *z = NULL; | |
| if (site) { | |
| hash = ap_md5(r->pool, | |
| (unsigned char *) apr_pstrcat(r->pool, user, ":", site, NULL)); | |
| } | |
| ap_session_load_fn(r, &z); | |
| ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_USER, NULL), user); | |
| ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_PW, NULL), pw); | |
| ap_session_set_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_AUTH_FORM_HASH, NULL), hash); | |
| return APR_SUCCESS; | |
| } | |
| /** | |
| * Get the auth username and password from the main request | |
| * notes table, if present. | |
| */ | |
| static apr_status_t get_session_auth(request_rec * r, | |
| const char **user, const char **pw, const char **hash) | |
| { | |
| const char *authname = ap_auth_name(r); | |
| session_rec *z = NULL; | |
| ap_session_load_fn(r, &z); | |
| if (user) { | |
| ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_USER, NULL), user); | |
| } | |
| if (pw) { | |
| ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_SESSION_PW, NULL), pw); | |
| } | |
| if (hash) { | |
| ap_session_get_fn(r, z, apr_pstrcat(r->pool, authname, "-" MOD_AUTH_FORM_HASH, NULL), hash); | |
| } | |
| /* set the user, even though the user is unauthenticated at this point */ | |
| if (user && *user) { | |
| r->user = (char *) *user; | |
| } | |
| ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, | |
| "from session: " MOD_SESSION_USER ": %s, " MOD_SESSION_PW | |
| ": %s, " MOD_AUTH_FORM_HASH ": %s", | |
| user ? *user : "<null>", pw ? *pw : "<null>", | |
| hash ? *hash : "<null>"); | |
| return APR_SUCCESS; | |
| } | |
| /** | |
| * Isolate the username and password in a POSTed form with the | |
| * username in the "username" field, and the password in the | |
| * "password" field. | |
| * | |
| * If either the username or the password is missing, this | |
| * function will return HTTP_UNAUTHORIZED. | |
| * | |
| * The location field is considered optional, and will be returned | |
| * if present. | |
| */ | |
| static int get_form_auth(request_rec * r, | |
| const char *username, | |
| const char *password, | |
| const char *location, | |
| const char *method, | |
| const char *mimetype, | |
| const char *body, | |
| const char **sent_user, | |
| const char **sent_pw, | |
| const char **sent_loc, | |
| const char **sent_method, | |
| const char **sent_mimetype, | |
| apr_bucket_brigade **sent_body, | |
| auth_form_config_rec * conf) | |
| { | |
| /* sanity check - are we a POST request? */ | |
| /* find the username and password in the form */ | |
| apr_array_header_t *pairs = NULL; | |
| apr_off_t len; | |
| apr_size_t size; | |
| int res; | |
| char *buffer; | |
| /* have we isolated the user and pw before? */ | |
| get_notes_auth(r, sent_user, sent_pw, sent_method, sent_mimetype); | |
| if (sent_user && *sent_user && sent_pw && *sent_pw) { | |
| return OK; | |
| } | |
| res = ap_parse_form_data(r, NULL, &pairs, -1, conf->form_size); | |
| if (res != OK) { | |
| return res; | |
| } | |
| while (pairs && !apr_is_empty_array(pairs)) { | |
| ap_form_pair_t *pair = (ap_form_pair_t *) apr_array_pop(pairs); | |
| if (username && !strcmp(pair->name, username) && sent_user) { | |
| apr_brigade_length(pair->value, 1, &len); | |
| size = (apr_size_t) len; | |
| buffer = apr_palloc(r->pool, size + 1); | |
| apr_brigade_flatten(pair->value, buffer, &size); | |
| buffer[len] = 0; | |
| *sent_user = buffer; | |
| } | |
| else if (password && !strcmp(pair->name, password) && sent_pw) { | |
| apr_brigade_length(pair->value, 1, &len); | |
| size = (apr_size_t) len; | |
| buffer = apr_palloc(r->pool, size + 1); | |
| apr_brigade_flatten(pair->value, buffer, &size); | |
| buffer[len] = 0; | |
| *sent_pw = buffer; | |
| } | |
| else if (location && !strcmp(pair->name, location) && sent_loc) { | |
| apr_brigade_length(pair->value, 1, &len); | |
| size = (apr_size_t) len; | |
| buffer = apr_palloc(r->pool, size + 1); | |
| apr_brigade_flatten(pair->value, buffer, &size); | |
| buffer[len] = 0; | |
| *sent_loc = buffer; | |
| } | |
| else if (method && !strcmp(pair->name, method) && sent_method) { | |
| apr_brigade_length(pair->value, 1, &len); | |
| size = (apr_size_t) len; | |
| buffer = apr_palloc(r->pool, size + 1); | |
| apr_brigade_flatten(pair->value, buffer, &size); | |
| buffer[len] = 0; | |
| *sent_method = buffer; | |
| } | |
| else if (mimetype && !strcmp(pair->name, mimetype) && sent_mimetype) { | |
| apr_brigade_length(pair->value, 1, &len); | |
| size = (apr_size_t) len; | |
| buffer = apr_palloc(r->pool, size + 1); | |
| apr_brigade_flatten(pair->value, buffer, &size); | |
| buffer[len] = 0; | |
| *sent_mimetype = buffer; | |
| } | |
| else if (body && !strcmp(pair->name, body) && sent_body) { | |
| *sent_body = pair->value; | |
| } | |
| } | |
| ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, | |
| "from form: user: %s, pw: %s, method: %s, mimetype: %s, location: %s", | |
| sent_user ? *sent_user : "<null>", sent_pw ? *sent_pw : "<null>", | |
| sent_method ? *sent_method : "<null>", | |
| sent_mimetype ? *sent_mimetype : "<null>", | |
| sent_loc ? *sent_loc : "<null>"); | |
| /* set the user, even though the user is unauthenticated at this point */ | |
| if (sent_user && *sent_user) { | |
| r->user = (char *) *sent_user; | |
| } | |
| /* a missing username or missing password means auth denied */ | |
| if (!sent_user || !*sent_user) { | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02982) | |
| "form parsed, but username field '%s' was missing or empty, unauthorized", | |
| username); | |
| return HTTP_UNAUTHORIZED; | |
| } | |
| if (!sent_pw || !*sent_pw) { | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02983) | |
| "form parsed, but password field '%s' was missing or empty, unauthorized", | |
| password); | |
| return HTTP_UNAUTHORIZED; | |
| } | |
| /* | |
| * save away the username, password, mimetype and method, so that they | |
| * are available should the auth need to be run again. | |
| */ | |
| set_notes_auth(r, *sent_user, *sent_pw, sent_method ? *sent_method : NULL, | |
| sent_mimetype ? *sent_mimetype : NULL); | |
| return OK; | |
| } | |
| /* These functions return 0 if client is OK, and proper error status | |
| * if not... either HTTP_UNAUTHORIZED, if we made a check, and it failed, or | |
| * HTTP_INTERNAL_SERVER_ERROR, if things are so totally confused that we | |
| * couldn't figure out how to tell if the client is authorized or not. | |
| * | |
| * If they return DECLINED, and all other modules also decline, that's | |
| * treated by the server core as a configuration error, logged and | |
| * reported as such. | |
| */ | |
| /** | |
| * Given a username and site passphrase hash from the session, determine | |
| * whether the site passphrase is valid for this session. | |
| * | |
| * If the site passphrase is NULL, or if the sent_hash is NULL, this | |
| * function returns DECLINED. | |
| * | |
| * If the site passphrase hash does not match the sent hash, this function | |
| * returns AUTH_USER_NOT_FOUND. | |
| * | |
| * On success, returns OK. | |
| */ | |
| static int check_site(request_rec * r, const char *site, const char *sent_user, const char *sent_hash) | |
| { | |
| if (site && sent_user && sent_hash) { | |
| const char *hash = ap_md5(r->pool, | |
| (unsigned char *) apr_pstrcat(r->pool, sent_user, ":", site, NULL)); | |
| if (!strcmp(sent_hash, hash)) { | |
| return OK; | |
| } | |
| else { | |
| return AUTH_USER_NOT_FOUND; | |
| } | |
| } | |
| return DECLINED; | |
| } | |
| /** | |
| * Given a username and password (extracted externally from a cookie), run | |
| * the authnz hooks to determine whether this request is authorized. | |
| * | |
| * Return an HTTP code. | |
| */ | |
| static int check_authn(request_rec * r, const char *sent_user, const char *sent_pw) | |
| { | |
| authn_status auth_result; | |
| authn_provider_list *current_provider; | |
| auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config, | |
| &auth_form_module); | |
| current_provider = conf->providers; | |
| do { | |
| const authn_provider *provider; | |
| /* | |
| * For now, if a provider isn't set, we'll be nice and use the file | |
| * provider. | |
| */ | |
| if (!current_provider) { | |
| provider = ap_lookup_provider(AUTHN_PROVIDER_GROUP, | |
| AUTHN_DEFAULT_PROVIDER, | |
| AUTHN_PROVIDER_VERSION); | |
| if (!provider || !provider->check_password) { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01806) | |
| "no authn provider configured"); | |
| auth_result = AUTH_GENERAL_ERROR; | |
| break; | |
| } | |
| apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, AUTHN_DEFAULT_PROVIDER); | |
| } | |
| else { | |
| provider = current_provider->provider; | |
| apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name); | |
| } | |
| if (!sent_user || !sent_pw) { | |
| auth_result = AUTH_USER_NOT_FOUND; | |
| break; | |
| } | |
| auth_result = provider->check_password(r, sent_user, sent_pw); | |
| apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); | |
| /* Something occurred. Stop checking. */ | |
| if (auth_result != AUTH_USER_NOT_FOUND) { | |
| break; | |
| } | |
| /* If we're not really configured for providers, stop now. */ | |
| if (!conf->providers) { | |
| break; | |
| } | |
| current_provider = current_provider->next; | |
| } while (current_provider); | |
| if (auth_result != AUTH_GRANTED) { | |
| int return_code; | |
| /* If we're not authoritative, then any error is ignored. */ | |
| if (!(conf->authoritative) && auth_result != AUTH_DENIED) { | |
| return DECLINED; | |
| } | |
| switch (auth_result) { | |
| case AUTH_DENIED: | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01807) | |
| "user '%s': authentication failure for \"%s\": " | |
| "password Mismatch", | |
| sent_user, r->uri); | |
| return_code = HTTP_UNAUTHORIZED; | |
| break; | |
| case AUTH_USER_NOT_FOUND: | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01808) | |
| "user '%s' not found: %s", sent_user, r->uri); | |
| return_code = HTTP_UNAUTHORIZED; | |
| break; | |
| case AUTH_GENERAL_ERROR: | |
| default: | |
| /* | |
| * We'll assume that the module has already said what its error | |
| * was in the logs. | |
| */ | |
| return_code = HTTP_INTERNAL_SERVER_ERROR; | |
| break; | |
| } | |
| /* If we're returning 401, tell them to try again. */ | |
| if (return_code == HTTP_UNAUTHORIZED) { | |
| note_cookie_auth_failure(r); | |
| } | |
| /* TODO: Flag the user somehow as to the reason for the failure */ | |
| return return_code; | |
| } | |
| return OK; | |
| } | |
| /* fake the basic authentication header if configured to do so */ | |
| static void fake_basic_authentication(request_rec *r, auth_form_config_rec *conf, | |
| const char *user, const char *pw) | |
| { | |
| if (conf->fakebasicauth) { | |
| char *basic = apr_pstrcat(r->pool, user, ":", pw, NULL); | |
| apr_size_t size = (apr_size_t) strlen(basic); | |
| char *base64 = apr_palloc(r->pool, | |
| apr_base64_encode_len(size + 1) * sizeof(char)); | |
| apr_base64_encode(base64, basic, size); | |
| apr_table_setn(r->headers_in, "Authorization", | |
| apr_pstrcat(r->pool, "Basic ", base64, NULL)); | |
| } | |
| } | |
| /** | |
| * Must we use form authentication? If so, extract the cookie and run | |
| * the authnz hooks to determine if the login is valid. | |
| * | |
| * If the login is not valid, a 401 Not Authorized will be returned. It | |
| * is up to the webmaster to ensure this screen displays a suitable login | |
| * form to give the user the opportunity to log in. | |
| */ | |
| static int authenticate_form_authn(request_rec * r) | |
| { | |
| auth_form_config_rec *conf = ap_get_module_config(r->per_dir_config, | |
| &auth_form_module); | |
| const char *sent_user = NULL, *sent_pw = NULL, *sent_hash = NULL; | |
| const char *sent_loc = NULL, *sent_method = "GET", *sent_mimetype = NULL; | |
| const char *current_auth = NULL; | |
| const char *err; | |
| apr_status_t res; | |
| int rv = HTTP_UNAUTHORIZED; | |
| /* Are we configured to be Form auth? */ | |
| current_auth = ap_auth_type(r); | |
| if (!current_auth || ap_cstr_casecmp(current_auth, "form")) { | |
| return DECLINED; | |
| } | |
| /* | |
| * XSS security warning: using cookies to store private data only works | |
| * when the administrator has full control over the source website. When | |
| * in forward-proxy mode, websites are public by definition, and so can | |
| * never be secure. Abort the auth attempt in this case. | |
| */ | |
| if (PROXYREQ_PROXY == r->proxyreq) { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01809) | |
| "form auth cannot be used for proxy " | |
| "requests due to XSS risk, access denied: %s", r->uri); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| /* We need an authentication realm. */ | |
| if (!ap_auth_name(r)) { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01810) | |
| "need AuthName: %s", r->uri); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| r->ap_auth_type = (char *) current_auth; | |
| /* try get the username and password from the notes, if present */ | |
| get_notes_auth(r, &sent_user, &sent_pw, &sent_method, &sent_mimetype); | |
| if (!sent_user || !sent_pw || !*sent_user || !*sent_pw) { | |
| /* otherwise try get the username and password from a session, if present */ | |
| res = get_session_auth(r, &sent_user, &sent_pw, &sent_hash); | |
| } | |
| else { | |
| res = APR_SUCCESS; | |
| } | |
| /* first test whether the site passphrase matches */ | |
| if (APR_SUCCESS == res && sent_user && sent_hash && sent_pw) { | |
| rv = check_site(r, conf->site, sent_user, sent_hash); | |
| if (OK == rv) { | |
| fake_basic_authentication(r, conf, sent_user, sent_pw); | |
| return OK; | |
| } | |
| } | |
| /* otherwise test for a normal password match */ | |
| if (APR_SUCCESS == res && sent_user && sent_pw) { | |
| rv = check_authn(r, sent_user, sent_pw); | |
| if (OK == rv) { | |
| fake_basic_authentication(r, conf, sent_user, sent_pw); | |
| return OK; | |
| } | |
| } | |
| /* | |
| * If we reach this point, the request should fail with access denied, | |
| * except for one potential scenario: | |
| * | |
| * If the request is a POST, and the posted form contains user defined fields | |
| * for a username and a password, and the username and password are correct, | |
| * then return the response obtained by a GET to this URL. | |
| * | |
| * If an additional user defined location field is present in the form, | |
| * instead of a GET of the current URL, redirect the browser to the new | |
| * location. | |
| * | |
| * As a further option, if the user defined fields for the type of request, | |
| * the mime type of the body of the request, and the body of the request | |
| * itself are present, replace this request with a new request of the given | |
| * type and with the given body. | |
| * | |
| * Otherwise access is denied. | |
| * | |
| * Reading the body requires some song and dance, because the input filters | |
| * are not yet configured. To work around this problem, we create a | |
| * subrequest and use that to create a sane filter stack we can read the | |
| * form from. | |
| * | |
| * The main request is then capped with a kept_body input filter, which has | |
| * the effect of guaranteeing the input stack can be safely read a second time. | |
| * | |
| */ | |
| if (HTTP_UNAUTHORIZED == rv && r->method_number == M_POST && ap_is_initial_req(r)) { | |
| request_rec *rr; | |
| apr_bucket_brigade *sent_body = NULL; | |
| /* create a subrequest of our current uri */ | |
| rr = ap_sub_req_lookup_uri(r->uri, r, r->input_filters); | |
| rr->headers_in = r->headers_in; | |
| /* run the insert_filters hook on the subrequest to ensure a body read can | |
| * be done properly. | |
| */ | |
| ap_run_insert_filter(rr); | |
| /* parse the form by reading the subrequest */ | |
| rv = get_form_auth(rr, conf->username, conf->password, conf->location, | |
| conf->method, conf->mimetype, conf->body, | |
| &sent_user, &sent_pw, &sent_loc, &sent_method, | |
| &sent_mimetype, &sent_body, conf); | |
| /* make sure any user detected within the subrequest is saved back to | |
| * the main request. | |
| */ | |
| r->user = apr_pstrdup(r->pool, rr->user); | |
| /* we cannot clean up rr at this point, as memory allocated to rr is | |
| * referenced from the main request. It will be cleaned up when the | |
| * main request is cleaned up. | |
| */ | |
| /* insert the kept_body filter on the main request to guarantee the | |
| * input filter stack cannot be read a second time, optionally inject | |
| * a saved body if one was specified in the login form. | |
| */ | |
| if (sent_body && sent_mimetype) { | |
| apr_table_set(r->headers_in, "Content-Type", sent_mimetype); | |
| r->kept_body = sent_body; | |
| } | |
| else { | |
| r->kept_body = apr_brigade_create(r->pool, r->connection->bucket_alloc); | |
| } | |
| ap_request_insert_filter_fn(r); | |
| /* did the form ask to change the method? if so, switch in the redirect handler | |
| * to relaunch this request as the subrequest with the new method. If the | |
| * form didn't specify a method, the default value GET will force a redirect. | |
| */ | |
| if (sent_method && strcmp(r->method, sent_method)) { | |
| r->handler = FORM_REDIRECT_HANDLER; | |
| } | |
| /* check the authn in the main request, based on the username found */ | |
| if (OK == rv) { | |
| rv = check_authn(r, sent_user, sent_pw); | |
| if (OK == rv) { | |
| fake_basic_authentication(r, conf, sent_user, sent_pw); | |
| set_session_auth(r, sent_user, sent_pw, conf->site); | |
| if (sent_loc) { | |
| apr_table_set(r->headers_out, "Location", sent_loc); | |
| return HTTP_MOVED_TEMPORARILY; | |
| } | |
| if (conf->loginsuccess) { | |
| const char *loginsuccess = ap_expr_str_exec(r, | |
| conf->loginsuccess, &err); | |
| if (!err) { | |
| apr_table_set(r->headers_out, "Location", loginsuccess); | |
| return HTTP_MOVED_TEMPORARILY; | |
| } | |
| else { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02339) | |
| "Can't evaluate login success expression: %s", err); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /* | |
| * did the admin prefer to be redirected to the login page on failure | |
| * instead? | |
| */ | |
| if (HTTP_UNAUTHORIZED == rv && conf->loginrequired) { | |
| const char *loginrequired = ap_expr_str_exec(r, | |
| conf->loginrequired, &err); | |
| if (!err) { | |
| apr_table_set(r->headers_out, "Location", loginrequired); | |
| return HTTP_MOVED_TEMPORARILY; | |
| } | |
| else { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02340) | |
| "Can't evaluate login required expression: %s", err); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| } | |
| /* did the user ask to be redirected on login success? */ | |
| if (sent_loc) { | |
| apr_table_set(r->headers_out, "Location", sent_loc); | |
| rv = HTTP_MOVED_TEMPORARILY; | |
| } | |
| /* | |
| * potential security issue: if we return a login to the browser, we must | |
| * send a no-store to make sure a well behaved browser will not try and | |
| * send the login details a second time if the back button is pressed. | |
| * | |
| * if the user has full control over the backend, the | |
| * AuthCookieDisableNoStore can be used to turn this off. | |
| */ | |
| if (HTTP_UNAUTHORIZED == rv && !conf->disable_no_store) { | |
| apr_table_addn(r->headers_out, "Cache-Control", "no-store"); | |
| apr_table_addn(r->err_headers_out, "Cache-Control", "no-store"); | |
| } | |
| return rv; | |
| } | |
| /** | |
| * Handle a login attempt. | |
| * | |
| * If the login session is either missing or form authnz is unsuccessful, a | |
| * 401 Not Authorized will be returned to the browser. The webmaster | |
| * is expected to insert a login form into the 401 Not Authorized | |
| * error screen. | |
| * | |
| * If the webmaster wishes, they can point the form submission at this | |
| * handler, which will redirect the user to the correct page on success. | |
| * On failure, the 401 Not Authorized error screen will be redisplayed, | |
| * where the login attempt can be repeated. | |
| * | |
| */ | |
| static int authenticate_form_login_handler(request_rec * r) | |
| { | |
| auth_form_config_rec *conf; | |
| const char *err; | |
| const char *sent_user = NULL, *sent_pw = NULL, *sent_loc = NULL; | |
| int rv; | |
| if (strcmp(r->handler, FORM_LOGIN_HANDLER)) { | |
| return DECLINED; | |
| } | |
| if (r->method_number != M_POST) { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01811) | |
| "the " FORM_LOGIN_HANDLER " only supports the POST method for %s", | |
| r->uri); | |
| return HTTP_METHOD_NOT_ALLOWED; | |
| } | |
| conf = ap_get_module_config(r->per_dir_config, &auth_form_module); | |
| rv = get_form_auth(r, conf->username, conf->password, conf->location, | |
| NULL, NULL, NULL, | |
| &sent_user, &sent_pw, &sent_loc, | |
| NULL, NULL, NULL, conf); | |
| if (OK == rv) { | |
| rv = check_authn(r, sent_user, sent_pw); | |
| if (OK == rv) { | |
| set_session_auth(r, sent_user, sent_pw, conf->site); | |
| if (sent_loc) { | |
| apr_table_set(r->headers_out, "Location", sent_loc); | |
| return HTTP_MOVED_TEMPORARILY; | |
| } | |
| if (conf->loginsuccess) { | |
| const char *loginsuccess = ap_expr_str_exec(r, | |
| conf->loginsuccess, &err); | |
| if (!err) { | |
| apr_table_set(r->headers_out, "Location", loginsuccess); | |
| return HTTP_MOVED_TEMPORARILY; | |
| } | |
| else { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02341) | |
| "Can't evaluate login success expression: %s", err); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| } | |
| return HTTP_OK; | |
| } | |
| } | |
| /* did we prefer to be redirected to the login page on failure instead? */ | |
| if (HTTP_UNAUTHORIZED == rv && conf->loginrequired) { | |
| const char *loginrequired = ap_expr_str_exec(r, | |
| conf->loginrequired, &err); | |
| if (!err) { | |
| apr_table_set(r->headers_out, "Location", loginrequired); | |
| return HTTP_MOVED_TEMPORARILY; | |
| } | |
| else { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02342) | |
| "Can't evaluate login required expression: %s", err); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| } | |
| return rv; | |
| } | |
| /** | |
| * Handle a logout attempt. | |
| * | |
| * If an attempt is made to access this URL, any username and password | |
| * embedded in the session is deleted. | |
| * | |
| * This has the effect of logging the person out. | |
| * | |
| * If a logout URI has been specified, this function will create an | |
| * internal redirect to this page. | |
| */ | |
| static int authenticate_form_logout_handler(request_rec * r) | |
| { | |
| auth_form_config_rec *conf; | |
| const char *err; | |
| if (strcmp(r->handler, FORM_LOGOUT_HANDLER)) { | |
| return DECLINED; | |
| } | |
| conf = ap_get_module_config(r->per_dir_config, &auth_form_module); | |
| /* remove the username and password, effectively logging the user out */ | |
| set_session_auth(r, NULL, NULL, NULL); | |
| /* | |
| * make sure the logout page is never cached - otherwise the logout won't | |
| * work! | |
| */ | |
| apr_table_addn(r->headers_out, "Cache-Control", "no-store"); | |
| apr_table_addn(r->err_headers_out, "Cache-Control", "no-store"); | |
| /* if set, internal redirect to the logout page */ | |
| if (conf->logout) { | |
| const char *logout = ap_expr_str_exec(r, | |
| conf->logout, &err); | |
| if (!err) { | |
| apr_table_addn(r->headers_out, "Location", logout); | |
| return HTTP_TEMPORARY_REDIRECT; | |
| } | |
| else { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02343) | |
| "Can't evaluate logout expression: %s", err); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| } | |
| return HTTP_OK; | |
| } | |
| /** | |
| * Handle a redirect attempt. | |
| * | |
| * If during a form login, the method, mimetype and request body are | |
| * specified, this handler will ensure that this request is included | |
| * as an internal redirect. | |
| * | |
| */ | |
| static int authenticate_form_redirect_handler(request_rec * r) | |
| { | |
| request_rec *rr = NULL; | |
| const char *sent_method = NULL, *sent_mimetype = NULL; | |
| if (strcmp(r->handler, FORM_REDIRECT_HANDLER)) { | |
| return DECLINED; | |
| } | |
| /* get the method and mimetype from the notes */ | |
| get_notes_auth(r, NULL, NULL, &sent_method, &sent_mimetype); | |
| if (r->kept_body && sent_method && sent_mimetype) { | |
| ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01812) | |
| "internal redirect to method '%s' and body mimetype '%s' for the " | |
| "uri: %s", sent_method, sent_mimetype, r->uri); | |
| rr = ap_sub_req_method_uri(sent_method, r->uri, r, r->output_filters); | |
| r->status = ap_run_sub_req(rr); | |
| } | |
| else { | |
| ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01813) | |
| "internal redirect requested but one or all of method, mimetype or " | |
| "body are NULL: %s", r->uri); | |
| return HTTP_INTERNAL_SERVER_ERROR; | |
| } | |
| /* return the underlying error, or OK on success */ | |
| return r->status == HTTP_OK || r->status == OK ? OK : r->status; | |
| } | |
| static int authenticate_form_post_config(apr_pool_t *pconf, apr_pool_t *plog, | |
| apr_pool_t *ptemp, server_rec *s) | |
| { | |
| if (!ap_session_load_fn || !ap_session_get_fn || !ap_session_set_fn) { | |
| ap_session_load_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_load); | |
| ap_session_get_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_get); | |
| ap_session_set_fn = APR_RETRIEVE_OPTIONAL_FN(ap_session_set); | |
| if (!ap_session_load_fn || !ap_session_get_fn || !ap_session_set_fn) { | |
| ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(02617) | |
| "You must load mod_session to enable the mod_auth_form " | |
| "functions"); | |
| return !OK; | |
| } | |
| } | |
| if (!ap_request_insert_filter_fn || !ap_request_remove_filter_fn) { | |
| ap_request_insert_filter_fn = APR_RETRIEVE_OPTIONAL_FN(ap_request_insert_filter); | |
| ap_request_remove_filter_fn = APR_RETRIEVE_OPTIONAL_FN(ap_request_remove_filter); | |
| if (!ap_request_insert_filter_fn || !ap_request_remove_filter_fn) { | |
| ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL, APLOGNO(02618) | |
| "You must load mod_request to enable the mod_auth_form " | |
| "functions"); | |
| return !OK; | |
| } | |
| } | |
| return OK; | |
| } | |
| static void register_hooks(apr_pool_t * p) | |
| { | |
| ap_hook_post_config(authenticate_form_post_config,NULL,NULL,APR_HOOK_MIDDLE); | |
| #if AP_MODULE_MAGIC_AT_LEAST(20080403,1) | |
| ap_hook_check_authn(authenticate_form_authn, NULL, NULL, APR_HOOK_MIDDLE, | |
| AP_AUTH_INTERNAL_PER_CONF); | |
| #else | |
| ap_hook_check_user_id(authenticate_form_authn, NULL, NULL, APR_HOOK_MIDDLE); | |
| #endif | |
| ap_hook_handler(authenticate_form_login_handler, NULL, NULL, APR_HOOK_MIDDLE); | |
| ap_hook_handler(authenticate_form_logout_handler, NULL, NULL, APR_HOOK_MIDDLE); | |
| ap_hook_handler(authenticate_form_redirect_handler, NULL, NULL, APR_HOOK_MIDDLE); | |
| ap_hook_note_auth_failure(hook_note_cookie_auth_failure, NULL, NULL, | |
| APR_HOOK_MIDDLE); | |
| } | |
| AP_DECLARE_MODULE(auth_form) = | |
| { | |
| STANDARD20_MODULE_STUFF, | |
| create_auth_form_dir_config, /* dir config creater */ | |
| merge_auth_form_dir_config, /* dir merger --- default is to override */ | |
| NULL, /* server config */ | |
| NULL, /* merge server config */ | |
| auth_form_cmds, /* command apr_table_t */ | |
| register_hooks /* register hooks */ | |
| }; |