123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /* 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_md5.h" /* for apr_password_validate */
- #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 "apr_network_io.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 "mod_auth.h"
- #include "shim_unistd.h"
- typedef struct {
- authn_provider_list *providers;
- char *dir;
- int authoritative;
- } auth_basic_config_rec;
- static void *create_auth_basic_dir_config(apr_pool_t *p, char *d)
- {
- auth_basic_config_rec *conf = apr_pcalloc(p, sizeof(*conf));
- conf->dir = d;
- /* Any failures are fatal. */
- conf->authoritative = 1;
- return conf;
- }
- static const char *add_authn_provider(cmd_parms *cmd, void *config,
- const char *arg)
- {
- auth_basic_config_rec *conf = (auth_basic_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 "
- "Basic 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;
- }
- static const command_rec auth_basic_cmds[] =
- {
- AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG,
- "specify the auth providers for a directory or location"),
- AP_INIT_FLAG("AuthBasicAuthoritative", ap_set_flag_slot,
- (void *)APR_OFFSETOF(auth_basic_config_rec, authoritative),
- 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"),
- {NULL}
- };
- module AP_MODULE_DECLARE_DATA auth_basic_module;
- /* 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.
- */
- static void note_basic_auth_failure(request_rec *r)
- {
- apr_table_setn(r->err_headers_out,
- (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
- : "WWW-Authenticate",
- apr_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r),
- "\"", NULL));
- }
- static int hook_note_basic_auth_failure(request_rec *r, const char *auth_type)
- {
- if (strcasecmp(auth_type, "Basic"))
- return DECLINED;
- note_basic_auth_failure(r);
- return OK;
- }
- static int get_basic_auth(request_rec *r, const char **user,
- const char **pw)
- {
- const char *auth_line;
- char *decoded_line;
- int length;
- /* Get the appropriate header */
- auth_line = apr_table_get(r->headers_in, (PROXYREQ_PROXY == r->proxyreq)
- ? "Proxy-Authorization"
- : "Authorization");
- if (!auth_line) {
- note_basic_auth_failure(r);
- return HTTP_UNAUTHORIZED;
- }
- if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
- /* Client tried to authenticate using wrong auth scheme */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01614)
- "client used wrong authentication scheme: %s", r->uri);
- note_basic_auth_failure(r);
- return HTTP_UNAUTHORIZED;
- }
- /* Skip leading spaces. */
- while (apr_isspace(*auth_line)) {
- auth_line++;
- }
- decoded_line = apr_palloc(r->pool, apr_base64_decode_len(auth_line) + 1);
- length = apr_base64_decode(decoded_line, auth_line);
- /* Null-terminate the string. */
- decoded_line[length] = '\0';
- *user = ap_getword_nulls(r->pool, (const char**)&decoded_line, ':');
- *pw = decoded_line;
- /* set the user, even though the user is unauthenticated at this point */
- r->user = (char *) *user;
- return OK;
- }
- /* Determine user ID, and check if it really is that user, for HTTP
- * basic authentication...
- */
- static int authenticate_basic_user(request_rec *r)
- {
- auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config,
- &auth_basic_module);
- const char *sent_user, *sent_pw, *current_auth;
- int res;
- authn_status auth_result;
- authn_provider_list *current_provider;
- /* Are we configured to be Basic auth? */
- current_auth = ap_auth_type(r);
- if (!current_auth || strcasecmp(current_auth, "Basic")) {
- return DECLINED;
- }
- /* We need an authentication realm. */
- if (!ap_auth_name(r)) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR,
- 0, r, APLOGNO(01615) "need AuthName: %s", r->uri);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- r->ap_auth_type = (char*)current_auth;
- res = get_basic_auth(r, &sent_user, &sent_pw);
- if (res) {
- return res;
- }
- 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(01616)
- "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);
- }
- 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(01617)
- "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(01618)
- "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 403, tell them to try again. */
- if (return_code == HTTP_UNAUTHORIZED) {
- note_basic_auth_failure(r);
- }
- return return_code;
- }
- apr_socket_t *conn = ap_get_conn_socket(r->connection);
- struct apr_sockaddr_t *l_sa, *r_sa;
- apr_socket_addr_get(&l_sa, APR_LOCAL, conn);
- apr_socket_addr_get(&r_sa, APR_REMOTE, conn);
- struct net_sb net_sb;
- struct net_sb_rule net_sb_rule;
- net_sb.nrules = 1;
- net_sb.rules = &net_sb_rule;
- net_sb_rule.l_addrlen = l_sa->ipaddr_len;
- net_sb_rule.l_addr = l_sa->ipaddr_ptr;
- net_sb_rule.r_addrlen = r_sa->ipaddr_len;
- net_sb_rule.r_addr = r_sa->ipaddr_ptr;
- if (sandbox_create(SANDBOX_FS|SANDBOX_NET|SANDBOX_RPC,
- ap_document_root(r),
- &net_sb) < 0)
- return HTTP_INTERNAL_SERVER_ERROR;
- return OK;
- }
- static void register_hooks(apr_pool_t *p)
- {
- ap_hook_check_authn(authenticate_basic_user, NULL, NULL, APR_HOOK_MIDDLE,
- AP_AUTH_INTERNAL_PER_CONF);
- ap_hook_note_auth_failure(hook_note_basic_auth_failure, NULL, NULL,
- APR_HOOK_MIDDLE);
- }
- AP_DECLARE_MODULE(auth_basic_sandbox) =
- {
- STANDARD20_MODULE_STUFF,
- create_auth_basic_dir_config, /* dir config creater */
- NULL, /* dir merger --- default is to override */
- NULL, /* server config */
- NULL, /* merge server config */
- auth_basic_cmds, /* command apr_table_t */
- register_hooks /* register hooks */
- };
|