* 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.
This commit is contained in:
Corinna Vinschen
2014-12-02 10:49:47 +00:00
parent 195a9205e5
commit 41f77e25f1
8 changed files with 145 additions and 109 deletions

View File

@ -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)
{