]> granicus.if.org Git - apache/blob - server/request.c
Merge r1745039 from trunk:
[apache] / server / request.c
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  * @file  request.c
19  * @brief functions to get and process requests
20  *
21  * @author Rob McCool 3/21/93
22  *
23  * Thoroughly revamped by rst for Apache.  NB this file reads
24  * best from the bottom up.
25  *
26  */
27
28 #include "apr_strings.h"
29 #include "apr_file_io.h"
30 #include "apr_fnmatch.h"
31
32 #define APR_WANT_STRFUNC
33 #include "apr_want.h"
34
35 #include "ap_config.h"
36 #include "ap_provider.h"
37 #include "httpd.h"
38 #include "http_config.h"
39 #include "http_request.h"
40 #include "http_core.h"
41 #include "http_protocol.h"
42 #include "http_log.h"
43 #include "http_main.h"
44 #include "util_filter.h"
45 #include "util_charset.h"
46 #include "util_script.h"
47 #include "ap_expr.h"
48 #include "mod_request.h"
49
50 #include "mod_core.h"
51 #include "mod_auth.h"
52
53 #if APR_HAVE_STDARG_H
54 #include <stdarg.h>
55 #endif
56
57 /* we know core's module_index is 0 */
58 #undef APLOG_MODULE_INDEX
59 #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
60
61 APR_HOOK_STRUCT(
62     APR_HOOK_LINK(translate_name)
63     APR_HOOK_LINK(map_to_storage)
64     APR_HOOK_LINK(check_user_id)
65     APR_HOOK_LINK(fixups)
66     APR_HOOK_LINK(type_checker)
67     APR_HOOK_LINK(access_checker)
68     APR_HOOK_LINK(access_checker_ex)
69     APR_HOOK_LINK(auth_checker)
70     APR_HOOK_LINK(insert_filter)
71     APR_HOOK_LINK(create_request)
72     APR_HOOK_LINK(post_perdir_config)
73     APR_HOOK_LINK(dirwalk_stat)
74     APR_HOOK_LINK(force_authn)
75 )
76
77 AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
78                             (request_rec *r), (r), DECLINED)
79 AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
80                             (request_rec *r), (r), DECLINED)
81 AP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id,
82                             (request_rec *r), (r), DECLINED)
83 AP_IMPLEMENT_HOOK_RUN_ALL(int,fixups,
84                           (request_rec *r), (r), OK, DECLINED)
85 AP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker,
86                             (request_rec *r), (r), DECLINED)
87 AP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker,
88                           (request_rec *r), (r), OK, DECLINED)
89 AP_IMPLEMENT_HOOK_RUN_FIRST(int,access_checker_ex,
90                           (request_rec *r), (r), DECLINED)
91 AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
92                             (request_rec *r), (r), DECLINED)
93 AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
94 AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request,
95                           (request_rec *r), (r), OK, DECLINED)
96 AP_IMPLEMENT_HOOK_RUN_ALL(int, post_perdir_config,
97                           (request_rec *r), (r), OK, DECLINED)
98 AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t,dirwalk_stat,
99                             (apr_finfo_t *finfo, request_rec *r, apr_int32_t wanted),
100                             (finfo, r, wanted), AP_DECLINED)
101 AP_IMPLEMENT_HOOK_RUN_FIRST(int,force_authn,
102                           (request_rec *r), (r), DECLINED)
103
104 static int auth_internal_per_conf = 0;
105 static int auth_internal_per_conf_hooks = 0;
106 static int auth_internal_per_conf_providers = 0;
107
108
109 static int decl_die(int status, const char *phase, request_rec *r)
110 {
111     if (status == DECLINED) {
112         ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(00025)
113                       "configuration error:  couldn't %s: %s", phase, r->uri);
114         return HTTP_INTERNAL_SERVER_ERROR;
115     }
116     else {
117         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
118                       "auth phase '%s' gave status %d: %s", phase,
119                       status, r->uri);
120         return status;
121     }
122 }
123
124 AP_DECLARE(int) ap_some_authn_required(request_rec *r)
125 {
126     int access_status;
127     char *olduser = r->user;
128     int rv = FALSE;
129
130     switch (ap_satisfies(r)) {
131     case SATISFY_ALL:
132     case SATISFY_NOSPEC:
133         if ((access_status = ap_run_access_checker(r)) != OK) {
134             break;
135         }
136
137         access_status = ap_run_access_checker_ex(r);
138         if (access_status == DECLINED) {
139             rv = TRUE;
140         }
141
142         break;
143     case SATISFY_ANY:
144         if ((access_status = ap_run_access_checker(r)) == OK) {
145             break;
146         }
147
148         access_status = ap_run_access_checker_ex(r);
149         if (access_status == DECLINED) {
150             rv = TRUE;
151         }
152
153         break;
154     }
155
156     r->user = olduser;
157     return rv;
158 }
159
160 /* This is the master logic for processing requests.  Do NOT duplicate
161  * this logic elsewhere, or the security model will be broken by future
162  * API changes.  Each phase must be individually optimized to pick up
163  * redundant/duplicate calls by subrequests, and redirects.
164  */
165 AP_DECLARE(int) ap_process_request_internal(request_rec *r)
166 {
167     int file_req = (r->main && r->filename);
168     int access_status;
169     core_dir_config *d;
170
171     /* Ignore embedded %2F's in path for proxy requests */
172     if (!r->proxyreq && r->parsed_uri.path) {
173         d = ap_get_core_module_config(r->per_dir_config);
174         if (d->allow_encoded_slashes) {
175             access_status = ap_unescape_url_keep2f(r->parsed_uri.path, d->decode_encoded_slashes);
176         }
177         else {
178             access_status = ap_unescape_url(r->parsed_uri.path);
179         }
180         if (access_status) {
181             if (access_status == HTTP_NOT_FOUND) {
182                 if (! d->allow_encoded_slashes) {
183                     ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00026)
184                                   "found %%2f (encoded '/') in URI "
185                                   "(decoded='%s'), returning 404",
186                                   r->parsed_uri.path);
187                 }
188             }
189             return access_status;
190         }
191     }
192
193     ap_getparents(r->uri);     /* OK --- shrinking transformations... */
194
195     /* All file subrequests are a huge pain... they cannot bubble through the
196      * next several steps.  Only file subrequests are allowed an empty uri,
197      * otherwise let translate_name kill the request.
198      */
199     if (!file_req) {
200         if ((access_status = ap_location_walk(r))) {
201             return access_status;
202         }
203         if ((access_status = ap_if_walk(r))) {
204             return access_status;
205         }
206
207         d = ap_get_core_module_config(r->per_dir_config);
208         if (d->log) {
209             r->log = d->log;
210         }
211
212         if ((access_status = ap_run_translate_name(r))) {
213             return decl_die(access_status, "translate", r);
214         }
215     }
216
217     /* Reset to the server default config prior to running map_to_storage
218      */
219     r->per_dir_config = r->server->lookup_defaults;
220
221     if ((access_status = ap_run_map_to_storage(r))) {
222         /* This request wasn't in storage (e.g. TRACE) */
223         return access_status;
224     }
225
226     /* Rerun the location walk, which overrides any map_to_storage config.
227      */
228     if ((access_status = ap_location_walk(r))) {
229         return access_status;
230     }
231     if ((access_status = ap_if_walk(r))) {
232         return access_status;
233     }
234
235     d = ap_get_core_module_config(r->per_dir_config);
236     if (d->log) {
237         r->log = d->log;
238     }
239
240     if ((access_status = ap_run_post_perdir_config(r))) {
241         return access_status;
242     }
243
244     /* Only on the main request! */
245     if (r->main == NULL) {
246         if ((access_status = ap_run_header_parser(r))) {
247             return access_status;
248         }
249     }
250
251     /* Skip authn/authz if the parent or prior request passed the authn/authz,
252      * and that configuration didn't change (this requires optimized _walk()
253      * functions in map_to_storage that use the same merge results given
254      * identical input.)  If the config changes, we must re-auth.
255      */
256     if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) {
257         r->user = r->prev->user;
258         r->ap_auth_type = r->prev->ap_auth_type;
259     }
260     else if (r->main && (r->main->per_dir_config == r->per_dir_config)) {
261         r->user = r->main->user;
262         r->ap_auth_type = r->main->ap_auth_type;
263     }
264     else {
265         /* A module using a confusing API (ap_get_basic_auth_pw) caused
266         ** r->user to be filled out prior to check_authn hook. We treat
267         ** it is inadvertent.
268         */
269         if (r->user && apr_table_get(r->notes, AP_GET_BASIC_AUTH_PW_NOTE)) { 
270             r->user = NULL;
271         }
272
273         switch (ap_satisfies(r)) {
274         case SATISFY_ALL:
275         case SATISFY_NOSPEC:
276             if ((access_status = ap_run_access_checker(r)) != OK) {
277                 return decl_die(access_status,
278                                 "check access (with Satisfy All)", r);
279             }
280
281             access_status = ap_run_access_checker_ex(r);
282             if (access_status == DECLINED
283                 || (access_status == OK && ap_run_force_authn(r) == OK)) {
284                 if ((access_status = ap_run_check_user_id(r)) != OK) {
285                     return decl_die(access_status, "check user", r);
286                 }
287                 if (r->user == NULL) {
288                     /* don't let buggy authn module crash us in authz */
289                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00027)
290                                   "No authentication done but request not "
291                                   "allowed without authentication for %s. "
292                                   "Authentication not configured?",
293                                   r->uri);
294                     access_status = HTTP_INTERNAL_SERVER_ERROR;
295                     return decl_die(access_status, "check user", r);
296                 }
297                 if ((access_status = ap_run_auth_checker(r)) != OK) {
298                     return decl_die(access_status, "check authorization", r);
299                 }
300             }
301             else if (access_status == OK) {
302                 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
303                               "request authorized without authentication by "
304                               "access_checker_ex hook: %s", r->uri);
305             }
306             else {
307                 return decl_die(access_status, "check access", r);
308             }
309             break;
310         case SATISFY_ANY:
311             if ((access_status = ap_run_access_checker(r)) == OK) {
312                 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
313                               "request authorized without authentication by "
314                               "access_checker hook and 'Satisfy any': %s",
315                               r->uri);
316                 break;
317             }
318
319             access_status = ap_run_access_checker_ex(r);
320             if (access_status == DECLINED
321                 || (access_status == OK && ap_run_force_authn(r) == OK)) {
322                 if ((access_status = ap_run_check_user_id(r)) != OK) {
323                     return decl_die(access_status, "check user", r);
324                 }
325                 if (r->user == NULL) {
326                     /* don't let buggy authn module crash us in authz */
327                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00028)
328                                   "No authentication done but request not "
329                                   "allowed without authentication for %s. "
330                                   "Authentication not configured?",
331                                   r->uri);
332                     access_status = HTTP_INTERNAL_SERVER_ERROR;
333                     return decl_die(access_status, "check user", r);
334                 }
335                 if ((access_status = ap_run_auth_checker(r)) != OK) {
336                     return decl_die(access_status, "check authorization", r);
337                 }
338             }
339             else if (access_status == OK) {
340                 ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r,
341                               "request authorized without authentication by "
342                               "access_checker_ex hook: %s", r->uri);
343             }
344             else {
345                 return decl_die(access_status, "check access", r);
346             }
347             break;
348         }
349     }
350     /* XXX Must make certain the ap_run_type_checker short circuits mime
351      * in mod-proxy for r->proxyreq && r->parsed_uri.scheme
352      *                              && !strcmp(r->parsed_uri.scheme, "http")
353      */
354     if ((access_status = ap_run_type_checker(r)) != OK) {
355         return decl_die(access_status, "find types", r);
356     }
357
358     if ((access_status = ap_run_fixups(r)) != OK) {
359         ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, "fixups hook gave %d: %s",
360                       access_status, r->uri);
361         return access_status;
362     }
363
364     return OK;
365 }
366
367
368 /* Useful caching structures to repeat _walk/merge sequences as required
369  * when a subrequest or redirect reuses substantially the same config.
370  *
371  * Directive order in the httpd.conf file and its Includes significantly
372  * impact this optimization.  Grouping common blocks at the front of the
373  * config that are less likely to change between a request and
374  * its subrequests, or between a request and its redirects reduced
375  * the work of these functions significantly.
376  */
377
378 typedef struct walk_walked_t {
379     ap_conf_vector_t *matched; /* A dir_conf sections we matched */
380     ap_conf_vector_t *merged;  /* The dir_conf merged result */
381 } walk_walked_t;
382
383 typedef struct walk_cache_t {
384     const char         *cached;          /* The identifier we matched */
385     ap_conf_vector_t  **dir_conf_tested; /* The sections we matched against */
386     ap_conf_vector_t   *dir_conf_merged; /* Base per_dir_config */
387     ap_conf_vector_t   *per_dir_result;  /* per_dir_config += walked result */
388     apr_array_header_t *walked;          /* The list of walk_walked_t results */
389     struct walk_cache_t *prev; /* Prev cache of same call in this (sub)req */
390     int count; /* Number of prev invocations of same call in this (sub)req */
391 } walk_cache_t;
392
393 static walk_cache_t *prep_walk_cache(apr_size_t t, request_rec *r)
394 {
395     void **note, **inherit_note;
396     walk_cache_t *cache, *prev_cache, *copy_cache;
397     int count;
398
399     /* Find the most relevant, recent walk cache to work from and provide
400      * a copy the caller is allowed to munge.  In the case of a sub-request
401      * or internal redirect, this is the cache corresponding to the equivalent
402      * invocation of the same function call in the "parent" request, if such
403      * a cache exists.  Otherwise it is the walk cache of the previous
404      * invocation of the same function call in the current request, if
405      * that exists; if not, then create a new walk cache.
406      */
407     note = ap_get_request_note(r, t);
408     AP_DEBUG_ASSERT(note != NULL);
409
410     copy_cache = prev_cache = *note;
411     count = prev_cache ? (prev_cache->count + 1) : 0;
412
413     if ((r->prev
414          && (inherit_note = ap_get_request_note(r->prev, t))
415          && *inherit_note)
416         || (r->main
417             && (inherit_note = ap_get_request_note(r->main, t))
418             && *inherit_note)) {
419         walk_cache_t *inherit_cache = *inherit_note;
420
421         while (inherit_cache->count > count) {
422             inherit_cache = inherit_cache->prev;
423         }
424         if (inherit_cache->count == count) {
425             copy_cache = inherit_cache;
426         }
427     }
428
429     if (copy_cache) {
430         cache = apr_pmemdup(r->pool, copy_cache, sizeof(*cache));
431         cache->walked = apr_array_copy(r->pool, cache->walked);
432         cache->prev = prev_cache;
433         cache->count = count;
434     }
435     else {
436         cache = apr_pcalloc(r->pool, sizeof(*cache));
437         cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t));
438     }
439
440     *note = cache;
441
442     return cache;
443 }
444
445 /*****************************************************************
446  *
447  * Getting and checking directory configuration.  Also checks the
448  * FollowSymlinks and FollowSymOwner stuff, since this is really the
449  * only place that can happen (barring a new mid_dir_walk callout).
450  *
451  * We can't do it as an access_checker module function which gets
452  * called with the final per_dir_config, since we could have a directory
453  * with FollowSymLinks disabled, which contains a symlink to another
454  * with a .htaccess file which turns FollowSymLinks back on --- and
455  * access in such a case must be denied.  So, whatever it is that
456  * checks FollowSymLinks needs to know the state of the options as
457  * they change, all the way down.
458  */
459
460
461 /*
462  * resolve_symlink must _always_ be called on an APR_LNK file type!
463  * It will resolve the actual target file type, modification date, etc,
464  * and provide any processing required for symlink evaluation.
465  * Path must already be cleaned, no trailing slash, no multi-slashes,
466  * and don't call this on the root!
467  *
468  * Simply, the number of times we deref a symlink are minimal compared
469  * to the number of times we had an extra lstat() since we 'weren't sure'.
470  *
471  * To optimize, we stat() anything when given (opts & OPT_SYM_LINKS), otherwise
472  * we start off with an lstat().  Every lstat() must be dereferenced in case
473  * it points at a 'nasty' - we must always rerun check_safe_file (or similar.)
474  */
475 static int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p)
476 {
477     apr_finfo_t fi;
478     const char *savename;
479
480     if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS))) {
481         return HTTP_FORBIDDEN;
482     }
483
484     /* Save the name from the valid bits. */
485     savename = (lfi->valid & APR_FINFO_NAME) ? lfi->name : NULL;
486
487     /* if OPT_SYM_OWNER is unset, we only need to check target accessible */
488     if (!(opts & OPT_SYM_OWNER)) {
489         if (apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME | APR_FINFO_LINK), p)
490             != APR_SUCCESS)
491         {
492             return HTTP_FORBIDDEN;
493         }
494
495         /* Give back the target */
496         memcpy(lfi, &fi, sizeof(fi));
497         if (savename) {
498             lfi->name = savename;
499             lfi->valid |= APR_FINFO_NAME;
500         }
501
502         return OK;
503     }
504
505     /* OPT_SYM_OWNER only works if we can get the owner of
506      * both the file and symlink.  First fill in a missing
507      * owner of the symlink, then get the info of the target.
508      */
509     if (!(lfi->valid & APR_FINFO_OWNER)) {
510         if (apr_stat(lfi, d, lfi->valid | APR_FINFO_LINK | APR_FINFO_OWNER, p)
511             != APR_SUCCESS)
512         {
513             return HTTP_FORBIDDEN;
514         }
515     }
516
517     if (apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME), p) != APR_SUCCESS) {
518         return HTTP_FORBIDDEN;
519     }
520
521     if (apr_uid_compare(fi.user, lfi->user) != APR_SUCCESS) {
522         return HTTP_FORBIDDEN;
523     }
524
525     /* Give back the target */
526     memcpy(lfi, &fi, sizeof(fi));
527     if (savename) {
528         lfi->name = savename;
529         lfi->valid |= APR_FINFO_NAME;
530     }
531
532     return OK;
533 }
534
535
536 /*
537  * As we walk the directory configuration, the merged config won't
538  * be 'rooted' to a specific vhost until the very end of the merge.
539  *
540  * We need a very fast mini-merge to a real, vhost-rooted merge
541  * of core.opts and core.override, the only options tested within
542  * directory_walk itself.
543  *
544  * See core.c::merge_core_dir_configs() for explanation.
545  */
546
547 typedef struct core_opts_t {
548         allow_options_t opts;
549         allow_options_t add;
550         allow_options_t remove;
551         overrides_t override;
552         overrides_t override_opts;
553         apr_table_t *override_list;
554 } core_opts_t;
555
556 static void core_opts_merge(const ap_conf_vector_t *sec, core_opts_t *opts)
557 {
558     core_dir_config *this_dir = ap_get_core_module_config(sec);
559
560     if (!this_dir) {
561         return;
562     }
563
564     if (this_dir->opts & OPT_UNSET) {
565         opts->add = (opts->add & ~this_dir->opts_remove)
566                    | this_dir->opts_add;
567         opts->remove = (opts->remove & ~this_dir->opts_add)
568                       | this_dir->opts_remove;
569         opts->opts = (opts->opts & ~opts->remove) | opts->add;
570     }
571     else {
572         opts->opts = this_dir->opts;
573         opts->add = this_dir->opts_add;
574         opts->remove = this_dir->opts_remove;
575     }
576
577     if (!(this_dir->override & OR_UNSET)) {
578         opts->override = this_dir->override;
579         opts->override_opts = this_dir->override_opts;
580     }
581
582     if (this_dir->override_list != NULL) {
583         opts->override_list = this_dir->override_list;
584     }
585 }
586
587
588 /*****************************************************************
589  *
590  * Getting and checking directory configuration.  Also checks the
591  * FollowSymlinks and FollowSymOwner stuff, since this is really the
592  * only place that can happen (barring a new mid_dir_walk callout).
593  *
594  * We can't do it as an access_checker module function which gets
595  * called with the final per_dir_config, since we could have a directory
596  * with FollowSymLinks disabled, which contains a symlink to another
597  * with a .htaccess file which turns FollowSymLinks back on --- and
598  * access in such a case must be denied.  So, whatever it is that
599  * checks FollowSymLinks needs to know the state of the options as
600  * they change, all the way down.
601  */
602
603 AP_DECLARE(int) ap_directory_walk(request_rec *r)
604 {
605     ap_conf_vector_t *now_merged = NULL;
606     core_server_config *sconf =
607         ap_get_core_module_config(r->server->module_config);
608     ap_conf_vector_t **sec_ent = (ap_conf_vector_t **) sconf->sec_dir->elts;
609     int num_sec = sconf->sec_dir->nelts;
610     walk_cache_t *cache;
611     char *entry_dir;
612     apr_status_t rv;
613     int cached;
614
615     /* XXX: Better (faster) tests needed!!!
616      *
617      * "OK" as a response to a real problem is not _OK_, but to allow broken
618      * modules to proceed, we will permit the not-a-path filename to pass the
619      * following two tests.  This behavior may be revoked in future versions
620      * of Apache.  We still must catch it later if it's heading for the core
621      * handler.  Leave INFO notes here for module debugging.
622      */
623     if (r->filename == NULL) {
624         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00029)
625                       "Module bug?  Request filename is missing for URI %s",
626                       r->uri);
627         return OK;
628     }
629
630     /* Canonicalize the file path without resolving filename case or aliases
631      * so we can begin by checking the cache for a recent directory walk.
632      * This call will ensure we have an absolute path in the same pass.
633      */
634     if ((rv = apr_filepath_merge(&entry_dir, NULL, r->filename,
635                                  APR_FILEPATH_NOTRELATIVE, r->pool))
636                   != APR_SUCCESS) {
637         ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00030)
638                       "Module bug?  Request filename path %s is invalid or "
639                       "or not absolute for uri %s",
640                       r->filename, r->uri);
641         return OK;
642     }
643
644     /* XXX Notice that this forces path_info to be canonical.  That might
645      * not be desired by all apps.  However, some of those same apps likely
646      * have significant security holes.
647      */
648     r->filename = entry_dir;
649
650     cache = prep_walk_cache(AP_NOTE_DIRECTORY_WALK, r);
651     cached = (cache->cached != NULL);
652
653     /* If this is not a dirent subrequest with a preconstructed
654      * r->finfo value, then we can simply stat the filename to
655      * save burning mega-cycles with unneeded stats - if this is
656      * an exact file match.  We don't care about failure... we
657      * will stat by component failing this meager attempt.
658      *
659      * It would be nice to distinguish APR_ENOENT from other
660      * types of failure, such as APR_ENOTDIR.  We can do something
661      * with APR_ENOENT, knowing that the path is good.
662      */
663     if (r->finfo.filetype == APR_NOFILE || r->finfo.filetype == APR_LNK) {
664         rv = ap_run_dirwalk_stat(&r->finfo, r, APR_FINFO_MIN);
665
666         /* some OSs will return APR_SUCCESS/APR_REG if we stat
667          * a regular file but we have '/' at the end of the name;
668          *
669          * other OSs will return APR_ENOTDIR for that situation;
670          *
671          * handle it the same everywhere by simulating a failure
672          * if it looks like a directory but really isn't
673          *
674          * Also reset if the stat failed, just for safety.
675          */
676         if ((rv != APR_SUCCESS) ||
677             (r->finfo.filetype != APR_NOFILE &&
678              (r->finfo.filetype != APR_DIR) &&
679              (r->filename[strlen(r->filename) - 1] == '/'))) {
680              r->finfo.filetype = APR_NOFILE; /* forget what we learned */
681         }
682     }
683
684     if (r->finfo.filetype == APR_REG) {
685         entry_dir = ap_make_dirstr_parent(r->pool, entry_dir);
686     }
687     else if (r->filename[strlen(r->filename) - 1] != '/') {
688         entry_dir = apr_pstrcat(r->pool, r->filename, "/", NULL);
689     }
690
691     /* If we have a file already matches the path of r->filename,
692      * and the vhost's list of directory sections hasn't changed,
693      * we can skip rewalking the directory_walk entries.
694      */
695     if (cached
696         && ((r->finfo.filetype == APR_REG)
697             || ((r->finfo.filetype == APR_DIR)
698                 && (!r->path_info || !*r->path_info)))
699         && (cache->dir_conf_tested == sec_ent)
700         && (strcmp(entry_dir, cache->cached) == 0)) {
701         int familiar = 0;
702
703         /* Well this looks really familiar!  If our end-result (per_dir_result)
704          * didn't change, we have absolutely nothing to do :)
705          * Otherwise (as is the case with most dir_merged/file_merged requests)
706          * we must merge our dir_conf_merged onto this new r->per_dir_config.
707          */
708         if (r->per_dir_config == cache->per_dir_result) {
709             familiar = 1;
710         }
711
712         if (r->per_dir_config == cache->dir_conf_merged) {
713             r->per_dir_config = cache->per_dir_result;
714             familiar = 1;
715         }
716
717         if (familiar) {
718             apr_finfo_t thisinfo;
719             int res;
720             allow_options_t opts;
721             core_dir_config *this_dir;
722
723             this_dir = ap_get_core_module_config(r->per_dir_config);
724             opts = this_dir->opts;
725             /*
726              * If Symlinks are allowed in general we do not need the following
727              * check.
728              */
729             if (!(opts & OPT_SYM_LINKS)) {
730                 rv = ap_run_dirwalk_stat(&thisinfo, r,
731                                          APR_FINFO_MIN | APR_FINFO_NAME | APR_FINFO_LINK);
732                 /*
733                  * APR_INCOMPLETE is as fine as result as APR_SUCCESS as we
734                  * have added APR_FINFO_NAME to the wanted parameter of
735                  * apr_stat above. On Unix platforms this means that apr_stat
736                  * is always going to return APR_INCOMPLETE in the case that
737                  * the call to the native stat / lstat did not fail.
738                  */
739                 if ((rv != APR_INCOMPLETE) && (rv != APR_SUCCESS)) {
740                     /*
741                      * This should never happen, because we did a stat on the
742                      * same file, resolving a possible symlink several lines
743                      * above. Therefore do not make a detailed analysis of rv
744                      * in this case for the reason of the failure, just bail out
745                      * with a HTTP_FORBIDDEN in case we hit a race condition
746                      * here.
747                      */
748                     ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00031)
749                                   "access to %s failed; stat of '%s' failed.",
750                                   r->uri, r->filename);
751                     return r->status = HTTP_FORBIDDEN;
752                 }
753                 if (thisinfo.filetype == APR_LNK) {
754                     /* Is this a possibly acceptable symlink? */
755                     if ((res = resolve_symlink(r->filename, &thisinfo,
756                                                opts, r->pool)) != OK) {
757                         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00032)
758                                       "Symbolic link not allowed "
759                                       "or link target not accessible: %s",
760                                       r->filename);
761                         return r->status = res;
762                     }
763                 }
764             }
765             return OK;
766         }
767
768         if (cache->walked->nelts) {
769             now_merged = ((walk_walked_t*)cache->walked->elts)
770                 [cache->walked->nelts - 1].merged;
771         }
772     }
773     else {
774         /* We start now_merged from NULL since we want to build
775          * a locations list that can be merged to any vhost.
776          */
777         int sec_idx;
778         int matches = cache->walked->nelts;
779         int cached_matches = matches;
780         walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
781         core_dir_config *this_dir;
782         core_opts_t opts;
783         apr_finfo_t thisinfo;
784         char *save_path_info;
785         apr_size_t buflen;
786         char *buf;
787         unsigned int seg, startseg;
788         apr_pool_t *rxpool = NULL;
789
790         /* Invariant: from the first time filename_len is set until
791          * it goes out of scope, filename_len==strlen(r->filename)
792          */
793         apr_size_t filename_len;
794 #ifdef CASE_BLIND_FILESYSTEM
795         apr_size_t canonical_len;
796 #endif
797
798         cached &= auth_internal_per_conf;
799
800         /*
801          * We must play our own mini-merge game here, for the few
802          * running dir_config values we care about within dir_walk.
803          * We didn't start the merge from r->per_dir_config, so we
804          * accumulate opts and override as we merge, from the globals.
805          */
806         this_dir = ap_get_core_module_config(r->per_dir_config);
807         opts.opts = this_dir->opts;
808         opts.add = this_dir->opts_add;
809         opts.remove = this_dir->opts_remove;
810         opts.override = this_dir->override;
811         opts.override_opts = this_dir->override_opts;
812         opts.override_list = this_dir->override_list;
813
814         /* Set aside path_info to merge back onto path_info later.
815          * If r->filename is a directory, we must remerge the path_info,
816          * before we continue!  [Directories cannot, by definition, have
817          * path info.  Either the next segment is not-found, or a file.]
818          *
819          * r->path_info tracks the unconsumed source path.
820          * r->filename  tracks the path as we process it
821          */
822         if ((r->finfo.filetype == APR_DIR) && r->path_info && *r->path_info)
823         {
824             if ((rv = apr_filepath_merge(&r->path_info, r->filename,
825                                          r->path_info,
826                                          APR_FILEPATH_NOTABOVEROOT, r->pool))
827                 != APR_SUCCESS) {
828                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00033)
829                               "dir_walk error, path_info %s is not relative "
830                               "to the filename path %s for uri %s",
831                               r->path_info, r->filename, r->uri);
832                 return HTTP_INTERNAL_SERVER_ERROR;
833             }
834
835             save_path_info = NULL;
836         }
837         else {
838             save_path_info = r->path_info;
839             r->path_info = r->filename;
840         }
841
842 #ifdef CASE_BLIND_FILESYSTEM
843
844         canonical_len = 0;
845         while (r->canonical_filename && r->canonical_filename[canonical_len]
846                && (r->canonical_filename[canonical_len]
847                    == r->path_info[canonical_len])) {
848              ++canonical_len;
849         }
850
851         while (canonical_len
852                && ((r->canonical_filename[canonical_len - 1] != '/'
853                    && r->canonical_filename[canonical_len - 1])
854                    || (r->path_info[canonical_len - 1] != '/'
855                        && r->path_info[canonical_len - 1]))) {
856             --canonical_len;
857         }
858
859         /*
860          * Now build r->filename component by component, starting
861          * with the root (on Unix, simply "/").  We will make a huge
862          * assumption here for efficiency, that any canonical path
863          * already given included a canonical root.
864          */
865         rv = apr_filepath_root((const char **)&r->filename,
866                                (const char **)&r->path_info,
867                                canonical_len ? 0 : APR_FILEPATH_TRUENAME,
868                                r->pool);
869         filename_len = strlen(r->filename);
870
871         /*
872          * Bad assumption above?  If the root's length is longer
873          * than the canonical length, then it cannot be trusted as
874          * a truename.  So try again, this time more seriously.
875          */
876         if ((rv == APR_SUCCESS) && canonical_len
877             && (filename_len > canonical_len)) {
878             rv = apr_filepath_root((const char **)&r->filename,
879                                    (const char **)&r->path_info,
880                                    APR_FILEPATH_TRUENAME, r->pool);
881             filename_len = strlen(r->filename);
882             canonical_len = 0;
883         }
884
885 #else /* ndef CASE_BLIND_FILESYSTEM, really this simple for Unix today; */
886
887         rv = apr_filepath_root((const char **)&r->filename,
888                                (const char **)&r->path_info,
889                                0, r->pool);
890         filename_len = strlen(r->filename);
891
892 #endif
893
894         if (rv != APR_SUCCESS) {
895             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00034)
896                           "dir_walk error, could not determine the root "
897                           "path of filename %s%s for uri %s",
898                           r->filename, r->path_info, r->uri);
899             return HTTP_INTERNAL_SERVER_ERROR;
900         }
901
902         /* Working space for terminating null and an extra / is required.
903          */
904         buflen = filename_len + strlen(r->path_info) + 2;
905         buf = apr_palloc(r->pool, buflen);
906         memcpy(buf, r->filename, filename_len + 1);
907         r->filename = buf;
908         thisinfo.valid = APR_FINFO_TYPE;
909         thisinfo.filetype = APR_DIR; /* It's the root, of course it's a dir */
910
911         /*
912          * seg keeps track of which segment we've copied.
913          * sec_idx keeps track of which section we're on, since sections are
914          *     ordered by number of segments. See core_reorder_directories
915          * startseg tells us how many segments describe the root path
916          *     e.g. the complete path "//host/foo/" to a UNC share (4)
917          */
918         startseg = seg = ap_count_dirs(r->filename);
919         sec_idx = 0;
920
921         /*
922          * Go down the directory hierarchy.  Where we have to check for
923          * symlinks, do so.  Where a .htaccess file has permission to
924          * override anything, try to find one.
925          */
926         do {
927             int res;
928             char *seg_name;
929             char *delim;
930             int temp_slash=0;
931
932             /* We have no trailing slash, but we sure would appreciate one.
933              * However, we don't want to append a / our first time through.
934              */
935             if ((seg > startseg) && r->filename[filename_len-1] != '/') {
936                 r->filename[filename_len++] = '/';
937                 r->filename[filename_len] = 0;
938                 temp_slash=1;
939             }
940
941             /* Begin *this* level by looking for matching <Directory> sections
942              * from the server config.
943              */
944             for (; sec_idx < num_sec; ++sec_idx) {
945
946                 ap_conf_vector_t *entry_config = sec_ent[sec_idx];
947                 core_dir_config *entry_core;
948                 entry_core = ap_get_core_module_config(entry_config);
949
950                 /* No more possible matches for this many segments?
951                  * We are done when we find relative/regex/longer components.
952                  */
953                 if (entry_core->r || entry_core->d_components > seg) {
954                     break;
955                 }
956
957                 /* We will never skip '0' element components, e.g. plain old
958                  * <Directory >, and <Directory "/"> are classified as zero
959                  * so that Win32/Netware/OS2 etc all pick them up.
960                  * Otherwise, skip over the mismatches.
961                  */
962                 if (entry_core->d_components
963                     && ((entry_core->d_components < seg)
964                      || (entry_core->d_is_fnmatch
965                          ? (apr_fnmatch(entry_core->d, r->filename,
966                                         APR_FNM_PATHNAME) != APR_SUCCESS)
967                          : (strcmp(r->filename, entry_core->d) != 0)))) {
968                     continue;
969                 }
970
971                 /* If we haven't continue'd above, we have a match.
972                  *
973                  * Calculate our full-context core opts & override.
974                  */
975                 core_opts_merge(sec_ent[sec_idx], &opts);
976
977                 /* If we merged this same section last time, reuse it
978                  */
979                 if (matches) {
980                     if (last_walk->matched == sec_ent[sec_idx]) {
981                         now_merged = last_walk->merged;
982                         ++last_walk;
983                         --matches;
984                         continue;
985                     }
986
987                     /* We fell out of sync.  This is our own copy of walked,
988                      * so truncate the remaining matches and reset remaining.
989                      */
990                     cache->walked->nelts -= matches;
991                     matches = 0;
992                     cached = 0;
993                 }
994
995                 if (now_merged) {
996                     now_merged = ap_merge_per_dir_configs(r->pool,
997                                                           now_merged,
998                                                           sec_ent[sec_idx]);
999                 }
1000                 else {
1001                     now_merged = sec_ent[sec_idx];
1002                 }
1003
1004                 last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1005                 last_walk->matched = sec_ent[sec_idx];
1006                 last_walk->merged = now_merged;
1007             }
1008
1009             /* If .htaccess files are enabled, check for one, provided we
1010              * have reached a real path.
1011              */
1012             do {  /* Not really a loop, just a break'able code block */
1013
1014                 ap_conf_vector_t *htaccess_conf = NULL;
1015
1016                 /* No htaccess in an incomplete root path,
1017                  * nor if it's disabled
1018                  */
1019                 if (seg < startseg || (!opts.override 
1020                     && apr_is_empty_table(opts.override_list)
1021                     )) {
1022                     break;
1023                 }
1024
1025
1026                 res = ap_parse_htaccess(&htaccess_conf, r, opts.override,
1027                                         opts.override_opts, opts.override_list,
1028                                         r->filename, sconf->access_name);
1029                 if (res) {
1030                     return res;
1031                 }
1032
1033                 if (!htaccess_conf) {
1034                     break;
1035                 }
1036
1037                 /* If we are still here, we found our htaccess.
1038                  *
1039                  * Calculate our full-context core opts & override.
1040                  */
1041                 core_opts_merge(htaccess_conf, &opts);
1042
1043                 /* If we merged this same htaccess last time, reuse it...
1044                  * this wouldn't work except that we cache the htaccess
1045                  * sections for the lifetime of the request, so we match
1046                  * the same conf.  Good planning (no, pure luck ;)
1047                  */
1048                 if (matches) {
1049                     if (last_walk->matched == htaccess_conf) {
1050                         now_merged = last_walk->merged;
1051                         ++last_walk;
1052                         --matches;
1053                         break;
1054                     }
1055
1056                     /* We fell out of sync.  This is our own copy of walked,
1057                      * so truncate the remaining matches and reset
1058                      * remaining.
1059                      */
1060                     cache->walked->nelts -= matches;
1061                     matches = 0;
1062                     cached = 0;
1063                 }
1064
1065                 if (now_merged) {
1066                     now_merged = ap_merge_per_dir_configs(r->pool,
1067                                                           now_merged,
1068                                                           htaccess_conf);
1069                 }
1070                 else {
1071                     now_merged = htaccess_conf;
1072                 }
1073
1074                 last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1075                 last_walk->matched = htaccess_conf;
1076                 last_walk->merged = now_merged;
1077
1078             } while (0); /* Only one htaccess, not a real loop */
1079
1080             /* That temporary trailing slash was useful, now drop it.
1081              */
1082             if (temp_slash) {
1083                 r->filename[--filename_len] = '\0';
1084             }
1085
1086             /* Time for all good things to come to an end?
1087              */
1088             if (!r->path_info || !*r->path_info) {
1089                 break;
1090             }
1091
1092             /* Now it's time for the next segment...
1093              * We will assume the next element is an end node, and fix it up
1094              * below as necessary...
1095              */
1096
1097             seg_name = r->filename + filename_len;
1098             delim = strchr(r->path_info + (*r->path_info == '/' ? 1 : 0), '/');
1099             if (delim) {
1100                 apr_size_t path_info_len = delim - r->path_info;
1101                 *delim = '\0';
1102                 memcpy(seg_name, r->path_info, path_info_len + 1);
1103                 filename_len += path_info_len;
1104                 r->path_info = delim;
1105                 *delim = '/';
1106             }
1107             else {
1108                 apr_size_t path_info_len = strlen(r->path_info);
1109                 memcpy(seg_name, r->path_info, path_info_len + 1);
1110                 filename_len += path_info_len;
1111                 r->path_info += path_info_len;
1112             }
1113             if (*seg_name == '/')
1114                 ++seg_name;
1115
1116             /* If nothing remained but a '/' string, we are finished
1117              * XXX: NO WE ARE NOT!!!  Now process this puppy!!! */
1118             if (!*seg_name) {
1119                 break;
1120             }
1121
1122             /* First optimization;
1123              * If...we knew r->filename was a file, and
1124              * if...we have strict (case-sensitive) filenames, or
1125              *      we know the canonical_filename matches to _this_ name, and
1126              * if...we have allowed symlinks
1127              * skip the lstat and dummy up an APR_DIR value for thisinfo.
1128              */
1129             if (r->finfo.filetype != APR_NOFILE
1130 #ifdef CASE_BLIND_FILESYSTEM
1131                 && (filename_len <= canonical_len)
1132 #endif
1133                 && ((opts.opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)) == OPT_SYM_LINKS))
1134             {
1135
1136                 thisinfo.filetype = APR_DIR;
1137                 ++seg;
1138                 continue;
1139             }
1140
1141             /* We choose apr_stat with flag APR_FINFO_LINK here, rather that
1142              * plain apr_stat, so that we capture this path object rather than
1143              * its target.  We will replace the info with our target's info
1144              * below.  We especially want the name of this 'link' object, not
1145              * the name of its target, if we are fixing the filename
1146              * case/resolving aliases.
1147              */
1148             rv = ap_run_dirwalk_stat(&thisinfo, r,
1149                                      APR_FINFO_MIN | APR_FINFO_NAME | APR_FINFO_LINK);
1150
1151             if (APR_STATUS_IS_ENOENT(rv)) {
1152                 /* Nothing?  That could be nice.  But our directory
1153                  * walk is done.
1154                  */
1155                 thisinfo.filetype = APR_NOFILE;
1156                 break;
1157             }
1158             else if (APR_STATUS_IS_EACCES(rv)) {
1159                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00035)
1160                               "access to %s denied (filesystem path '%s') "
1161                               "because search permissions are missing on a "
1162                               "component of the path", r->uri, r->filename);
1163                 return r->status = HTTP_FORBIDDEN;
1164             }
1165             else if ((rv != APR_SUCCESS && rv != APR_INCOMPLETE)
1166                      || !(thisinfo.valid & APR_FINFO_TYPE)) {
1167                 /* If we hit ENOTDIR, we must have over-optimized, deny
1168                  * rather than assume not found.
1169                  */
1170                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00036)
1171                               "access to %s failed (filesystem path '%s')", 
1172                               r->uri, r->filename);
1173                 return r->status = HTTP_FORBIDDEN;
1174             }
1175
1176             /* Fix up the path now if we have a name, and they don't agree
1177              */
1178             if ((thisinfo.valid & APR_FINFO_NAME)
1179                 && strcmp(seg_name, thisinfo.name)) {
1180                 /* TODO: provide users an option that an internal/external
1181                  * redirect is required here?  We need to walk the URI and
1182                  * filename in tandem to properly correlate these.
1183                  */
1184                 strcpy(seg_name, thisinfo.name);
1185                 filename_len = strlen(r->filename);
1186             }
1187
1188             if (thisinfo.filetype == APR_LNK) {
1189                 /* Is this a possibly acceptable symlink?
1190                  */
1191                 if ((res = resolve_symlink(r->filename, &thisinfo,
1192                                            opts.opts, r->pool)) != OK) {
1193                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00037)
1194                                   "Symbolic link not allowed "
1195                                   "or link target not accessible: %s",
1196                                   r->filename);
1197                     return r->status = res;
1198                 }
1199             }
1200
1201             /* Ok, we are done with the link's info, test the real target
1202              */
1203             if (thisinfo.filetype == APR_REG ||
1204                 thisinfo.filetype == APR_NOFILE) {
1205                 /* That was fun, nothing left for us here
1206                  */
1207                 break;
1208             }
1209             else if (thisinfo.filetype != APR_DIR) {
1210                 ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00038)
1211                               "Forbidden: %s doesn't point to "
1212                               "a file or directory",
1213                               r->filename);
1214                 return r->status = HTTP_FORBIDDEN;
1215             }
1216
1217             ++seg;
1218         } while (thisinfo.filetype == APR_DIR);
1219
1220         /* If we have _not_ optimized, this is the time to recover
1221          * the final stat result.
1222          */
1223         if (r->finfo.filetype == APR_NOFILE || r->finfo.filetype == APR_LNK) {
1224             r->finfo = thisinfo;
1225         }
1226
1227         /* Now splice the saved path_info back onto any new path_info
1228          */
1229         if (save_path_info) {
1230             if (r->path_info && *r->path_info) {
1231                 r->path_info = ap_make_full_path(r->pool, r->path_info,
1232                                                  save_path_info);
1233             }
1234             else {
1235                 r->path_info = save_path_info;
1236             }
1237         }
1238
1239         /*
1240          * Now we'll deal with the regexes, note we pick up sec_idx
1241          * where we left off (we gave up after we hit entry_core->r)
1242          */
1243         for (; sec_idx < num_sec; ++sec_idx) {
1244
1245             int nmatch = 0;
1246             int i;
1247             ap_regmatch_t *pmatch = NULL;
1248
1249             core_dir_config *entry_core;
1250             entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
1251
1252             if (!entry_core->r) {
1253                 continue;
1254             }
1255
1256             if (entry_core->refs && entry_core->refs->nelts) {
1257                 if (!rxpool) {
1258                     apr_pool_create(&rxpool, r->pool);
1259                 }
1260                 nmatch = entry_core->refs->nelts;
1261                 pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
1262             }
1263
1264             if (ap_regexec(entry_core->r, r->filename, nmatch, pmatch, 0)) {
1265                 continue;
1266             }
1267
1268             for (i = 0; i < nmatch; i++) {
1269                 if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 &&
1270                     ((const char **)entry_core->refs->elts)[i]) {
1271                     apr_table_setn(r->subprocess_env, 
1272                                    ((const char **)entry_core->refs->elts)[i],
1273                                    apr_pstrndup(r->pool,
1274                                    r->filename + pmatch[i].rm_so,
1275                                    pmatch[i].rm_eo - pmatch[i].rm_so));
1276                 }
1277             }
1278
1279             /* If we haven't already continue'd above, we have a match.
1280              *
1281              * Calculate our full-context core opts & override.
1282              */
1283             core_opts_merge(sec_ent[sec_idx], &opts);
1284
1285             /* If we merged this same section last time, reuse it
1286              */
1287             if (matches) {
1288                 if (last_walk->matched == sec_ent[sec_idx]) {
1289                     now_merged = last_walk->merged;
1290                     ++last_walk;
1291                     --matches;
1292                     continue;
1293                 }
1294
1295                 /* We fell out of sync.  This is our own copy of walked,
1296                  * so truncate the remaining matches and reset remaining.
1297                  */
1298                 cache->walked->nelts -= matches;
1299                 matches = 0;
1300                 cached = 0;
1301             }
1302
1303             if (now_merged) {
1304                 now_merged = ap_merge_per_dir_configs(r->pool,
1305                                                       now_merged,
1306                                                       sec_ent[sec_idx]);
1307             }
1308             else {
1309                 now_merged = sec_ent[sec_idx];
1310             }
1311
1312             last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1313             last_walk->matched = sec_ent[sec_idx];
1314             last_walk->merged = now_merged;
1315         }
1316
1317         if (rxpool) {
1318             apr_pool_destroy(rxpool);
1319         }
1320
1321         /* Whoops - everything matched in sequence, but either the original
1322          * walk found some additional matches (which we need to truncate), or
1323          * this walk found some additional matches.
1324          */
1325         if (matches) {
1326             cache->walked->nelts -= matches;
1327             cached = 0;
1328         }
1329         else if (cache->walked->nelts > cached_matches) {
1330             cached = 0;
1331         }
1332     }
1333
1334 /* It seems this shouldn't be needed anymore.  We translated the
1335  x symlink above into a real resource, and should have died up there.
1336  x Even if we keep this, it needs more thought (maybe an r->file_is_symlink)
1337  x perhaps it should actually happen in file_walk, so we catch more
1338  x obscure cases in autoindex subrequests, etc.
1339  x
1340  x    * Symlink permissions are determined by the parent.  If the request is
1341  x    * for a directory then applying the symlink test here would use the
1342  x    * permissions of the directory as opposed to its parent.  Consider a
1343  x    * symlink pointing to a dir with a .htaccess disallowing symlinks.  If
1344  x    * you access /symlink (or /symlink/) you would get a 403 without this
1345  x    * APR_DIR test.  But if you accessed /symlink/index.html, for example,
1346  x    * you would *not* get the 403.
1347  x
1348  x   if (r->finfo.filetype != APR_DIR
1349  x       && (res = resolve_symlink(r->filename, r->info, ap_allow_options(r),
1350  x                                 r->pool))) {
1351  x       ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
1352  x                     "Symbolic link not allowed: %s", r->filename);
1353  x       return res;
1354  x   }
1355  */
1356
1357     /* Save future sub-requestors much angst in processing
1358      * this subrequest.  If dir_walk couldn't canonicalize
1359      * the file path, nothing can.
1360      */
1361     r->canonical_filename = r->filename;
1362
1363     if (r->finfo.filetype == APR_DIR) {
1364         cache->cached = r->filename;
1365     }
1366     else {
1367         cache->cached = ap_make_dirstr_parent(r->pool, r->filename);
1368     }
1369
1370     if (cached
1371         && r->per_dir_config == cache->dir_conf_merged) {
1372         r->per_dir_config = cache->per_dir_result;
1373         return OK;
1374     }
1375
1376     cache->dir_conf_tested = sec_ent;
1377     cache->dir_conf_merged = r->per_dir_config;
1378
1379     /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
1380      * and note the end result to (potentially) skip this step next time.
1381      */
1382     if (now_merged) {
1383         r->per_dir_config = ap_merge_per_dir_configs(r->pool,
1384                                                      r->per_dir_config,
1385                                                      now_merged);
1386     }
1387     cache->per_dir_result = r->per_dir_config;
1388
1389     return OK;
1390 }
1391
1392
1393 AP_DECLARE(int) ap_location_walk(request_rec *r)
1394 {
1395     ap_conf_vector_t *now_merged = NULL;
1396     core_server_config *sconf =
1397         ap_get_core_module_config(r->server->module_config);
1398     ap_conf_vector_t **sec_ent = (ap_conf_vector_t **)sconf->sec_url->elts;
1399     int num_sec = sconf->sec_url->nelts;
1400     walk_cache_t *cache;
1401     const char *entry_uri;
1402     int cached;
1403
1404     /* No tricks here, there are no <Locations > to parse in this vhost.
1405      * We won't destroy the cache, just in case _this_ redirect is later
1406      * redirected again to a vhost with <Location > blocks to optimize.
1407      */
1408     if (!num_sec) {
1409         return OK;
1410     }
1411
1412     cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r);
1413     cached = (cache->cached != NULL);
1414
1415     /* Location and LocationMatch differ on their behaviour w.r.t. multiple
1416      * slashes.  Location matches multiple slashes with a single slash,
1417      * LocationMatch doesn't.  An exception, for backwards brokenness is
1418      * absoluteURIs... in which case neither match multiple slashes.
1419      */
1420     if (r->uri[0] != '/') {
1421         entry_uri = r->uri;
1422     }
1423     else {
1424         char *uri = apr_pstrdup(r->pool, r->uri);
1425         ap_no2slash(uri);
1426         entry_uri = uri;
1427     }
1428
1429     /* If we have an cache->cached location that matches r->uri,
1430      * and the vhost's list of locations hasn't changed, we can skip
1431      * rewalking the location_walk entries.
1432      */
1433     if (cached
1434         && (cache->dir_conf_tested == sec_ent)
1435         && (strcmp(entry_uri, cache->cached) == 0)) {
1436         /* Well this looks really familiar!  If our end-result (per_dir_result)
1437          * didn't change, we have absolutely nothing to do :)
1438          * Otherwise (as is the case with most dir_merged/file_merged requests)
1439          * we must merge our dir_conf_merged onto this new r->per_dir_config.
1440          */
1441         if (r->per_dir_config == cache->per_dir_result) {
1442             return OK;
1443         }
1444
1445         if (cache->walked->nelts) {
1446             now_merged = ((walk_walked_t*)cache->walked->elts)
1447                                             [cache->walked->nelts - 1].merged;
1448         }
1449     }
1450     else {
1451         /* We start now_merged from NULL since we want to build
1452          * a locations list that can be merged to any vhost.
1453          */
1454         int len, sec_idx;
1455         int matches = cache->walked->nelts;
1456         int cached_matches = matches;
1457         walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
1458         apr_pool_t *rxpool = NULL;
1459
1460         cached &= auth_internal_per_conf;
1461         cache->cached = entry_uri;
1462
1463         /* Go through the location entries, and check for matches.
1464          * We apply the directive sections in given order, we should
1465          * really try them with the most general first.
1466          */
1467         for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
1468
1469             core_dir_config *entry_core;
1470             entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
1471
1472             /* ### const strlen can be optimized in location config parsing */
1473             len = strlen(entry_core->d);
1474
1475             /* Test the regex, fnmatch or string as appropriate.
1476              * If it's a strcmp, and the <Location > pattern was
1477              * not slash terminated, then this uri must be slash
1478              * terminated (or at the end of the string) to match.
1479              */
1480             if (entry_core->r) {
1481
1482                 int nmatch = 0;
1483                 int i;
1484                 ap_regmatch_t *pmatch = NULL;
1485
1486                 if (entry_core->refs && entry_core->refs->nelts) {
1487                     if (!rxpool) {
1488                         apr_pool_create(&rxpool, r->pool);
1489                     }
1490                     nmatch = entry_core->refs->nelts;
1491                     pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
1492                 }
1493
1494                 if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) {
1495                     continue;
1496                 }
1497
1498                 for (i = 0; i < nmatch; i++) {
1499                     if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && 
1500                         ((const char **)entry_core->refs->elts)[i]) {
1501                         apr_table_setn(r->subprocess_env,
1502                                        ((const char **)entry_core->refs->elts)[i],
1503                                        apr_pstrndup(r->pool,
1504                                        r->uri + pmatch[i].rm_so,
1505                                        pmatch[i].rm_eo - pmatch[i].rm_so));
1506                     }
1507                 }
1508
1509             }
1510             else {
1511
1512                 if ((entry_core->d_is_fnmatch
1513                    ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
1514                    : (strncmp(entry_core->d, cache->cached, len)
1515                       || (len > 0
1516                           && entry_core->d[len - 1] != '/'
1517                           && cache->cached[len] != '/'
1518                           && cache->cached[len] != '\0')))) {
1519                     continue;
1520                 }
1521
1522             }
1523
1524             /* If we merged this same section last time, reuse it
1525              */
1526             if (matches) {
1527                 if (last_walk->matched == sec_ent[sec_idx]) {
1528                     now_merged = last_walk->merged;
1529                     ++last_walk;
1530                     --matches;
1531                     continue;
1532                 }
1533
1534                 /* We fell out of sync.  This is our own copy of walked,
1535                  * so truncate the remaining matches and reset remaining.
1536                  */
1537                 cache->walked->nelts -= matches;
1538                 matches = 0;
1539                 cached = 0;
1540             }
1541
1542             if (now_merged) {
1543                 now_merged = ap_merge_per_dir_configs(r->pool,
1544                                                       now_merged,
1545                                                       sec_ent[sec_idx]);
1546             }
1547             else {
1548                 now_merged = sec_ent[sec_idx];
1549             }
1550
1551             last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1552             last_walk->matched = sec_ent[sec_idx];
1553             last_walk->merged = now_merged;
1554         }
1555
1556         if (rxpool) {
1557             apr_pool_destroy(rxpool);
1558         }
1559
1560         /* Whoops - everything matched in sequence, but either the original
1561          * walk found some additional matches (which we need to truncate), or
1562          * this walk found some additional matches.
1563          */
1564         if (matches) {
1565             cache->walked->nelts -= matches;
1566             cached = 0;
1567         }
1568         else if (cache->walked->nelts > cached_matches) {
1569             cached = 0;
1570         }
1571     }
1572
1573     if (cached
1574         && r->per_dir_config == cache->dir_conf_merged) {
1575         r->per_dir_config = cache->per_dir_result;
1576         return OK;
1577     }
1578
1579     cache->dir_conf_tested = sec_ent;
1580     cache->dir_conf_merged = r->per_dir_config;
1581
1582     /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
1583      * and note the end result to (potentially) skip this step next time.
1584      */
1585     if (now_merged) {
1586         r->per_dir_config = ap_merge_per_dir_configs(r->pool,
1587                                                      r->per_dir_config,
1588                                                      now_merged);
1589     }
1590     cache->per_dir_result = r->per_dir_config;
1591
1592     return OK;
1593 }
1594
1595 AP_DECLARE(int) ap_file_walk(request_rec *r)
1596 {
1597     ap_conf_vector_t *now_merged = NULL;
1598     core_dir_config *dconf = ap_get_core_module_config(r->per_dir_config);
1599     ap_conf_vector_t **sec_ent = NULL;
1600     int num_sec = 0;
1601     walk_cache_t *cache;
1602     const char *test_file;
1603     int cached;
1604
1605     if (dconf->sec_file) {
1606         sec_ent = (ap_conf_vector_t **)dconf->sec_file->elts;
1607         num_sec = dconf->sec_file->nelts;
1608     }
1609
1610     /* To allow broken modules to proceed, we allow missing filenames to pass.
1611      * We will catch it later if it's heading for the core handler.
1612      * directory_walk already posted an INFO note for module debugging.
1613      */
1614     if (r->filename == NULL) {
1615         return OK;
1616     }
1617
1618     /* No tricks here, there are just no <Files > to parse in this context.
1619      * We won't destroy the cache, just in case _this_ redirect is later
1620      * redirected again to a context containing the same or similar <Files >.
1621      */
1622     if (!num_sec) {
1623         return OK;
1624     }
1625
1626     cache = prep_walk_cache(AP_NOTE_FILE_WALK, r);
1627     cached = (cache->cached != NULL);
1628
1629     /* Get the basename .. and copy for the cache just
1630      * in case r->filename is munged by another module
1631      */
1632     test_file = strrchr(r->filename, '/');
1633     if (test_file == NULL) {
1634         test_file = apr_pstrdup(r->pool, r->filename);
1635     }
1636     else {
1637         test_file = apr_pstrdup(r->pool, ++test_file);
1638     }
1639
1640     /* If we have an cache->cached file name that matches test_file,
1641      * and the directory's list of file sections hasn't changed, we
1642      * can skip rewalking the file_walk entries.
1643      */
1644     if (cached
1645         && (cache->dir_conf_tested == sec_ent)
1646         && (strcmp(test_file, cache->cached) == 0)) {
1647         /* Well this looks really familiar!  If our end-result (per_dir_result)
1648          * didn't change, we have absolutely nothing to do :)
1649          * Otherwise (as is the case with most dir_merged requests)
1650          * we must merge our dir_conf_merged onto this new r->per_dir_config.
1651          */
1652         if (r->per_dir_config == cache->per_dir_result) {
1653             return OK;
1654         }
1655
1656         if (cache->walked->nelts) {
1657             now_merged = ((walk_walked_t*)cache->walked->elts)
1658                 [cache->walked->nelts - 1].merged;
1659         }
1660     }
1661     else {
1662         /* We start now_merged from NULL since we want to build
1663          * a file section list that can be merged to any dir_walk.
1664          */
1665         int sec_idx;
1666         int matches = cache->walked->nelts;
1667         int cached_matches = matches;
1668         walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
1669         apr_pool_t *rxpool = NULL;
1670
1671         cached &= auth_internal_per_conf;
1672         cache->cached = test_file;
1673
1674         /* Go through the location entries, and check for matches.
1675          * We apply the directive sections in given order, we should
1676          * really try them with the most general first.
1677          */
1678         for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
1679             core_dir_config *entry_core;
1680             entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
1681
1682             if (entry_core->r) {
1683
1684                 int nmatch = 0;
1685                 int i;
1686                 ap_regmatch_t *pmatch = NULL;
1687
1688                 if (entry_core->refs && entry_core->refs->nelts) {
1689                     if (!rxpool) {
1690                         apr_pool_create(&rxpool, r->pool);
1691                     }
1692                     nmatch = entry_core->refs->nelts;
1693                     pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
1694                 }
1695
1696                 if (ap_regexec(entry_core->r, cache->cached, nmatch, pmatch, 0)) {
1697                     continue;
1698                 }
1699
1700                 for (i = 0; i < nmatch; i++) {
1701                     if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && 
1702                         ((const char **)entry_core->refs->elts)[i]) {
1703                         apr_table_setn(r->subprocess_env,
1704                                        ((const char **)entry_core->refs->elts)[i],
1705                                        apr_pstrndup(r->pool,
1706                                        cache->cached + pmatch[i].rm_so,
1707                                        pmatch[i].rm_eo - pmatch[i].rm_so));
1708                     }
1709                 }
1710
1711             }
1712             else {
1713                 if ((entry_core->d_is_fnmatch
1714                        ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
1715                        : strcmp(entry_core->d, cache->cached))) {
1716                     continue;
1717                 }
1718             }
1719
1720             /* If we merged this same section last time, reuse it
1721              */
1722             if (matches) {
1723                 if (last_walk->matched == sec_ent[sec_idx]) {
1724                     now_merged = last_walk->merged;
1725                     ++last_walk;
1726                     --matches;
1727                     continue;
1728                 }
1729
1730                 /* We fell out of sync.  This is our own copy of walked,
1731                  * so truncate the remaining matches and reset remaining.
1732                  */
1733                 cache->walked->nelts -= matches;
1734                 matches = 0;
1735                 cached = 0;
1736             }
1737
1738             if (now_merged) {
1739                 now_merged = ap_merge_per_dir_configs(r->pool,
1740                                                       now_merged,
1741                                                       sec_ent[sec_idx]);
1742             }
1743             else {
1744                 now_merged = sec_ent[sec_idx];
1745             }
1746
1747             last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1748             last_walk->matched = sec_ent[sec_idx];
1749             last_walk->merged = now_merged;
1750         }
1751
1752         if (rxpool) {
1753             apr_pool_destroy(rxpool);
1754         }
1755
1756         /* Whoops - everything matched in sequence, but either the original
1757          * walk found some additional matches (which we need to truncate), or
1758          * this walk found some additional matches.
1759          */
1760         if (matches) {
1761             cache->walked->nelts -= matches;
1762             cached = 0;
1763         }
1764         else if (cache->walked->nelts > cached_matches) {
1765             cached = 0;
1766         }
1767     }
1768
1769     if (cached
1770         && r->per_dir_config == cache->dir_conf_merged) {
1771         r->per_dir_config = cache->per_dir_result;
1772         return OK;
1773     }
1774
1775     cache->dir_conf_tested = sec_ent;
1776     cache->dir_conf_merged = r->per_dir_config;
1777
1778     /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
1779      * and note the end result to (potentially) skip this step next time.
1780      */
1781     if (now_merged) {
1782         r->per_dir_config = ap_merge_per_dir_configs(r->pool,
1783                                                      r->per_dir_config,
1784                                                      now_merged);
1785     }
1786     cache->per_dir_result = r->per_dir_config;
1787
1788     return OK;
1789 }
1790
1791 static int ap_if_walk_sub(request_rec *r, core_dir_config* dconf)
1792 {
1793     ap_conf_vector_t *now_merged = NULL;
1794     ap_conf_vector_t **sec_ent = NULL;
1795     int num_sec = 0;
1796     walk_cache_t *cache;
1797     int cached;
1798     int sec_idx;
1799     int matches;
1800     int cached_matches;
1801     int prev_result = -1;
1802     walk_walked_t *last_walk;
1803
1804     if (dconf && dconf->sec_if) {
1805         sec_ent = (ap_conf_vector_t **)dconf->sec_if->elts;
1806         num_sec = dconf->sec_if->nelts;
1807     }
1808
1809     /* No tricks here, there are just no <If > to parse in this context.
1810      * We won't destroy the cache, just in case _this_ redirect is later
1811      * redirected again to a context containing the same or similar <If >.
1812      */
1813     if (!num_sec) {
1814         return OK;
1815     }
1816
1817     cache = prep_walk_cache(AP_NOTE_IF_WALK, r);
1818     cached = (cache->cached != NULL);
1819     cache->cached = (void *)1;
1820     matches = cache->walked->nelts;
1821     cached_matches = matches;
1822     last_walk = (walk_walked_t*)cache->walked->elts;
1823
1824     cached &= auth_internal_per_conf;
1825
1826     /* Go through the if entries, and check for matches  */
1827     for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
1828         const char *err = NULL;
1829         core_dir_config *entry_core;
1830         int rc;
1831         entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
1832
1833         AP_DEBUG_ASSERT(entry_core->condition_ifelse != 0);
1834         if (entry_core->condition_ifelse & AP_CONDITION_ELSE) {
1835             AP_DEBUG_ASSERT(prev_result != -1);
1836             if (prev_result == 1)
1837                 continue;
1838         }
1839
1840         if (entry_core->condition_ifelse & AP_CONDITION_IF) {
1841             rc = ap_expr_exec(r, entry_core->condition, &err);
1842             if (rc <= 0) {
1843                 if (rc < 0)
1844                     ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00039)
1845                                   "Failed to evaluate <If > condition: %s",
1846                                   err);
1847                 prev_result = 0;
1848                 continue;
1849             }
1850             prev_result = 1;
1851         }
1852         else {
1853             prev_result = -1;
1854         }
1855
1856         /* If we merged this same section last time, reuse it
1857          */
1858         if (matches) {
1859             if (last_walk->matched == sec_ent[sec_idx]) {
1860                 now_merged = last_walk->merged;
1861                 ++last_walk;
1862                 --matches;
1863                 continue;
1864             }
1865
1866             /* We fell out of sync.  This is our own copy of walked,
1867              * so truncate the remaining matches and reset remaining.
1868              */
1869             cache->walked->nelts -= matches;
1870             matches = 0;
1871             cached = 0;
1872         }
1873
1874         if (now_merged) {
1875             now_merged = ap_merge_per_dir_configs(r->pool,
1876                                                   now_merged,
1877                                                   sec_ent[sec_idx]);
1878         }
1879         else {
1880             now_merged = sec_ent[sec_idx];
1881         }
1882
1883         last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1884         last_walk->matched = sec_ent[sec_idx];
1885         last_walk->merged = now_merged;
1886     }
1887
1888     /* Everything matched in sequence, but it may be that the original
1889      * walk found some additional matches (which we need to truncate), or
1890      * this walk found some additional matches.
1891      */
1892     if (matches) {
1893         cache->walked->nelts -= matches;
1894         cached = 0;
1895     }
1896     else if (cache->walked->nelts > cached_matches) {
1897         cached = 0;
1898     }
1899
1900     if (cached
1901         && r->per_dir_config == cache->dir_conf_merged) {
1902         r->per_dir_config = cache->per_dir_result;
1903         return OK;
1904     }
1905
1906     cache->dir_conf_tested = sec_ent;
1907     cache->dir_conf_merged = r->per_dir_config;
1908
1909     /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
1910      * and note the end result to (potentially) skip this step next time.
1911      */
1912     if (now_merged) {
1913         r->per_dir_config = ap_merge_per_dir_configs(r->pool,
1914                                                      r->per_dir_config,
1915                                                      now_merged);
1916     }
1917     cache->per_dir_result = r->per_dir_config;
1918
1919     if (now_merged) {
1920         core_dir_config *dconf_merged = ap_get_core_module_config(now_merged);
1921
1922         /* Allow nested <If>s and their configs to get merged
1923          * with the current one.
1924          */
1925         return ap_if_walk_sub(r, dconf_merged);
1926     }
1927
1928     return OK;
1929 }
1930
1931 AP_DECLARE(int) ap_if_walk(request_rec *r)
1932 {
1933     core_dir_config *dconf = ap_get_core_module_config(r->per_dir_config);
1934     int status = ap_if_walk_sub(r, dconf);
1935     return status;
1936 }
1937
1938 /*****************************************************************
1939  *
1940  * The sub_request mechanism.
1941  *
1942  * Fns to look up a relative URI from, e.g., a map file or SSI document.
1943  * These do all access checks, etc., but don't actually run the transaction
1944  * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
1945  * as appropriate if you're likely to be creating more than a few of these.
1946  * (An early Apache version didn't destroy the sub_reqs used in directory
1947  * indexing.  The result, when indexing a directory with 800-odd files in
1948  * it, was massively excessive storage allocation).
1949  *
1950  * Note more manipulation of protocol-specific vars in the request
1951  * structure...
1952  */
1953
1954 static request_rec *make_sub_request(const request_rec *r,
1955                                      ap_filter_t *next_filter)
1956 {
1957     apr_pool_t *rrp;
1958     request_rec *rnew;
1959
1960     apr_pool_create(&rrp, r->pool);
1961     apr_pool_tag(rrp, "subrequest");
1962     rnew = apr_pcalloc(rrp, sizeof(request_rec));
1963     rnew->pool = rrp;
1964
1965     rnew->hostname       = r->hostname;
1966     rnew->request_time   = r->request_time;
1967     rnew->connection     = r->connection;
1968     rnew->server         = r->server;
1969     rnew->log            = r->log;
1970
1971     rnew->request_config = ap_create_request_config(rnew->pool);
1972
1973     /* Start a clean config from this subrequest's vhost.  Optimization in
1974      * Location/File/Dir walks from the parent request assure that if the
1975      * config blocks of the subrequest match the parent request, no merges
1976      * will actually occur (and generally a minimal number of merges are
1977      * required, even if the parent and subrequest aren't quite identical.)
1978      */
1979     rnew->per_dir_config = r->server->lookup_defaults;
1980
1981     rnew->htaccess = r->htaccess;
1982     rnew->allowed_methods = ap_make_method_list(rnew->pool, 2);
1983
1984     /* make a copy of the allowed-methods list */
1985     ap_copy_method_list(rnew->allowed_methods, r->allowed_methods);
1986
1987     /* start with the same set of output filters */
1988     if (next_filter) {
1989         ap_filter_t *scan = next_filter;
1990
1991         /* while there are no input filters for a subrequest, we will
1992          * try to insert some, so if we don't have valid data, the code
1993          * will seg fault.
1994          */
1995         rnew->input_filters = r->input_filters;
1996         rnew->proto_input_filters = r->proto_input_filters;
1997         rnew->output_filters = next_filter;
1998         rnew->proto_output_filters = r->proto_output_filters;
1999         while (scan && (scan != r->proto_output_filters)) {
2000             if (scan->frec == ap_subreq_core_filter_handle) {
2001                 break;
2002             }
2003             scan = scan->next;
2004         }
2005         if (!scan || scan == r->proto_output_filters) {
2006             ap_add_output_filter_handle(ap_subreq_core_filter_handle,
2007                     NULL, rnew, rnew->connection);
2008         }
2009     }
2010     else {
2011         /* If NULL - we are expecting to be internal_fast_redirect'ed
2012          * to this subrequest - or this request will never be invoked.
2013          * Ignore the original request filter stack entirely, and
2014          * drill the input and output stacks back to the connection.
2015          */
2016         rnew->proto_input_filters = r->proto_input_filters;
2017         rnew->proto_output_filters = r->proto_output_filters;
2018
2019         rnew->input_filters = r->proto_input_filters;
2020         rnew->output_filters = r->proto_output_filters;
2021     }
2022
2023     rnew->useragent_addr = r->useragent_addr;
2024     rnew->useragent_ip = r->useragent_ip;
2025
2026     /* no input filters for a subrequest */
2027
2028     ap_set_sub_req_protocol(rnew, r);
2029
2030     /* We have to run this after we fill in sub req vars,
2031      * or the r->main pointer won't be setup
2032      */
2033     ap_run_create_request(rnew);
2034
2035     /* Begin by presuming any module can make its own path_info assumptions,
2036      * until some module interjects and changes the value.
2037      */
2038     rnew->used_path_info = AP_REQ_DEFAULT_PATH_INFO;
2039
2040     /* Pass on the kept body (if any) into the new request. */
2041     rnew->kept_body = r->kept_body;
2042
2043     return rnew;
2044 }
2045
2046 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_sub_req_output_filter(ap_filter_t *f,
2047                                                               apr_bucket_brigade *bb)
2048 {
2049     apr_bucket *e = APR_BRIGADE_LAST(bb);
2050
2051     if (APR_BUCKET_IS_EOS(e)) {
2052         apr_bucket_delete(e);
2053     }
2054
2055     if (!APR_BRIGADE_EMPTY(bb)) {
2056         return ap_pass_brigade(f->next, bb);
2057     }
2058
2059     return APR_SUCCESS;
2060 }
2061
2062 extern APR_OPTIONAL_FN_TYPE(authz_some_auth_required) *ap__authz_ap_some_auth_required;
2063
2064 AP_DECLARE(int) ap_some_auth_required(request_rec *r)
2065 {
2066     /* Is there a require line configured for the type of *this* req? */
2067     if (ap__authz_ap_some_auth_required) {
2068         return ap__authz_ap_some_auth_required(r);
2069     }
2070     else
2071         return 0;
2072 }
2073
2074 AP_DECLARE(void) ap_clear_auth_internal(void)
2075 {
2076     auth_internal_per_conf_hooks = 0;
2077     auth_internal_per_conf_providers = 0;
2078 }
2079
2080 AP_DECLARE(void) ap_setup_auth_internal(apr_pool_t *ptemp)
2081 {
2082     int total_auth_hooks = 0;
2083     int total_auth_providers = 0;
2084
2085     auth_internal_per_conf = 0;
2086
2087     if (_hooks.link_access_checker) {
2088         total_auth_hooks += _hooks.link_access_checker->nelts;
2089     }
2090     if (_hooks.link_access_checker_ex) {
2091         total_auth_hooks += _hooks.link_access_checker_ex->nelts;
2092     }
2093     if (_hooks.link_check_user_id) {
2094         total_auth_hooks += _hooks.link_check_user_id->nelts;
2095     }
2096     if (_hooks.link_auth_checker) {
2097         total_auth_hooks += _hooks.link_auth_checker->nelts;
2098     }
2099
2100     if (total_auth_hooks > auth_internal_per_conf_hooks) {
2101         return;
2102     }
2103
2104     total_auth_providers +=
2105         ap_list_provider_names(ptemp, AUTHN_PROVIDER_GROUP,
2106                                AUTHN_PROVIDER_VERSION)->nelts;
2107     total_auth_providers +=
2108         ap_list_provider_names(ptemp, AUTHZ_PROVIDER_GROUP,
2109                                AUTHZ_PROVIDER_VERSION)->nelts;
2110
2111     if (total_auth_providers > auth_internal_per_conf_providers) {
2112         return;
2113     }
2114
2115     auth_internal_per_conf = 1;
2116 }
2117
2118 AP_DECLARE(apr_status_t) ap_register_auth_provider(apr_pool_t *pool,
2119                                                    const char *provider_group,
2120                                                    const char *provider_name,
2121                                                    const char *provider_version,
2122                                                    const void *provider,
2123                                                    int type)
2124 {
2125     if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) {
2126         ++auth_internal_per_conf_providers;
2127     }
2128
2129     return ap_register_provider(pool, provider_group, provider_name,
2130                                 provider_version, provider);
2131 }
2132
2133 AP_DECLARE(void) ap_hook_check_access(ap_HOOK_access_checker_t *pf,
2134                                       const char * const *aszPre,
2135                                       const char * const *aszSucc,
2136                                       int nOrder, int type)
2137 {
2138     if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) {
2139         ++auth_internal_per_conf_hooks;
2140     }
2141
2142     ap_hook_access_checker(pf, aszPre, aszSucc, nOrder);
2143 }
2144
2145 AP_DECLARE(void) ap_hook_check_access_ex(ap_HOOK_access_checker_ex_t *pf,
2146                                       const char * const *aszPre,
2147                                       const char * const *aszSucc,
2148                                       int nOrder, int type)
2149 {
2150     if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) {
2151         ++auth_internal_per_conf_hooks;
2152     }
2153
2154     ap_hook_access_checker_ex(pf, aszPre, aszSucc, nOrder);
2155 }
2156
2157 AP_DECLARE(void) ap_hook_check_authn(ap_HOOK_check_user_id_t *pf,
2158                                      const char * const *aszPre,
2159                                      const char * const *aszSucc,
2160                                      int nOrder, int type)
2161 {
2162     if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) {
2163         ++auth_internal_per_conf_hooks;
2164     }
2165
2166     ap_hook_check_user_id(pf, aszPre, aszSucc, nOrder);
2167 }
2168
2169 AP_DECLARE(void) ap_hook_check_authz(ap_HOOK_auth_checker_t *pf,
2170                                      const char * const *aszPre,
2171                                      const char * const *aszSucc,
2172                                      int nOrder, int type)
2173 {
2174     if ((type & AP_AUTH_INTERNAL_MASK) == AP_AUTH_INTERNAL_PER_CONF) {
2175         ++auth_internal_per_conf_hooks;
2176     }
2177
2178     ap_hook_auth_checker(pf, aszPre, aszSucc, nOrder);
2179 }
2180
2181 AP_DECLARE(request_rec *) ap_sub_req_method_uri(const char *method,
2182                                                 const char *new_uri,
2183                                                 const request_rec *r,
2184                                                 ap_filter_t *next_filter)
2185 {
2186     request_rec *rnew;
2187     /* Initialise res, to avoid a gcc warning */
2188     int res = HTTP_INTERNAL_SERVER_ERROR;
2189     char *udir;
2190
2191     rnew = make_sub_request(r, next_filter);
2192
2193     /* would be nicer to pass "method" to ap_set_sub_req_protocol */
2194     rnew->method = method;
2195     rnew->method_number = ap_method_number_of(method);
2196
2197     if (new_uri[0] == '/') {
2198         ap_parse_uri(rnew, new_uri);
2199     }
2200     else {
2201         udir = ap_make_dirstr_parent(rnew->pool, r->uri);
2202         udir = ap_escape_uri(rnew->pool, udir);    /* re-escape it */
2203         ap_parse_uri(rnew, ap_make_full_path(rnew->pool, udir, new_uri));
2204     }
2205
2206     /* We cannot return NULL without violating the API. So just turn this
2207      * subrequest into a 500 to indicate the failure. */
2208     if (ap_is_recursion_limit_exceeded(r)) {
2209         rnew->status = HTTP_INTERNAL_SERVER_ERROR;
2210         return rnew;
2211     }
2212
2213     /* lookup_uri
2214      * If the content can be served by the quick_handler, we can
2215      * safely bypass request_internal processing.
2216      *
2217      * If next_filter is NULL we are expecting to be
2218      * internal_fast_redirect'ed to the subrequest, or the subrequest will
2219      * never be invoked. We need to make sure that the quickhandler is not
2220      * invoked by any lookups. Since an internal_fast_redirect will always
2221      * occur too late for the quickhandler to handle the request.
2222      */
2223     if (next_filter) {
2224         res = ap_run_quick_handler(rnew, 1);
2225     }
2226
2227     if (next_filter == NULL || res != OK) {
2228         if ((res = ap_process_request_internal(rnew))) {
2229             rnew->status = res;
2230         }
2231     }
2232
2233     return rnew;
2234 }
2235
2236 AP_DECLARE(request_rec *) ap_sub_req_lookup_uri(const char *new_uri,
2237                                                 const request_rec *r,
2238                                                 ap_filter_t *next_filter)
2239 {
2240     return ap_sub_req_method_uri("GET", new_uri, r, next_filter);
2241 }
2242
2243 AP_DECLARE(request_rec *) ap_sub_req_lookup_dirent(const apr_finfo_t *dirent,
2244                                                    const request_rec *r,
2245                                                    int subtype,
2246                                                    ap_filter_t *next_filter)
2247 {
2248     request_rec *rnew;
2249     int res;
2250     char *fdir;
2251     char *udir;
2252
2253     rnew = make_sub_request(r, next_filter);
2254
2255     /* Special case: we are looking at a relative lookup in the same directory.
2256      * This is 100% safe, since dirent->name just came from the filesystem.
2257      */
2258     if (r->path_info && *r->path_info) {
2259         /* strip path_info off the end of the uri to keep it in sync
2260          * with r->filename, which has already been stripped by directory_walk,
2261          * merge the dirent->name, and then, if the caller wants us to remerge
2262          * the original path info, do so.  Note we never fix the path_info back
2263          * to r->filename, since dir_walk would do so (but we don't expect it
2264          * to happen in the usual cases)
2265          */
2266         udir = apr_pstrdup(rnew->pool, r->uri);
2267         udir[ap_find_path_info(udir, r->path_info)] = '\0';
2268         udir = ap_make_dirstr_parent(rnew->pool, udir);
2269
2270         rnew->uri = ap_make_full_path(rnew->pool, udir, dirent->name);
2271         if (subtype == AP_SUBREQ_MERGE_ARGS) {
2272             rnew->uri = ap_make_full_path(rnew->pool, rnew->uri, r->path_info + 1);
2273             rnew->path_info = apr_pstrdup(rnew->pool, r->path_info);
2274         }
2275         rnew->uri = ap_escape_uri(rnew->pool, rnew->uri);
2276     }
2277     else {
2278         udir = ap_make_dirstr_parent(rnew->pool, r->uri);
2279         rnew->uri = ap_escape_uri(rnew->pool, ap_make_full_path(rnew->pool,
2280                                                                 udir,
2281                                                                 dirent->name));
2282     }
2283
2284     fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
2285     rnew->filename = ap_make_full_path(rnew->pool, fdir, dirent->name);
2286     if (r->canonical_filename == r->filename) {
2287         rnew->canonical_filename = rnew->filename;
2288     }
2289
2290     /* XXX This is now less relevant; we will do a full location walk
2291      * these days for this case.  Preserve the apr_stat results, and
2292      * perhaps we also tag that symlinks were tested and/or found for
2293      * r->filename.
2294      */
2295     rnew->per_dir_config = r->server->lookup_defaults;
2296
2297     if ((dirent->valid & APR_FINFO_MIN) != APR_FINFO_MIN) {
2298         /*
2299          * apr_dir_read isn't very complete on this platform, so
2300          * we need another apr_stat (with or without APR_FINFO_LINK
2301          * depending on whether we allow all symlinks here.)  If this
2302          * is an APR_LNK that resolves to an APR_DIR, then we will rerun
2303          * everything anyways... this should be safe.
2304          */
2305         apr_status_t rv;
2306         if (ap_allow_options(rnew) & OPT_SYM_LINKS) {
2307             if (((rv = apr_stat(&rnew->finfo, rnew->filename,
2308                                 APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
2309                 && (rv != APR_INCOMPLETE)) {
2310                 rnew->finfo.filetype = APR_NOFILE;
2311             }
2312         }
2313         else {
2314             if (((rv = apr_stat(&rnew->finfo, rnew->filename,
2315                                 APR_FINFO_LINK | APR_FINFO_MIN,
2316                                 rnew->pool)) != APR_SUCCESS)
2317                 && (rv != APR_INCOMPLETE)) {
2318                 rnew->finfo.filetype = APR_NOFILE;
2319             }
2320         }
2321     }
2322     else {
2323         memcpy(&rnew->finfo, dirent, sizeof(apr_finfo_t));
2324     }
2325
2326     if (rnew->finfo.filetype == APR_LNK) {
2327         /*
2328          * Resolve this symlink.  We should tie this back to dir_walk's cache
2329          */
2330         if ((res = resolve_symlink(rnew->filename, &rnew->finfo,
2331                                    ap_allow_options(rnew), rnew->pool))
2332             != OK) {
2333             rnew->status = res;
2334             return rnew;
2335         }
2336     }
2337
2338     if (rnew->finfo.filetype == APR_DIR) {
2339         /* ap_make_full_path overallocated the buffers
2340          * by one character to help us out here.
2341          */
2342         strcat(rnew->filename, "/");
2343         if (!rnew->path_info || !*rnew->path_info) {
2344             strcat(rnew->uri, "/");
2345         }
2346     }
2347
2348     /* fill in parsed_uri values
2349      */
2350     if (r->args && *r->args && (subtype == AP_SUBREQ_MERGE_ARGS)) {
2351         ap_parse_uri(rnew, apr_pstrcat(r->pool, rnew->uri, "?",
2352                                        r->args, NULL));
2353     }
2354     else {
2355         ap_parse_uri(rnew, rnew->uri);
2356     }
2357
2358     /* We cannot return NULL without violating the API. So just turn this
2359      * subrequest into a 500. */
2360     if (ap_is_recursion_limit_exceeded(r)) {
2361         rnew->status = HTTP_INTERNAL_SERVER_ERROR;
2362         return rnew;
2363     }
2364
2365     if ((res = ap_process_request_internal(rnew))) {
2366         rnew->status = res;
2367     }
2368
2369     return rnew;
2370 }
2371
2372 AP_DECLARE(request_rec *) ap_sub_req_lookup_file(const char *new_file,
2373                                                  const request_rec *r,
2374                                                  ap_filter_t *next_filter)
2375 {
2376     request_rec *rnew;
2377     int res;
2378     char *fdir;
2379     apr_size_t fdirlen;
2380
2381     rnew = make_sub_request(r, next_filter);
2382
2383     fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
2384     fdirlen = strlen(fdir);
2385
2386     /* Translate r->filename, if it was canonical, it stays canonical
2387      */
2388     if (r->canonical_filename == r->filename) {
2389         rnew->canonical_filename = (char*)(1);
2390     }
2391
2392     if (apr_filepath_merge(&rnew->filename, fdir, new_file,
2393                            APR_FILEPATH_TRUENAME, rnew->pool) != APR_SUCCESS) {
2394         rnew->status = HTTP_FORBIDDEN;
2395         return rnew;
2396     }
2397
2398     if (rnew->canonical_filename) {
2399         rnew->canonical_filename = rnew->filename;
2400     }
2401
2402     /*
2403      * Check for a special case... if there are no '/' characters in new_file
2404      * at all, and the path was the same, then we are looking at a relative
2405      * lookup in the same directory.  Fixup the URI to match.
2406      */
2407
2408     if (strncmp(rnew->filename, fdir, fdirlen) == 0
2409         && rnew->filename[fdirlen]
2410         && ap_strchr_c(rnew->filename + fdirlen, '/') == NULL) {
2411         apr_status_t rv;
2412         if (ap_allow_options(rnew) & OPT_SYM_LINKS) {
2413             if (((rv = apr_stat(&rnew->finfo, rnew->filename,
2414                                 APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
2415                 && (rv != APR_INCOMPLETE)) {
2416                 rnew->finfo.filetype = APR_NOFILE;
2417             }
2418         }
2419         else {
2420             if (((rv = apr_stat(&rnew->finfo, rnew->filename,
2421                                 APR_FINFO_LINK | APR_FINFO_MIN,
2422                                 rnew->pool)) != APR_SUCCESS)
2423                 && (rv != APR_INCOMPLETE)) {
2424                 rnew->finfo.filetype = APR_NOFILE;
2425             }
2426         }
2427
2428         if (r->uri && *r->uri) {
2429             char *udir = ap_make_dirstr_parent(rnew->pool, r->uri);
2430             rnew->uri = ap_make_full_path(rnew->pool, udir,
2431                                           rnew->filename + fdirlen);
2432             ap_parse_uri(rnew, rnew->uri);    /* fill in parsed_uri values */
2433         }
2434         else {
2435             ap_parse_uri(rnew, new_file);        /* fill in parsed_uri values */
2436             rnew->uri = apr_pstrdup(rnew->pool, "");
2437         }
2438     }
2439     else {
2440         /* XXX: @@@: What should be done with the parsed_uri values?
2441          * We would be better off stripping down to the 'common' elements
2442          * of the path, then reassembling the URI as best as we can.
2443          */
2444         ap_parse_uri(rnew, new_file);        /* fill in parsed_uri values */
2445         /*
2446          * XXX: this should be set properly like it is in the same-dir case
2447          * but it's actually sometimes to impossible to do it... because the
2448          * file may not have a uri associated with it -djg
2449          */
2450         rnew->uri = apr_pstrdup(rnew->pool, "");
2451     }
2452
2453     /* We cannot return NULL without violating the API. So just turn this
2454      * subrequest into a 500. */
2455     if (ap_is_recursion_limit_exceeded(r)) {
2456         rnew->status = HTTP_INTERNAL_SERVER_ERROR;
2457         return rnew;
2458     }
2459
2460     if ((res = ap_process_request_internal(rnew))) {
2461         rnew->status = res;
2462     }
2463
2464     return rnew;
2465 }
2466
2467 AP_DECLARE(int) ap_run_sub_req(request_rec *r)
2468 {
2469     int retval = DECLINED;
2470     /* Run the quick handler if the subrequest is not a dirent or file
2471      * subrequest
2472      */
2473     if (!(r->filename && r->finfo.filetype != APR_NOFILE)) {
2474         retval = ap_run_quick_handler(r, 0);
2475     }
2476     if (retval != OK) {
2477         retval = ap_invoke_handler(r);
2478         if (retval == DONE) {
2479             retval = OK;
2480         }
2481     }
2482     ap_finalize_sub_req_protocol(r);
2483     return retval;
2484 }
2485
2486 AP_DECLARE(void) ap_destroy_sub_req(request_rec *r)
2487 {
2488     /* Reclaim the space */
2489     apr_pool_destroy(r->pool);
2490 }
2491
2492 /*
2493  * Function to set the r->mtime field to the specified value if it's later
2494  * than what's already there.
2495  */
2496 AP_DECLARE(void) ap_update_mtime(request_rec *r, apr_time_t dependency_mtime)
2497 {
2498     if (r->mtime < dependency_mtime) {
2499         r->mtime = dependency_mtime;
2500     }
2501 }
2502
2503 /*
2504  * Is it the initial main request, which we only get *once* per HTTP request?
2505  */
2506 AP_DECLARE(int) ap_is_initial_req(request_rec *r)
2507 {
2508     return (r->main == NULL)       /* otherwise, this is a sub-request */
2509            && (r->prev == NULL);   /* otherwise, this is an internal redirect */
2510 }
2511