[PATCH] (issue48) Fallback to HKEY_USERS on hive load failure

Wald Commits scm-commit at wald.intevation.org
Thu Jul 31 12:56:30 CEST 2014


# HG changeset patch
# User Andre Heinecke <andre.heinecke at intevation.de>
# Date 1406804186 -7200
# Node ID 797aa8d9c78531a3a38056ae5da32eb6ee15d751
# Parent  e4cf249ba1a65fecab65bb509ed806ed727322e7
(issue48) Fallback to HKEY_USERS on hive load failure

    If the hive can not be loaded it might mean that the user
    is currently logged on. In that case we can access his
    registry via HKEY_USERS.

diff -r e4cf249ba1a6 -r 797aa8d9c785 cinst/nssstore_win.c
--- a/cinst/nssstore_win.c	Wed Jul 30 18:47:39 2014 +0200
+++ b/cinst/nssstore_win.c	Thu Jul 31 12:56:26 2014 +0200
@@ -69,6 +69,34 @@
 
 /**@def The registry key to look for user profile directories */
 #define PROFILE_LIST L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
+#define RUNONCE_PATH L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"
+
+struct profile_key_path {
+  char *sid;
+  char *hive_path;
+  struct profile_key_path *next;
+};
+
+/**
+ * @brief combination of sid and hive path
+ */
+typedef struct profile_key_path pkp_t;
+
+static void
+pkp_t_free (pkp_t *item)
+{
+  if (!item)
+    {
+      return;
+    }
+  xfree (item->sid);
+  xfree (item->hive_path);
+  if (item->next)
+    {
+      pkp_t_free (item->next);
+    }
+  xfree (item);
+}
 
 /** @brief get a restricted access token to execute nss process
   *
@@ -174,17 +202,17 @@
 /**@brief Get the path to all users default registry hive
  *
  * Enumerates the keys in #PROFILE_LIST and retuns a
- * strv array with the utf-8 encoded paths to their suggested
- * registry hive location.
+ * list of their profile path / sid pairs with the utf-8 encoded paths to
+ * their suggestedregistry hive location.
  *
  * Users with an SID not starting with S-1-5-21- are ignored
  * as is the current user.
  *
- * Use strv_free to free that array.
+ * The return value should be freed with pkp_t_free
  *
  * @returns a newly allocated strv of the paths to the registry hives or NULL
  */
-static char**
+static pkp_t*
 locate_other_hives()
 {
   HKEY profile_list = NULL;
@@ -198,7 +226,8 @@
      the actual limit is 256 + \0 thus we create a buffer for 257 wchar_t's*/
   wchar_t key_name[257],
           *current_user_sid = NULL;
-  char **retval = NULL;
+  pkp_t *retval = NULL,
+        *cur_item = NULL;
   bool error = true;
   PSID current_user = NULL;
 
@@ -256,7 +285,7 @@
 
       wcscpy_s (key_path, key_path_len, PROFILE_LIST L"\\");
       wcscat_s (key_path, key_path_len, key_name);
-      key_path[key_len - 1] = '\0';
+      key_path[key_path_len - 1] = '\0';
 
       DEBUGPRINTF ("Key : %S", key_name);
       profile_path = read_registry_string (HKEY_LOCAL_MACHINE,
@@ -270,11 +299,21 @@
         }
       profile_path_len = strlen (profile_path);
       str_append_str (&profile_path, &profile_path_len, "\\ntuser.dat", 11);
+      if (retval == NULL)
+        {
+          retval = xmalloc (sizeof (pkp_t));
+          cur_item = retval;
+        }
+      else
+        {
+          cur_item->next = xmalloc (sizeof(pkp_t));
+          cur_item = cur_item->next;
+        }
+      cur_item->hive_path = profile_path;
+      cur_item->sid = wchar_to_utf8 (key_name, wcslen(key_name));
+      cur_item->next = NULL;
 
-      strv_append (&retval, profile_path, profile_path_len);
       DEBUGPRINTF ("Trying to access registry hive: %s", profile_path);
-
-      xfree (profile_path);
     }
 
   if (ret != ERROR_NO_MORE_ITEMS)
@@ -297,7 +336,7 @@
 
   if (error)
     {
-      strv_free (retval);
+      pkp_t_free (retval);
       retval = NULL;
     }
 
@@ -468,11 +507,11 @@
 static void
 register_proccesses_for_others (wchar_t *selection_file)
 {
-  char **hives = locate_other_hives();
-  int i = 0;
+  pkp_t *pkplist = locate_other_hives(),
+        *cur = NULL;
   wchar_t *run_command = NULL;
 
-  if (hives == NULL)
+  if (pkplist == NULL)
     {
       DEBUGPRINTF ("No hives found.");
       return;
@@ -485,11 +524,12 @@
     }
 
   run_command = get_command_line (selection_file);
-  for (i = 0; hives[i] != NULL; i++)
+  for (cur = pkplist; cur != NULL; cur = cur->next)
     {
       LONG ret = 0;
-      wchar_t *hivepath = utf8_to_wchar (hives[i], strlen(hives[i]));
+      wchar_t *hivepath = utf8_to_wchar (cur->hive_path, strlen(cur->hive_path));
       HKEY key_handle = NULL;
+      bool key_loaded = false;
 
       if (hivepath == NULL)
         {
@@ -504,23 +544,57 @@
       if (ret != ERROR_SUCCESS)
         {
           /* This is somewhat expected if the registry is not located
-             in the standard location. Failure is accepted in that case. */
+             in the standard location or already loaded. Try to access
+             the loaded registry in that case*/
+          wchar_t *user_key = NULL,
+                  *w_sid = NULL;
+          size_t user_key_len = 0;
+
           SetLastError((DWORD)ret);
-          PRINTLASTERROR ("Failed to load hive.");
-          continue;
+          PRINTLASTERROR ("Failed to load hive. Trying to access already loaded hive.");
+
+          w_sid = utf8_to_wchar (cur->sid, strlen(cur->sid));
+          if (!w_sid)
+            {
+              ERRORPRINTF ("Failed to read sid.");
+              continue;
+            }
+          user_key_len = wcslen (L"\\" RUNONCE_PATH) + wcslen(w_sid) + 1;
+          user_key = xmalloc (user_key_len * sizeof (wchar_t));
+          wcscpy_s (user_key, user_key_len, w_sid);
+          wcscat_s (user_key, user_key_len, L"\\" RUNONCE_PATH);
+          user_key[user_key_len - 1] = '\0';
+          xfree (w_sid);
+          w_sid = NULL;
+
+          ret = RegOpenKeyExW (HKEY_USERS,
+                               user_key,
+                               0,
+                               KEY_WRITE,
+                               &key_handle);
+          xfree (user_key);
+          if (ret != ERROR_SUCCESS)
+            {
+              ERRORPRINTF ("Failed to find RunOnce key for sid: %s in HKEY_USERS.", cur->sid);
+              continue;
+            }
         }
+      else
+        {
+          key_loaded = true;
+          ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
+                               APPNAME L"_tmphive\\" RUNONCE_PATH,
+                               0,
+                               KEY_WRITE,
+                               &key_handle);
 
-      ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
-                           APPNAME L"_tmphive\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
-                           0,
-                           KEY_WRITE,
-                           &key_handle);
+          if (ret != ERROR_SUCCESS)
+            {
+              ERRORPRINTF ("Failed to find RunOnce key in other registry.");
+              RegUnLoadKey (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive");
+              continue;
+            }
 
-      if (ret != ERROR_SUCCESS)
-        {
-          ERRORPRINTF ("Failed to find RunOnce key in other registry.");
-          RegUnLoadKey (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive");
-          continue;
         }
 
       ret = RegSetValueExW (key_handle, APPNAME, 0, REG_SZ, (LPBYTE) run_command,
@@ -532,16 +606,19 @@
         }
 
       RegCloseKey (key_handle);
-      ret = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive");
-      if (ret != ERROR_SUCCESS)
+      if (key_loaded)
         {
-          SetLastError ((DWORD)ret);
-          PRINTLASTERROR ("Failed to unload hive.");
+          ret = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive");
+          if (ret != ERROR_SUCCESS)
+            {
+              SetLastError ((DWORD)ret);
+              PRINTLASTERROR ("Failed to unload hive.");
+            }
         }
     }
 
   xfree (run_command);
-  strv_free (hives);
+  pkp_t_free (pkplist);
 }
 
 /**@brief Start the process to install / remove


More information about the Trustbridge-commits mailing list