request.c revision 42da244268b11ec661b528510f80a18b73c51727
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski/* ====================================================================
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * The Apache Software License, Version 1.1
980f1e5f03d0c0772698ebb372fc711431dd0114Christian Maeder * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
3f69b6948966979163bdfe8331c38833d5d90ecdChristian Maeder * Redistribution and use in source and binary forms, with or without
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * modification, are permitted provided that the following conditions
e6d40133bc9f858308654afb1262b8b483ec5922Till Mossakowski * 1. Redistributions of source code must retain the above copyright
679d3f541f7a9ede4079e045f7758873bb901872Till Mossakowski * notice, this list of conditions and the following disclaimer.
10a2cf8d9887524acde19d4ea59f8fea3a7f3258Till Mossakowski * 2. Redistributions in binary form must reproduce the above copyright
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * notice, this list of conditions and the following disclaimer in
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * the documentation and/or other materials provided with the
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * distribution.
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * 3. The end-user documentation included with the redistribution,
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * if any, must include the following acknowledgment:
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * "This product includes software developed by the
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * Apache Software Foundation (http://www.apache.org/)."
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * Alternately, this acknowledgment may appear in the software itself,
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * if and wherever such third-party acknowledgments normally appear.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * 4. The names "Apache" and "Apache Software Foundation" must
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * not be used to endorse or promote products derived from this
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * software without prior written permission. For written
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * permission, please contact apache@apache.org.
ad270004874ce1d0697fb30d7309f180553bb315Christian Maeder * 5. Products derived from this software may not be called "Apache",
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * nor may "Apache" appear in their name, without prior written
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * permission of the Apache Software Foundation.
67869d63d1725c79e4c07b51acd466a31932b275Christian Maeder * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
575a55eadc8dcab8ee350324b417cbd9e52e69c0Christian Maeder * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill Mossakowski * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * SUCH DAMAGE.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * ====================================================================
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * This software consists of voluntary contributions made by many
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * individuals on behalf of the Apache Software Foundation. For more
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * information on the Apache Software Foundation, please see
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Portions of this software are based upon public domain software
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * originally written at the National Center for Supercomputing Applications,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * University of Illinois, Urbana-Champaign.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * http_request.c: functions to get and process requests
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Rob McCool 3/21/93
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Thoroughly revamped by rst for Apache. NB this file reads
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * best from the bottom up.
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
f64f785dc42953597cb8d98900833ecf83fcab09Christian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill MossakowskiAP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker,
d7f3a1e900a30469268df8033b87b92d7e827e30Christian MaederAP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker,
aea143fff7a50aceb809845fbc42698b0b3f545aChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill MossakowskiAP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
0c2a90cbfb63865ff485c3fbe20a14589a5914beTill MossakowskiAP_IMPLEMENT_HOOK_RUN_ALL(int, create_request,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowskistatic int decl_die(int status, char *phase, request_rec *r)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, r,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski "configuration error: couldn't %s: %s", phase, r->uri);
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder/* This is the master logic for processing requests. Do NOT duplicate
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * this logic elsewhere, or the security model will be broken by future
5f427cfb286859e5f450b2049f0e21008289c830Christian Maeder * API changes. Each phase must be individually optimized to pick up
5f427cfb286859e5f450b2049f0e21008289c830Christian Maeder * redundant/duplicate calls by subrequests, and redirects.
5f427cfb286859e5f450b2049f0e21008289c830Christian MaederAP_DECLARE(int) ap_process_request_internal(request_rec *r)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* Ignore embedded %2F's in path for proxy requests */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski access_status = ap_unescape_url(r->parsed_uri.path);
d0c66a832d7b556e20ea4af4852cdc27a5463d51Christian Maeder ap_getparents(r->uri); /* OK --- shrinking transformations... */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder /* All file subrequests are a huge pain... they cannot bubble through the
4b338e9d8a4e0bffb4d1bc6fb5fa371a8a0dec1aTill Mossakowski * next several steps. Only file subrequests are allowed an empty uri,
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * otherwise let translate_name kill the request.
eb8a05567e94cb9f477cd9dee6b337aa8dee02d6Christian Maeder if ((access_status = ap_location_walk(r))) {
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder if ((access_status = ap_run_translate_name(r))) {
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder return decl_die(access_status, "translate", r);
aea143fff7a50aceb809845fbc42698b0b3f545aChristian Maeder /* Reset to the server default config prior to running map_to_storage
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder r->per_dir_config = r->server->lookup_defaults;
9ecf13b5fd914bc7272f1fc17348d7f4a8c77061Christian Maeder if ((access_status = ap_run_map_to_storage(r))) {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder /* This request wasn't in storage (e.g. TRACE) */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* Excluding file-specific requests with no 'true' URI...
aea143fff7a50aceb809845fbc42698b0b3f545aChristian Maeder /* Rerun the location walk, which overrides any map_to_storage config.
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder if ((access_status = ap_location_walk(r))) {
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder /* Only on the main request! */
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder if ((access_status = ap_run_header_parser(r))) {
e01299e9b22b96b31b720ca1e9f9f5f25af9b024Christian Maeder /* Skip authn/authz if the parent or prior request passed the authn/authz,
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * and that configuration didn't change (this requires optimized _walk()
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * functions in map_to_storage that use the same merge results given
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * identical input.) If the config changes, we must re-auth.
9ecf13b5fd914bc7272f1fc17348d7f4a8c77061Christian Maeder if (r->main && (r->main->per_dir_config == r->per_dir_config)) {
fa167e362877db231378e17ba49c66fbb84862fcChristian Maeder else if (r->prev && (r->prev->per_dir_config == r->per_dir_config)) {
fa167e362877db231378e17ba49c66fbb84862fcChristian Maeder if ((access_status = ap_run_access_checker(r)) != 0) {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder return decl_die(access_status, "check access", r);
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder if (((access_status = ap_run_check_user_id(r)) != 0)
40d15f6c5f4d15866e085c588f8b5130dfd6cf63Christian Maeder return decl_die(access_status, ap_auth_type(r)
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder ? "check user. No user file?"
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder : "perform authentication. AuthType not set!",
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder if (((access_status = ap_run_auth_checker(r)) != 0)
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder return decl_die(access_status, ap_auth_type(r)
aea143fff7a50aceb809845fbc42698b0b3f545aChristian Maeder ? "check access. No groups file?"
40d15f6c5f4d15866e085c588f8b5130dfd6cf63Christian Maeder : "perform authentication. AuthType not set!",
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder if (((access_status = ap_run_access_checker(r)) != 0)
40d15f6c5f4d15866e085c588f8b5130dfd6cf63Christian Maeder return decl_die(access_status, ap_auth_type(r)
6a22b2854c3bc9cb4877cb7d29049d6559238639Christian Maeder ? "check access"
dd00735e659586abdebbb9442e4f44bf9eceedeeChristian Maeder : "perform authentication. AuthType not set!",
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder if (((access_status = ap_run_check_user_id(r)) != 0)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski return decl_die(access_status, ap_auth_type(r)
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder ? "check user. No user file?"
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski : "perform authentication. AuthType not set!",
aea143fff7a50aceb809845fbc42698b0b3f545aChristian Maeder if (((access_status = ap_run_auth_checker(r)) != 0)
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder return decl_die(access_status, ap_auth_type(r)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski ? "check access. No groups file?"
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder : "perform authentication. AuthType not set!",
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder /* XXX Must make certain the ap_run_type_checker short circuits mime
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * in mod-proxy for r->proxyreq && r->parsed_uri.scheme
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * && !strcmp(r->parsed_uri.scheme, "http")
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder if ((access_status = ap_run_type_checker(r)) != 0) {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski return decl_die(access_status, "find types", r);
9ecf13b5fd914bc7272f1fc17348d7f4a8c77061Christian Maeder if ((access_status = ap_run_fixups(r)) != 0) {
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder/* Useful caching structures to repeat _walk/merge sequences as required
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * when a subrequest or redirect reuses substantially the same config.
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * Directive order in the httpd.conf file and its Includes significantly
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * impact this optimization. Grouping common blocks at the front of the
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder * config that are less likely to change between a request and
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * its subrequests, or between a request and its redirects reduced
68138d26bcddf5e89c30206aa83ab5ec006d170dChristian Maeder * the work of these functions significantly.
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maeder ap_conf_vector_t *matched; /* A dir_conf sections we matched */
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder ap_conf_vector_t *merged; /* The dir_conf merged result */
786f66a85ab6d4541c407d4ae0d71dc338494f67Christian Maedertypedef struct walk_cache_t {
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder const char *cached; /* The identifier we matched */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder ap_conf_vector_t **dir_conf_tested; /* The sections we matched against */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder ap_conf_vector_t *dir_conf_merged; /* Base per_dir_config */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder ap_conf_vector_t *per_dir_result; /* per_dir_config += walked result */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder apr_array_header_t *walked; /* The list of walk_walked_t results */
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maederstatic walk_cache_t *prep_walk_cache(apr_size_t t, request_rec *r)
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder /* Find the most relevant, recent entry to work from. That would be
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * this request (on the second call), or the parent request of a
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * subrequest, or the prior request of an internal redirect. Provide
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * this _walk()er with a copy it is allowed to munge. If there is no
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * parent or prior cached request, then create a new walk cache.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski && ((inherit_note = ap_get_request_note(r->main, t)))
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski && ((inherit_note = ap_get_request_note(r->prev, t)))
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski cache = apr_pmemdup(r->pool, *inherit_note,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski cache->walked = apr_array_copy(r->pool, cache->walked);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski cache = apr_pcalloc(r->pool, sizeof(*cache));
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski cache->walked = apr_array_make(r->pool, 4, sizeof(walk_walked_t));
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski/*****************************************************************
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * Getting and checking directory configuration. Also checks the
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * FollowSymlinks and FollowSymOwner stuff, since this is really the
03136b84a0c70d877e227444f0875e209506b9e4Christian Maeder * only place that can happen (barring a new mid_dir_walk callout).
df6f4a9e6b3d0542ecc181fbc1bcec2affca1d30Christian Maeder * We can't do it as an access_checker module function which gets
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * called with the final per_dir_config, since we could have a directory
67869d63d1725c79e4c07b51acd466a31932b275Christian Maeder * with FollowSymLinks disabled, which contains a symlink to another
67869d63d1725c79e4c07b51acd466a31932b275Christian Maeder * with a .htaccess file which turns FollowSymLinks back on --- and
f64f785dc42953597cb8d98900833ecf83fcab09Christian Maeder * access in such a case must be denied. So, whatever it is that
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * checks FollowSymLinks needs to know the state of the options as
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * they change, all the way down.
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * We don't want people able to serve up pipes, or unix sockets, or other
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * scary things. Note that symlink tests are performed later.
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder if (r->finfo.filetype == 0 /* doesn't exist */
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder "object is not a file, directory or symlink: %s",
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder * resolve_symlink must _always_ be called on an APR_LNK file type!
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder * It will resolve the actual target file type, modification date, etc,
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder * and provide any processing required for symlink evaluation.
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder * Path must already be cleaned, no trailing slash, no multi-slashes,
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder * and don't call this on the root!
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder * Simply, the number of times we deref a symlink are minimal compared
ee152ae82dc19d6415119c0019ae1bfa991b1f02Christian Maeder * to the number of times we had an extra lstat() since we 'weren't sure'.
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder * To optimize, we stat() anything when given (opts & OPT_SYM_LINKS), otherwise
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * we start off with an lstat(). Every lstat() must be dereferenced in case
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder * it points at a 'nasty' - we must always rerun check_safe_file (or similar.)
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maederstatic int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p)
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS))) {
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder /* Save the name from the valid bits. */
58ab88e9fa53620974ff94aad166988495a27dc4Christian Maeder savename = (lfi->valid & APR_FINFO_NAME) ? lfi->name : NULL;
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if ((res = apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME
d0c66a832d7b556e20ea4af4852cdc27a5463d51Christian Maeder /* Give back the target */
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* OPT_SYM_OWNER only works if we can get the owner of
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * both the file and symlink. First fill in a missing
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * owner of the symlink, then get the info of the target.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if ((res = apr_lstat(&fi, d, lfi->valid | APR_FINFO_OWNER, p))
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if ((res = apr_stat(&fi, d, lfi->valid & ~(APR_FINFO_NAME), p))
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if (apr_compare_users(fi.user, lfi->user) != APR_SUCCESS) {
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* Give back the target */
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder/*****************************************************************
d8f14f4b0bc8d94b61a10c1d268ac33c8e43cca0Christian Maeder * Getting and checking directory configuration. Also checks the
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder * FollowSymlinks and FollowSymOwner stuff, since this is really the
40d15f6c5f4d15866e085c588f8b5130dfd6cf63Christian Maeder * only place that can happen (barring a new mid_dir_walk callout).
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * We can't do it as an access_checker module function which gets
1f086d5155f47fdad9a0de4e46bbebb2c4b33d30Christian Maeder * called with the final per_dir_config, since we could have a directory
0e2ae85e2453466d03c1fc5884a3d693235bb9d9Christian Maeder * with FollowSymLinks disabled, which contains a symlink to another
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * with a .htaccess file which turns FollowSymLinks back on --- and
5a9a06d23910b9521e1d1cd39865ac7912ccee4bChristian Maeder * access in such a case must be denied. So, whatever it is that
5a9a06d23910b9521e1d1cd39865ac7912ccee4bChristian Maeder * checks FollowSymLinks needs to know the state of the options as
5a9a06d23910b9521e1d1cd39865ac7912ccee4bChristian Maeder * they change, all the way down.
d7f3a1e900a30469268df8033b87b92d7e827e30Christian MaederAP_DECLARE(int) ap_directory_walk(request_rec *r)
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski core_server_config *sconf = ap_get_module_config(r->server->module_config,
6a22b2854c3bc9cb4877cb7d29049d6559238639Christian Maeder ap_conf_vector_t **sec_ent = (ap_conf_vector_t **) sconf->sec_dir->elts;
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder /* XXX: Better (faster) tests needed!!!
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * "OK" as a response to a real problem is not _OK_, but to allow broken
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * modules to proceed, we will permit the not-a-path filename to pass the
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * following two tests. This behavior may be revoked in future versions
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * of Apache. We still must catch it later if it's heading for the core
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * handler. Leave INFO notes here for module debugging.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski "Module bug? Request filename is missing for URI %s",
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* Canonicalize the file path without resolving filename case or aliases
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * so we can begin by checking the cache for a recent directory walk.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * This call will ensure we have an absolute path in the same pass.
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski if ((rv = apr_filepath_merge(&entry_dir, NULL, r->filename,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r,
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski "Module bug? Request filename path %s is invalid or "
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski "or not absolute for uri %s",
a7be28e157e9ceeec73a8fd0e642c36ea29d4218Christian Maeder /* XXX Notice that this forces path_info to be canonical. That might
fbf1cdad9a9775bd7332e85f01b6a307d7dbb1cfChristian Maeder * not be desired by all apps. However, some of those same apps likely
245e63ca4e8facdc267b6262e269ef3ac63b3c39Christian Maeder * have significant security holes.
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder cache = prep_walk_cache(AP_NOTE_DIRECTORY_WALK, r);
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder /* If this is not a dirent subrequest with a preconstructed
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski * r->finfo value, then we can simply stat the filename to
c438c79d00fc438f99627e612498744bdc0d0c89Christian Maeder * save burning mega-cycles with unneeded stats - if this is
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * an exact file match. We don't care about failure... we
f69658e57cba7ecb37c0d84181f4c563215c2534Till Mossakowski * will stat by component failing this meager attempt.
f69658e57cba7ecb37c0d84181f4c563215c2534Till Mossakowski * It would be nice to distinguish APR_ENOENT from other
d7f3a1e900a30469268df8033b87b92d7e827e30Christian Maeder * types of failure, such as APR_ENOTDIR. We can do something
6a22b2854c3bc9cb4877cb7d29049d6559238639Christian Maeder * with APR_ENOENT, knowing that the path is good.
6a22b2854c3bc9cb4877cb7d29049d6559238639Christian Maeder if (!r->finfo.filetype || r->finfo.filetype == APR_LNK) {
6a22b2854c3bc9cb4877cb7d29049d6559238639Christian Maeder apr_stat(&r->finfo, r->filename, APR_FINFO_MIN, r->pool);
58b671de3fe578346fef9642ffa3c5a0a0edb3cbTill Mossakowski /* some OSs will return APR_SUCCESS/APR_REG if we stat
0e2ae85e2453466d03c1fc5884a3d693235bb9d9Christian Maeder * a regular file but we have '/' at the end of the name;
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * other OSs will return APR_ENOTDIR for that situation;
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * handle it the same everywhere by simulating a failure
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * if it looks like a directory but really isn't
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder r->filename[strlen(r->filename) - 1] == '/') {
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder r->finfo.filetype = 0; /* forget what we learned */
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder entry_dir = ap_make_dirstr_parent(r->pool, entry_dir);
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder else if (r->filename[strlen(r->filename) - 1] != '/') {
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder entry_dir = apr_pstrcat(r->pool, r->filename, "/", NULL);
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder /* If we have a file already matches the path of r->filename,
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * and the vhost's list of directory sections hasn't changed,
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * we can skip rewalking the directory_walk entries.
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder && (strcmp(entry_dir, cache->cached) == 0)) {
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder /* Well this looks really familiar! If our end-result (per_dir_result)
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * didn't change, we have absolutely nothing to do :)
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * Otherwise (as is the case with most dir_merged/file_merged requests)
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder * we must merge our dir_conf_merged onto this new r->per_dir_config.
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder if (r->per_dir_config == cache->per_dir_result) {
a0ac3ce207826aaccfdd220ac72cd49924660038Christian Maeder if (r->per_dir_config == cache->dir_conf_merged) {
int sec_idx;
char *save_path_info;
char *buf;
#ifdef CASE_BLIND_FILESYSTEM
r->path_info,
!= APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
#ifdef CASE_BLIND_FILESYSTEM
canonical_len = 0;
while (canonical_len
(const char **)&r->path_info,
r->pool);
(const char **)&r->path_info,
canonical_len = 0;
(const char **)&r->path_info,
0, r->pool);
return HTTP_INTERNAL_SERVER_ERROR;
sec_idx = 0;
int res;
char *seg_name;
char *delim;
int temp_slash=0;
if (matches) {
++last_walk;
--matches;
goto minimerge;
matches = 0;
if (now_merged) {
* See core.c::merge_core_dir_configs() for explanation.
if (!this_dir) {
if (res) {
return res;
if (htaccess_conf) {
if (matches) {
++last_walk;
--matches;
goto minimerge2;
matches = 0;
if (now_merged) {
* See core.c::merge_core_dir_configs() for explanation.
&core_module);
if (this_dir) {
if (temp_slash) {
if (delim) {
++seg_name;
if (!*seg_name) {
#ifdef CASE_BLIND_FILESYSTEM
++seg;
return res;
r->filename);
r->filename);
++seg;
if (save_path_info) {
if (!entry_core->r) {
if (matches) {
++last_walk;
--matches;
goto minimerge;
matches = 0;
if (now_merged) {
if (matches) {
x * APR_DIR test. But if you accessed /symlink/index.html, for example,
if (now_merged) {
r->per_dir_config,
return OK;
&core_module);
const char *entry_uri;
if (!num_sec) {
return OK;
/* Location and LocationMatch differ on their behaviour w.r.t. multiple
* Otherwise (as is the case with most dir_merged/file_merged requests)
return OK;
return OK;
if (entry_core->r
if (matches) {
++last_walk;
--matches;
matches = 0;
if (now_merged) {
if (matches) {
if (now_merged) {
r->per_dir_config,
return OK;
&core_module);
const char *test_file;
return OK;
if (!num_sec) {
return OK;
return OK;
return OK;
int sec_idx;
if (entry_core->r
if (matches) {
++last_walk;
--matches;
matches = 0;
if (now_merged) {
if (matches) {
if (now_merged) {
r->per_dir_config,
return OK;
if (next_filter) {
return rnew;
if (APR_BUCKET_IS_EOS(e)) {
return APR_SUCCESS;
if (!reqs_arr) {
const char *new_file,
const request_rec *r,
int res;
char *udir;
return rnew;
const request_rec *r,
const request_rec *r,
int subtype,
int res;
char *fdir;
char *udir;
!= OK) {
return rnew;
return rnew;
const request_rec *r,
int res;
char *fdir;
return rnew;
return rnew;
return retval;