# HG changeset patch # User Andre Heinecke # Date 1403878690 -7200 # Node ID f1795a232418691eed69f3c4a35cdd503b0688bf # Parent e8bc1215904eb9f8a8e6631d6eb5b4a803a88926 Implement reading registry entries for other users. diff -r e8bc1215904e -r f1795a232418 cinst/nssstore_win.c --- a/cinst/nssstore_win.c Fri Jun 27 11:51:53 2014 +0200 +++ b/cinst/nssstore_win.c Fri Jun 27 16:18:10 2014 +0200 @@ -139,6 +139,113 @@ return true; } +/**@brief Read (and expand if necessary) a registry string. + * + * Reads a registry string and calls ExpandEnvironmentString + * if necessary on it. Returns a newly allocated string array + * with the expanded registry value converted to UTF-8 + * + * Caller has to free return value with free. + * + * @param [in] root the root key (e.g. HKEY_LOCAL_MACHINE) + * @param [in] key the key + * @param [in] name the name of the value to read. + * + * @returns the expanded, null terminated utf-8 string of the value. + * or NULL on error. + */ +static char* +read_registry_string (const HKEY root, const wchar_t *key, + const wchar_t *name) +{ + HKEY key_handle = NULL; + DWORD size = 0, + type = 0, + ex_size = 0, + dwRet = 0; + LONG ret = 0; + char *retval = NULL; + wchar_t *buf = NULL, + *ex_buf = NULL; + if (root == NULL || key == NULL || name == NULL) + { + ERRORPRINTF ("Invalid call to read_registry_string"); + return NULL; + } + + ret = RegOpenKeyExW (root, key, 0, KEY_READ, &key_handle); + if (ret != ERROR_SUCCESS) + { + ERRORPRINTF ("Failed to open key."); + return NULL; + } + + /* Get the size */ + ret = RegQueryValueExW (key_handle, name, 0, NULL, NULL, &size); + if (ret != ERROR_MORE_DATA && !(ret == ERROR_SUCCESS && size != 0)) + { + ERRORPRINTF ("Failed to get required registry size."); + return retval; + } + + /* Size is size in bytes not in characters */ + buf = xmalloc (size + sizeof(wchar_t)); + + /* If the stored value is not zero terminated the returned value also + is not zero terminated. That's why we reserve more and ensure it's + initialized. */ + memset (buf, 0, size + sizeof(wchar_t)); + + ret = RegQueryValueExW (key_handle, name, 0, &type, (LPBYTE) buf, &size); + if (ret != ERROR_SUCCESS) + { + ERRORPRINTF ("Failed get registry value."); + return retval; + } + + if (type == REG_SZ || (type == REG_EXPAND_SZ && wcschr (buf, '%') == NULL)) + { + /* Nothing to expand, we are done */ + retval = wchar_to_utf8 (buf, wcslen (buf)); + goto done; + } + + if (type != REG_EXPAND_SZ) + { + ERRORPRINTF ("Unhandled registry type %i", type); + goto done; + } + + /* Expand the registry string */ + ex_size = ExpandEnvironmentStringsW (buf, NULL, 0); + + if (ex_size == 0) + { + PRINTLASTERROR ("Failed to determine expanded environment size."); + goto done; + } + + ex_buf = xmalloc ((ex_size + 1) * sizeof(wchar_t)); + + dwRet = ExpandEnvironmentStringsW (buf, ex_buf, ex_size); + + ex_buf[ex_size] = '\0'; /* Make sure it's a string */ + + if (dwRet == 0 || dwRet != ex_size) + { + PRINTLASTERROR ("Failed to expand environment variables."); + goto done; + } + + retval = wchar_to_utf8 (ex_buf, ex_size); + +done: + xfree (ex_buf); + xfree (buf); + + RegCloseKey (key_handle); + return retval; +} /**@brief Get the path to all users default registry hive * * Enumerates the keys in #PROFILE_LIST and retuns a @@ -152,7 +259,6 @@ * * @returns a newly allocated strv of the paths to the registry hives or NULL */ - static char** locate_other_hives() { @@ -198,6 +304,11 @@ key_name, &key_len, NULL, NULL, NULL, NULL)) == ERROR_SUCCESS) { + char *profile_path = NULL; + wchar_t *key_path = NULL; + size_t key_path_len = 0, + profile_path_len = 0; + if (key_len == 257) { ERRORPRINTF ("Registry key too long."); @@ -215,7 +326,30 @@ continue; } + key_path_len = key_len + wcslen(PROFILE_LIST L"\\") + 1; + key_path = xmalloc (key_path_len * sizeof (wchar_t)); + + 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'; + DEBUGPRINTF ("Key : %S", key_name); + profile_path = read_registry_string (HKEY_LOCAL_MACHINE, + key_path, L"ProfileImagePath"); + xfree (key_path); + + if (profile_path == NULL) + { + ERRORPRINTF ("Failed to get profile path."); + continue; + } + profile_path_len = strlen (profile_path); + str_append_str (&profile_path, &profile_path_len, "\\ntuser.dat", 11); + + 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)