mod_netware.c revision 9e5410cf4f579668d32359a1ef7658a7866cf4d5
252N/A/* ====================================================================
252N/A * The Apache Software License, Version 1.1
252N/A *
252N/A * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
252N/A * reserved.
252N/A *
252N/A * Redistribution and use in source and binary forms, with or without
252N/A * modification, are permitted provided that the following conditions
252N/A * are met:
252N/A *
252N/A * 1. Redistributions of source code must retain the above copyright
252N/A * notice, this list of conditions and the following disclaimer.
252N/A *
252N/A * 2. Redistributions in binary form must reproduce the above copyright
252N/A * notice, this list of conditions and the following disclaimer in
252N/A * the documentation and/or other materials provided with the
252N/A * distribution.
252N/A *
252N/A * 3. The end-user documentation included with the redistribution,
252N/A * if any, must include the following acknowledgment:
252N/A * "This product includes software developed by the
252N/A * Apache Software Foundation (http://www.apache.org/)."
252N/A * Alternately, this acknowledgment may appear in the software itself,
252N/A * if and wherever such third-party acknowledgments normally appear.
252N/A *
252N/A * 4. The names "Apache" and "Apache Software Foundation" must
252N/A * not be used to endorse or promote products derived from this
252N/A * software without prior written permission. For written
252N/A * permission, please contact apache@apache.org.
252N/A *
252N/A * 5. Products derived from this software may not be called "Apache",
252N/A * nor may "Apache" appear in their name, without prior written
252N/A * permission of the Apache Software Foundation.
252N/A *
252N/A * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
252N/A * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
252N/A * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
252N/A * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
252N/A * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
252N/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
252N/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
252N/A * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
252N/A * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
252N/A * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
252N/A * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252N/A * SUCH DAMAGE.
252N/A * ====================================================================
252N/A *
252N/A * This software consists of voluntary contributions made by many
252N/A * individuals on behalf of the Apache Software Foundation. For more
252N/A * information on the Apache Software Foundation, please see
252N/A * <http://www.apache.org/>.
252N/A *
252N/A * Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#include "apr_strings.h"
#include "apr_portable.h"
#include "apr_buckets.h"
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_request.h"
#include "http_log.h"
#include "util_script.h"
#include "mod_core.h"
#include "apr_optional.h"
#include "apr_lib.h"
#ifdef NETWARE
module AP_MODULE_DECLARE_DATA netware_module;
typedef struct {
apr_table_t *file_type_handlers; /* CGI map from file types to CGI modules */
apr_table_t *extra_env_vars; /* Environment variables to be added to the CGI environment */
} netware_dir_config;
static void *create_netware_dir_config(apr_pool_t *p, char *dir)
{
netware_dir_config *new = (netware_dir_config*) apr_palloc(p, sizeof(netware_dir_config));
new->file_type_handlers = apr_table_make(p, 10);
new->extra_env_vars = apr_table_make(p, 10);
return new;
}
static void *merge_netware_dir_configs(apr_pool_t *p, void *basev, void *addv)
{
netware_dir_config *base = (netware_dir_config *) basev;
netware_dir_config *add = (netware_dir_config *) addv;
netware_dir_config *new = (netware_dir_config *) apr_palloc(p, sizeof(netware_dir_config));
new->file_type_handlers = apr_table_overlay(p, add->file_type_handlers, base->file_type_handlers);
new->extra_env_vars = apr_table_overlay(p, add->extra_env_vars, base->extra_env_vars);
return new;
}
static const char *set_extension_map(cmd_parms *cmd, netware_dir_config *m, char *CGIhdlr, char *ext)
{
if (*ext == '.')
++ext;
apr_table_set(m->file_type_handlers, ext, CGIhdlr);
return NULL;
}
static apr_array_header_t *split_argv(apr_pool_t *p, const char *interp,
const char *cgiprg, const char *cgiargs)
{
apr_array_header_t *args = apr_array_make(p, 8, sizeof(char*));
char *d = apr_palloc(p, strlen(interp)+1);
const char *ch = interp;
const char **arg;
int prgtaken = 0;
int argtaken = 0;
int inquo;
int sl;
while (*ch) {
/* Skip on through Deep Space */
if (isspace(*ch)) {
++ch; continue;
}
/* One Arg */
if (((*ch == '$') || (*ch == '%')) && (*(ch + 1) == '*')) {
const char *cgiarg = cgiargs;
argtaken = 1;
for (;;) {
char *w = ap_getword_nulls(p, &cgiarg, '+');
if (!*w) {
break;
}
ap_unescape_url(w);
arg = (const char**)apr_array_push(args);
*arg = ap_escape_shell_cmd(p, w);
}
ch += 2;
continue;
}
if (((*ch == '$') || (*ch == '%')) && (*(ch + 1) == '1')) {
/* Todo: Make short name!!! */
prgtaken = 1;
arg = (const char**)apr_array_push(args);
if (*ch == '%') {
char *repl = apr_pstrdup(p, cgiprg);
*arg = repl;
while ((repl = strchr(repl, '/'))) {
*repl++ = '\\';
}
}
else {
*arg = cgiprg;
}
ch += 2;
continue;
}
if ((*ch == '\"') && ((*(ch + 1) == '$')
|| (*(ch + 1) == '%')) && (*(ch + 2) == '1')
&& (*(ch + 3) == '\"')) {
prgtaken = 1;
arg = (const char**)apr_array_push(args);
if (*(ch + 1) == '%') {
char *repl = apr_pstrdup(p, cgiprg);
*arg = repl;
while ((repl = strchr(repl, '/'))) {
*repl++ = '\\';
}
}
else {
*arg = cgiprg;
}
ch += 4;
continue;
}
arg = (const char**)apr_array_push(args);
*arg = d;
inquo = 0;
while (*ch) {
if (isspace(*ch) && !inquo) {
++ch; break;
}
/* Get 'em backslashes */
for (sl = 0; *ch == '\\'; ++sl) {
*d++ = *ch++;
}
if (sl & 1) {
/* last unmatched '\' + '"' sequence is a '"' */
if (*ch == '\"') {
*(d - 1) = *ch++;
}
continue;
}
if (*ch == '\"') {
/* '""' sequence within quotes is a '"' */
if (*++ch == '\"' && inquo) {
*d++ = *ch++; continue;
}
/* Flip quote state */
inquo = !inquo;
if (isspace(*ch) && !inquo) {
++ch; break;
}
/* All other '"'s are Munched */
continue;
}
/* Anything else is, well, something else */
*d++ = *ch++;
}
/* Term that arg, already pushed on args */
*d++ = '\0';
}
if (!prgtaken) {
arg = (const char**)apr_array_push(args);
*arg = cgiprg;
}
if (!argtaken) {
const char *cgiarg = cgiargs;
for (;;) {
char *w = ap_getword_nulls(p, &cgiarg, '+');
if (!*w) {
break;
}
ap_unescape_url(w);
arg = (const char**)apr_array_push(args);
*arg = ap_escape_shell_cmd(p, w);
}
}
arg = (const char**)apr_array_push(args);
*arg = NULL;
return args;
}
static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
request_rec *r, apr_pool_t *p,
int process_cgi, apr_cmdtype_e *type)
{
const char *ext = NULL;
const char *interpreter = NULL;
netware_dir_config *d;
apr_file_t *fh;
const char *args = "";
d = (netware_dir_config *)ap_get_module_config(r->per_dir_config,
&netware_module);
if (process_cgi) {
/* Handle the complete file name, we DON'T want to follow suexec, since
* an unrooted command is as predictable as shooting craps in Win32.
*
* Notice that unlike most mime extension parsing, we have to use the
* win32 parsing here, therefore the final extension is the only one
* we will consider
*/
*cmd = r->filename;
if (r->args && r->args[0] && !ap_strchr_c(r->args, '=')) {
args = r->args;
}
}
ext = strrchr(apr_filename_of_pathname(*cmd), '.');
if (*ext == '.')
++ext;
/* If it is an NLM then just execute it. */
if (stricmp(ext, "nlm")) {
*cmd = apr_table_get(d->file_type_handlers, ext);
if (*cmd == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"Could not find a command associated with the %s extension", ext);
return APR_EBADF;
}
}
apr_tokenize_to_argv(r->filename, (char***)argv, p);
*type = APR_PROGRAM;
// /* If the file has an extension and it is not .com and not .exe and
// * we've been instructed to search the registry, then do so.
// * Let apr_proc_create do all of the .bat/.cmd dirty work.
// */
// if (ext && (!strcasecmp(ext,".exe") || !strcasecmp(ext,".com")
// || !strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) {
// interpreter = "";
// }
// if (!interpreter && ext
// && (d->script_interpreter_source
// == INTERPRETER_SOURCE_REGISTRY
// || d->script_interpreter_source
// == INTERPRETER_SOURCE_REGISTRY_STRICT)) {
// /* Check the registry */
// int strict = (d->script_interpreter_source
// == INTERPRETER_SOURCE_REGISTRY_STRICT);
// interpreter = get_interpreter_from_win32_registry(r->pool, ext,
// strict);
// if (interpreter && *type != APR_SHELLCMD) {
// *type = APR_PROGRAM_PATH;
// }
// else {
// ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
// strict ? "No ExecCGI verb found for files of type '%s'."
// : "No ExecCGI or Open verb found for files of type '%s'.",
// ext);
// }
// }
// if (!interpreter) {
// apr_status_t rv;
// char buffer[1024];
// apr_size_t bytes = sizeof(buffer);
// int i;
//
// /* Need to peek into the file figure out what it really is...
// * ### aught to go back and build a cache for this one of these days.
// */
// if (((rv = apr_file_open(&fh, *cmd, APR_READ | APR_BUFFERED,
// APR_OS_DEFAULT, r->pool)) != APR_SUCCESS)
// || ((rv = apr_file_read(fh, buffer, &bytes)) != APR_SUCCESS)) {
// ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
// "Failed to read cgi file %s for testing", *cmd);
// return rv;
// }
// apr_file_close(fh);
//
// /* Script or executable, that is the question... */
// if ((buffer[0] == '#') && (buffer[1] == '!')) {
// /* Assuming file is a script since it starts with a shebang */
// for (i = 2; i < sizeof(buffer); i++) {
// if ((buffer[i] == '\r') || (buffer[i] == '\n')) {
// buffer[i] = '\0';
// break;
// }
// }
// if (i < sizeof(buffer)) {
// interpreter = buffer + 2;
// while (isspace(*interpreter)) {
// ++interpreter;
// }
// if (*type != APR_SHELLCMD) {
// *type = APR_PROGRAM_PATH;
// }
// }
// }
// else {
// /* Not a script, is it an executable? */
// IMAGE_DOS_HEADER *hdr = (IMAGE_DOS_HEADER*)buffer;
// if ((bytes >= sizeof(IMAGE_DOS_HEADER))
// && (hdr->e_magic == IMAGE_DOS_SIGNATURE)) {
// if (hdr->e_lfarlc < 0x40) {
// /* Ought to invoke this 16 bit exe by a stub, (cmd /c?) */
// interpreter = "";
// }
// else {
// interpreter = "";
// }
// }
// }
// }
// if (!interpreter) {
// ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
// "%s is not executable; ensure interpreted scripts have "
// "\"#!\" first line", *cmd);
// return APR_EBADF;
// }
//
// *argv = (const char **)(split_argv(p, interpreter, *cmd,
// args)->elts);
// *cmd = (*argv)[0];
return APR_SUCCESS;
}
APR_DECLARE_OPTIONAL_FN(apr_status_t, ap_cgi_build_command,
(const char **cmd, const char ***argv,
request_rec *r, apr_pool_t *p,
int replace_cmd, apr_cmdtype_e *type));
static void register_hooks(apr_pool_t *p)
{
APR_REGISTER_OPTIONAL_FN(ap_cgi_build_command);
}
static const command_rec netware_cmds[] = {
AP_INIT_ITERATE2("CGIMapExtension", set_extension_map, NULL, OR_FILEINFO,
"full path to the CGI NLM module followed by one or more file extensions"),
{ NULL }
};
module AP_MODULE_DECLARE_DATA netware_module = {
STANDARD20_MODULE_STUFF,
create_netware_dir_config, /* create per-dir config */
merge_netware_dir_configs, /* merge per-dir config */
NULL, /* server config */
NULL, /* merge server config */
netware_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
#endif