| /* 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 int (*ap_session_load_fn) (request_rec * r, session_rec ** z) = NULL; |
| static apr_status_t (*ap_session_get_fn)(request_rec * r, session_rec * z, |
| const char *key, const char **value) = NULL; |
| static apr_status_t (*ap_session_set_fn)(request_rec * r, session_rec * z, |
| const char *key, const char *value) = 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 != apr_strtoff(&size, arg, NULL, 10) |
| || 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 occured. 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 */ |
| }; |