[PATCH v2 2/2] kernel32: Properly expand environment variables in PEB block

Fabian Maurer dark.shadow4 at web.de
Sat May 11 07:17:41 CDT 2019


Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
v2: Rebased
---
 dlls/kernel32/process.c | 68 +++++++++++++++++++++++++++++++----------
 dlls/ntdll/tests/env.c  |  1 -
 2 files changed, 52 insertions(+), 17 deletions(-)

diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index 200ea8bc97..fc42fb15e9 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -62,6 +62,7 @@
 #include "wine/server.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
+#include "wine/list.h"

 WINE_DEFAULT_DEBUG_CHANNEL(process);
 WINE_DECLARE_DEBUG_CHANNEL(relay);
@@ -502,6 +503,14 @@ static BOOL build_initial_environment(void)
     return TRUE;
 }

+struct environment_variable
+{
+    struct list entry;
+    UNICODE_STRING name;
+    UNICODE_STRING value;
+    ULONG type;
+};
+

 /***********************************************************************
  *           set_registry_variables
@@ -510,7 +519,7 @@ static BOOL build_initial_environment(void)
  * helper for set_registry_environment().
  * Note that Windows happily truncates the value if it's too big.
  */
-static void set_registry_variables( HANDLE hkey, ULONG type )
+static void set_registry_variables( HANDLE hkey )
 {
     static const WCHAR pathW[] = {'P','A','T','H'};
     static const WCHAR sep[] = {';',0};
@@ -522,6 +531,11 @@ static void set_registry_variables( HANDLE hkey, ULONG type )
     WCHAR tmpbuf[1024];
     UNICODE_STRING tmp;
     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
+    struct list registry_variables = LIST_INIT(registry_variables);
+    struct environment_variable *variable, *variable_next;
+    PWSTR penv = NULL;
+
+    RtlCreateEnvironment(FALSE, &penv);

     tmp.Buffer = tmpbuf;
     tmp.MaximumLength = sizeof(tmpbuf);
@@ -532,8 +546,10 @@ static void set_registry_variables( HANDLE hkey, ULONG type )
                                       buffer, sizeof(buffer), &size );
         if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW)
             break;
-        if (info->Type != type)
+        if (info->Type != REG_SZ && info->Type != REG_EXPAND_SZ)
             continue;
+
+        variable = malloc(sizeof(struct environment_variable));
         env_name.Buffer = info->Name;
         env_name.Length = env_name.MaximumLength = info->NameLength;
         env_value.Buffer = (WCHAR *)(buffer + info->DataOffset);
@@ -542,12 +558,6 @@ static void set_registry_variables( HANDLE hkey, ULONG type )
         if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1])
             env_value.Length -= sizeof(WCHAR);  /* don't count terminating null if any */
         if (!env_value.Length) continue;
-        if (info->Type == REG_EXPAND_SZ)
-        {
-            status = RtlExpandEnvironmentStrings_U( NULL, &env_value, &tmp, NULL );
-            if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue;
-            RtlCopyUnicodeString( &env_value, &tmp );
-        }
         /* PATH is magic */
         if (env_name.Length == sizeof(pathW) &&
             !strncmpiW( env_name.Buffer, pathW, ARRAY_SIZE( pathW )) &&
@@ -557,8 +567,37 @@ static void set_registry_variables( HANDLE hkey, ULONG type )
             if (RtlAppendUnicodeStringToString( &tmp, &env_value )) continue;
             RtlCopyUnicodeString( &env_value, &tmp );
         }
-        RtlSetEnvironmentVariable( NULL, &env_name, &env_value );
+
+        RtlDuplicateUnicodeString(0, &env_name, &variable->name);
+        RtlDuplicateUnicodeString(0, &env_value, &variable->value);
+        variable->type = info->Type;
+        list_add_head(&registry_variables, &variable->entry);
+        RtlSetEnvironmentVariable(&penv, &env_name, &env_value);
     }
+
+    LIST_FOR_EACH_ENTRY_SAFE(variable, variable_next, &registry_variables, struct environment_variable, entry)
+    {
+        if (variable->type == REG_EXPAND_SZ)
+        {
+            /* Expand values found inside outside environment */
+            status = RtlExpandEnvironmentStrings_U(NULL, &variable->value, &tmp, NULL);
+            if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue;
+            RtlCopyUnicodeString(&variable->value, &tmp);
+
+            /* Expand values found inside the registry environment we're currently adding */
+            status = RtlExpandEnvironmentStrings_U(penv, &variable->value, &tmp, NULL);
+            if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue;
+            RtlCopyUnicodeString(&variable->value, &tmp);
+        }
+
+        RtlSetEnvironmentVariable(NULL, &variable->name, &variable->value);
+
+        RtlFreeUnicodeString(&variable->name);
+        RtlFreeUnicodeString(&variable->value);
+        free(variable);
+    }
+
+    RtlDestroyEnvironment(penv);
 }


@@ -572,7 +611,7 @@ static void set_registry_variables( HANDLE hkey, ULONG type )
  * on the order in which the variables are processed. But on Windows it
  * does not really matter since they only use %SystemDrive% and
  * %SystemRoot% which are predefined. But Wine defines these in the
- * registry, so we need two passes.
+ * registry, so we need two passes inside set_registry_variables
  */
 static BOOL set_registry_environment( BOOL volatile_only )
 {
@@ -602,8 +641,7 @@ static BOOL set_registry_environment( BOOL volatile_only )
     RtlInitUnicodeString( &nameW, env_keyW );
     if (!volatile_only && NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS)
     {
-        set_registry_variables( hkey, REG_SZ );
-        set_registry_variables( hkey, REG_EXPAND_SZ );
+        set_registry_variables( hkey );
         NtClose( hkey );
         ret = TRUE;
     }
@@ -613,16 +651,14 @@ static BOOL set_registry_environment( BOOL volatile_only )
     RtlInitUnicodeString( &nameW, envW );
     if (!volatile_only && NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS)
     {
-        set_registry_variables( hkey, REG_SZ );
-        set_registry_variables( hkey, REG_EXPAND_SZ );
+        set_registry_variables( hkey );
         NtClose( hkey );
     }

     RtlInitUnicodeString( &nameW, volatile_envW );
     if (NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS)
     {
-        set_registry_variables( hkey, REG_SZ );
-        set_registry_variables( hkey, REG_EXPAND_SZ );
+        set_registry_variables( hkey );
         NtClose( hkey );
     }

diff --git a/dlls/ntdll/tests/env.c b/dlls/ntdll/tests/env.c
index 41cb44ecd2..e295fb97b2 100644
--- a/dlls/ntdll/tests/env.c
+++ b/dlls/ntdll/tests/env.c
@@ -558,7 +558,6 @@ static void test_peb_environment(void)
             if (lstrcmpW(env, result2) == 0)
                 found2 = TRUE;
         }
-        todo_wine
         ok(found1, "Didn't find %s in the PEB environment variables\n", wine_dbgstr_w(result1));
         ok(found2, "Didn't find %s in the PEB environment variables\n", wine_dbgstr_w(result2));
     }
--
2.21.0




More information about the wine-devel mailing list