~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to modules/aaa/mod_authz_host.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
 
2
 * contributor license agreements.  See the NOTICE file distributed with
 
3
 * this work for additional information regarding copyright ownership.
 
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
 
5
 * (the "License"); you may not use this file except in compliance with
 
6
 * the License.  You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
/*
 
18
 * Security options etc.
 
19
 *
 
20
 * Module derived from code originally written by Rob McCool
 
21
 *
 
22
 */
 
23
 
 
24
#include "apr_strings.h"
 
25
#include "apr_network_io.h"
 
26
#include "apr_md5.h"
 
27
 
 
28
#define APR_WANT_STRFUNC
 
29
#define APR_WANT_BYTEFUNC
 
30
#include "apr_want.h"
 
31
 
 
32
#include "ap_config.h"
 
33
#include "httpd.h"
 
34
#include "http_core.h"
 
35
#include "http_config.h"
 
36
#include "http_log.h"
 
37
#include "http_request.h"
 
38
 
 
39
#if APR_HAVE_NETINET_IN_H
 
40
#include <netinet/in.h>
 
41
#endif
 
42
 
 
43
enum allowdeny_type {
 
44
    T_ENV,
 
45
    T_ALL,
 
46
    T_IP,
 
47
    T_HOST,
 
48
    T_FAIL
 
49
};
 
50
 
 
51
typedef struct {
 
52
    apr_int64_t limited;
 
53
    union {
 
54
        char *from;
 
55
        apr_ipsubnet_t *ip;
 
56
    } x;
 
57
    enum allowdeny_type type;
 
58
} allowdeny;
 
59
 
 
60
/* things in the 'order' array */
 
61
#define DENY_THEN_ALLOW 0
 
62
#define ALLOW_THEN_DENY 1
 
63
#define MUTUAL_FAILURE 2
 
64
 
 
65
typedef struct {
 
66
    int order[METHODS];
 
67
    apr_array_header_t *allows;
 
68
    apr_array_header_t *denys;
 
69
} authz_host_dir_conf;
 
70
 
 
71
module AP_MODULE_DECLARE_DATA authz_host_module;
 
72
 
 
73
static void *create_authz_host_dir_config(apr_pool_t *p, char *dummy)
 
74
{
 
75
    int i;
 
76
    authz_host_dir_conf *conf =
 
77
        (authz_host_dir_conf *)apr_pcalloc(p, sizeof(authz_host_dir_conf));
 
78
 
 
79
    for (i = 0; i < METHODS; ++i) {
 
80
        conf->order[i] = DENY_THEN_ALLOW;
 
81
    }
 
82
    conf->allows = apr_array_make(p, 1, sizeof(allowdeny));
 
83
    conf->denys = apr_array_make(p, 1, sizeof(allowdeny));
 
84
 
 
85
    return (void *)conf;
 
86
}
 
87
 
 
88
static const char *order(cmd_parms *cmd, void *dv, const char *arg)
 
89
{
 
90
    authz_host_dir_conf *d = (authz_host_dir_conf *) dv;
 
91
    int i, o;
 
92
 
 
93
    if (!strcasecmp(arg, "allow,deny"))
 
94
        o = ALLOW_THEN_DENY;
 
95
    else if (!strcasecmp(arg, "deny,allow"))
 
96
        o = DENY_THEN_ALLOW;
 
97
    else if (!strcasecmp(arg, "mutual-failure"))
 
98
        o = MUTUAL_FAILURE;
 
99
    else
 
100
        return "unknown order";
 
101
 
 
102
    for (i = 0; i < METHODS; ++i)
 
103
        if (cmd->limited & (AP_METHOD_BIT << i))
 
104
            d->order[i] = o;
 
105
 
 
106
    return NULL;
 
107
}
 
108
 
 
109
static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from,
 
110
                             const char *where_c)
 
111
{
 
112
    authz_host_dir_conf *d = (authz_host_dir_conf *) dv;
 
113
    allowdeny *a;
 
114
    char *where = apr_pstrdup(cmd->pool, where_c);
 
115
    char *s;
 
116
    char msgbuf[120];
 
117
    apr_status_t rv;
 
118
 
 
119
    if (strcasecmp(from, "from"))
 
120
        return "allow and deny must be followed by 'from'";
 
121
 
 
122
    a = (allowdeny *) apr_array_push(cmd->info ? d->allows : d->denys);
 
123
    a->x.from = where;
 
124
    a->limited = cmd->limited;
 
125
 
 
126
    if (!strncasecmp(where, "env=", 4)) {
 
127
        a->type = T_ENV;
 
128
        a->x.from += 4;
 
129
 
 
130
    }
 
131
    else if (!strcasecmp(where, "all")) {
 
132
        a->type = T_ALL;
 
133
    }
 
134
    else if ((s = ap_strchr(where, '/'))) {
 
135
        *s++ = '\0';
 
136
        rv = apr_ipsubnet_create(&a->x.ip, where, s, cmd->pool);
 
137
        if(APR_STATUS_IS_EINVAL(rv)) {
 
138
            /* looked nothing like an IP address */
 
139
            return "An IP address was expected";
 
140
        }
 
141
        else if (rv != APR_SUCCESS) {
 
142
            apr_strerror(rv, msgbuf, sizeof msgbuf);
 
143
            return apr_pstrdup(cmd->pool, msgbuf);
 
144
        }
 
145
        a->type = T_IP;
 
146
    }
 
147
    else if (!APR_STATUS_IS_EINVAL(rv = apr_ipsubnet_create(&a->x.ip, where,
 
148
                                                            NULL, cmd->pool))) {
 
149
        if (rv != APR_SUCCESS) {
 
150
            apr_strerror(rv, msgbuf, sizeof msgbuf);
 
151
            return apr_pstrdup(cmd->pool, msgbuf);
 
152
        }
 
153
        a->type = T_IP;
 
154
    }
 
155
    else { /* no slash, didn't look like an IP address => must be a host */
 
156
        a->type = T_HOST;
 
157
    }
 
158
 
 
159
    return NULL;
 
160
}
 
161
 
 
162
static char its_an_allow;
 
163
 
 
164
static const command_rec authz_host_cmds[] =
 
165
{
 
166
    AP_INIT_TAKE1("order", order, NULL, OR_LIMIT,
 
167
                  "'allow,deny', 'deny,allow', or 'mutual-failure'"),
 
168
    AP_INIT_ITERATE2("allow", allow_cmd, &its_an_allow, OR_LIMIT,
 
169
                     "'from' followed by hostnames or IP-address wildcards"),
 
170
    AP_INIT_ITERATE2("deny", allow_cmd, NULL, OR_LIMIT,
 
171
                     "'from' followed by hostnames or IP-address wildcards"),
 
172
    {NULL}
 
173
};
 
174
 
 
175
static int in_domain(const char *domain, const char *what)
 
176
{
 
177
    int dl = strlen(domain);
 
178
    int wl = strlen(what);
 
179
 
 
180
    if ((wl - dl) >= 0) {
 
181
        if (strcasecmp(domain, &what[wl - dl]) != 0) {
 
182
            return 0;
 
183
        }
 
184
 
 
185
        /* Make sure we matched an *entire* subdomain --- if the user
 
186
         * said 'allow from good.com', we don't want people from nogood.com
 
187
         * to be able to get in.
 
188
         */
 
189
 
 
190
        if (wl == dl) {
 
191
            return 1;                /* matched whole thing */
 
192
        }
 
193
        else {
 
194
            return (domain[0] == '.' || what[wl - dl - 1] == '.');
 
195
        }
 
196
    }
 
197
    else {
 
198
        return 0;
 
199
    }
 
200
}
 
201
 
 
202
static int find_allowdeny(request_rec *r, apr_array_header_t *a, int method)
 
203
{
 
204
 
 
205
    allowdeny *ap = (allowdeny *) a->elts;
 
206
    apr_int64_t mmask = (AP_METHOD_BIT << method);
 
207
    int i;
 
208
    int gothost = 0;
 
209
    const char *remotehost = NULL;
 
210
 
 
211
    for (i = 0; i < a->nelts; ++i) {
 
212
        if (!(mmask & ap[i].limited)) {
 
213
            continue;
 
214
        }
 
215
 
 
216
        switch (ap[i].type) {
 
217
        case T_ENV:
 
218
            if (apr_table_get(r->subprocess_env, ap[i].x.from)) {
 
219
                return 1;
 
220
            }
 
221
            break;
 
222
 
 
223
        case T_ALL:
 
224
            return 1;
 
225
 
 
226
        case T_IP:
 
227
            if (apr_ipsubnet_test(ap[i].x.ip, r->connection->remote_addr)) {
 
228
                return 1;
 
229
            }
 
230
            break;
 
231
 
 
232
        case T_HOST:
 
233
            if (!gothost) {
 
234
                int remotehost_is_ip;
 
235
 
 
236
                remotehost = ap_get_remote_host(r->connection,
 
237
                                                r->per_dir_config,
 
238
                                                REMOTE_DOUBLE_REV,
 
239
                                                &remotehost_is_ip);
 
240
 
 
241
                if ((remotehost == NULL) || remotehost_is_ip) {
 
242
                    gothost = 1;
 
243
                }
 
244
                else {
 
245
                    gothost = 2;
 
246
                }
 
247
            }
 
248
 
 
249
            if ((gothost == 2) && in_domain(ap[i].x.from, remotehost)) {
 
250
                return 1;
 
251
            }
 
252
            break;
 
253
 
 
254
        case T_FAIL:
 
255
            /* do nothing? */
 
256
            break;
 
257
        }
 
258
    }
 
259
 
 
260
    return 0;
 
261
}
 
262
 
 
263
static int check_dir_access(request_rec *r)
 
264
{
 
265
    int method = r->method_number;
 
266
    int ret = OK;
 
267
    authz_host_dir_conf *a = (authz_host_dir_conf *)
 
268
        ap_get_module_config(r->per_dir_config, &authz_host_module);
 
269
 
 
270
    if (a->order[method] == ALLOW_THEN_DENY) {
 
271
        ret = HTTP_FORBIDDEN;
 
272
        if (find_allowdeny(r, a->allows, method)) {
 
273
            ret = OK;
 
274
        }
 
275
        if (find_allowdeny(r, a->denys, method)) {
 
276
            ret = HTTP_FORBIDDEN;
 
277
        }
 
278
    }
 
279
    else if (a->order[method] == DENY_THEN_ALLOW) {
 
280
        if (find_allowdeny(r, a->denys, method)) {
 
281
            ret = HTTP_FORBIDDEN;
 
282
        }
 
283
        if (find_allowdeny(r, a->allows, method)) {
 
284
            ret = OK;
 
285
        }
 
286
    }
 
287
    else {
 
288
        if (find_allowdeny(r, a->allows, method)
 
289
            && !find_allowdeny(r, a->denys, method)) {
 
290
            ret = OK;
 
291
        }
 
292
        else {
 
293
            ret = HTTP_FORBIDDEN;
 
294
        }
 
295
    }
 
296
 
 
297
    if (ret == HTTP_FORBIDDEN
 
298
        && (ap_satisfies(r) != SATISFY_ANY || !ap_some_auth_required(r))) {
 
299
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
 
300
            "client denied by server configuration: %s",
 
301
            r->filename);
 
302
    }
 
303
 
 
304
    return ret;
 
305
}
 
306
 
 
307
static void register_hooks(apr_pool_t *p)
 
308
{
 
309
    /* This can be access checker since we don't require r->user to be set. */
 
310
    ap_hook_access_checker(check_dir_access,NULL,NULL,APR_HOOK_MIDDLE);
 
311
}
 
312
 
 
313
module AP_MODULE_DECLARE_DATA authz_host_module =
 
314
{
 
315
    STANDARD20_MODULE_STUFF,
 
316
    create_authz_host_dir_config,   /* dir config creater */
 
317
    NULL,                           /* dir merger --- default is to override */
 
318
    NULL,                           /* server config */
 
319
    NULL,                           /* merge server config */
 
320
    authz_host_cmds,
 
321
    register_hooks                  /* register hooks */
 
322
};