diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2014-12-02 10:49:47 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2014-12-02 10:49:47 +0000 |
commit | 41f77e25f11d2b152d2f4da12d1e6378c64fc78e (patch) | |
tree | bd51f7bf99de9278c427694a609c2a9e45cf3faa /winsup/cygwin/sec_auth.cc | |
parent | 195a9205e5c8d6ddded25c7dca736105ed9a1e86 (diff) | |
download | cygnal-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.
Diffstat (limited to 'winsup/cygwin/sec_auth.cc')
-rw-r--r-- | winsup/cygwin/sec_auth.cc | 110 |
1 files changed, 110 insertions, 0 deletions
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) { |