]> granicus.if.org Git - apache/blob - server/request.c
Rambling on
[apache] / server / request.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60  * http_request.c: functions to get and process requests
61  *
62  * Rob McCool 3/21/93
63  *
64  * Thoroughly revamped by rst for Apache.  NB this file reads
65  * best from the bottom up.
66  *
67  */
68
69 #include "apr_strings.h"
70 #include "apr_file_io.h"
71 #include "apr_fnmatch.h"
72
73 #define APR_WANT_STRFUNC
74 #include "apr_want.h"
75
76 #define CORE_PRIVATE
77 #include "ap_config.h"
78 #include "httpd.h"
79 #include "http_config.h"
80 #include "http_request.h"
81 #include "http_core.h"
82 #include "http_protocol.h"
83 #include "http_log.h"
84 #include "http_main.h"
85 #include "util_filter.h"
86 #include "util_charset.h"
87
88 #include "mod_core.h"
89
90 #if APR_HAVE_STDARG_H
91 #include <stdarg.h>
92 #endif
93
94 APR_HOOK_STRUCT(
95             APR_HOOK_LINK(translate_name)
96             APR_HOOK_LINK(map_to_storage)
97             APR_HOOK_LINK(check_user_id)
98             APR_HOOK_LINK(fixups)
99             APR_HOOK_LINK(type_checker)
100             APR_HOOK_LINK(access_checker)
101             APR_HOOK_LINK(auth_checker)
102             APR_HOOK_LINK(insert_filter)
103             APR_HOOK_LINK(create_request)
104 )
105
106 AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
107                             (request_rec *r),(r),DECLINED)
108 AP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
109                             (request_rec *r),(r),DECLINED)
110 AP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id,
111                             (request_rec *r),(r),DECLINED)
112 AP_IMPLEMENT_HOOK_RUN_ALL(int,fixups,
113                           (request_rec *r),(r),OK,DECLINED)
114 AP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker,
115                             (request_rec *r),(r),DECLINED)
116 AP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker,
117                           (request_rec *r),(r),OK,DECLINED)
118 AP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
119                             (request_rec *r),(r),DECLINED)
120 AP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
121 AP_IMPLEMENT_HOOK_RUN_ALL(int,create_request,(request_rec *r),(r),OK,DECLINED)
122
123
124 static int decl_die(int status, char *phase, request_rec *r)
125 {
126     if (status == DECLINED) {
127         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, r,
128                     "configuration error:  couldn't %s: %s", phase, r->uri);
129         return HTTP_INTERNAL_SERVER_ERROR;
130     }
131     else
132         return status;
133 }
134
135 /* This is the master logic for processing requests.  Do NOT duplicate
136  * this logic elsewhere, or the security model will be broken by future
137  * API changes.  Each phase must be individually optimized to pick up
138  * redundant/duplicate calls by subrequests, and redirects.
139  */
140 AP_DECLARE(int) ap_process_request_internal(request_rec *r)
141 {
142     int access_status;
143
144     /* Ignore embedded %2F's in path for proxy requests */
145     if (!r->proxyreq && r->parsed_uri.path) {
146         access_status = ap_unescape_url(r->parsed_uri.path);
147         if (access_status) {
148             return access_status;
149         }
150     }
151
152     ap_getparents(r->uri);     /* OK --- shrinking transformations... */
153
154     if ((access_status = ap_location_walk(r))) {
155         return access_status;
156     }
157
158     if ((access_status = ap_run_translate_name(r))) {
159         return decl_die(access_status, "translate", r);
160         return access_status;
161     }
162
163     if ((access_status = ap_run_map_to_storage(r))) {
164         /* This request wasn't in storage (e.g. TRACE) */
165         if (access_status == DONE)
166             return OK;
167         else
168             return access_status;
169     }
170
171     if ((access_status = ap_location_walk(r))) {
172         return access_status;
173     }
174
175     /* Only on the main request! */
176     if (r->main == NULL) {
177         if ((access_status = ap_run_header_parser(r))) {
178             return access_status;
179         }
180     }
181
182     switch (ap_satisfies(r)) {
183     case SATISFY_ALL:
184     case SATISFY_NOSPEC:
185         if ((access_status = ap_run_access_checker(r)) != 0) {
186             return decl_die(access_status, "check access", r);
187         }
188         if (ap_some_auth_required(r)) {
189             if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) {
190                 return decl_die(access_status, ap_auth_type(r)
191                             ? "check user.  No user file?"
192                             : "perform authentication. AuthType not set!", r);
193             }
194             if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) {
195                 return decl_die(access_status, ap_auth_type(r)
196                             ? "check access.  No groups file?"
197                             : "perform authentication. AuthType not set!", r);
198             }
199         }
200         break;
201     case SATISFY_ANY:
202         if (((access_status = ap_run_access_checker(r)) != 0) || !ap_auth_type(r)) {
203             if (!ap_some_auth_required(r)) {
204                 return decl_die(access_status, ap_auth_type(r)
205                             ? "check access"
206                             : "perform authentication. AuthType not set!", r);
207             }
208             if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) {
209                 return decl_die(access_status, ap_auth_type(r)
210                             ? "check user.  No user file?"
211                             : "perform authentication. AuthType not set!", r);
212             }
213             if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) {
214                 return decl_die(access_status, ap_auth_type(r)
215                             ? "check access.  No groups file?"
216                             : "perform authentication. AuthType not set!", r);
217             }
218         }
219         break;
220     }
221
222     /* XXX Must make certain the ap_run_type_checker short circuits mime
223      * in mod-proxy for r->proxyreq && r->parsed_uri.scheme 
224      *                              && !strcmp(r->parsed_uri.scheme, "http")
225      */
226     if ((access_status = ap_run_type_checker(r)) != 0) {
227         return decl_die(access_status, "find types", r);
228     }
229
230     if ((access_status = ap_run_fixups(r)) != 0) {
231         return access_status;
232     }
233
234     /* The new insert_filter stage makes sense here IMHO.  We are sure that
235      * we are going to run the request now, so we may as well insert filters
236      * if any are available.  Since the goal of this phase is to allow all
237      * modules to insert a filter if they want to, this filter returns
238      * void.  I just can't see any way that this filter can reasonably
239      * fail, either your modules inserts something or it doesn't.  rbb
240      */
241     ap_run_insert_filter(r);
242
243     return OK;
244 }
245
246
247 /*****************************************************************
248  *
249  * Getting and checking directory configuration.  Also checks the
250  * FollowSymlinks and FollowSymOwner stuff, since this is really the
251  * only place that can happen (barring a new mid_dir_walk callout).
252  *
253  * We can't do it as an access_checker module function which gets
254  * called with the final per_dir_config, since we could have a directory
255  * with FollowSymLinks disabled, which contains a symlink to another
256  * with a .htaccess file which turns FollowSymLinks back on --- and
257  * access in such a case must be denied.  So, whatever it is that
258  * checks FollowSymLinks needs to know the state of the options as
259  * they change, all the way down.
260  */
261
262 /*
263  * We don't want people able to serve up pipes, or unix sockets, or other
264  * scary things.  Note that symlink tests are performed later.
265  */
266 static int check_safe_file(request_rec *r)
267 {
268
269     if (r->finfo.filetype == 0      /* doesn't exist */
270         || r->finfo.filetype == APR_DIR
271         || r->finfo.filetype == APR_REG
272         || r->finfo.filetype == APR_LNK) {
273         return OK;
274     }
275
276     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
277                 "object is not a file, directory or symlink: %s",
278                 r->filename);
279     return HTTP_FORBIDDEN;
280 }
281
282 #ifdef REPLACE_PATH_INFO_METHOD
283 /*
284  * resolve_symlink must _always_ be called on an APR_LNK file type!
285  * It will resolve the actual target file type, modification date, etc, 
286  * and provide any processing required for symlink evaluation.
287  * Path must already be cleaned, no trailing slash, no multi-slashes,
288  * and don't call this on the root!
289  *
290  * Simply, the number of times we deref a symlink are minimal compared
291  * to the number of times we had an extra lstat() since we 'weren't sure'.
292  *
293  * To optimize, we stat() anything when given (opts & OPT_SYM_LINKS), otherwise
294  * we start off with an lstat().  Every lstat() must be dereferenced in case 
295  * it points at a 'nasty' - we must always rerun check_safe_file (or similar.)
296  */
297 static int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p)
298 {
299     apr_finfo_t fi;
300     int res;
301
302     if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)))
303         return HTTP_FORBIDDEN;
304
305     if (opts & OPT_SYM_LINKS) {
306         if ((res = apr_stat(&fi, d, lfi->valid, p)) != APR_SUCCESS)
307             return HTTP_FORBIDDEN;
308         return OK;
309     }
310
311     /* OPT_SYM_OWNER only works if we can get the owner of 
312      * both the file and symlink.  First fill in a missing
313      * owner of the symlink, then get the info of the target.
314      */
315     if (!(lfi->valid & APR_FINFO_OWNER))
316         if ((res = apr_lstat(&fi, d, lfi->valid | APR_FINFO_OWNER, p))
317                 != APR_SUCCESS)
318             return HTTP_FORBIDDEN;
319
320     if ((res = apr_stat(&fi, d, lfi->valid, p)) != APR_SUCCESS)
321         return HTTP_FORBIDDEN;
322
323     if (apr_compare_users(fi.user, lfi->user) != APR_SUCCESS) 
324         return HTTP_FORBIDDEN;
325
326     /* Give back the target */
327     memcpy(lfi, &fi, sizeof(fi));
328     return OK;
329 }
330 #endif /* REPLACE_PATH_INFO_METHOD */
331
332 #ifndef REPLACE_PATH_INFO_METHOD
333
334 static int check_symlinks(char *d, int opts, apr_pool_t *p)
335 {
336 #if defined(OS2)
337     /* OS/2 doesn't have symlinks */
338     return OK;
339 #else
340     apr_finfo_t lfi, fi;
341     char *lastp;
342     int res;
343
344     if (opts & OPT_SYM_LINKS)
345         return OK;
346
347     /*
348      * Strip trailing '/', if any, off what we're checking; trailing slashes
349      * make some systems follow symlinks to directories even in lstat().
350      * After we've done the lstat, put it back.  Also, don't bother checking
351      * '/' at all...
352      * 
353      * Note that we don't have to worry about multiple slashes here because of
354      * no2slash() below...
355      */
356
357     lastp = d + strlen(d) - 1;
358     if (lastp == d)
359         return OK;              /* Root directory, '/' */
360
361     if (*lastp == '/')
362         *lastp = '\0';
363     else
364         lastp = NULL;
365
366     res = apr_lstat(&lfi, d, APR_FINFO_TYPE | APR_FINFO_OWNER, p);
367
368     if (lastp)
369         *lastp = '/';
370
371     /*
372      * Note that we don't reject accesses to nonexistent files (multiviews or
373      * the like may cons up a way to run the transaction anyway)...
374      */
375
376     if ((res != APR_SUCCESS && res != APR_INCOMPLETE)
377            || (lfi.filetype != APR_LNK))
378         return OK;
379
380     /* OK, it's a symlink.  May still be OK with OPT_SYM_OWNER */
381
382     if (!(opts & OPT_SYM_OWNER))
383         return HTTP_FORBIDDEN;
384
385     /* OPT_SYM_OWNER only works if we can get the owner from the file */
386
387     if (res != APR_SUCCESS)
388         return HTTP_FORBIDDEN;
389
390     if (apr_stat(&fi, d, APR_FINFO_OWNER, p) != APR_SUCCESS)
391         return HTTP_FORBIDDEN;
392
393     /* TODO: replace with an apr_compare_users() fn */
394     return (fi.user == lfi.user) ? OK : HTTP_FORBIDDEN;
395
396 #endif
397 }
398
399 /* Dealing with the file system to get PATH_INFO
400  */
401 static int get_path_info(request_rec *r)
402 {
403     char *cp;
404     char *path = r->filename;
405     char *end = &path[strlen(path)];
406     char *last_cp = NULL;
407     int rv;
408 #if defined(HAVE_DRIVE_LETTERS) || defined(HAVE_UNC_PATHS)
409     char bStripSlash=1;
410 #endif
411
412     if (r->finfo.filetype != APR_NOFILE) {
413         /* assume path_info already set */
414         return OK;
415     }
416
417 #ifdef HAVE_DRIVE_LETTERS
418     /* If the directory is x:\, then we don't want to strip
419      * the trailing slash since x: is not a valid directory.
420      */
421     if (strlen(path) == 3 && path[1] == ':' && path[2] == '/')
422         bStripSlash = 0;
423 #endif
424
425 #ifdef HAVE_UNC_PATHS
426     /* If UNC name == //machine/share/, do not 
427      * advance over the trailing slash.  Any other
428      * UNC name is OK to strip the slash.
429      */
430     cp = end;
431     if (path[0] == '/' && path[1] == '/' && 
432         path[2] != '/' && cp[-1] == '/') {
433         char *p;
434         int iCount=0;
435         p = path;
436         while ((p = strchr(p,'/')) != NULL) {
437             p++;
438             iCount++;
439         }
440     
441         if (iCount == 4)
442             bStripSlash = 0;
443     }
444 #endif
445    
446 #if defined(HAVE_DRIVE_LETTERS) || defined(HAVE_UNC_PATHS)
447     if (bStripSlash)
448 #endif
449         /* Advance over trailing slashes ... NOT part of filename 
450          * if file is not a UNC name (Win32 only).
451          */
452         for (cp = end; cp > path && cp[-1] == '/'; --cp)
453             continue;
454
455     while (cp > path) {
456
457         /* See if the pathname ending here exists... */
458         *cp = '\0';
459
460         /* ### We no longer need the test ap_os_is_filename_valid() here 
461          * since apr_stat isn't a posix thing - it's apr_stat's responsibility
462          * to handle whatever path string arrives at its door - by platform
463          * and volume restrictions as applicable... 
464          * TODO: This code becomes even simpler if apr_stat grows 
465          * an APR_PATHINCOMPLETE result to indicate that we are staring at
466          * an partial virtual root.  Only OS2/Win32/Netware need apply it :-)
467          */
468         rv = apr_stat(&r->finfo, path, APR_FINFO_MIN, r->pool);
469
470         if (cp != end)
471             *cp = '/';
472
473         if (rv == APR_SUCCESS || rv == APR_INCOMPLETE) {
474             /*
475              * Aha!  Found something.  If it was a directory, we will search
476              * contents of that directory for a multi_match, so the PATH_INFO
477              * argument starts with the component after that.
478              */
479             if (r->finfo.filetype == APR_DIR && last_cp) {
480                 r->finfo.filetype = APR_NOFILE;  /* No such file... */
481                 cp = last_cp;
482             }
483
484             r->path_info = apr_pstrdup(r->pool, cp);
485             *cp = '\0';
486             return OK;
487         }
488         
489         if (APR_STATUS_IS_ENOENT(rv) || APR_STATUS_IS_ENOTDIR(rv)) {
490             last_cp = cp;
491
492             while (--cp > path && *cp != '/')
493                 continue;
494
495             while (cp > path && cp[-1] == '/')
496                 --cp;
497         }
498         else {
499             if (APR_STATUS_IS_EACCES(rv))
500                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
501                               "access to %s denied", r->uri);
502             else
503                 ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
504                               "access to %s failed", r->uri);
505             return HTTP_FORBIDDEN;
506         }
507     }
508     return OK;
509 }
510
511 AP_DECLARE(int) ap_directory_walk(request_rec *r)
512 {
513     core_server_config *sconf = ap_get_module_config(r->server->module_config,
514                                                      &core_module);
515     ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;
516     ap_conf_vector_t **sec_dir = (ap_conf_vector_t **) sconf->sec_dir->elts;
517     int num_sec = sconf->sec_dir->nelts;
518     char *test_filename;
519     char *test_dirname;
520     int res;
521     unsigned i, num_dirs;
522     int j, test_filename_len;
523     unsigned iStart = 1;
524     ap_conf_vector_t *entry_config;
525     ap_conf_vector_t *this_conf;
526     core_dir_config *entry_core;
527
528     /*
529      * Are we dealing with a file? If not, the handler needed to register
530      * a hook to escape from our walking the file.  Since they haven't, we
531      * are going to assume the worst and refuse to proceed.
532      */
533     if (r->filename == NULL || !ap_os_is_path_absolute(r->pool, r->filename)) {
534         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
535                       "Module bug?  Request filename path %s is missing or "
536                       "or not absolute for uri %s", 
537                       r->filename ? r->filename : "<NULL>", r->uri);
538         return HTTP_INTERNAL_SERVER_ERROR;
539     }
540
541     /*
542      * Go down the directory hierarchy.  Where we have to check for symlinks,
543      * do so.  Where a .htaccess file has permission to override anything,
544      * try to find one.  If either of these things fails, we could poke
545      * around, see why, and adjust the lookup_rec accordingly --- this might
546      * save us a call to get_path_info (with the attendant stat()s); however,
547      * for the moment, that's not worth the trouble.
548      */
549     res = get_path_info(r);
550     if (res != OK) {
551         return res;
552     }
553
554     /* XXX Momentary period of extreme danger, Will Robinson.
555      * Removed ap_os_canonical_filename.  Anybody munging the
556      * r->filename better have pre-canonicalized the name that
557      * they just changed.  Since the two most key functions
558      * in the entire server, ap_server_root_relative() and
559      * ap_make_full_path now canonicalize as they go.
560      *
561      * To be very safe, the server is in hyper-paranoid mode.
562      * That means that non-canonical paths will be captured and
563      * denied.  This is very cpu/fs intensive, we need to finish
564      * auditing, and remove the paranoia trigger.
565      */
566     if (r->filename == r->canonical_filename)
567 #ifdef NO_LONGER_PARANOID
568         test_filename = apr_pstrdup(r->pool, r->filename);
569 #else
570     {
571         if (apr_filepath_merge(&test_filename, "", r->filename,
572                                APR_FILEPATH_NOTRELATIVE | APR_FILEPATH_TRUENAME,
573                                r->pool) != APR_SUCCESS
574                || strcmp(test_filename, r->filename) != 0) {
575             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
576                           "Module bug?  Filepath: %s is not the canonical %s", 
577                           r->filename, test_filename);
578             return HTTP_FORBIDDEN;
579         }
580     }
581 #endif
582     else {
583         /* Apparently, somebody didn't know to update r->canonical_filename
584          * which is lucky, since they didn't canonicalize r->filename either.
585          */
586         if (apr_filepath_merge(&test_filename, NULL, r->filename,
587                                APR_FILEPATH_NOTRELATIVE | APR_FILEPATH_TRUENAME,
588                                r->pool) != APR_SUCCESS) {
589             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
590                           "Module bug?  Filepath: %s is not an absolute path", 
591                           r->filename);
592             return HTTP_FORBIDDEN;
593         }
594         if (strcmp(r->filename, test_filename) != 0)
595             r->filename = apr_pstrdup(r->pool, test_filename);
596         r->canonical_filename = r->filename;
597     }
598
599     num_dirs = ap_count_dirs(test_filename);
600
601     if ((res = check_safe_file(r))) {
602         return res;
603     }
604
605     test_filename_len = strlen(test_filename);
606     if (test_filename[test_filename_len - 1] == '/')
607         --num_dirs;
608
609     if (r->finfo.filetype == APR_DIR)
610         ++num_dirs;
611
612     /*
613      * We will use test_dirname as scratch space while we build directory
614      * names during the walk.  Profiling shows directory_walk to be a busy
615      * function so we try to avoid allocating lots of extra memory here.
616      * We need 2 extra bytes, one for trailing \0 and one because
617      * make_dirstr_prefix will add potentially one extra /.
618      */
619     test_dirname = apr_palloc(r->pool, test_filename_len + 2);
620
621     /* XXX The garbage below disappears in the new directory_walk;
622      */
623
624 #if defined(HAVE_UNC_PATHS)
625     /* If the name is a UNC name, then do not perform any true file test
626      * against the machine name (start at //machine/share/)
627      * This is optimized to use the normal walk (skips the redundant '/' root)
628      */
629     if (num_dirs > 3 && test_filename[0] == '/' && test_filename[1] == '/')
630         iStart = 4;
631 #endif
632
633 #if defined(NETWARE)
634     /* If the name is a fully qualified volume name, then do not perform any
635      * true file test on the machine name (start at machine/share:/)
636      * XXX: The implementation eludes me at this moment... 
637      *      Does this make sense?  Please test!
638      */
639     if (num_dirs > 1 && strchr(test_filename, '/') < strchr(test_filename, ':'))
640         iStart = 2;
641 #endif
642
643     /* i keeps track of how many segments we are testing
644      * j keeps track of which section we're on, see core_reorder_directories 
645      */
646     j = 0;
647     for (i = 1; i <= num_dirs; ++i) {
648         int overrides_here;
649         core_dir_config *core_dir = ap_get_module_config(per_dir_defaults,
650                                                          &core_module);
651
652         /*
653          * XXX: this could be made faster by only copying the next component
654          * rather than copying the entire thing all over.
655          */
656         ap_make_dirstr_prefix(test_dirname, test_filename, i);
657
658         /*
659          * Do symlink checks first, because they are done with the
660          * permissions appropriate to the *parent* directory...
661          */
662
663         /* Test only real names (after the root) against the real filesystem */
664         if ((i > iStart) && (res = check_symlinks(test_dirname, core_dir->opts, r->pool))) {
665             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
666                         "Symbolic link not allowed: %s", test_dirname);
667             return res;
668         }
669
670         /*
671          * Begin *this* level by looking for matching <Directory> sections
672          * from access.conf.
673          */
674
675         for (; j < num_sec; ++j) {
676             char *entry_dir;
677
678             entry_config = sec_dir[j];
679             entry_core = ap_get_module_config(entry_config, &core_module);
680             entry_dir = entry_core->d;
681
682             if (entry_core->r || entry_core->d_components > i)
683                 break;
684
685             this_conf = NULL;
686             /* We will always add in '0' element components, e.g. plain old
687              * <Directory >, and <Directory "/"> is classified as zero 
688              * so that Win32/Netware/OS2 etc all pick that up.
689              */
690             if (!entry_core->d_components) {
691                 this_conf = entry_config;
692             }
693             else if (entry_core->d_is_fnmatch) {
694                 if (!apr_fnmatch(entry_dir, test_dirname, FNM_PATHNAME)) {
695                     this_conf = entry_config;
696                 }
697             }
698             else if (!strcmp(test_dirname, entry_dir))
699                 this_conf = entry_config;
700
701             if (this_conf) {
702                 per_dir_defaults = ap_merge_per_dir_configs(r->pool,
703                                                             per_dir_defaults,
704                                                             this_conf);
705                 core_dir = ap_get_module_config(per_dir_defaults,
706                                                 &core_module);
707             }
708         }
709         overrides_here = core_dir->override;
710
711         /* If .htaccess files are enabled, check for one. */
712
713         /* Test only legal names against the real filesystem */
714         if ((i >= iStart) && overrides_here) {
715             ap_conf_vector_t *htaccess_conf = NULL;
716
717             res = ap_parse_htaccess(&htaccess_conf, r, overrides_here,
718                                     apr_pstrdup(r->pool, test_dirname),
719                                     sconf->access_name);
720             if (res)
721                 return res;
722
723             if (htaccess_conf) {
724                 per_dir_defaults = ap_merge_per_dir_configs(r->pool,
725                                                             per_dir_defaults,
726                                                             htaccess_conf);
727                 r->per_dir_config = per_dir_defaults;
728             }
729         }
730     }
731
732     /*
733      * Now we'll deal with the regexes.
734      */
735     for (; j < num_sec; ++j) {
736
737         entry_config = sec_dir[j];
738         entry_core = ap_get_module_config(entry_config, &core_module);
739
740         if (!entry_core->r) {
741             continue;
742         }
743         if (!ap_regexec(entry_core->r, test_dirname, 0, NULL, REG_NOTEOL)) {
744             per_dir_defaults = ap_merge_per_dir_configs(r->pool,
745                                                         per_dir_defaults,
746                                                         entry_config);
747         }
748     }
749     r->per_dir_config = per_dir_defaults;
750
751     /*
752      * Symlink permissions are determined by the parent.  If the request is
753      * for a directory then applying the symlink test here would use the
754      * permissions of the directory as opposed to its parent.  Consider a
755      * symlink pointing to a dir with a .htaccess disallowing symlinks.  If
756      * you access /symlink (or /symlink/) you would get a 403 without this
757      * APR_DIR test.  But if you accessed /symlink/index.html, for example,
758      * you would *not* get the 403.
759      */
760     if (r->finfo.filetype != APR_DIR
761         && (res = check_symlinks(r->filename, ap_allow_options(r), r->pool))) {
762         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
763                     "Symbolic link not allowed: %s", r->filename);
764         return res;
765     }
766     return OK;                  /* Can only "fail" if access denied by the
767                                  * symlink goop. */
768 }
769
770 #else /* defined REPLACE_PATH_INFO_METHOD */
771
772 /*****************************************************************
773  *
774  * Getting and checking directory configuration.  Also checks the
775  * FollowSymlinks and FollowSymOwner stuff, since this is really the
776  * only place that can happen (barring a new mid_dir_walk callout).
777  *
778  * We can't do it as an access_checker module function which gets
779  * called with the final per_dir_config, since we could have a directory
780  * with FollowSymLinks disabled, which contains a symlink to another
781  * with a .htaccess file which turns FollowSymLinks back on --- and
782  * access in such a case must be denied.  So, whatever it is that
783  * checks FollowSymLinks needs to know the state of the options as
784  * they change, all the way down.
785  */
786
787 AP_DECLARE(int) ap_directory_walk(request_rec *r)
788 {
789     core_server_config *sconf = ap_get_module_config(r->server->module_config,
790                                                      &core_module);
791     ap_conf_vector_t *per_dir_defaults = r->server->lookup_defaults;
792     ap_conf_vector_t **sec_ent = (ap_conf_vector_t **) sconf->sec_dir->elts;
793     int num_sec = sconf->sec_dir->nelts;
794     int sec_idx;
795     unsigned int seg, startseg;
796     int res;
797     ap_conf_vector_t *entry_config;
798     core_dir_config *entry_core;
799     apr_status_t rv;
800     apr_size_t buflen;
801     char *seg_name;
802     char *delim;
803
804     /*
805      * XXX: Better (faster) tests needed!!!
806      *
807      * Are we dealing with a file? If not, the handler needed to register
808      * a hook to escape from our walking the file.  Since they haven't, we
809      * are going to assume the worst and refuse to proceed.
810      */
811     if (r->filename == NULL || !ap_os_is_path_absolute(r->pool, r->filename)) {
812         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
813                       "Module bug?  Request filename path %s is missing or "
814                       "or not absolute for uri %s", 
815                       r->filename ? r->filename : "<NULL>", r->uri);
816         return HTTP_INTERNAL_SERVER_ERROR;
817     }
818
819     /*
820      * Go down the directory hierarchy.  Where we have to check for symlinks,
821      * do so.  Where a .htaccess file has permission to override anything,
822      * try to find one.  If either of these things fails, we could poke
823      * around, see why, and adjust the lookup_rec accordingly --- this might
824      * save us a call to get_path_info (with the attendant stat()s); however,
825      * for the moment, that's not worth the trouble.
826      *
827      * r->path_info tracks the remaining source path.
828      * r->filename  tracks the path as we build it.
829      * we begin our adventure at the root...
830      */
831     r->path_info = r->filename;
832     if ((rv = apr_filepath_merge(&r->path_info, NULL, r->filename, 
833                                  APR_FILEPATH_NOTRELATIVE, r->pool)) 
834                   == APR_SUCCESS) {
835         char *buf;
836         rv = apr_filepath_root(&r->filename, &r->path_info, 
837                                APR_FILEPATH_TRUENAME, r->pool);
838         buflen = strlen(r->filename) + strlen(r->path_info) + 1;
839         buf = apr_palloc(r->pool, buflen);
840         strcpy (buf, r->filename);
841         r->filename = buf;
842         r->finfo.valid = APR_FINFO_TYPE;
843         r->finfo.filetype = APR_DIR; /* It's the root, of course it's a dir */
844     } else {
845         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
846                       "Config bug?  Request filename path %s is invalid or "
847                       "or not absolute for uri %s", 
848                       r->filename, r->uri);
849         return HTTP_INTERNAL_SERVER_ERROR;
850     }
851
852     /*
853      * seg keeps track of which segment we've copied.
854      * sec_idx keeps track of which section we're on, since sections are
855      *     ordered by number of segments. See core_reorder_directories 
856      */
857     startseg = seg = ap_count_dirs(r->filename);
858     sec_idx = 0;
859     do {
860         int overrides_here;
861         core_dir_config *core_dir = ap_get_module_config(per_dir_defaults,
862                                                          &core_module);
863         
864         /* We have no trailing slash, but we sure would appreciate one...
865          */
866         if (sec_idx && r->filename[strlen(r->filename)-1] != '/')
867             strcat(r->filename, "/");
868
869         /* Begin *this* level by looking for matching <Directory> sections
870          * from the server config.
871          */
872         for (; sec_idx < num_sec; ++sec_idx) {
873             const char *entry_dir;
874
875             entry_config = sec_ent[sec_idx];
876             entry_core = ap_get_module_config(entry_config, &core_module);
877             entry_dir = entry_core->d;
878
879             /* No more possible matches for this many segments? 
880              * We are done when we find relative/regex/longer components.
881              */
882             if (entry_core->r || entry_core->d_components > seg)
883                 break;
884
885             /* We will never skip '0' element components, e.g. plain old
886              * <Directory >, and <Directory "/"> are classified as zero 
887              * so that Win32/Netware/OS2 etc all pick them up.
888              * Otherwise, skip over the mismatches.
889              */
890             if (entry_core->d_components
891                   && (entry_core->d_is_fnmatch
892                         ? (apr_fnmatch(entry_dir, r->filename, FNM_PATHNAME) != APR_SUCCESS)
893                         : (strcmp(r->filename, entry_dir) != 0))) {
894                 continue;
895             }
896
897             per_dir_defaults = ap_merge_per_dir_configs(r->pool,
898                                                         per_dir_defaults,
899                                                         entry_config);
900             core_dir = ap_get_module_config(per_dir_defaults,
901                                                 &core_module);
902         }
903         overrides_here = core_dir->override;
904
905         /* If .htaccess files are enabled, check for one. */
906         if (overrides_here) {
907             ap_conf_vector_t *htaccess_conf = NULL;
908
909             res = ap_parse_htaccess(&htaccess_conf, r, overrides_here,
910                                     apr_pstrdup(r->pool, r->filename),
911                                     sconf->access_name);
912             if (res)
913                 return res;
914
915             if (htaccess_conf) {
916                 per_dir_defaults = ap_merge_per_dir_configs(r->pool,
917                                                             per_dir_defaults,
918                                                             htaccess_conf);
919                 r->per_dir_config = per_dir_defaults;
920             }
921         }
922
923         /* That temporary trailing slash was useful, now drop it.
924          */
925         if (seg > startseg)
926             r->filename[strlen(r->filename) - 1] = '\0';
927
928         /* Time for all good things to come to an end?
929          */
930         if (!r->path_info || !*r->path_info)
931             break;
932
933         /* Now it's time for the next segment... 
934          * We will assume the next element is an end node, and fix it up
935          * below as necessary...
936          */
937         
938         seg_name = strchr(r->filename, '\0');
939         delim = strchr(r->path_info + (*r->path_info == '/' ? 1 : 0), '/');
940         if (delim) {
941             *delim = '\0';
942             strcpy(seg_name, r->path_info);
943             r->path_info = delim;
944             *delim = '/';
945         }
946         else {
947             strcpy(seg_name, r->path_info);
948             r->path_info = strchr(r->path_info, '\0');
949         }
950         if (*seg_name == '/') 
951             ++seg_name;
952         
953         /* If nothing remained but a '/' string, we are finished
954          */
955         if (!*seg_name)
956             break;
957
958         /* XXX: Optimization required:
959          * If...we have allowed symlinks, and
960          * if...we find the segment exists in the directory list
961          * skip the lstat and dummy up an APR_DIR value for r->finfo
962          * this means case sensitive platforms go quite quickly.
963          * Case insensitive platforms might be given the wrong path,
964          * but if it's not found in the cache, then we know we have
965          * something to test (the misspelling is never cached.)
966          */
967
968         /* We choose apr_lstat here, rather that apr_stat, so that we
969          * capture this path object rather than its target.  We will
970          * replace the info with our target's info below.  We especially
971          * want the name of this 'link' object, not the name of its
972          * target, if we are fixing case.
973          */
974         rv = apr_lstat(&r->finfo, r->filename, APR_FINFO_MIN | APR_FINFO_NAME, r->pool);
975
976         if (APR_STATUS_IS_ENOENT(rv)) {
977             /* Nothing?  That could be nice.  But our directory walk is done.
978              */
979             r->finfo.filetype = APR_NOFILE;
980             break;
981         }
982         else if (APR_STATUS_IS_EACCES(rv)) {
983             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
984                           "access to %s denied", r->uri);
985             return r->status = HTTP_FORBIDDEN;
986         }
987         else if ((rv != APR_SUCCESS && rv != APR_INCOMPLETE) 
988                  || !(r->finfo.valid & APR_FINFO_TYPE)) {
989             /* If we hit ENOTDIR, we must have over-optimized, deny 
990              * rather than assume not found.
991              */
992             ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
993                           "access to %s failed", r->uri);
994             return r->status = HTTP_FORBIDDEN;
995         }
996         else if ((res = check_safe_file(r))) {
997             r->status = res;
998             return res;
999         }
1000
1001         /* Fix up the path now if we have a name, and they don't agree
1002          */
1003         if ((r->finfo.valid & APR_FINFO_NAME) 
1004             && strcmp(seg_name, r->finfo.name)) {
1005             /* TODO: provide users an option that an internal/external
1006              * redirect is required here?
1007              */
1008             strcpy(seg_name, r->finfo.name);
1009         }
1010
1011         if (r->finfo.filetype == APR_LNK) 
1012         {
1013             /* Is this an possibly acceptable symlink?
1014              */
1015             if ((res = resolve_symlink(r->filename, &r->finfo, 
1016                                        core_dir->opts, r->pool)) != OK) {
1017                 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
1018                             "Symbolic link not allowed: %s", r->filename);
1019                 return r->status = res;
1020             }
1021
1022             /* Ok, we are done with the link's info, test the real target
1023              */
1024             if (r->finfo.filetype == APR_REG) {
1025                 /* That was fun, nothing left for us here
1026                  */
1027                 break;
1028             }
1029             else if (r->finfo.filetype != APR_DIR) {
1030                 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
1031                               "symlink doesn't point to a file or directory: %s",
1032                               r->filename);
1033                 return r->status = HTTP_FORBIDDEN;
1034             }
1035         }
1036
1037         ++seg;
1038     } while (r->finfo.filetype == APR_DIR);
1039
1040     /*
1041      * Now we'll deal with the regexes.
1042      */
1043     for (; sec_idx < num_sec; ++sec_idx) {
1044
1045         entry_config = sec_ent[sec_idx];
1046         entry_core = ap_get_module_config(entry_config, &core_module);
1047
1048         if (!entry_core->r) {
1049             continue;
1050         }
1051         if (!ap_regexec(entry_core->r, r->filename, 0, NULL, REG_NOTEOL)) {
1052             per_dir_defaults = ap_merge_per_dir_configs(r->pool,
1053                                                         per_dir_defaults,
1054                                                         entry_config);
1055         }
1056     }
1057     r->per_dir_config = per_dir_defaults;
1058
1059 /* It seems this shouldn't be needed anymore.  We translated the symlink above
1060  x  into a real resource, and should have died up there.  Even if we keep this,
1061  x  it needs more thought (maybe an r->file_is_symlink) perhaps it should actually
1062  x  happen in file_walk, so we catch more obscure cases in autoindex sub requests, etc.
1063  x
1064  x    * Symlink permissions are determined by the parent.  If the request is
1065  x    * for a directory then applying the symlink test here would use the
1066  x    * permissions of the directory as opposed to its parent.  Consider a
1067  x    * symlink pointing to a dir with a .htaccess disallowing symlinks.  If
1068  x    * you access /symlink (or /symlink/) you would get a 403 without this
1069  x    * APR_DIR test.  But if you accessed /symlink/index.html, for example,
1070  x    * you would *not* get the 403.
1071  x
1072  x   if (r->finfo.filetype != APR_DIR
1073  x       && (res = resolve_symlink(r->filename, r->info, ap_allow_options(r), r->pool))) {
1074  x       ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
1075  x                   "Symbolic link not allowed: %s", r->filename);
1076  x       return res;
1077  x   }
1078  */
1079
1080     return OK;  /* 'no excuses' */
1081 }
1082
1083 #endif /* defined REPLACE_PATH_INFO_METHOD */
1084
1085 typedef struct walk_walked_t {
1086     ap_conf_vector_t *matched; /* A dir_conf sections we matched */
1087     ap_conf_vector_t *merged;  /* The dir_conf merged result */
1088 } walk_walked_t;
1089
1090 typedef struct walk_cache_t {
1091     const char         *cached;         /* The identifier we matched */
1092     ap_conf_vector_t  **dir_conf_tested;/* The sections we matched against */
1093     ap_conf_vector_t   *per_dir_result; /* per_dir_config += walked result */
1094     apr_array_header_t *walked;         /* The list of walk_walked_t results */
1095 } walk_cache_t;
1096
1097 AP_DECLARE(int) ap_location_walk(request_rec *r)
1098 {
1099     ap_conf_vector_t *now_merged = NULL;
1100     core_server_config *sconf = ap_get_module_config(r->server->module_config,
1101                                                      &core_module);
1102     ap_conf_vector_t **locations = (ap_conf_vector_t **) sconf->sec_url->elts;
1103     int num_loc = sconf->sec_url->nelts;
1104     core_dir_config *entry_core;
1105     walk_cache_t *cache;
1106     walk_walked_t *last_walk;
1107     const char *entry_uri;
1108     int len, j;
1109
1110     /* Find the most relevant, recent entry to work from.  That would be
1111      * this request (on the second call), or the parent request of a
1112      * subrequest, or the prior request of an internal redirect.
1113      */
1114     if ((apr_pool_userdata_get((void **)&cache, 
1115                                "ap_location_walk::cache", r->pool)
1116                 != APR_SUCCESS) || !cache) 
1117     {
1118         if ((r->main && (apr_pool_userdata_get((void **)&cache, 
1119                                                "ap_location_walk::cache",
1120                                                r->main->pool)
1121                                  == APR_SUCCESS) && cache)
1122          || (r->prev && (apr_pool_userdata_get((void **)&cache, 
1123                                                "ap_location_walk::cache",
1124                                                r->prev->pool)
1125                                  == APR_SUCCESS) && cache)) {
1126             cache = apr_pmemdup(r->pool, cache, sizeof(*cache));
1127             cache->walked = apr_array_copy(r->pool, cache->walked);
1128         }
1129         else {
1130             cache = apr_pcalloc(r->pool, sizeof(*cache));
1131             cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t));
1132         }
1133         apr_pool_userdata_set(cache, "ap_location_walk::cache", 
1134                               apr_pool_cleanup_null, r->pool);
1135     }
1136
1137     /* If the initial request creation logic failed to reset the
1138      * per_dir_config, we will do so here.
1139      * ### at this time, only subreq creation fails to do so.
1140      */
1141     if (!r->per_dir_config)
1142         r->per_dir_config = r->server->lookup_defaults;
1143     
1144     /* No tricks here, there are no <Locations > to parse in this vhost.
1145      * We cache NULL because it's possible that another vhost had some
1146      * different locations, and we are throwing those away.
1147      */
1148     if (!num_loc) {
1149         return OK;
1150     }
1151
1152     /* Location and LocationMatch differ on their behaviour w.r.t. multiple
1153      * slashes.  Location matches multiple slashes with a single slash,
1154      * LocationMatch doesn't.  An exception, for backwards brokenness is
1155      * absoluteURIs... in which case neither match multiple slashes.
1156      */
1157     if (r->uri[0] != '/') {
1158         entry_uri = r->uri;
1159     }
1160     else {
1161         char *uri = apr_pstrdup(r->pool, r->uri);
1162         ap_no2slash(uri);
1163         entry_uri = uri;
1164     }
1165
1166     /* If we have an cache->cached location that matches r->uri,
1167      * and the vhost's list of locations hasn't changed, we can skip
1168      * rewalking the location_walk entries.
1169      */
1170     if (cache->cached && (cache->dir_conf_tested == locations) 
1171                       && (strcmp(entry_uri, cache->cached) == 0)) {
1172         /* Well this looks really familiar!  If our end-result (per_dir_result)
1173          * didn't change, we have absolutely nothing to do :)  
1174          * Otherwise (as is the case with most dir_merged/file_merged requests)
1175          * we must merge our dir_conf_merged onto this new r->per_dir_config.
1176          */
1177         if (cache->per_dir_result == r->per_dir_config)
1178             return OK;
1179         if (cache->walked->nelts)
1180             now_merged = ((walk_walked_t*)cache->walked->elts)
1181                                             [cache->walked->nelts - 1].merged;
1182     }
1183     else {
1184         /* We start now_merged from NULL since we want to build 
1185          * a locations list that can be merged to any vhost.
1186          */
1187         int matches = cache->walked->nelts;
1188         last_walk = (walk_walked_t*)cache->walked->elts;
1189         cache->cached = entry_uri;
1190         cache->dir_conf_tested = locations;
1191
1192         /* Go through the location entries, and check for matches.
1193          * We apply the directive sections in given order, we should
1194          * really try them with the most general first.
1195          */
1196         for (j = 0; j < num_loc; ++j) {
1197
1198             entry_core = ap_get_module_config(locations[j], &core_module);
1199             entry_uri = entry_core->d;
1200
1201             len = strlen(entry_uri);
1202
1203             /* Test the regex, fnmatch or string as appropriate.
1204              * If it's a strcmp, and the <Location > pattern was 
1205              * not slash terminated, then this uri must be slash
1206              * terminated (or at the end of the string) to match.
1207              */
1208             if (entry_core->r 
1209                   ? ap_regexec(entry_core->r, r->uri, 0, NULL, 0)
1210                   : (entry_core->d_is_fnmatch
1211                        ? apr_fnmatch(entry_uri, cache->cached, FNM_PATHNAME)
1212                        : (strncmp(cache->cached, entry_uri, len)
1213                             || (entry_uri[len - 1] != '/'
1214                              && cache->cached[len] != '/' 
1215                              && cache->cached[len] != '\0')))) {
1216                 continue;
1217             }
1218
1219             /* If we merged this same section last time, reuse it
1220              */
1221             if (matches) {
1222                 if (last_walk->matched == locations[j]) {
1223                     now_merged = last_walk->merged;
1224                     ++last_walk;
1225                     --matches;
1226                     continue;
1227                 }
1228                 /* We fell out of sync.  This is our own copy of walked,
1229                  * so truncate the remaining matches and reset remaining.
1230                  */
1231                 cache->walked->nelts -= matches;
1232                 matches = 0;
1233             }
1234
1235             if (now_merged)
1236                 now_merged = ap_merge_per_dir_configs(r->pool, 
1237                                                       now_merged,
1238                                                       locations[j]);
1239             else
1240                 now_merged = locations[j];
1241
1242             last_walk = (walk_walked_t*)apr_array_push(cache->walked);
1243             last_walk->matched = locations[j];
1244             last_walk->merged = now_merged;
1245         }
1246         /* Whoops - everything matched in sequence, but the original walk
1247          * found some additional matches.  Truncate them.
1248          */
1249         if (matches)
1250             cache->walked->nelts -= matches;
1251     }
1252
1253     /* Merge our cache->dir_conf_merged construct with the r->per_dir_configs,
1254      * and note the end result to (potentially) skip this step next time.
1255      */
1256     if (now_merged)
1257         r->per_dir_config = ap_merge_per_dir_configs(r->pool,
1258                                                      r->per_dir_config,
1259                                                      now_merged);
1260     cache->per_dir_result = r->per_dir_config;
1261
1262     return OK;
1263 }
1264
1265 AP_DECLARE(int) ap_file_walk(request_rec *r)
1266 {
1267     core_dir_config *conf = ap_get_module_config(r->per_dir_config,
1268                                                  &core_module);
1269     ap_conf_vector_t *per_dir_defaults = r->per_dir_config;
1270     ap_conf_vector_t **file = (ap_conf_vector_t **) conf->sec_file->elts;
1271     int num_files = conf->sec_file->nelts;
1272     char *test_file;
1273
1274     /* get the basename */
1275     test_file = strrchr(r->filename, '/');
1276     if (test_file == NULL) {
1277         test_file = r->filename;
1278     }
1279     else {
1280         ++test_file;
1281     }
1282
1283     /* Go through the file entries, and check for matches. */
1284
1285     if (num_files) {
1286         ap_conf_vector_t *this_conf;
1287         ap_conf_vector_t *entry_config;
1288         core_dir_config *entry_core;
1289         char *entry_file;
1290         int j;
1291
1292         /* we apply the directive sections in some order;
1293          * should really try them with the most general first.
1294          */
1295         for (j = 0; j < num_files; ++j) {
1296
1297             entry_config = file[j];
1298
1299             entry_core = ap_get_module_config(entry_config, &core_module);
1300             entry_file = entry_core->d;
1301
1302             this_conf = NULL;
1303
1304             if (entry_core->r) {
1305                 if (!ap_regexec(entry_core->r, test_file, 0, NULL, 0))
1306                     this_conf = entry_config;
1307             }
1308             else if (entry_core->d_is_fnmatch) {
1309                 if (!apr_fnmatch(entry_file, test_file, FNM_PATHNAME)) {
1310                     this_conf = entry_config;
1311                 }
1312             }
1313             else if (!strcmp(test_file, entry_file)) {
1314                 this_conf = entry_config;
1315             }
1316
1317             if (this_conf)
1318                 per_dir_defaults = ap_merge_per_dir_configs(r->pool,
1319                                                             per_dir_defaults,
1320                                                             this_conf);
1321         }
1322         r->per_dir_config = per_dir_defaults;
1323     }
1324     return OK;
1325 }
1326
1327 /*****************************************************************
1328  *
1329  * The sub_request mechanism.
1330  *
1331  * Fns to look up a relative URI from, e.g., a map file or SSI document.
1332  * These do all access checks, etc., but don't actually run the transaction
1333  * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
1334  * as appropriate if you're likely to be creating more than a few of these.
1335  * (An early Apache version didn't destroy the sub_reqs used in directory
1336  * indexing.  The result, when indexing a directory with 800-odd files in
1337  * it, was massively excessive storage allocation).
1338  *
1339  * Note more manipulation of protocol-specific vars in the request
1340  * structure...
1341  */
1342
1343 static request_rec *make_sub_request(const request_rec *r)
1344 {
1345     apr_pool_t *rrp;
1346     request_rec *rr;
1347     
1348     apr_pool_create(&rrp, r->pool);
1349     rr = apr_pcalloc(rrp, sizeof(request_rec));
1350     rr->pool = rrp;
1351     return rr;
1352 }
1353
1354 static void fill_in_sub_req_vars(request_rec *rnew, const request_rec *r,
1355                                  ap_filter_t *next_filter)
1356 {
1357     rnew->hostname       = r->hostname;
1358     rnew->request_time   = r->request_time;
1359     rnew->connection     = r->connection;
1360     rnew->server         = r->server;
1361
1362     rnew->request_config = ap_create_request_config(rnew->pool);
1363
1364     rnew->htaccess       = r->htaccess;
1365     rnew->allowed_methods = ap_make_method_list(rnew->pool, 2);
1366
1367     /* make a copy of the allowed-methods list */
1368     ap_copy_method_list(rnew->allowed_methods, r->allowed_methods);
1369
1370     /* start with the same set of output filters */
1371     if (next_filter) {
1372         rnew->output_filters = next_filter;
1373     }
1374     else {
1375         rnew->output_filters = r->output_filters;
1376     }
1377     ap_add_output_filter("SUBREQ_CORE", NULL, rnew, rnew->connection); 
1378
1379     /* no input filters for a subrequest */
1380
1381     ap_set_sub_req_protocol(rnew, r);
1382 }
1383
1384 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_sub_req_output_filter(ap_filter_t *f,
1385                                                         apr_bucket_brigade *bb)
1386 {
1387     apr_bucket *e = APR_BRIGADE_LAST(bb);
1388
1389     if (APR_BUCKET_IS_EOS(e)) {
1390         apr_bucket_delete(e);
1391     }
1392     return ap_pass_brigade(f->next, bb);
1393 }
1394
1395  
1396 AP_DECLARE(int) ap_some_auth_required(request_rec *r)
1397 {
1398     /* Is there a require line configured for the type of *this* req? */
1399  
1400     const apr_array_header_t *reqs_arr = ap_requires(r);
1401     require_line *reqs;
1402     int i;
1403  
1404     if (!reqs_arr)
1405         return 0;
1406  
1407     reqs = (require_line *) reqs_arr->elts;
1408  
1409     for (i = 0; i < reqs_arr->nelts; ++i)
1410         if (reqs[i].method_mask & (AP_METHOD_BIT << r->method_number))
1411             return 1;
1412  
1413     return 0;
1414
1415
1416
1417 AP_DECLARE(request_rec *) ap_sub_req_method_uri(const char *method,
1418                                                 const char *new_file,
1419                                                 const request_rec *r,
1420                                                 ap_filter_t *next_filter)
1421 {
1422     request_rec *rnew;
1423     int res;
1424     char *udir;
1425
1426     rnew = make_sub_request(r);
1427     fill_in_sub_req_vars(rnew, r, next_filter);
1428
1429     rnew->per_dir_config = r->server->lookup_defaults;
1430
1431     /* We have to run this after fill_in_sub_req_vars, or the r->main
1432      * pointer won't be setup
1433      */
1434     ap_run_create_request(rnew);
1435
1436     /* would be nicer to pass "method" to ap_set_sub_req_protocol */
1437     rnew->method = method;
1438     rnew->method_number = ap_method_number_of(method);
1439
1440     if (new_file[0] == '/')
1441         ap_parse_uri(rnew, new_file);
1442     else {
1443         udir = ap_make_dirstr_parent(rnew->pool, r->uri);
1444         udir = ap_escape_uri(rnew->pool, udir);    /* re-escape it */
1445         ap_parse_uri(rnew, ap_make_full_path(rnew->pool, udir, new_file));
1446     }
1447
1448     if ((res = ap_process_request_internal(rnew))) {
1449         rnew->status = res;
1450     }
1451
1452     return rnew;
1453 }
1454
1455 AP_DECLARE(request_rec *) ap_sub_req_lookup_uri(const char *new_file,
1456                                                 const request_rec *r,
1457                                                 ap_filter_t *next_filter)
1458 {
1459     return ap_sub_req_method_uri("GET", new_file, r, next_filter);
1460 }
1461
1462 AP_DECLARE(request_rec *) ap_sub_req_lookup_dirent(const apr_finfo_t *dirent,
1463                                                    const request_rec *r,
1464                                                    ap_filter_t *next_filter)
1465 {
1466     request_rec *rnew;
1467     int res;
1468     char *fdir;
1469     char *udir;
1470
1471     rnew = make_sub_request(r);
1472     fill_in_sub_req_vars(rnew, r, next_filter);
1473
1474     rnew->chunked        = r->chunked;
1475
1476     /* We have to run this after fill_in_sub_req_vars, or the r->main
1477      * pointer won't be setup
1478      */
1479     ap_run_create_request(rnew);
1480
1481     fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
1482
1483     /*
1484      * Special case: we are looking at a relative lookup in the same directory. 
1485      * That means we won't have to redo directory_walk, and we may
1486      * not even have to redo access checks.
1487      */
1488
1489     udir = ap_make_dirstr_parent(rnew->pool, r->uri);
1490
1491     /* This is 100% safe, since dirent->name just came from the filesystem */
1492     rnew->uri = ap_make_full_path(rnew->pool, udir, dirent->name);
1493     rnew->filename = ap_make_full_path(rnew->pool, fdir, dirent->name);
1494     if (r->canonical_filename == r->filename)
1495         rnew->canonical_filename = rnew->filename;
1496     
1497     ap_parse_uri(rnew, rnew->uri);    /* fill in parsed_uri values */
1498
1499 #if 0 /* XXX When this is reenabled, the cache triggers need to be set to faux
1500        * dir_walk/file_walk values.
1501        */
1502     rnew->per_dir_config = r->per_dir_config;
1503
1504     if ((dirent->valid & APR_FINFO_MIN) != APR_FINFO_MIN) {
1505         /*
1506          * apr_dir_read isn't very complete on this platform, so
1507          * we need another apr_lstat (or simply apr_stat if we allow
1508          * all symlinks here.)  If this is an APR_LNK that resolves 
1509          * to an APR_DIR, then we will rerun everything anyways... 
1510          * this should be safe.
1511          */
1512         apr_status_t rv;
1513         if (ap_allow_options(rnew) & OPT_SYM_LINKS) {
1514             if (((rv = apr_stat(&rnew->finfo, rnew->filename,
1515                                  APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
1516                                                       && (rv != APR_INCOMPLETE))
1517                 rnew->finfo.filetype = 0;
1518         }
1519         else
1520             if (((rv = apr_lstat(&rnew->finfo, rnew->filename,
1521                                  APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
1522                                                       && (rv != APR_INCOMPLETE))
1523                 rnew->finfo.filetype = 0;
1524     }
1525     else {
1526         memcpy (&rnew->finfo, dirent, sizeof(apr_finfo_t));
1527     }
1528
1529     if ((res = check_safe_file(rnew))) {
1530         rnew->status = res;
1531         return rnew;
1532     }
1533
1534     if (rnew->finfo.filetype == APR_LNK
1535         && (res = resolve_symlink(rnew->filename, &rnew->finfo, 
1536                                   ap_allow_options(rnew), rnew->pool)) != OK) {
1537         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, rnew,
1538                     "Symbolic link not allowed: %s", rnew->filename);
1539         rnew->status = res;
1540         return rnew;
1541     }
1542
1543     /*
1544      * no matter what, if it's a subdirectory, we need to re-run
1545      * directory_walk
1546      */
1547     if (rnew->finfo.filetype == APR_DIR) {
1548         if (!(res = ap_directory_walk(rnew)))
1549             if (!(res = ap_file_walk(rnew)))
1550                 res = ap_location_walk(rnew);
1551     }
1552     else if (rnew->finfo.filetype == APR_REG || !rnew->finfo.filetype) {
1553         /*
1554          * do a file_walk, if it doesn't change the per_dir_config then
1555          * we know that we don't have to redo all the access checks
1556          */
1557         if (   !(res = ap_file_walk(rnew))
1558             && !(res = ap_location_walk(rnew))
1559             && (rnew->per_dir_config == r->per_dir_config))
1560         {
1561             if (   (res = ap_run_type_checker(rnew)) 
1562                 || (res = ap_run_fixups(rnew))) {
1563                 rnew->status = res;
1564             }
1565             return rnew;
1566         }  
1567     }
1568 #endif
1569
1570     if ((res = ap_process_request_internal(rnew))) {
1571         rnew->status = res;
1572     }
1573
1574     return rnew;
1575 }
1576
1577 AP_DECLARE(request_rec *) ap_sub_req_lookup_file(const char *new_file,
1578                                               const request_rec *r,
1579                                               ap_filter_t *next_filter)
1580 {
1581     request_rec *rnew;
1582     int res;
1583     char *fdir;
1584     apr_size_t fdirlen;
1585
1586     rnew = make_sub_request(r);
1587     fill_in_sub_req_vars(rnew, r, next_filter);
1588
1589     /* XXX Either this is needed for all subreq types (move into
1590      * fill_in_sub_req_vars), or it isn't needed at all.  
1591      * WHICH IS IT?
1592      */
1593     rnew->chunked        = r->chunked;
1594
1595     /* We have to run this after fill_in_sub_req_vars, or the r->main
1596      * pointer won't be setup
1597      */
1598     ap_run_create_request(rnew);
1599
1600     fdir = ap_make_dirstr_parent(rnew->pool, r->filename);
1601     fdirlen = strlen(fdir);
1602
1603     /* Translate r->filename, if it was canonical, it stays canonical
1604      */
1605     if (r->canonical_filename == r->filename)
1606         rnew->canonical_filename = (char*)(1);
1607     if (apr_filepath_merge(&rnew->filename, fdir, new_file,
1608                            APR_FILEPATH_TRUENAME, rnew->pool) != APR_SUCCESS) {
1609         rnew->status = HTTP_FORBIDDEN;
1610         return rnew;
1611     }
1612     if (rnew->canonical_filename)
1613         rnew->canonical_filename = rnew->filename;
1614
1615     /*
1616      * Check for a special case... if there are no '/' characters in new_file
1617      * at all, and the path was the same, then we are looking at a relative 
1618      * lookup in the same directory. That means we won't have to redo 
1619      * directory_walk, and we may not even have to redo access checks.
1620      * ### Someday we don't even have to redo the entire directory walk,
1621      * either, if the base paths match, we can pick up where we leave off.
1622      */
1623
1624     if (strncmp(rnew->filename, fdir, fdirlen) == 0
1625            && rnew->filename[fdirlen] 
1626            && ap_strchr_c(rnew->filename + fdirlen, '/') == NULL) 
1627     {
1628         char *udir = ap_make_dirstr_parent(rnew->pool, r->uri);
1629
1630         rnew->uri = ap_make_full_path(rnew->pool, udir, new_file);
1631         ap_parse_uri(rnew, rnew->uri);    /* fill in parsed_uri values */
1632
1633 #if 0 /* XXX When this is reenabled, the cache triggers need to be set to faux
1634        * dir_walk/file_walk values.
1635        */
1636
1637         rnew->per_dir_config = r->per_dir_config;
1638
1639         /*
1640          * If this is an APR_LNK that resolves to an APR_DIR, then 
1641          * we will rerun everything anyways... this should be safe.
1642          */
1643         if (ap_allow_options(rnew) & OPT_SYM_LINKS) {
1644             apr_status_t rv;
1645             if (((rv = apr_stat(&rnew->finfo, rnew->filename,
1646                                  APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
1647                                                       && (rv != APR_INCOMPLETE))
1648                 rnew->finfo.filetype = 0;
1649         }
1650         else {
1651             apr_status_t rv;
1652             if (((rv = apr_lstat(&rnew->finfo, rnew->filename,
1653                                  APR_FINFO_MIN, rnew->pool)) != APR_SUCCESS)
1654                                                       && (rv != APR_INCOMPLETE))
1655                 rnew->finfo.filetype = 0;
1656         }
1657
1658         if ((res = check_safe_file(rnew))) {
1659             rnew->status = res;
1660             return rnew;
1661         }
1662
1663         if (rnew->finfo.filetype == APR_LNK
1664             && (res = resolve_symlink(rnew->filename, &rnew->finfo, 
1665                                       ap_allow_options(rnew), rnew->pool)) != OK) {
1666             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, rnew,
1667                         "Symbolic link not allowed: %s", rnew->filename);
1668             rnew->status = res;
1669             return rnew;
1670         }
1671
1672         /*
1673          * no matter what, if it's a subdirectory, we need to re-run
1674          * directory_walk
1675          */
1676         if (rnew->finfo.filetype == APR_DIR) {
1677             if (!(res = ap_directory_walk(rnew)))
1678                 if (!(res = ap_file_walk(rnew)))
1679                     res = ap_location_walk(rnew);
1680         }
1681         else if (rnew->finfo.filetype == APR_REG || !rnew->finfo.filetype) {
1682             /*
1683              * do a file_walk, if it doesn't change the per_dir_config then
1684              * we know that we don't have to redo all the access checks
1685              */
1686             if (   !(res = ap_file_walk(rnew))
1687                 && !(res = ap_location_walk(rnew))
1688                 && (rnew->per_dir_config == r->per_dir_config))
1689             {
1690                 if (   (res = ap_run_type_checker(rnew)) 
1691                     || (res = ap_run_fixups(rnew))) {
1692                     rnew->status = res;
1693                 }
1694                 return rnew;
1695             }
1696         }
1697         else {
1698             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, rnew,
1699                           "symlink doesn't point to a file or directory: %s",
1700                           r->filename);
1701             res = HTTP_FORBIDDEN;
1702         }
1703 #endif
1704     }
1705     else {
1706         /* XXX: @@@: What should be done with the parsed_uri values? */
1707         ap_parse_uri(rnew, new_file);   /* fill in parsed_uri values */
1708         /*
1709          * XXX: this should be set properly like it is in the same-dir case
1710          * but it's actually sometimes to impossible to do it... because the
1711          * file may not have a uri associated with it -djg
1712          */
1713         rnew->uri = "INTERNALLY GENERATED file-relative req";
1714
1715 #if 0 /* XXX When this is reenabled, the cache triggers need to be set to faux
1716        * dir_walk/file_walk values.
1717        */
1718
1719         rnew->per_dir_config = r->server->lookup_defaults;
1720         res = ap_directory_walk(rnew);
1721         if (!res) {
1722             res = ap_file_walk(rnew);
1723         }
1724 #endif
1725     }
1726
1727
1728     if ((res = ap_process_request_internal(rnew))) {
1729         rnew->status = res;
1730     }
1731
1732     return rnew;
1733 }
1734
1735 AP_DECLARE(int) ap_run_sub_req(request_rec *r)
1736 {
1737     int retval;
1738
1739     retval = ap_invoke_handler(r);
1740     ap_finalize_sub_req_protocol(r);
1741     return retval;
1742 }
1743
1744 AP_DECLARE(void) ap_destroy_sub_req(request_rec *r)
1745 {
1746     /* Reclaim the space */
1747     apr_pool_destroy(r->pool);
1748 }
1749
1750 /*
1751  * Function to set the r->mtime field to the specified value if it's later
1752  * than what's already there.
1753  */
1754 AP_DECLARE(void) ap_update_mtime(request_rec *r, apr_time_t dependency_mtime)
1755 {
1756     if (r->mtime < dependency_mtime) {
1757         r->mtime = dependency_mtime;
1758     }
1759 }
1760
1761 /*
1762  * Is it the initial main request, which we only get *once* per HTTP request?
1763  */
1764 AP_DECLARE(int) ap_is_initial_req(request_rec *r)
1765 {
1766     return
1767         (r->main == NULL)       /* otherwise, this is a sub-request */
1768         &&
1769         (r->prev == NULL);      /* otherwise, this is an internal redirect */
1770
1771