From: Gibson Pilconis gibsonpil@protonmail.com
--- dlls/ntdll/unix/env.c | 167 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+)
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c index ad9ab0dc220..0bc663bf80f 100644 --- a/dlls/ntdll/unix/env.c +++ b/dlls/ntdll/unix/env.c @@ -25,6 +25,7 @@
#include "config.h"
+#include <strings.h> #include <assert.h> #include <errno.h> #include <locale.h> @@ -1916,6 +1917,171 @@ static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module ) } }
+/************************************************************************* + * is_parseautoexec_enabled + * + * Checks if ParseAutoexec is enabled in the registry. + */ +static BOOL is_parseautoexec_enabled(void) { + BOOL result = FALSE; + NTSTATUS ns; + HANDLE winlogon_key = NULL; + WCHAR parseautoexec_nameW[] = {'P','a','r','s','e','A','u','t','o','e','x','e','c',0}; + WCHAR parseautoexec_on[] = {'1',0}; + UNICODE_STRING parseautoexec_name; + KEY_VALUE_PARTIAL_INFORMATION *parseautoexec = NULL; + DWORD parseautoexec_size; + WCHAR* parseautoexec_value; + + ns = open_hkcu_key("Software\Microsoft\Windows NT\CurrentVersion\Winlogon", &winlogon_key); + if(FAILED(ns)) { + ERR("couldn't get Winlogon key from the registry.\n"); + goto end; + } + + init_unicode_string(&parseautoexec_name, parseautoexec_nameW); + ns = NtQueryValueKey(winlogon_key, &parseautoexec_name, KeyValuePartialInformation, NULL, 0, &parseautoexec_size); + if(ns != STATUS_BUFFER_TOO_SMALL && ns != STATUS_BUFFER_OVERFLOW && ns != STATUS_SUCCESS) { + ERR("failed to get ParseAutoexec size. maybe it doesn't exist?\n"); + goto end; + } + + parseautoexec = (KEY_VALUE_PARTIAL_INFORMATION*)malloc(parseautoexec_size); + ns = NtQueryValueKey(winlogon_key, &parseautoexec_name, KeyValuePartialInformation, parseautoexec, parseautoexec_size, &parseautoexec_size); + if(ns) { + ERR("failed to get ParseAutoexec value.\n"); + goto end; + } + parseautoexec_value = (WCHAR*)(parseautoexec->Data); + + /* Check if Autoexec parsing is on. */ + if(ntdll_wcsicmp(parseautoexec_value, parseautoexec_on) != 0) { + result = TRUE; + } + +end: + if(winlogon_key) NtClose(winlogon_key); + if(parseautoexec) free(parseautoexec); + return result; +} + +/************************************************************************* + * parse_autoexec + * + * Parses and adds environment variables defined in AUTOEXEC.bat. + */ +static BOOL parse_autoexec( WCHAR **env, SIZE_T *pos, SIZE_T *size ) { + NTSTATUS ns; + BOOL result = FALSE; + + /* File IO variables. */ + LARGE_INTEGER autoexec_offset = {0}; + WCHAR autoexec_pathW[] = {'\','?','?','\','C',':','\','a','u','t','o','e','x','e','c','.','b','a','t',0}; + UNICODE_STRING autoexec_path; + HANDLE autoexec = NULL; + OBJECT_ATTRIBUTES autoexec_attributes; + IO_STATUS_BLOCK isb; + FILE_STANDARD_INFORMATION autoexec_info = {0}; + char* autoexec_buffer = NULL; + int autoexec_buffer_length; + + /* Parsing variables. */ + char variable_name[256] = {0}; + char variable_text[32768] = {0}; + BOOL first_run = TRUE; + BOOL skip = FALSE; + BOOL after_equals = FALSE; + + init_unicode_string(&autoexec_path, autoexec_pathW); + InitializeObjectAttributes(&autoexec_attributes, &autoexec_path, 0, NULL, NULL); + ns = NtOpenFile(&autoexec, GENERIC_READ, &autoexec_attributes, &isb, NULL, FILE_SYNCHRONOUS_IO_NONALERT); + if(ns) { + if(ns == STATUS_NO_SUCH_FILE) { + /* The user simply doesn't have an autoexec. */ + result = TRUE; + goto end; + } + ERR("unable to open autoexec.bat.\n"); + goto end; + } + + ns = NtQueryInformationFile(autoexec, &isb, &autoexec_info, sizeof(autoexec_info), FileStandardInformation); + if(ns) { + ERR("unable to query autoexec.bat information.\n"); + goto end; + } + autoexec_buffer_length = autoexec_info.EndOfFile.QuadPart + 1; + + autoexec_buffer = (char*)malloc(autoexec_buffer_length); + ns = NtReadFile(autoexec, NULL, NULL, NULL, &isb, autoexec_buffer, autoexec_buffer_length, &autoexec_offset, NULL); + if(ns) { + ERR("unable to read autoexec.bat.\n"); + goto end; + } + + /* Through testing I found that when parsing autoexec files, modern version of + Windows only look at environment variable declarations (i.e. "SET <var>=") and + plain path declarations (i.e. "Path=C:"). No commands are actually run. */ + for(char* i = autoexec_buffer; *i != '\0'; i++) { + /* Check for delimiters. */ + if(*i == '\n' || *i == '\r' || *i == '&' || first_run == TRUE) { + if(!first_run) { + /* Save last variable. */ + /* TODO: Add variable concat code! */ + i++; /* Move past delimiter */ + } + + *variable_name = 0; + *variable_text = 0; + + /* Hop whitespaces. */ + while(*i == ' ') i++; + + /* Reset state. */ + first_run = FALSE; + after_equals = FALSE; + skip = FALSE; + + if(strncasecmp(i, "SET", 3) == 0) { /* SET directive. */ + i += 3; /* Skip directive. */ + continue; + } else if(strncasecmp(i, "Path", 4) == 0) { /* Path directive. */ + after_equals = TRUE; + strcpy(variable_name, "PATH"); + i += 4; /* Skip Path directive. */ + continue; + } else { + skip = TRUE; + continue; + } + } else if(skip) { + continue; + } else if(*i == '=') { + after_equals = TRUE; + continue; + } + + /* Bounds checking. */ + if(strlen(variable_name) >= 255 || strlen(variable_text) >= 32767) { + ERR("buffer filled up while parsing autoexec.bat.\n"); + goto end; + } + + /* Add text to buffers. */ + if(after_equals) { + strncat(variable_text, i, 1); + } else { + strncat(variable_name, i, 1); + } + } + + result = TRUE; + +end: + if(autoexec) NtClose(autoexec); + if(autoexec_buffer) free(autoexec_buffer); + return result; +}
/************************************************************************* * build_initial_params @@ -1950,6 +2116,7 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params( void **module ) is_prefix_bootstrap = !!bootstrap; free( bootstrap ); add_registry_environment( &env, &env_pos, &env_size ); + if(is_parseautoexec_enabled()) parse_autoexec( &env, &env_pos, &env_size ); env[env_pos++] = 0;
status = load_main_exe( NULL, main_argv[1], curdir, 0, &image, module );