From fd3e806b92842661bb1102f925803ffe2d754ffe Mon Sep 17 00:00:00 2001 From: "William A. Rowe Jr" Date: Tue, 20 Jun 2000 03:48:25 +0000 Subject: [PATCH] This patch solves several specific issues: 1.3.x truncated any open/command arguments following the %1 arg. so this patch adds the char** arguments to several functions 1.3.x did not expand environment strings (%userprofile% etc.) *) This patch may still not do so, if we are running with a subset of the 'normal' environment for security reasons. 1.3.x did not parse the extension itself (eg. the .pl key itself) for the command, failing the 'named' type (eg. perlscript), so this patch first tests the 'named' key, then the .ext key PR: Obtained from: Submitted by: Reviewed by: git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@85623 13f79535-47bb-0310-9956-ffa450edef68 --- include/http_core.h | 4 +- modules/generators/mod_cgi.c | 20 +++-- modules/http/http_core.c | 155 +++++++++++++++++++++++++---------- 3 files changed, 128 insertions(+), 51 deletions(-) diff --git a/include/http_core.h b/include/http_core.h index 481ff542b6..aa2852ecc8 100644 --- a/include/http_core.h +++ b/include/http_core.h @@ -164,7 +164,9 @@ typedef enum { eFileTypeUNKNOWN, eFileTypeBIN, eFileTypeEXE16, eFileTypeEXE32, eFileTypeSCRIPT } file_type_e; typedef enum { INTERPRETER_SOURCE_UNSET, INTERPRETER_SOURCE_REGISTRY, INTERPRETER_SOURCE_SHEBANG } interpreter_source_e; -API_EXPORT(file_type_e) ap_get_win32_interpreter(const request_rec *, char **); +API_EXPORT(file_type_e) ap_get_win32_interpreter(const request_rec *, + char **interpreter, + char **arguments); #endif #ifdef CORE_PRIVATE diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c index 3321d82d75..6df34af2f2 100644 --- a/modules/generators/mod_cgi.c +++ b/modules/generators/mod_cgi.c @@ -436,15 +436,16 @@ static ap_status_t build_argv_list(char ***argv, request_rec *r, ap_pool_t *p) return APR_SUCCESS; } -static ap_status_t build_command_line(char **c, request_rec *r, ap_pool_t *p) +static ap_status_t build_command_line(char **cmd, request_rec *r, ap_pool_t *p) { #ifdef WIN32 char *quoted_filename = NULL; char *interpreter = NULL; + char *arguments = NULL; file_type_e fileType; - *c = NULL; - fileType = ap_get_win32_interpreter(r, &interpreter); + *cmd = NULL; + fileType = ap_get_win32_interpreter(r, &interpreter, &arguments); if (fileType == eFileTypeUNKNOWN) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r, @@ -459,13 +460,20 @@ static ap_status_t build_command_line(char **c, request_rec *r, ap_pool_t *p) */ quoted_filename = ap_pstrcat(p, "\"", r->filename, "\"", NULL); if (interpreter && *interpreter) { - *c = ap_pstrcat(p, interpreter, " ", quoted_filename, " ", NULL); + if (arguments && *arguments) + *cmd = ap_pstrcat(p, interpreter, " ", quoted_filename, " ", + arguments, NULL); + else + *cmd = ap_pstrcat(p, interpreter, " ", quoted_filename, " ", NULL); + } + else if (arguments && *arguments) { + *cmd = ap_pstrcat(p, quoted_filename, " ", arguments, NULL); } else { - *c = ap_pstrcat(p, quoted_filename, " ", NULL); + *cmd = ap_pstrcat(p, quoted_filename, NULL); } #else - *c = ap_pstrcat(p, r->filename, NULL); + *cmd = ap_pstrcat(p, r->filename, NULL); #endif return APR_SUCCESS; } diff --git a/modules/http/http_core.c b/modules/http/http_core.c index 47f764008e..1d30c4491e 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -770,16 +770,62 @@ API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r) } #ifdef WIN32 -static char* get_interpreter_from_win32_registry(ap_pool_t *p, const char* ext) +static DWORD get_win32_registry_default_value(ap_pool_t *p, HKEY hkey, + char* relativepath, char **value) { - char extension_path[] = "SOFTWARE\\Classes\\"; - char executable_path[] = "\\SHELL\\OPEN\\COMMAND"; - HKEY hkeyOpen; DWORD type; + DWORD size = 0; + DWORD result = RegOpenKeyEx(hkey, relativepath, 0, + KEY_QUERY_VALUE, &hkeyOpen); + + if (result != ERROR_SUCCESS) + return result; + + /* Read to NULL buffer to determine value size */ + result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size); + + if (result == ERROR_SUCCESS) { + if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) { + result = ERROR_INVALID_PARAMETER; + } + else { + *value = ap_palloc(p, size); + /* Read value based on size query above */ + result = RegQueryValueEx(hkeyOpen, "", 0, &type, *value, &size); + } + } + + /* TODO: This might look fine, but we need to provide some warning + * somewhere that some environment variables may -not- be translated, + * seeing as we may have chopped the environment table down somewhat. + */ + if ((result == ERROR_SUCCESS) && (type == REG_EXPAND_SZ)) + { + char *tmp = *value; + size = ExpandEnvironmentStrings(tmp, *value, 0); + if (size) { + *value = ap_palloc(p, size); + size = ExpandEnvironmentStrings(tmp, *value, size); + } + } + + RegCloseKey(hkeyOpen); + return result; +} + +static char* get_interpreter_from_win32_registry(ap_pool_t *p, const char* ext, + char** arguments) +{ + char execcgi_path[] = "SHELL\\EXECCGI\\COMMAND"; + char execopen_path[] = "SHELL\\OPEN\\COMMAND"; + char typeName[MAX_PATH]; + int cmdOfName = FALSE; + HKEY hkeyName; + HKEY hkeyType; + DWORD type; int size; int result; - char *keyName; char *buffer; char *s; @@ -787,52 +833,50 @@ static char* get_interpreter_from_win32_registry(ap_pool_t *p, const char* ext) return NULL; /* * Future optimization: - * When the registry is successfully searched, store the interpreter - * string in a ap_table_t to make subsequent look-ups faster + * When the registry is successfully searched, store the strings for + * interpreter and arguments in an ext hash to speed up subsequent look-ups */ - /* Open the key associated with the script extension */ - keyName = ap_pstrcat(p, extension_path, ext, NULL); - - result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, - &hkeyOpen); + /* Open the key associated with the script filetype extension */ + result = RegOpenKeyEx(HKEY_CLASSES_ROOT, ext, 0, KEY_QUERY_VALUE, + &hkeyType); if (result != ERROR_SUCCESS) return NULL; - /* Read to NULL buffer to find value size */ - size = 0; - result = RegQueryValueEx(hkeyOpen, "", NULL, &type, NULL, &size); + /* Retrieve the name of the script filetype extension */ + size = sizeof(typeName); + result = RegQueryValueEx(hkeyType, "", NULL, &type, typeName, &size); + + if (result == ERROR_SUCCESS && type == REG_SZ && typeName[0]) { + /* Open the key associated with the script filetype extension */ + result = RegOpenKeyEx(HKEY_CLASSES_ROOT, typeName, 0, + KEY_QUERY_VALUE, &hkeyName); - if (result == ERROR_SUCCESS) { - buffer = ap_palloc(p, size); - result = RegQueryValueEx(hkeyOpen, "", NULL, &type, buffer, &size); + if (result == ERROR_SUCCESS) + cmdOfName = TRUE; } - RegCloseKey(hkeyOpen); - - if (result != ERROR_SUCCESS) - return NULL; - - /* Open the key associated with the interpreter path */ - keyName = ap_pstrcat(p, extension_path, buffer, executable_path, NULL); - - result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, - &hkeyOpen); - - if (result != ERROR_SUCCESS) - return NULL; - - /* Read to NULL buffer to find value size */ - size = 0; - result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size); + /* Open the key for the script command path by: + * + * 1) the 'named' filetype key for Open/Command + * 2) the extension's type key for Open/Command + */ + + if (cmdOfName) { + result = get_win32_registry_default_value(p, hkeyName, + execopen_path, &buffer); + } - if (result == ERROR_SUCCESS) { - buffer = ap_palloc(p, size); - result = RegQueryValueEx(hkeyOpen, "", 0, &type, buffer, &size); + if (result != ERROR_SUCCESS) { + result = get_win32_registry_default_value(p, hkeyType, + execopen_path, &buffer); } - RegCloseKey(hkeyOpen); + if (cmdOfName) + RegCloseKey(hkeyName); + + RegCloseKey(hkeyType); if (result != ERROR_SUCCESS) return NULL; @@ -840,7 +884,7 @@ static char* get_interpreter_from_win32_registry(ap_pool_t *p, const char* ext) /* * The canonical way shell command entries are entered in the Win32 * registry is as follows: - * shell [options] "%1" + * shell [options] "%1" [args] * where * shell - full path name to interpreter or shell to run. * E.g., c:\usr\local\ntreskit\perl\bin\perl.exe @@ -848,21 +892,34 @@ static char* get_interpreter_from_win32_registry(ap_pool_t *p, const char* ext) * E.g., \C * "%1" - Place holder for file to run the shell against. * Typically quoted. + * options - additional arguments + * E.g., /silent * * If we find a %1 or a quoted %1, lop it off. */ if (buffer && *buffer) { if ((s = strstr(buffer, "\"%1"))) + { *s = '\0'; + *arguments = s + 4; + } else if ((s = strstr(buffer, "%1"))) + { *s = '\0'; + *arguments = buffer + 2; + } + else + *arguments = strchr(buffer, '\0'); + while (**arguments && isspace(**arguments)) + ++*arguments; } return buffer; } API_EXPORT (file_type_e) ap_get_win32_interpreter(const request_rec *r, - char** interpreter ) + char** interpreter, + char** arguments) { HANDLE hFile; DWORD nBytesRead; @@ -890,8 +947,17 @@ API_EXPORT (file_type_e) ap_get_win32_interpreter(const request_rec *r, } ext = strrchr(exename, '.'); - if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) { - return eFileTypeEXE32; + if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) + { + char *comspec = getenv("COMSPEC"); + if (comspec) { + *interpreter = ap_pstrcat(r->pool, "\"", comspec, "\" /c ", NULL); + return eFileTypeSCRIPT; + } + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r->server, + "Failed to start a '%s' file as a script.\n\t" + "COMSPEC variable is missing from the environment.", ext); + return eFileTypeUNKNOWN; } /* If the file has an extension and it is not .com and not .exe and @@ -900,7 +966,8 @@ API_EXPORT (file_type_e) ap_get_win32_interpreter(const request_rec *r, if (ext && strcasecmp(ext,".exe") && strcasecmp(ext,".com") && d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY) { /* Check the registry */ - *interpreter = get_interpreter_from_win32_registry(r->pool, ext); + *interpreter = get_interpreter_from_win32_registry(r->pool, ext, + arguments); if (*interpreter) return eFileTypeSCRIPT; else { -- 2.40.0