summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2014-12-02 10:49:47 +0000
committerCorinna Vinschen <corinna@vinschen.de>2014-12-02 10:49:47 +0000
commit41f77e25f11d2b152d2f4da12d1e6378c64fc78e (patch)
treebd51f7bf99de9278c427694a609c2a9e45cf3faa
parent195a9205e5c8d6ddded25c7dca736105ed9a1e86 (diff)
downloadcygnal-41f77e25f11d2b152d2f4da12d1e6378c64fc78e.tar.gz
cygnal-41f77e25f11d2b152d2f4da12d1e6378c64fc78e.tar.bz2
cygnal-41f77e25f11d2b152d2f4da12d1e6378c64fc78e.zip
* autoload.cc (CreateProfile): Import.
(LoadUserProfileW): Import. * registry.cc (get_registry_hive_path): Move to sec_auth.cc. (load_registry_hive): Remove. * registry.h (get_registry_hive_path): Drop declaration. (load_registry_hive): Ditto. * sec_auth.cc (get_user_profile_directory): Moved from registry.cc and renamed. Take third parameter with buffer length. (load_user_profile): New function taking over for load_registry_hive. Use official functions to load profile. If profile is missing, create it on Vista and later. * security.h (get_user_profile_directory): Declare. (load_user_profile): Declare. * syscalls.cc (seteuid32): Replace call to load_registry_hive with call to load_user_profile. * uinfo.cc (cygheap_user::env_userprofile): Replace call to get_registry_hive_path with call to get_user_profile_directory.
-rw-r--r--winsup/cygwin/ChangeLog20
-rw-r--r--winsup/cygwin/autoload.cc2
-rw-r--r--winsup/cygwin/registry.cc96
-rw-r--r--winsup/cygwin/registry.h6
-rw-r--r--winsup/cygwin/sec_auth.cc110
-rw-r--r--winsup/cygwin/security.h6
-rw-r--r--winsup/cygwin/syscalls.cc6
-rw-r--r--winsup/cygwin/uinfo.cc8
8 files changed, 145 insertions, 109 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 960d1ce03..7d4e03e2a 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,25 @@
2014-12-02 Corinna Vinschen <corinna@vinschen.de>
+ * autoload.cc (CreateProfile): Import.
+ (LoadUserProfileW): Import.
+ * registry.cc (get_registry_hive_path): Move to sec_auth.cc.
+ (load_registry_hive): Remove.
+ * registry.h (get_registry_hive_path): Drop declaration.
+ (load_registry_hive): Ditto.
+ * sec_auth.cc (get_user_profile_directory): Moved from registry.cc and
+ renamed. Take third parameter with buffer length.
+ (load_user_profile): New function taking over for load_registry_hive.
+ Use official functions to load profile. If profile is missing, create
+ it on Vista and later.
+ * security.h (get_user_profile_directory): Declare.
+ (load_user_profile): Declare.
+ * syscalls.cc (seteuid32): Replace call to load_registry_hive with call
+ to load_user_profile.
+ * uinfo.cc (cygheap_user::env_userprofile): Replace call to
+ get_registry_hive_path with call to get_user_profile_directory.
+
+2014-12-02 Corinna Vinschen <corinna@vinschen.de>
+
* uinfo.cc (fetch_from_description): Make static.
(fetch_from_path): Ditto.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 7859725ff..ce5d32834 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -676,7 +676,9 @@ LoadDLLfunc (SetProcessWindowStation, 4, user32)
LoadDLLfunc (SetThreadDesktop, 4, user32)
LoadDLLfunc (CreateEnvironmentBlock, 12, userenv)
+LoadDLLfuncEx2 (CreateProfile, 16, userenv, 1, 1)
LoadDLLfunc (DestroyEnvironmentBlock, 4, userenv)
+LoadDLLfunc (LoadUserProfileW, 8, userenv)
LoadDLLfuncEx3 (waveInAddBuffer, 12, winmm, 1, 0, 1)
LoadDLLfuncEx3 (waveInClose, 4, winmm, 1, 0, 1)
diff --git a/winsup/cygwin/registry.cc b/winsup/cygwin/registry.cc
index 632260aae..99b1d9b2d 100644
--- a/winsup/cygwin/registry.cc
+++ b/winsup/cygwin/registry.cc
@@ -1,7 +1,7 @@
/* registry.cc: registry interface
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -19,7 +19,6 @@ details. */
#include "tls_pbuf.h"
#include "ntdll.h"
#include <wchar.h>
-#include <alloca.h>
/* Opens a key under the appropriate Cygwin key.
Do not use HKCU per MS KB 199190 */
@@ -213,96 +212,3 @@ reg_key::~reg_key ()
NtClose (key);
key_is_invalid = 1;
}
-
-/* The buffer path points to should be at least MAX_PATH bytes. */
-PWCHAR
-get_registry_hive_path (PCWSTR name, PWCHAR path)
-{
- if (!name || !path)
- return NULL;
-
- WCHAR key[256];
- UNICODE_STRING buf;
- tmp_pathbuf tp;
- tp.u_get (&buf);
- NTSTATUS status;
-
- RTL_QUERY_REGISTRY_TABLE tab[2] = {
- { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT
- | RTL_QUERY_REGISTRY_REQUIRED,
- L"ProfileImagePath", &buf, REG_NONE, NULL, 0 },
- { NULL, 0, NULL, NULL, 0, NULL, 0 }
- };
- wcpcpy (wcpcpy (key, L"ProfileList\\"), name);
- status = RtlQueryRegistryValues (RTL_REGISTRY_WINDOWS_NT, key, tab,
- NULL, NULL);
- if (!NT_SUCCESS (status) || buf.Length == 0)
- {
- debug_printf ("ProfileImagePath for %W not found, status %y", name,
- status);
- return NULL;
- }
- ExpandEnvironmentStringsW (buf.Buffer, path, MAX_PATH);
- debug_printf ("ProfileImagePath for %W: %W", name, path);
- return path;
-}
-
-void
-load_registry_hive (PCWSTR name)
-{
- if (!name)
- return;
-
- /* Fetch the path. Prepend native NT path prefix. */
- tmp_pathbuf tp;
- PWCHAR path = tp.w_get ();
- if (!get_registry_hive_path (name, wcpcpy (path, L"\\??\\")))
- return;
-
- WCHAR key[256];
- PWCHAR path_comp;
- UNICODE_STRING ukey, upath;
- OBJECT_ATTRIBUTES key_attr, path_attr;
- NTSTATUS status;
-
- /* Create keyname and path strings and object attributes. */
- wcpcpy (wcpcpy (key, L"\\Registry\\User\\"), name);
- RtlInitUnicodeString (&ukey, key);
- InitializeObjectAttributes (&key_attr, &ukey, OBJ_CASE_INSENSITIVE,
- NULL, NULL);
- /* First try to load the "normal" registry hive, which is what the user
- is supposed to see under HKEY_CURRENT_USER. */
- path_comp = wcschr (path, L'\0');
- wcpcpy (path_comp, L"\\ntuser.dat");
- RtlInitUnicodeString (&upath, path);
- InitializeObjectAttributes (&path_attr, &upath, OBJ_CASE_INSENSITIVE,
- NULL, NULL);
- status = NtLoadKey (&key_attr, &path_attr);
- if (!NT_SUCCESS (status))
- {
- debug_printf ("Loading user registry hive %S into %S failed: %y",
- &upath, &ukey, status);
- return;
- }
- debug_printf ("Loading user registry hive %S into %S SUCCEEDED: %y",
- &upath, &ukey, status);
- /* If loading the normal hive worked, try to load the classes hive into
- the sibling *_Classes subkey, which is what the user is supposed to
- see under HKEY_CLASSES_ROOT, merged with the machine-wide classes. */
- wcscat (key, L"_Classes");
- RtlInitUnicodeString (&ukey, key);
- /* Path to UsrClass.dat changed in Vista to
- \\AppData\\Local\\Microsoft\\Windows\\UsrClass.dat
- but old path is still available via symlinks. */
- wcpcpy (path_comp, L"\\Local Settings\\Application Data\\Microsoft\\"
- "Windows\\UsrClass.dat");
- RtlInitUnicodeString (&upath, path);
- /* Load UsrClass.dat file into key. */
- status = NtLoadKey (&key_attr, &path_attr);
- if (!NT_SUCCESS (status))
- debug_printf ("Loading user classes hive %S into %S failed: %y",
- &upath, &ukey, status);
- else
- debug_printf ("Loading user classes hive %S into %S SUCCEEDED: %y",
- &upath, &ukey, status);
-}
diff --git a/winsup/cygwin/registry.h b/winsup/cygwin/registry.h
index 50d6345ab..6a885db4d 100644
--- a/winsup/cygwin/registry.h
+++ b/winsup/cygwin/registry.h
@@ -1,7 +1,7 @@
/* registry.h: shared info for cygwin
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011 Red Hat, Inc.
+ 2011, 2012, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -37,7 +37,3 @@ public:
~reg_key ();
};
-
-/* Evaluates path to the directory of the local user registry hive */
-PWCHAR __stdcall get_registry_hive_path (PCWSTR name, PWCHAR path);
-void __stdcall load_registry_hive (PCWSTR name);
diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc
index b616c45e2..2906b715d 100644
--- a/winsup/cygwin/sec_auth.cc
+++ b/winsup/cygwin/sec_auth.cc
@@ -20,10 +20,13 @@ details. */
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
+#include "registry.h"
#include "ntdll.h"
#include "tls_pbuf.h"
#include <lm.h>
#include <iptypes.h>
+#include <wininet.h>
+#include <userenv.h>
#include "cyglsa.h"
#include "cygserver_setpwd.h"
#include <cygwin/version.h>
@@ -172,6 +175,113 @@ cygwin_logon_user (const struct passwd *pw, const char *password)
return hToken;
}
+/* The buffer path points to should be at least MAX_PATH bytes. */
+PWCHAR
+get_user_profile_directory (PCWSTR sidstr, PWCHAR path, SIZE_T path_len)
+{
+ if (!sidstr || !path)
+ return NULL;
+
+ UNICODE_STRING buf;
+ tmp_pathbuf tp;
+ tp.u_get (&buf);
+ NTSTATUS status;
+
+ RTL_QUERY_REGISTRY_TABLE tab[2] = {
+ { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT
+ | RTL_QUERY_REGISTRY_REQUIRED,
+ L"ProfileImagePath", &buf, REG_NONE, NULL, 0 },
+ { NULL, 0, NULL, NULL, 0, NULL, 0 }
+ };
+
+ WCHAR key[wcslen (sidstr) + 16];
+ wcpcpy (wcpcpy (key, L"ProfileList\\"), sidstr);
+ status = RtlQueryRegistryValues (RTL_REGISTRY_WINDOWS_NT, key, tab,
+ NULL, NULL);
+ if (!NT_SUCCESS (status) || buf.Length == 0)
+ {
+ debug_printf ("ProfileImagePath for %W not found, status %y", sidstr,
+ status);
+ return NULL;
+ }
+ ExpandEnvironmentStringsW (buf.Buffer, path, path_len);
+ debug_printf ("ProfileImagePath for %W: %W", sidstr, path);
+ return path;
+}
+
+/* The CreateProfile prototype is for some reason missing in our w32api headers,
+ even though it's defined upstream since Dec-2013. */
+extern "C" {
+ HRESULT WINAPI CreateProfile (LPCWSTR pszUserSid, LPCWSTR pszUserName,
+ LPWSTR pszProfilePath, DWORD cchProfilePath);
+}
+
+/* Load user profile if it's not already loaded. If the user profile doesn't
+ exist on the machine, and if we're running Vista or later, try to create it.
+
+ Return a handle to the loaded user registry hive only if it got actually
+ loaded here, not if it already existed. There's no reliable way to know
+ when to unload the hive yet, so we're leaking this registry handle for now.
+ TODO: Try to find a way to reliably unload the user profile again. */
+HANDLE
+load_user_profile (HANDLE token, struct passwd *pw, cygpsid &usersid)
+{
+ WCHAR domain[DNLEN + 1];
+ WCHAR username[UNLEN + 1];
+ WCHAR sid[128];
+ HKEY hkey;
+ WCHAR userpath[MAX_PATH];
+ PROFILEINFOW pi;
+ WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+ NET_API_STATUS nas = NERR_UserNotFound;
+ PUSER_INFO_3 ui;
+
+ extract_nt_dom_user (pw, domain, username);
+ usersid.string (sid);
+ debug_printf ("user: <%W> <%W>", username, sid);
+ /* Check if user hive is already loaded. */
+ if (!RegOpenKeyExW (HKEY_USERS, sid, 0, KEY_READ, &hkey))
+ {
+ debug_printf ("User registry hive for %W already exists", username);
+ RegCloseKey (hkey);
+ return NULL;
+ }
+ /* Check if the local profile dir has already been created. */
+ if (!get_user_profile_directory (sid, userpath, MAX_PATH))
+ {
+ /* No, try to create it. This function exists only on Vista and later. */
+ HRESULT res = CreateProfile (sid, username, userpath, MAX_PATH);
+ if (res != S_OK)
+ {
+ /* If res is 1 (S_FALSE), autoloading failed (XP or 2K3). */
+ if (res != S_FALSE)
+ debug_printf ("CreateProfile, HRESULT %x", res);
+ return NULL;
+ }
+ }
+ /* Fill PROFILEINFO */
+ memset (&pi, 0, sizeof pi);
+ pi.dwSize = sizeof pi;
+ pi.dwFlags = PI_NOUI;
+ pi.lpUserName = username;
+ /* Check if user has a roaming profile and fill in lpProfilePath, if so. */
+ if (get_logon_server (domain, server, DS_IS_FLAT_NAME))
+ {
+ nas = NetUserGetInfo (server, username, 3, (PBYTE *) &ui);
+ if (NetUserGetInfo (server, username, 3, (PBYTE *) &ui) != NERR_Success)
+ debug_printf ("NetUserGetInfo, %u", nas);
+ else if (ui->usri3_profile && *ui->usri3_profile)
+ pi.lpProfilePath = ui->usri3_profile;
+ }
+
+ if (!LoadUserProfileW (token, &pi))
+ debug_printf ("LoadUserProfileW, %E");
+ /* Free buffer created by NetUserGetInfo */
+ if (nas == NERR_Success)
+ NetApiBufferFree (ui);
+ return pi.hProfile;
+}
+
HANDLE
lsa_open_policy (PWCHAR server, ACCESS_MASK access)
{
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index eb3e0f1e5..50b5b3cc0 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -472,6 +472,12 @@ void extract_nt_dom_user (const struct passwd *pw, PWCHAR domain, PWCHAR user);
/* Get default logonserver for a domain. */
bool get_logon_server (PWCHAR domain, PWCHAR wserver, ULONG flags);
+/* Fetch user profile path from registry, if it already exists. */
+PWCHAR get_user_profile_directory (PCWSTR sidstr, PWCHAR path, SIZE_T path_len);
+
+/* Load user profile if it's not already loaded. */
+HANDLE load_user_profile (HANDLE token, struct passwd *pw, cygpsid &sid);
+
HANDLE lsa_open_policy (PWCHAR server, ACCESS_MASK access);
void lsa_close_policy (HANDLE lsa);
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 933bfe464..9890db4f2 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -3387,11 +3387,7 @@ seteuid32 (uid_t uid)
NTSTATUS status;
if (!request_restricted_uid_switch)
- {
- /* Avoid having HKCU use default user */
- WCHAR name[128];
- load_registry_hive (usersid.string (name));
- }
+ load_user_profile (new_token, pw_new, usersid);
/* Try setting owner to same value as user. */
status = NtSetInformationToken (new_token, TokenOwner,
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index e0243d4ac..7c161622d 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -482,13 +482,13 @@ cygheap_user::env_userprofile (const char *name, size_t namelen)
if (test_uid (puserprof, name, namelen))
return puserprof;
- /* User hive path is never longer than MAX_PATH. */
- WCHAR userprofile_env_buf[MAX_PATH];
+ /* User profile path is never longer than MAX_PATH. */
+ WCHAR profile[MAX_PATH];
WCHAR win_id[UNLEN + 1]; /* Large enough for SID */
cfree_and_set (puserprof, almost_null);
- if (get_registry_hive_path (get_windows_id (win_id), userprofile_env_buf))
- sys_wcstombs_alloc (&puserprof, HEAP_STR, userprofile_env_buf);
+ if (get_user_profile_directory (get_windows_id (win_id), profile, MAX_PATH))
+ sys_wcstombs_alloc (&puserprof, HEAP_STR, profile);
return puserprof;
}