mod_authz_host.c revision fa23323ff617b08417d3834afb3dacb9cccff317
2N/A/* ====================================================================
2N/A * The Apache Software License, Version 1.1
2N/A *
2N/A * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
2N/A * reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions
2N/A * are met:
2N/A *
2N/A * 1. Redistributions of source code must retain the above copyright
2N/A * notice, this list of conditions and the following disclaimer.
2N/A *
2N/A * 2. Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in
2N/A * the documentation and/or other materials provided with the
2N/A * distribution.
2N/A *
2N/A * 3. The end-user documentation included with the redistribution,
2N/A * if any, must include the following acknowledgment:
2790N/A * "This product includes software developed by the
2790N/A * Apache Software Foundation (http://www.apache.org/)."
2515N/A * Alternately, this acknowledgment may appear in the software itself,
2N/A * if and wherever such third-party acknowledgments normally appear.
2N/A *
2N/A * 4. The names "Apache" and "Apache Software Foundation" must
2N/A * not be used to endorse or promote products derived from this
2N/A * software without prior written permission. For written
2N/A * permission, please contact apache@apache.org.
2N/A *
2N/A * 5. Products derived from this software may not be called "Apache",
2N/A * nor may "Apache" appear in their name, without prior written
2N/A * permission of the Apache Software Foundation.
59N/A *
59N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
2N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
2N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1470N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1470N/A * SUCH DAMAGE.
1470N/A * ====================================================================
1470N/A *
181N/A * This software consists of voluntary contributions made by many
26N/A * individuals on behalf of the Apache Software Foundation. For more
26N/A * information on the Apache Software Foundation, please see
26N/A * <http://www.apache.org/>.
26N/A *
26N/A * Portions of this software are based upon public domain software
26N/A * originally written at the National Center for Supercomputing Applications,
26N/A * University of Illinois, Urbana-Champaign.
26N/A */
700N/A
700N/A/*
26N/A * Security options etc.
26N/A *
26N/A * Module derived from code originally written by Rob McCool
1498N/A *
1498N/A */
26N/A
1498N/A#include "apr_strings.h"
151N/A#include "apr_network_io.h"
206N/A#include "apr_md5.h"
26N/A
26N/A#define APR_WANT_STRFUNC
26N/A#define APR_WANT_BYTEFUNC
26N/A#include "apr_want.h"
26N/A
2790N/A#include "ap_config.h"
2818N/A#include "httpd.h"
2830N/A#include "http_core.h"
26N/A#include "http_config.h"
26N/A#include "http_log.h"
2N/A#include "http_request.h"
26N/A
26N/A#if APR_HAVE_NETINET_IN_H
26N/A#include <netinet/in.h>
26N/A#endif
883N/A
26N/Aenum allowdeny_type {
26N/A T_ENV,
26N/A T_ALL,
26N/A T_IP,
1043N/A T_HOST,
586N/A T_FAIL
26N/A};
93N/A
166N/Atypedef struct {
26N/A apr_int64_t limited;
379N/A union {
379N/A char *from;
1498N/A apr_ipsubnet_t *ip;
1498N/A } x;
2236N/A enum allowdeny_type type;
2236N/A} allowdeny;
2818N/A
2N/A/* things in the 'order' array */
26N/A#define DENY_THEN_ALLOW 0
26N/A#define ALLOW_THEN_DENY 1
181N/A#define MUTUAL_FAILURE 2
181N/A
181N/Atypedef struct {
99N/A int order[METHODS];
59N/A apr_array_header_t *allows;
12N/A apr_array_header_t *denys;
30N/A} authz_host_dir_conf;
1256N/A
1256N/Amodule AP_MODULE_DECLARE_DATA authz_host_module;
1256N/A
2818N/Astatic void *create_authz_host_dir_config(apr_pool_t *p, char *dummy)
1256N/A{
1256N/A int i;
1256N/A authz_host_dir_conf *conf =
1256N/A (authz_host_dir_conf *)apr_pcalloc(p, sizeof(authz_host_dir_conf));
1256N/A
1256N/A for (i = 0; i < METHODS; ++i) {
1256N/A conf->order[i] = DENY_THEN_ALLOW;
1256N/A }
1256N/A conf->allows = apr_array_make(p, 1, sizeof(allowdeny));
2818N/A conf->denys = apr_array_make(p, 1, sizeof(allowdeny));
1256N/A
1256N/A return (void *)conf;
1256N/A}
1256N/A
1256N/Astatic const char *order(cmd_parms *cmd, void *dv, const char *arg)
1256N/A{
1256N/A authz_host_dir_conf *d = (authz_host_dir_conf *) dv;
1256N/A int i, o;
1256N/A
1256N/A if (!strcasecmp(arg, "allow,deny"))
1413N/A o = ALLOW_THEN_DENY;
1256N/A else if (!strcasecmp(arg, "deny,allow"))
26N/A o = DENY_THEN_ALLOW;
26N/A else if (!strcasecmp(arg, "mutual-failure"))
1256N/A o = MUTUAL_FAILURE;
2N/A else
26N/A return "unknown order";
1256N/A
1256N/A for (i = 0; i < METHODS; ++i)
185N/A if (cmd->limited & (AP_METHOD_BIT << i))
2N/A d->order[i] = o;
255N/A
145N/A return NULL;
7N/A}
26N/A
26N/Astatic const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from,
38N/A const char *where_c)
26N/A{
197N/A authz_host_dir_conf *d = (authz_host_dir_conf *) dv;
197N/A allowdeny *a;
197N/A char *where = apr_pstrdup(cmd->pool, where_c);
197N/A char *s;
197N/A char msgbuf[120];
26N/A apr_status_t rv;
30N/A
26N/A if (strcasecmp(from, "from"))
46N/A return "allow and deny must be followed by 'from'";
46N/A
46N/A a = (allowdeny *) apr_array_push(cmd->info ? d->allows : d->denys);
64N/A a->x.from = where;
64N/A a->limited = cmd->limited;
26N/A
46N/A if (!strncasecmp(where, "env=", 4)) {
46N/A a->type = T_ENV;
46N/A a->x.from += 4;
2N/A
1256N/A }
1256N/A else if (!strcasecmp(where, "all")) {
1256N/A a->type = T_ALL;
1256N/A }
1256N/A else if ((s = ap_strchr(where, '/'))) {
2818N/A *s++ = '\0';
1256N/A rv = apr_ipsubnet_create(&a->x.ip, where, s, cmd->pool);
1256N/A if(APR_STATUS_IS_EINVAL(rv)) {
1256N/A /* looked nothing like an IP address */
1256N/A return "An IP address was expected";
1256N/A }
2818N/A else if (rv != APR_SUCCESS) {
2818N/A apr_strerror(rv, msgbuf, sizeof msgbuf);
1256N/A return apr_pstrdup(cmd->pool, msgbuf);
2236N/A }
2236N/A a->type = T_IP;
1256N/A }
2818N/A else if (!APR_STATUS_IS_EINVAL(rv = apr_ipsubnet_create(&a->x.ip, where,
1256N/A NULL, cmd->pool))) {
1256N/A if (rv != APR_SUCCESS) {
1256N/A apr_strerror(rv, msgbuf, sizeof msgbuf);
1256N/A return apr_pstrdup(cmd->pool, msgbuf);
1256N/A }
1256N/A a->type = T_IP;
1256N/A }
1256N/A else { /* no slash, didn't look like an IP address => must be a host */
1934N/A a->type = T_HOST;
1256N/A }
1256N/A
1256N/A return NULL;
1256N/A}
1256N/A
2818N/Astatic char its_an_allow;
1934N/A
2818N/Astatic const command_rec authz_host_cmds[] =
1256N/A{
1256N/A AP_INIT_TAKE1("order", order, NULL, OR_LIMIT,
1256N/A "'allow,deny', 'deny,allow', or 'mutual-failure'"),
1413N/A AP_INIT_ITERATE2("allow", allow_cmd, &its_an_allow, OR_LIMIT,
1413N/A "'from' followed by hostnames or IP-address wildcards"),
1413N/A AP_INIT_ITERATE2("deny", allow_cmd, NULL, OR_LIMIT,
1413N/A "'from' followed by hostnames or IP-address wildcards"),
1413N/A {NULL}
1413N/A};
1413N/A
1413N/Astatic int in_domain(const char *domain, const char *what)
1413N/A{
1256N/A int dl = strlen(domain);
1256N/A int wl = strlen(what);
1256N/A
1256N/A if ((wl - dl) >= 0) {
1934N/A if (strcasecmp(domain, &what[wl - dl]) != 0) {
1256N/A return 0;
1256N/A }
1256N/A
1256N/A /* Make sure we matched an *entire* subdomain --- if the user
1256N/A * said 'allow from good.com', we don't want people from nogood.com
1934N/A * to be able to get in.
1934N/A */
1256N/A
1256N/A if (wl == dl) {
1256N/A return 1; /* matched whole thing */
1256N/A }
1256N/A else {
1256N/A return (domain[0] == '.' || what[wl - dl - 1] == '.');
1256N/A }
1256N/A }
1256N/A else {
1256N/A return 0;
1256N/A }
53N/A}
46N/A
46N/Astatic int find_allowdeny(request_rec *r, apr_array_header_t *a, int method)
26N/A{
181N/A
369N/A allowdeny *ap = (allowdeny *) a->elts;
181N/A apr_int64_t mmask = (AP_METHOD_BIT << method);
181N/A int i;
181N/A int gothost = 0;
181N/A const char *remotehost = NULL;
181N/A
181N/A for (i = 0; i < a->nelts; ++i) {
76N/A if (!(mmask & ap[i].limited)) {
99N/A continue;
181N/A }
2818N/A
2818N/A switch (ap[i].type) {
26N/A case T_ENV:
1549N/A if (apr_table_get(r->subprocess_env, ap[i].x.from)) {
1549N/A return 1;
1549N/A }
1929N/A break;
1929N/A
1929N/A case T_ALL:
1929N/A return 1;
1929N/A
1929N/A case T_IP:
1929N/A if (apr_ipsubnet_test(ap[i].x.ip, r->connection->remote_addr)) {
1929N/A return 1;
1549N/A }
1549N/A break;
1549N/A
1549N/A case T_HOST:
1555N/A if (!gothost) {
1549N/A int remotehost_is_ip;
1555N/A
1555N/A remotehost = ap_get_remote_host(r->connection,
1549N/A r->per_dir_config,
1555N/A REMOTE_DOUBLE_REV,
1549N/A &remotehost_is_ip);
1549N/A
1549N/A if ((remotehost == NULL) || remotehost_is_ip) {
1549N/A gothost = 1;
1549N/A }
1549N/A else {
1549N/A gothost = 2;
185N/A }
185N/A }
1936N/A
1929N/A if ((gothost == 2) && in_domain(ap[i].x.from, remotehost)) {
1929N/A return 1;
1549N/A }
145N/A break;
145N/A
145N/A case T_FAIL:
145N/A /* do nothing? */
145N/A break;
117N/A }
2515N/A }
84N/A
145N/A return 0;
145N/A}
145N/A
1392N/Astatic int check_dir_access(request_rec *r)
1392N/A{
1392N/A int method = r->method_number;
2515N/A int ret = OK;
1392N/A authz_host_dir_conf *a = (authz_host_dir_conf *)
1392N/A ap_get_module_config(r->per_dir_config, &authz_host_module);
1392N/A
1392N/A if (a->order[method] == ALLOW_THEN_DENY) {
1392N/A ret = HTTP_FORBIDDEN;
38N/A if (find_allowdeny(r, a->allows, method)) {
46N/A ret = OK;
1899N/A }
1899N/A if (find_allowdeny(r, a->denys, method)) {
99N/A ret = HTTP_FORBIDDEN;
196N/A }
1899N/A }
185N/A else if (a->order[method] == DENY_THEN_ALLOW) {
99N/A if (find_allowdeny(r, a->denys, method)) {
46N/A ret = HTTP_FORBIDDEN;
2N/A }
145N/A if (find_allowdeny(r, a->allows, method)) {
1899N/A ret = OK;
1899N/A }
1899N/A }
26N/A else {
2N/A if (find_allowdeny(r, a->allows, method)
32N/A && !find_allowdeny(r, a->denys, method)) {
1256N/A ret = OK;
32N/A }
32N/A else {
32N/A ret = HTTP_FORBIDDEN;
32N/A }
1256N/A }
32N/A
32N/A if (ret == HTTP_FORBIDDEN
32N/A && (ap_satisfies(r) != SATISFY_ANY || !ap_some_auth_required(r))) {
38N/A ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
38N/A "client denied by server configuration: %s",
1256N/A r->filename);
38N/A }
38N/A
38N/A return ret;
38N/A}
38N/A
38N/Astatic void register_hooks(apr_pool_t *p)
38N/A{
145N/A /* This can be access checker since we don't require r->user to be set. */
38N/A ap_hook_access_checker(check_dir_access,NULL,NULL,APR_HOOK_MIDDLE);
38N/A}
26N/A
26N/Amodule AP_MODULE_DECLARE_DATA authz_host_module =
26N/A{
26N/A STANDARD20_MODULE_STUFF,
26N/A create_authz_host_dir_config, /* dir config creater */
26N/A NULL, /* dir merger --- default is to override */
26N/A NULL, /* server config */
26N/A NULL, /* merge server config */
26N/A authz_host_cmds,
32N/A register_hooks /* register hooks */
32N/A};
32N/A