changeset 856:797aa8d9c785

(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.
author Andre Heinecke <andre.heinecke@intevation.de>
date Thu, 31 Jul 2014 12:56:26 +0200
parents e4cf249ba1a6
children 9bab4fc3a1fe
files cinst/nssstore_win.c
diffstat 1 files changed, 111 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- 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. */
-          SetLastError((DWORD)ret);
-          PRINTLASTERROR ("Failed to load hive.");
-          continue;
-        }
+             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;
 
-      ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
-                           APPNAME L"_tmphive\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
-                           0,
-                           KEY_WRITE,
-                           &key_handle);
+          SetLastError((DWORD)ret);
+          PRINTLASTERROR ("Failed to load hive. Trying to access already loaded hive.");
 
-      if (ret != ERROR_SUCCESS)
+          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
         {
-          ERRORPRINTF ("Failed to find RunOnce key in other registry.");
-          RegUnLoadKey (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive");
-          continue;
+          key_loaded = true;
+          ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE,
+                               APPNAME L"_tmphive\\" RUNONCE_PATH,
+                               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;
+            }
+
         }
 
       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

http://wald.intevation.org/projects/trustbridge/