mirror of
https://github.com/reactos/reactos
synced 2025-10-06 08:22:58 +02:00
[MSGINA] CreateProfile(): Fix initialization of some WLX_PROFILE_V2_0
members (#8321)
The following members of the returned `WLX_PROFILE_V2_0` structure: `pszProfile`, `pszPolicy`, `pszNetworkDefaultUserProfile`, and `pszServerName`, have a specific meaning and are used when logging to (NT4, Active Directory...) domains. See the added code comments for details. In particular, `pszProfile` specifies the path to a *roaming* user profile[^1] on a domain server, if any. It **DOES NOT** specify the local `"C:\Documents and Settings"` path (got via `GetProfilesDirectoryW()`). Since we don't really support user login on domains, set these pointers to NULL. ---- Enabling UserEnv debug logging[^2] on Windows 2003, one can observe such following traces, for a `TestUser` roaming user profile: ``` USERENV(148.14c) 20:24:59:821 LoadUserProfile: Entering, hToken = <0x8bc>, lpProfileInfo = 0x6e5d8 USERENV(148.14c) 20:24:59:875 LoadUserProfile: lpProfileInfo->dwFlags = <0x0> USERENV(148.14c) 20:24:59:912 LoadUserProfile: lpProfileInfo->lpUserName = <TestUser> USERENV(148.14c) 20:24:59:966 LoadUserProfile: lpProfileInfo->lpProfilePath = <C:\Documents and Settings\TestUser_Roaming> USERENV(148.14c) 20:25:00:021 LoadUserProfile: lpProfileInfo->lpDefaultPath = <\\PC-H\netlogon\Default User> USERENV(148.14c) 20:25:00:075 LoadUserProfile: NULL server name ... USERENV(148.14c) 20:25:06:177 CopyProfileDirectoryEx: Found hive file NTUSER.DAT USERENV(148.14c) 20:25:06:395 ReconcileFile: C:\Documents and Settings\TestUser_Roaming\NTUSER.DAT ==> C:\Documents and Settings\TestUser\NTUSER.DAT [OK] ... ``` The `lpProfilePath` specifies a roaming profile directory (`"TestUser_Roaming"`) for a user named named `TestUser`, and UserEnv proceeds to image the roaming profile into the directory (`"TestUser"`) in the local computer. However, when the user has a local profile, the `lpProfilePath` is set to NULL in this case, and one observes instead: ``` USERENV(148.14c) 20:21:22:644 LoadUserProfile: NULL central profile path ``` ---- [^1]: The following links explain this, also demonstrating UserEnv debug logging: - https://web.archive.org/web/20130319204738/http://blogs.technet.com/b/askds/archive/2008/11/11/understanding-how-to-read-a-userenv-log-part-2.aspx - https://web.archive.org/web/20150405040409/http://blogs.technet.com/b/ad/archive/2007/08/20/tracking-user-environment-creation.aspx [^2]: For more details, see: https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/221833 (archived from: http://support.microsoft.com/kb/221833) UserEnv debug logging is achieved by adding a `REG_DWORD` value named `UserEnvDebugLevel` in the following registry sub-key: `HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon` with a non-zero value. To view the output in a debugger (e.g. WinDbg when kernel-debugging Windows), set the value to `0x00020002`.
This commit is contained in:
@@ -835,19 +835,21 @@ CreateProfile(
|
||||
IN PWSTR Password)
|
||||
{
|
||||
PWLX_PROFILE_V2_0 pProfile = NULL;
|
||||
PWSTR pProfilePath = NULL;
|
||||
PWSTR pEnvironment = NULL;
|
||||
TOKEN_STATISTICS Stats;
|
||||
DWORD cbStats, cbSize;
|
||||
DWORD dwLength;
|
||||
BOOL bResult;
|
||||
#if 0
|
||||
BOOL bIsDomainLogon;
|
||||
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
||||
#endif
|
||||
|
||||
/* Store the logon time in the context */
|
||||
GetLocalTime(&pgContext->LogonTime);
|
||||
|
||||
/* Store user and domain in the context */
|
||||
wcscpy(pgContext->UserName, UserName);
|
||||
if (Domain == NULL || wcslen(Domain) == 0)
|
||||
if (Domain == NULL || !Domain[0])
|
||||
{
|
||||
dwLength = _countof(pgContext->DomainName);
|
||||
GetComputerNameW(pgContext->DomainName, &dwLength);
|
||||
@@ -856,25 +858,17 @@ CreateProfile(
|
||||
{
|
||||
wcscpy(pgContext->DomainName, Domain);
|
||||
}
|
||||
/* From now on we use in UserName and Domain the captured values from pgContext */
|
||||
UserName = pgContext->UserName;
|
||||
Domain = pgContext->DomainName;
|
||||
|
||||
/* Get profile path */
|
||||
cbSize = 0;
|
||||
bResult = GetProfilesDirectoryW(NULL, &cbSize);
|
||||
if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
pProfilePath = LocalAlloc(LMEM_FIXED, cbSize * sizeof(WCHAR));
|
||||
if (!pProfilePath)
|
||||
{
|
||||
WARN("LocalAlloc() failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
bResult = GetProfilesDirectoryW(pProfilePath, &cbSize);
|
||||
}
|
||||
if (!bResult)
|
||||
{
|
||||
WARN("GetUserProfileDirectoryW() failed\n");
|
||||
goto cleanup;
|
||||
}
|
||||
#if 0
|
||||
/* Determine whether this is really a domain logon, by verifying
|
||||
* that the specified domain is different from the local computer */
|
||||
dwLength = _countof(ComputerName);
|
||||
GetComputerNameW(ComputerName, &dwLength);
|
||||
bIsDomainLogon = (_wcsicmp(ComputerName, Domain) != 0);
|
||||
#endif
|
||||
|
||||
/* Allocate memory for profile */
|
||||
pProfile = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*pProfile));
|
||||
@@ -884,10 +878,61 @@ CreateProfile(
|
||||
goto cleanup;
|
||||
}
|
||||
pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
|
||||
pProfile->pszProfile = pProfilePath;
|
||||
|
||||
/*
|
||||
* TODO: For domain logon support:
|
||||
*
|
||||
* - pszProfile: Specifies the path to a *roaming* user profile on a
|
||||
* domain server, if any. It is then used to create a local image
|
||||
* (copy) of the profile on the local computer.
|
||||
* ** This data should be retrieved from the LsaLogonUser() call
|
||||
* made by MyLogonUser()! **
|
||||
*
|
||||
* - pszPolicy (for domain logon): Path to a policy file.
|
||||
* Windows' msgina.dll hardcodes it as:
|
||||
* "\\<domain_controller>\netlogon\ntconfig.pol"
|
||||
*
|
||||
* - pszNetworkDefaultUserProfile (for domain logon): Path to the
|
||||
* default user profile. Windows' msgina.dll hardcodes it as:
|
||||
* "\\<domain_controller>\netlogon\Default User"
|
||||
*
|
||||
* - pszServerName (for domain logon): Name ("domain_controller") of
|
||||
* the server (local computer; Active Directory domain controller...)
|
||||
* that validated the logon.
|
||||
* ** This data should be retrieved from the LsaLogonUser() call
|
||||
* made by MyLogonUser()! **
|
||||
*
|
||||
* NOTES:
|
||||
* - The paths use the domain controllers' "netlogon" share.
|
||||
* - These strings are LocalAlloc'd here, and LocalFree'd by Winlogon.
|
||||
*/
|
||||
pProfile->pszProfile = NULL;
|
||||
pProfile->pszPolicy = NULL;
|
||||
pProfile->pszNetworkDefaultUserProfile = NULL;
|
||||
pProfile->pszServerName = NULL;
|
||||
#if 0
|
||||
if (bIsDomainLogon)
|
||||
{
|
||||
PWSTR pServerName;
|
||||
cbSize = sizeof(L"\\\\") + wcslen(Domain) * sizeof(WCHAR);
|
||||
pServerName = LocalAlloc(LMEM_FIXED, cbSize);
|
||||
if (!pServerName)
|
||||
WARN("HeapAlloc() failed\n"); // Consider this optional, so no failure.
|
||||
else
|
||||
StringCbPrintfW(pServerName, cbSize, L"\\\\%ws", Domain); // See LogonServer below.
|
||||
pProfile->pszServerName = pServerName;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Build the minimal environment string block */
|
||||
// FIXME: LogonServer is the name of the server that processed the logon
|
||||
// request ("domain_controller"). It can be different from the selected
|
||||
// user's logon domain.
|
||||
// See e.g.:
|
||||
// - https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/ns-ntsecapi-msv1_0_interactive_profile
|
||||
// - https://learn.microsoft.com/en-us/windows/win32/api/winwlx/ns-winwlx-wlx_consoleswitch_credentials_info_v1_0
|
||||
cbSize = sizeof(L"LOGONSERVER=\\\\") +
|
||||
wcslen(pgContext->DomainName) * sizeof(WCHAR) +
|
||||
wcslen(Domain) * sizeof(WCHAR) +
|
||||
sizeof(UNICODE_NULL);
|
||||
pEnvironment = LocalAlloc(LMEM_FIXED, cbSize);
|
||||
if (!pEnvironment)
|
||||
@@ -896,19 +941,20 @@ CreateProfile(
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
StringCbPrintfW(pEnvironment, cbSize, L"LOGONSERVER=\\\\%ls", pgContext->DomainName);
|
||||
StringCbPrintfW(pEnvironment, cbSize, L"LOGONSERVER=\\\\%ws", Domain);
|
||||
ASSERT(wcslen(pEnvironment) == cbSize / sizeof(WCHAR) - 2);
|
||||
pEnvironment[cbSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
|
||||
|
||||
pProfile->pszEnvironment = pEnvironment;
|
||||
|
||||
/* Return the other info */
|
||||
if (!GetTokenInformation(pgContext->UserToken,
|
||||
TokenStatistics,
|
||||
&Stats,
|
||||
sizeof(Stats),
|
||||
&cbStats))
|
||||
{
|
||||
WARN("Couldn't get Authentication id from user token!\n");
|
||||
WARN("Couldn't get Authentication Id from user token!\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -924,8 +970,6 @@ CreateProfile(
|
||||
cleanup:
|
||||
if (pEnvironment)
|
||||
LocalFree(pEnvironment);
|
||||
if (pProfilePath)
|
||||
LocalFree(pProfilePath);
|
||||
if (pProfile)
|
||||
LocalFree(pProfile);
|
||||
return FALSE;
|
||||
|
Reference in New Issue
Block a user