util_script.c revision 070d2f9fd52a3f0e45ca7ae1235c5a5755b80d24
6de8046f8f7e07cd83895a528df25d977e502c76nd/* ====================================================================
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * The Apache Software License, Version 1.1
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * reserved.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Redistribution and use in source and binary forms, with or without
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * modification, are permitted provided that the following conditions
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * are met:
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * 1. Redistributions of source code must retain the above copyright
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * notice, this list of conditions and the following disclaimer.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 2. Redistributions in binary form must reproduce the above copyright
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * notice, this list of conditions and the following disclaimer in
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * the documentation and/or other materials provided with the
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * distribution.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 3. The end-user documentation included with the redistribution,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * if any, must include the following acknowledgment:
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * "This product includes software developed by the
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Apache Software Foundation (http://www.apache.org/)."
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * Alternately, this acknowledgment may appear in the software itself,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * if and wherever such third-party acknowledgments normally appear.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 4. The names "Apache" and "Apache Software Foundation" must
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * not be used to endorse or promote products derived from this
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * software without prior written permission. For written
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * permission, please contact apache@apache.org.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * 5. Products derived from this software may not be called "Apache",
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * nor may "Apache" appear in their name, without prior written
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * permission of the Apache Software Foundation.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
f888346b48f5e5b5e3f0a47dedb8cefd2759a4e2gregames * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * SUCH DAMAGE.
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * ====================================================================
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * This software consists of voluntary contributions made by many
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * individuals on behalf of the Apache Software Foundation. For more
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * information on the Apache Software Foundation, please see
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * Portions of this software are based upon public domain software
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * originally written at the National Center for Supercomputing Applications,
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * University of Illinois, Urbana-Champaign.
4f9c22c4f27571d54197be9674e1fc0d528192aestriker#include "apr_date.h" /* For apr_date_parse_http() */
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe * Various utility functions which are common to a whole lot of
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * script-type extensions mechanisms, and might as well be gathered
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe * in one place (if only to avoid creating inter-module dependancies
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * where there don't have to be).
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe#define MALFORMED_MESSAGE "malformed header from script. Bad header="
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe while (*++cp) {
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantzAP_DECLARE(char **) ap_create_environment(apr_pool_t *p, apr_table_t *t)
8419e6f8bff1a3617933f3ba760d2bdec7442f44coar apr_table_entry_t *elts = (apr_table_entry_t *) env_arr->elts;
8419e6f8bff1a3617933f3ba760d2bdec7442f44coar char **env = (char **) apr_palloc(p, (env_arr->nelts + 2) * sizeof(char *));
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe env[j] = apr_pstrcat(p, elts[i].key, "=", elts[i].val, NULL);
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe const char *rem_logname;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe const char *host;
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe /* use a temporary apr_table_t which we'll overlap onto
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * r->subprocess_env later
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe /* First, add environment vars from headers... this is as per
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * CGI specs, though other sorts of scripting interfaces see
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * the same vars...
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe /* A few headers are special cased --- Authorization to prevent
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * rogue scripts from capturing passwords; content-type and -length
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * for no particular reason.
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz * You really don't want to disable this check, since it leaves you
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe * wide open to CGIs stealing passwords and people viewing them
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * in the environment with "ps -e". But, if you must...
d4abb06ac220bb280ae996b6d21bbd257db51bb1jerenkrantz || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) {
fa06de8a28a737e8fbaad76d7f3ff67aaa5e4a09wrowe apr_table_addn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker apr_table_addn(e, "PATH", apr_pstrdup(r->pool, env_path));
83a8dc5a596a8a1b9d14f063268287d123b9ed7ewrowe apr_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r));
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_table_addn(e, "SERVER_SOFTWARE", ap_get_server_version());
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_table_addn(e, "SERVER_NAME", ap_get_server_name(r));
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_table_addn(e, "SERVER_ADDR", r->connection->local_ip); /* Apache */
4f9c22c4f27571d54197be9674e1fc0d528192aestriker host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL);
0540a0b469147b52e858587270dba31c2aaa9e09wrowe apr_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r)); /* Apache */
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_table_addn(e, "SERVER_ADMIN", s->server_admin); /* Apache */
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_table_addn(e, "SCRIPT_FILENAME", r->filename); /* Apache */
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_socket_addr_get(&remotesa, APR_REMOTE, c->client_socket);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker apr_table_addn(e, "REMOTE_PORT", apr_psprintf(r->pool, "%d", rport));
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp apr_table_addn(e, "REMOTE_IDENT", apr_pstrdup(r->pool, rem_logname));
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe /* Apache custom error responses. If we have redirected set two new vars */
cc9582e53aead2a044077c4a92f3dfc3605590b3wrowe apr_table_addn(e, "REDIRECT_QUERY_STRING", r->prev->args);
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianp apr_table_overlap(r->subprocess_env, e, APR_OVERLAP_TABLES_SET);
4f9c22c4f27571d54197be9674e1fc0d528192aestriker/* This "cute" little function comes about because the path info on
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * filenames and URLs aren't always the same. So we take the two,
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * and find as much of the two that match as possible.
a2b181763cb35fd899feb4a436aeadaa80bf91eabrianpAP_DECLARE(int) ap_find_path_info(const char *uri, const char *path_info)
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb/* Obtain the Request-URI from the original request-line, returning
b38846b15c8891c6dec44dcc4f96ca40721bf663rbb * a new string from the request pool containing the URI or "".
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar apr_table_setn(e, "QUERY_STRING", r->args ? r->args : "");
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz /* Note that the code below special-cases scripts run from includes,
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz * because it "knows" that the sub_request has been hacked to have the
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * args and path_info of the original request, and not any that may have
659ad814f714e556bdd03e1d771cba156baab92ewrowe * come with the script URI in the include command. Ugh.
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe int path_info_start = ap_find_path_info(r->uri, r->path_info);
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * To get PATH_TRANSLATED, treat PATH_INFO as a URI path.
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe * Need to re-escape it for this, since the entire URI was
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar * un-escaped before we determined where the PATH_INFO began.
4f9c22c4f27571d54197be9674e1fc0d528192aestriker pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r,
1fbf6ba0f5207e6637b49f9a9dfcc779bbe952a9trawick char *pt = apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info,
290ecc1ddceca1ed49bc1a5338921264b5c3e07cwrowe /* We need to make this a real Windows path name */
7c301a1818939f85da8f3629cc3e9b5588610ef0jerenkrantz apr_table_setn(e, "PATH_TRANSLATED", apr_pstrdup(r->pool, buffer));
700b96db75e7cfadb5219978c1735b710d583763wrowestatic int set_cookie_doo_doo(void *v, const char *key, const char *val)
700b96db75e7cfadb5219978c1735b710d583763wroweAP_DECLARE(int) ap_scan_script_header_err_core(request_rec *r, char *buffer,
700b96db75e7cfadb5219978c1735b710d583763wrowe int (*getsfunc) (char *, int, void *),
700b96db75e7cfadb5219978c1735b710d583763wrowe char *w, *l;
700b96db75e7cfadb5219978c1735b710d583763wrowe /* temporary place to hold headers to merge in later */
700b96db75e7cfadb5219978c1735b710d583763wrowe /* The HTTP specification says that it is legal to merge duplicate
700b96db75e7cfadb5219978c1735b710d583763wrowe * headers into one. Some browsers that support Cookies don't like
700b96db75e7cfadb5219978c1735b710d583763wrowe * merged headers and prefer that each Set-Cookie header is sent
700b96db75e7cfadb5219978c1735b710d583763wrowe * separately. Lets humour those browsers by not merging.
700b96db75e7cfadb5219978c1735b710d583763wrowe * Oh what a pain it is.
700b96db75e7cfadb5219978c1735b710d583763wrowe apr_table_do(set_cookie_doo_doo, cookie_table, r->err_headers_out, "Set-Cookie", NULL);
700b96db75e7cfadb5219978c1735b710d583763wrowe while (1) {
700b96db75e7cfadb5219978c1735b710d583763wrowe if ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data) == 0) {
700b96db75e7cfadb5219978c1735b710d583763wrowe ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
103a93c625bcde1a6a7a5155b64dcda36f612180pquerna /* Delete terminal (CR?)LF */
700b96db75e7cfadb5219978c1735b710d583763wrowe /* Indeed, the host's '\n':
700b96db75e7cfadb5219978c1735b710d583763wrowe '\012' for UNIX; '\015' for MacOS; '\025' for OS/390
700b96db75e7cfadb5219978c1735b710d583763wrowe -- whatever the script generates.
8aefbd756763807188d2e3ce336a8680e4893066wrowe * If we've finished reading the headers, check to make sure any
8aefbd756763807188d2e3ce336a8680e4893066wrowe * HTTP/1.1 conditions are met. If so, we're done; normal processing
8aefbd756763807188d2e3ce336a8680e4893066wrowe * will handle the script's output. If not, just return the error.
8aefbd756763807188d2e3ce336a8680e4893066wrowe * The appropriate thing to do would be to send the script process a
a2a0abd88b19e042a3eb2a9fa1702c25ad51303dwrowe * SIGPIPE to let it know we're ignoring it, close the channel to the
8aefbd756763807188d2e3ce336a8680e4893066wrowe * script process, and *then* return the failed-to-meet-condition
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe * error. Otherwise we'd be waiting for the script to finish
8aefbd756763807188d2e3ce336a8680e4893066wrowe * blithering before telling the client the output was no good.
8aefbd756763807188d2e3ce336a8680e4893066wrowe * However, we don't have the information to do that, so we have to
2fa5b5878e7567e2875807c3e2a2b3b0d3ef74bewrowe * leave it to an upper layer.
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe if (w[0] == '\0') {
8aefbd756763807188d2e3ce336a8680e4893066wrowe if ((cgi_status == HTTP_OK) && (r->method_number == M_GET)) {
4f9c22c4f27571d54197be9674e1fc0d528192aestriker /* the cookies have already been copied to the cookie_table */
8aefbd756763807188d2e3ce336a8680e4893066wrowe /* if we see a bogus header don't ignore it. Shout and scream */
cf6ef072483172309861d06e85b1aeff4573c060wrowe /* Chances are that we received an ASCII header text instead of
cf6ef072483172309861d06e85b1aeff4573c060wrowe * the expected EBCDIC header lines. Try to auto-detect:
a8d11d78181478da6a672f7fbc58b8d523351f49wrowe native = apr_xlate_conv_byte(ap_hdrs_from_ascii, *cp);
8aefbd756763807188d2e3ce336a8680e4893066wrowe ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r->server,
cf6ef072483172309861d06e85b1aeff4573c060wrowe "CGI Interface Error: Script headers apparently ASCII: (CGI = %s)",
cf6ef072483172309861d06e85b1aeff4573c060wrowe#endif /*APR_CHARSET_EBCDIC*/
cf6ef072483172309861d06e85b1aeff4573c060wrowe strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW);
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick /* Soak up all the script output - may save an outright kill */
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) {
d75626f0952c6152a99acd013a4f127d46f0f9edtrawick ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
ecde48c75338ff5712f2036711f813c6dedca28ewrowe *l++ = '\0';
ecde48c75338ff5712f2036711f813c6dedca28ewrowe while (*l && apr_isspace(*l)) {
731344ed8f3677d1661c261ca5fcdd2ee3dbc74ccoar /* Nuke trailing whitespace */
23c6309e36a63b13b61c35999c978017521993d6wrowe * If the script returned a specific status, that's what
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * we'll use - otherwise we assume 200 OK.
a9a4544168a37b43bd180b3703ccee995f27a80awrowe * If the script gave us a Last-Modified header, we can't just
4f9c22c4f27571d54197be9674e1fc0d528192aestriker * pass it on blindly because of restrictions on future values.
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe return apr_file_gets(buf, len, (apr_file_t *) f) == APR_SUCCESS;
0e58e92812f2f679d6bf2ff66cbcfa6c1d1e14bbjerenkrantzAP_DECLARE(int) ap_scan_script_header_err(request_rec *r, apr_file_t *f,
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe return ap_scan_script_header_err_core(r, buffer, getsfunc_FILE, f);
e4a3f3c2f080cac75a15a6454cca429b8161c050wrowe const char *curpos;
8aefbd756763807188d2e3ce336a8680e4893066wrowestatic int getsfunc_STRING(char *w, int len, void *pvastrs)
700b96db75e7cfadb5219978c1735b710d583763wrowe const char *p;
4f9c22c4f27571d54197be9674e1fc0d528192aestriker w[t] = '\0';
4f9c22c4f27571d54197be9674e1fc0d528192aestriker/* ap_scan_script_header_err_strs() accepts additional const char* args...
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * each is treated as one or more header lines, and the first non-header
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * character is returned to **arg, **data. (The first optional arg is
1b315ee865b0f11e582beb64127ca3a99a319d2fwrowe * counted as 0.)
1b315ee865b0f11e582beb64127ca3a99a319d2fwroweAP_DECLARE_NONSTD(int) ap_scan_script_header_err_strs(request_rec *r,
cf6ef072483172309861d06e85b1aeff4573c060wrowe const char **termch,