diff -r a94cf2e94492 -r 38bf6dd8f4e7 src/server/safs/cgiutils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/server/safs/cgiutils.c Wed Oct 26 15:53:56 2016 +0200 @@ -0,0 +1,379 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// code from open webserver +// safs/cgi.cpp + +#include "cgiutils.h" + +#include +#include + +#include "../util/util.h" +#include "../util/pblock.h" + + +//----------------------------------------------------------------------------- +// Macros +//----------------------------------------------------------------------------- + +#define CGI_VERSION "CGI/1.1" + +// CGI env sizing +#define MAX_CGI_COMMON_VARS 23 +#define MAX_CGI_SPECIFIC_VARS 10 +#define MAX_CGI_CLIENT_AUTH_VARS 64 + +//----------------------------------------------------------------------------- +// cgi_parse_query +//----------------------------------------------------------------------------- + +int cgi_parse_query(char **argv, int n, char *q) +{ + int i = 0; + + for (;;) { + // Parse an arg from the query string + char *arg = q; + while (*q != ' ' && *q != '\0') + q++; + + // Caller must ensure argv[] is appropriately sized + WS_ASSERT(i < n); + if (i >= n) + return -1; + + // Escape any shell characters (does a MALLOC on our behalf) + char c = *q; + *q = '\0'; + argv[i] = util_sh_escape(arg); // TODO + *q = c; + + // Unescape this arg, bailing on error + if (!argv[i] || !util_uri_unescape_strict(argv[i])) + return -1; + + // We successfully parsed another arg + i++; + + // We're done when we hit the end of the query string + if (*q == '\0') + break; + + q++; + } + + return i; +} + +//----------------------------------------------------------------------------- +// cgi_create_argv +//----------------------------------------------------------------------------- + +char **cgi_create_argv(const char *program, const char *script, const char *query) +{ + int nargs = 1; + + // The script name, if any, will be argv[1] + if (script) + nargs++; + + // Turn '+' into ' ' in query string, counting the number of arg as we go + char *qargs = NULL; + if (query && !strchr(query, '=')) { + qargs = STRDUP(query); + if (!qargs) + return NULL; + nargs++; + for (char *t = qargs; *t; t++) { + if (*t == '+') + *t = ' '; + if (*t == ' ') + nargs++; + } + } + + // Allocate the argv[] array, leaving room for the trailing NULL + char **argv = (char **) MALLOC((nargs + 1) * sizeof(char *)); + if (!argv) + return NULL; + + int i = 0; + + // Set argv[0] to the program name + argv[i] = STRDUP(program); + i++; + + // Set argv[1] to the script name + if (script) { + argv[i] = STRDUP(script); + i++; + } + + // Parse the query string into argv[] + if (qargs) { + int n = cgi_parse_query(&argv[i], nargs - i, qargs); + if (n > 0) + i += n; + } + + // Mark end of argv[] + argv[i] = NULL; + + return argv; +} + +//---------------------------------------------------------------------------- +// cgi_get_request_uri +//---------------------------------------------------------------------------- + +char* cgi_get_request_uri(Request *req) +{ + // Extract the encoded URI from the request line if possible + char *clf_request = pblock_findkeyval(pb_key_clf_request, req->reqpb); + if (clf_request) { + // Find the beginning of the method + char *method = clf_request; + while (*method && isspace(*method)) + method++; + + // Skip over the method + char *uri = method; + while (*uri && !isspace(*uri)) + uri++; + + // Find the beginning of the URI + while (*uri && isspace(*uri)) + uri++; + + // Find the end of the URI + char *end = uri; + while (*end && !isspace(*end)) + end++; + + // Make a copy of the uri + int len = end - uri; + char* request_uri = (char*) MALLOC(len+1); + memcpy(request_uri, uri, len); + request_uri[len] = '\0'; + + return request_uri; + } + + // No request line. + return NULL; +} + +//----------------------------------------------------------------------------- +// cgi_specific_vars +//----------------------------------------------------------------------------- + +char** cgi_specific_vars(Session *sn, Request *rq, const char *args, + char** env, int scriptVars) +{ + int y; + register pblock *pb; + char c, *t, *u; + + pb = rq->reqpb; + + int x; + env = util_env_create(env, MAX_CGI_SPECIFIC_VARS, &x); + env[x++] = util_env_str("GATEWAY_INTERFACE", CGI_VERSION); + + // Added error check for missing request information. + t = pblock_findval("protocol", pb); + if (t == NULL) { + log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"protocol\" in rq->reqpb"); + return NULL; + } + env[x++] = util_env_str("SERVER_PROTOCOL", t); + + t = pblock_findval("method", pb); + if (t == NULL) { + log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"request method\" in rq->reqpb"); + return NULL; + } + env[x++] = util_env_str("REQUEST_METHOD", t); + + if (args) + env[x++] = util_env_str("QUERY_STRING", args); + + // set REQUEST_URI + if (rq->orig_rq) { + t = cgi_get_request_uri(rq->orig_rq); + } else { + t = cgi_get_request_uri(rq); + } + if (t) { + env[x++] = util_env_str("REQUEST_URI", t); + FREE(t); + } + + if (scriptVars) { + t = pblock_findval("uri", pb); + + /* Simulate CGI URIs by truncating path info */ + if ((u = pblock_findval("path-info", rq->vars))) { + y = strlen(t) - strlen(u); + if (y >= 0) { + c = t[y]; + t[y] = '\0'; + } + env[x++] = util_env_str("SCRIPT_NAME", t); + if (y >= 0) { + t[y] = c; + } + + env[x++] = util_env_str("PATH_INFO", u); + + // TODO + /* + if((t = INTservact_translate_uri2(u, sn, rq))) { + env[x++] = util_env_str("PATH_TRANSLATED", t); + // keep path-translated in rq->vars since we may need it + // during fastcgi processing + pblock_nvinsert("path-translated", t, rq->vars); + FREE(t); + } + */ + } else { + env[x++] = util_env_str("SCRIPT_NAME", t); + } + + if (t = pblock_findval("path", rq->vars)) + env[x++] = util_env_str("SCRIPT_FILENAME", t); + } + + env[x] = NULL; + return env; +} + +//----------------------------------------------------------------------------- +// cgi_common_vars +//----------------------------------------------------------------------------- + +char** cgi_common_vars(Session *sn, Request *rq, char **env) +{ + // TODO: enable code and add cgi_client_auth_vars() + return env; +#if 0 + char *t; + int x; + + env = util_env_create(env, MAX_CGI_COMMON_VARS, &x); + + if (!_env_initialized) cgi_env_init(); + if (_env_path) env[x++] = util_env_str("PATH", _env_path); + if (_env_tz) env[x++] = util_env_str("TZ", _env_tz); + if (_env_lang) env[x++] = util_env_str("LANG", _env_lang); + if (_env_ldpath) env[x++] = util_env_str(LIBRARY_PATH, _env_ldpath); + env[x++] = util_env_str("SERVER_SOFTWARE", PRODUCT_HEADER_ID"/"PRODUCT_VERSION_ID); + + NSString srvName, portStr; + char buf1[256], buf2[64]; + srvName.useStatic(buf1, sizeof(buf1), 0); + portStr.useStatic(buf2, sizeof(buf2), 0); + GetServerHostnameAndPort(*rq, *sn, srvName, portStr); + env[x++] = util_env_str("SERVER_PORT", (char*)(const char*)portStr); + env[x++] = util_env_str("SERVER_NAME", (char*)(const char*)srvName); + + t = http_uri2url_dynamic("","",sn,rq); + env[x++] = util_env_str("SERVER_URL", t); + FREE(t); + + char *ip; + ip = pblock_findval("ip", sn->client); + t = session_dns(sn); + env[x++] = util_env_str("REMOTE_HOST", (t ? t : ip)); + env[x++] = util_env_str("REMOTE_ADDR", ip); + + if((t = pblock_findval("auth-user", rq->vars))) { + env[x++] = util_env_str("REMOTE_USER", t); + if((t = pblock_findval("auth-type", rq->vars))) { + env[x++] = util_env_str("AUTH_TYPE", t); + } + if((t = pblock_findval("auth-userdn", rq->vars))) { + env[x++] = util_env_str("REMOTE_USERDN", t); + } + } + if((t = pblock_findval("password-policy", rq->vars))) { + /* chrisk made up this variable name */ + env[x++] = util_env_str("PASSWORD_POLICY", t); + } + + // Handle Apache ErrorDocument-style variables from the send-error SAF + if (rq->orig_rq != rq) { + if (t = pblock_findval("uri", rq->orig_rq->reqpb)) { + env[x++] = util_env_str("REDIRECT_URL", t); + } + if (t = pblock_findval("status", rq->orig_rq->srvhdrs)) { + env[x++] = util_env_str("REDIRECT_STATUS", t); + } + } + + if (GetSecurity(sn)) { + env[x++] = util_env_str("HTTPS", "ON"); + + if (t = pblock_findval("keysize", sn->client)) + env[x++] = util_env_str("HTTPS_KEYSIZE", t); + + if (t = pblock_findval("secret-keysize", sn->client)) + env[x++] = util_env_str("HTTPS_SECRETKEYSIZE", t); + + t = pblock_findval("ssl-id", sn->client); + env[x++] = util_env_str("HTTPS_SESSIONID", t ? t : (char *)""); + + unsigned char random_bytes[NUM_RANDOM_BYTES + 2]; + char random_string[NUM_RANDOM_BYTES*2 + 2]; + PK11_GenerateRandom(random_bytes, NUM_RANDOM_BYTES); + + int i; + for(i = 0; i < NUM_RANDOM_BYTES; i++) { + sprintf(&random_string[i*2], "%02x", + (unsigned int)(random_bytes[i] & 0xff)); + } + random_string[NUM_RANDOM_BYTES*2] = '\0'; + env[x++] = util_env_str("HTTPS_RANDOM", random_string); + + } else { + env[x++] = util_env_str("HTTPS", "OFF"); + } + + env[x] = NULL; + + env = cgi_client_auth_vars(sn, rq, env); + + return env; +#endif +}