mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 12:23:31 +00: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:
+71
-27
@@ -835,19 +835,21 @@ CreateProfile(
|
|||||||
IN PWSTR Password)
|
IN PWSTR Password)
|
||||||
{
|
{
|
||||||
PWLX_PROFILE_V2_0 pProfile = NULL;
|
PWLX_PROFILE_V2_0 pProfile = NULL;
|
||||||
PWSTR pProfilePath = NULL;
|
|
||||||
PWSTR pEnvironment = NULL;
|
PWSTR pEnvironment = NULL;
|
||||||
TOKEN_STATISTICS Stats;
|
TOKEN_STATISTICS Stats;
|
||||||
DWORD cbStats, cbSize;
|
DWORD cbStats, cbSize;
|
||||||
DWORD dwLength;
|
DWORD dwLength;
|
||||||
BOOL bResult;
|
#if 0
|
||||||
|
BOOL bIsDomainLogon;
|
||||||
|
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH+1];
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Store the logon time in the context */
|
/* Store the logon time in the context */
|
||||||
GetLocalTime(&pgContext->LogonTime);
|
GetLocalTime(&pgContext->LogonTime);
|
||||||
|
|
||||||
/* Store user and domain in the context */
|
/* Store user and domain in the context */
|
||||||
wcscpy(pgContext->UserName, UserName);
|
wcscpy(pgContext->UserName, UserName);
|
||||||
if (Domain == NULL || wcslen(Domain) == 0)
|
if (Domain == NULL || !Domain[0])
|
||||||
{
|
{
|
||||||
dwLength = _countof(pgContext->DomainName);
|
dwLength = _countof(pgContext->DomainName);
|
||||||
GetComputerNameW(pgContext->DomainName, &dwLength);
|
GetComputerNameW(pgContext->DomainName, &dwLength);
|
||||||
@@ -856,25 +858,17 @@ CreateProfile(
|
|||||||
{
|
{
|
||||||
wcscpy(pgContext->DomainName, Domain);
|
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 */
|
#if 0
|
||||||
cbSize = 0;
|
/* Determine whether this is really a domain logon, by verifying
|
||||||
bResult = GetProfilesDirectoryW(NULL, &cbSize);
|
* that the specified domain is different from the local computer */
|
||||||
if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
dwLength = _countof(ComputerName);
|
||||||
{
|
GetComputerNameW(ComputerName, &dwLength);
|
||||||
pProfilePath = LocalAlloc(LMEM_FIXED, cbSize * sizeof(WCHAR));
|
bIsDomainLogon = (_wcsicmp(ComputerName, Domain) != 0);
|
||||||
if (!pProfilePath)
|
#endif
|
||||||
{
|
|
||||||
WARN("LocalAlloc() failed\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
bResult = GetProfilesDirectoryW(pProfilePath, &cbSize);
|
|
||||||
}
|
|
||||||
if (!bResult)
|
|
||||||
{
|
|
||||||
WARN("GetUserProfileDirectoryW() failed\n");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate memory for profile */
|
/* Allocate memory for profile */
|
||||||
pProfile = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*pProfile));
|
pProfile = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*pProfile));
|
||||||
@@ -884,10 +878,61 @@ CreateProfile(
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
|
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=\\\\") +
|
cbSize = sizeof(L"LOGONSERVER=\\\\") +
|
||||||
wcslen(pgContext->DomainName) * sizeof(WCHAR) +
|
wcslen(Domain) * sizeof(WCHAR) +
|
||||||
sizeof(UNICODE_NULL);
|
sizeof(UNICODE_NULL);
|
||||||
pEnvironment = LocalAlloc(LMEM_FIXED, cbSize);
|
pEnvironment = LocalAlloc(LMEM_FIXED, cbSize);
|
||||||
if (!pEnvironment)
|
if (!pEnvironment)
|
||||||
@@ -896,19 +941,20 @@ CreateProfile(
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringCbPrintfW(pEnvironment, cbSize, L"LOGONSERVER=\\\\%ls", pgContext->DomainName);
|
StringCbPrintfW(pEnvironment, cbSize, L"LOGONSERVER=\\\\%ws", Domain);
|
||||||
ASSERT(wcslen(pEnvironment) == cbSize / sizeof(WCHAR) - 2);
|
ASSERT(wcslen(pEnvironment) == cbSize / sizeof(WCHAR) - 2);
|
||||||
pEnvironment[cbSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
|
pEnvironment[cbSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
|
||||||
|
|
||||||
pProfile->pszEnvironment = pEnvironment;
|
pProfile->pszEnvironment = pEnvironment;
|
||||||
|
|
||||||
|
/* Return the other info */
|
||||||
if (!GetTokenInformation(pgContext->UserToken,
|
if (!GetTokenInformation(pgContext->UserToken,
|
||||||
TokenStatistics,
|
TokenStatistics,
|
||||||
&Stats,
|
&Stats,
|
||||||
sizeof(Stats),
|
sizeof(Stats),
|
||||||
&cbStats))
|
&cbStats))
|
||||||
{
|
{
|
||||||
WARN("Couldn't get Authentication id from user token!\n");
|
WARN("Couldn't get Authentication Id from user token!\n");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,8 +970,6 @@ CreateProfile(
|
|||||||
cleanup:
|
cleanup:
|
||||||
if (pEnvironment)
|
if (pEnvironment)
|
||||||
LocalFree(pEnvironment);
|
LocalFree(pEnvironment);
|
||||||
if (pProfilePath)
|
|
||||||
LocalFree(pProfilePath);
|
|
||||||
if (pProfile)
|
if (pProfile)
|
||||||
LocalFree(pProfile);
|
LocalFree(pProfile);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|||||||
Reference in New Issue
Block a user