request.c revision 58097d7d8d1a394092374b9f6ddf76b7993724a4
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder/* ====================================================================
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The Apache Software License, Version 1.1
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Redistribution and use in source and binary forms, with or without
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * modification, are permitted provided that the following conditions
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * 1. Redistributions of source code must retain the above copyright
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * notice, this list of conditions and the following disclaimer.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * 2. Redistributions in binary form must reproduce the above copyright
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * notice, this list of conditions and the following disclaimer in
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * the documentation and/or other materials provided with the
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * distribution.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * 3. The end-user documentation included with the redistribution,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * if any, must include the following acknowledgment:
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * "This product includes software developed by the
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Apache Software Foundation (http://www.apache.org/)."
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Alternately, this acknowledgment may appear in the software itself,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * if and wherever such third-party acknowledgments normally appear.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * 4. The names "Apache" and "Apache Software Foundation" must
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * not be used to endorse or promote products derived from this
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * software without prior written permission. For written
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * permission, please contact apache@apache.org.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * 5. Products derived from this software may not be called "Apache",
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder * nor may "Apache" appear in their name, without prior written
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder * permission of the Apache Software Foundation.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
162a689da386fc8ddbbe47bcae83eaca4fc8dbc0Christian Maeder * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * SUCH DAMAGE.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * ====================================================================
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * This software consists of voluntary contributions made by many
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * individuals on behalf of the Apache Software Foundation. For more
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * information on the Apache Software Foundation, please see
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Portions of this software are based upon public domain software
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * originally written at the National Center for Supercomputing Applications,
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * University of Illinois, Urbana-Champaign.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * http_request.c: functions to get and process requests
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Rob McCool 3/21/93
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Thoroughly revamped by rst for Apache. NB this file reads
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * best from the bottom up.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,map_to_storage,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,check_user_id,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,type_checker,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_ALL(int,access_checker,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_FIRST(int,auth_checker,
af1cb109bce240bcafe3823df022d6088cbfc438Christian MaederAP_IMPLEMENT_HOOK_VOID(insert_filter, (request_rec *r), (r))
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_IMPLEMENT_HOOK_RUN_ALL(int,create_request,(request_rec *r),(r),OK,DECLINED)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederstatic int decl_die(int status, char *phase, request_rec *r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_CRIT, 0, r,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder "configuration error: couldn't %s: %s", phase, r->uri);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* This is the master logic for processing requests. Do NOT duplicate
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * this logic elsewhere, or the security model will be broken by future
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * API changes. Each phase must be individually optimized to pick up
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * redundant/duplicate calls by subrequests, and redirects.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAP_DECLARE(int) ap_process_request_internal(request_rec *r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder /* Ignore embedded %2F's in path for proxy requests */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder access_status = ap_unescape_url(r->parsed_uri.path);
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder ap_getparents(r->uri); /* OK --- shrinking transformations... */
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder if ((access_status = ap_location_walk(r))) {
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder if ((access_status = ap_run_translate_name(r))) {
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder return decl_die(access_status, "translate", r);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if ((access_status = ap_run_map_to_storage(r))) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder /* This request wasn't in storage (e.g. TRACE) */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if ((access_status = ap_location_walk(r))) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder /* Only on the main request! */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if ((access_status = ap_run_header_parser(r))) {
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder if ((access_status = ap_run_access_checker(r)) != 0) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder return decl_die(access_status, "check access", r);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) {
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder return decl_die(access_status, ap_auth_type(r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder ? "check user. No user file?"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder : "perform authentication. AuthType not set!", r);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder return decl_die(access_status, ap_auth_type(r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder ? "check access. No groups file?"
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder : "perform authentication. AuthType not set!", r);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if (((access_status = ap_run_access_checker(r)) != 0) || !ap_auth_type(r)) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder return decl_die(access_status, ap_auth_type(r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder ? "check access"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder : "perform authentication. AuthType not set!", r);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if (((access_status = ap_run_check_user_id(r)) != 0) || !ap_auth_type(r)) {
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder return decl_die(access_status, ap_auth_type(r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder ? "check user. No user file?"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder : "perform authentication. AuthType not set!", r);
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if (((access_status = ap_run_auth_checker(r)) != 0) || !ap_auth_type(r)) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder return decl_die(access_status, ap_auth_type(r)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder ? "check access. No groups file?"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder : "perform authentication. AuthType not set!", r);
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder /* XXX Must make certain the ap_run_type_checker short circuits mime
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * in mod-proxy for r->proxyreq && r->parsed_uri.scheme
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder * && !strcmp(r->parsed_uri.scheme, "http")
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if ((access_status = ap_run_type_checker(r)) != 0) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder return decl_die(access_status, "find types", r);
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder if ((access_status = ap_run_fixups(r)) != 0) {
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder /* The new insert_filter stage makes sense here IMHO. We are sure that
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * we are going to run the request now, so we may as well insert filters
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * if any are available. Since the goal of this phase is to allow all
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * modules to insert a filter if they want to, this filter returns
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * void. I just can't see any way that this filter can reasonably
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * fail, either your modules inserts something or it doesn't. rbb
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/*****************************************************************
162a689da386fc8ddbbe47bcae83eaca4fc8dbc0Christian Maeder * Getting and checking directory configuration. Also checks the
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * FollowSymlinks and FollowSymOwner stuff, since this is really the
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * only place that can happen (barring a new mid_dir_walk callout).
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * We can't do it as an access_checker module function which gets
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * called with the final per_dir_config, since we could have a directory
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * with FollowSymLinks disabled, which contains a symlink to another
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * with a .htaccess file which turns FollowSymLinks back on --- and
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * access in such a case must be denied. So, whatever it is that
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * checks FollowSymLinks needs to know the state of the options as
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * they change, all the way down.
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder * We don't want people able to serve up pipes, or unix sockets, or other
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * scary things. Note that symlink tests are performed later.
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder if (r->finfo.filetype == 0 /* doesn't exist */
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder "object is not a file, directory or symlink: %s",
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * resolve_symlink must _always_ be called on an APR_LNK file type!
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * It will resolve the actual target file type, modification date, etc,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * and provide any processing required for symlink evaluation.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Path must already be cleaned, no trailing slash, no multi-slashes,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * and don't call this on the root!
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Simply, the number of times we deref a symlink are minimal compared
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * to the number of times we had an extra lstat() since we 'weren't sure'.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * To optimize, we stat() anything when given (opts & OPT_SYM_LINKS), otherwise
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * we start off with an lstat(). Every lstat() must be dereferenced in case
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * it points at a 'nasty' - we must always rerun check_safe_file (or similar.)
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maederstatic int resolve_symlink(char *d, apr_finfo_t *lfi, int opts, apr_pool_t *p)
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder if (!(opts & (OPT_SYM_OWNER | OPT_SYM_LINKS)))
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder if ((res = apr_stat(&fi, d, lfi->valid, p)) != APR_SUCCESS)
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder /* OPT_SYM_OWNER only works if we can get the owner of
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * both the file and symlink. First fill in a missing
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * owner of the symlink, then get the info of the target.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder if ((res = apr_lstat(&fi, d, lfi->valid | APR_FINFO_OWNER, p))
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder if ((res = apr_stat(&fi, d, lfi->valid, p)) != APR_SUCCESS)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder if (apr_compare_users(fi.user, lfi->user) != APR_SUCCESS)
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder /* Give back the target */
return OK;
#ifndef REPLACE_PATH_INFO_METHOD
#if defined(OS2)
return OK;
char *lastp;
int res;
return OK;
if (lastp == d)
if (lastp)
return OK;
return HTTP_FORBIDDEN;
return HTTP_FORBIDDEN;
return HTTP_FORBIDDEN;
char *cp;
int rv;
return OK;
#ifdef HAVE_DRIVE_LETTERS
bStripSlash = 0;
#ifdef HAVE_UNC_PATHS
int iCount=0;
p = path;
iCount++;
bStripSlash = 0;
if (bStripSlash)
return OK;
--cp;
return HTTP_FORBIDDEN;
return OK;
&core_module);
char *test_filename;
char *test_dirname;
int res;
unsigned i, num_dirs;
int j, test_filename_len;
return HTTP_INTERNAL_SERVER_ERROR;
return res;
#ifdef NO_LONGER_PARANOID
return HTTP_FORBIDDEN;
r->filename);
return HTTP_FORBIDDEN;
return res;
--num_dirs;
++num_dirs;
#if defined(HAVE_UNC_PATHS)
#if defined(NETWARE)
int overrides_here;
&core_module);
return res;
* from access.conf.
for (; j < num_sec; ++j) {
char *entry_dir;
if (this_conf) {
&core_module);
if (res)
return res;
if (htaccess_conf) {
for (; j < num_sec; ++j) {
if (!entry_core->r) {
* APR_DIR test. But if you accessed /symlink/index.html, for example,
return res;
&core_module);
int sec_idx;
int res;
char *seg_name;
char *delim;
return HTTP_INTERNAL_SERVER_ERROR;
== APR_SUCCESS) {
char *buf;
return HTTP_INTERNAL_SERVER_ERROR;
sec_idx = 0;
int overrides_here;
&core_module);
const char *entry_dir;
&core_module);
if (overrides_here) {
if (res)
return res;
if (htaccess_conf) {
if (delim) {
++seg_name;
if (!*seg_name)
return res;
r->filename);
++seg;
if (!entry_core->r) {
x * APR_DIR test. But if you accessed /symlink/index.html, for example,
typedef struct walk_walked_t {
typedef struct walk_cache_t {
} walk_cache_t;
&core_module);
const char *entry_uri;
int len, j;
if (!r->per_dir_config)
if (!num_loc) {
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;
for (j = 0; j < num_loc; ++j) {
if (entry_core->r
if (matches) {
++last_walk;
--matches;
matches = 0;
if (now_merged)
locations[j]);
if (matches)
if (now_merged)
r->per_dir_config,
return OK;
&core_module);
char *test_file;
++test_file;
if (num_files) {
char *entry_file;
for (j = 0; j < num_files; ++j) {
if (entry_core->r) {
if (this_conf)
return OK;
return rr;
if (next_filter) {
if (APR_BUCKET_IS_EOS(e)) {
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 res;
char *fdir;
char *udir;
return rnew;
return rnew;
return rnew;
return rnew;
const request_rec *r,
int res;
char *fdir;
return rnew;
return rnew;
return rnew;
return rnew;
r->filename);
if (!res) {
return rnew;
int retval;
return retval;